stream-chat-angular 6.4.1 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -18
- package/assets/version.d.ts +1 -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 +232 -0
- package/esm2022/lib/attachment-preview-list/attachment-preview-list.component.mjs +55 -0
- package/{esm2020 → esm2022}/lib/attachment.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/avatar/avatar.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/avatar-placeholder/avatar-placeholder.component.mjs +6 -6
- package/esm2022/lib/channel/channel.component.mjs +45 -0
- package/{esm2020 → esm2022}/lib/channel-header/channel-header.component.mjs +6 -6
- package/esm2022/lib/channel-list/channel-list.component.mjs +47 -0
- package/{esm2020 → esm2022}/lib/channel-preview/channel-preview.component.mjs +6 -6
- package/esm2022/lib/channel.service.mjs +1575 -0
- package/{esm2020 → esm2022}/lib/chat-client.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/custom-templates.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/date-parser.service.mjs +5 -5
- 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/esm2022/lib/message/message.component.mjs +501 -0
- package/{esm2020 → esm2022}/lib/message-actions-box/message-actions-box.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/message-actions.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-blocked/message-blocked.component.mjs +4 -4
- package/{esm2020 → esm2022}/lib/message-bounce-prompt/message-bounce-prompt.component.mjs +6 -6
- 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/{esm2020 → esm2022}/lib/message-input/message-input.component.mjs +7 -7
- 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/esm2022/lib/message-list/message-list.component.mjs +717 -0
- package/{esm2020 → esm2022}/lib/message-reactions/message-reactions.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/message-reactions-selector/message-reactions-selector.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-reactions.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-text/message-text.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/message.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/modal/modal.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/modal/stream-modal.module.mjs +5 -5
- package/{esm2020 → esm2022}/lib/notification/notification.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/notification-list/notification-list.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/notification-list/stream-notification.module.mjs +5 -5
- package/{esm2020 → esm2022}/lib/notification.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/paginated-list/paginated-list.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/paginated-list/stream-paginated-list.module.mjs +5 -5
- package/{esm2020 → esm2022}/lib/polls/base-poll.component.mjs +5 -5
- package/esm2022/lib/polls/poll/poll.component.mjs +34 -0
- package/{esm2020 → esm2022}/lib/polls/poll-actions/add-option/add-option.component.mjs +4 -4
- package/{esm2020 → esm2022}/lib/polls/poll-actions/poll-actions.component.mjs +6 -6
- package/esm2022/lib/polls/poll-actions/poll-answers-list/poll-answers-list.component.mjs +82 -0
- package/esm2022/lib/polls/poll-actions/poll-results/poll-results-list/poll-results-list.component.mjs +63 -0
- package/{esm2020 → esm2022}/lib/polls/poll-actions/poll-results/poll-vote/poll-vote.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/polls/poll-actions/poll-results/poll-vote-results-list/poll-vote-results-list.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/polls/poll-actions/upsert-answer/upsert-answer.component.mjs +4 -4
- package/esm2022/lib/polls/poll-composer/poll-composer.component.mjs +134 -0
- package/{esm2020 → esm2022}/lib/polls/poll-header/poll-header.component.mjs +4 -4
- package/{esm2020 → esm2022}/lib/polls/poll-option-selector/poll-option-selector.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/polls/poll-options-list/poll-options-list.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/polls/poll-preview/poll-preview.component.mjs +4 -4
- package/{esm2020 → esm2022}/lib/polls/stream-polls.module.mjs +41 -41
- 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 +67 -67
- package/esm2022/lib/stream-i18n.service.mjs +34 -0
- 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/{esm2020 → esm2022}/lib/types.mjs +1 -1
- package/{esm2020 → esm2022}/lib/user-list/user-list.component.mjs +5 -5
- 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/transcoder.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/voice-recorder/voice-recorder-wavebar/voice-recorder-wavebar.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/voice-recorder/voice-recorder.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/voice-recorder/voice-recorder.module.mjs +9 -9
- package/{esm2020 → esm2022}/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/voice-recording/voice-recording.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/voice-recording/voice-recording.module.mjs +5 -5
- package/{fesm2020 → fesm2022}/stream-chat-angular.mjs +463 -470
- package/fesm2022/stream-chat-angular.mjs.map +1 -0
- package/lib/attachment-list/attachment-list.component.d.ts +1 -1
- package/lib/attachment-preview-list/attachment-preview-list.component.d.ts +1 -1
- package/lib/avatar/avatar.component.d.ts +1 -1
- package/lib/avatar-placeholder/avatar-placeholder.component.d.ts +1 -1
- package/lib/channel-preview/channel-preview.component.d.ts +1 -1
- package/lib/chat-client.service.d.ts +1 -1
- package/lib/custom-templates.service.d.ts +1 -0
- 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 +1 -1
- package/lib/message-actions-box/message-actions-box.component.d.ts +1 -1
- package/lib/message-blocked/message-blocked.component.d.ts +1 -1
- package/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.d.ts +1 -1
- package/lib/message-input/message-input.component.d.ts +1 -1
- package/lib/message-input/textarea/textarea.component.d.ts +1 -1
- package/lib/message-input/textarea.directive.d.ts +1 -1
- package/lib/message-list/group-styles.d.ts +1 -1
- package/lib/message-list/message-list.component.d.ts +1 -1
- package/lib/message-reactions/message-reactions.component.d.ts +1 -1
- package/lib/message-reactions-selector/message-reactions-selector.component.d.ts +1 -1
- 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/paginated-list/paginated-list.component.d.ts +5 -2
- package/lib/polls/base-poll.component.d.ts +1 -1
- package/lib/polls/poll-actions/add-option/add-option.component.d.ts +1 -1
- package/lib/polls/poll-actions/poll-actions.component.d.ts +2 -2
- package/lib/polls/poll-actions/poll-answers-list/poll-answers-list.component.d.ts +1 -1
- package/lib/polls/poll-actions/poll-results/poll-vote/poll-vote.component.d.ts +1 -1
- package/lib/polls/poll-actions/poll-results/poll-vote-results-list/poll-vote-results-list.component.d.ts +1 -1
- package/lib/polls/poll-actions/upsert-answer/upsert-answer.component.d.ts +1 -1
- package/lib/polls/poll-composer/poll-composer.component.d.ts +2 -2
- package/lib/polls/poll-header/poll-header.component.d.ts +1 -1
- package/lib/polls/poll-option-selector/poll-option-selector.component.d.ts +1 -1
- package/lib/polls/poll-options-list/poll-options-list.component.d.ts +1 -1
- package/lib/types.d.ts +79 -79
- 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.component.d.ts +1 -1
- package/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.d.ts +1 -1
- package/lib/voice-recording/voice-recording.component.d.ts +1 -1
- package/package.json +11 -17
- package/src/assets/version.ts +1 -1
- package/esm2020/lib/attachment-list/attachment-list.component.mjs +0 -232
- package/esm2020/lib/attachment-preview-list/attachment-preview-list.component.mjs +0 -55
- package/esm2020/lib/channel/channel.component.mjs +0 -45
- package/esm2020/lib/channel-list/channel-list.component.mjs +0 -47
- package/esm2020/lib/channel.service.mjs +0 -1575
- package/esm2020/lib/message/message.component.mjs +0 -501
- package/esm2020/lib/message-list/message-list.component.mjs +0 -717
- package/esm2020/lib/polls/poll/poll.component.mjs +0 -34
- package/esm2020/lib/polls/poll-actions/poll-answers-list/poll-answers-list.component.mjs +0 -82
- package/esm2020/lib/polls/poll-actions/poll-results/poll-results-list/poll-results-list.component.mjs +0 -63
- package/esm2020/lib/polls/poll-composer/poll-composer.component.mjs +0 -134
- package/esm2020/lib/stream-autocomplete-textarea.module.mjs +0 -33
- package/esm2020/lib/stream-i18n.service.mjs +0 -41
- package/esm2020/lib/stream-textarea.module.mjs +0 -31
- package/fesm2015/stream-chat-angular.mjs +0 -10596
- package/fesm2015/stream-chat-angular.mjs.map +0 -1
- package/fesm2020/stream-chat-angular.mjs.map +0 -1
- /package/{esm2020 → esm2022}/assets/i18n/en.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/channel-query.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/file-utils.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/format-duration.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/get-channel-display-text.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/get-message-translation.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/list-users.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/message-input/textarea.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/message-list/group-styles.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/message-preview.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/parse-date.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/polls/poll-composer/validators.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/polls/unique.validator.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/read-by.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/types-custom.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/virtualized-list.service.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/virtualized-message-list.service.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/voice-recorder/media-recorder.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/voice-recorder/mp3-transcoder.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/wave-form-sampler.mjs +0 -0
- /package/{esm2020 → esm2022}/public-api.mjs +0 -0
- /package/{esm2020 → esm2022}/stream-chat-angular.mjs +0 -0
- /package/{esm2020 → esm2022}/stream-chat.mjs +0 -0
|
@@ -0,0 +1,1575 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject, combineLatest, ReplaySubject, } from 'rxjs';
|
|
3
|
+
import { filter, first, map, shareReplay, take } from 'rxjs/operators';
|
|
4
|
+
import { getMessageTranslation } from './get-message-translation';
|
|
5
|
+
import { createMessagePreview } from './message-preview';
|
|
6
|
+
import { getReadBy } from './read-by';
|
|
7
|
+
import { ChannelQuery } from './channel-query';
|
|
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
|
+
this.messagePageSize = 25;
|
|
28
|
+
this.channelsSubject = new BehaviorSubject(undefined);
|
|
29
|
+
this.activeChannelSubject = new BehaviorSubject(undefined);
|
|
30
|
+
this.activeChannelMessagesSubject = new BehaviorSubject([]);
|
|
31
|
+
this.activeChannelPinnedMessagesSubject = new BehaviorSubject([]);
|
|
32
|
+
this.hasMoreChannelsSubject = new ReplaySubject(1);
|
|
33
|
+
this.activeChannelSubscriptions = [];
|
|
34
|
+
this.channelSubscriptions = {};
|
|
35
|
+
this.activeParentMessageIdSubject = new BehaviorSubject(undefined);
|
|
36
|
+
this.activeThreadMessagesSubject = new BehaviorSubject([]);
|
|
37
|
+
this.jumpToMessageSubject = new BehaviorSubject({ id: undefined, parentId: undefined });
|
|
38
|
+
this.latestMessageDateByUserByChannelsSubject = new BehaviorSubject({});
|
|
39
|
+
this.attachmentMaxSizeFallbackInMB = 100;
|
|
40
|
+
this.messageToQuoteSubject = new BehaviorSubject(undefined);
|
|
41
|
+
this.usersTypingInChannelSubject = new BehaviorSubject([]);
|
|
42
|
+
this.usersTypingInThreadSubject = new BehaviorSubject([]);
|
|
43
|
+
this._shouldMarkActiveChannelAsRead = true;
|
|
44
|
+
this.isStateRecoveryInProgress = false;
|
|
45
|
+
this.channelQueryStateSubject = new BehaviorSubject(undefined);
|
|
46
|
+
this.channelSwitchStateSubject = new BehaviorSubject('end');
|
|
47
|
+
this.channelListSetter = (channels, shouldStopWatchingRemovedChannels = true) => {
|
|
48
|
+
const currentChannels = this.channelsSubject.getValue() || [];
|
|
49
|
+
const deletedChannels = currentChannels.filter((c) => !channels?.find((channel) => channel.cid === c.cid));
|
|
50
|
+
for (let i = 0; i < channels.length; i++) {
|
|
51
|
+
const channel = channels[i];
|
|
52
|
+
if (!this.channelSubscriptions[channel.cid]) {
|
|
53
|
+
this.watchForChannelEvents(channel);
|
|
54
|
+
}
|
|
55
|
+
if (deletedChannels.includes(channel)) {
|
|
56
|
+
if (shouldStopWatchingRemovedChannels) {
|
|
57
|
+
if (this.channelSubscriptions[channel.cid]) {
|
|
58
|
+
this.channelSubscriptions[channel.cid]();
|
|
59
|
+
delete this.channelSubscriptions.cid;
|
|
60
|
+
}
|
|
61
|
+
void this.chatClientService.chatClient.activeChannels[channel.cid]
|
|
62
|
+
?.stopWatching()
|
|
63
|
+
.catch((err) => this.chatClientService.chatClient.logger('warn', 'Failed to unwatch channel', err));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const nextChannels = channels;
|
|
68
|
+
this.channelsSubject.next(nextChannels);
|
|
69
|
+
if (!nextChannels.find((c) => c.cid === this.activeChannelSubject.getValue()?.cid)) {
|
|
70
|
+
if (nextChannels.length > 0) {
|
|
71
|
+
this.setAsActiveChannel(nextChannels[0]);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.activeChannelSubject.next(undefined);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
this.messageListSetter = (messages) => {
|
|
79
|
+
this.activeChannelMessagesSubject.next(messages);
|
|
80
|
+
};
|
|
81
|
+
this.threadListSetter = (messages) => {
|
|
82
|
+
this.activeThreadMessagesSubject.next(messages);
|
|
83
|
+
};
|
|
84
|
+
this.parentMessageSetter = (message) => {
|
|
85
|
+
this.activeParentMessageIdSubject.next(message?.id);
|
|
86
|
+
};
|
|
87
|
+
this.areReadEventsPaused = false;
|
|
88
|
+
this.markReadThrottleTime = 1050;
|
|
89
|
+
this.channels$ = this.channelsSubject.asObservable().pipe(shareReplay(1));
|
|
90
|
+
this.activeChannel$ = this.activeChannelSubject
|
|
91
|
+
.asObservable()
|
|
92
|
+
.pipe(shareReplay(1));
|
|
93
|
+
this.activeChannelMessages$ = this.activeChannelMessagesSubject.pipe(map((messages) => {
|
|
94
|
+
const channel = this.activeChannelSubject.getValue();
|
|
95
|
+
return messages.map((message) => this.transformToStreamMessage(message, channel));
|
|
96
|
+
}), shareReplay(1));
|
|
97
|
+
this.bouncedMessage$ = new BehaviorSubject(undefined);
|
|
98
|
+
this.hasMoreChannels$ = this.hasMoreChannelsSubject
|
|
99
|
+
.asObservable()
|
|
100
|
+
.pipe(shareReplay(1));
|
|
101
|
+
this.activeParentMessageId$ = this.activeParentMessageIdSubject
|
|
102
|
+
.asObservable()
|
|
103
|
+
.pipe(shareReplay(1));
|
|
104
|
+
this.activeThreadMessages$ = this.activeThreadMessagesSubject.pipe(map((messages) => {
|
|
105
|
+
const channel = this.activeChannelSubject.getValue();
|
|
106
|
+
return messages.map((message) => this.transformToStreamMessage(message, channel));
|
|
107
|
+
}), shareReplay(1));
|
|
108
|
+
this.activeParentMessage$ = combineLatest([
|
|
109
|
+
this.activeChannelMessages$,
|
|
110
|
+
this.activeParentMessageId$,
|
|
111
|
+
]).pipe(map(([messages, parentMessageId]) => {
|
|
112
|
+
if (!parentMessageId) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const message = messages.find((m) => m.id === parentMessageId);
|
|
117
|
+
if (!message) {
|
|
118
|
+
void this.setAsActiveParentMessage(undefined);
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
return message;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}), shareReplay(1));
|
|
126
|
+
this.messageToQuote$ = this.messageToQuoteSubject
|
|
127
|
+
.asObservable()
|
|
128
|
+
.pipe(shareReplay(1));
|
|
129
|
+
this.jumpToMessage$ = this.jumpToMessageSubject
|
|
130
|
+
.asObservable()
|
|
131
|
+
.pipe(shareReplay(1));
|
|
132
|
+
this.usersTypingInChannel$ = this.usersTypingInChannelSubject
|
|
133
|
+
.asObservable()
|
|
134
|
+
.pipe(shareReplay(1));
|
|
135
|
+
this.usersTypingInThread$ = this.usersTypingInThreadSubject
|
|
136
|
+
.asObservable()
|
|
137
|
+
.pipe(shareReplay(1));
|
|
138
|
+
this.latestMessageDateByUserByChannels$ =
|
|
139
|
+
this.latestMessageDateByUserByChannelsSubject
|
|
140
|
+
.asObservable()
|
|
141
|
+
.pipe(shareReplay(1));
|
|
142
|
+
this.activeChannelPinnedMessages$ = this.activeChannelPinnedMessagesSubject
|
|
143
|
+
.asObservable()
|
|
144
|
+
.pipe(shareReplay(1));
|
|
145
|
+
this.channelQueryState$ = this.channelQueryStateSubject
|
|
146
|
+
.asObservable()
|
|
147
|
+
.pipe(shareReplay(1));
|
|
148
|
+
this.channelSwitchState$ = this.channelSwitchStateSubject
|
|
149
|
+
.asObservable()
|
|
150
|
+
.pipe(shareReplay(1));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 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.
|
|
154
|
+
*/
|
|
155
|
+
get shouldMarkActiveChannelAsRead() {
|
|
156
|
+
return this._shouldMarkActiveChannelAsRead;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 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.
|
|
160
|
+
*/
|
|
161
|
+
set shouldMarkActiveChannelAsRead(shouldMarkActiveChannelAsRead) {
|
|
162
|
+
if (!this._shouldMarkActiveChannelAsRead && shouldMarkActiveChannelAsRead) {
|
|
163
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
164
|
+
if (activeChannel && this.canSendReadEvents) {
|
|
165
|
+
void activeChannel.markRead();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
this._shouldMarkActiveChannelAsRead = shouldMarkActiveChannelAsRead;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* By default the SDK uses an offset based pagination, you can change/extend this by providing your own custom paginator method.
|
|
172
|
+
*
|
|
173
|
+
* The method will be called with the result of the latest channel query.
|
|
174
|
+
*
|
|
175
|
+
* You can return either an offset, or a filter using the [`$lte`/`$gte` operator](/chat/docs/javascript/query_syntax_operators/). If you return a filter, it will be merged with the filter provided for the `init` method.
|
|
176
|
+
*/
|
|
177
|
+
set customPaginator(paginator) {
|
|
178
|
+
this._customPaginator = paginator;
|
|
179
|
+
if (this.channelQuery && 'customPaginator' in this.channelQuery) {
|
|
180
|
+
this.channelQuery.customPaginator = this._customPaginator;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Sets the given `channel` as active and marks it as read.
|
|
185
|
+
* If the channel wasn't previously part of the channel, it will be added to the beginning of the list.
|
|
186
|
+
* @param channel
|
|
187
|
+
*/
|
|
188
|
+
setAsActiveChannel(channel) {
|
|
189
|
+
this.channelSwitchStateSubject.next('start');
|
|
190
|
+
const prevActiveChannel = this.activeChannelSubject.getValue();
|
|
191
|
+
if (prevActiveChannel?.cid === channel.cid) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
this.stopWatchForActiveChannelEvents(prevActiveChannel);
|
|
195
|
+
this.flushMarkReadQueue();
|
|
196
|
+
this.areReadEventsPaused = false;
|
|
197
|
+
this.isMessageLoadingInProgress = false;
|
|
198
|
+
const readState = channel.state.read[this.chatClientService.chatClient.user?.id || ''];
|
|
199
|
+
this.activeChannelLastReadMessageId = readState?.last_read_message_id;
|
|
200
|
+
if (channel.state.latestMessages[channel.state.latestMessages.length - 1]
|
|
201
|
+
?.id === this.activeChannelLastReadMessageId) {
|
|
202
|
+
this.activeChannelLastReadMessageId = undefined;
|
|
203
|
+
}
|
|
204
|
+
this.activeChannelUnreadCount = readState?.unread_messages || 0;
|
|
205
|
+
this.watchForActiveChannelEvents(channel);
|
|
206
|
+
this.addChannel(channel);
|
|
207
|
+
this.activeChannelSubject.next(channel);
|
|
208
|
+
const channelStateLength = channel.state.latestMessages.length;
|
|
209
|
+
if (channelStateLength > 2 * this.messagePageSize) {
|
|
210
|
+
channel.state.latestMessages = channel.state.latestMessages.slice(channelStateLength - 2 * this.messagePageSize);
|
|
211
|
+
}
|
|
212
|
+
this.setChannelState(channel);
|
|
213
|
+
this.channelSwitchStateSubject.next('end');
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Deselects the currently active (if any) channel
|
|
217
|
+
*/
|
|
218
|
+
deselectActiveChannel() {
|
|
219
|
+
this.channelSwitchStateSubject.next('start');
|
|
220
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
221
|
+
if (!activeChannel) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
this.stopWatchForActiveChannelEvents(activeChannel);
|
|
225
|
+
this.flushMarkReadQueue();
|
|
226
|
+
this.activeChannelMessagesSubject.next([]);
|
|
227
|
+
this.activeChannelSubject.next(undefined);
|
|
228
|
+
this.activeParentMessageIdSubject.next(undefined);
|
|
229
|
+
this.activeThreadMessagesSubject.next([]);
|
|
230
|
+
this.latestMessageDateByUserByChannelsSubject.next({});
|
|
231
|
+
this.selectMessageToQuote(undefined);
|
|
232
|
+
this.jumpToMessageSubject.next({ id: undefined, parentId: undefined });
|
|
233
|
+
this.activeChannelPinnedMessagesSubject.next([]);
|
|
234
|
+
this.usersTypingInChannelSubject.next([]);
|
|
235
|
+
this.usersTypingInThreadSubject.next([]);
|
|
236
|
+
this.activeChannelLastReadMessageId = undefined;
|
|
237
|
+
this.activeChannelUnreadCount = undefined;
|
|
238
|
+
this.areReadEventsPaused = false;
|
|
239
|
+
this.isMessageLoadingInProgress = false;
|
|
240
|
+
this.channelSwitchStateSubject.next('end');
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Sets the given `message` as an active parent message. If `undefined` is provided, it will deleselect the current parent message.
|
|
244
|
+
* @param message
|
|
245
|
+
* @param loadMessagesForm
|
|
246
|
+
*/
|
|
247
|
+
async setAsActiveParentMessage(message, loadMessagesForm = 'request') {
|
|
248
|
+
const messageToQuote = this.messageToQuoteSubject.getValue();
|
|
249
|
+
if (messageToQuote && !!messageToQuote.parent_id) {
|
|
250
|
+
this.messageToQuoteSubject.next(undefined);
|
|
251
|
+
}
|
|
252
|
+
if (!message) {
|
|
253
|
+
this.activeParentMessageIdSubject.next(undefined);
|
|
254
|
+
this.activeThreadMessagesSubject.next([]);
|
|
255
|
+
const messageToJumpTo = this.jumpToMessageSubject.getValue();
|
|
256
|
+
if (messageToJumpTo && !!messageToJumpTo.parentId) {
|
|
257
|
+
this.jumpToMessageSubject.next({ id: undefined, parentId: undefined });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
this.activeParentMessageIdSubject.next(message.id);
|
|
262
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
263
|
+
if (loadMessagesForm === 'request') {
|
|
264
|
+
const result = await activeChannel?.getReplies(message.id, {
|
|
265
|
+
limit: this.messagePageSize,
|
|
266
|
+
});
|
|
267
|
+
this.activeThreadMessagesSubject.next(result?.messages || []);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
this.activeThreadMessagesSubject.next(activeChannel?.state.threads[message.id] || []);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* 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.
|
|
276
|
+
* @param direction
|
|
277
|
+
*/
|
|
278
|
+
loadMoreMessages(direction = 'older') {
|
|
279
|
+
const activeChnannel = this.activeChannelSubject.getValue();
|
|
280
|
+
const messages = this.activeChannelMessagesSubject.getValue();
|
|
281
|
+
const lastMessageId = messages[direction === 'older' ? 0 : messages.length - 1]?.id;
|
|
282
|
+
if (direction === 'newer' &&
|
|
283
|
+
activeChnannel?.state?.latestMessages === activeChnannel?.state?.messages) {
|
|
284
|
+
// If we are on latest message set, activeChannelMessages$ will be refreshed by WS events, no need for a request
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
return activeChnannel
|
|
288
|
+
?.query({
|
|
289
|
+
messages: {
|
|
290
|
+
limit: this.messagePageSize,
|
|
291
|
+
[direction === 'older' ? 'id_lt' : 'id_gt']: lastMessageId,
|
|
292
|
+
},
|
|
293
|
+
members: { limit: 0 },
|
|
294
|
+
watchers: { limit: 0 },
|
|
295
|
+
})
|
|
296
|
+
.then((res) => {
|
|
297
|
+
if (activeChnannel?.data?.id ===
|
|
298
|
+
this.activeChannelSubject.getValue()?.data?.id) {
|
|
299
|
+
this.activeChannelMessagesSubject.next([
|
|
300
|
+
...activeChnannel.state.messages,
|
|
301
|
+
]);
|
|
302
|
+
}
|
|
303
|
+
return res;
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* 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.
|
|
308
|
+
* @param direction
|
|
309
|
+
*/
|
|
310
|
+
loadMoreThreadReplies(direction = 'older') {
|
|
311
|
+
if (direction === 'newer') {
|
|
312
|
+
// Thread replies aren't broke into different message sets, activeThreadMessages$ will be refreshed by WS events, no need for a request
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
const activeChnannel = this.activeChannelSubject.getValue();
|
|
316
|
+
const parentMessageId = this.activeParentMessageIdSubject.getValue();
|
|
317
|
+
if (!parentMessageId || !activeChnannel) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
const threadMessages = this.activeThreadMessagesSubject.getValue();
|
|
321
|
+
const lastMessageId = threadMessages[direction === 'older' ? 0 : threadMessages.length - 1]?.id;
|
|
322
|
+
return activeChnannel
|
|
323
|
+
.getReplies(parentMessageId, {
|
|
324
|
+
limit: this.messagePageSize,
|
|
325
|
+
[direction === 'older' ? 'id_lt' : 'id_gt']: lastMessageId,
|
|
326
|
+
})
|
|
327
|
+
.then(() => {
|
|
328
|
+
this.activeThreadMessagesSubject.next(activeChnannel?.state.threads[parentMessageId] || []);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* 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.
|
|
333
|
+
* @param filters
|
|
334
|
+
* @param sort
|
|
335
|
+
* @param options
|
|
336
|
+
* @param shouldSetActiveChannel Decides if the first channel in the result should be made as an active channel or not.
|
|
337
|
+
* @returns the list of channels found by the query
|
|
338
|
+
*/
|
|
339
|
+
init(filters, sort, options, shouldSetActiveChannel = true) {
|
|
340
|
+
this.channelQuery = new ChannelQuery(this.chatClientService, this, filters, sort || { last_message_at: -1 }, {
|
|
341
|
+
limit: 25,
|
|
342
|
+
state: true,
|
|
343
|
+
presence: true,
|
|
344
|
+
watch: true,
|
|
345
|
+
message_limit: this.messagePageSize,
|
|
346
|
+
...options,
|
|
347
|
+
});
|
|
348
|
+
this.channelQuery.customPaginator = this._customPaginator;
|
|
349
|
+
return this._init({
|
|
350
|
+
shouldSetActiveChannel,
|
|
351
|
+
messagePageSize: options?.message_limit ?? this.messagePageSize,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* 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.
|
|
356
|
+
* @param query
|
|
357
|
+
* @param options
|
|
358
|
+
* @param options.shouldSetActiveChannel The `shouldSetActiveChannel` specifies if the first channel in the result should be selected as the active channel or not. Default is `true`.
|
|
359
|
+
* @param options.messagePageSize How many messages should we load? The default is 25
|
|
360
|
+
* @returns the channels that were loaded
|
|
361
|
+
*/
|
|
362
|
+
initWithCustomQuery(query, options = {
|
|
363
|
+
shouldSetActiveChannel: true,
|
|
364
|
+
messagePageSize: this.messagePageSize,
|
|
365
|
+
}) {
|
|
366
|
+
this.channelQuery = query;
|
|
367
|
+
return this._init(options);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* 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/).
|
|
371
|
+
*/
|
|
372
|
+
reset() {
|
|
373
|
+
this.deselectActiveChannel();
|
|
374
|
+
this.channelsSubject.next(undefined);
|
|
375
|
+
this.channelQueryStateSubject.next(undefined);
|
|
376
|
+
this.clientEventsSubscription?.unsubscribe();
|
|
377
|
+
this.dismissErrorNotification?.();
|
|
378
|
+
this.dismissErrorNotification = undefined;
|
|
379
|
+
Object.keys(this.channelSubscriptions).forEach((cid) => {
|
|
380
|
+
this.channelSubscriptions[cid]();
|
|
381
|
+
});
|
|
382
|
+
this.channelSubscriptions = {};
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Loads the next page of channels. The page size can be set in the [query option](/chat/docs/javascript/query_channels/#query-options) object.
|
|
386
|
+
*/
|
|
387
|
+
async loadMoreChannels() {
|
|
388
|
+
await this.queryChannels(false, 'next-page');
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Adds a reaction to a message.
|
|
392
|
+
* @param messageId The id of the message to add the reaction to
|
|
393
|
+
* @param reactionType The type of the reaction
|
|
394
|
+
* @param customData
|
|
395
|
+
*/
|
|
396
|
+
async addReaction(messageId, reactionType, customData) {
|
|
397
|
+
await this.activeChannelSubject.getValue()?.sendReaction(messageId, {
|
|
398
|
+
type: reactionType,
|
|
399
|
+
...customData,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Removes a reaction from a message.
|
|
404
|
+
* @param messageId The id of the message to remove the reaction from
|
|
405
|
+
* @param reactionType Thr type of reaction to remove
|
|
406
|
+
*/
|
|
407
|
+
async removeReaction(messageId, reactionType) {
|
|
408
|
+
await this.activeChannelSubject
|
|
409
|
+
.getValue()
|
|
410
|
+
?.deleteReaction(messageId, reactionType);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* 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.
|
|
414
|
+
* @param text The text of the message
|
|
415
|
+
* @param attachments The attachments
|
|
416
|
+
* @param mentionedUsers Mentioned users
|
|
417
|
+
* @param parentId Id of the parent message (if sending a thread reply)
|
|
418
|
+
* @param quotedMessageId Id of the message to quote (if sending a quote reply)
|
|
419
|
+
* @param customData
|
|
420
|
+
* @param pollId Id of the poll (if sending a poll message)
|
|
421
|
+
*/
|
|
422
|
+
async sendMessage(text, attachments = [], mentionedUsers = [], parentId = undefined, quotedMessageId = undefined, customData = undefined, pollId = undefined) {
|
|
423
|
+
let input = {
|
|
424
|
+
text,
|
|
425
|
+
attachments,
|
|
426
|
+
mentionedUsers,
|
|
427
|
+
parentId,
|
|
428
|
+
quotedMessageId,
|
|
429
|
+
customData,
|
|
430
|
+
pollId,
|
|
431
|
+
};
|
|
432
|
+
if (this.beforeSendMessage) {
|
|
433
|
+
input = await this.beforeSendMessage(input);
|
|
434
|
+
}
|
|
435
|
+
const preview = createMessagePreview(this.chatClientService.chatClient.user, input.text, input.attachments, input.mentionedUsers, input.parentId, input.quotedMessageId, input.customData, input.pollId);
|
|
436
|
+
const channel = this.activeChannelSubject.getValue();
|
|
437
|
+
channel.state.addMessageSorted(preview, true);
|
|
438
|
+
const response = await this.sendMessageRequest(preview, input.customData);
|
|
439
|
+
return response;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Resends the given message to the active channel
|
|
443
|
+
* @param message The message to resend
|
|
444
|
+
*/
|
|
445
|
+
async resendMessage(message) {
|
|
446
|
+
const channel = this.activeChannelSubject.getValue();
|
|
447
|
+
channel.state.addMessageSorted({
|
|
448
|
+
...message,
|
|
449
|
+
// @ts-expect-error stream-chat doesn't know about this property
|
|
450
|
+
errorStatusCode: undefined,
|
|
451
|
+
status: 'sending',
|
|
452
|
+
}, true);
|
|
453
|
+
return this.sendMessageRequest(message, undefined, true);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Updates the message in the active channel
|
|
457
|
+
* @param message Mesage to be updated
|
|
458
|
+
*/
|
|
459
|
+
async updateMessage(message) {
|
|
460
|
+
let messageToUpdate = {
|
|
461
|
+
...message,
|
|
462
|
+
};
|
|
463
|
+
if (messageToUpdate.quoted_message) {
|
|
464
|
+
messageToUpdate.quoted_message = {
|
|
465
|
+
...messageToUpdate.quoted_message,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
delete messageToUpdate.i18n;
|
|
469
|
+
if (this.beforeUpdateMessage) {
|
|
470
|
+
messageToUpdate = await this.beforeUpdateMessage(messageToUpdate);
|
|
471
|
+
}
|
|
472
|
+
if (messageToUpdate.readBy) {
|
|
473
|
+
// @ts-expect-error this is only a run time proparty for the SDK
|
|
474
|
+
delete messageToUpdate.readBy;
|
|
475
|
+
}
|
|
476
|
+
if (messageToUpdate.translation) {
|
|
477
|
+
delete messageToUpdate.translation;
|
|
478
|
+
}
|
|
479
|
+
if (messageToUpdate.quoted_message?.translation) {
|
|
480
|
+
delete messageToUpdate.quoted_message.translation;
|
|
481
|
+
}
|
|
482
|
+
if (message.moderation_details) {
|
|
483
|
+
return this.resendMessage(message);
|
|
484
|
+
}
|
|
485
|
+
const response = await this.chatClientService.chatClient.updateMessage(messageToUpdate);
|
|
486
|
+
const channel = this.channelsSubject
|
|
487
|
+
.getValue()
|
|
488
|
+
?.find((c) => c.cid === message.cid);
|
|
489
|
+
if (response.message.type === 'error' &&
|
|
490
|
+
response.message.moderation_details) {
|
|
491
|
+
this.notificationService.addTemporaryNotification('streamChat.This message did not meet our content guidelines');
|
|
492
|
+
return message;
|
|
493
|
+
}
|
|
494
|
+
return this.transformToStreamMessage(response.message, channel);
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Deletes the message from the active channel
|
|
498
|
+
* @param message Message to be deleted
|
|
499
|
+
* @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
|
|
500
|
+
*/
|
|
501
|
+
async deleteMessage(message, isLocalDelete = false) {
|
|
502
|
+
if (isLocalDelete && this.activeChannel) {
|
|
503
|
+
const result = this.activeChannel.state.removeMessage({
|
|
504
|
+
id: message.id,
|
|
505
|
+
parent_id: message.parent_id,
|
|
506
|
+
});
|
|
507
|
+
if (result) {
|
|
508
|
+
message.parent_id
|
|
509
|
+
? this.activeThreadMessagesSubject.next(this.activeChannel.state.threads[message.parent_id])
|
|
510
|
+
: this.activeChannelMessagesSubject.next(this.activeChannel.state.messages);
|
|
511
|
+
}
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
if (this.messageDeleteConfirmationHandler) {
|
|
515
|
+
const result = await this.messageDeleteConfirmationHandler(message);
|
|
516
|
+
if (result) {
|
|
517
|
+
await this.chatClientService.chatClient.deleteMessage(message.id);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
await this.chatClientService.chatClient.deleteMessage(message.id);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Uploads files to the channel. If you want to know more about [file uploads](/chat/docs/javascript/file_uploads/) check out the platform documentation.
|
|
526
|
+
* @param uploads the attachments to upload (output of the [`AttachmentService`](/chat/docs/sdk/angular/services/AttachmentService/))
|
|
527
|
+
* @returns the result of file upload requests
|
|
528
|
+
*/
|
|
529
|
+
async uploadAttachments(uploads) {
|
|
530
|
+
const result = [];
|
|
531
|
+
const channel = this.activeChannelSubject.getValue();
|
|
532
|
+
const uploadResults = await Promise.allSettled(uploads.map((upload) => upload.type === 'image'
|
|
533
|
+
? this.customImageUploadRequest
|
|
534
|
+
? this.customImageUploadRequest(upload.file, channel)
|
|
535
|
+
: channel.sendImage(upload.file, upload.file.name, upload.file.type)
|
|
536
|
+
: this.customFileUploadRequest
|
|
537
|
+
? this.customFileUploadRequest(upload.file, channel)
|
|
538
|
+
: channel.sendFile(upload.file, upload.file.name, upload.file.type)));
|
|
539
|
+
uploadResults.forEach((uploadResult, i) => {
|
|
540
|
+
const file = uploads[i].file;
|
|
541
|
+
const type = uploads[i].type;
|
|
542
|
+
if (uploadResult.status === 'fulfilled') {
|
|
543
|
+
result.push({
|
|
544
|
+
file,
|
|
545
|
+
type,
|
|
546
|
+
state: 'success',
|
|
547
|
+
url: uploadResult.value.file,
|
|
548
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */
|
|
549
|
+
thumb_url: uploadResult.value.thumb_url,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
let reason = 'unknown';
|
|
554
|
+
let extraData;
|
|
555
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */
|
|
556
|
+
const message =
|
|
557
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */
|
|
558
|
+
uploadResult.reason.response?.data?.message;
|
|
559
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */
|
|
560
|
+
const code =
|
|
561
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */
|
|
562
|
+
uploadResult.reason.response?.data?.code;
|
|
563
|
+
if (code === 22 ||
|
|
564
|
+
(code === 4 && message?.toLowerCase()?.includes('bytes'))) {
|
|
565
|
+
reason = 'file-size';
|
|
566
|
+
extraData = {
|
|
567
|
+
param: /\d+MB|\d+\s?bytes/.exec(message || '')?.[0] ||
|
|
568
|
+
`${this.attachmentMaxSizeFallbackInMB}MB`,
|
|
569
|
+
};
|
|
570
|
+
if (extraData.param.includes('bytes')) {
|
|
571
|
+
const limitInBytes = +(/\d+/.exec(extraData.param)?.[0] ||
|
|
572
|
+
this.attachmentMaxSizeFallbackInMB * 1024 * 1024);
|
|
573
|
+
extraData.param = `${limitInBytes / (1024 * 1024)}MB`;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
else if (code === 4 &&
|
|
577
|
+
message?.toLowerCase()?.includes('file extension')) {
|
|
578
|
+
reason = 'file-extension';
|
|
579
|
+
extraData = { param: /\.\w+/.exec(message)?.[0] || '' };
|
|
580
|
+
}
|
|
581
|
+
result.push({
|
|
582
|
+
file,
|
|
583
|
+
type,
|
|
584
|
+
state: 'error',
|
|
585
|
+
errorReason: reason,
|
|
586
|
+
errorExtraInfo: extraData ? [extraData] : undefined,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
return result;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* 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
|
|
594
|
+
* @param attachmentUpload Attachment to be deleted (output of the [`AttachmentService`](/chat/docs/sdk/angular/services/AttachmentService/))
|
|
595
|
+
*/
|
|
596
|
+
async deleteAttachment(attachmentUpload) {
|
|
597
|
+
const channel = this.activeChannelSubject.getValue();
|
|
598
|
+
await (attachmentUpload.type === 'image'
|
|
599
|
+
? this.customImageDeleteRequest
|
|
600
|
+
? this.customImageDeleteRequest(attachmentUpload.url, channel)
|
|
601
|
+
: channel.deleteImage(attachmentUpload.url)
|
|
602
|
+
: this.customFileDeleteRequest
|
|
603
|
+
? this.customFileDeleteRequest(attachmentUpload.url, channel)
|
|
604
|
+
: channel.deleteFile(attachmentUpload.url));
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* 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.
|
|
608
|
+
* @param searchTerm Text to search for in the names of members
|
|
609
|
+
* @returns The list of members matching the search filter
|
|
610
|
+
*/
|
|
611
|
+
async autocompleteMembers(searchTerm) {
|
|
612
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
613
|
+
if (!activeChannel) {
|
|
614
|
+
return [];
|
|
615
|
+
}
|
|
616
|
+
if (Object.keys(activeChannel.state.members).length < 100) {
|
|
617
|
+
return Object.values(activeChannel.state.members).filter((m) => m.user?.id !== this.chatClientService.chatClient.userID);
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
if (!searchTerm) {
|
|
621
|
+
return [];
|
|
622
|
+
}
|
|
623
|
+
const result = await activeChannel.queryMembers({
|
|
624
|
+
name: { $autocomplete: searchTerm },
|
|
625
|
+
}); // TODO: find out why we need typecast here
|
|
626
|
+
return result.members.filter((m) => m.user_id !== this.chatClientService.chatClient?.user?.id);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* [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).
|
|
631
|
+
* @param messageId
|
|
632
|
+
* @param formData
|
|
633
|
+
* @param parentMessageId
|
|
634
|
+
*/
|
|
635
|
+
async sendAction(messageId, formData, parentMessageId) {
|
|
636
|
+
const channel = this.activeChannelSubject.getValue();
|
|
637
|
+
const response = await channel.sendAction(messageId, formData);
|
|
638
|
+
if (response?.message) {
|
|
639
|
+
channel.state.addMessageSorted({
|
|
640
|
+
...response.message,
|
|
641
|
+
status: 'received',
|
|
642
|
+
});
|
|
643
|
+
const isThreadReply = !!response.message.parent_id;
|
|
644
|
+
isThreadReply
|
|
645
|
+
? this.activeThreadMessagesSubject.next([
|
|
646
|
+
...channel.state.threads[response.message.parent_id],
|
|
647
|
+
])
|
|
648
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
channel.state.removeMessage({
|
|
652
|
+
id: messageId,
|
|
653
|
+
parent_id: parentMessageId,
|
|
654
|
+
});
|
|
655
|
+
if (parentMessageId) {
|
|
656
|
+
this.activeThreadMessagesSubject.next(channel.state.threads[this.activeParentMessageIdSubject.getValue()]);
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Selects or deselects the current message to quote reply to
|
|
665
|
+
* @param message The message to select, if called with `undefined`, it deselects the message
|
|
666
|
+
*/
|
|
667
|
+
selectMessageToQuote(message) {
|
|
668
|
+
if (message && !this.isStreamMessage(message)) {
|
|
669
|
+
message = this.transformToStreamMessage(message);
|
|
670
|
+
}
|
|
671
|
+
this.messageToQuoteSubject.next(message);
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Add a new channel to the channel list
|
|
675
|
+
* The channel will be added to the beginning of the channel list
|
|
676
|
+
* @param channel
|
|
677
|
+
*/
|
|
678
|
+
addChannel(channel) {
|
|
679
|
+
if (!this.channels.find((c) => c.cid === channel.cid)) {
|
|
680
|
+
this.channelsSubject.next([channel, ...this.channels]);
|
|
681
|
+
this.watchForChannelEvents(channel);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
*
|
|
686
|
+
* @param cid
|
|
687
|
+
* @param shouldStopWatching
|
|
688
|
+
*/
|
|
689
|
+
removeChannel(cid, shouldStopWatching = true) {
|
|
690
|
+
const remainingChannels = this.channels.filter((c) => c.cid !== cid);
|
|
691
|
+
if (shouldStopWatching) {
|
|
692
|
+
if (this.channelSubscriptions[cid]) {
|
|
693
|
+
this.channelSubscriptions[cid]();
|
|
694
|
+
delete this.channelSubscriptions.cid;
|
|
695
|
+
}
|
|
696
|
+
void this.chatClientService.chatClient.activeChannels[cid]
|
|
697
|
+
?.stopWatching()
|
|
698
|
+
.catch((err) => this.chatClientService.chatClient.logger('warn', 'Failed to unwatch channel', err));
|
|
699
|
+
}
|
|
700
|
+
if (remainingChannels.length < this.channels.length) {
|
|
701
|
+
this.channelsSubject.next(remainingChannels);
|
|
702
|
+
if (cid === this.activeChannelSubject.getValue()?.cid) {
|
|
703
|
+
if (remainingChannels.length > 0) {
|
|
704
|
+
this.setAsActiveChannel(remainingChannels[0]);
|
|
705
|
+
}
|
|
706
|
+
else {
|
|
707
|
+
this.activeChannelSubject.next(undefined);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
async sendMessageRequest(preview, customData, isResend = false) {
|
|
713
|
+
const channel = this.activeChannelSubject.getValue();
|
|
714
|
+
const isThreadReply = !!preview.parent_id;
|
|
715
|
+
isThreadReply
|
|
716
|
+
? this.activeThreadMessagesSubject.next([
|
|
717
|
+
...channel.state.threads[preview.parent_id],
|
|
718
|
+
])
|
|
719
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
720
|
+
try {
|
|
721
|
+
const response = await channel.sendMessage({
|
|
722
|
+
id: preview.id,
|
|
723
|
+
text: preview.text,
|
|
724
|
+
attachments: preview.attachments,
|
|
725
|
+
mentioned_users: preview.mentioned_users?.map((u) => u.id),
|
|
726
|
+
parent_id: preview.parent_id,
|
|
727
|
+
quoted_message_id: preview.quoted_message_id,
|
|
728
|
+
poll_id: preview.poll_id,
|
|
729
|
+
...customData,
|
|
730
|
+
}); // TODO: find out why we need typecast here
|
|
731
|
+
channel.state.addMessageSorted({
|
|
732
|
+
...response.message,
|
|
733
|
+
status: 'received',
|
|
734
|
+
}, true);
|
|
735
|
+
isThreadReply
|
|
736
|
+
? this.activeThreadMessagesSubject.next([
|
|
737
|
+
...channel.state.threads[preview.parent_id],
|
|
738
|
+
])
|
|
739
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
740
|
+
let messages;
|
|
741
|
+
(isThreadReply ? this.activeThreadMessages$ : this.activeChannelMessages$)
|
|
742
|
+
.pipe(take(1))
|
|
743
|
+
.subscribe((m) => (messages = m));
|
|
744
|
+
const newMessage = messages[messages.length - 1];
|
|
745
|
+
return newMessage;
|
|
746
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
747
|
+
}
|
|
748
|
+
catch (error) {
|
|
749
|
+
const stringError = JSON.stringify(error);
|
|
750
|
+
const parsedError = stringError ? JSON.parse(stringError) : {};
|
|
751
|
+
let isAlreadyExists = false;
|
|
752
|
+
if (isResend) {
|
|
753
|
+
if (parsedError.status === 400 &&
|
|
754
|
+
parsedError.code === 4 &&
|
|
755
|
+
parsedError?.response?.data?.message?.includes('already exists')) {
|
|
756
|
+
isAlreadyExists = true;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
channel.state.addMessageSorted({
|
|
760
|
+
...preview,
|
|
761
|
+
// @ts-expect-error stream-chat doesn't know about this property
|
|
762
|
+
errorStatusCode: isAlreadyExists
|
|
763
|
+
? undefined
|
|
764
|
+
: parsedError.status || undefined,
|
|
765
|
+
status: isAlreadyExists ? 'received' : 'failed',
|
|
766
|
+
}, true);
|
|
767
|
+
isThreadReply
|
|
768
|
+
? this.activeThreadMessagesSubject.next([
|
|
769
|
+
...channel.state.threads[preview.parent_id],
|
|
770
|
+
])
|
|
771
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
772
|
+
let messages;
|
|
773
|
+
(isThreadReply ? this.activeThreadMessages$ : this.activeChannelMessages$)
|
|
774
|
+
.pipe(take(1))
|
|
775
|
+
.subscribe((m) => (messages = m));
|
|
776
|
+
const newMessage = messages[messages.length - 1];
|
|
777
|
+
return newMessage;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* 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.
|
|
782
|
+
* @param messageId The ID of the message to be loaded, 'latest' means jump to the latest messages
|
|
783
|
+
* @param parentMessageId The ID of the parent message if we want to load a thread message
|
|
784
|
+
*/
|
|
785
|
+
async jumpToMessage(messageId, parentMessageId) {
|
|
786
|
+
this.isMessageLoadingInProgress = true;
|
|
787
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
788
|
+
try {
|
|
789
|
+
await activeChannel?.state.loadMessageIntoState(messageId, parentMessageId);
|
|
790
|
+
const messages = activeChannel?.state.messages || [];
|
|
791
|
+
this.activeChannelMessagesSubject.next([...messages]);
|
|
792
|
+
if (parentMessageId) {
|
|
793
|
+
const parentMessage = messages.find((m) => m.id === parentMessageId);
|
|
794
|
+
void this.setAsActiveParentMessage(parentMessage, 'state');
|
|
795
|
+
}
|
|
796
|
+
this.jumpToMessageSubject.next({
|
|
797
|
+
id: messageId,
|
|
798
|
+
parentId: parentMessageId,
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
catch (error) {
|
|
802
|
+
this.notificationService.addTemporaryNotification('streamChat.Message not found');
|
|
803
|
+
throw error;
|
|
804
|
+
}
|
|
805
|
+
finally {
|
|
806
|
+
this.isMessageLoadingInProgress = false;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Clears the currently selected message to jump
|
|
811
|
+
*/
|
|
812
|
+
clearMessageJump() {
|
|
813
|
+
this.jumpToMessageSubject.next({ id: undefined, parentId: undefined });
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Pins the given message in the channel
|
|
817
|
+
* @param message
|
|
818
|
+
*/
|
|
819
|
+
async pinMessage(message) {
|
|
820
|
+
try {
|
|
821
|
+
await this.chatClientService.chatClient?.pinMessage(message);
|
|
822
|
+
this.notificationService.addTemporaryNotification('streamChat.Message pinned', 'success');
|
|
823
|
+
}
|
|
824
|
+
catch (error) {
|
|
825
|
+
this.notificationService.addTemporaryNotification('streamChat.Error pinning message');
|
|
826
|
+
throw error;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Removes the given message from pinned messages
|
|
831
|
+
* @param message
|
|
832
|
+
*/
|
|
833
|
+
async unpinMessage(message) {
|
|
834
|
+
try {
|
|
835
|
+
await this.chatClientService.chatClient?.unpinMessage(message);
|
|
836
|
+
this.notificationService.addTemporaryNotification('streamChat.Message unpinned', 'success');
|
|
837
|
+
}
|
|
838
|
+
catch (error) {
|
|
839
|
+
this.notificationService.addTemporaryNotification('streamChat.Error removing message pin');
|
|
840
|
+
throw error;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
handleNotification(clientEvent) {
|
|
844
|
+
switch (clientEvent.eventType) {
|
|
845
|
+
case 'connection.recovered': {
|
|
846
|
+
void this.ngZone.run(async () => {
|
|
847
|
+
if (this.isStateRecoveryInProgress) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
this.isStateRecoveryInProgress = true;
|
|
851
|
+
try {
|
|
852
|
+
// If channel list is not inited, we set the active channel
|
|
853
|
+
const shoulSetActiveChannel = this.shouldSetActiveChannel &&
|
|
854
|
+
!this.activeChannelSubject.getValue();
|
|
855
|
+
await this.queryChannels(shoulSetActiveChannel || false, 'recover-state');
|
|
856
|
+
if (this.activeChannelSubject.getValue()) {
|
|
857
|
+
// Thread messages are not refetched so active thread gets deselected to avoid displaying stale messages
|
|
858
|
+
void this.setAsActiveParentMessage(undefined);
|
|
859
|
+
// Update and reselect message to quote
|
|
860
|
+
const messageToQuote = this.messageToQuoteSubject.getValue();
|
|
861
|
+
this.setChannelState(this.activeChannelSubject.getValue());
|
|
862
|
+
let messages;
|
|
863
|
+
this.activeChannelMessages$
|
|
864
|
+
.pipe(take(1))
|
|
865
|
+
.subscribe((m) => (messages = m));
|
|
866
|
+
const updatedMessageToQuote = messages.find((m) => m.id === messageToQuote?.id);
|
|
867
|
+
if (updatedMessageToQuote) {
|
|
868
|
+
this.selectMessageToQuote(updatedMessageToQuote);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
this.isStateRecoveryInProgress = false;
|
|
872
|
+
}
|
|
873
|
+
catch {
|
|
874
|
+
this.isStateRecoveryInProgress = false;
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
break;
|
|
878
|
+
}
|
|
879
|
+
case 'notification.message_new': {
|
|
880
|
+
this.ngZone.run(() => {
|
|
881
|
+
if (this.customNewMessageNotificationHandler) {
|
|
882
|
+
this.customNewMessageNotificationHandler(clientEvent, this.channelListSetter);
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
this.handleNewMessageNotification(clientEvent);
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
case 'notification.added_to_channel': {
|
|
891
|
+
this.ngZone.run(() => {
|
|
892
|
+
if (this.customAddedToChannelNotificationHandler) {
|
|
893
|
+
this.customAddedToChannelNotificationHandler(clientEvent, this.channelListSetter);
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
this.handleAddedToChannelNotification(clientEvent);
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
case 'notification.removed_from_channel': {
|
|
902
|
+
this.ngZone.run(() => {
|
|
903
|
+
if (this.customRemovedFromChannelNotificationHandler) {
|
|
904
|
+
this.customRemovedFromChannelNotificationHandler(clientEvent, this.channelListSetter);
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
this.handleRemovedFromChannelNotification(clientEvent);
|
|
908
|
+
}
|
|
909
|
+
});
|
|
910
|
+
break;
|
|
911
|
+
}
|
|
912
|
+
case 'user.updated': {
|
|
913
|
+
this.ngZone.run(() => {
|
|
914
|
+
const updatedChannels = this.channelsSubject.getValue()?.map((c) => {
|
|
915
|
+
if (this.chatClientService.chatClient.activeChannels[c.cid]) {
|
|
916
|
+
return this.chatClientService.chatClient.activeChannels[c.cid];
|
|
917
|
+
}
|
|
918
|
+
else {
|
|
919
|
+
return c;
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
this.channelsSubject.next(updatedChannels);
|
|
923
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
924
|
+
if (activeChannel) {
|
|
925
|
+
this.activeChannelSubject.next(this.chatClientService.chatClient.activeChannels[activeChannel.cid] || activeChannel);
|
|
926
|
+
this.activeChannelMessagesSubject.next(activeChannel.state.messages.map((m) => {
|
|
927
|
+
m.readBy = getReadBy(m, activeChannel);
|
|
928
|
+
return { ...m };
|
|
929
|
+
}));
|
|
930
|
+
const activeParentMessage = this.activeParentMessageIdSubject.getValue();
|
|
931
|
+
if (activeParentMessage) {
|
|
932
|
+
const messages = activeChannel.state.threads[activeParentMessage];
|
|
933
|
+
this.activeThreadMessagesSubject.next([...messages]);
|
|
934
|
+
}
|
|
935
|
+
this.activeChannelPinnedMessagesSubject.next([
|
|
936
|
+
...activeChannel.state.pinnedMessages,
|
|
937
|
+
]);
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
handleRemovedFromChannelNotification(clientEvent) {
|
|
945
|
+
const channelIdToBeRemoved = clientEvent.event.channel.cid;
|
|
946
|
+
this.removeChannel(channelIdToBeRemoved, true);
|
|
947
|
+
}
|
|
948
|
+
handleNewMessageNotification(clientEvent) {
|
|
949
|
+
if (clientEvent.event.channel) {
|
|
950
|
+
void this.addChannelFromNotification(clientEvent.event.channel);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
handleAddedToChannelNotification(clientEvent) {
|
|
954
|
+
if (clientEvent.event.channel) {
|
|
955
|
+
void this.addChannelFromNotification(clientEvent.event.channel);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
async addChannelFromNotification(channelResponse) {
|
|
959
|
+
const newChannel = this.chatClientService.chatClient.channel(channelResponse.type, channelResponse.id);
|
|
960
|
+
let currentChannels = this.channelsSubject.getValue() || [];
|
|
961
|
+
if (currentChannels.find((c) => c.cid === newChannel.cid)) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
await newChannel.watch().catch((err) => {
|
|
965
|
+
this.chatClientService.chatClient.logger('error', 'Failed to add channel to channel list because watch request failed', err);
|
|
966
|
+
});
|
|
967
|
+
currentChannels = this.channelsSubject.getValue() || [];
|
|
968
|
+
if (currentChannels.find((c) => c.cid === newChannel.cid)) {
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
this.watchForChannelEvents(newChannel);
|
|
972
|
+
this.channelsSubject.next([newChannel, ...currentChannels]);
|
|
973
|
+
}
|
|
974
|
+
watchForActiveChannelEvents(channel) {
|
|
975
|
+
this.activeChannelSubscriptions.push(channel.on('message.new', (event) => {
|
|
976
|
+
this.ngZone.run(() => {
|
|
977
|
+
event.message && event.message.parent_id
|
|
978
|
+
? event.message.parent_id ===
|
|
979
|
+
this.activeParentMessageIdSubject.getValue()
|
|
980
|
+
? this.activeThreadMessagesSubject.next([
|
|
981
|
+
...channel.state.threads[event.message.parent_id],
|
|
982
|
+
])
|
|
983
|
+
: null
|
|
984
|
+
: this.activeChannelMessagesSubject.next([
|
|
985
|
+
...channel.state.messages,
|
|
986
|
+
]);
|
|
987
|
+
this.activeChannel$.pipe(first()).subscribe((c) => {
|
|
988
|
+
if (c) {
|
|
989
|
+
this.markRead(c);
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
this.updateLatestMessages(event);
|
|
993
|
+
});
|
|
994
|
+
}));
|
|
995
|
+
this.activeChannelSubscriptions.push(channel.on('message.updated', (event) => this.messageUpdated(event)));
|
|
996
|
+
this.activeChannelSubscriptions.push(channel.on('message.deleted', (event) => this.messageUpdated(event)));
|
|
997
|
+
this.activeChannelSubscriptions.push(channel.on('reaction.new', (e) => this.messageReactionEventReceived(e)));
|
|
998
|
+
this.activeChannelSubscriptions.push(channel.on('reaction.deleted', (e) => this.messageReactionEventReceived(e)));
|
|
999
|
+
this.activeChannelSubscriptions.push(channel.on('reaction.updated', (e) => this.messageReactionEventReceived(e)));
|
|
1000
|
+
this.activeChannelSubscriptions.push(channel.on('message.read', (e) => {
|
|
1001
|
+
this.ngZone.run(() => {
|
|
1002
|
+
let latestMessage;
|
|
1003
|
+
let messages;
|
|
1004
|
+
this.activeChannelMessages$.pipe(first()).subscribe((m) => {
|
|
1005
|
+
messages = m;
|
|
1006
|
+
latestMessage = messages[messages.length - 1];
|
|
1007
|
+
});
|
|
1008
|
+
if (!latestMessage || !e.user) {
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
if (latestMessage.readBy) {
|
|
1012
|
+
latestMessage.readBy.splice(0, latestMessage.readBy.length);
|
|
1013
|
+
}
|
|
1014
|
+
else {
|
|
1015
|
+
latestMessage.readBy = [];
|
|
1016
|
+
}
|
|
1017
|
+
latestMessage.readBy.push(...getReadBy(latestMessage, channel));
|
|
1018
|
+
messages[messages.length - 1] = { ...latestMessage };
|
|
1019
|
+
this.activeChannelMessagesSubject.next([...messages]);
|
|
1020
|
+
});
|
|
1021
|
+
}));
|
|
1022
|
+
this.activeChannelSubscriptions.push(this.chatClientService.events$
|
|
1023
|
+
.pipe(filter((e) => e.eventType === 'notification.mark_unread' &&
|
|
1024
|
+
e.event.channel_id === channel.id), map((e) => e.event))
|
|
1025
|
+
.subscribe((e) => {
|
|
1026
|
+
this.ngZone.run(() => {
|
|
1027
|
+
this.activeChannelLastReadMessageId = e.last_read_message_id;
|
|
1028
|
+
this.activeChannelUnreadCount = e.unread_messages;
|
|
1029
|
+
this.activeChannelSubject.next(this.activeChannel);
|
|
1030
|
+
});
|
|
1031
|
+
}));
|
|
1032
|
+
this.activeChannelSubscriptions.push(channel.on('typing.start', (e) => this.ngZone.run(() => this.handleTypingStartEvent(e))));
|
|
1033
|
+
this.activeChannelSubscriptions.push(channel.on('typing.stop', (e) => this.ngZone.run(() => this.handleTypingStopEvent(e))));
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Call this method if user started typing in the active channel
|
|
1037
|
+
* @param parentId The id of the parent message, if user is typing in a thread
|
|
1038
|
+
*/
|
|
1039
|
+
async typingStarted(parentId) {
|
|
1040
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
1041
|
+
await activeChannel?.keystroke(parentId);
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Call this method if user stopped typing in the active channel
|
|
1045
|
+
* @param parentId The id of the parent message, if user were typing in a thread
|
|
1046
|
+
*/
|
|
1047
|
+
async typingStopped(parentId) {
|
|
1048
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
1049
|
+
await activeChannel?.stopTyping(parentId);
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* The current list of channels
|
|
1053
|
+
*/
|
|
1054
|
+
get channels() {
|
|
1055
|
+
return this.channelsSubject.getValue() || [];
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* The current active channel
|
|
1059
|
+
*/
|
|
1060
|
+
get activeChannel() {
|
|
1061
|
+
return this.activeChannelSubject.getValue() || undefined;
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* The current active channel messages
|
|
1065
|
+
*/
|
|
1066
|
+
get activeChannelMessages() {
|
|
1067
|
+
return this.activeChannelMessagesSubject.getValue() || [];
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* The current thread replies
|
|
1071
|
+
*/
|
|
1072
|
+
get activeChannelThreadReplies() {
|
|
1073
|
+
return this.activeThreadMessagesSubject.getValue() || [];
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* 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).
|
|
1077
|
+
* @deprecated use [`messageReactionsService.queryReactions()`](/chat/docs/sdk/angular/services/MessageReactionsService/#queryreactions) instead
|
|
1078
|
+
* @param messageId
|
|
1079
|
+
* @returns all reactions of a message
|
|
1080
|
+
*/
|
|
1081
|
+
async getMessageReactions(messageId) {
|
|
1082
|
+
const reactions = [];
|
|
1083
|
+
const limit = 300;
|
|
1084
|
+
let offset = 0;
|
|
1085
|
+
const reactionsLimit = ChannelService.MAX_MESSAGE_REACTIONS_TO_FETCH;
|
|
1086
|
+
let lastPageSize = limit;
|
|
1087
|
+
while (lastPageSize === limit && reactions.length < reactionsLimit) {
|
|
1088
|
+
try {
|
|
1089
|
+
const response = await this.activeChannel?.getReactions(messageId, {
|
|
1090
|
+
offset,
|
|
1091
|
+
limit,
|
|
1092
|
+
});
|
|
1093
|
+
lastPageSize = response?.reactions?.length || 0;
|
|
1094
|
+
if (lastPageSize > 0) {
|
|
1095
|
+
reactions.push(...response.reactions);
|
|
1096
|
+
}
|
|
1097
|
+
offset += lastPageSize;
|
|
1098
|
+
}
|
|
1099
|
+
catch (e) {
|
|
1100
|
+
this.notificationService.addTemporaryNotification('streamChat.Error loading reactions');
|
|
1101
|
+
throw e;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
return reactions;
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Marks the channel from the given message as unread
|
|
1108
|
+
* @param messageId
|
|
1109
|
+
* @returns the result of the request
|
|
1110
|
+
*/
|
|
1111
|
+
async markMessageUnread(messageId) {
|
|
1112
|
+
if (!this.activeChannel) {
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
try {
|
|
1116
|
+
const response = await this.activeChannel.markUnread({
|
|
1117
|
+
message_id: messageId,
|
|
1118
|
+
});
|
|
1119
|
+
this.areReadEventsPaused = true;
|
|
1120
|
+
return response;
|
|
1121
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1122
|
+
}
|
|
1123
|
+
catch (e) {
|
|
1124
|
+
const error = JSON.parse(JSON.stringify(e));
|
|
1125
|
+
const data = error?.response?.data;
|
|
1126
|
+
if (data &&
|
|
1127
|
+
data.code === 4 &&
|
|
1128
|
+
data.StatusCode === 400 &&
|
|
1129
|
+
data.message?.includes('it is older than last')) {
|
|
1130
|
+
const count = /\d+ channel messages/
|
|
1131
|
+
.exec(data.message)?.[0]
|
|
1132
|
+
.match(/\d+/)?.[0];
|
|
1133
|
+
if (count) {
|
|
1134
|
+
this.notificationService.addTemporaryNotification('streamChat.Error, only the first {{count}} message can be marked as unread', undefined, undefined, { count });
|
|
1135
|
+
throw e;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
this.notificationService.addTemporaryNotification('streamChat.Error marking message as unread');
|
|
1139
|
+
throw e;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
messageUpdated(event) {
|
|
1143
|
+
this.ngZone.run(() => {
|
|
1144
|
+
const isThreadReply = event.message && event.message.parent_id;
|
|
1145
|
+
const channel = this.activeChannelSubject.getValue();
|
|
1146
|
+
if (!channel) {
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
// Get messages from state as message order could change, and message could've been deleted
|
|
1150
|
+
const messages = isThreadReply
|
|
1151
|
+
? channel.state.threads[event?.message?.parent_id || '']
|
|
1152
|
+
: channel.state.messages;
|
|
1153
|
+
if (!messages) {
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
const messageIndex = messages.findIndex((m) => m.id === event?.message?.id);
|
|
1157
|
+
if (messageIndex !== -1 || event.type === 'message.deleted') {
|
|
1158
|
+
isThreadReply
|
|
1159
|
+
? this.activeThreadMessagesSubject.next([...messages])
|
|
1160
|
+
: this.activeChannelMessagesSubject.next([...messages]);
|
|
1161
|
+
this.activeChannelPinnedMessagesSubject.next([
|
|
1162
|
+
...channel.state.pinnedMessages,
|
|
1163
|
+
]);
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
messageReactionEventReceived(e) {
|
|
1168
|
+
this.ngZone.run(() => {
|
|
1169
|
+
const isThreadMessage = e.message && e.message.parent_id;
|
|
1170
|
+
let messages;
|
|
1171
|
+
(isThreadMessage
|
|
1172
|
+
? this.activeThreadMessages$
|
|
1173
|
+
: this.activeChannelMessages$)
|
|
1174
|
+
.pipe(first())
|
|
1175
|
+
.subscribe((m) => (messages = m));
|
|
1176
|
+
const messageIndex = messages.findIndex((m) => m.id === e?.message?.id);
|
|
1177
|
+
if (messageIndex === -1) {
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
const message = messages[messageIndex];
|
|
1181
|
+
message.reaction_counts = { ...e.message?.reaction_counts };
|
|
1182
|
+
message.reaction_scores = { ...e.message?.reaction_scores };
|
|
1183
|
+
message.latest_reactions = [...(e.message?.latest_reactions || [])];
|
|
1184
|
+
message.own_reactions = [...(e.message?.own_reactions || [])];
|
|
1185
|
+
message.reaction_groups = { ...e.message?.reaction_groups };
|
|
1186
|
+
messages[messageIndex] = { ...message };
|
|
1187
|
+
isThreadMessage
|
|
1188
|
+
? this.activeThreadMessagesSubject.next([...messages])
|
|
1189
|
+
: this.activeChannelMessagesSubject.next([...messages]);
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
formatMessage(message) {
|
|
1193
|
+
const m = message;
|
|
1194
|
+
m.pinned_at = message.pinned_at ? new Date(message.pinned_at) : null;
|
|
1195
|
+
m.created_at = message.created_at
|
|
1196
|
+
? new Date(message.created_at)
|
|
1197
|
+
: new Date();
|
|
1198
|
+
m.updated_at = message.updated_at
|
|
1199
|
+
? new Date(message.updated_at)
|
|
1200
|
+
: new Date();
|
|
1201
|
+
message.status = message.status || 'received';
|
|
1202
|
+
return m;
|
|
1203
|
+
}
|
|
1204
|
+
isStreamMessage(message) {
|
|
1205
|
+
return 'readBy' in message;
|
|
1206
|
+
}
|
|
1207
|
+
isFormatMessageResponse(message) {
|
|
1208
|
+
return message.created_at instanceof Date;
|
|
1209
|
+
}
|
|
1210
|
+
stopWatchForActiveChannelEvents(channel) {
|
|
1211
|
+
if (!channel) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
this.activeChannelSubscriptions.forEach((s) => s.unsubscribe());
|
|
1215
|
+
this.activeChannelSubscriptions = [];
|
|
1216
|
+
}
|
|
1217
|
+
async queryChannels(shouldSetActiveChannel, queryType) {
|
|
1218
|
+
if (!this.channelQuery) {
|
|
1219
|
+
throw new Error('Query channels called before initializing ChannelQuery instance');
|
|
1220
|
+
}
|
|
1221
|
+
try {
|
|
1222
|
+
this.channelQueryStateSubject.next({ state: 'in-progress' });
|
|
1223
|
+
const { channels, hasMorePage } = await ('query' in this.channelQuery
|
|
1224
|
+
? this.channelQuery.query(queryType)
|
|
1225
|
+
: this.channelQuery(queryType));
|
|
1226
|
+
const filteredChannels = channels.filter((channel, index) => !channels.slice(0, index).find((c) => c.cid === channel.cid));
|
|
1227
|
+
filteredChannels.forEach((c) => {
|
|
1228
|
+
if (!this.channelSubscriptions[c.cid]) {
|
|
1229
|
+
this.watchForChannelEvents(c);
|
|
1230
|
+
}
|
|
1231
|
+
});
|
|
1232
|
+
this.channelsSubject.next(filteredChannels);
|
|
1233
|
+
const currentActiveChannel = this.activeChannelSubject.getValue();
|
|
1234
|
+
if (currentActiveChannel &&
|
|
1235
|
+
!filteredChannels.find((c) => c.cid === currentActiveChannel?.cid)) {
|
|
1236
|
+
this.deselectActiveChannel();
|
|
1237
|
+
}
|
|
1238
|
+
else if (filteredChannels.length > 0 &&
|
|
1239
|
+
!currentActiveChannel &&
|
|
1240
|
+
shouldSetActiveChannel) {
|
|
1241
|
+
this.setAsActiveChannel(filteredChannels[0]);
|
|
1242
|
+
}
|
|
1243
|
+
this.hasMoreChannelsSubject.next(hasMorePage);
|
|
1244
|
+
this.channelQueryStateSubject.next({ state: 'success' });
|
|
1245
|
+
this.dismissErrorNotification?.();
|
|
1246
|
+
return channels;
|
|
1247
|
+
}
|
|
1248
|
+
catch (error) {
|
|
1249
|
+
this.channelQueryStateSubject.next({
|
|
1250
|
+
state: 'error',
|
|
1251
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1252
|
+
error,
|
|
1253
|
+
});
|
|
1254
|
+
throw error;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
watchForChannelEvents(channel) {
|
|
1258
|
+
if (this.channelSubscriptions[channel.cid]) {
|
|
1259
|
+
this.channelSubscriptions[channel.cid]();
|
|
1260
|
+
}
|
|
1261
|
+
const unsubscribe = channel.on((event) => {
|
|
1262
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
1263
|
+
const type = event.type;
|
|
1264
|
+
switch (type) {
|
|
1265
|
+
case 'message.new': {
|
|
1266
|
+
this.ngZone.run(() => {
|
|
1267
|
+
if (this.customNewMessageHandler) {
|
|
1268
|
+
this.customNewMessageHandler(event, channel, this.channelListSetter, this.messageListSetter, this.threadListSetter, this.parentMessageSetter);
|
|
1269
|
+
}
|
|
1270
|
+
else {
|
|
1271
|
+
this.handleNewMessage(event, channel);
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1276
|
+
case 'channel.hidden': {
|
|
1277
|
+
this.ngZone.run(() => {
|
|
1278
|
+
if (this.customChannelHiddenHandler) {
|
|
1279
|
+
this.customChannelHiddenHandler(event, channel, this.channelListSetter, this.messageListSetter, this.threadListSetter, this.parentMessageSetter);
|
|
1280
|
+
}
|
|
1281
|
+
else {
|
|
1282
|
+
this.handleChannelHidden(event);
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
break;
|
|
1286
|
+
}
|
|
1287
|
+
case 'channel.deleted': {
|
|
1288
|
+
this.ngZone.run(() => {
|
|
1289
|
+
if (this.customChannelDeletedHandler) {
|
|
1290
|
+
this.customChannelDeletedHandler(event, channel, this.channelListSetter, this.messageListSetter, this.threadListSetter, this.parentMessageSetter);
|
|
1291
|
+
}
|
|
1292
|
+
else {
|
|
1293
|
+
this.handleChannelDeleted(event);
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1296
|
+
break;
|
|
1297
|
+
}
|
|
1298
|
+
case 'channel.visible': {
|
|
1299
|
+
this.ngZone.run(() => {
|
|
1300
|
+
if (this.customChannelVisibleHandler) {
|
|
1301
|
+
this.customChannelVisibleHandler(event, channel, this.channelListSetter, this.messageListSetter, this.threadListSetter, this.parentMessageSetter);
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
this.handleChannelVisible(event, channel);
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
break;
|
|
1308
|
+
}
|
|
1309
|
+
case 'channel.updated': {
|
|
1310
|
+
this.ngZone.run(() => {
|
|
1311
|
+
if (this.customChannelUpdatedHandler) {
|
|
1312
|
+
this.customChannelUpdatedHandler(event, channel, this.channelListSetter, this.messageListSetter, this.threadListSetter, this.parentMessageSetter);
|
|
1313
|
+
}
|
|
1314
|
+
else {
|
|
1315
|
+
this.handleChannelUpdate(event);
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
1318
|
+
break;
|
|
1319
|
+
}
|
|
1320
|
+
case 'channel.truncated': {
|
|
1321
|
+
this.ngZone.run(() => {
|
|
1322
|
+
if (this.customChannelTruncatedHandler) {
|
|
1323
|
+
this.customChannelTruncatedHandler(event, channel, this.channelListSetter, this.messageListSetter, this.threadListSetter, this.parentMessageSetter);
|
|
1324
|
+
}
|
|
1325
|
+
else {
|
|
1326
|
+
this.handleChannelTruncate(event);
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
break;
|
|
1330
|
+
}
|
|
1331
|
+
case 'capabilities.changed': {
|
|
1332
|
+
this.ngZone.run(() => {
|
|
1333
|
+
const cid = event.cid;
|
|
1334
|
+
if (cid) {
|
|
1335
|
+
const currentChannels = this.channelsSubject.getValue();
|
|
1336
|
+
const index = currentChannels?.findIndex((c) => c.cid === cid);
|
|
1337
|
+
if (index !== -1 && index !== undefined) {
|
|
1338
|
+
this.channelsSubject.next([...currentChannels]);
|
|
1339
|
+
if (cid === this.activeChannelSubject.getValue()?.cid) {
|
|
1340
|
+
this.activeChannelSubject.next(this.activeChannelSubject.getValue());
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
});
|
|
1345
|
+
break;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
});
|
|
1349
|
+
this.channelSubscriptions[channel.cid] = unsubscribe.unsubscribe;
|
|
1350
|
+
}
|
|
1351
|
+
handleNewMessage(_, channel) {
|
|
1352
|
+
const channelIndex = this.channels.findIndex((c) => c.cid === channel.cid);
|
|
1353
|
+
this.channels.splice(channelIndex, 1);
|
|
1354
|
+
this.channelsSubject.next([channel, ...this.channels]);
|
|
1355
|
+
}
|
|
1356
|
+
handleChannelHidden(event) {
|
|
1357
|
+
this.removeChannel(event.channel.cid, false);
|
|
1358
|
+
}
|
|
1359
|
+
handleChannelDeleted(event) {
|
|
1360
|
+
this.removeChannel(event.channel.cid, false);
|
|
1361
|
+
}
|
|
1362
|
+
handleChannelVisible(event, channel) {
|
|
1363
|
+
if (!this.channels.find((c) => c.cid === event.cid)) {
|
|
1364
|
+
this.ngZone.run(() => this.channelsSubject.next([...this.channels, channel]));
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
handleChannelUpdate(event) {
|
|
1368
|
+
const channelIndex = this.channels.findIndex((c) => c.cid === event.channel.cid);
|
|
1369
|
+
if (channelIndex !== -1) {
|
|
1370
|
+
const channel = this.channels[channelIndex];
|
|
1371
|
+
const notIncludedProperies = {
|
|
1372
|
+
hidden: channel.data?.hidden || false,
|
|
1373
|
+
own_capabilities: channel.data?.own_capabilities || [],
|
|
1374
|
+
};
|
|
1375
|
+
channel.data = {
|
|
1376
|
+
...event.channel,
|
|
1377
|
+
...notIncludedProperies,
|
|
1378
|
+
};
|
|
1379
|
+
this.channelsSubject.next([...this.channels]);
|
|
1380
|
+
if (event.channel?.cid === this.activeChannelSubject.getValue()?.cid) {
|
|
1381
|
+
this.activeChannelSubject.next(channel);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
handleChannelTruncate(event) {
|
|
1386
|
+
const channelIndex = this.channels.findIndex((c) => c.cid === event.channel.cid);
|
|
1387
|
+
if (channelIndex !== -1) {
|
|
1388
|
+
this.channels[channelIndex].state.messages = [];
|
|
1389
|
+
this.channelsSubject.next([...this.channels]);
|
|
1390
|
+
if (event.channel?.cid === this.activeChannelSubject.getValue()?.cid) {
|
|
1391
|
+
const channel = this.activeChannelSubject.getValue();
|
|
1392
|
+
channel.state.messages = [];
|
|
1393
|
+
this.activeChannelSubject.next(channel);
|
|
1394
|
+
this.activeChannelMessagesSubject.next([]);
|
|
1395
|
+
this.activeParentMessageIdSubject.next(undefined);
|
|
1396
|
+
this.activeThreadMessagesSubject.next([]);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
get canSendReadEvents() {
|
|
1401
|
+
const channel = this.activeChannelSubject.getValue();
|
|
1402
|
+
if (!channel) {
|
|
1403
|
+
return false;
|
|
1404
|
+
}
|
|
1405
|
+
const capabilites = channel.data?.own_capabilities;
|
|
1406
|
+
return capabilites.indexOf('read-events') !== -1;
|
|
1407
|
+
}
|
|
1408
|
+
transformToStreamMessage(message, channel) {
|
|
1409
|
+
const isThreadMessage = !!message.parent_id;
|
|
1410
|
+
if (this.isStreamMessage(message) &&
|
|
1411
|
+
this.isFormatMessageResponse(message)) {
|
|
1412
|
+
if (message.quoted_message) {
|
|
1413
|
+
message.quoted_message.translation = getMessageTranslation(message.quoted_message, channel, this.chatClientService.chatClient.user);
|
|
1414
|
+
}
|
|
1415
|
+
message.translation = getMessageTranslation(message, channel, this.chatClientService.chatClient.user);
|
|
1416
|
+
return message;
|
|
1417
|
+
}
|
|
1418
|
+
else {
|
|
1419
|
+
if (message.quoted_message) {
|
|
1420
|
+
message.quoted_message.translation =
|
|
1421
|
+
getMessageTranslation(message.quoted_message, channel, this.chatClientService.chatClient.user);
|
|
1422
|
+
}
|
|
1423
|
+
if (this.isFormatMessageResponse(message)) {
|
|
1424
|
+
message.readBy = isThreadMessage
|
|
1425
|
+
? []
|
|
1426
|
+
: channel
|
|
1427
|
+
? getReadBy(message, channel)
|
|
1428
|
+
: [];
|
|
1429
|
+
message.translation = getMessageTranslation(message, channel, this.chatClientService.chatClient.user);
|
|
1430
|
+
return message;
|
|
1431
|
+
}
|
|
1432
|
+
else {
|
|
1433
|
+
message = this.formatMessage(message);
|
|
1434
|
+
message.readBy = isThreadMessage
|
|
1435
|
+
? []
|
|
1436
|
+
: channel
|
|
1437
|
+
? getReadBy(message, channel)
|
|
1438
|
+
: [];
|
|
1439
|
+
message.translation = getMessageTranslation(message, channel, this.chatClientService.chatClient.user);
|
|
1440
|
+
return message;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
handleTypingStartEvent(event) {
|
|
1445
|
+
if (event.user?.id === this.chatClientService.chatClient.user?.id) {
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
const isTypingInThread = !!event.parent_id;
|
|
1449
|
+
if (isTypingInThread &&
|
|
1450
|
+
event.parent_id !== this.activeParentMessageIdSubject.getValue()) {
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
const subject = isTypingInThread
|
|
1454
|
+
? this.usersTypingInThreadSubject
|
|
1455
|
+
: this.usersTypingInChannelSubject;
|
|
1456
|
+
const users = subject.getValue();
|
|
1457
|
+
const user = event.user;
|
|
1458
|
+
if (user && !users.find((u) => u.id === user.id)) {
|
|
1459
|
+
users.push(user);
|
|
1460
|
+
subject.next([...users]);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
handleTypingStopEvent(event) {
|
|
1464
|
+
const usersTypingInChannel = this.usersTypingInChannelSubject.getValue();
|
|
1465
|
+
const usersTypingInThread = this.usersTypingInThreadSubject.getValue();
|
|
1466
|
+
const user = event.user;
|
|
1467
|
+
if (user && usersTypingInChannel.find((u) => u.id === user.id)) {
|
|
1468
|
+
usersTypingInChannel.splice(usersTypingInChannel.findIndex((u) => u.id === user.id), 1);
|
|
1469
|
+
this.usersTypingInChannelSubject.next([...usersTypingInChannel]);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
if (user && usersTypingInThread.find((u) => u.id === user.id)) {
|
|
1473
|
+
usersTypingInThread.splice(usersTypingInThread.findIndex((u) => u.id === user.id), 1);
|
|
1474
|
+
this.usersTypingInThreadSubject.next([...usersTypingInThread]);
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
updateLatestMessages(event) {
|
|
1479
|
+
if (event.message?.user?.id !== this.chatClientService?.chatClient.user?.id) {
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
const latestMessages = this.latestMessageDateByUserByChannelsSubject.getValue();
|
|
1483
|
+
if (!event.message?.created_at) {
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
const channelId = event?.message?.cid;
|
|
1487
|
+
if (!channelId) {
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
const messageDate = new Date(event.message.created_at);
|
|
1491
|
+
if (!latestMessages[channelId] ||
|
|
1492
|
+
latestMessages[channelId]?.getTime() < messageDate.getTime()) {
|
|
1493
|
+
latestMessages[channelId] = messageDate;
|
|
1494
|
+
this.latestMessageDateByUserByChannelsSubject.next({
|
|
1495
|
+
...latestMessages,
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
setChannelState(channel) {
|
|
1500
|
+
channel.state.messages.forEach((m) => {
|
|
1501
|
+
m.readBy = getReadBy(m, channel);
|
|
1502
|
+
m.translation = getMessageTranslation(m, channel, this.chatClientService.chatClient.user);
|
|
1503
|
+
if (m.quoted_message) {
|
|
1504
|
+
m.quoted_message.translation =
|
|
1505
|
+
getMessageTranslation(m.quoted_message, channel, this.chatClientService.chatClient.user);
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
this.markRead(channel);
|
|
1509
|
+
this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
1510
|
+
this.activeChannelPinnedMessagesSubject.next([
|
|
1511
|
+
...channel.state.pinnedMessages,
|
|
1512
|
+
]);
|
|
1513
|
+
this.activeParentMessageIdSubject.next(undefined);
|
|
1514
|
+
this.activeThreadMessagesSubject.next([]);
|
|
1515
|
+
this.messageToQuoteSubject.next(undefined);
|
|
1516
|
+
this.usersTypingInChannelSubject.next([]);
|
|
1517
|
+
this.usersTypingInThreadSubject.next([]);
|
|
1518
|
+
}
|
|
1519
|
+
markRead(channel, isThrottled = true) {
|
|
1520
|
+
if (this.canSendReadEvents &&
|
|
1521
|
+
this.shouldMarkActiveChannelAsRead &&
|
|
1522
|
+
!this.areReadEventsPaused) {
|
|
1523
|
+
if (isThrottled) {
|
|
1524
|
+
this.markReadThrottled(channel);
|
|
1525
|
+
}
|
|
1526
|
+
else {
|
|
1527
|
+
void channel.markRead();
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
markReadThrottled(channel) {
|
|
1532
|
+
if (!this.markReadTimeout) {
|
|
1533
|
+
this.markRead(channel, false);
|
|
1534
|
+
this.markReadTimeout = setTimeout(() => {
|
|
1535
|
+
this.flushMarkReadQueue();
|
|
1536
|
+
}, this.markReadThrottleTime);
|
|
1537
|
+
}
|
|
1538
|
+
else {
|
|
1539
|
+
clearTimeout(this.markReadTimeout);
|
|
1540
|
+
this.scheduledMarkReadRequest = () => this.markRead(channel, false);
|
|
1541
|
+
this.markReadTimeout = setTimeout(() => {
|
|
1542
|
+
this.flushMarkReadQueue();
|
|
1543
|
+
}, this.markReadThrottleTime);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
flushMarkReadQueue() {
|
|
1547
|
+
this.scheduledMarkReadRequest?.();
|
|
1548
|
+
this.scheduledMarkReadRequest = undefined;
|
|
1549
|
+
clearTimeout(this.markReadTimeout);
|
|
1550
|
+
this.markReadTimeout = undefined;
|
|
1551
|
+
}
|
|
1552
|
+
async _init(settings) {
|
|
1553
|
+
this.shouldSetActiveChannel = settings.shouldSetActiveChannel;
|
|
1554
|
+
this.messagePageSize = settings.messagePageSize;
|
|
1555
|
+
this.clientEventsSubscription = this.chatClientService.events$.subscribe((notification) => void this.handleNotification(notification));
|
|
1556
|
+
try {
|
|
1557
|
+
const result = await this.queryChannels(this.shouldSetActiveChannel, 'first-page');
|
|
1558
|
+
return result;
|
|
1559
|
+
}
|
|
1560
|
+
catch (error) {
|
|
1561
|
+
this.dismissErrorNotification =
|
|
1562
|
+
this.notificationService.addPermanentNotification('streamChat.Error loading channels', 'error');
|
|
1563
|
+
throw error;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChannelService, deps: [{ token: i1.ChatClientService }, { token: i0.NgZone }, { token: i2.NotificationService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1567
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChannelService, providedIn: 'root' }); }
|
|
1568
|
+
}
|
|
1569
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChannelService, decorators: [{
|
|
1570
|
+
type: Injectable,
|
|
1571
|
+
args: [{
|
|
1572
|
+
providedIn: 'root',
|
|
1573
|
+
}]
|
|
1574
|
+
}], ctorParameters: () => [{ type: i1.ChatClientService }, { type: i0.NgZone }, { type: i2.NotificationService }] });
|
|
1575
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhbm5lbC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvc3RyZWFtLWNoYXQtYW5ndWxhci9zcmMvbGliL2NoYW5uZWwuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFDTCxlQUFlLEVBQ2YsYUFBYSxFQUViLGFBQWEsR0FFZCxNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFxQnZFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXpELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFZdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDOzs7O0FBRS9DOztHQUVHO0FBSUgsTUFBTSxPQUFPLGNBQWM7SUF1UXpCOztPQUVHO2FBQ2EsbUNBQThCLEdBQUcsSUFBSSxBQUFQLENBQVE7SUF5SHRELFlBQ1UsaUJBQW9DLEVBQ3BDLE1BQWMsRUFDZCxtQkFBd0M7UUFGeEMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQUNwQyxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQ2Qsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFxQjtRQTNIbEQ7O1dBRUc7UUFDSCwrQkFBMEIsR0FBRyxLQUFLLENBQUM7UUFDbkMsb0JBQWUsR0FBRyxFQUFFLENBQUM7UUFDYixvQkFBZSxHQUFHLElBQUksZUFBZSxDQUMzQyxTQUFTLENBQ1YsQ0FBQztRQUNNLHlCQUFvQixHQUFHLElBQUksZUFBZSxDQUNoRCxTQUFTLENBQ1YsQ0FBQztRQUNNLGlD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U0FDYjtJQUNILENBQUM7K0dBMXVFVSxjQUFjO21IQUFkLGNBQWMsY0FGYixNQUFNOzs0RkFFUCxjQUFjO2tCQUgxQixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQmVoYXZpb3JTdWJqZWN0LFxuICBjb21iaW5lTGF0ZXN0LFxuICBPYnNlcnZhYmxlLFxuICBSZXBsYXlTdWJqZWN0LFxuICBTdWJzY3JpcHRpb24sXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmlsdGVyLCBmaXJzdCwgbWFwLCBzaGFyZVJlcGxheSwgdGFrZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7XG4gIEF0dGFjaG1lbnQsXG4gIENoYW5uZWwsXG4gIENoYW5uZWxGaWx0ZXJzLFxuICBDaGFubmVsT3B0aW9ucyxcbiAgQ2hhbm5lbFJlc3BvbnNlLFxuICBDaGFubmVsU29ydCxcbiAgQ3VzdG9tTWVzc2FnZURhdGEsXG4gIEN1c3RvbVJlYWN0aW9uRGF0YSxcbiAgRXZlbnQsXG4gIEV2ZW50VHlwZXMsXG4gIEZvcm1hdE1lc3NhZ2VSZXNwb25zZSxcbiAgTG9jYWxNZXNzYWdlLFxuICBNZW1iZXJGaWx0ZXJzLFxuICBNZXNzYWdlLFxuICBNZXNzYWdlUmVzcG9uc2UsXG4gIFJlYWN0aW9uUmVzcG9uc2UsXG4gIFVzZXJSZXNwb25zZSxcbn0gZnJvbSAnc3RyZWFtLWNoYXQnO1xuaW1wb3J0IHsgQ2hhdENsaWVudFNlcnZpY2UsIENsaWVudEV2ZW50IH0gZnJvbSAnLi9jaGF0LWNsaWVudC5zZXJ2aWNlJztcbmltcG9ydCB7IGdldE1lc3NhZ2VUcmFuc2xhdGlvbiB9IGZyb20gJy4vZ2V0LW1lc3NhZ2UtdHJhbnNsYXRpb24nO1xuaW1wb3J0IHsgY3JlYXRlTWVzc2FnZVByZXZpZXcgfSBmcm9tICcuL21lc3NhZ2UtcHJldmlldyc7XG5pbXBvcnQgeyBOb3RpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9ub3RpZmljYXRpb24uc2VydmljZSc7XG5pbXBvcnQgeyBnZXRSZWFkQnkgfSBmcm9tICcuL3JlYWQtYnknO1xuaW1wb3J0IHtcbiAgQXR0YWNobWVudFVwbG9hZCxcbiAgQXR0YWNobWVudFVwbG9hZEVycm9yUmVhc29uLFxuICBDaGFubmVsUXVlcnlSZXN1bHQsXG4gIENoYW5uZWxRdWVyeVN0YXRlLFxuICBDaGFubmVsUXVlcnlUeXBlLFxuICBNZXNzYWdlSW5wdXQsXG4gIE1lc3NhZ2VSZWFjdGlvblR5cGUsXG4gIE5leHRQYWdlQ29uZmlndXJhdGlvbixcbiAgU3RyZWFtTWVzc2FnZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBDaGFubmVsUXVlcnkgfSBmcm9tICcuL2NoYW5uZWwtcXVlcnknO1xuXG4vKipcbiAqIFRoZSBgQ2hhbm5lbFNlcnZpY2VgIHByb3ZpZGVzIGRhdGEgYW5kIGludGVyYWN0aW9uIGZvciB0aGUgY2hhbm5lbCBsaXN0IGFuZCBtZXNzYWdlIGxpc3QuXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBDaGFubmVsU2VydmljZSB7XG4gIC8qKlxuICAgKiBFbWl0cyBgZmFsc2VgIGlmIHRoZXJlIGFyZSBubyBtb3JlIHBhZ2VzIG9mIGNoYW5uZWxzIHRoYXQgY2FuIGJlIGxvYWRlZC5cbiAgICovXG4gIGhhc01vcmVDaGFubmVscyQ6IE9ic2VydmFibGU8Ym9vbGVhbj47XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgY3VycmVudGx5IGxvYWRlZCBhbmQgW3dhdGNoZWRdKC9jaGF0L2RvY3MvamF2YXNjcmlwdC93YXRjaF9jaGFubmVsLykgY2hhbm5lbCBsaXN0LlxuICAgKlxuICAgKiA6OjppbXBvcnRhbnRcbiAgICogSWYgeW91IHdhbnQgdG8gc3Vic2NyaWJlIHRvIGNoYW5uZWwgZXZlbnRzLCB5b3UgbmVlZCB0byBtYW51YWxseSByZWVudGVyIEFuZ3VsYXIncyBjaGFuZ2UgZGV0ZWN0aW9uIHpvbmUsIG91ciBbQ2hhbmdlIGRldGVjdGlvbiBndWlkZV0oL2NoYXQvZG9jcy9zZGsvYW5ndWxhci9jb25jZXB0cy9jaGFuZ2UtZGV0ZWN0aW9uLykgZXhwbGFpbnMgdGhpcyBpbiBkZXRhaWwuXG4gICAqIDo6OlxuICAgKi9cbiAgY2hhbm5lbHMkOiBPYnNlcnZhYmxlPENoYW5uZWxbXSB8IHVuZGVmaW5lZD47XG4gIC8qKlxuICAgKiBUaGUgcmVzdWx0IG9mIHRoZSBsYXRlc3QgY2hhbm5lbCBxdWVyeSByZXF1ZXN0LlxuICAgKi9cbiAgY2hhbm5lbFF1ZXJ5U3RhdGUkOiBPYnNlcnZhYmxlPENoYW5uZWxRdWVyeVN0YXRlIHwgdW5kZWZpbmVkPjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBjdXJyZW50bHkgYWN0aXZlIGNoYW5uZWwuXG4gICAqXG4gICAqIDo6OmltcG9ydGFudFxuICAgKiBJZiB5b3Ugd2FudCB0byBzdWJzY3JpYmUgdG8gY2hhbm5lbCBldmVudHMsIHlvdSBuZWVkIHRvIG1hbnVhbGx5IHJlZW50ZXIgQW5ndWxhcidzIGNoYW5nZSBkZXRlY3Rpb24gem9uZSwgb3VyIFtDaGFuZ2UgZGV0ZWN0aW9uIGd1aWRlXSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL2NvbmNlcHRzL2NoYW5nZS1kZXRlY3Rpb24vKSBleHBsYWlucyB0aGlzIGluIGRldGFpbC5cbiAgICogOjo6XG4gICAqXG4gICAqIFRoZSBhY3RpdmUgY2hhbm5lbCB3aWxsIGFsd2F5cyBiZSBtYXJrZWQgYXMgcmVhZCB3aGVuIGEgbmV3IG1lc3NhZ2UgaXMgcmVjZWl2ZWRcbiAgICovXG4gIGFjdGl2ZUNoYW5uZWwkOiBPYnNlcnZhYmxlPENoYW5uZWwgfCB1bmRlZmluZWQ+O1xuICAvKipcbiAgICogRW1pdHMgdGhlIGxpc3Qgb2YgY3VycmVudGx5IGxvYWRlZCBtZXNzYWdlcyBvZiB0aGUgYWN0aXZlIGNoYW5uZWwuXG4gICAqL1xuICBhY3RpdmVDaGFubmVsTWVzc2FnZXMkOiBPYnNlcnZhYmxlPFN0cmVhbU1lc3NhZ2VbXT47XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgbGlzdCBvZiBwaW5uZWQgbWVzc2FnZXMgb2YgdGhlIGFjdGl2ZSBjaGFubmVsLlxuICAgKi9cbiAgYWN0aXZlQ2hhbm5lbFBpbm5lZE1lc3NhZ2VzJDogT2JzZXJ2YWJsZTxTdHJlYW1NZXNzYWdlW10+O1xuICAvKipcbiAgICogRW1pdHMgdGhlIGlkIG9mIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgcGFyZW50IG1lc3NhZ2UuIElmIG5vIG1lc3NhZ2UgaXMgc2VsZWN0ZWQsIGl0IGVtaXRzIHVuZGVmaW5lZC5cbiAgICovXG4gIGFjdGl2ZVBhcmVudE1lc3NhZ2VJZCQ6IE9ic2VydmFibGU8c3RyaW5nIHwgdW5kZWZpbmVkPjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBsaXN0IG9mIGN1cnJlbnRseSBsb2FkZWQgdGhyZWFkIHJlcGxpZXMgYmVsb25naW5nIHRvIHRoZSBzZWxlY3RlZCBwYXJlbnQgbWVzc2FnZS4gSWYgdGhlcmUgaXMgbm8gY3VycmVudGx5IGFjdGl2ZSB0aHJlYWQgaXQgZW1pdHMgYW4gZW1wdHkgYXJyYXkuXG4gICAqL1xuICBhY3RpdmVUaHJlYWRNZXNzYWdlcyQ6IE9ic2VydmFibGU8U3RyZWFtTWVzc2FnZVtdPjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgcGFyZW50IG1lc3NhZ2UuIElmIG5vIG1lc3NhZ2UgaXMgc2VsZWN0ZWQsIGl0IGVtaXRzIHVuZGVmaW5lZC5cbiAgICovXG4gIGFjdGl2ZVBhcmVudE1lc3NhZ2UkOiBPYnNlcnZhYmxlPFN0cmVhbU1lc3NhZ2UgfCB1bmRlZmluZWQ+O1xuICAvKipcbiAgICogRW1pdHMgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBtZXNzYWdlIHRvIHF1b3RlXG4gICAqL1xuICBtZXNzYWdlVG9RdW90ZSQ6IE9ic2VydmFibGU8U3RyZWFtTWVzc2FnZSB8IHVuZGVmaW5lZD47XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgSUQgb2YgdGhlIG1lc3NhZ2UgdGhlIG1lc3NhZ2UgbGlzdCBzaG91bGQganVtcCB0byAoY2FuIGJlIGEgY2hhbm5lbCBtZXNzYWdlIG9yIHRocmVhZCBtZXNzYWdlKVxuICAgKi9cbiAganVtcFRvTWVzc2FnZSQ6IE9ic2VydmFibGU8eyBpZD86IHN0cmluZzsgcGFyZW50SWQ/OiBzdHJpbmcgfT47XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgbGlzdCBvZiB1c2VycyB0aGF0IGFyZSBjdXJyZW50bHkgdHlwaW5nIGluIHRoZSBjaGFubmVsIChjdXJyZW50IHVzZXIgaXMgbm90IGluY2x1ZGVkKVxuICAgKi9cbiAgdXNlcnNUeXBpbmdJbkNoYW5uZWwkOiBPYnNlcnZhYmxlPFVzZXJSZXNwb25zZVtdPjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBsaXN0IG9mIHVzZXJzIHRoYXQgYXJlIGN1cnJlbnRseSB0eXBpbmcgaW4gdGhlIGFjdGl2ZSB0aHJlYWQgKGN1cnJlbnQgdXNlciBpcyBub3QgaW5jbHVkZWQpXG4gICAqL1xuICB1c2Vyc1R5cGluZ0luVGhyZWFkJDogT2JzZXJ2YWJsZTxVc2VyUmVzcG9uc2VbXT47XG4gIC8qKlxuICAgKiBFbWl0cyBhIG1hcCB0aGF0IGNvbnRhaW5zIHRoZSBkYXRlIG9mIHRoZSBsYXRlc3QgbWVzc2FnZSBzZW50IGJ5IHRoZSBjdXJyZW50IHVzZXIgYnkgY2hhbm5lbHMgKHRoaXMgaXMgdXNlZCB0byBkZXRlY3QgaWYgc2xvdyBtb2RlIGNvdW50ZG93biBzaG91bGQgYmUgc3RhcnRlZClcbiAgICovXG4gIGxhdGVzdE1lc3NhZ2VEYXRlQnlVc2VyQnlDaGFubmVscyQ6IE9ic2VydmFibGU8eyBba2V5OiBzdHJpbmddOiBEYXRlIH0+O1xuICAvKipcbiAgICogSWYgeW91J3JlIHVzaW5nIFtzZW1hbnRpYyBmaWx0ZXJzIGZvciBtb2RlcmF0aW9uXSgvbW9kZXJhdGlvbi9kb2NzLykgeW91IGNhbiBzZXQgdXAgcnVsZXMgZm9yIGJvdW5jaW5nIG1lc3NhZ2VzLlxuICAgKlxuICAgKiBJZiBhIG1lc3NhZ2UgaXMgYm91bmNlZCwgaXQgd2lsbCBiZSBlbWl0dGVkIHZpYSB0aGlzIGBPYnNlcnZhYmxlYC4gVGhlIGJ1aWx0LWluIFtgTWVzc2FnZUJvdW5jZVByb21wdGAgY29tcG9uZW50XSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL2NvbXBvbmVudHMvTWVzc2FnZUJvdW5jZVByb21wdENvbXBvbmVudC8pIHdpbGwgZGlzcGxheSB0aGUgYm91bmNlIG9wdGlvbiB0byB0aGUgdXNlciBpZiBhIGJvdW5jZWQgbWVzc2FnZSBpcyBjbGlja2VkLlxuICAgKi9cbiAgYm91bmNlZE1lc3NhZ2UkOiBCZWhhdmlvclN1YmplY3Q8U3RyZWFtTWVzc2FnZSB8IHVuZGVmaW5lZD47XG4gIC8qKlxuICAgKiBUaGUgbGFzdCByZWFkIG1lc3NhZ2UgaWQgb2YgdGhlIGFjdGl2ZSBjaGFubmVsLCBpdCdzIHVzZWQgYnkgdGhlIG1lc3NhZ2UgbGlzdCBjb21wb25lbnQgdG8gZGlzcGxheSB1bnJlYWQgVUksIGFuZCBqdW1wIHRvIGxhdGVzdCByZWFkIG1lc3NhZ2VcbiAgICpcbiAgICogVGhpcyBwcm9wZXJ0eSBpc24ndCBhbHdheXMgdXBkYXRlZCwgcGxlYXNlIHVzZSBgY2hhbm5lbC5yZWFkYCB0byBkaXNwbGF5IHVwLXRvLWRhdGUgcmVhZCBpbmZvcm1hdGlvblxuICAgKi9cbiAgYWN0aXZlQ2hhbm5lbExhc3RSZWFkTWVzc2FnZUlkPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHVucmVhZCBjb3VudCBvZiB0aGUgYWN0aXZlIGNoYW5uZWwsIGl0J3MgdXNlZCBieSB0aGUgbWVzc2FnZSBsaXN0IGNvbXBvbmVudCB0byBkaXNwbGF5IHVucmVhZCBVSVxuICAgKlxuICAgKiBUaGlzIHByb3BlcnR5IGlzbid0IGFsd2F5cyB1cGRhdGVkLCBwbGVhc2UgdXNlIGBjaGFubmVsLnJlYWRgIHRvIGRpc3BsYXkgdXAtdG8tZGF0ZSByZWFkIGluZm9ybWF0aW9uXG4gICAqL1xuICBhY3RpdmVDaGFubmVsVW5yZWFkQ291bnQ/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBDdXN0b20gZXZlbnQgaGFuZGxlciB0byBjYWxsIGlmIGEgbmV3IG1lc3NhZ2UgcmVjZWl2ZWQgZnJvbSBhIGNoYW5uZWwgdGhhdCBpcyBub3QgYmVpbmcgd2F0Y2hlZCwgcHJvdmlkZSBhbiBldmVudCBoYW5kbGVyIGlmIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoZSBbZGVmYXVsdCBjaGFubmVsIGxpc3Qgb3JkZXJpbmddKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvc2VydmljZXMvQ2hhbm5lbFNlcnZpY2UvI2NoYW5uZWxzLylcbiAgICpcbiAgICogSWYgeW91J3JlIGFkZGluZyBhIG5ldyBjaGFubmVsLCBtYWtlIHN1cmUgdGhhdCBpdCdzIGEgW3dhdGNoZWRdKC9jaGF0L2RvY3MvamF2YXNjcmlwdC93YXRjaF9jaGFubmVsLykgY2hhbm5lbC5cbiAgICovXG4gIGN1c3RvbU5ld01lc3NhZ2VOb3RpZmljYXRpb25IYW5kbGVyPzogKFxuICAgIGNsaWVudEV2ZW50OiBDbGllbnRFdmVudCxcbiAgICBjaGFubmVsTGlzdFNldHRlcjogKFxuICAgICAgY2hhbm5lbHM6IENoYW5uZWxbXSxcbiAgICAgIHNob3VsZFN0b3BXYXRjaGluZ1JlbW92ZWRDaGFubmVscz86IGJvb2xlYW5cbiAgICApID0+IHZvaWRcbiAgKSA9PiB2b2lkO1xuICAvKipcbiAgICogQ3VzdG9tIGV2ZW50IGhhbmRsZXIgdG8gY2FsbCB3aGVuIHRoZSB1c2VyIGlzIGFkZGVkIHRvIGEgY2hhbm5lbCwgcHJvdmlkZSBhbiBldmVudCBoYW5kbGVyIGlmIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoZSBbZGVmYXVsdCBjaGFubmVsIGxpc3Qgb3JkZXJpbmddKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvc2VydmljZXMvQ2hhbm5lbFNlcnZpY2UvI2NoYW5uZWxzLykuXG4gICAqXG4gICAqIElmIHlvdSdyZSBhZGRpbmcgYSBuZXcgY2hhbm5lbCwgbWFrZSBzdXJlIHRoYXQgaXQncyBhIFt3YXRjaGVkXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvd2F0Y2hfY2hhbm5lbC8pIGNoYW5uZWwuXG4gICAqL1xuICBjdXN0b21BZGRlZFRvQ2hhbm5lbE5vdGlmaWNhdGlvbkhhbmRsZXI/OiAoXG4gICAgY2xpZW50RXZlbnQ6IENsaWVudEV2ZW50LFxuICAgIGNoYW5uZWxMaXN0U2V0dGVyOiAoXG4gICAgICBjaGFubmVsczogQ2hhbm5lbFtdLFxuICAgICAgc2hvdWxkU3RvcFdhdGNoaW5nUmVtb3ZlZENoYW5uZWxzPzogYm9vbGVhblxuICAgICkgPT4gdm9pZFxuICApID0+IHZvaWQ7XG4gIC8qKlxuICAgKiBDdXN0b20gZXZlbnQgaGFuZGxlciB0byBjYWxsIHdoZW4gdGhlIHVzZXIgaXMgcmVtb3ZlZCBmcm9tIGEgY2hhbm5lbCwgcHJvdmlkZSBhbiBldmVudCBoYW5kbGVyIGlmIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoZSBbZGVmYXVsdCBjaGFubmVsIGxpc3Qgb3JkZXJpbmddKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvc2VydmljZXMvQ2hhbm5lbFNlcnZpY2UvI2NoYW5uZWxzLykuXG4gICAqXG4gICAqIElmIHlvdSdyZSBhZGRpbmcgYSBuZXcgY2hhbm5lbCwgbWFrZSBzdXJlIHRoYXQgaXQncyBhIFt3YXRjaGVkXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvd2F0Y2hfY2hhbm5lbC8pIGNoYW5uZWwuXG4gICAqL1xuICBjdXN0b21SZW1vdmVkRnJvbUNoYW5uZWxOb3RpZmljYXRpb25IYW5kbGVyPzogKFxuICAgIGNsaWVudEV2ZW50OiBDbGllbnRFdmVudCxcbiAgICBjaGFubmVsTGlzdFNldHRlcjogKFxuICAgICAgY2hhbm5lbHM6IENoYW5uZWxbXSxcbiAgICAgIHNob3VsZFN0b3BXYXRjaGluZ1JlbW92ZWRDaGFubmVscz86IGJvb2xlYW5cbiAgICApID0+IHZvaWRcbiAgKSA9PiB2b2lkO1xuICAvKipcbiAgICogQ3VzdG9tIGV2ZW50IGhhbmRsZXIgdG8gY2FsbCB3aGVuIGEgY2hhbm5lbCBpcyBkZWxldGVkLCBwcm92aWRlIGFuIGV2ZW50IGhhbmRsZXIgaWYgeW91IHdhbnQgdG8gb3ZlcnJpZGUgdGhlIFtkZWZhdWx0IGNoYW5uZWwgbGlzdCBvcmRlcmluZ10oL2NoYXQvZG9jcy9zZGsvYW5ndWxhci9zZXJ2aWNlcy9DaGFubmVsU2VydmljZS8jY2hhbm5lbHMvKS5cbiAgICpcbiAgICogSWYgeW91J3JlIGFkZGluZyBhIG5ldyBjaGFubmVsLCBtYWtlIHN1cmUgdGhhdCBpdCdzIGEgW3dhdGNoZWRdKC9jaGF0L2RvY3MvamF2YXNjcmlwdC93YXRjaF9jaGFubmVsLykgY2hhbm5lbC5cbiAgICovXG4gIGN1c3RvbUNoYW5uZWxEZWxldGVkSGFuZGxlcj86IChcbiAgICBldmVudDogRXZlbnQsXG4gICAgY2hhbm5lbDogQ2hhbm5lbCxcbiAgICBjaGFubmVsTGlzdFNldHRlcjogKFxuICAgICAgY2hhbm5lbHM6IENoYW5uZWxbXSxcbiAgICAgIHNob3VsZFN0b3BXYXRjaGluZ1JlbW92ZWRDaGFubmVscz86IGJvb2xlYW5cbiAgICApID0+IHZvaWQsXG4gICAgbWVzc2FnZUxpc3RTZXR0ZXI6IChtZXNzYWdlczogU3RyZWFtTWVzc2FnZVtdKSA9PiB2b2lkLFxuICAgIHRocmVhZExpc3RTZXR0ZXI6IChtZXNzYWdlczogU3RyZWFtTWVzc2FnZVtdKSA9PiB2b2lkLFxuICAgIHBhcmVudE1lc3NhZ2VTZXR0ZXI6IChtZXNzYWdlOiBTdHJlYW1NZXNzYWdlIHwgdW5kZWZpbmVkKSA9PiB2b2lkXG4gICkgPT4gdm9pZDtcbiAgLyoqXG4gICAqIEN1c3RvbSBldmVudCBoYW5kbGVyIHRvIGNhbGwgd2hlbiBhIGNoYW5uZWwgaXMgdXBkYXRlZCwgcHJvdmlkZSBhbiBldmVudCBoYW5kbGVyIGlmIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoZSBbZGVmYXVsdCBjaGFubmVsIGxpc3Qgb3JkZXJpbmddKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvc2VydmljZXMvQ2hhbm5lbFNlcnZpY2UvI2NoYW5uZWxzLykuXG4gICAqXG4gICAqIElmIHlvdSdyZSBhZGRpbmcgYSBuZXcgY2hhbm5lbCwgbWFrZSBzdXJlIHRoYXQgaXQncyBhIFt3YXRjaGVkXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvd2F0Y2hfY2hhbm5lbC8pIGNoYW5uZWwuXG4gICAqL1xuICBjdXN0b21DaGFubmVsVXBkYXRlZEhhbmRsZXI/OiAoXG4gICAgZXZlbnQ6IEV2ZW50LFxuICAgIGNoYW5uZWw6IENoYW5uZWwsXG4gICAgY2hhbm5lbExpc3RTZXR0ZXI6IChcbiAgICAgIGNoYW5uZWxzOiBDaGFubmVsW10sXG4gICAgICBzaG91bGRTdG9wV2F0Y2hpbmdSZW1vdmVkQ2hhbm5lbHM/OiBib29sZWFuXG4gICAgKSA9PiB2b2lkLFxuICAgIG1lc3NhZ2VMaXN0U2V0dGVyOiAobWVzc2FnZXM6IFN0cmVhbU1lc3NhZ2VbXSkgPT4gdm9pZCxcbiAgICB0aHJlYWRMaXN0U2V0dGVyOiAobWVzc2FnZXM6IFN0cmVhbU1lc3NhZ2VbXSkgPT4gdm9pZCxcbiAgICBwYXJlbnRNZXNzYWdlU2V0dGVyOiAobWVzc2FnZTogU3RyZWFtTWVzc2FnZSB8IHVuZGVmaW5lZCkgPT4gdm9pZFxuICApID0+IHZvaWQ7XG4gIC8qKlxuICAgKiBDdXN0b20gZXZlbnQgaGFuZGxlciB0byBjYWxsIHdoZW4gYSBjaGFubmVsIGlzIHRydW5jYXRlZCwgcHJvdmlkZSBhbiBldmVudCBoYW5kbGVyIGlmIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoZSBbZGVmYXVsdCBjaGFubmVsIGxpc3Qgb3JkZXJpbmddKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvc2VydmljZXMvQ2hhbm5lbFNlcnZpY2UvI2NoYW5uZWxzLykuXG4gICAqXG4gICAqIElmIHlvdSdyZSBhZGRpbmcgYSBuZXcgY2hhbm5lbCwgbWFrZSBzdXJlIHRoYXQgaXQncyBhIFt3YXRjaGVkXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvd2F0Y2hfY2hhbm5lbC8pIGNoYW5uZWwuXG4gICAqL1xuICBjdXN0b21DaGFubmVsVHJ1bmNhdGVkSGFuZGxlcj86IChcbiAgICBldmVudDogRXZlbnQsXG4gICAgY2hhbm5lbDogQ2hhbm5lbCxcbiAgICBjaGFubmVsTGlzdFNldHRlcjogKFxuICAgICAgY2hhbm5lbHM6IENoYW5uZWxbXSxcbiAgICAgIHNob3VsZFN0b3BXYXRjaGluZ1JlbW92ZWRDaGFubmVscz86IGJvb2xlYW5cbiAgICApID0+IHZvaWQsXG4gICAgbWVzc2FnZUxpc3RTZXR0ZXI6IChtZXNzYWdlczogU3RyZWFtTWVzc2FnZVtdKSA9PiB2b2lkLFxuICAgIHRocmVhZExpc3RTZXR0ZXI6IChtZXNzYWdlczogU3RyZWFtTWVzc2FnZVtdKSA9PiB2b2lkLFxuICAgIHBhcmVudE1lc3NhZ2VTZXR0ZXI6IChtZXNzYWdlOiBTdHJlYW1NZXNzYWdlIHwgdW5kZWZpbmVkKSA9PiB2b2lkXG4gICkgPT4gdm9pZDtcbiAgLyoqXG4gICAqIEN1c3RvbSBldmVudCBoYW5kbGVyIHRvIGNhbGwgd2hlbiBhIGNoYW5uZWwgYmVjb21lcyBoaWRkZW4sIHByb3ZpZGUgYW4gZXZlbnQgaGFuZGxlciBpZiB5b3Ugd2FudCB0byBvdmVycmlkZSB0aGUgW2RlZmF1bHQgY2hhbm5lbCBsaXN0IG9yZGVyaW5nXSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL3NlcnZpY2VzL0NoYW5uZWxTZXJ2aWNlLyNjaGFubmVscy8pLlxuICAgKlxuICAgKiBJZiB5b3UncmUgYWRkaW5nIGEgbmV3IGNoYW5uZWwsIG1ha2Ugc3VyZSB0aGF0IGl0J3MgYSBbd2F0Y2hlZF0oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L3dhdGNoX2NoYW5uZWwvKSBjaGFubmVsLlxuICAgKi9cbiAgY3VzdG9tQ2hhbm5lbEhpZGRlbkhhbmRsZXI/OiAoXG4gICAgZXZlbnQ6IEV2ZW50LFxuICAgIGNoYW5uZWw6IENoYW5uZWwsXG4gICAgY2hhbm5lbExpc3RTZXR0ZXI6IChcbiAgICAgIGNoYW5uZWxzOiBDaGFubmVsW10sXG4gICAgICBzaG91bGRTdG9wV2F0Y2hpbmdSZW1vdmVkQ2hhbm5lbHM/OiBib29sZWFuXG4gICAgKSA9PiB2b2lkLFxuICAgIG1lc3NhZ2VMaXN0U2V0dGVyOiAobWVzc2FnZXM6IFN0cmVhbU1lc3NhZ2VbXSkgPT4gdm9pZCxcbiAgICB0aHJlYWRMaXN0U2V0dGVyOiAobWVzc2FnZXM6IFN0cmVhbU1lc3NhZ2VbXSkgPT4gdm9pZCxcbiAgICBwYXJlbnRNZXNzYWdlU2V0dGVyOiAobWVzc2FnZTogU3RyZWFtTWVzc2FnZSB8IHVuZGVmaW5lZCkgPT4gdm9pZFxuICApID0+IHZvaWQ7XG4gIC8qKlxuICAgKiBDdXN0b20gZXZlbnQgaGFuZGxlciB0byBjYWxsIHdoZW4gYSBjaGFubmVsIGJlY29tZXMgdmlzaWJsZSwgcHJvdmlkZSBhbiBldmVudCBoYW5kbGVyIGlmIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoZSBbZGVmYXVsdCBjaGFubmVsIGxpc3Qgb3JkZXJpbmddKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvc2VydmljZXMvQ2hhbm5lbFNlcnZpY2UvI2NoYW5uZWxzLykuXG4gICAqXG4gICAqIElmIHlvdSdyZSBhZGRpbmcgYSBuZXcgY2hhbm5lbCwgbWFrZSBzdXJlIHRoYXQgaXQncyBhIFt3YXRjaGVkXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvd2F0Y2hfY2hhbm5lbC8pIGNoYW5uZWwuXG4gICAqL1xuICBjdXN0b21DaGFubmVsVmlzaWJsZUhhbmRsZXI/OiAoXG4gICAgZXZlbnQ6IEV2ZW50LFxuICAgIGNoYW5uZWw6IENoYW5uZWwsXG4gICAgY2hhbm5lbExpc3RTZXR0ZXI6IChcbiAgICAgIGNoYW5uZWxzOiBDaGFubmVsW10sXG4gICAgICBzaG91bGRTdG9wV2F0Y2hpbmdSZW1vdmVkQ2hhbm5lbHM/OiBib29sZWFuXG4gICAgKSA9PiB2b2lkLFxuICAgIG1lc3NhZ2VMaXN0U2V0dGVyOiAobWVzc2FnZXM6IFN0cmVhbU1lc3NhZ2VbXSkgPT4gdm9pZCxcbiAgICB0aHJlYWRMaXN0U2V0dGVyOiAobWVzc2FnZXM6IFN0cmVhbU1lc3NhZ2VbXSkgPT4gdm9pZCxcbiAgICBwYXJlbnRNZXNzYWdlU2V0dGVyOiAobWVzc2FnZTogU3RyZWFtTWVzc2FnZSB8IHVuZGVmaW5lZCkgPT4gdm9pZFxuICApID0+IHZvaWQ7XG4gIC8qKlxuICAgKiBDdXN0b20gZXZlbnQgaGFuZGxlciB0byBjYWxsIGlmIGEgbmV3IG1lc3NhZ2UgcmVjZWl2ZWQgZnJvbSBhIGNoYW5uZWwgdGhhdCBpcyBiZWluZyB3YXRjaGVkLCBwcm92aWRlIGFuIGV2ZW50IGhhbmRsZXIgaWYgeW91IHdhbnQgdG8gb3ZlcnJpZGUgdGhlIFtkZWZhdWx0IGNoYW5uZWwgbGlzdCBvcmRlcmluZ10oL2NoYXQvZG9jcy9zZGsvYW5ndWxhci9zZXJ2aWNlcy9DaGFubmVsU2VydmljZS8jY2hhbm5lbHMvKS5cbiAgICpcbiAgICogSWYgeW91J3JlIGFkZGluZyBhIG5ldyBjaGFubmVsLCBtYWtlIHN1cmUgdGhhdCBpdCdzIGEgW3dhdGNoZWRdKC9jaGF0L2RvY3MvamF2YXNjcmlwdC93YXRjaF9jaGFubmVsLykgY2hhbm5lbC5cbiAgICovXG4gIGN1c3RvbU5ld01lc3NhZ2VIYW5kbGVyPzogKFxuICAgIGV2ZW50OiBFdmVudCxcbiAgICBjaGFubmVsOiBDaGFubmVsLFxuICAgIGNoYW5uZWxMaXN0U2V0dGVyOiAoXG4gICAgICBjaGFubmVsczogQ2hhbm5lbFtdLFxuICAgICAgc2hvdWxkU3RvcFdhdGNoaW5nUmVtb3ZlZENoYW5uZWxzPzogYm9vbGVhblxuICAgICkgPT4gdm9pZCxcbiAgICBtZXNzYWdlTGlzdFNldHRlcjogKG1lc3NhZ2VzOiBTdHJlYW1NZXNzYWdlW10pID0+IHZvaWQsXG4gICAgdGhyZWFkTGlzdFNldHRlcjogKG1lc3NhZ2VzOiBTdHJlYW1NZXNzYWdlW10pID0+IHZvaWQsXG4gICAgcGFyZW50TWVzc2FnZVNldHRlcjogKG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UgfCB1bmRlZmluZWQpID0+IHZvaWRcbiAgKSA9PiB2b2lkO1xuICAvKipcbiAgICogWW91IGNhbiBvdmVycmlkZSB0aGUgZGVmYXVsdCBmaWxlIHVwbG9hZCByZXF1ZXN0IC0geW91IGNhbiB1c2UgdGhpcyB0byB1cGxvYWQgZmlsZXMgdG8geW91ciBvd24gQ0ROXG4gICAqL1xuICBjdXN0b21GaWxlVXBsb2FkUmVxdWVzdD86IChcbiAgICBmaWxlOiBGaWxlLFxuICAgIGNoYW5uZWw6IENoYW5uZWxcbiAgKSA9PiBQcm9taXNlPHsgZmlsZTogc3RyaW5nIH0+O1xuICAvKipcbiAgICogWW91IGNhbiBvdmVycmlkZSB0aGUgZGVmYXVsdCBpbWFnZSB1cGxvYWQgcmVxdWVzdCAtIHlvdSBjYW4gdXNlIHRoaXMgdG8gdXBsb2FkIGltYWdlcyB0byB5b3VyIG93biBDRE5cbiAgICovXG4gIGN1c3RvbUltYWdlVXBsb2FkUmVxdWVzdD86IChcbiAgICBmaWxlOiBGaWxlLFxuICAgIGNoYW5uZWw6IENoYW5uZWxcbiAgKSA9PiBQcm9taXNlPHsgZmlsZTogc3RyaW5nIH0+O1xuICAvKipcbiAgICogWW91IGNhbiBvdmVycmlkZSB0aGUgZGVmYXVsdCBmaWxlIGRlbGV0ZSByZXF1ZXN0IC0gb3ZlcnJpZGUgdGhpcyBpZiB5b3UgdXNlIHlvdXIgb3duIENETlxuICAgKi9cbiAgY3VzdG9tRmlsZURlbGV0ZVJlcXVlc3Q/OiAodXJsOiBzdHJpbmcsIGNoYW5uZWw6IENoYW5uZWwpID0+IFByb21pc2U8dm9pZD47XG4gIC8qKlxuICAgKiBZb3UgY2FuIG92ZXJyaWRlIHRoZSBkZWZhdWx0IGltYWdlIGRlbGV0ZSByZXF1ZXN0IC0gb3ZlcnJpZGUgdGhpcyBpZiB5b3UgdXNlIHlvdXIgb3duIENETlxuICAgKi9cbiAgY3VzdG9tSW1hZ2VEZWxldGVSZXF1ZXN0PzogKHVybDogc3RyaW5nLCBjaGFubmVsOiBDaGFubmVsKSA9PiBQcm9taXNlPHZvaWQ+O1xuICAvKipcbiAgICogVGhlIHByb3ZpZGVkIG1ldGhvZCB3aWxsIGJlIGNhbGxlZCBiZWZvcmUgZGVsZXRpbmcgYSBtZXNzYWdlLiBJZiB0aGUgcmV0dXJuZWQgUHJvbWlzZSByZXNvbHZlcyB0byBgdHJ1ZWAgdG8gZGVsZXRpb24gd2lsbCBnbyBhaGVhZC4gSWYgYGZhbHNlYCBpcyByZXR1cm5lZCwgdGhlIG1lc3NhZ2Ugd29uJ3QgYmUgZGVsZXRlZC5cbiAgICovXG4gIG1lc3NhZ2VEZWxldGVDb25maXJtYXRpb25IYW5kbGVyPzogKFxuICAgIG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2VcbiAgKSA9PiBQcm9taXNlPGJvb2xlYW4+O1xuICAvKipcbiAgICogVGhlIHByb3ZpZGVkIG1ldGhvZCB3aWxsIGJlIGNhbGxlZCBiZWZvcmUgYSBuZXcgbWVzc2FnZSBpcyBzZW50IHRvIFN0cmVhbSdzIEFQSS4gWW91IGNhbiB1c2UgdGhpcyBob29rIHRvIHRyYW5mcm9tIG9yIGVucmljaCB0aGUgbWVzc2FnZSBiZWluZyBzZW50LlxuICAgKi9cbiAgYmVmb3JlU2VuZE1lc3NhZ2U/OiAoXG4gICAgaW5wdXQ6IE1lc3NhZ2VJbnB1dFxuICApID0+IE1lc3NhZ2VJbnB1dCB8IFByb21pc2U8TWVzc2FnZUlucHV0PjtcbiAgLyoqXG4gICAqIFRoZSBwcm92aWRlZCBtZXRob2Qgd2lsbCBiZSBjYWxsZWQgYmVmb3JlIGEgbWVzc2FnZSBpcyBzZW50IHRvIFN0cmVhbSdzIEFQSSBmb3IgdXBkYXRlLiBZb3UgY2FuIHVzZSB0aGlzIGhvb2sgdG8gdHJhbmZyb20gb3IgZW5yaWNoIHRoZSBtZXNzYWdlIGJlaW5nIHVwZGF0ZWQuXG4gICAqL1xuICBiZWZvcmVVcGRhdGVNZXNzYWdlPzogKFxuICAgIG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2VcbiAgKSA9PiBTdHJlYW1NZXNzYWdlIHwgUHJvbWlzZTxTdHJlYW1NZXNzYWdlPjtcbiAgLyoqXG4gICAqIFNpbmNlIHN3aXRjaGluZyBjaGFubmVscyBjaGFuZ2VzIHRoZSBzdGF0ZSBvZiBtdWx0aXBsZSBvYnNlcmFibGVzLCB0aGlzIG9ic2VydmFibGUgY2FuIGJlIHVzZWQgdG8gY2hlY2sgaWYgYWxsIG9ic2VydmFibGVzIGFyZSB1cGRhdGVkLlxuICAgKiAtIGBlbmRgIG1lYW5zIGFsbCBvYnNlcnZhYmxlcyBhcmUgaW4gc3RhYmxlIHN0YXRlXG4gICAqIC0gYHN0YXJ0YCBtZWFucyBhbGwgb2JzZXJ2YWJsZXMgYXJlIGluIHVuc3RhYmxlIHN0YXRlXG4gICAqL1xuICBjaGFubmVsU3dpdGNoU3RhdGUkOiBPYnNlcnZhYmxlPCdzdGFydCcgfCAnZW5kJz47XG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHN0YXRpYyByZWFkb25seSBNQVhfTUVTU0FHRV9SRUFDVElPTlNfVE9fRkVUQ0ggPSAxMjAwO1xuICAvKipcbiAgICogQGludGVybmFsXG4gICAqL1xuICBpc01lc3NhZ2VMb2FkaW5nSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICBtZXNzYWdlUGFnZVNpemUgPSAyNTtcbiAgcHJpdmF0ZSBjaGFubmVsc1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENoYW5uZWxbXSB8IHVuZGVmaW5lZD4oXG4gICAgdW5kZWZpbmVkXG4gICk7XG4gIHByaXZhdGUgYWN0aXZlQ2hhbm5lbFN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENoYW5uZWwgfCB1bmRlZmluZWQ+KFxuICAgIHVuZGVmaW5lZFxuICApO1xuICBwcml2YXRlIGFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFxuICAgIChTdHJlYW1NZXNzYWdlIHwgTWVzc2FnZVJlc3BvbnNlIHwgRm9ybWF0TWVzc2FnZVJlc3BvbnNlKVtdXG4gID4oW10pO1xuICBwcml2YXRlIGFjdGl2ZUNoYW5uZWxQaW5uZWRNZXNzYWdlc1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFxuICAgIFN0cmVhbU1lc3NhZ2VbXVxuICA+KFtdKTtcbiAgcHJpdmF0ZSBoYXNNb3JlQ2hhbm5lbHNTdWJqZWN0ID0gbmV3IFJlcGxheVN1YmplY3Q8Ym9vbGVhbj4oMSk7XG4gIHByaXZhdGUgYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnM6IHsgdW5zdWJzY3JpYmU6ICgpID0+IHZvaWQgfVtdID0gW107XG4gIHByaXZhdGUgY2hhbm5lbFN1YnNjcmlwdGlvbnM6IHsgW2tleTogc3RyaW5nXTogKCkgPT4gdm9pZCB9ID0ge307XG4gIHByaXZhdGUgYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8XG4gICAgc3RyaW5nIHwgdW5kZWZpbmVkXG4gID4odW5kZWZpbmVkKTtcbiAgcHJpdmF0ZSBhY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFxuICAgIChTdHJlYW1NZXNzYWdlIHwgTWVzc2FnZVJlc3BvbnNlIHwgRm9ybWF0TWVzc2FnZVJlc3BvbnNlKVtdXG4gID4oW10pO1xuICBwcml2YXRlIGp1bXBUb01lc3NhZ2VTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDx7XG4gICAgaWQ/OiBzdHJpbmc7XG4gICAgcGFyZW50SWQ/OiBzdHJpbmc7XG4gIH0+KHsgaWQ6IHVuZGVmaW5lZCwgcGFyZW50SWQ6IHVuZGVmaW5lZCB9KTtcbiAgcHJpdmF0ZSBsYXRlc3RNZXNzYWdlRGF0ZUJ5VXNlckJ5Q2hhbm5lbHNTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDx7XG4gICAgW2tleTogc3RyaW5nXTogRGF0ZTtcbiAgfT4oe30pO1xuICBwcml2YXRlIHJlYWRvbmx5IGF0dGFjaG1lbnRNYXhTaXplRmFsbGJhY2tJbk1CID0gMTAwO1xuICBwcml2YXRlIG1lc3NhZ2VUb1F1b3RlU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8XG4gICAgU3RyZWFtTWVzc2FnZSB8IHVuZGVmaW5lZFxuICA+KHVuZGVmaW5lZCk7XG4gIHByaXZhdGUgdXNlcnNUeXBpbmdJbkNoYW5uZWxTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxVc2VyUmVzcG9uc2VbXT4oW10pO1xuICBwcml2YXRlIHVzZXJzVHlwaW5nSW5UaHJlYWRTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxVc2VyUmVzcG9uc2VbXT4oW10pO1xuICBwcml2YXRlIF9zaG91bGRNYXJrQWN0aXZlQ2hhbm5lbEFzUmVhZCA9IHRydWU7XG4gIHByaXZhdGUgc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbDogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBjbGllbnRFdmVudHNTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBpc1N0YXRlUmVjb3ZlcnlJblByb2dyZXNzID0gZmFsc2U7XG4gIHByaXZhdGUgY2hhbm5lbFF1ZXJ5U3RhdGVTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxcbiAgICBDaGFubmVsUXVlcnlTdGF0ZSB8IHVuZGVmaW5lZFxuICA+KHVuZGVmaW5lZCk7XG4gIHByaXZhdGUgY2hhbm5lbFN3aXRjaFN0YXRlU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8J3N0YXJ0JyB8ICdlbmQnPihcbiAgICAnZW5kJ1xuICApO1xuICBwcml2YXRlIGNoYW5uZWxRdWVyeT86XG4gICAgfCBDaGFubmVsUXVlcnlcbiAgICB8ICgocXVlcnlUeXBlOiBDaGFubmVsUXVlcnlUeXBlKSA9PiBQcm9taXNlPENoYW5uZWxRdWVyeVJlc3VsdD4pO1xuICBwcml2YXRlIF9jdXN0b21QYWdpbmF0b3I6XG4gICAgfCAoKGNoYW5uZWxRdWVyeVJlc3VsdDogQ2hhbm5lbFtdKSA9PiBOZXh0UGFnZUNvbmZpZ3VyYXRpb24pXG4gICAgfCB1bmRlZmluZWQ7XG5cbiAgcHJpdmF0ZSBjaGFubmVsTGlzdFNldHRlciA9IChcbiAgICBjaGFubmVsczogQ2hhbm5lbFtdLFxuICAgIHNob3VsZFN0b3BXYXRjaGluZ1JlbW92ZWRDaGFubmVscyA9IHRydWVcbiAgKSA9PiB7XG4gICAgY29uc3QgY3VycmVudENoYW5uZWxzID0gdGhpcy5jaGFubmVsc1N1YmplY3QuZ2V0VmFsdWUoKSB8fCBbXTtcbiAgICBjb25zdCBkZWxldGVkQ2hhbm5lbHMgPSBjdXJyZW50Q2hhbm5lbHMuZmlsdGVyKFxuICAgICAgKGMpID0+ICFjaGFubmVscz8uZmluZCgoY2hhbm5lbCkgPT4gY2hhbm5lbC5jaWQgPT09IGMuY2lkKVxuICAgICk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNoYW5uZWxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjaGFubmVsID0gY2hhbm5lbHNbaV07XG4gICAgICBpZiAoIXRoaXMuY2hhbm5lbFN1YnNjcmlwdGlvbnNbY2hhbm5lbC5jaWRdKSB7XG4gICAgICAgIHRoaXMud2F0Y2hGb3JDaGFubmVsRXZlbnRzKGNoYW5uZWwpO1xuICAgICAgfVxuICAgICAgaWYgKGRlbGV0ZWRDaGFubmVscy5pbmNsdWRlcyhjaGFubmVsKSkge1xuICAgICAgICBpZiAoc2hvdWxkU3RvcFdhdGNoaW5nUmVtb3ZlZENoYW5uZWxzKSB7XG4gICAgICAgICAgaWYgKHRoaXMuY2hhbm5lbFN1YnNjcmlwdGlvbnNbY2hhbm5lbC5jaWRdKSB7XG4gICAgICAgICAgICB0aGlzLmNoYW5uZWxTdWJzY3JpcHRpb25zW2NoYW5uZWwuY2lkXSgpO1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuY2hhbm5lbFN1YnNjcmlwdGlvbnMuY2lkO1xuICAgICAgICAgIH1cbiAgICAgICAgICB2b2lkIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC5hY3RpdmVDaGFubmVsc1tjaGFubmVsLmNpZF1cbiAgICAgICAgICAgID8uc3RvcFdhdGNoaW5nKClcbiAgICAgICAgICAgIC5jYXRjaCgoZXJyKSA9PlxuICAgICAgICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQubG9nZ2VyKFxuICAgICAgICAgICAgICAgICd3YXJuJyxcbiAgICAgICAgICAgICAgICAnRmFpbGVkIHRvIHVud2F0Y2ggY2hhbm5lbCcsXG4gICAgICAgICAgICAgICAgZXJyIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgbmV4dENoYW5uZWxzID0gY2hhbm5lbHM7XG4gICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dChuZXh0Q2hhbm5lbHMpO1xuICAgIGlmIChcbiAgICAgICFuZXh0Q2hhbm5lbHMuZmluZChcbiAgICAgICAgKGMpID0+IGMuY2lkID09PSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk/LmNpZFxuICAgICAgKVxuICAgICkge1xuICAgICAgaWYgKG5leHRDaGFubmVscy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuc2V0QXNBY3RpdmVDaGFubmVsKG5leHRDaGFubmVsc1swXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQodW5kZWZpbmVkKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgcHJpdmF0ZSBtZXNzYWdlTGlzdFNldHRlciA9IChtZXNzYWdlczogU3RyZWFtTWVzc2FnZVtdKSA9PiB7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQobWVzc2FnZXMpO1xuICB9O1xuXG4gIHByaXZhdGUgdGhyZWFkTGlzdFNldHRlciA9IChtZXNzYWdlczogU3RyZWFtTWVzc2FnZVtdKSA9PiB7XG4gICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChtZXNzYWdlcyk7XG4gIH07XG5cbiAgcHJpdmF0ZSBwYXJlbnRNZXNzYWdlU2V0dGVyID0gKG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UgfCB1bmRlZmluZWQpID0+IHtcbiAgICB0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2VJZFN1YmplY3QubmV4dChtZXNzYWdlPy5pZCk7XG4gIH07XG4gIHByaXZhdGUgZGlzbWlzc0Vycm9yTm90aWZpY2F0aW9uPzogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBhcmVSZWFkRXZlbnRzUGF1c2VkID0gZmFsc2U7XG4gIHByaXZhdGUgbWFya1JlYWRUaHJvdHRsZVRpbWUgPSAxMDUwO1xuICBwcml2YXRlIG1hcmtSZWFkVGltZW91dD86IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+O1xuICBwcml2YXRlIHNjaGVkdWxlZE1hcmtSZWFkUmVxdWVzdD86ICgpID0+IHZvaWQ7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjaGF0Q2xpZW50U2VydmljZTogQ2hhdENsaWVudFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIG5vdGlmaWNhdGlvblNlcnZpY2U6IE5vdGlmaWNhdGlvblNlcnZpY2VcbiAgKSB7XG4gICAgdGhpcy5jaGFubmVscyQgPSB0aGlzLmNoYW5uZWxzU3ViamVjdC5hc09ic2VydmFibGUoKS5waXBlKHNoYXJlUmVwbGF5KDEpKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWwkID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkID0gdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0LnBpcGUoXG4gICAgICBtYXAoKG1lc3NhZ2VzKSA9PiB7XG4gICAgICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgICAgICByZXR1cm4gbWVzc2FnZXMubWFwKChtZXNzYWdlKSA9PlxuICAgICAgICAgIHRoaXMudHJhbnNmb3JtVG9TdHJlYW1NZXNzYWdlKG1lc3NhZ2UsIGNoYW5uZWwpXG4gICAgICAgICk7XG4gICAgICB9KSxcbiAgICAgIHNoYXJlUmVwbGF5KDEpXG4gICAgKTtcbiAgICB0aGlzLmJvdW5jZWRNZXNzYWdlJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8U3RyZWFtTWVzc2FnZSB8IHVuZGVmaW5lZD4oXG4gICAgICB1bmRlZmluZWRcbiAgICApO1xuICAgIHRoaXMuaGFzTW9yZUNoYW5uZWxzJCA9IHRoaXMuaGFzTW9yZUNoYW5uZWxzU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWQkID0gdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0XG4gICAgICAuYXNPYnNlcnZhYmxlKClcbiAgICAgIC5waXBlKHNoYXJlUmVwbGF5KDEpKTtcbiAgICB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzJCA9IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0LnBpcGUoXG4gICAgICBtYXAoKG1lc3NhZ2VzKSA9PiB7XG4gICAgICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgICAgICByZXR1cm4gbWVzc2FnZXMubWFwKChtZXNzYWdlKSA9PlxuICAgICAgICAgIHRoaXMudHJhbnNmb3JtVG9TdHJlYW1NZXNzYWdlKG1lc3NhZ2UsIGNoYW5uZWwpXG4gICAgICAgICk7XG4gICAgICB9KSxcbiAgICAgIHNoYXJlUmVwbGF5KDEpXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2UkID0gY29tYmluZUxhdGVzdChbXG4gICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlcyQsXG4gICAgICB0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2VJZCQsXG4gICAgXSkucGlwZShcbiAgICAgIG1hcChcbiAgICAgICAgKFttZXNzYWdlcywgcGFyZW50TWVzc2FnZUlkXTogW1xuICAgICAgICAgIFN0cmVhbU1lc3NhZ2VbXSxcbiAgICAgICAgICBzdHJpbmcgfCB1bmRlZmluZWRcbiAgICAgICAgXSkgPT4ge1xuICAgICAgICAgIGlmICghcGFyZW50TWVzc2FnZUlkKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gbWVzc2FnZXMuZmluZCgobSkgPT4gbS5pZCA9PT0gcGFyZW50TWVzc2FnZUlkKTtcbiAgICAgICAgICAgIGlmICghbWVzc2FnZSkge1xuICAgICAgICAgICAgICB2b2lkIHRoaXMuc2V0QXNBY3RpdmVQYXJlbnRNZXNzYWdlKHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICksXG4gICAgICBzaGFyZVJlcGxheSgxKVxuICAgICk7XG4gICAgdGhpcy5tZXNzYWdlVG9RdW90ZSQgPSB0aGlzLm1lc3NhZ2VUb1F1b3RlU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5qdW1wVG9NZXNzYWdlJCA9IHRoaXMuanVtcFRvTWVzc2FnZVN1YmplY3RcbiAgICAgIC5hc09ic2VydmFibGUoKVxuICAgICAgLnBpcGUoc2hhcmVSZXBsYXkoMSkpO1xuXG4gICAgdGhpcy51c2Vyc1R5cGluZ0luQ2hhbm5lbCQgPSB0aGlzLnVzZXJzVHlwaW5nSW5DaGFubmVsU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy51c2Vyc1R5cGluZ0luVGhyZWFkJCA9IHRoaXMudXNlcnNUeXBpbmdJblRocmVhZFN1YmplY3RcbiAgICAgIC5hc09ic2VydmFibGUoKVxuICAgICAgLnBpcGUoc2hhcmVSZXBsYXkoMSkpO1xuICAgIHRoaXMubGF0ZXN0TWVzc2FnZURhdGVCeVVzZXJCeUNoYW5uZWxzJCA9XG4gICAgICB0aGlzLmxhdGVzdE1lc3NhZ2VEYXRlQnlVc2VyQnlDaGFubmVsc1N1YmplY3RcbiAgICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAgIC5waXBlKHNoYXJlUmVwbGF5KDEpKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxQaW5uZWRNZXNzYWdlcyQgPSB0aGlzLmFjdGl2ZUNoYW5uZWxQaW5uZWRNZXNzYWdlc1N1YmplY3RcbiAgICAgIC5hc09ic2VydmFibGUoKVxuICAgICAgLnBpcGUoc2hhcmVSZXBsYXkoMSkpO1xuICAgIHRoaXMuY2hhbm5lbFF1ZXJ5U3RhdGUkID0gdGhpcy5jaGFubmVsUXVlcnlTdGF0ZVN1YmplY3RcbiAgICAgIC5hc09ic2VydmFibGUoKVxuICAgICAgLnBpcGUoc2hhcmVSZXBsYXkoMSkpO1xuICAgIHRoaXMuY2hhbm5lbFN3aXRjaFN0YXRlJCA9IHRoaXMuY2hhbm5lbFN3aXRjaFN0YXRlU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gIH1cblxuICAvKipcbiAgICogSWYgc2V0IHRvIGZhbHNlLCByZWFkIGV2ZW50cyB3b24ndCBiZSBzZW50IGFzIG5ldyBtZXNzYWdlcyBhcmUgcmVjZWl2ZWQuIElmIHNldCB0byB0cnVlIGFjdGl2ZSBjaGFubmVsIChpZiBhbnkpIHdpbGwgaW1tZWRpYXRlbHkgYmUgbWFya2VkIGFzIHJlYWQuXG4gICAqL1xuICBnZXQgc2hvdWxkTWFya0FjdGl2ZUNoYW5uZWxBc1JlYWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Nob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkO1xuICB9XG5cbiAgLyoqXG4gICAqIElmIHNldCB0byBmYWxzZSwgcmVhZCBldmVudHMgd29uJ3QgYmUgc2VudCBhcyBuZXcgbWVzc2FnZXMgYXJlIHJlY2VpdmVkLiBJZiBzZXQgdG8gdHJ1ZSBhY3RpdmUgY2hhbm5lbCAoaWYgYW55KSB3aWxsIGltbWVkaWF0ZWx5IGJlIG1hcmtlZCBhcyByZWFkLlxuICAgKi9cbiAgc2V0IHNob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkKHNob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkOiBib29sZWFuKSB7XG4gICAgaWYgKCF0aGlzLl9zaG91bGRNYXJrQWN0aXZlQ2hhbm5lbEFzUmVhZCAmJiBzaG91bGRNYXJrQWN0aXZlQ2hhbm5lbEFzUmVhZCkge1xuICAgICAgY29uc3QgYWN0aXZlQ2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICAgIGlmIChhY3RpdmVDaGFubmVsICYmIHRoaXMuY2FuU2VuZFJlYWRFdmVudHMpIHtcbiAgICAgICAgdm9pZCBhY3RpdmVDaGFubmVsLm1hcmtSZWFkKCk7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuX3Nob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkID0gc2hvdWxkTWFya0FjdGl2ZUNoYW5uZWxBc1JlYWQ7XG4gIH1cblxuICAvKipcbiAgICogQnkgZGVmYXVsdCB0aGUgU0RLIHVzZXMgYW4gb2Zmc2V0IGJhc2VkIHBhZ2luYXRpb24sIHlvdSBjYW4gY2hhbmdlL2V4dGVuZCB0aGlzIGJ5IHByb3ZpZGluZyB5b3VyIG93biBjdXN0b20gcGFnaW5hdG9yIG1ldGhvZC5cbiAgICpcbiAgICogVGhlIG1ldGhvZCB3aWxsIGJlIGNhbGxlZCB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGxhdGVzdCBjaGFubmVsIHF1ZXJ5LlxuICAgKlxuICAgKiBZb3UgY2FuIHJldHVybiBlaXRoZXIgYW4gb2Zmc2V0LCBvciBhIGZpbHRlciB1c2luZyB0aGUgW2AkbHRlYC9gJGd0ZWAgb3BlcmF0b3JdKC9jaGF0L2RvY3MvamF2YXNjcmlwdC9xdWVyeV9zeW50YXhfb3BlcmF0b3JzLykuIElmIHlvdSByZXR1cm4gYSBmaWx0ZXIsIGl0IHdpbGwgYmUgbWVyZ2VkIHdpdGggdGhlIGZpbHRlciBwcm92aWRlZCBmb3IgdGhlIGBpbml0YCBtZXRob2QuXG4gICAqL1xuICBzZXQgY3VzdG9tUGFnaW5hdG9yKFxuICAgIHBhZ2luYXRvcjpcbiAgICAgIHwgKChjaGFubmVsUXVlcnlSZXN1bHQ6IENoYW5uZWxbXSkgPT4gTmV4dFBhZ2VDb25maWd1cmF0aW9uKVxuICAgICAgfCB1bmRlZmluZWRcbiAgKSB7XG4gICAgdGhpcy5fY3VzdG9tUGFnaW5hdG9yID0gcGFnaW5hdG9yO1xuICAgIGlmICh0aGlzLmNoYW5uZWxRdWVyeSAmJiAnY3VzdG9tUGFnaW5hdG9yJyBpbiB0aGlzLmNoYW5uZWxRdWVyeSkge1xuICAgICAgdGhpcy5jaGFubmVsUXVlcnkuY3VzdG9tUGFnaW5hdG9yID0gdGhpcy5fY3VzdG9tUGFnaW5hdG9yO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBnaXZlbiBgY2hhbm5lbGAgYXMgYWN0aXZlIGFuZCBtYXJrcyBpdCBhcyByZWFkLlxuICAgKiBJZiB0aGUgY2hhbm5lbCB3YXNuJ3QgcHJldmlvdXNseSBwYXJ0IG9mIHRoZSBjaGFubmVsLCBpdCB3aWxsIGJlIGFkZGVkIHRvIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGxpc3QuXG4gICAqIEBwYXJhbSBjaGFubmVsXG4gICAqL1xuICBzZXRBc0FjdGl2ZUNoYW5uZWwoY2hhbm5lbDogQ2hhbm5lbCkge1xuICAgIHRoaXMuY2hhbm5lbFN3aXRjaFN0YXRlU3ViamVjdC5uZXh0KCdzdGFydCcpO1xuICAgIGNvbnN0IHByZXZBY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGlmIChwcmV2QWN0aXZlQ2hhbm5lbD8uY2lkID09PSBjaGFubmVsLmNpZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnN0b3BXYXRjaEZvckFjdGl2ZUNoYW5uZWxFdmVudHMocHJldkFjdGl2ZUNoYW5uZWwpO1xuICAgIHRoaXMuZmx1c2hNYXJrUmVhZFF1ZXVlKCk7XG4gICAgdGhpcy5hcmVSZWFkRXZlbnRzUGF1c2VkID0gZmFsc2U7XG4gICAgdGhpcy5pc01lc3NhZ2VMb2FkaW5nSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgIGNvbnN0IHJlYWRTdGF0ZSA9XG4gICAgICBjaGFubmVsLnN0YXRlLnJlYWRbdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXI/LmlkIHx8ICcnXTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxMYXN0UmVhZE1lc3NhZ2VJZCA9IHJlYWRTdGF0ZT8ubGFzdF9yZWFkX21lc3NhZ2VfaWQ7XG4gICAgaWYgKFxuICAgICAgY2hhbm5lbC5zdGF0ZS5sYXRlc3RNZXNzYWdlc1tjaGFubmVsLnN0YXRlLmxhdGVzdE1lc3NhZ2VzLmxlbmd0aCAtIDFdXG4gICAgICAgID8uaWQgPT09IHRoaXMuYWN0aXZlQ2hhbm5lbExhc3RSZWFkTWVzc2FnZUlkXG4gICAgKSB7XG4gICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxMYXN0UmVhZE1lc3NhZ2VJZCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsVW5yZWFkQ291bnQgPSByZWFkU3RhdGU/LnVucmVhZF9tZXNzYWdlcyB8fCAwO1xuICAgIHRoaXMud2F0Y2hGb3JBY3RpdmVDaGFubmVsRXZlbnRzKGNoYW5uZWwpO1xuICAgIHRoaXMuYWRkQ2hhbm5lbChjaGFubmVsKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQoY2hhbm5lbCk7XG4gICAgY29uc3QgY2hhbm5lbFN0YXRlTGVuZ3RoID0gY2hhbm5lbC5zdGF0ZS5sYXRlc3RNZXNzYWdlcy5sZW5ndGg7XG4gICAgaWYgKGNoYW5uZWxTdGF0ZUxlbmd0aCA+IDIgKiB0aGlzLm1lc3NhZ2VQYWdlU2l6ZSkge1xuICAgICAgY2hhbm5lbC5zdGF0ZS5sYXRlc3RNZXNzYWdlcyA9IGNoYW5uZWwuc3RhdGUubGF0ZXN0TWVzc2FnZXMuc2xpY2UoXG4gICAgICAgIGNoYW5uZWxTdGF0ZUxlbmd0aCAtIDIgKiB0aGlzLm1lc3NhZ2VQYWdlU2l6ZVxuICAgICAgKTtcbiAgICB9XG4gICAgdGhpcy5zZXRDaGFubmVsU3RhdGUoY2hhbm5lbCk7XG4gICAgdGhpcy5jaGFubmVsU3dpdGNoU3RhdGVTdWJqZWN0Lm5leHQoJ2VuZCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlc2VsZWN0cyB0aGUgY3VycmVudGx5IGFjdGl2ZSAoaWYgYW55KSBjaGFubmVsXG4gICAqL1xuICBkZXNlbGVjdEFjdGl2ZUNoYW5uZWwoKSB7XG4gICAgdGhpcy5jaGFubmVsU3dpdGNoU3RhdGVTdWJqZWN0Lm5leHQoJ3N0YXJ0Jyk7XG4gICAgY29uc3QgYWN0aXZlQ2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBpZiAoIWFjdGl2ZUNoYW5uZWwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5zdG9wV2F0Y2hGb3JBY3RpdmVDaGFubmVsRXZlbnRzKGFjdGl2ZUNoYW5uZWwpO1xuICAgIHRoaXMuZmx1c2hNYXJrUmVhZFF1ZXVlKCk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoW10pO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5uZXh0KHVuZGVmaW5lZCk7XG4gICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChbXSk7XG4gICAgdGhpcy5sYXRlc3RNZXNzYWdlRGF0ZUJ5VXNlckJ5Q2hhbm5lbHNTdWJqZWN0Lm5leHQoe30pO1xuICAgIHRoaXMuc2VsZWN0TWVzc2FnZVRvUXVvdGUodW5kZWZpbmVkKTtcbiAgICB0aGlzLmp1bXBUb01lc3NhZ2VTdWJqZWN0Lm5leHQoeyBpZDogdW5kZWZpbmVkLCBwYXJlbnRJZDogdW5kZWZpbmVkIH0pO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFBpbm5lZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtdKTtcbiAgICB0aGlzLnVzZXJzVHlwaW5nSW5DaGFubmVsU3ViamVjdC5uZXh0KFtdKTtcbiAgICB0aGlzLnVzZXJzVHlwaW5nSW5UaHJlYWRTdWJqZWN0Lm5leHQoW10pO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbExhc3RSZWFkTWVzc2FnZUlkID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFVucmVhZENvdW50ID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuYXJlUmVhZEV2ZW50c1BhdXNlZCA9IGZhbHNlO1xuICAgIHRoaXMuaXNNZXNzYWdlTG9hZGluZ0luUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgICB0aGlzLmNoYW5uZWxTd2l0Y2hTdGF0ZVN1YmplY3QubmV4dCgnZW5kJyk7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgZ2l2ZW4gYG1lc3NhZ2VgIGFzIGFuIGFjdGl2ZSBwYXJlbnQgbWVzc2FnZS4gSWYgYHVuZGVmaW5lZGAgaXMgcHJvdmlkZWQsIGl0IHdpbGwgZGVsZXNlbGVjdCB0aGUgY3VycmVudCBwYXJlbnQgbWVzc2FnZS5cbiAgICogQHBhcmFtIG1lc3NhZ2VcbiAgICogQHBhcmFtIGxvYWRNZXNzYWdlc0Zvcm1cbiAgICovXG4gIGFzeW5jIHNldEFzQWN0aXZlUGFyZW50TWVzc2FnZShcbiAgICBtZXNzYWdlOiBTdHJlYW1NZXNzYWdlIHwgdW5kZWZpbmVkLFxuICAgIGxvYWRNZXNzYWdlc0Zvcm06ICdyZXF1ZXN0JyB8ICdzdGF0ZScgPSAncmVxdWVzdCdcbiAgKSB7XG4gICAgY29uc3QgbWVzc2FnZVRvUXVvdGUgPSB0aGlzLm1lc3NhZ2VUb1F1b3RlU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGlmIChtZXNzYWdlVG9RdW90ZSAmJiAhIW1lc3NhZ2VUb1F1b3RlLnBhcmVudF9pZCkge1xuICAgICAgdGhpcy5tZXNzYWdlVG9RdW90ZVN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIH1cbiAgICBpZiAoIW1lc3NhZ2UpIHtcbiAgICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5uZXh0KHVuZGVmaW5lZCk7XG4gICAgICB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtdKTtcbiAgICAgIGNvbnN0IG1lc3NhZ2VUb0p1bXBUbyA9IHRoaXMuanVtcFRvTWVzc2FnZVN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICAgIGlmIChtZXNzYWdlVG9KdW1wVG8gJiYgISFtZXNzYWdlVG9KdW1wVG8ucGFyZW50SWQpIHtcbiAgICAgICAgdGhpcy5qdW1wVG9NZXNzYWdlU3ViamVjdC5uZXh0KHsgaWQ6IHVuZGVmaW5lZCwgcGFyZW50SWQ6IHVuZGVmaW5lZCB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0Lm5leHQobWVzc2FnZS5pZCk7XG4gICAgICBjb25zdCBhY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgaWYgKGxvYWRNZXNzYWdlc0Zvcm0gPT09ICdyZXF1ZXN0Jykge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBhY3RpdmVDaGFubmVsPy5nZXRSZXBsaWVzKG1lc3NhZ2UuaWQsIHtcbiAgICAgICAgICBsaW1pdDogdGhpcy5tZXNzYWdlUGFnZVNpemUsXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KHJlc3VsdD8ubWVzc2FnZXMgfHwgW10pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChcbiAgICAgICAgICBhY3RpdmVDaGFubmVsPy5zdGF0ZS50aHJlYWRzW21lc3NhZ2UuaWRdIHx8IFtdXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIExvYWRzIHRoZSBuZXh0IHBhZ2Ugb2YgbWVzc2FnZXMgb2YgdGhlIGFjdGl2ZSBjaGFubmVsLiBUaGUgcGFnZSBzaXplIGNhbiBiZSBzZXQgaW4gdGhlIFtxdWVyeSBvcHRpb25dKC9jaGF0L2RvY3MvamF2YXNjcmlwdC9xdWVyeV9jaGFubmVscy8jcXVlcnktb3B0aW9ucykgb2JqZWN0LlxuICAgKiBAcGFyYW0gZGlyZWN0aW9uXG4gICAqL1xuICBsb2FkTW9yZU1lc3NhZ2VzKGRpcmVjdGlvbjogJ29sZGVyJyB8ICduZXdlcicgPSAnb2xkZXInKSB7XG4gICAgY29uc3QgYWN0aXZlQ2huYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgY29uc3QgbWVzc2FnZXMgPSB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCBsYXN0TWVzc2FnZUlkID1cbiAgICAgIG1lc3NhZ2VzW2RpcmVjdGlvbiA9PT0gJ29sZGVyJyA/IDAgOiBtZXNzYWdlcy5sZW5ndGggLSAxXT8uaWQ7XG4gICAgaWYgKFxuICAgICAgZGlyZWN0aW9uID09PSAnbmV3ZXInICYmXG4gICAgICBhY3RpdmVDaG5hbm5lbD8uc3RhdGU/LmxhdGVzdE1lc3NhZ2VzID09PSBhY3RpdmVDaG5hbm5lbD8uc3RhdGU/Lm1lc3NhZ2VzXG4gICAgKSB7XG4gICAgICAvLyBJZiB3ZSBhcmUgb24gbGF0ZXN0IG1lc3NhZ2Ugc2V0LCBhY3RpdmVDaGFubmVsTWVzc2FnZXMkIHdpbGwgYmUgcmVmcmVzaGVkIGJ5IFdTIGV2ZW50cywgbm8gbmVlZCBmb3IgYSByZXF1ZXN0XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiBhY3RpdmVDaG5hbm5lbFxuICAgICAgPy5xdWVyeSh7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgbGltaXQ6IHRoaXMubWVzc2FnZVBhZ2VTaXplLFxuICAgICAgICAgIFtkaXJlY3Rpb24gPT09ICdvbGRlcicgPyAnaWRfbHQnIDogJ2lkX2d0J106IGxhc3RNZXNzYWdlSWQsXG4gICAgICAgIH0sXG4gICAgICAgIG1lbWJlcnM6IHsgbGltaXQ6IDAgfSxcbiAgICAgICAgd2F0Y2hlcnM6IHsgbGltaXQ6IDAgfSxcbiAgICAgIH0pXG4gICAgICAudGhlbigocmVzKSA9PiB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBhY3RpdmVDaG5hbm5lbD8uZGF0YT8uaWQgPT09XG4gICAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpPy5kYXRhPy5pZFxuICAgICAgICApIHtcbiAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QubmV4dChbXG4gICAgICAgICAgICAuLi5hY3RpdmVDaG5hbm5lbC5zdGF0ZS5tZXNzYWdlcyxcbiAgICAgICAgICBdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkcyB0aGUgbmV4dCBwYWdlIG9mIG1lc3NhZ2VzIG9mIHRoZSBhY3RpdmUgdGhyZWFkLiBUaGUgcGFnZSBzaXplIGNhbiBiZSBzZXQgaW4gdGhlIFtxdWVyeSBvcHRpb25dKC9jaGF0L2RvY3MvamF2YXNjcmlwdC9xdWVyeV9jaGFubmVscy8jcXVlcnktb3B0aW9ucykgb2JqZWN0LlxuICAgKiBAcGFyYW0gZGlyZWN0aW9uXG4gICAqL1xuICBsb2FkTW9yZVRocmVhZFJlcGxpZXMoZGlyZWN0aW9uOiAnb2xkZXInIHwgJ25ld2VyJyA9ICdvbGRlcicpIHtcbiAgICBpZiAoZGlyZWN0aW9uID09PSAnbmV3ZXInKSB7XG4gICAgICAvLyBUaHJlYWQgcmVwbGllcyBhcmVuJ3QgYnJva2UgaW50byBkaWZmZXJlbnQgbWVzc2FnZSBzZXRzLCBhY3RpdmVUaHJlYWRNZXNzYWdlcyQgd2lsbCBiZSByZWZyZXNoZWQgYnkgV1MgZXZlbnRzLCBubyBuZWVkIGZvciBhIHJlcXVlc3RcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgYWN0aXZlQ2huYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgY29uc3QgcGFyZW50TWVzc2FnZUlkID0gdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgaWYgKCFwYXJlbnRNZXNzYWdlSWQgfHwgIWFjdGl2ZUNobmFubmVsKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IHRocmVhZE1lc3NhZ2VzID0gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCBsYXN0TWVzc2FnZUlkID1cbiAgICAgIHRocmVhZE1lc3NhZ2VzW2RpcmVjdGlvbiA9PT0gJ29sZGVyJyA/IDAgOiB0aHJlYWRNZXNzYWdlcy5sZW5ndGggLSAxXT8uaWQ7XG4gICAgcmV0dXJuIGFjdGl2ZUNobmFubmVsXG4gICAgICAuZ2V0UmVwbGllcyhwYXJlbnRNZXNzYWdlSWQsIHtcbiAgICAgICAgbGltaXQ6IHRoaXMubWVzc2FnZVBhZ2VTaXplLFxuICAgICAgICBbZGlyZWN0aW9uID09PSAnb2xkZXInID8gJ2lkX2x0JyA6ICdpZF9ndCddOiBsYXN0TWVzc2FnZUlkLFxuICAgICAgfSlcbiAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChcbiAgICAgICAgICBhY3RpdmVDaG5hbm5lbD8uc3RhdGUudGhyZWFkc1twYXJlbnRNZXNzYWdlSWRdIHx8IFtdXG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyaWVzIHRoZSBjaGFubmVscyB3aXRoIHRoZSBnaXZlbiBmaWx0ZXJzLCBzb3J0cyBhbmQgb3B0aW9ucy4gTW9yZSBpbmZvIGFib3V0IFtjaGFubmVsIHF1ZXJ5aW5nXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvcXVlcnlfY2hhbm5lbHMvKSBjYW4gYmUgZm91bmQgaW4gdGhlIHBsYXRmb3JtIGRvY3VtZW50YXRpb24uIEJ5IGRlZmF1bHQgdGhlIGZpcnN0IGNoYW5uZWwgaW4gdGhlIGxpc3Qgd2lsbCBiZSBzZXQgYXMgYWN0aXZlIGNoYW5uZWwgYW5kIHdpbGwgYmUgbWFya2VkIGFzIHJlYWQuXG4gICAqIEBwYXJhbSBmaWx0ZXJzXG4gICAqIEBwYXJhbSBzb3J0XG4gICAqIEBwYXJhbSBvcHRpb25zXG4gICAqIEBwYXJhbSBzaG91bGRTZXRBY3RpdmVDaGFubmVsIERlY2lkZXMgaWYgdGhlIGZpcnN0IGNoYW5uZWwgaW4gdGhlIHJlc3VsdCBzaG91bGQgYmUgbWFkZSBhcyBhbiBhY3RpdmUgY2hhbm5lbCBvciBub3QuXG4gICAqIEByZXR1cm5zIHRoZSBsaXN0IG9mIGNoYW5uZWxzIGZvdW5kIGJ5IHRoZSBxdWVyeVxuICAgKi9cbiAgaW5pdChcbiAgICBmaWx0ZXJzOiBDaGFubmVsRmlsdGVycyxcbiAgICBzb3J0PzogQ2hhbm5lbFNvcnQsXG4gICAgb3B0aW9ucz86IENoYW5uZWxPcHRpb25zLFxuICAgIHNob3VsZFNldEFjdGl2ZUNoYW5uZWw6IGJvb2xlYW4gPSB0cnVlXG4gICkge1xuICAgIHRoaXMuY2hhbm5lbFF1ZXJ5ID0gbmV3IENoYW5uZWxRdWVyeShcbiAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UsXG4gICAgICB0aGlzLFxuICAgICAgZmlsdGVycyxcbiAgICAgIHNvcnQgfHwgeyBsYXN0X21lc3NhZ2VfYXQ6IC0xIH0sXG4gICAgICB7XG4gICAgICAgIGxpbWl0OiAyNSxcbiAgICAgICAgc3RhdGU6IHRydWUsXG4gICAgICAgIHByZXNlbmNlOiB0cnVlLFxuICAgICAgICB3YXRjaDogdHJ1ZSxcbiAgICAgICAgbWVzc2FnZV9saW1pdDogdGhpcy5tZXNzYWdlUGFnZVNpemUsXG4gICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICB9XG4gICAgKTtcbiAgICB0aGlzLmNoYW5uZWxRdWVyeS5jdXN0b21QYWdpbmF0b3IgPSB0aGlzLl9jdXN0b21QYWdpbmF0b3I7XG5cbiAgICByZXR1cm4gdGhpcy5faW5pdCh7XG4gICAgICBzaG91bGRTZXRBY3RpdmVDaGFubmVsLFxuICAgICAgbWVzc2FnZVBhZ2VTaXplOiBvcHRpb25zPy5tZXNzYWdlX2xpbWl0ID8/IHRoaXMubWVzc2FnZVBhZ2VTaXplLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFF1ZXJpZXMgdGhlIGNoYW5uZWxzIHdpdGggdGhlIGdpdmVuIHF1ZXJ5IGZ1bmN0aW9uLiBNb3JlIGluZm8gYWJvdXQgW2NoYW5uZWwgcXVlcnlpbmddKC9jaGF0L2RvY3MvamF2YXNjcmlwdC9xdWVyeV9jaGFubmVscy8pIGNhbiBiZSBmb3VuZCBpbiB0aGUgcGxhdGZvcm0gZG9jdW1lbnRhdGlvbi5cbiAgICogQHBhcmFtIHF1ZXJ5XG4gICAqIEBwYXJhbSBvcHRpb25zXG4gICAqIEBwYXJhbSBvcHRpb25zLnNob3VsZFNldEFjdGl2ZUNoYW5uZWwgVGhlIGBzaG91bGRTZXRBY3RpdmVDaGFubmVsYCBzcGVjaWZpZXMgaWYgdGhlIGZpcnN0IGNoYW5uZWwgaW4gdGhlIHJlc3VsdCBzaG91bGQgYmUgc2VsZWN0ZWQgYXMgdGhlIGFjdGl2ZSBjaGFubmVsIG9yIG5vdC4gRGVmYXVsdCBpcyBgdHJ1ZWAuXG4gICAqIEBwYXJhbSBvcHRpb25zLm1lc3NhZ2VQYWdlU2l6ZSBIb3cgbWFueSBtZXNzYWdlcyBzaG91bGQgd2UgbG9hZD8gVGhlIGRlZmF1bHQgaXMgMjVcbiAgICogQHJldHVybnMgdGhlIGNoYW5uZWxzIHRoYXQgd2VyZSBsb2FkZWRcbiAgICovXG4gIGluaXRXaXRoQ3VzdG9tUXVlcnkoXG4gICAgcXVlcnk6IChxdWVyeVR5cGU6IENoYW5uZWxRdWVyeVR5cGUpID0+IFByb21pc2U8Q2hhbm5lbFF1ZXJ5UmVzdWx0PixcbiAgICBvcHRpb25zOiB7IHNob3VsZFNldEFjdGl2ZUNoYW5uZWw6IGJvb2xlYW47IG1lc3NhZ2VQYWdlU2l6ZTogbnVtYmVyIH0gPSB7XG4gICAgICBzaG91bGRTZXRBY3RpdmVDaGFubmVsOiB0cnVlLFxuICAgICAgbWVzc2FnZVBhZ2VTaXplOiB0aGlzLm1lc3NhZ2VQYWdlU2l6ZSxcbiAgICB9XG4gICkge1xuICAgIHRoaXMuY2hhbm5lbFF1ZXJ5ID0gcXVlcnk7XG4gICAgcmV0dXJuIHRoaXMuX2luaXQob3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUmVzZXRzIHRoZSBgYWN0aXZlQ2hhbm5lbCRgLCBgY2hhbm5lbHMkYCBhbmQgYGFjdGl2ZUNoYW5uZWxNZXNzYWdlcyRgIE9ic2VydmFibGVzLiBVc2VmdWwgd2hlbiBkaXNjb25uZWN0aW5nIGEgY2hhdCB1c2VyLCB1c2UgaW4gY29tYmluYXRpb24gd2l0aCBbYGRpc2Nvbm5lY3RVc2VyYF0oL2NoYXQvZG9jcy9zZGsvYW5ndWxhci9zZXJ2aWNlcy9DaGF0Q2xpZW50U2VydmljZS8jZGlzY29ubmVjdHVzZXIvKS5cbiAgICovXG4gIHJlc2V0KCkge1xuICAgIHRoaXMuZGVzZWxlY3RBY3RpdmVDaGFubmVsKCk7XG4gICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIHRoaXMuY2hhbm5lbFF1ZXJ5U3RhdGVTdWJqZWN0Lm5leHQodW5kZWZpbmVkKTtcbiAgICB0aGlzLmNsaWVudEV2ZW50c1N1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLmRpc21pc3NFcnJvck5vdGlmaWNhdGlvbj8uKCk7XG4gICAgdGhpcy5kaXNtaXNzRXJyb3JOb3RpZmljYXRpb24gPSB1bmRlZmluZWQ7XG4gICAgT2JqZWN0LmtleXModGhpcy5jaGFubmVsU3Vic2NyaXB0aW9ucykuZm9yRWFjaCgoY2lkKSA9PiB7XG4gICAgICB0aGlzLmNoYW5uZWxTdWJzY3JpcHRpb25zW2NpZF0oKTtcbiAgICB9KTtcbiAgICB0aGlzLmNoYW5uZWxTdWJzY3JpcHRpb25zID0ge307XG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIG5leHQgcGFnZSBvZiBjaGFubmVscy4gVGhlIHBhZ2Ugc2l6ZSBjYW4gYmUgc2V0IGluIHRoZSBbcXVlcnkgb3B0aW9uXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvcXVlcnlfY2hhbm5lbHMvI3F1ZXJ5LW9wdGlvbnMpIG9iamVjdC5cbiAgICovXG4gIGFzeW5jIGxvYWRNb3JlQ2hhbm5lbHMoKSB7XG4gICAgYXdhaXQgdGhpcy5xdWVyeUNoYW5uZWxzKGZhbHNlLCAnbmV4dC1wYWdlJyk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHJlYWN0aW9uIHRvIGEgbWVzc2FnZS5cbiAgICogQHBhcmFtIG1lc3NhZ2VJZCBUaGUgaWQgb2YgdGhlIG1lc3NhZ2UgdG8gYWRkIHRoZSByZWFjdGlvbiB0b1xuICAgKiBAcGFyYW0gcmVhY3Rpb25UeXBlIFRoZSB0eXBlIG9mIHRoZSByZWFjdGlvblxuICAgKiBAcGFyYW0gY3VzdG9tRGF0YVxuICAgKi9cbiAgYXN5bmMgYWRkUmVhY3Rpb24oXG4gICAgbWVzc2FnZUlkOiBzdHJpbmcsXG4gICAgcmVhY3Rpb25UeXBlOiBNZXNzYWdlUmVhY3Rpb25UeXBlLFxuICAgIGN1c3RvbURhdGE/OiBDdXN0b21SZWFjdGlvbkRhdGFcbiAgKSB7XG4gICAgYXdhaXQgdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpPy5zZW5kUmVhY3Rpb24obWVzc2FnZUlkLCB7XG4gICAgICB0eXBlOiByZWFjdGlvblR5cGUsXG4gICAgICAuLi5jdXN0b21EYXRhLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYSByZWFjdGlvbiBmcm9tIGEgbWVzc2FnZS5cbiAgICogQHBhcmFtIG1lc3NhZ2VJZCBUaGUgaWQgb2YgdGhlIG1lc3NhZ2UgdG8gcmVtb3ZlIHRoZSByZWFjdGlvbiBmcm9tXG4gICAqIEBwYXJhbSByZWFjdGlvblR5cGUgVGhyIHR5cGUgb2YgcmVhY3Rpb24gdG8gcmVtb3ZlXG4gICAqL1xuICBhc3luYyByZW1vdmVSZWFjdGlvbihtZXNzYWdlSWQ6IHN0cmluZywgcmVhY3Rpb25UeXBlOiBNZXNzYWdlUmVhY3Rpb25UeXBlKSB7XG4gICAgYXdhaXQgdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdFxuICAgICAgLmdldFZhbHVlKClcbiAgICAgID8uZGVsZXRlUmVhY3Rpb24obWVzc2FnZUlkLCByZWFjdGlvblR5cGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIGEgbWVzc2FnZSB0byB0aGUgYWN0aXZlIGNoYW5uZWwuIFRoZSBtZXNzYWdlIGlzIGltbWVkaWF0ZWx5IGFkZGVkIHRvIHRoZSBtZXNzYWdlIGxpc3QsIGlmIGFuIGVycm9yIG9jY3VycyBhbmQgdGhlIG1lc3NhZ2UgY2FuJ3QgYmUgc2VudCwgdGhlIGVycm9yIGlzIGluZGljYXRlZCBpbiBgc3RhdGVgIG9mIHRoZSBtZXNzYWdlLlxuICAgKiBAcGFyYW0gdGV4dCBUaGUgdGV4dCBvZiB0aGUgbWVzc2FnZVxuICAgKiBAcGFyYW0gYXR0YWNobWVudHMgVGhlIGF0dGFjaG1lbnRzXG4gICAqIEBwYXJhbSBtZW50aW9uZWRVc2VycyBNZW50aW9uZWQgdXNlcnNcbiAgICogQHBhcmFtIHBhcmVudElkIElkIG9mIHRoZSBwYXJlbnQgbWVzc2FnZSAoaWYgc2VuZGluZyBhIHRocmVhZCByZXBseSlcbiAgICogQHBhcmFtIHF1b3RlZE1lc3NhZ2VJZCBJZCBvZiB0aGUgbWVzc2FnZSB0byBxdW90ZSAoaWYgc2VuZGluZyBhIHF1b3RlIHJlcGx5KVxuICAgKiBAcGFyYW0gY3VzdG9tRGF0YVxuICAgKiBAcGFyYW0gcG9sbElkIElkIG9mIHRoZSBwb2xsIChpZiBzZW5kaW5nIGEgcG9sbCBtZXNzYWdlKVxuICAgKi9cbiAgYXN5bmMgc2VuZE1lc3NhZ2UoXG4gICAgdGV4dDogc3RyaW5nLFxuICAgIGF0dGFjaG1lbnRzOiBBdHRhY2htZW50W10gPSBbXSxcbiAgICBtZW50aW9uZWRVc2VyczogVXNlclJlc3BvbnNlW10gPSBbXSxcbiAgICBwYXJlbnRJZDogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkLFxuICAgIHF1b3RlZE1lc3NhZ2VJZDogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkLFxuICAgIGN1c3RvbURhdGE6IHVuZGVmaW5lZCB8IEN1c3RvbU1lc3NhZ2VEYXRhID0gdW5kZWZpbmVkLFxuICAgIHBvbGxJZDogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG4gICkge1xuICAgIGxldCBpbnB1dDogTWVzc2FnZUlucHV0ID0ge1xuICAgICAgdGV4dCxcbiAgICAgIGF0dGFjaG1lbnRzLFxuICAgICAgbWVudGlvbmVkVXNlcnMsXG4gICAgICBwYXJlbnRJZCxcbiAgICAgIHF1b3RlZE1lc3NhZ2VJZCxcbiAgICAgIGN1c3RvbURhdGEsXG4gICAgICBwb2xsSWQsXG4gICAgfTtcbiAgICBpZiAodGhpcy5iZWZvcmVTZW5kTWVzc2FnZSkge1xuICAgICAgaW5wdXQgPSBhd2FpdCB0aGlzLmJlZm9yZVNlbmRNZXNzYWdlKGlucHV0KTtcbiAgICB9XG4gICAgY29uc3QgcHJldmlldyA9IGNyZWF0ZU1lc3NhZ2VQcmV2aWV3KFxuICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXIhLFxuICAgICAgaW5wdXQudGV4dCxcbiAgICAgIGlucHV0LmF0dGFjaG1lbnRzLFxuICAgICAgaW5wdXQubWVudGlvbmVkVXNlcnMsXG4gICAgICBpbnB1dC5wYXJlbnRJZCxcbiAgICAgIGlucHV0LnF1b3RlZE1lc3NhZ2VJZCxcbiAgICAgIGlucHV0LmN1c3RvbURhdGEsXG4gICAgICBpbnB1dC5wb2xsSWRcbiAgICApO1xuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgIGNoYW5uZWwuc3RhdGUuYWRkTWVzc2FnZVNvcnRlZChwcmV2aWV3LCB0cnVlKTtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuc2VuZE1lc3NhZ2VSZXF1ZXN0KHByZXZpZXcsIGlucHV0LmN1c3RvbURhdGEpO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNlbmRzIHRoZSBnaXZlbiBtZXNzYWdlIHRvIHRoZSBhY3RpdmUgY2hhbm5lbFxuICAgKiBAcGFyYW0gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byByZXNlbmRcbiAgICovXG4gIGFzeW5jIHJlc2VuZE1lc3NhZ2UobWVzc2FnZTogU3RyZWFtTWVzc2FnZSkge1xuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgIGNoYW5uZWwuc3RhdGUuYWRkTWVzc2FnZVNvcnRlZChcbiAgICAgIHtcbiAgICAgICAgLi4uKG1lc3NhZ2UgYXMgdW5rbm93biBhcyBNZXNzYWdlUmVzcG9uc2UpLFxuICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIHN0cmVhbS1jaGF0IGRvZXNuJ3Qga25vdyBhYm91dCB0aGlzIHByb3BlcnR5XG4gICAgICAgIGVycm9yU3RhdHVzQ29kZTogdW5kZWZpbmVkLFxuICAgICAgICBzdGF0dXM6ICdzZW5kaW5nJyxcbiAgICAgIH0sXG4gICAgICB0cnVlXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5zZW5kTWVzc2FnZVJlcXVlc3QobWVzc2FnZSwgdW5kZWZpbmVkLCB0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoZSBtZXNzYWdlIGluIHRoZSBhY3RpdmUgY2hhbm5lbFxuICAgKiBAcGFyYW0gbWVzc2FnZSBNZXNhZ2UgdG8gYmUgdXBkYXRlZFxuICAgKi9cbiAgYXN5bmMgdXBkYXRlTWVzc2FnZShtZXNzYWdlOiBTdHJlYW1NZXNzYWdlKSB7XG4gICAgbGV0IG1lc3NhZ2VUb1VwZGF0ZTogU3RyZWFtTWVzc2FnZSA9IHtcbiAgICAgIC4uLm1lc3NhZ2UsXG4gICAgfTtcbiAgICBpZiAobWVzc2FnZVRvVXBkYXRlLnF1b3RlZF9tZXNzYWdlKSB7XG4gICAgICBtZXNzYWdlVG9VcGRhdGUucXVvdGVkX21lc3NhZ2UgPSB7XG4gICAgICAgIC4uLm1lc3NhZ2VUb1VwZGF0ZS5xdW90ZWRfbWVzc2FnZSxcbiAgICAgIH07XG4gICAgfVxuICAgIGRlbGV0ZSBtZXNzYWdlVG9VcGRhdGUuaTE4bjtcbiAgICBpZiAodGhpcy5iZWZvcmVVcGRhdGVNZXNzYWdlKSB7XG4gICAgICBtZXNzYWdlVG9VcGRhdGUgPSBhd2FpdCB0aGlzLmJlZm9yZVVwZGF0ZU1lc3NhZ2UobWVzc2FnZVRvVXBkYXRlKTtcbiAgICB9XG4gICAgaWYgKG1lc3NhZ2VUb1VwZGF0ZS5yZWFkQnkpIHtcbiAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgdGhpcyBpcyBvbmx5IGEgcnVuIHRpbWUgcHJvcGFydHkgZm9yIHRoZSBTREtcbiAgICAgIGRlbGV0ZSBtZXNzYWdlVG9VcGRhdGUucmVhZEJ5O1xuICAgIH1cbiAgICBpZiAobWVzc2FnZVRvVXBkYXRlLnRyYW5zbGF0aW9uKSB7XG4gICAgICBkZWxldGUgbWVzc2FnZVRvVXBkYXRlLnRyYW5zbGF0aW9uO1xuICAgIH1cbiAgICBpZiAobWVzc2FnZVRvVXBkYXRlLnF1b3RlZF9tZXNzYWdlPy50cmFuc2xhdGlvbikge1xuICAgICAgZGVsZXRlIG1lc3NhZ2VUb1VwZGF0ZS5xdW90ZWRfbWVzc2FnZS50cmFuc2xhdGlvbjtcbiAgICB9XG4gICAgaWYgKG1lc3NhZ2UubW9kZXJhdGlvbl9kZXRhaWxzKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZXNlbmRNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIH1cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51cGRhdGVNZXNzYWdlKFxuICAgICAgbWVzc2FnZVRvVXBkYXRlIGFzIHVua25vd24gYXMgTG9jYWxNZXNzYWdlXG4gICAgKTtcblxuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmNoYW5uZWxzU3ViamVjdFxuICAgICAgLmdldFZhbHVlKClcbiAgICAgID8uZmluZCgoYykgPT4gYy5jaWQgPT09IG1lc3NhZ2UuY2lkKTtcblxuICAgIGlmIChcbiAgICAgIHJlc3BvbnNlLm1lc3NhZ2UudHlwZSA9PT0gJ2Vycm9yJyAmJlxuICAgICAgcmVzcG9uc2UubWVzc2FnZS5tb2RlcmF0aW9uX2RldGFpbHNcbiAgICApIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICdzdHJlYW1DaGF0LlRoaXMgbWVzc2FnZSBkaWQgbm90IG1lZXQgb3VyIGNvbnRlbnQgZ3VpZGVsaW5lcydcbiAgICAgICk7XG4gICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy50cmFuc2Zvcm1Ub1N0cmVhbU1lc3NhZ2UocmVzcG9uc2UubWVzc2FnZSwgY2hhbm5lbCk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyB0aGUgbWVzc2FnZSBmcm9tIHRoZSBhY3RpdmUgY2hhbm5lbFxuICAgKiBAcGFyYW0gbWVzc2FnZSBNZXNzYWdlIHRvIGJlIGRlbGV0ZWRcbiAgICogQHBhcmFtIGlzTG9jYWxEZWxldGUgc2V0IHRoaXMgYHRydWVgIGlmIHlvdSB3YW50IHRvIGRlbGV0ZSBhIG1lc3NhZ2UgdGhhdCdzIG9ubHkgcGFydCBvZiB0aGUgbG9jYWwgc3RhdGUsIG5vdCB5ZXQgc2F2ZWQgb24gdGhlIGJhY2tlbmRcbiAgICovXG4gIGFzeW5jIGRlbGV0ZU1lc3NhZ2UobWVzc2FnZTogU3RyZWFtTWVzc2FnZSwgaXNMb2NhbERlbGV0ZSA9IGZhbHNlKSB7XG4gICAgaWYgKGlzTG9jYWxEZWxldGUgJiYgdGhpcy5hY3RpdmVDaGFubmVsKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSB0aGlzLmFjdGl2ZUNoYW5uZWwuc3RhdGUucmVtb3ZlTWVzc2FnZSh7XG4gICAgICAgIGlkOiBtZXNzYWdlLmlkLFxuICAgICAgICBwYXJlbnRfaWQ6IG1lc3NhZ2UucGFyZW50X2lkLFxuICAgICAgfSk7XG4gICAgICBpZiAocmVzdWx0KSB7XG4gICAgICAgIG1lc3NhZ2UucGFyZW50X2lkXG4gICAgICAgICAgPyB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFxuICAgICAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWwuc3RhdGUudGhyZWFkc1ttZXNzYWdlLnBhcmVudF9pZF1cbiAgICAgICAgICAgIClcbiAgICAgICAgICA6IHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFxuICAgICAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWwuc3RhdGUubWVzc2FnZXNcbiAgICAgICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh0aGlzLm1lc3NhZ2VEZWxldGVDb25maXJtYXRpb25IYW5kbGVyKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLm1lc3NhZ2VEZWxldGVDb25maXJtYXRpb25IYW5kbGVyKG1lc3NhZ2UpO1xuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICBhd2FpdCB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQuZGVsZXRlTWVzc2FnZShtZXNzYWdlLmlkKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LmRlbGV0ZU1lc3NhZ2UobWVzc2FnZS5pZCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVwbG9hZHMgZmlsZXMgdG8gdGhlIGNoYW5uZWwuIElmIHlvdSB3YW50IHRvIGtub3cgbW9yZSBhYm91dCBbZmlsZSB1cGxvYWRzXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvZmlsZV91cGxvYWRzLykgY2hlY2sgb3V0IHRoZSBwbGF0Zm9ybSBkb2N1bWVudGF0aW9uLlxuICAgKiBAcGFyYW0gdXBsb2FkcyB0aGUgYXR0YWNobWVudHMgdG8gdXBsb2FkIChvdXRwdXQgb2YgdGhlIFtgQXR0YWNobWVudFNlcnZpY2VgXSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL3NlcnZpY2VzL0F0dGFjaG1lbnRTZXJ2aWNlLykpXG4gICAqIEByZXR1cm5zIHRoZSByZXN1bHQgb2YgZmlsZSB1cGxvYWQgcmVxdWVzdHNcbiAgICovXG4gIGFzeW5jIHVwbG9hZEF0dGFjaG1lbnRzKFxuICAgIHVwbG9hZHM6IEF0dGFjaG1lbnRVcGxvYWRbXVxuICApOiBQcm9taXNlPEF0dGFjaG1lbnRVcGxvYWRbXT4ge1xuICAgIGNvbnN0IHJlc3VsdDogQXR0YWNobWVudFVwbG9hZFtdID0gW107XG4gICAgY29uc3QgY2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSE7XG4gICAgY29uc3QgdXBsb2FkUmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChcbiAgICAgIHVwbG9hZHMubWFwKCh1cGxvYWQpID0+XG4gICAgICAgIHVwbG9hZC50eXBlID09PSAnaW1hZ2UnXG4gICAgICAgICAgPyB0aGlzLmN1c3RvbUltYWdlVXBsb2FkUmVxdWVzdFxuICAgICAgICAgICAgPyB0aGlzLmN1c3RvbUltYWdlVXBsb2FkUmVxdWVzdCh1cGxvYWQuZmlsZSwgY2hhbm5lbClcbiAgICAgICAgICAgIDogY2hhbm5lbC5zZW5kSW1hZ2UodXBsb2FkLmZpbGUsIHVwbG9hZC5maWxlLm5hbWUsIHVwbG9hZC5maWxlLnR5cGUpXG4gICAgICAgICAgOiB0aGlzLmN1c3RvbUZpbGVVcGxvYWRSZXF1ZXN0XG4gICAgICAgICAgPyB0aGlzLmN1c3RvbUZpbGVVcGxvYWRSZXF1ZXN0KHVwbG9hZC5maWxlLCBjaGFubmVsKVxuICAgICAgICAgIDogY2hhbm5lbC5zZW5kRmlsZSh1cGxvYWQuZmlsZSwgdXBsb2FkLmZpbGUubmFtZSwgdXBsb2FkLmZpbGUudHlwZSlcbiAgICAgIClcbiAgICApO1xuICAgIHVwbG9hZFJlc3VsdHMuZm9yRWFjaCgodXBsb2FkUmVzdWx0LCBpKSA9PiB7XG4gICAgICBjb25zdCBmaWxlID0gdXBsb2Fkc1tpXS5maWxlO1xuICAgICAgY29uc3QgdHlwZSA9IHVwbG9hZHNbaV0udHlwZTtcbiAgICAgIGlmICh1cGxvYWRSZXN1bHQuc3RhdHVzID09PSAnZnVsZmlsbGVkJykge1xuICAgICAgICByZXN1bHQucHVzaCh7XG4gICAgICAgICAgZmlsZSxcbiAgICAgICAgICB0eXBlLFxuICAgICAgICAgIHN0YXRlOiAnc3VjY2VzcycsXG4gICAgICAgICAgdXJsOiB1cGxvYWRSZXN1bHQudmFsdWUuZmlsZSxcbiAgICAgICAgICAvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1hc3NpZ25tZW50LCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLW1lbWJlci1hY2Nlc3MsIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi9cbiAgICAgICAgICB0aHVtYl91cmw6ICh1cGxvYWRSZXN1bHQudmFsdWUgYXMgYW55KS50aHVtYl91cmwsXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IHJlYXNvbjogQXR0YWNobWVudFVwbG9hZEVycm9yUmVhc29uID0gJ3Vua25vd24nO1xuICAgICAgICBsZXQgZXh0cmFEYXRhOiB7IHBhcmFtOiBzdHJpbmcgfSB8IHVuZGVmaW5lZDtcbiAgICAgICAgLyogZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtYXNzaWdubWVudCAqL1xuICAgICAgICBjb25zdCBtZXNzYWdlOiBzdHJpbmcgfCB1bmRlZmluZWQgPVxuICAgICAgICAgIC8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLW1lbWJlci1hY2Nlc3MgKi9cbiAgICAgICAgICB1cGxvYWRSZXN1bHQucmVhc29uLnJlc3BvbnNlPy5kYXRhPy5tZXNzYWdlO1xuICAgICAgICAvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1hc3NpZ25tZW50ICovXG4gICAgICAgIGNvbnN0IGNvZGU6IG51bWJlciB8IHVuZGVmaW5lZCA9XG4gICAgICAgICAgLyogZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtbWVtYmVyLWFjY2VzcyAqL1xuICAgICAgICAgIHVwbG9hZFJlc3VsdC5yZWFzb24ucmVzcG9uc2U/LmRhdGE/LmNvZGU7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBjb2RlID09PSAyMiB8fFxuICAgICAgICAgIChjb2RlID09PSA0ICYmIG1lc3NhZ2U/LnRvTG93ZXJDYXNlKCk/LmluY2x1ZGVzKCdieXRlcycpKVxuICAgICAgICApIHtcbiAgICAgICAgICByZWFzb24gPSAnZmlsZS1zaXplJztcbiAgICAgICAgICBleHRyYURhdGEgPSB7XG4gICAgICAgICAgICBwYXJhbTpcbiAgICAgICAgICAgICAgL1xcZCtNQnxcXGQrXFxzP2J5dGVzLy5leGVjKG1lc3NhZ2UgfHwgJycpPy5bMF0gfHxcbiAgICAgICAgICAgICAgYCR7dGhpcy5hdHRhY2htZW50TWF4U2l6ZUZhbGxiYWNrSW5NQn1NQmAsXG4gICAgICAgICAgfTtcbiAgICAgICAgICBpZiAoZXh0cmFEYXRhLnBhcmFtLmluY2x1ZGVzKCdieXRlcycpKSB7XG4gICAgICAgICAgICBjb25zdCBsaW1pdEluQnl0ZXMgPSArKFxuICAgICAgICAgICAgICAvXFxkKy8uZXhlYyhleHRyYURhdGEucGFyYW0pPy5bMF0gfHxcbiAgICAgICAgICAgICAgdGhpcy5hdHRhY2htZW50TWF4U2l6ZUZhbGxiYWNrSW5NQiAqIDEwMjQgKiAxMDI0XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZXh0cmFEYXRhLnBhcmFtID0gYCR7bGltaXRJbkJ5dGVzIC8gKDEwMjQgKiAxMDI0KX1NQmA7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgIGNvZGUgPT09IDQgJiZcbiAgICAgICAgICBtZXNzYWdlPy50b0xvd2VyQ2FzZSgpPy5pbmNsdWRlcygnZmlsZSBleHRlbnNpb24nKVxuICAgICAgICApIHtcbiAgICAgICAgICByZWFzb24gPSAnZmlsZS1leHRlbnNpb24nO1xuICAgICAgICAgIGV4dHJhRGF0YSA9IHsgcGFyYW06IC9cXC5cXHcrLy5leGVjKG1lc3NhZ2UpPy5bMF0gfHwgJycgfTtcbiAgICAgICAgfVxuICAgICAgICByZXN1bHQucHVzaCh7XG4gICAgICAgICAgZmlsZSxcbiAgICAgICAgICB0eXBlLFxuICAgICAgICAgIHN0YXRlOiAnZXJyb3InLFxuICAgICAgICAgIGVycm9yUmVhc29uOiByZWFzb24sXG4gICAgICAgICAgZXJyb3JFeHRyYUluZm86IGV4dHJhRGF0YSA/IFtleHRyYURhdGFdIDogdW5kZWZpbmVkLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyBhbiB1cGxvYWRlZCBmaWxlIGJ5IFVSTC4gSWYgeW91IHdhbnQgdG8ga25vdyBtb3JlIGFib3V0IFtmaWxlIHVwbG9hZHNdKC9jaGF0L2RvY3MvamF2YXNjcmlwdC9maWxlX3VwbG9hZHMvKSBjaGVjayBvdXQgdGhlIHBsYXRmb3JtIGRvY3VtZW50YXRpb25cbiAgICogQHBhcmFtIGF0dGFjaG1lbnRVcGxvYWQgQXR0YWNobWVudCB0byBiZSBkZWxldGVkIChvdXRwdXQgb2YgdGhlIFtgQXR0YWNobWVudFNlcnZpY2VgXSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL3NlcnZpY2VzL0F0dGFjaG1lbnRTZXJ2aWNlLykpXG4gICAqL1xuICBhc3luYyBkZWxldGVBdHRhY2htZW50KGF0dGFjaG1lbnRVcGxvYWQ6IEF0dGFjaG1lbnRVcGxvYWQpIHtcbiAgICBjb25zdCBjaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpITtcbiAgICBhd2FpdCAoYXR0YWNobWVudFVwbG9hZC50eXBlID09PSAnaW1hZ2UnXG4gICAgICA/IHRoaXMuY3VzdG9tSW1hZ2VEZWxldGVSZXF1ZXN0XG4gICAgICAgID8gdGhpcy5jdXN0b21JbWFnZURlbGV0ZVJlcXVlc3QoYXR0YWNobWVudFVwbG9hZC51cmwhLCBjaGFubmVsKVxuICAgICAgICA6IGNoYW5uZWwuZGVsZXRlSW1hZ2UoYXR0YWNobWVudFVwbG9hZC51cmwhKVxuICAgICAgOiB0aGlzLmN1c3RvbUZpbGVEZWxldGVSZXF1ZXN0XG4gICAgICA/IHRoaXMuY3VzdG9tRmlsZURlbGV0ZVJlcXVlc3QoYXR0YWNobWVudFVwbG9hZC51cmwhLCBjaGFubmVsKVxuICAgICAgOiBjaGFubmVsLmRlbGV0ZUZpbGUoYXR0YWNobWVudFVwbG9hZC51cmwhKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXV0b2NvbXBsZXRlIG9wdGlvbnMgZm9yIGN1cnJlbnQgY2hhbm5lbCBtZW1iZXJzLiBJZiB0aGUgY2hhbm5lbCBoYXMgbGVzcyB0aGFuIDEwMCBtZW1iZXJzLCBpdCByZXR1cm5zIHRoZSBjaGFubmVsIG1lbWJlcnMsIG90aGVyd2lzZSBzZW5kcyBhIFtzZWFyY2ggcmVxdWVzdF0oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L3F1ZXJ5X21lbWJlcnMvI3BhZ2luYXRpb24tYW5kLW9yZGVyaW5nKSB3aXRoIHRoZSBnaXZlbiBzZWFyY2ggdGVybS5cbiAgICogQHBhcmFtIHNlYXJjaFRlcm0gVGV4dCB0byBzZWFyY2ggZm9yIGluIHRoZSBuYW1lcyBvZiBtZW1iZXJzXG4gICAqIEByZXR1cm5zIFRoZSBsaXN0IG9mIG1lbWJlcnMgbWF0Y2hpbmcgdGhlIHNlYXJjaCBmaWx0ZXJcbiAgICovXG4gIGFzeW5jIGF1dG9jb21wbGV0ZU1lbWJlcnMoc2VhcmNoVGVybTogc3RyaW5nKSB7XG4gICAgY29uc3QgYWN0aXZlQ2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBpZiAoIWFjdGl2ZUNoYW5uZWwpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgaWYgKE9iamVjdC5rZXlzKGFjdGl2ZUNoYW5uZWwuc3RhdGUubWVtYmVycykubGVuZ3RoIDwgMTAwKSB7XG4gICAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyhhY3RpdmVDaGFubmVsLnN0YXRlLm1lbWJlcnMpLmZpbHRlcihcbiAgICAgICAgKG0pID0+IG0udXNlcj8uaWQgIT09IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51c2VySUQhXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoIXNlYXJjaFRlcm0pIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYWN0aXZlQ2hhbm5lbC5xdWVyeU1lbWJlcnMoe1xuICAgICAgICBuYW1lOiB7ICRhdXRvY29tcGxldGU6IHNlYXJjaFRlcm0gfSxcbiAgICAgIH0gYXMgTWVtYmVyRmlsdGVycyk7IC8vIFRPRE86IGZpbmQgb3V0IHdoeSB3ZSBuZWVkIHR5cGVjYXN0IGhlcmVcblxuICAgICAgcmV0dXJuIHJlc3VsdC5tZW1iZXJzLmZpbHRlcihcbiAgICAgICAgKG0pID0+IG0udXNlcl9pZCAhPT0gdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50Py51c2VyPy5pZFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogW1J1bnMgYSBtZXNzYWdlIGFjdGlvbl0oaHR0cHM6Ly9nZXRzdHJlYW0uaW8vY2hhdC9kb2NzL3Jlc3QvI21lc3NhZ2VzLXJ1bm1lc3NhZ2VhY3Rpb24pIGluIHRoZSBjdXJyZW50IGNoYW5uZWwuIFVwZGF0ZXMgdGhlIG1lc3NhZ2UgbGlzdCBiYXNlZCBvbiB0aGUgYWN0aW9uIHJlc3VsdCAoaWYgbm8gbWVzc2FnZSBpcyByZXR1cm5lZCwgdGhlIG1lc3NhZ2Ugd2lsbCBiZSByZW1vdmVkIGZyb20gdGhlIG1lc3NhZ2UgbGlzdCkuXG4gICAqIEBwYXJhbSBtZXNzYWdlSWRcbiAgICogQHBhcmFtIGZvcm1EYXRhXG4gICAqIEBwYXJhbSBwYXJlbnRNZXNzYWdlSWRcbiAgICovXG4gIGFzeW5jIHNlbmRBY3Rpb24oXG4gICAgbWVzc2FnZUlkOiBzdHJpbmcsXG4gICAgZm9ybURhdGE6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4sXG4gICAgcGFyZW50TWVzc2FnZUlkPzogc3RyaW5nXG4gICkge1xuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2hhbm5lbC5zZW5kQWN0aW9uKG1lc3NhZ2VJZCwgZm9ybURhdGEpO1xuICAgIGlmIChyZXNwb25zZT8ubWVzc2FnZSkge1xuICAgICAgY2hhbm5lbC5zdGF0ZS5hZGRNZXNzYWdlU29ydGVkKHtcbiAgICAgICAgLi4ucmVzcG9uc2UubWVzc2FnZSxcbiAgICAgICAgc3RhdHVzOiAncmVjZWl2ZWQnLFxuICAgICAgfSk7XG4gICAgICBjb25zdCBpc1RocmVhZFJlcGx5ID0gISFyZXNwb25zZS5tZXNzYWdlLnBhcmVudF9pZDtcbiAgICAgIGlzVGhyZWFkUmVwbHlcbiAgICAgICAgPyB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtcbiAgICAgICAgICAgIC4uLmNoYW5uZWwuc3RhdGUudGhyZWFkc1tyZXNwb25zZS5tZXNzYWdlLnBhcmVudF9pZCFdLFxuICAgICAgICAgIF0pXG4gICAgICAgIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLmNoYW5uZWwuc3RhdGUubWVzc2FnZXNdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY2hhbm5lbC5zdGF0ZS5yZW1vdmVNZXNzYWdlKHtcbiAgICAgICAgaWQ6IG1lc3NhZ2VJZCxcbiAgICAgICAgcGFyZW50X2lkOiBwYXJlbnRNZXNzYWdlSWQsXG4gICAgICB9KTtcbiAgICAgIGlmIChwYXJlbnRNZXNzYWdlSWQpIHtcbiAgICAgICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChcbiAgICAgICAgICBjaGFubmVsLnN0YXRlLnRocmVhZHNbdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0LmdldFZhbHVlKCkhXVxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLmNoYW5uZWwuc3RhdGUubWVzc2FnZXNdKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2VsZWN0cyBvciBkZXNlbGVjdHMgdGhlIGN1cnJlbnQgbWVzc2FnZSB0byBxdW90ZSByZXBseSB0b1xuICAgKiBAcGFyYW0gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byBzZWxlY3QsIGlmIGNhbGxlZCB3aXRoIGB1bmRlZmluZWRgLCBpdCBkZXNlbGVjdHMgdGhlIG1lc3NhZ2VcbiAgICovXG4gIHNlbGVjdE1lc3NhZ2VUb1F1b3RlKG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UgfCB1bmRlZmluZWQgfCBNZXNzYWdlUmVzcG9uc2UpIHtcbiAgICBpZiAobWVzc2FnZSAmJiAhdGhpcy5pc1N0cmVhbU1lc3NhZ2UobWVzc2FnZSkpIHtcbiAgICAgIG1lc3NhZ2UgPSB0aGlzLnRyYW5zZm9ybVRvU3RyZWFtTWVzc2FnZShtZXNzYWdlKTtcbiAgICB9XG4gICAgdGhpcy5tZXNzYWdlVG9RdW90ZVN1YmplY3QubmV4dChtZXNzYWdlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBuZXcgY2hhbm5lbCB0byB0aGUgY2hhbm5lbCBsaXN0XG4gICAqIFRoZSBjaGFubmVsIHdpbGwgYmUgYWRkZWQgdG8gdGhlIGJlZ2lubmluZyBvZiB0aGUgY2hhbm5lbCBsaXN0XG4gICAqIEBwYXJhbSBjaGFubmVsXG4gICAqL1xuICBhZGRDaGFubmVsKGNoYW5uZWw6IENoYW5uZWwpIHtcbiAgICBpZiAoIXRoaXMuY2hhbm5lbHMuZmluZCgoYykgPT4gYy5jaWQgPT09IGNoYW5uZWwuY2lkKSkge1xuICAgICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dChbY2hhbm5lbCwgLi4udGhpcy5jaGFubmVsc10pO1xuICAgICAgdGhpcy53YXRjaEZvckNoYW5uZWxFdmVudHMoY2hhbm5lbCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIEBwYXJhbSBjaWRcbiAgICogQHBhcmFtIHNob3VsZFN0b3BXYXRjaGluZ1xuICAgKi9cbiAgcmVtb3ZlQ2hhbm5lbChjaWQ6IHN0cmluZywgc2hvdWxkU3RvcFdhdGNoaW5nID0gdHJ1ZSkge1xuICAgIGNvbnN0IHJlbWFpbmluZ0NoYW5uZWxzID0gdGhpcy5jaGFubmVscy5maWx0ZXIoKGMpID0+IGMuY2lkICE9PSBjaWQpO1xuXG4gICAgaWYgKHNob3VsZFN0b3BXYXRjaGluZykge1xuICAgICAgaWYgKHRoaXMuY2hhbm5lbFN1YnNjcmlwdGlvbnNbY2lkXSkge1xuICAgICAgICB0aGlzLmNoYW5uZWxTdWJzY3JpcHRpb25zW2NpZF0oKTtcbiAgICAgICAgZGVsZXRlIHRoaXMuY2hhbm5lbFN1YnNjcmlwdGlvbnMuY2lkO1xuICAgICAgfVxuICAgICAgdm9pZCB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQuYWN0aXZlQ2hhbm5lbHNbY2lkXVxuICAgICAgICA/LnN0b3BXYXRjaGluZygpXG4gICAgICAgIC5jYXRjaCgoZXJyKSA9PlxuICAgICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC5sb2dnZXIoXG4gICAgICAgICAgICAnd2FybicsXG4gICAgICAgICAgICAnRmFpbGVkIHRvIHVud2F0Y2ggY2hhbm5lbCcsXG4gICAgICAgICAgICBlcnIgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj5cbiAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKHJlbWFpbmluZ0NoYW5uZWxzLmxlbmd0aCA8IHRoaXMuY2hhbm5lbHMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmNoYW5uZWxzU3ViamVjdC5uZXh0KHJlbWFpbmluZ0NoYW5uZWxzKTtcbiAgICAgIGlmIChjaWQgPT09IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKT8uY2lkKSB7XG4gICAgICAgIGlmIChyZW1haW5pbmdDaGFubmVscy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgdGhpcy5zZXRBc0FjdGl2ZUNoYW5uZWwocmVtYWluaW5nQ2hhbm5lbHNbMF0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZW5kTWVzc2FnZVJlcXVlc3QoXG4gICAgcHJldmlldzogTWVzc2FnZVJlc3BvbnNlIHwgU3RyZWFtTWVzc2FnZSxcbiAgICBjdXN0b21EYXRhPzogQ3VzdG9tTWVzc2FnZURhdGEsXG4gICAgaXNSZXNlbmQgPSBmYWxzZVxuICApIHtcbiAgICBjb25zdCBjaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpITtcbiAgICBjb25zdCBpc1RocmVhZFJlcGx5ID0gISFwcmV2aWV3LnBhcmVudF9pZDtcbiAgICBpc1RocmVhZFJlcGx5XG4gICAgICA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW1xuICAgICAgICAgIC4uLmNoYW5uZWwuc3RhdGUudGhyZWFkc1twcmV2aWV3LnBhcmVudF9pZCFdLFxuICAgICAgICBdKVxuICAgICAgOiB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QubmV4dChbLi4uY2hhbm5lbC5zdGF0ZS5tZXNzYWdlc10pO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNoYW5uZWwuc2VuZE1lc3NhZ2Uoe1xuICAgICAgICBpZDogcHJldmlldy5pZCxcbiAgICAgICAgdGV4dDogcHJldmlldy50ZXh0LFxuICAgICAgICBhdHRhY2htZW50czogcHJldmlldy5hdHRhY2htZW50cyxcbiAgICAgICAgbWVudGlvbmVkX3VzZXJzOiBwcmV2aWV3Lm1lbnRpb25lZF91c2Vycz8ubWFwKCh1KSA9PiB1LmlkKSxcbiAgICAgICAgcGFyZW50X2lkOiBwcmV2aWV3LnBhcmVudF9pZCxcbiAgICAgICAgcXVvdGVkX21lc3NhZ2VfaWQ6IHByZXZpZXcucXVvdGVkX21lc3NhZ2VfaWQsXG4gICAgICAgIHBvbGxfaWQ6IHByZXZpZXcucG9sbF9pZCxcbiAgICAgICAgLi4uY3VzdG9tRGF0YSxcbiAgICAgIH0gYXMgTWVzc2FnZSk7IC8vIFRPRE86IGZpbmQgb3V0IHdoeSB3ZSBuZWVkIHR5cGVjYXN0IGhlcmVcbiAgICAgIGNoYW5uZWwuc3RhdGUuYWRkTWVzc2FnZVNvcnRlZChcbiAgICAgICAge1xuICAgICAgICAgIC4uLnJlc3BvbnNlLm1lc3NhZ2UsXG4gICAgICAgICAgc3RhdHVzOiAncmVjZWl2ZWQnLFxuICAgICAgICB9LFxuICAgICAgICB0cnVlXG4gICAgICApO1xuICAgICAgaXNUaHJlYWRSZXBseVxuICAgICAgICA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW1xuICAgICAgICAgICAgLi4uY2hhbm5lbC5zdGF0ZS50aHJlYWRzW3ByZXZpZXcucGFyZW50X2lkIV0sXG4gICAgICAgICAgXSlcbiAgICAgICAgOiB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QubmV4dChbLi4uY2hhbm5lbC5zdGF0ZS5tZXNzYWdlc10pO1xuICAgICAgbGV0IG1lc3NhZ2VzITogU3RyZWFtTWVzc2FnZVtdO1xuICAgICAgKGlzVGhyZWFkUmVwbHkgPyB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzJCA6IHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzJClcbiAgICAgICAgLnBpcGUodGFrZSgxKSlcbiAgICAgICAgLnN1YnNjcmliZSgobSkgPT4gKG1lc3NhZ2VzID0gbSkpO1xuICAgICAgY29uc3QgbmV3TWVzc2FnZSA9IG1lc3NhZ2VzW21lc3NhZ2VzLmxlbmd0aCAtIDFdO1xuICAgICAgcmV0dXJuIG5ld01lc3NhZ2U7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnN0IHN0cmluZ0Vycm9yID0gSlNPTi5zdHJpbmdpZnkoZXJyb3IpO1xuICAgICAgY29uc3QgcGFyc2VkRXJyb3I6IHtcbiAgICAgICAgc3RhdHVzPzogbnVtYmVyO1xuICAgICAgICBjb2RlPzogbnVtYmVyO1xuICAgICAgICByZXNwb25zZT86IHsgZGF0YT86IHsgbWVzc2FnZT86IHN0cmluZyB9IH07XG4gICAgICB9ID0gc3RyaW5nRXJyb3IgPyAoSlNPTi5wYXJzZShzdHJpbmdFcnJvcikgYXMgeyBzdGF0dXM/OiBudW1iZXIgfSkgOiB7fTtcblxuICAgICAgbGV0IGlzQWxyZWFkeUV4aXN0cyA9IGZhbHNlO1xuICAgICAgaWYgKGlzUmVzZW5kKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBwYXJzZWRFcnJvci5zdGF0dXMgPT09IDQwMCAmJlxuICAgICAgICAgIHBhcnNlZEVycm9yLmNvZGUgPT09IDQgJiZcbiAgICAgICAgICBwYXJzZWRFcnJvcj8ucmVzcG9uc2U/LmRhdGE/Lm1lc3NhZ2U/LmluY2x1ZGVzKCdhbHJlYWR5IGV4aXN0cycpXG4gICAgICAgICkge1xuICAgICAgICAgIGlzQWxyZWFkeUV4aXN0cyA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY2hhbm5lbC5zdGF0ZS5hZGRNZXNzYWdlU29ydGVkKFxuICAgICAgICB7XG4gICAgICAgICAgLi4uKHByZXZpZXcgYXMgTWVzc2FnZVJlc3BvbnNlKSxcbiAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIHN0cmVhbS1jaGF0IGRvZXNuJ3Qga25vdyBhYm91dCB0aGlzIHByb3BlcnR5XG4gICAgICAgICAgZXJyb3JTdGF0dXNDb2RlOiBpc0FscmVhZHlFeGlzdHNcbiAgICAgICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgICAgICA6IHBhcnNlZEVycm9yLnN0YXR1cyB8fCB1bmRlZmluZWQsXG4gICAgICAgICAgc3RhdHVzOiBpc0FscmVhZHlFeGlzdHMgPyAncmVjZWl2ZWQnIDogJ2ZhaWxlZCcsXG4gICAgICAgIH0sXG4gICAgICAgIHRydWVcbiAgICAgICk7XG4gICAgICBpc1RocmVhZFJlcGx5XG4gICAgICAgID8gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChbXG4gICAgICAgICAgICAuLi5jaGFubmVsLnN0YXRlLnRocmVhZHNbcHJldmlldy5wYXJlbnRfaWQhXSxcbiAgICAgICAgICBdKVxuICAgICAgICA6IHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5jaGFubmVsLnN0YXRlLm1lc3NhZ2VzXSk7XG4gICAgICBsZXQgbWVzc2FnZXMhOiBTdHJlYW1NZXNzYWdlW107XG4gICAgICAoaXNUaHJlYWRSZXBseSA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXMkIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkKVxuICAgICAgICAucGlwZSh0YWtlKDEpKVxuICAgICAgICAuc3Vic2NyaWJlKChtKSA9PiAobWVzc2FnZXMgPSBtKSk7XG4gICAgICBjb25zdCBuZXdNZXNzYWdlID0gbWVzc2FnZXNbbWVzc2FnZXMubGVuZ3RoIC0gMV07XG4gICAgICByZXR1cm4gbmV3TWVzc2FnZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSnVtcHMgdG8gdGhlIHNlbGVjdGVkIG1lc3NhZ2UgaW5zaWRlIHRoZSBtZXNzYWdlIGxpc3QsIGlmIHRoZSBtZXNzYWdlIGlzIG5vdCB5ZXQgbG9hZGVkLCBpdCdsbCBsb2FkIHRoZSBtZXNzYWdlIChhbmQgaXQncyBzdXJyb3VuZGluZ3MpIGZyb20gdGhlIEFQSS5cbiAgICogQHBhcmFtIG1lc3NhZ2VJZCBUaGUgSUQgb2YgdGhlIG1lc3NhZ2UgdG8gYmUgbG9hZGVkLCAnbGF0ZXN0JyBtZWFucyBqdW1wIHRvIHRoZSBsYXRlc3QgbWVzc2FnZXNcbiAgICogQHBhcmFtIHBhcmVudE1lc3NhZ2VJZCBUaGUgSUQgb2YgdGhlIHBhcmVudCBtZXNzYWdlIGlmIHdlIHdhbnQgdG8gbG9hZCBhIHRocmVhZCBtZXNzYWdlXG4gICAqL1xuICBhc3luYyBqdW1wVG9NZXNzYWdlKG1lc3NhZ2VJZDogc3RyaW5nLCBwYXJlbnRNZXNzYWdlSWQ/OiBzdHJpbmcpIHtcbiAgICB0aGlzLmlzTWVzc2FnZUxvYWRpbmdJblByb2dyZXNzID0gdHJ1ZTtcbiAgICBjb25zdCBhY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBhY3RpdmVDaGFubmVsPy5zdGF0ZS5sb2FkTWVzc2FnZUludG9TdGF0ZShcbiAgICAgICAgbWVzc2FnZUlkLFxuICAgICAgICBwYXJlbnRNZXNzYWdlSWRcbiAgICAgICk7XG4gICAgICBjb25zdCBtZXNzYWdlcyA9IGFjdGl2ZUNoYW5uZWw/LnN0YXRlLm1lc3NhZ2VzIHx8IFtdO1xuICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLm1lc3NhZ2VzXSk7XG4gICAgICBpZiAocGFyZW50TWVzc2FnZUlkKSB7XG4gICAgICAgIGNvbnN0IHBhcmVudE1lc3NhZ2UgPSBtZXNzYWdlcy5maW5kKChtKSA9PiBtLmlkID09PSBwYXJlbnRNZXNzYWdlSWQpO1xuICAgICAgICB2b2lkIHRoaXMuc2V0QXNBY3RpdmVQYXJlbnRNZXNzYWdlKFxuICAgICAgICAgIHBhcmVudE1lc3NhZ2UgYXMgU3RyZWFtTWVzc2FnZSxcbiAgICAgICAgICAnc3RhdGUnXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICB0aGlzLmp1bXBUb01lc3NhZ2VTdWJqZWN0Lm5leHQoe1xuICAgICAgICBpZDogbWVzc2FnZUlkLFxuICAgICAgICBwYXJlbnRJZDogcGFyZW50TWVzc2FnZUlkLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICdzdHJlYW1DaGF0Lk1lc3NhZ2Ugbm90IGZvdW5kJ1xuICAgICAgKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmlzTWVzc2FnZUxvYWRpbmdJblByb2dyZXNzID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIG1lc3NhZ2UgdG8ganVtcFxuICAgKi9cbiAgY2xlYXJNZXNzYWdlSnVtcCgpIHtcbiAgICB0aGlzLmp1bXBUb01lc3NhZ2VTdWJqZWN0Lm5leHQoeyBpZDogdW5kZWZpbmVkLCBwYXJlbnRJZDogdW5kZWZpbmVkIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBpbnMgdGhlIGdpdmVuIG1lc3NhZ2UgaW4gdGhlIGNoYW5uZWxcbiAgICogQHBhcmFtIG1lc3NhZ2VcbiAgICovXG4gIGFzeW5jIHBpbk1lc3NhZ2UobWVzc2FnZTogU3RyZWFtTWVzc2FnZSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQ/LnBpbk1lc3NhZ2UobWVzc2FnZSk7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2UuYWRkVGVtcG9yYXJ5Tm90aWZpY2F0aW9uKFxuICAgICAgICAnc3RyZWFtQ2hhdC5NZXNzYWdlIHBpbm5lZCcsXG4gICAgICAgICdzdWNjZXNzJ1xuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLmFkZFRlbXBvcmFyeU5vdGlmaWNhdGlvbihcbiAgICAgICAgJ3N0cmVhbUNoYXQuRXJyb3IgcGlubmluZyBtZXNzYWdlJ1xuICAgICAgKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHRoZSBnaXZlbiBtZXNzYWdlIGZyb20gcGlubmVkIG1lc3NhZ2VzXG4gICAqIEBwYXJhbSBtZXNzYWdlXG4gICAqL1xuICBhc3luYyB1bnBpbk1lc3NhZ2UobWVzc2FnZTogU3RyZWFtTWVzc2FnZSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQ/LnVucGluTWVzc2FnZShtZXNzYWdlKTtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICdzdHJlYW1DaGF0Lk1lc3NhZ2UgdW5waW5uZWQnLFxuICAgICAgICAnc3VjY2VzcydcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICdzdHJlYW1DaGF0LkVycm9yIHJlbW92aW5nIG1lc3NhZ2UgcGluJ1xuICAgICAgKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlTm90aWZpY2F0aW9uKGNsaWVudEV2ZW50OiBDbGllbnRFdmVudCkge1xuICAgIHN3aXRjaCAoY2xpZW50RXZlbnQuZXZlbnRUeXBlKSB7XG4gICAgICBjYXNlICdjb25uZWN0aW9uLnJlY292ZXJlZCc6IHtcbiAgICAgICAgdm9pZCB0aGlzLm5nWm9uZS5ydW4oYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLmlzU3RhdGVSZWNvdmVyeUluUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5pc1N0YXRlUmVjb3ZlcnlJblByb2dyZXNzID0gdHJ1ZTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gSWYgY2hhbm5lbCBsaXN0IGlzIG5vdCBpbml0ZWQsIHdlIHNldCB0aGUgYWN0aXZlIGNoYW5uZWxcbiAgICAgICAgICAgIGNvbnN0IHNob3VsU2V0QWN0aXZlQ2hhbm5lbCA9XG4gICAgICAgICAgICAgIHRoaXMuc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbCAmJlxuICAgICAgICAgICAgICAhdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5xdWVyeUNoYW5uZWxzKFxuICAgICAgICAgICAgICBzaG91bFNldEFjdGl2ZUNoYW5uZWwgfHwgZmFsc2UsXG4gICAgICAgICAgICAgICdyZWNvdmVyLXN0YXRlJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmICh0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkpIHtcbiAgICAgICAgICAgICAgLy8gVGhyZWFkIG1lc3NhZ2VzIGFyZSBub3QgcmVmZXRjaGVkIHNvIGFjdGl2ZSB0aHJlYWQgZ2V0cyBkZXNlbGVjdGVkIHRvIGF2b2lkIGRpc3BsYXlpbmcgc3RhbGUgbWVzc2FnZXNcbiAgICAgICAgICAgICAgdm9pZCB0aGlzLnNldEFzQWN0aXZlUGFyZW50TWVzc2FnZSh1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAvLyBVcGRhdGUgYW5kIHJlc2VsZWN0IG1lc3NhZ2UgdG8gcXVvdGVcbiAgICAgICAgICAgICAgY29uc3QgbWVzc2FnZVRvUXVvdGUgPSB0aGlzLm1lc3NhZ2VUb1F1b3RlU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgICAgICAgICB0aGlzLnNldENoYW5uZWxTdGF0ZSh0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhKTtcbiAgICAgICAgICAgICAgbGV0IG1lc3NhZ2VzITogU3RyZWFtTWVzc2FnZVtdO1xuICAgICAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlcyRcbiAgICAgICAgICAgICAgICAucGlwZSh0YWtlKDEpKVxuICAgICAgICAgICAgICAgIC5zdWJzY3JpYmUoKG0pID0+IChtZXNzYWdlcyA9IG0pKTtcbiAgICAgICAgICAgICAgY29uc3QgdXBkYXRlZE1lc3NhZ2VUb1F1b3RlID0gbWVzc2FnZXMuZmluZChcbiAgICAgICAgICAgICAgICAobSkgPT4gbS5pZCA9PT0gbWVzc2FnZVRvUXVvdGU/LmlkXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIGlmICh1cGRhdGVkTWVzc2FnZVRvUXVvdGUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdE1lc3NhZ2VUb1F1b3RlKHVwZGF0ZWRNZXNzYWdlVG9RdW90ZSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuaXNTdGF0ZVJlY292ZXJ5SW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgdGhpcy5pc1N0YXRlUmVjb3ZlcnlJblByb2dyZXNzID0gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdub3RpZmljYXRpb24ubWVzc2FnZV9uZXcnOiB7XG4gICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMuY3VzdG9tTmV3TWVzc2FnZU5vdGlmaWNhdGlvbkhhbmRsZXIpIHtcbiAgICAgICAgICAgIHRoaXMuY3VzdG9tTmV3TWVzc2FnZU5vdGlmaWNhdGlvbkhhbmRsZXIoXG4gICAgICAgICAgICAgIGNsaWVudEV2ZW50LFxuICAgICAgICAgICAgICB0aGlzLmNoYW5uZWxMaXN0U2V0dGVyXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZU5ld01lc3NhZ2VOb3RpZmljYXRpb24oY2xpZW50RXZlbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSAnbm90aWZpY2F0aW9uLmFkZGVkX3RvX2NoYW5uZWwnOiB7XG4gICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMuY3VzdG9tQWRkZWRUb0NoYW5uZWxOb3RpZmljYXRpb25IYW5kbGVyKSB7XG4gICAgICAgICAgICB0aGlzLmN1c3RvbUFkZGVkVG9DaGFubmVsTm90aWZpY2F0aW9uSGFuZGxlcihcbiAgICAgICAgICAgICAgY2xpZW50RXZlbnQsXG4gICAgICAgICAgICAgIHRoaXMuY2hhbm5lbExpc3RTZXR0ZXJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlQWRkZWRUb0NoYW5uZWxOb3RpZmljYXRpb24oY2xpZW50RXZlbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSAnbm90aWZpY2F0aW9uLnJlbW92ZWRfZnJvbV9jaGFubmVsJzoge1xuICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLmN1c3RvbVJlbW92ZWRGcm9tQ2hhbm5lbE5vdGlmaWNhdGlvbkhhbmRsZXIpIHtcbiAgICAgICAgICAgIHRoaXMuY3VzdG9tUmVtb3ZlZEZyb21DaGFubmVsTm90aWZpY2F0aW9uSGFuZGxlcihcbiAgICAgICAgICAgICAgY2xpZW50RXZlbnQsXG4gICAgICAgICAgICAgIHRoaXMuY2hhbm5lbExpc3RTZXR0ZXJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlUmVtb3ZlZEZyb21DaGFubmVsTm90aWZpY2F0aW9uKGNsaWVudEV2ZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ3VzZXIudXBkYXRlZCc6IHtcbiAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICBjb25zdCB1cGRhdGVkQ2hhbm5lbHMgPSB0aGlzLmNoYW5uZWxzU3ViamVjdC5nZXRWYWx1ZSgpPy5tYXAoKGMpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQuYWN0aXZlQ2hhbm5lbHNbYy5jaWRdKSB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQuYWN0aXZlQ2hhbm5lbHNbYy5jaWRdO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dCh1cGRhdGVkQ2hhbm5lbHMpO1xuICAgICAgICAgIGNvbnN0IGFjdGl2ZUNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgICAgICAgaWYgKGFjdGl2ZUNoYW5uZWwpIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QubmV4dChcbiAgICAgICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LmFjdGl2ZUNoYW5uZWxzW1xuICAgICAgICAgICAgICAgIGFjdGl2ZUNoYW5uZWwuY2lkXG4gICAgICAgICAgICAgIF0gfHwgYWN0aXZlQ2hhbm5lbFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFxuICAgICAgICAgICAgICBhY3RpdmVDaGFubmVsLnN0YXRlLm1lc3NhZ2VzLm1hcCgobSkgPT4ge1xuICAgICAgICAgICAgICAgIChtIGFzIFN0cmVhbU1lc3NhZ2UpLnJlYWRCeSA9IGdldFJlYWRCeShtLCBhY3RpdmVDaGFubmVsKTtcbiAgICAgICAgICAgICAgICByZXR1cm4geyAuLi5tIH07XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgYWN0aXZlUGFyZW50TWVzc2FnZSA9XG4gICAgICAgICAgICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgICAgICAgaWYgKGFjdGl2ZVBhcmVudE1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgY29uc3QgbWVzc2FnZXMgPSBhY3RpdmVDaGFubmVsLnN0YXRlLnRocmVhZHNbYWN0aXZlUGFyZW50TWVzc2FnZV07XG4gICAgICAgICAgICAgIHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLm1lc3NhZ2VzXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxQaW5uZWRNZXNzYWdlc1N1YmplY3QubmV4dChbXG4gICAgICAgICAgICAgIC4uLihhY3RpdmVDaGFubmVsLnN0YXRlLnBpbm5lZE1lc3NhZ2VzIGFzIFN0cmVhbU1lc3NhZ2VbXSksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZVJlbW92ZWRGcm9tQ2hhbm5lbE5vdGlmaWNhdGlvbihjbGllbnRFdmVudDogQ2xpZW50RXZlbnQpIHtcbiAgICBjb25zdCBjaGFubmVsSWRUb0JlUmVtb3ZlZCA9IGNsaWVudEV2ZW50LmV2ZW50LmNoYW5uZWwhLmNpZDtcbiAgICB0aGlzLnJlbW92ZUNoYW5uZWwoY2hhbm5lbElkVG9CZVJlbW92ZWQsIHRydWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVOZXdNZXNzYWdlTm90aWZpY2F0aW9uKGNsaWVudEV2ZW50OiBDbGllbnRFdmVudCkge1xuICAgIGlmIChjbGllbnRFdmVudC5ldmVudC5jaGFubmVsKSB7XG4gICAgICB2b2lkIHRoaXMuYWRkQ2hhbm5lbEZyb21Ob3RpZmljYXRpb24oY2xpZW50RXZlbnQuZXZlbnQuY2hhbm5lbCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVBZGRlZFRvQ2hhbm5lbE5vdGlmaWNhdGlvbihjbGllbnRFdmVudDogQ2xpZW50RXZlbnQpIHtcbiAgICBpZiAoY2xpZW50RXZlbnQuZXZlbnQuY2hhbm5lbCkge1xuICAgICAgdm9pZCB0aGlzLmFkZENoYW5uZWxGcm9tTm90aWZpY2F0aW9uKGNsaWVudEV2ZW50LmV2ZW50LmNoYW5uZWwpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgYWRkQ2hhbm5lbEZyb21Ob3RpZmljYXRpb24oY2hhbm5lbFJlc3BvbnNlOiBDaGFubmVsUmVzcG9uc2UpIHtcbiAgICBjb25zdCBuZXdDaGFubmVsID0gdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LmNoYW5uZWwoXG4gICAgICBjaGFubmVsUmVzcG9uc2UudHlwZSxcbiAgICAgIGNoYW5uZWxSZXNwb25zZS5pZFxuICAgICk7XG4gICAgbGV0IGN1cnJlbnRDaGFubmVscyA9IHRoaXMuY2hhbm5lbHNTdWJqZWN0LmdldFZhbHVlKCkgfHwgW107XG4gICAgaWYgKGN1cnJlbnRDaGFubmVscy5maW5kKChjKSA9PiBjLmNpZCA9PT0gbmV3Q2hhbm5lbC5jaWQpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGF3YWl0IG5ld0NoYW5uZWwud2F0Y2goKS5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQubG9nZ2VyKFxuICAgICAgICAnZXJyb3InLFxuICAgICAgICAnRmFpbGVkIHRvIGFkZCBjaGFubmVsIHRvIGNoYW5uZWwgbGlzdCBiZWNhdXNlIHdhdGNoIHJlcXVlc3QgZmFpbGVkJyxcbiAgICAgICAgZXJyIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4gICAgICApO1xuICAgIH0pO1xuICAgIGN1cnJlbnRDaGFubmVscyA9IHRoaXMuY2hhbm5lbHNTdWJqZWN0LmdldFZhbHVlKCkgfHwgW107XG4gICAgaWYgKGN1cnJlbnRDaGFubmVscy5maW5kKChjKSA9PiBjLmNpZCA9PT0gbmV3Q2hhbm5lbC5jaWQpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMud2F0Y2hGb3JDaGFubmVsRXZlbnRzKG5ld0NoYW5uZWwpO1xuICAgIHRoaXMuY2hhbm5lbHNTdWJqZWN0Lm5leHQoW25ld0NoYW5uZWwsIC4uLmN1cnJlbnRDaGFubmVsc10pO1xuICB9XG5cbiAgcHJpdmF0ZSB3YXRjaEZvckFjdGl2ZUNoYW5uZWxFdmVudHMoY2hhbm5lbDogQ2hhbm5lbCkge1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIGNoYW5uZWwub24oJ21lc3NhZ2UubmV3JywgKGV2ZW50KSA9PiB7XG4gICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgZXZlbnQubWVzc2FnZSAmJiBldmVudC5tZXNzYWdlLnBhcmVudF9pZFxuICAgICAgICAgICAgPyBldmVudC5tZXNzYWdlLnBhcmVudF9pZCA9PT1cbiAgICAgICAgICAgICAgdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0LmdldFZhbHVlKClcbiAgICAgICAgICAgICAgPyB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtcbiAgICAgICAgICAgICAgICAgIC4uLmNoYW5uZWwuc3RhdGUudGhyZWFkc1tldmVudC5tZXNzYWdlLnBhcmVudF9pZF0sXG4gICAgICAgICAgICAgICAgXSlcbiAgICAgICAgICAgICAgOiBudWxsXG4gICAgICAgICAgICA6IHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtcbiAgICAgICAgICAgICAgICAuLi5jaGFubmVsLnN0YXRlLm1lc3NhZ2VzLFxuICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWwkLnBpcGUoZmlyc3QoKSkuc3Vic2NyaWJlKChjKSA9PiB7XG4gICAgICAgICAgICBpZiAoYykge1xuICAgICAgICAgICAgICB0aGlzLm1hcmtSZWFkKGMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMudXBkYXRlTGF0ZXN0TWVzc2FnZXMoZXZlbnQpO1xuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdtZXNzYWdlLnVwZGF0ZWQnLCAoZXZlbnQpID0+IHRoaXMubWVzc2FnZVVwZGF0ZWQoZXZlbnQpKVxuICAgICk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgY2hhbm5lbC5vbignbWVzc2FnZS5kZWxldGVkJywgKGV2ZW50KSA9PiB0aGlzLm1lc3NhZ2VVcGRhdGVkKGV2ZW50KSlcbiAgICApO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIGNoYW5uZWwub24oJ3JlYWN0aW9uLm5ldycsIChlKSA9PiB0aGlzLm1lc3NhZ2VSZWFjdGlvbkV2ZW50UmVjZWl2ZWQoZSkpXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdyZWFjdGlvbi5kZWxldGVkJywgKGUpID0+XG4gICAgICAgIHRoaXMubWVzc2FnZVJlYWN0aW9uRXZlbnRSZWNlaXZlZChlKVxuICAgICAgKVxuICAgICk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgY2hhbm5lbC5vbigncmVhY3Rpb24udXBkYXRlZCcsIChlKSA9PlxuICAgICAgICB0aGlzLm1lc3NhZ2VSZWFjdGlvbkV2ZW50UmVjZWl2ZWQoZSlcbiAgICAgIClcbiAgICApO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIGNoYW5uZWwub24oJ21lc3NhZ2UucmVhZCcsIChlKSA9PiB7XG4gICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgbGV0IGxhdGVzdE1lc3NhZ2UhOiBTdHJlYW1NZXNzYWdlO1xuICAgICAgICAgIGxldCBtZXNzYWdlcyE6IFN0cmVhbU1lc3NhZ2VbXTtcbiAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlcyQucGlwZShmaXJzdCgpKS5zdWJzY3JpYmUoKG0pID0+IHtcbiAgICAgICAgICAgIG1lc3NhZ2VzID0gbTtcbiAgICAgICAgICAgIGxhdGVzdE1lc3NhZ2UgPSBtZXNzYWdlc1ttZXNzYWdlcy5sZW5ndGggLSAxXTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAoIWxhdGVzdE1lc3NhZ2UgfHwgIWUudXNlcikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAobGF0ZXN0TWVzc2FnZS5yZWFkQnkpIHtcbiAgICAgICAgICAgIGxhdGVzdE1lc3NhZ2UucmVhZEJ5LnNwbGljZSgwLCBsYXRlc3RNZXNzYWdlLnJlYWRCeS5sZW5ndGgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsYXRlc3RNZXNzYWdlLnJlYWRCeSA9IFtdO1xuICAgICAgICAgIH1cbiAgICAgICAgICBsYXRlc3RNZXNzYWdlLnJlYWRCeS5wdXNoKC4uLmdldFJlYWRCeShsYXRlc3RNZXNzYWdlLCBjaGFubmVsKSk7XG4gICAgICAgICAgbWVzc2FnZXNbbWVzc2FnZXMubGVuZ3RoIC0gMV0gPSB7IC4uLmxhdGVzdE1lc3NhZ2UgfTtcblxuICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5tZXNzYWdlc10pO1xuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmV2ZW50cyRcbiAgICAgICAgLnBpcGUoXG4gICAgICAgICAgZmlsdGVyKFxuICAgICAgICAgICAgKGUpID0+XG4gICAgICAgICAgICAgIGUuZXZlbnRUeXBlID09PSAnbm90aWZpY2F0aW9uLm1hcmtfdW5yZWFkJyAmJlxuICAgICAgICAgICAgICBlLmV2ZW50LmNoYW5uZWxfaWQgPT09IGNoYW5uZWwuaWRcbiAgICAgICAgICApLFxuICAgICAgICAgIG1hcCgoZSkgPT4gZS5ldmVudClcbiAgICAgICAgKVxuICAgICAgICAuc3Vic2NyaWJlKChlKSA9PiB7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbExhc3RSZWFkTWVzc2FnZUlkID0gZS5sYXN0X3JlYWRfbWVzc2FnZV9pZDtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFVucmVhZENvdW50ID0gZS51bnJlYWRfbWVzc2FnZXM7XG4gICAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQodGhpcy5hY3RpdmVDaGFubmVsKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSlcbiAgICApO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIGNoYW5uZWwub24oJ3R5cGluZy5zdGFydCcsIChlKSA9PlxuICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4gdGhpcy5oYW5kbGVUeXBpbmdTdGFydEV2ZW50KGUpKVxuICAgICAgKVxuICAgICk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgY2hhbm5lbC5vbigndHlwaW5nLnN0b3AnLCAoZSkgPT5cbiAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuaGFuZGxlVHlwaW5nU3RvcEV2ZW50KGUpKVxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbCB0aGlzIG1ldGhvZCBpZiB1c2VyIHN0YXJ0ZWQgdHlwaW5nIGluIHRoZSBhY3RpdmUgY2hhbm5lbFxuICAgKiBAcGFyYW0gcGFyZW50SWQgVGhlIGlkIG9mIHRoZSBwYXJlbnQgbWVzc2FnZSwgaWYgdXNlciBpcyB0eXBpbmcgaW4gYSB0aHJlYWRcbiAgICovXG4gIGFzeW5jIHR5cGluZ1N0YXJ0ZWQocGFyZW50SWQ/OiBzdHJpbmcpIHtcbiAgICBjb25zdCBhY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGF3YWl0IGFjdGl2ZUNoYW5uZWw/LmtleXN0cm9rZShwYXJlbnRJZCk7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbCB0aGlzIG1ldGhvZCBpZiB1c2VyIHN0b3BwZWQgdHlwaW5nIGluIHRoZSBhY3RpdmUgY2hhbm5lbFxuICAgKiBAcGFyYW0gcGFyZW50SWQgVGhlIGlkIG9mIHRoZSBwYXJlbnQgbWVzc2FnZSwgaWYgdXNlciB3ZXJlIHR5cGluZyBpbiBhIHRocmVhZFxuICAgKi9cbiAgYXN5bmMgdHlwaW5nU3RvcHBlZChwYXJlbnRJZD86IHN0cmluZykge1xuICAgIGNvbnN0IGFjdGl2ZUNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgYXdhaXQgYWN0aXZlQ2hhbm5lbD8uc3RvcFR5cGluZyhwYXJlbnRJZCk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGN1cnJlbnQgbGlzdCBvZiBjaGFubmVsc1xuICAgKi9cbiAgZ2V0IGNoYW5uZWxzKCkge1xuICAgIHJldHVybiB0aGlzLmNoYW5uZWxzU3ViamVjdC5nZXRWYWx1ZSgpIHx8IFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGFjdGl2ZSBjaGFubmVsXG4gICAqL1xuICBnZXQgYWN0aXZlQ2hhbm5lbCgpIHtcbiAgICByZXR1cm4gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpIHx8IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCBhY3RpdmUgY2hhbm5lbCBtZXNzYWdlc1xuICAgKi9cbiAgZ2V0IGFjdGl2ZUNoYW5uZWxNZXNzYWdlcygpIHtcbiAgICByZXR1cm4gdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0LmdldFZhbHVlKCkgfHwgW107XG4gIH1cblxuICAvKipcbiAgICogVGhlIGN1cnJlbnQgdGhyZWFkIHJlcGxpZXNcbiAgICovXG4gIGdldCBhY3RpdmVDaGFubmVsVGhyZWFkUmVwbGllcygpIHtcbiAgICByZXR1cm4gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QuZ2V0VmFsdWUoKSB8fCBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGxhc3QgMTIwMCByZWFjdGlvbnMgb2YgYSBtZXNzYWdlIGluIHRoZSBjdXJyZW50IGFjdGl2ZSBjaGFubmVsLiBJZiB5b3UgbmVlZCB0byBmZXRjaCBtb3JlIHJlYWN0aW9ucyBwbGVhc2UgdXNlIHRoZSBbZm9sbG93aW5nIGVuZHBvaW50XSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvc2VuZF9yZWFjdGlvbi8jcGFnaW5hdGluZy1yZWFjdGlvbnMpLlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgW2BtZXNzYWdlUmVhY3Rpb25zU2VydmljZS5xdWVyeVJlYWN0aW9ucygpYF0oL2NoYXQvZG9jcy9zZGsvYW5ndWxhci9zZXJ2aWNlcy9NZXNzYWdlUmVhY3Rpb25zU2VydmljZS8jcXVlcnlyZWFjdGlvbnMpIGluc3RlYWRcbiAgICogQHBhcmFtIG1lc3NhZ2VJZFxuICAgKiBAcmV0dXJucyBhbGwgcmVhY3Rpb25zIG9mIGEgbWVzc2FnZVxuICAgKi9cbiAgYXN5bmMgZ2V0TWVzc2FnZVJlYWN0aW9ucyhtZXNzYWdlSWQ6IHN0cmluZykge1xuICAgIGNvbnN0IHJlYWN0aW9uczogUmVhY3Rpb25SZXNwb25zZVtdID0gW107XG4gICAgY29uc3QgbGltaXQgPSAzMDA7XG4gICAgbGV0IG9mZnNldCA9IDA7XG4gICAgY29uc3QgcmVhY3Rpb25zTGltaXQgPSBDaGFubmVsU2VydmljZS5NQVhfTUVTU0FHRV9SRUFDVElPTlNfVE9fRkVUQ0g7XG4gICAgbGV0IGxhc3RQYWdlU2l6ZSA9IGxpbWl0O1xuXG4gICAgd2hpbGUgKGxhc3RQYWdlU2l6ZSA9PT0gbGltaXQgJiYgcmVhY3Rpb25zLmxlbmd0aCA8IHJlYWN0aW9uc0xpbWl0KSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuYWN0aXZlQ2hhbm5lbD8uZ2V0UmVhY3Rpb25zKG1lc3NhZ2VJZCwge1xuICAgICAgICAgIG9mZnNldCxcbiAgICAgICAgICBsaW1pdCxcbiAgICAgICAgfSk7XG4gICAgICAgIGxhc3RQYWdlU2l6ZSA9IHJlc3BvbnNlPy5yZWFjdGlvbnM/Lmxlbmd0aCB8fCAwO1xuICAgICAgICBpZiAobGFzdFBhZ2VTaXplID4gMCkge1xuICAgICAgICAgIHJlYWN0aW9ucy5wdXNoKC4uLnJlc3BvbnNlIS5yZWFjdGlvbnMpO1xuICAgICAgICB9XG4gICAgICAgIG9mZnNldCArPSBsYXN0UGFnZVNpemU7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICAgJ3N0cmVhbUNoYXQuRXJyb3IgbG9hZGluZyByZWFjdGlvbnMnXG4gICAgICAgICk7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZWFjdGlvbnM7XG4gIH1cblxuICAvKipcbiAgICogTWFya3MgdGhlIGNoYW5uZWwgZnJvbSB0aGUgZ2l2ZW4gbWVzc2FnZSBhcyB1bnJlYWRcbiAgICogQHBhcmFtIG1lc3NhZ2VJZFxuICAgKiBAcmV0dXJucyB0aGUgcmVzdWx0IG9mIHRoZSByZXF1ZXN0XG4gICAqL1xuICBhc3luYyBtYXJrTWVzc2FnZVVucmVhZChtZXNzYWdlSWQ6IHN0cmluZykge1xuICAgIGlmICghdGhpcy5hY3RpdmVDaGFubmVsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5hY3RpdmVDaGFubmVsLm1hcmtVbnJlYWQoe1xuICAgICAgICBtZXNzYWdlX2lkOiBtZXNzYWdlSWQsXG4gICAgICB9KTtcbiAgICAgIHRoaXMuYXJlUmVhZEV2ZW50c1BhdXNlZCA9IHRydWU7XG4gICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgY29uc3QgZXJyb3I6IHtcbiAgICAgICAgcmVzcG9uc2U/OiB7XG4gICAgICAgICAgZGF0YT86IHsgY29kZT86IG51bWJlcjsgbWVzc2FnZT86IHN0cmluZzsgU3RhdHVzQ29kZT86IG51bWJlciB9O1xuICAgICAgICB9O1xuICAgICAgfSA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZSkpIGFzIHtcbiAgICAgICAgcmVzcG9uc2U/OiB7XG4gICAgICAgICAgZGF0YT86IHsgY29kZT86IG51bWJlcjsgbWVzc2FnZT86IHN0cmluZzsgU3RhdHVzQ29kZT86IG51bWJlciB9O1xuICAgICAgICB9O1xuICAgICAgfTtcbiAgICAgIGNvbnN0IGRhdGEgPSBlcnJvcj8ucmVzcG9uc2U/LmRhdGE7XG4gICAgICBpZiAoXG4gICAgICAgIGRhdGEgJiZcbiAgICAgICAgZGF0YS5jb2RlID09PSA0ICYmXG4gICAgICAgIGRhdGEuU3RhdHVzQ29kZSA9PT0gNDAwICYmXG4gICAgICAgIGRhdGEubWVzc2FnZT8uaW5jbHVkZXMoJ2l0IGlzIG9sZGVyIHRoYW4gbGFzdCcpXG4gICAgICApIHtcbiAgICAgICAgY29uc3QgY291bnQgPSAvXFxkKyBjaGFubmVsIG1lc3NhZ2VzL1xuICAgICAgICAgIC5leGVjKGRhdGEubWVzc2FnZSk/LlswXVxuICAgICAgICAgIC5tYXRjaCgvXFxkKy8pPy5bMF07XG4gICAgICAgIGlmIChjb3VudCkge1xuICAgICAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICAgICAnc3RyZWFtQ2hhdC5FcnJvciwgb25seSB0aGUgZmlyc3Qge3tjb3VudH19IG1lc3NhZ2UgY2FuIGJlIG1hcmtlZCBhcyB1bnJlYWQnLFxuICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgeyBjb3VudCB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2UuYWRkVGVtcG9yYXJ5Tm90aWZpY2F0aW9uKFxuICAgICAgICAnc3RyZWFtQ2hhdC5FcnJvciBtYXJraW5nIG1lc3NhZ2UgYXMgdW5yZWFkJ1xuICAgICAgKTtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBtZXNzYWdlVXBkYXRlZChldmVudDogRXZlbnQpIHtcbiAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgY29uc3QgaXNUaHJlYWRSZXBseSA9IGV2ZW50Lm1lc3NhZ2UgJiYgZXZlbnQubWVzc2FnZS5wYXJlbnRfaWQ7XG4gICAgICBjb25zdCBjaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgaWYgKCFjaGFubmVsKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIC8vIEdldCBtZXNzYWdlcyBmcm9tIHN0YXRlIGFzIG1lc3NhZ2Ugb3JkZXIgY291bGQgY2hhbmdlLCBhbmQgbWVzc2FnZSBjb3VsZCd2ZSBiZWVuIGRlbGV0ZWRcbiAgICAgIGNvbnN0IG1lc3NhZ2VzOiBGb3JtYXRNZXNzYWdlUmVzcG9uc2VbXSA9IGlzVGhyZWFkUmVwbHlcbiAgICAgICAgPyBjaGFubmVsLnN0YXRlLnRocmVhZHNbZXZlbnQ/Lm1lc3NhZ2U/LnBhcmVudF9pZCB8fCAnJ11cbiAgICAgICAgOiBjaGFubmVsLnN0YXRlLm1lc3NhZ2VzO1xuICAgICAgaWYgKCFtZXNzYWdlcykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCBtZXNzYWdlSW5kZXggPSBtZXNzYWdlcy5maW5kSW5kZXgoXG4gICAgICAgIChtKSA9PiBtLmlkID09PSBldmVudD8ubWVzc2FnZT8uaWRcbiAgICAgICk7XG4gICAgICBpZiAobWVzc2FnZUluZGV4ICE9PSAtMSB8fCBldmVudC50eXBlID09PSAnbWVzc2FnZS5kZWxldGVkJykge1xuICAgICAgICBpc1RocmVhZFJlcGx5XG4gICAgICAgICAgPyB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5tZXNzYWdlc10pXG4gICAgICAgICAgOiB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QubmV4dChbLi4ubWVzc2FnZXNdKTtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsUGlubmVkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW1xuICAgICAgICAgIC4uLihjaGFubmVsLnN0YXRlLnBpbm5lZE1lc3NhZ2VzIGFzIFN0cmVhbU1lc3NhZ2VbXSksXG4gICAgICAgIF0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBtZXNzYWdlUmVhY3Rpb25FdmVudFJlY2VpdmVkKGU6IEV2ZW50KSB7XG4gICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgIGNvbnN0IGlzVGhyZWFkTWVzc2FnZSA9IGUubWVzc2FnZSAmJiBlLm1lc3NhZ2UucGFyZW50X2lkO1xuICAgICAgbGV0IG1lc3NhZ2VzITogU3RyZWFtTWVzc2FnZVtdO1xuICAgICAgKGlzVGhyZWFkTWVzc2FnZVxuICAgICAgICA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXMkXG4gICAgICAgIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkXG4gICAgICApXG4gICAgICAgIC5waXBlKGZpcnN0KCkpXG4gICAgICAgIC5zdWJzY3JpYmUoKG0pID0+IChtZXNzYWdlcyA9IG0pKTtcbiAgICAgIGNvbnN0IG1lc3NhZ2VJbmRleCA9IG1lc3NhZ2VzLmZpbmRJbmRleCgobSkgPT4gbS5pZCA9PT0gZT8ubWVzc2FnZT8uaWQpO1xuICAgICAgaWYgKG1lc3NhZ2VJbmRleCA9PT0gLTEpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3QgbWVzc2FnZSA9IG1lc3NhZ2VzW21lc3NhZ2VJbmRleF07XG4gICAgICBtZXNzYWdlLnJlYWN0aW9uX2NvdW50cyA9IHsgLi4uZS5tZXNzYWdlPy5yZWFjdGlvbl9jb3VudHMgfTtcbiAgICAgIG1lc3NhZ2UucmVhY3Rpb25fc2NvcmVzID0geyAuLi5lLm1lc3NhZ2U/LnJlYWN0aW9uX3Njb3JlcyB9O1xuICAgICAgbWVzc2FnZS5sYXRlc3RfcmVhY3Rpb25zID0gWy4uLihlLm1lc3NhZ2U/LmxhdGVzdF9yZWFjdGlvbnMgfHwgW10pXTtcbiAgICAgIG1lc3NhZ2Uub3duX3JlYWN0aW9ucyA9IFsuLi4oZS5tZXNzYWdlPy5vd25fcmVhY3Rpb25zIHx8IFtdKV07XG4gICAgICBtZXNzYWdlLnJlYWN0aW9uX2dyb3VwcyA9IHsgLi4uZS5tZXNzYWdlPy5yZWFjdGlvbl9ncm91cHMgfTtcblxuICAgICAgbWVzc2FnZXNbbWVzc2FnZUluZGV4XSA9IHsgLi4ubWVzc2FnZSB9O1xuICAgICAgaXNUaHJlYWRNZXNzYWdlXG4gICAgICAgID8gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChbLi4ubWVzc2FnZXNdKVxuICAgICAgICA6IHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5tZXNzYWdlc10pO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBmb3JtYXRNZXNzYWdlKG1lc3NhZ2U6IE1lc3NhZ2VSZXNwb25zZSkge1xuICAgIGNvbnN0IG0gPSBtZXNzYWdlIGFzIHVua25vd24gYXMgRm9ybWF0TWVzc2FnZVJlc3BvbnNlO1xuICAgIG0ucGlubmVkX2F0ID0gbWVzc2FnZS5waW5uZWRfYXQgPyBuZXcgRGF0ZShtZXNzYWdlLnBpbm5lZF9hdCkgOiBudWxsO1xuICAgIG0uY3JlYXRlZF9hdCA9IG1lc3NhZ2UuY3JlYXRlZF9hdFxuICAgICAgPyBuZXcgRGF0ZShtZXNzYWdlLmNyZWF0ZWRfYXQpXG4gICAgICA6IG5ldyBEYXRlKCk7XG4gICAgbS51cGRhdGVkX2F0ID0gbWVzc2FnZS51cGRhdGVkX2F0XG4gICAgICA/IG5ldyBEYXRlKG1lc3NhZ2UudXBkYXRlZF9hdClcbiAgICAgIDogbmV3IERhdGUoKTtcbiAgICBtZXNzYWdlLnN0YXR1cyA9IG1lc3NhZ2Uuc3RhdHVzIHx8ICdyZWNlaXZlZCc7XG5cbiAgICByZXR1cm4gbTtcbiAgfVxuXG4gIHByaXZhdGUgaXNTdHJlYW1NZXNzYWdlKFxuICAgIG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UgfCBGb3JtYXRNZXNzYWdlUmVzcG9uc2UgfCBNZXNzYWdlUmVzcG9uc2VcbiAgKTogbWVzc2FnZSBpcyBTdHJlYW1NZXNzYWdlIHtcbiAgICByZXR1cm4gJ3JlYWRCeScgaW4gbWVzc2FnZTtcbiAgfVxuXG4gIHByaXZhdGUgaXNGb3JtYXRNZXNzYWdlUmVzcG9uc2UoXG4gICAgbWVzc2FnZTogU3RyZWFtTWVzc2FnZSB8IEZvcm1hdE1lc3NhZ2VSZXNwb25zZSB8IE1lc3NhZ2VSZXNwb25zZVxuICApOiBtZXNzYWdlIGlzIEZvcm1hdE1lc3NhZ2VSZXNwb25zZSB7XG4gICAgcmV0dXJuIG1lc3NhZ2UuY3JlYXRlZF9hdCBpbnN0YW5jZW9mIERhdGU7XG4gIH1cblxuICBwcml2YXRlIHN0b3BXYXRjaEZvckFjdGl2ZUNoYW5uZWxFdmVudHMoY2hhbm5lbDogQ2hhbm5lbCB8IHVuZGVmaW5lZCkge1xuICAgIGlmICghY2hhbm5lbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLmZvckVhY2goKHMpID0+IHMudW5zdWJzY3JpYmUoKSk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9ucyA9IFtdO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBxdWVyeUNoYW5uZWxzKFxuICAgIHNob3VsZFNldEFjdGl2ZUNoYW5uZWw6IGJvb2xlYW4sXG4gICAgcXVlcnlUeXBlOiBDaGFubmVsUXVlcnlUeXBlXG4gICkge1xuICAgIGlmICghdGhpcy5jaGFubmVsUXVlcnkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ1F1ZXJ5IGNoYW5uZWxzIGNhbGxlZCBiZWZvcmUgaW5pdGlhbGl6aW5nIENoYW5uZWxRdWVyeSBpbnN0YW5jZSdcbiAgICAgICk7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICB0aGlzLmNoYW5uZWxRdWVyeVN0YXRlU3ViamVjdC5uZXh0KHsgc3RhdGU6ICdpbi1wcm9ncmVzcycgfSk7XG5cbiAgICAgIGNvbnN0IHsgY2hhbm5lbHMsIGhhc01vcmVQYWdlIH0gPSBhd2FpdCAoJ3F1ZXJ5JyBpbiB0aGlzLmNoYW5uZWxRdWVyeVxuICAgICAgICA/IHRoaXMuY2hhbm5lbFF1ZXJ5LnF1ZXJ5KHF1ZXJ5VHlwZSlcbiAgICAgICAgOiB0aGlzLmNoYW5uZWxRdWVyeShxdWVyeVR5cGUpKTtcbiAgICAgIGNvbnN0IGZpbHRlcmVkQ2hhbm5lbHMgPSBjaGFubmVscy5maWx0ZXIoXG4gICAgICAgIChjaGFubmVsLCBpbmRleCkgPT5cbiAgICAgICAgICAhY2hhbm5lbHMuc2xpY2UoMCwgaW5kZXgpLmZpbmQoKGMpID0+IGMuY2lkID09PSBjaGFubmVsLmNpZClcbiAgICAgICk7XG4gICAgICBmaWx0ZXJlZENoYW5uZWxzLmZvckVhY2goKGMpID0+IHtcbiAgICAgICAgaWYgKCF0aGlzLmNoYW5uZWxTdWJzY3JpcHRpb25zW2MuY2lkXSkge1xuICAgICAgICAgIHRoaXMud2F0Y2hGb3JDaGFubmVsRXZlbnRzKGMpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dChmaWx0ZXJlZENoYW5uZWxzKTtcbiAgICAgIGNvbnN0IGN1cnJlbnRBY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgaWYgKFxuICAgICAgICBjdXJyZW50QWN0aXZlQ2hhbm5lbCAmJlxuICAgICAgICAhZmlsdGVyZWRDaGFubmVscy5maW5kKChjKSA9PiBjLmNpZCA9PT0gY3VycmVudEFjdGl2ZUNoYW5uZWw/LmNpZClcbiAgICAgICkge1xuICAgICAgICB0aGlzLmRlc2VsZWN0QWN0aXZlQ2hhbm5lbCgpO1xuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgZmlsdGVyZWRDaGFubmVscy5sZW5ndGggPiAwICYmXG4gICAgICAgICFjdXJyZW50QWN0aXZlQ2hhbm5lbCAmJlxuICAgICAgICBzaG91bGRTZXRBY3RpdmVDaGFubmVsXG4gICAgICApIHtcbiAgICAgICAgdGhpcy5zZXRBc0FjdGl2ZUNoYW5uZWwoZmlsdGVyZWRDaGFubmVsc1swXSk7XG4gICAgICB9XG4gICAgICB0aGlzLmhhc01vcmVDaGFubmVsc1N1YmplY3QubmV4dChoYXNNb3JlUGFnZSk7XG4gICAgICB0aGlzLmNoYW5uZWxRdWVyeVN0YXRlU3ViamVjdC5uZXh0KHsgc3RhdGU6ICdzdWNjZXNzJyB9KTtcbiAgICAgIHRoaXMuZGlzbWlzc0Vycm9yTm90aWZpY2F0aW9uPy4oKTtcbiAgICAgIHJldHVybiBjaGFubmVscztcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5jaGFubmVsUXVlcnlTdGF0ZVN1YmplY3QubmV4dCh7XG4gICAgICAgIHN0YXRlOiAnZXJyb3InLFxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1hc3NpZ25tZW50XG4gICAgICAgIGVycm9yLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHdhdGNoRm9yQ2hhbm5lbEV2ZW50cyhjaGFubmVsOiBDaGFubmVsKSB7XG4gICAgaWYgKHRoaXMuY2hhbm5lbFN1YnNjcmlwdGlvbnNbY2hhbm5lbC5jaWRdKSB7XG4gICAgICB0aGlzLmNoYW5uZWxTdWJzY3JpcHRpb25zW2NoYW5uZWwuY2lkXSgpO1xuICAgIH1cbiAgICBjb25zdCB1bnN1YnNjcmliZSA9IGNoYW5uZWwub24oKGV2ZW50OiBFdmVudCkgPT4ge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bm5lY2Vzc2FyeS10eXBlLWFzc2VydGlvblxuICAgICAgY29uc3QgdHlwZSA9IGV2ZW50LnR5cGUgYXMgRXZlbnRUeXBlcyB8ICdjYXBhYmlsaXRpZXMuY2hhbmdlZCc7XG4gICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgY2FzZSAnbWVzc2FnZS5uZXcnOiB7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmN1c3RvbU5ld01lc3NhZ2VIYW5kbGVyKSB7XG4gICAgICAgICAgICAgIHRoaXMuY3VzdG9tTmV3TWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICAgICAgZXZlbnQsXG4gICAgICAgICAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgICAgICAgICB0aGlzLmNoYW5uZWxMaXN0U2V0dGVyLFxuICAgICAgICAgICAgICAgIHRoaXMubWVzc2FnZUxpc3RTZXR0ZXIsXG4gICAgICAgICAgICAgICAgdGhpcy50aHJlYWRMaXN0U2V0dGVyLFxuICAgICAgICAgICAgICAgIHRoaXMucGFyZW50TWVzc2FnZVNldHRlclxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5oYW5kbGVOZXdNZXNzYWdlKGV2ZW50LCBjaGFubmVsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBjYXNlICdjaGFubmVsLmhpZGRlbic6IHtcbiAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuY3VzdG9tQ2hhbm5lbEhpZGRlbkhhbmRsZXIpIHtcbiAgICAgICAgICAgICAgdGhpcy5jdXN0b21DaGFubmVsSGlkZGVuSGFuZGxlcihcbiAgICAgICAgICAgICAgICBldmVudCxcbiAgICAgICAgICAgICAgICBjaGFubmVsLFxuICAgICAgICAgICAgICAgIHRoaXMuY2hhbm5lbExpc3RTZXR0ZXIsXG4gICAgICAgICAgICAgICAgdGhpcy5tZXNzYWdlTGlzdFNldHRlcixcbiAgICAgICAgICAgICAgICB0aGlzLnRocmVhZExpc3RTZXR0ZXIsXG4gICAgICAgICAgICAgICAgdGhpcy5wYXJlbnRNZXNzYWdlU2V0dGVyXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aGlzLmhhbmRsZUNoYW5uZWxIaWRkZW4oZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgJ2NoYW5uZWwuZGVsZXRlZCc6IHtcbiAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuY3VzdG9tQ2hhbm5lbERlbGV0ZWRIYW5kbGVyKSB7XG4gICAgICAgICAgICAgIHRoaXMuY3VzdG9tQ2hhbm5lbERlbGV0ZWRIYW5kbGVyKFxuICAgICAgICAgICAgICAgIGV2ZW50LFxuICAgICAgICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgICAgICAgdGhpcy5jaGFubmVsTGlzdFNldHRlcixcbiAgICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VMaXN0U2V0dGVyLFxuICAgICAgICAgICAgICAgIHRoaXMudGhyZWFkTGlzdFNldHRlcixcbiAgICAgICAgICAgICAgICB0aGlzLnBhcmVudE1lc3NhZ2VTZXR0ZXJcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2hhbm5lbERlbGV0ZWQoZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgJ2NoYW5uZWwudmlzaWJsZSc6IHtcbiAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuY3VzdG9tQ2hhbm5lbFZpc2libGVIYW5kbGVyKSB7XG4gICAgICAgICAgICAgIHRoaXMuY3VzdG9tQ2hhbm5lbFZpc2libGVIYW5kbGVyKFxuICAgICAgICAgICAgICAgIGV2ZW50LFxuICAgICAgICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgICAgICAgdGhpcy5jaGFubmVsTGlzdFNldHRlcixcbiAgICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VMaXN0U2V0dGVyLFxuICAgICAgICAgICAgICAgIHRoaXMudGhyZWFkTGlzdFNldHRlcixcbiAgICAgICAgICAgICAgICB0aGlzLnBhcmVudE1lc3NhZ2VTZXR0ZXJcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2hhbm5lbFZpc2libGUoZXZlbnQsIGNoYW5uZWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgJ2NoYW5uZWwudXBkYXRlZCc6IHtcbiAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuY3VzdG9tQ2hhbm5lbFVwZGF0ZWRIYW5kbGVyKSB7XG4gICAgICAgICAgICAgIHRoaXMuY3VzdG9tQ2hhbm5lbFVwZGF0ZWRIYW5kbGVyKFxuICAgICAgICAgICAgICAgIGV2ZW50LFxuICAgICAgICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgICAgICAgdGhpcy5jaGFubmVsTGlzdFNldHRlcixcbiAgICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VMaXN0U2V0dGVyLFxuICAgICAgICAgICAgICAgIHRoaXMudGhyZWFkTGlzdFNldHRlcixcbiAgICAgICAgICAgICAgICB0aGlzLnBhcmVudE1lc3NhZ2VTZXR0ZXJcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2hhbm5lbFVwZGF0ZShldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgY2FzZSAnY2hhbm5lbC50cnVuY2F0ZWQnOiB7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmN1c3RvbUNoYW5uZWxUcnVuY2F0ZWRIYW5kbGVyKSB7XG4gICAgICAgICAgICAgIHRoaXMuY3VzdG9tQ2hhbm5lbFRydW5jYXRlZEhhbmRsZXIoXG4gICAgICAgICAgICAgICAgZXZlbnQsXG4gICAgICAgICAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgICAgICAgICB0aGlzLmNoYW5uZWxMaXN0U2V0dGVyLFxuICAgICAgICAgICAgICAgIHRoaXMubWVzc2FnZUxpc3RTZXR0ZXIsXG4gICAgICAgICAgICAgICAgdGhpcy50aHJlYWRMaXN0U2V0dGVyLFxuICAgICAgICAgICAgICAgIHRoaXMucGFyZW50TWVzc2FnZVNldHRlclxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5oYW5kbGVDaGFubmVsVHJ1bmNhdGUoZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgJ2NhcGFiaWxpdGllcy5jaGFuZ2VkJzoge1xuICAgICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjaWQgPSBldmVudC5jaWQ7XG4gICAgICAgICAgICBpZiAoY2lkKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRDaGFubmVscyA9IHRoaXMuY2hhbm5lbHNTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gY3VycmVudENoYW5uZWxzPy5maW5kSW5kZXgoKGMpID0+IGMuY2lkID09PSBjaWQpO1xuICAgICAgICAgICAgICBpZiAoaW5kZXggIT09IC0xICYmIGluZGV4ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYW5uZWxzU3ViamVjdC5uZXh0KFsuLi5jdXJyZW50Q2hhbm5lbHMhXSk7XG4gICAgICAgICAgICAgICAgaWYgKGNpZCA9PT0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpPy5jaWQpIHtcbiAgICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QubmV4dChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5jaGFubmVsU3Vic2NyaXB0aW9uc1tjaGFubmVsLmNpZF0gPSB1bnN1YnNjcmliZS51bnN1YnNjcmliZTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlTmV3TWVzc2FnZShfOiBFdmVudCwgY2hhbm5lbDogQ2hhbm5lbCkge1xuICAgIGNvbnN0IGNoYW5uZWxJbmRleCA9IHRoaXMuY2hhbm5lbHMuZmluZEluZGV4KChjKSA9PiBjLmNpZCA9PT0gY2hhbm5lbC5jaWQpO1xuICAgIHRoaXMuY2hhbm5lbHMuc3BsaWNlKGNoYW5uZWxJbmRleCwgMSk7XG4gICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dChbY2hhbm5lbCwgLi4udGhpcy5jaGFubmVsc10pO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVDaGFubmVsSGlkZGVuKGV2ZW50OiBFdmVudCkge1xuICAgIHRoaXMucmVtb3ZlQ2hhbm5lbChldmVudC5jaGFubmVsIS5jaWQsIGZhbHNlKTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlQ2hhbm5lbERlbGV0ZWQoZXZlbnQ6IEV2ZW50KSB7XG4gICAgdGhpcy5yZW1vdmVDaGFubmVsKGV2ZW50LmNoYW5uZWwhLmNpZCwgZmFsc2UpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVDaGFubmVsVmlzaWJsZShldmVudDogRXZlbnQsIGNoYW5uZWw6IENoYW5uZWwpIHtcbiAgICBpZiAoIXRoaXMuY2hhbm5lbHMuZmluZCgoYykgPT4gYy5jaWQgPT09IGV2ZW50LmNpZCkpIHtcbiAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PlxuICAgICAgICB0aGlzLmNoYW5uZWxzU3ViamVjdC5uZXh0KFsuLi50aGlzLmNoYW5uZWxzLCBjaGFubmVsXSlcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVDaGFubmVsVXBkYXRlKGV2ZW50OiBFdmVudCkge1xuICAgIGNvbnN0IGNoYW5uZWxJbmRleCA9IHRoaXMuY2hhbm5lbHMuZmluZEluZGV4KFxuICAgICAgKGMpID0+IGMuY2lkID09PSBldmVudC5jaGFubmVsIS5jaWRcbiAgICApO1xuICAgIGlmIChjaGFubmVsSW5kZXggIT09IC0xKSB7XG4gICAgICBjb25zdCBjaGFubmVsID0gdGhpcy5jaGFubmVsc1tjaGFubmVsSW5kZXhdO1xuICAgICAgY29uc3Qgbm90SW5jbHVkZWRQcm9wZXJpZXMgPSB7XG4gICAgICAgIGhpZGRlbjogY2hhbm5lbC5kYXRhPy5oaWRkZW4gfHwgZmFsc2UsXG4gICAgICAgIG93bl9jYXBhYmlsaXRpZXM6IGNoYW5uZWwuZGF0YT8ub3duX2NhcGFiaWxpdGllcyB8fCBbXSxcbiAgICAgIH07XG4gICAgICBjaGFubmVsLmRhdGEgPSB7XG4gICAgICAgIC4uLmV2ZW50LmNoYW5uZWwhLFxuICAgICAgICAuLi5ub3RJbmNsdWRlZFByb3BlcmllcyxcbiAgICAgIH07XG4gICAgICB0aGlzLmNoYW5uZWxzU3ViamVjdC5uZXh0KFsuLi50aGlzLmNoYW5uZWxzXSk7XG4gICAgICBpZiAoZXZlbnQuY2hhbm5lbD8uY2lkID09PSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk/LmNpZCkge1xuICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQoY2hhbm5lbCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVDaGFubmVsVHJ1bmNhdGUoZXZlbnQ6IEV2ZW50KSB7XG4gICAgY29uc3QgY2hhbm5lbEluZGV4ID0gdGhpcy5jaGFubmVscy5maW5kSW5kZXgoXG4gICAgICAoYykgPT4gYy5jaWQgPT09IGV2ZW50LmNoYW5uZWwhLmNpZFxuICAgICk7XG4gICAgaWYgKGNoYW5uZWxJbmRleCAhPT0gLTEpIHtcbiAgICAgIHRoaXMuY2hhbm5lbHNbY2hhbm5lbEluZGV4XS5zdGF0ZS5tZXNzYWdlcyA9IFtdO1xuICAgICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dChbLi4udGhpcy5jaGFubmVsc10pO1xuICAgICAgaWYgKGV2ZW50LmNoYW5uZWw/LmNpZCA9PT0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpPy5jaWQpIHtcbiAgICAgICAgY29uc3QgY2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSE7XG4gICAgICAgIGNoYW5uZWwuc3RhdGUubWVzc2FnZXMgPSBbXTtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5uZXh0KGNoYW5uZWwpO1xuICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QubmV4dChbXSk7XG4gICAgICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5uZXh0KHVuZGVmaW5lZCk7XG4gICAgICAgIHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW10pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0IGNhblNlbmRSZWFkRXZlbnRzKCkge1xuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgaWYgKCFjaGFubmVsKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IGNhcGFiaWxpdGVzID0gY2hhbm5lbC5kYXRhPy5vd25fY2FwYWJpbGl0aWVzIGFzIHN0cmluZ1tdO1xuICAgIHJldHVybiBjYXBhYmlsaXRlcy5pbmRleE9mKCdyZWFkLWV2ZW50cycpICE9PSAtMTtcbiAgfVxuXG4gIHByaXZhdGUgdHJhbnNmb3JtVG9TdHJlYW1NZXNzYWdlKFxuICAgIG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UgfCBNZXNzYWdlUmVzcG9uc2UgfCBGb3JtYXRNZXNzYWdlUmVzcG9uc2UsXG4gICAgY2hhbm5lbD86IENoYW5uZWxcbiAgKSB7XG4gICAgY29uc3QgaXNUaHJlYWRNZXNzYWdlID0gISFtZXNzYWdlLnBhcmVudF9pZDtcbiAgICBpZiAoXG4gICAgICB0aGlzLmlzU3RyZWFtTWVzc2FnZShtZXNzYWdlKSAmJlxuICAgICAgdGhpcy5pc0Zvcm1hdE1lc3NhZ2VSZXNwb25zZShtZXNzYWdlKVxuICAgICkge1xuICAgICAgaWYgKG1lc3NhZ2UucXVvdGVkX21lc3NhZ2UpIHtcbiAgICAgICAgbWVzc2FnZS5xdW90ZWRfbWVzc2FnZS50cmFuc2xhdGlvbiA9IGdldE1lc3NhZ2VUcmFuc2xhdGlvbihcbiAgICAgICAgICBtZXNzYWdlLnF1b3RlZF9tZXNzYWdlLFxuICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXJcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIG1lc3NhZ2UudHJhbnNsYXRpb24gPSBnZXRNZXNzYWdlVHJhbnNsYXRpb24oXG4gICAgICAgIG1lc3NhZ2UsXG4gICAgICAgIGNoYW5uZWwsXG4gICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51c2VyXG4gICAgICApO1xuICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChtZXNzYWdlLnF1b3RlZF9tZXNzYWdlKSB7XG4gICAgICAgIChtZXNzYWdlIGFzIFN0cmVhbU1lc3NhZ2UpLnF1b3RlZF9tZXNzYWdlIS50cmFuc2xhdGlvbiA9XG4gICAgICAgICAgZ2V0TWVzc2FnZVRyYW5zbGF0aW9uKFxuICAgICAgICAgICAgbWVzc2FnZS5xdW90ZWRfbWVzc2FnZSxcbiAgICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQudXNlclxuICAgICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5pc0Zvcm1hdE1lc3NhZ2VSZXNwb25zZShtZXNzYWdlKSkge1xuICAgICAgICAobWVzc2FnZSBhcyBTdHJlYW1NZXNzYWdlKS5yZWFkQnkgPSBpc1RocmVhZE1lc3NhZ2VcbiAgICAgICAgICA/IFtdXG4gICAgICAgICAgOiBjaGFubmVsXG4gICAgICAgICAgPyBnZXRSZWFkQnkobWVzc2FnZSwgY2hhbm5lbClcbiAgICAgICAgICA6IFtdO1xuICAgICAgICAobWVzc2FnZSBhcyBTdHJlYW1NZXNzYWdlKS50cmFuc2xhdGlvbiA9IGdldE1lc3NhZ2VUcmFuc2xhdGlvbihcbiAgICAgICAgICBtZXNzYWdlLFxuICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXJcbiAgICAgICAgKTtcblxuICAgICAgICByZXR1cm4gbWVzc2FnZSBhcyBTdHJlYW1NZXNzYWdlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbWVzc2FnZSA9IHRoaXMuZm9ybWF0TWVzc2FnZShtZXNzYWdlKTtcbiAgICAgICAgKG1lc3NhZ2UgYXMgU3RyZWFtTWVzc2FnZSkucmVhZEJ5ID0gaXNUaHJlYWRNZXNzYWdlXG4gICAgICAgICAgPyBbXVxuICAgICAgICAgIDogY2hhbm5lbFxuICAgICAgICAgID8gZ2V0UmVhZEJ5KG1lc3NhZ2UsIGNoYW5uZWwpXG4gICAgICAgICAgOiBbXTtcbiAgICAgICAgKG1lc3NhZ2UgYXMgU3RyZWFtTWVzc2FnZSkudHJhbnNsYXRpb24gPSBnZXRNZXNzYWdlVHJhbnNsYXRpb24oXG4gICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgICBjaGFubmVsLFxuICAgICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51c2VyXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBtZXNzYWdlIGFzIFN0cmVhbU1lc3NhZ2U7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVUeXBpbmdTdGFydEV2ZW50KGV2ZW50OiBFdmVudCkge1xuICAgIGlmIChldmVudC51c2VyPy5pZCA9PT0gdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXI/LmlkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGlzVHlwaW5nSW5UaHJlYWQgPSAhIWV2ZW50LnBhcmVudF9pZDtcbiAgICBpZiAoXG4gICAgICBpc1R5cGluZ0luVGhyZWFkICYmXG4gICAgICBldmVudC5wYXJlbnRfaWQgIT09IHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5nZXRWYWx1ZSgpXG4gICAgKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHN1YmplY3QgPSBpc1R5cGluZ0luVGhyZWFkXG4gICAgICA/IHRoaXMudXNlcnNUeXBpbmdJblRocmVhZFN1YmplY3RcbiAgICAgIDogdGhpcy51c2Vyc1R5cGluZ0luQ2hhbm5lbFN1YmplY3Q7XG4gICAgY29uc3QgdXNlcnM6IFVzZXJSZXNwb25zZVtdID0gc3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGNvbnN0IHVzZXIgPSBldmVudC51c2VyO1xuICAgIGlmICh1c2VyICYmICF1c2Vycy5maW5kKCh1KSA9PiB1LmlkID09PSB1c2VyLmlkKSkge1xuICAgICAgdXNlcnMucHVzaCh1c2VyKTtcbiAgICAgIHN1YmplY3QubmV4dChbLi4udXNlcnNdKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZVR5cGluZ1N0b3BFdmVudChldmVudDogRXZlbnQpIHtcbiAgICBjb25zdCB1c2Vyc1R5cGluZ0luQ2hhbm5lbCA9IHRoaXMudXNlcnNUeXBpbmdJbkNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgY29uc3QgdXNlcnNUeXBpbmdJblRocmVhZCA9IHRoaXMudXNlcnNUeXBpbmdJblRocmVhZFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCB1c2VyID0gZXZlbnQudXNlcjtcbiAgICBpZiAodXNlciAmJiB1c2Vyc1R5cGluZ0luQ2hhbm5lbC5maW5kKCh1KSA9PiB1LmlkID09PSB1c2VyLmlkKSkge1xuICAgICAgdXNlcnNUeXBpbmdJbkNoYW5uZWwuc3BsaWNlKFxuICAgICAgICB1c2Vyc1R5cGluZ0luQ2hhbm5lbC5maW5kSW5kZXgoKHUpID0+IHUuaWQgPT09IHVzZXIuaWQpLFxuICAgICAgICAxXG4gICAgICApO1xuICAgICAgdGhpcy51c2Vyc1R5cGluZ0luQ2hhbm5lbFN1YmplY3QubmV4dChbLi4udXNlcnNUeXBpbmdJbkNoYW5uZWxdKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHVzZXIgJiYgdXNlcnNUeXBpbmdJblRocmVhZC5maW5kKCh1KSA9PiB1LmlkID09PSB1c2VyLmlkKSkge1xuICAgICAgdXNlcnNUeXBpbmdJblRocmVhZC5zcGxpY2UoXG4gICAgICAgIHVzZXJzVHlwaW5nSW5UaHJlYWQuZmluZEluZGV4KCh1KSA9PiB1LmlkID09PSB1c2VyLmlkKSxcbiAgICAgICAgMVxuICAgICAgKTtcbiAgICAgIHRoaXMudXNlcnNUeXBpbmdJblRocmVhZFN1YmplY3QubmV4dChbLi4udXNlcnNUeXBpbmdJblRocmVhZF0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlTGF0ZXN0TWVzc2FnZXMoZXZlbnQ6IEV2ZW50KSB7XG4gICAgaWYgKFxuICAgICAgZXZlbnQubWVzc2FnZT8udXNlcj8uaWQgIT09IHRoaXMuY2hhdENsaWVudFNlcnZpY2U/LmNoYXRDbGllbnQudXNlcj8uaWRcbiAgICApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbGF0ZXN0TWVzc2FnZXMgPVxuICAgICAgdGhpcy5sYXRlc3RNZXNzYWdlRGF0ZUJ5VXNlckJ5Q2hhbm5lbHNTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgaWYgKCFldmVudC5tZXNzYWdlPy5jcmVhdGVkX2F0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGNoYW5uZWxJZCA9IGV2ZW50Py5tZXNzYWdlPy5jaWQ7XG4gICAgaWYgKCFjaGFubmVsSWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbWVzc2FnZURhdGUgPSBuZXcgRGF0ZShldmVudC5tZXNzYWdlLmNyZWF0ZWRfYXQpO1xuICAgIGlmIChcbiAgICAgICFsYXRlc3RNZXNzYWdlc1tjaGFubmVsSWRdIHx8XG4gICAgICBsYXRlc3RNZXNzYWdlc1tjaGFubmVsSWRdPy5nZXRUaW1lKCkgPCBtZXNzYWdlRGF0ZS5nZXRUaW1lKClcbiAgICApIHtcbiAgICAgIGxhdGVzdE1lc3NhZ2VzW2NoYW5uZWxJZF0gPSBtZXNzYWdlRGF0ZTtcbiAgICAgIHRoaXMubGF0ZXN0TWVzc2FnZURhdGVCeVVzZXJCeUNoYW5uZWxzU3ViamVjdC5uZXh0KHtcbiAgICAgICAgLi4ubGF0ZXN0TWVzc2FnZXMsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldENoYW5uZWxTdGF0ZShjaGFubmVsOiBDaGFubmVsKSB7XG4gICAgY2hhbm5lbC5zdGF0ZS5tZXNzYWdlcy5mb3JFYWNoKChtKSA9PiB7XG4gICAgICAobSBhcyBTdHJlYW1NZXNzYWdlKS5yZWFkQnkgPSBnZXRSZWFkQnkobSwgY2hhbm5lbCk7XG4gICAgICAobSBhcyBTdHJlYW1NZXNzYWdlKS50cmFuc2xhdGlvbiA9IGdldE1lc3NhZ2VUcmFuc2xhdGlvbihcbiAgICAgICAgbSxcbiAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXJcbiAgICAgICk7XG4gICAgICBpZiAobS5xdW90ZWRfbWVzc2FnZSkge1xuICAgICAgICAobSBhcyBTdHJlYW1NZXNzYWdlKS5xdW90ZWRfbWVzc2FnZSEudHJhbnNsYXRpb24gPVxuICAgICAgICAgIGdldE1lc3NhZ2VUcmFuc2xhdGlvbihcbiAgICAgICAgICAgIG0ucXVvdGVkX21lc3NhZ2UsXG4gICAgICAgICAgICBjaGFubmVsLFxuICAgICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXJcbiAgICAgICAgICApO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMubWFya1JlYWQoY2hhbm5lbCk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLmNoYW5uZWwuc3RhdGUubWVzc2FnZXNdKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxQaW5uZWRNZXNzYWdlc1N1YmplY3QubmV4dChbXG4gICAgICAuLi4oY2hhbm5lbC5zdGF0ZS5waW5uZWRNZXNzYWdlcyBhcyBTdHJlYW1NZXNzYWdlW10pLFxuICAgIF0pO1xuICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5uZXh0KHVuZGVmaW5lZCk7XG4gICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChbXSk7XG4gICAgdGhpcy5tZXNzYWdlVG9RdW90ZVN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIHRoaXMudXNlcnNUeXBpbmdJbkNoYW5uZWxTdWJqZWN0Lm5leHQoW10pO1xuICAgIHRoaXMudXNlcnNUeXBpbmdJblRocmVhZFN1YmplY3QubmV4dChbXSk7XG4gIH1cblxuICBwcml2YXRlIG1hcmtSZWFkKGNoYW5uZWw6IENoYW5uZWwsIGlzVGhyb3R0bGVkID0gdHJ1ZSkge1xuICAgIGlmIChcbiAgICAgIHRoaXMuY2FuU2VuZFJlYWRFdmVudHMgJiZcbiAgICAgIHRoaXMuc2hvdWxkTWFya0FjdGl2ZUNoYW5uZWxBc1JlYWQgJiZcbiAgICAgICF0aGlzLmFyZVJlYWRFdmVudHNQYXVzZWRcbiAgICApIHtcbiAgICAgIGlmIChpc1Rocm90dGxlZCkge1xuICAgICAgICB0aGlzLm1hcmtSZWFkVGhyb3R0bGVkKGNoYW5uZWwpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdm9pZCBjaGFubmVsLm1hcmtSZWFkKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBtYXJrUmVhZFRocm90dGxlZChjaGFubmVsOiBDaGFubmVsKSB7XG4gICAgaWYgKCF0aGlzLm1hcmtSZWFkVGltZW91dCkge1xuICAgICAgdGhpcy5tYXJrUmVhZChjaGFubmVsLCBmYWxzZSk7XG4gICAgICB0aGlzLm1hcmtSZWFkVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLmZsdXNoTWFya1JlYWRRdWV1ZSgpO1xuICAgICAgfSwgdGhpcy5tYXJrUmVhZFRocm90dGxlVGltZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLm1hcmtSZWFkVGltZW91dCk7XG4gICAgICB0aGlzLnNjaGVkdWxlZE1hcmtSZWFkUmVxdWVzdCA9ICgpID0+IHRoaXMubWFya1JlYWQoY2hhbm5lbCwgZmFsc2UpO1xuICAgICAgdGhpcy5tYXJrUmVhZFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgdGhpcy5mbHVzaE1hcmtSZWFkUXVldWUoKTtcbiAgICAgIH0sIHRoaXMubWFya1JlYWRUaHJvdHRsZVRpbWUpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmx1c2hNYXJrUmVhZFF1ZXVlKCkge1xuICAgIHRoaXMuc2NoZWR1bGVkTWFya1JlYWRSZXF1ZXN0Py4oKTtcbiAgICB0aGlzLnNjaGVkdWxlZE1hcmtSZWFkUmVxdWVzdCA9IHVuZGVmaW5lZDtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5tYXJrUmVhZFRpbWVvdXQpO1xuICAgIHRoaXMubWFya1JlYWRUaW1lb3V0ID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBfaW5pdChzZXR0aW5nczoge1xuICAgIHNob3VsZFNldEFjdGl2ZUNoYW5uZWw6IGJvb2xlYW47XG4gICAgbWVzc2FnZVBhZ2VTaXplOiBudW1iZXI7XG4gIH0pIHtcbiAgICB0aGlzLnNob3VsZFNldEFjdGl2ZUNoYW5uZWwgPSBzZXR0aW5ncy5zaG91bGRTZXRBY3RpdmVDaGFubmVsO1xuICAgIHRoaXMubWVzc2FnZVBhZ2VTaXplID0gc2V0dGluZ3MubWVzc2FnZVBhZ2VTaXplO1xuICAgIHRoaXMuY2xpZW50RXZlbnRzU3Vic2NyaXB0aW9uID0gdGhpcy5jaGF0Q2xpZW50U2VydmljZS5ldmVudHMkLnN1YnNjcmliZShcbiAgICAgIChub3RpZmljYXRpb24pID0+IHZvaWQgdGhpcy5oYW5kbGVOb3RpZmljYXRpb24obm90aWZpY2F0aW9uKVxuICAgICk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMucXVlcnlDaGFubmVscyhcbiAgICAgICAgdGhpcy5zaG91bGRTZXRBY3RpdmVDaGFubmVsLFxuICAgICAgICAnZmlyc3QtcGFnZSdcbiAgICAgICk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmRpc21pc3NFcnJvck5vdGlmaWNhdGlvbiA9XG4gICAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRQZXJtYW5lbnROb3RpZmljYXRpb24oXG4gICAgICAgICAgJ3N0cmVhbUNoYXQuRXJyb3IgbG9hZGluZyBjaGFubmVscycsXG4gICAgICAgICAgJ2Vycm9yJ1xuICAgICAgICApO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG59XG4iXX0=
|