@valtimo/sse 10.8.0 → 11.1.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/{esm2020 → esm2022}/lib/models/index.mjs +2 -2
- package/{esm2020 → esm2022}/lib/models/sse-bucket.model.mjs +2 -2
- package/{esm2020 → esm2022}/lib/models/sse-events.model.mjs +2 -2
- package/{esm2020 → esm2022}/lib/services/index.mjs +2 -2
- package/esm2022/lib/services/sse.service.mjs +238 -0
- package/{esm2020 → esm2022}/lib/sse.module.mjs +6 -6
- package/{esm2020 → esm2022}/public-api.mjs +2 -2
- package/{fesm2020 → fesm2022}/valtimo-sse.mjs +26 -23
- package/fesm2022/valtimo-sse.mjs.map +1 -0
- package/lib/models/sse-events.model.d.ts +2 -2
- package/package.json +8 -14
- package/esm2020/lib/services/sse.service.mjs +0 -238
- package/fesm2015/valtimo-sse.mjs +0 -369
- package/fesm2015/valtimo-sse.mjs.map +0 -1
- package/fesm2020/valtimo-sse.mjs.map +0 -1
- /package/{esm2020 → esm2022}/valtimo-sse.mjs +0 -0
package/package.json
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valtimo/sse",
|
|
3
3
|
"license": "EUPL-1.2",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "11.1.0",
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@angular/common": "^
|
|
7
|
-
"@angular/core": "^
|
|
6
|
+
"@angular/common": "^16.2.0",
|
|
7
|
+
"@angular/core": "^16.2.0"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"tslib": "
|
|
10
|
+
"tslib": "2.6.2"
|
|
11
11
|
},
|
|
12
|
-
"module": "
|
|
13
|
-
"es2020": "fesm2020/valtimo-sse.mjs",
|
|
14
|
-
"esm2020": "esm2020/valtimo-sse.mjs",
|
|
15
|
-
"fesm2020": "fesm2020/valtimo-sse.mjs",
|
|
16
|
-
"fesm2015": "fesm2015/valtimo-sse.mjs",
|
|
12
|
+
"module": "fesm2022/valtimo-sse.mjs",
|
|
17
13
|
"typings": "index.d.ts",
|
|
18
14
|
"exports": {
|
|
19
15
|
"./package.json": {
|
|
@@ -21,11 +17,9 @@
|
|
|
21
17
|
},
|
|
22
18
|
".": {
|
|
23
19
|
"types": "./index.d.ts",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"node": "./fesm2015/valtimo-sse.mjs",
|
|
28
|
-
"default": "./fesm2020/valtimo-sse.mjs"
|
|
20
|
+
"esm2022": "./esm2022/valtimo-sse.mjs",
|
|
21
|
+
"esm": "./esm2022/valtimo-sse.mjs",
|
|
22
|
+
"default": "./fesm2022/valtimo-sse.mjs"
|
|
29
23
|
}
|
|
30
24
|
},
|
|
31
25
|
"sideEffects": false
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2015-2020 Ritense BV, the Netherlands.
|
|
3
|
-
*
|
|
4
|
-
* Licensed under EUPL, Version 1.2 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" basis,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import { Injectable } from '@angular/core';
|
|
17
|
-
import { filter, Observable, Subject } from 'rxjs';
|
|
18
|
-
import { SseErrorBucket, SseEventSubscriptionBucket, SseSubscriptionBucket, } from '../models/sse-bucket.model';
|
|
19
|
-
import * as i0 from "@angular/core";
|
|
20
|
-
import * as i1 from "@valtimo/config";
|
|
21
|
-
import * as i2 from "ngx-logger";
|
|
22
|
-
/**
|
|
23
|
-
* Server-side events service, for connecting and reconnecting to SSE,
|
|
24
|
-
* and a translation layer between SSE json string data and TS typed events.
|
|
25
|
-
*
|
|
26
|
-
* The service is always present, and so events can be registered with {@link onMessage} and {@link onEvent},
|
|
27
|
-
* and will not be lost on disconnect or reconnect of the SSE connection itself.
|
|
28
|
-
* It is expected to also unregister events using the off-method variants of the on-method listeners.
|
|
29
|
-
*
|
|
30
|
-
* To ensure messages are received the connection must be explicitly opened with {@link connect},
|
|
31
|
-
* likewise the connection should also be closed with {@link disconnect} to stop receiving messages.
|
|
32
|
-
*
|
|
33
|
-
* This service can reconnect itself with the backend, and might use the {@link subscriptionId} to ask for its
|
|
34
|
-
* previous connection state. This state currently exists in the backend as the "Subscriber" class, and might
|
|
35
|
-
* have a state containing queues of items that need to be sent, so you can reconnect and receive the rest.
|
|
36
|
-
*
|
|
37
|
-
* At this time no state data is kept, so reconnection without a subscriptionId does not give a different result
|
|
38
|
-
*/
|
|
39
|
-
export class SseService {
|
|
40
|
-
constructor(configService, logger) {
|
|
41
|
-
this.configService = configService;
|
|
42
|
-
this.logger = logger;
|
|
43
|
-
this.connectionCount = 0; // amount of times we have connected sequentially, no concurrent connections
|
|
44
|
-
this.establishedDataHandler = null;
|
|
45
|
-
this.establishedConnection = null;
|
|
46
|
-
this.establishedConnectionObservable = null;
|
|
47
|
-
this.subscriptionId = null;
|
|
48
|
-
this.sequentialConnectionAttemptFailCount = 0;
|
|
49
|
-
this.errorBucket = new SseErrorBucket();
|
|
50
|
-
this.anySubscribersBucket = new SseSubscriptionBucket();
|
|
51
|
-
this.eventSubscribersBuckets = [];
|
|
52
|
-
this.state = SseService.NOT_CONNECTED;
|
|
53
|
-
this._sseMessages$ = new Subject();
|
|
54
|
-
this.VALTIMO_ENDPOINT_URL = configService.config.valtimoApi.endpointUri;
|
|
55
|
-
this.connect();
|
|
56
|
-
}
|
|
57
|
-
get sseMessages$() {
|
|
58
|
-
return this._sseMessages$.asObservable().pipe(filter(message => !!message));
|
|
59
|
-
}
|
|
60
|
-
getSseMessagesObservableByEventType(eventTypes) {
|
|
61
|
-
return this._sseMessages$.asObservable().pipe(filter(message => !!message), filter(message => eventTypes.includes(message?.data?.eventType)));
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Start receiving SSE events
|
|
65
|
-
*/
|
|
66
|
-
connect() {
|
|
67
|
-
this.ensureConnection();
|
|
68
|
-
return this;
|
|
69
|
-
}
|
|
70
|
-
onMessage(listener) {
|
|
71
|
-
this.ensureConnection(); // ensure connection
|
|
72
|
-
this.anySubscribersBucket.on(listener);
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
onEvent(event, listener) {
|
|
76
|
-
this.ensureConnection(); // ensure connection
|
|
77
|
-
let found = false;
|
|
78
|
-
this.eventSubscribersBuckets.forEach(bucket => {
|
|
79
|
-
if (bucket.event === event) {
|
|
80
|
-
bucket.on(listener);
|
|
81
|
-
found = true;
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
if (!found) {
|
|
85
|
-
const bucket = new SseEventSubscriptionBucket(event);
|
|
86
|
-
bucket.on(listener);
|
|
87
|
-
this.eventSubscribersBuckets.push(bucket);
|
|
88
|
-
}
|
|
89
|
-
return this;
|
|
90
|
-
}
|
|
91
|
-
offMessage(listener) {
|
|
92
|
-
this.anySubscribersBucket.off(listener);
|
|
93
|
-
}
|
|
94
|
-
offEvent(event, listener) {
|
|
95
|
-
this.eventSubscribersBuckets.forEach(bucket => {
|
|
96
|
-
if (bucket.event === event) {
|
|
97
|
-
bucket.off(listener);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
offEvents(type) {
|
|
102
|
-
this.eventSubscribersBuckets.forEach(bucket => {
|
|
103
|
-
if (type === null || type === bucket.event) {
|
|
104
|
-
bucket.offAll();
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
offMessages() {
|
|
109
|
-
this.anySubscribersBucket.offAll();
|
|
110
|
-
}
|
|
111
|
-
offAll() {
|
|
112
|
-
this.offEvents();
|
|
113
|
-
this.offMessages();
|
|
114
|
-
}
|
|
115
|
-
disconnect(keepSubscriptionId = false) {
|
|
116
|
-
this.disconnectWith(SseService.NOT_CONNECTED, keepSubscriptionId);
|
|
117
|
-
}
|
|
118
|
-
disconnectWith(state, keepSubscriptionId = false) {
|
|
119
|
-
this.state = state;
|
|
120
|
-
if (this.establishedConnection?.readyState !== EventSource.CLOSED) {
|
|
121
|
-
this.establishedConnection?.close();
|
|
122
|
-
}
|
|
123
|
-
this.establishedDataHandler.unsubscribe();
|
|
124
|
-
this.establishedConnection = null;
|
|
125
|
-
this.establishedConnectionObservable = null;
|
|
126
|
-
this.establishedDataHandler = null;
|
|
127
|
-
if (!keepSubscriptionId) {
|
|
128
|
-
this.subscriptionId = null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
ensureConnection(retry = false) {
|
|
132
|
-
if (this.establishedConnection !== null && this.establishedConnectionObservable !== null) {
|
|
133
|
-
if (this.establishedConnection.readyState !== EventSource.CLOSED) {
|
|
134
|
-
return; // found
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
if (this.state === SseService.CONNECTING || this.state === SseService.RECONNECTING) {
|
|
138
|
-
return; // already connecting
|
|
139
|
-
}
|
|
140
|
-
this.establishedConnection = null;
|
|
141
|
-
this.establishedConnectionObservable = null;
|
|
142
|
-
this.constructNewSse(retry); // create new
|
|
143
|
-
}
|
|
144
|
-
constructNewSse(retry) {
|
|
145
|
-
this.logger.debug('subscribing to sse events');
|
|
146
|
-
if (this.connectionCount > 0) {
|
|
147
|
-
this.state = SseService.RECONNECTING;
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
this.state = SseService.CONNECTING;
|
|
151
|
-
}
|
|
152
|
-
const observable = new Observable(observer => {
|
|
153
|
-
const eventSource = this.getEventSource();
|
|
154
|
-
eventSource.onopen = () => {
|
|
155
|
-
this.establishedConnection = eventSource;
|
|
156
|
-
this.logger.debug('connected to sse');
|
|
157
|
-
this.connectionCount++;
|
|
158
|
-
this.sequentialConnectionAttemptFailCount = 0; // reset retry count
|
|
159
|
-
this.state = SseService.CONNECTED;
|
|
160
|
-
};
|
|
161
|
-
eventSource.onmessage = event => {
|
|
162
|
-
observer.next({
|
|
163
|
-
...event,
|
|
164
|
-
data: JSON.parse(event.data), // parse JSON string to JSON object
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
eventSource.onerror = () => {
|
|
168
|
-
eventSource.close();
|
|
169
|
-
observer.complete();
|
|
170
|
-
if (retry) {
|
|
171
|
-
this.sequentialConnectionAttemptFailCount++;
|
|
172
|
-
this.logger.debug(`retry failed: ${this.sequentialConnectionAttemptFailCount}`);
|
|
173
|
-
if (this.sequentialConnectionAttemptFailCount > 3) {
|
|
174
|
-
this.disconnectWith(SseService.CONNECTION_RETRIES_EXCEEDED, false);
|
|
175
|
-
this.err(`Failed to connect to SSE after ${this.sequentialConnectionAttemptFailCount} retries`);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
this.disconnect(true);
|
|
180
|
-
this.ensureConnection(true);
|
|
181
|
-
};
|
|
182
|
-
return () => eventSource.close();
|
|
183
|
-
});
|
|
184
|
-
this.establishedConnectionObservable = observable;
|
|
185
|
-
this.registerSseEventHandling(observable);
|
|
186
|
-
return observable;
|
|
187
|
-
}
|
|
188
|
-
getEventSource() {
|
|
189
|
-
let suffix = '';
|
|
190
|
-
if (this.subscriptionId != null) {
|
|
191
|
-
suffix = '/' + this.subscriptionId;
|
|
192
|
-
}
|
|
193
|
-
// subscribe to /sse or /sse/<subscriptionId>
|
|
194
|
-
return new EventSource(this.VALTIMO_ENDPOINT_URL + 'v1/sse' + suffix);
|
|
195
|
-
}
|
|
196
|
-
registerSseEventHandling(observable) {
|
|
197
|
-
this.establishedDataHandler = observable.subscribe(event => {
|
|
198
|
-
this._sseMessages$.next(event);
|
|
199
|
-
this.internalListenerEstablishConnection(event);
|
|
200
|
-
// notify all generic listeners
|
|
201
|
-
this.anySubscribersBucket.sendEvent(event.data);
|
|
202
|
-
// notify the specific event listener bucket
|
|
203
|
-
this.eventSubscribersBuckets.forEach(bucket => {
|
|
204
|
-
if (bucket.event === event?.data?.eventType) {
|
|
205
|
-
bucket.sendEvent(event.data);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
internalListenerEstablishConnection(event) {
|
|
211
|
-
if (event?.data?.eventType !== 'ESTABLISHED_CONNECTION') {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
this.logger.debug(`established connection: ${event}`);
|
|
215
|
-
this.subscriptionId = event.data.subscriptionId;
|
|
216
|
-
}
|
|
217
|
-
err(message, ...data) {
|
|
218
|
-
this.errorBucket.sendEvent({
|
|
219
|
-
state: this.state,
|
|
220
|
-
message,
|
|
221
|
-
data,
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
SseService.CONNECTION_RETRIES_EXCEEDED = -1;
|
|
226
|
-
SseService.NOT_CONNECTED = 0;
|
|
227
|
-
SseService.CONNECTING = 1;
|
|
228
|
-
SseService.RECONNECTING = 2;
|
|
229
|
-
SseService.CONNECTED = 10;
|
|
230
|
-
SseService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SseService, deps: [{ token: i1.ConfigService }, { token: i2.NGXLogger }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
231
|
-
SseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SseService, providedIn: 'root' });
|
|
232
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SseService, decorators: [{
|
|
233
|
-
type: Injectable,
|
|
234
|
-
args: [{
|
|
235
|
-
providedIn: 'root',
|
|
236
|
-
}]
|
|
237
|
-
}], ctorParameters: function () { return [{ type: i1.ConfigService }, { type: i2.NGXLogger }]; } });
|
|
238
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3NlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy92YWx0aW1vL3NzZS9zcmMvbGliL3NlcnZpY2VzL3NzZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBRUgsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQWUsTUFBTSxNQUFNLENBQUM7QUFRL0QsT0FBTyxFQUNMLGNBQWMsRUFDZCwwQkFBMEIsRUFDMUIscUJBQXFCLEdBQ3RCLE1BQU0sNEJBQTRCLENBQUM7Ozs7QUFHcEM7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFJSCxNQUFNLE9BQU8sVUFBVTtJQTJCckIsWUFBNkIsYUFBNEIsRUFBbUIsTUFBaUI7UUFBaEUsa0JBQWEsR0FBYixhQUFhLENBQWU7UUFBbUIsV0FBTSxHQUFOLE1BQU0sQ0FBVztRQW5CckYsb0JBQWUsR0FBRyxDQUFDLENBQUMsQ0FBQyw0RUFBNEU7UUFDakcsMkJBQXNCLEdBQWtCLElBQUksQ0FBQztRQUM3QywwQkFBcUIsR0FBaUIsSUFBSSxDQUFDO1FBQzNDLG9DQUErQixHQUEyQyxJQUFJLENBQUM7UUFDL0UsbUJBQWMsR0FBWSxJQUFJLENBQUM7UUFDL0IseUNBQW9DLEdBQUcsQ0FBQyxDQUFDO1FBRXpDLGdCQUFXLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUNuQyx5QkFBb0IsR0FBRyxJQUFJLHFCQUFxQixFQUFnQixDQUFDO1FBQ2pFLDRCQUF1QixHQUErQyxFQUFFLENBQUM7UUFFekUsVUFBSyxHQUFXLFVBQVUsQ0FBQyxhQUFhLENBQUM7UUFFekMsa0JBQWEsR0FBRyxJQUFJLE9BQU8sRUFBOEIsQ0FBQztRQU9oRSxJQUFJLENBQUMsb0JBQW9CLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxV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QyxDQUFDLENBQUM7QUFDakMsd0JBQWEsR0FBRyxDQUFDLENBQUM7QUFDbEIscUJBQVUsR0FBRyxDQUFDLENBQUM7QUFDZix1QkFBWSxHQUFHLENBQUMsQ0FBQztBQUNqQixvQkFBUyxHQUFHLEVBQUUsQ0FBQzt1R0FMNUIsVUFBVTsyR0FBVixVQUFVLGNBRlQsTUFBTTsyRkFFUCxVQUFVO2tCQUh0QixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBDb3B5cmlnaHQgMjAxNS0yMDIwIFJpdGVuc2UgQlYsIHRoZSBOZXRoZXJsYW5kcy5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciBFVVBMLCBWZXJzaW9uIDEuMiAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHBzOi8vam9pbnVwLmVjLmV1cm9wYS5ldS9jb2xsZWN0aW9uL2V1cGwvZXVwbC10ZXh0LWV1cGwtMTJcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgYmFzaXMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbmltcG9ydCB7SW5qZWN0YWJsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge2ZpbHRlciwgT2JzZXJ2YWJsZSwgU3ViamVjdCwgU3Vic2NyaXB0aW9ufSBmcm9tICdyeGpzJztcbmltcG9ydCB7XG4gIEJhc2VTc2VFdmVudCxcbiAgRXN0YWJsaXNoZWRDb25uZWN0aW9uU3NlRXZlbnQsXG4gIFNzZUV2ZW50TGlzdGVuZXIsXG4gIFNzZUV2ZW50VHlwZSxcbn0gZnJvbSAnLi4vbW9kZWxzL3NzZS1ldmVudHMubW9kZWwnO1xuaW1wb3J0IHtDb25maWdTZXJ2aWNlfSBmcm9tICdAdmFsdGltby9jb25maWcnO1xuaW1wb3J0IHtcbiAgU3NlRXJyb3JCdWNrZXQsXG4gIFNzZUV2ZW50U3Vic2NyaXB0aW9uQnVja2V0LFxuICBTc2VTdWJzY3JpcHRpb25CdWNrZXQsXG59IGZyb20gJy4uL21vZGVscy9zc2UtYnVja2V0Lm1vZGVsJztcbmltcG9ydCB7TkdYTG9nZ2VyfSBmcm9tICduZ3gtbG9nZ2VyJztcblxuLyoqXG4gKiBTZXJ2ZXItc2lkZSBldmVudHMgc2VydmljZSwgZm9yIGNvbm5lY3RpbmcgYW5kIHJlY29ubmVjdGluZyB0byBTU0UsXG4gKiBhbmQgYSB0cmFuc2xhdGlvbiBsYXllciBiZXR3ZWVuIFNTRSBqc29uIHN0cmluZyBkYXRhIGFuZCBUUyB0eXBlZCBldmVudHMuXG4gKlxuICogVGhlIHNlcnZpY2UgaXMgYWx3YXlzIHByZXNlbnQsIGFuZCBzbyBldmVudHMgY2FuIGJlIHJlZ2lzdGVyZWQgd2l0aCB7QGxpbmsgb25NZXNzYWdlfSBhbmQge0BsaW5rIG9uRXZlbnR9LFxuICogYW5kIHdpbGwgbm90IGJlIGxvc3Qgb24gZGlzY29ubmVjdCBvciByZWNvbm5lY3Qgb2YgdGhlIFNTRSBjb25uZWN0aW9uIGl0c2VsZi5cbiAqIEl0IGlzIGV4cGVjdGVkIHRvIGFsc28gdW5yZWdpc3RlciBldmVudHMgdXNpbmcgdGhlIG9mZi1tZXRob2QgdmFyaWFudHMgb2YgdGhlIG9uLW1ldGhvZCBsaXN0ZW5lcnMuXG4gKlxuICogVG8gZW5zdXJlIG1lc3NhZ2VzIGFyZSByZWNlaXZlZCB0aGUgY29ubmVjdGlvbiBtdXN0IGJlIGV4cGxpY2l0bHkgb3BlbmVkIHdpdGgge0BsaW5rIGNvbm5lY3R9LFxuICogbGlrZXdpc2UgdGhlIGNvbm5lY3Rpb24gc2hvdWxkIGFsc28gYmUgY2xvc2VkIHdpdGgge0BsaW5rIGRpc2Nvbm5lY3R9IHRvIHN0b3AgcmVjZWl2aW5nIG1lc3NhZ2VzLlxuICpcbiAqIFRoaXMgc2VydmljZSBjYW4gcmVjb25uZWN0IGl0c2VsZiB3aXRoIHRoZSBiYWNrZW5kLCBhbmQgbWlnaHQgdXNlIHRoZSB7QGxpbmsgc3Vic2NyaXB0aW9uSWR9IHRvIGFzayBmb3IgaXRzXG4gKiBwcmV2aW91cyBjb25uZWN0aW9uIHN0YXRlLiBUaGlzIHN0YXRlIGN1cnJlbnRseSBleGlzdHMgaW4gdGhlIGJhY2tlbmQgYXMgdGhlIFwiU3Vic2NyaWJlclwiIGNsYXNzLCBhbmQgbWlnaHRcbiAqIGhhdmUgYSBzdGF0ZSBjb250YWluaW5nIHF1ZXVlcyBvZiBpdGVtcyB0aGF0IG5lZWQgdG8gYmUgc2VudCwgc28geW91IGNhbiByZWNvbm5lY3QgYW5kIHJlY2VpdmUgdGhlIHJlc3QuXG4gKlxuICogQXQgdGhpcyB0aW1lIG5vIHN0YXRlIGRhdGEgaXMga2VwdCwgc28gcmVjb25uZWN0aW9uIHdpdGhvdXQgYSBzdWJzY3JpcHRpb25JZCBkb2VzIG5vdCBnaXZlIGEgZGlmZmVyZW50IHJlc3VsdFxuICovXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290Jyxcbn0pXG5leHBvcnQgY2xhc3MgU3NlU2VydmljZSB7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IENPTk5FQ1RJT05fUkVUUklFU19FWENFRURFRCA9IC0xO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBOT1RfQ09OTkVDVEVEID0gMDtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgQ09OTkVDVElORyA9IDE7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFJFQ09OTkVDVElORyA9IDI7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IENPTk5FQ1RFRCA9IDEwO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgVkFMVElNT19FTkRQT0lOVF9VUkw6IHN0cmluZztcbiAgcHJpdmF0ZSBjb25uZWN0aW9uQ291bnQgPSAwOyAvLyBhbW91bnQgb2YgdGltZXMgd2UgaGF2ZSBjb25uZWN0ZWQgc2VxdWVudGlhbGx5LCBubyBjb25jdXJyZW50IGNvbm5lY3Rpb25zXG4gIHByaXZhdGUgZXN0YWJsaXNoZWREYXRhSGFuZGxlcj86IFN1YnNjcmlwdGlvbiA9IG51bGw7XG4gIHByaXZhdGUgZXN0YWJsaXNoZWRDb25uZWN0aW9uPzogRXZlbnRTb3VyY2UgPSBudWxsO1xuICBwcml2YXRlIGVzdGFibGlzaGVkQ29ubmVjdGlvbk9ic2VydmFibGU6IE9ic2VydmFibGU8TWVzc2FnZUV2ZW50PEJhc2VTc2VFdmVudD4+ID0gbnVsbDtcbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb25JZD86IHN0cmluZyA9IG51bGw7XG4gIHByaXZhdGUgc2VxdWVudGlhbENvbm5lY3Rpb25BdHRlbXB0RmFpbENvdW50ID0gMDtcblxuICBwcml2YXRlIGVycm9yQnVja2V0ID0gbmV3IFNzZUVycm9yQnVja2V0KCk7XG4gIHByaXZhdGUgYW55U3Vic2NyaWJlcnNCdWNrZXQgPSBuZXcgU3NlU3Vic2NyaXB0aW9uQnVja2V0PEJhc2VTc2VFdmVudD4oKTtcbiAgcHJpdmF0ZSBldmVudFN1YnNjcmliZXJzQnVja2V0czogU3NlRXZlbnRTdWJzY3JpcHRpb25CdWNrZXQ8QmFzZVNzZUV2ZW50PltdID0gW107XG5cbiAgcHJpdmF0ZSBzdGF0ZTogbnVtYmVyID0gU3NlU2VydmljZS5OT1RfQ09OTkVDVEVEO1xuXG4gIHByaXZhdGUgX3NzZU1lc3NhZ2VzJCA9IG5ldyBTdWJqZWN0PE1lc3NhZ2VFdmVudDxCYXNlU3NlRXZlbnQ+PigpO1xuXG4gIGdldCBzc2VNZXNzYWdlcyQoKTogT2JzZXJ2YWJsZTxNZXNzYWdlRXZlbnQ8QmFzZVNzZUV2ZW50Pj4ge1xuICAgIHJldHVybiB0aGlzLl9zc2VNZXNzYWdlcyQuYXNPYnNlcnZhYmxlKCkucGlwZShmaWx0ZXIobWVzc2FnZSA9PiAhIW1lc3NhZ2UpKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgY29uZmlnU2VydmljZTogQ29uZmlnU2VydmljZSwgcHJpdmF0ZSByZWFkb25seSBsb2dnZXI6IE5HWExvZ2dlcikge1xuICAgIHRoaXMuVkFMVElNT19FTkRQT0lOVF9VUkwgPSBjb25maWdTZXJ2aWNlLmNvbmZpZy52YWx0aW1vQXBpLmVuZHBvaW50VXJpO1xuICAgIHRoaXMuY29ubmVjdCgpO1xuICB9XG5cbiAgZ2V0U3NlTWVzc2FnZXNPYnNlcnZhYmxlQnlFdmVudFR5cGUoXG4gICAgZXZlbnRUeXBlczogQXJyYXk8U3NlRXZlbnRUeXBlPlxuICApOiBPYnNlcnZhYmxlPE1lc3NhZ2VFdmVudDxCYXNlU3NlRXZlbnQ+PiB7XG4gICAgcmV0dXJuIHRoaXMuX3NzZU1lc3NhZ2VzJC5hc09ic2VydmFibGUoKS5waXBlKFxuICAgICAgZmlsdGVyKG1lc3NhZ2UgPT4gISFtZXNzYWdlKSxcbiAgICAgIGZpbHRlcihtZXNzYWdlID0+IGV2ZW50VHlwZXMuaW5jbHVkZXMobWVzc2FnZT8uZGF0YT8uZXZlbnRUeXBlKSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IHJlY2VpdmluZyBTU0UgZXZlbnRzXG4gICAqL1xuICBwcml2YXRlIGNvbm5lY3QoKSB7XG4gICAgdGhpcy5lbnN1cmVDb25uZWN0aW9uKCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBwcml2YXRlIG9uTWVzc2FnZShsaXN0ZW5lcjogU3NlRXZlbnRMaXN0ZW5lcjxCYXNlU3NlRXZlbnQ+KSB7XG4gICAgdGhpcy5lbnN1cmVDb25uZWN0aW9uKCk7IC8vIGVuc3VyZSBjb25uZWN0aW9uXG4gICAgdGhpcy5hbnlTdWJzY3JpYmVyc0J1Y2tldC5vbihsaXN0ZW5lcik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBwcml2YXRlIG9uRXZlbnQ8VCBleHRlbmRzIEJhc2VTc2VFdmVudD4oZXZlbnQ6IHN0cmluZywgbGlzdGVuZXI6IFNzZUV2ZW50TGlzdGVuZXI8VD4pIHtcbiAgICB0aGlzLmVuc3VyZUNvbm5lY3Rpb24oKTsgLy8gZW5zdXJlIGNvbm5lY3Rpb25cbiAgICBsZXQgZm91bmQgPSBmYWxzZTtcbiAgICB0aGlzLmV2ZW50U3Vic2NyaWJlcnNCdWNrZXRzLmZvckVhY2goYnVja2V0ID0+IHtcbiAgICAgIGlmIChidWNrZXQuZXZlbnQgPT09IGV2ZW50KSB7XG4gICAgICAgIGJ1Y2tldC5vbihsaXN0ZW5lcik7XG4gICAgICAgIGZvdW5kID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBpZiAoIWZvdW5kKSB7XG4gICAgICBjb25zdCBidWNrZXQgPSBuZXcgU3NlRXZlbnRTdWJzY3JpcHRpb25CdWNrZXQoZXZlbnQpO1xuICAgICAgYnVja2V0Lm9uKGxpc3RlbmVyKTtcbiAgICAgIHRoaXMuZXZlbnRTdWJzY3JpYmVyc0J1Y2tldHMucHVzaChidWNrZXQpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHByaXZhdGUgb2ZmTWVzc2FnZShsaXN0ZW5lcjogU3NlRXZlbnRMaXN0ZW5lcjxCYXNlU3NlRXZlbnQ+KSB7XG4gICAgdGhpcy5hbnlTdWJzY3JpYmVyc0J1Y2tldC5vZmYobGlzdGVuZXIpO1xuICB9XG5cbiAgcHJpdmF0ZSBvZmZFdmVudChldmVudDogc3RyaW5nLCBsaXN0ZW5lcjogU3NlRXZlbnRMaXN0ZW5lcjxhbnk+KSB7XG4gICAgdGhpcy5ldmVudFN1YnNjcmliZXJzQnVja2V0cy5mb3JFYWNoKGJ1Y2tldCA9PiB7XG4gICAgICBpZiAoYnVja2V0LmV2ZW50ID09PSBldmVudCkge1xuICAgICAgICBidWNrZXQub2ZmKGxpc3RlbmVyKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgb2ZmRXZlbnRzKHR5cGU/OiBzdHJpbmcpIHtcbiAgICB0aGlzLmV2ZW50U3Vic2NyaWJlcnNCdWNrZXRzLmZvckVhY2goYnVja2V0ID0+IHtcbiAgICAgIGlmICh0eXBlID09PSBudWxsIHx8IHR5cGUgPT09IGJ1Y2tldC5ldmVudCkge1xuICAgICAgICBidWNrZXQub2ZmQWxsKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIG9mZk1lc3NhZ2VzKCkge1xuICAgIHRoaXMuYW55U3Vic2NyaWJlcnNCdWNrZXQub2ZmQWxsKCk7XG4gIH1cblxuICBwcml2YXRlIG9mZkFsbCgpIHtcbiAgICB0aGlzLm9mZkV2ZW50cygpO1xuICAgIHRoaXMub2ZmTWVzc2FnZXMoKTtcbiAgfVxuXG4gIHByaXZhdGUgZGlzY29ubmVjdChrZWVwU3Vic2NyaXB0aW9uSWQ6IGJvb2xlYW4gPSBmYWxzZSkge1xuICAgIHRoaXMuZGlzY29ubmVjdFdpdGgoU3NlU2VydmljZS5OT1RfQ09OTkVDVEVELCBrZWVwU3Vic2NyaXB0aW9uSWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBkaXNjb25uZWN0V2l0aChzdGF0ZTogbnVtYmVyLCBrZWVwU3Vic2NyaXB0aW9uSWQ6IGJvb2xlYW4gPSBmYWxzZSkge1xuICAgIHRoaXMuc3RhdGUgPSBzdGF0ZTtcbiAgICBpZiAodGhpcy5lc3RhYmxpc2hlZENvbm5lY3Rpb24/LnJlYWR5U3RhdGUgIT09IEV2ZW50U291cmNlLkNMT1NFRCkge1xuICAgICAgdGhpcy5lc3RhYmxpc2hlZENvbm5lY3Rpb24/LmNsb3NlKCk7XG4gICAgfVxuICAgIHRoaXMuZXN0YWJsaXNoZWREYXRhSGFuZGxlci51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9uID0gbnVsbDtcbiAgICB0aGlzLmVzdGFibGlzaGVkQ29ubmVjdGlvbk9ic2VydmFibGUgPSBudWxsO1xuICAgIHRoaXMuZXN0YWJsaXNoZWREYXRhSGFuZGxlciA9IG51bGw7XG4gICAgaWYgKCFrZWVwU3Vic2NyaXB0aW9uSWQpIHtcbiAgICAgIHRoaXMuc3Vic2NyaXB0aW9uSWQgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZW5zdXJlQ29ubmVjdGlvbihyZXRyeTogYm9vbGVhbiA9IGZhbHNlKSB7XG4gICAgaWYgKHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9uICE9PSBudWxsICYmIHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9uT2JzZXJ2YWJsZSAhPT0gbnVsbCkge1xuICAgICAgaWYgKHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9uLnJlYWR5U3RhdGUgIT09IEV2ZW50U291cmNlLkNMT1NFRCkge1xuICAgICAgICByZXR1cm47IC8vIGZvdW5kXG4gICAgICB9XG4gICAgfVxuICAgIGlmICh0aGlzLnN0YXRlID09PSBTc2VTZXJ2aWNlLkNPTk5FQ1RJTkcgfHwgdGhpcy5zdGF0ZSA9PT0gU3NlU2VydmljZS5SRUNPTk5FQ1RJTkcpIHtcbiAgICAgIHJldHVybjsgLy8gYWxyZWFkeSBjb25uZWN0aW5nXG4gICAgfVxuICAgIHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9uID0gbnVsbDtcbiAgICB0aGlzLmVzdGFibGlzaGVkQ29ubmVjdGlvbk9ic2VydmFibGUgPSBudWxsO1xuXG4gICAgdGhpcy5jb25zdHJ1Y3ROZXdTc2UocmV0cnkpOyAvLyBjcmVhdGUgbmV3XG4gIH1cblxuICBwcml2YXRlIGNvbnN0cnVjdE5ld1NzZShyZXRyeTogYm9vbGVhbikge1xuICAgIHRoaXMubG9nZ2VyLmRlYnVnKCdzdWJzY3JpYmluZyB0byBzc2UgZXZlbnRzJyk7XG4gICAgaWYgKHRoaXMuY29ubmVjdGlvbkNvdW50ID4gMCkge1xuICAgICAgdGhpcy5zdGF0ZSA9IFNzZVNlcnZpY2UuUkVDT05ORUNUSU5HO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnN0YXRlID0gU3NlU2VydmljZS5DT05ORUNUSU5HO1xuICAgIH1cbiAgICBjb25zdCBvYnNlcnZhYmxlID0gbmV3IE9ic2VydmFibGU8TWVzc2FnZUV2ZW50PEJhc2VTc2VFdmVudD4+KG9ic2VydmVyID0+IHtcbiAgICAgIGNvbnN0IGV2ZW50U291cmNlID0gdGhpcy5nZXRFdmVudFNvdXJjZSgpO1xuICAgICAgZXZlbnRTb3VyY2Uub25vcGVuID0gKCkgPT4ge1xuICAgICAgICB0aGlzLmVzdGFibGlzaGVkQ29ubmVjdGlvbiA9IGV2ZW50U291cmNlO1xuICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZygnY29ubmVjdGVkIHRvIHNzZScpO1xuICAgICAgICB0aGlzLmNvbm5lY3Rpb25Db3VudCsrO1xuICAgICAgICB0aGlzLnNlcXVlbnRpYWxDb25uZWN0aW9uQXR0ZW1wdEZhaWxDb3VudCA9IDA7IC8vIHJlc2V0IHJldHJ5IGNvdW50XG4gICAgICAgIHRoaXMuc3RhdGUgPSBTc2VTZXJ2aWNlLkNPTk5FQ1RFRDtcbiAgICAgIH07XG4gICAgICBldmVudFNvdXJjZS5vbm1lc3NhZ2UgPSBldmVudCA9PiB7XG4gICAgICAgIG9ic2VydmVyLm5leHQoe1xuICAgICAgICAgIC4uLmV2ZW50LCAvLyBmb3J3YXJkIGV2ZW50IG9iamVjdCBidXQgcmVwbGFjZSBkYXRhIGZpZWxkXG4gICAgICAgICAgZGF0YTogSlNPTi5wYXJzZShldmVudC5kYXRhKSwgLy8gcGFyc2UgSlNPTiBzdHJpbmcgdG8gSlNPTiBvYmplY3RcbiAgICAgICAgfSk7XG4gICAgICB9O1xuICAgICAgZXZlbnRTb3VyY2Uub25lcnJvciA9ICgpID0+IHtcbiAgICAgICAgZXZlbnRTb3VyY2UuY2xvc2UoKTtcbiAgICAgICAgb2JzZXJ2ZXIuY29tcGxldGUoKTtcbiAgICAgICAgaWYgKHJldHJ5KSB7XG4gICAgICAgICAgdGhpcy5zZXF1ZW50aWFsQ29ubmVjdGlvbkF0dGVtcHRGYWlsQ291bnQrKztcbiAgICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhgcmV0cnkgZmFpbGVkOiAke3RoaXMuc2VxdWVudGlhbENvbm5lY3Rpb25BdHRlbXB0RmFpbENvdW50fWApO1xuICAgICAgICAgIGlmICh0aGlzLnNlcXVlbnRpYWxDb25uZWN0aW9uQXR0ZW1wdEZhaWxDb3VudCA+IDMpIHtcbiAgICAgICAgICAgIHRoaXMuZGlzY29ubmVjdFdpdGgoU3NlU2VydmljZS5DT05ORUNUSU9OX1JFVFJJRVNfRVhDRUVERUQsIGZhbHNlKTtcbiAgICAgICAgICAgIHRoaXMuZXJyKFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIGNvbm5lY3QgdG8gU1NFIGFmdGVyICR7dGhpcy5zZXF1ZW50aWFsQ29ubmVjdGlvbkF0dGVtcHRGYWlsQ291bnR9IHJldHJpZXNgXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRpc2Nvbm5lY3QodHJ1ZSk7XG4gICAgICAgIHRoaXMuZW5zdXJlQ29ubmVjdGlvbih0cnVlKTtcbiAgICAgIH07XG4gICAgICByZXR1cm4gKCkgPT4gZXZlbnRTb3VyY2UuY2xvc2UoKTtcbiAgICB9KTtcbiAgICB0aGlzLmVzdGFibGlzaGVkQ29ubmVjdGlvbk9ic2VydmFibGUgPSBvYnNlcnZhYmxlO1xuICAgIHRoaXMucmVnaXN0ZXJTc2VFdmVudEhhbmRsaW5nKG9ic2VydmFibGUpO1xuICAgIHJldHVybiBvYnNlcnZhYmxlO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRFdmVudFNvdXJjZSgpIHtcbiAgICBsZXQgc3VmZml4ID0gJyc7XG4gICAgaWYgKHRoaXMuc3Vic2NyaXB0aW9uSWQgIT0gbnVsbCkge1xuICAgICAgc3VmZml4ID0gJy8nICsgdGhpcy5zdWJzY3JpcHRpb25JZDtcbiAgICB9XG4gICAgLy8gc3Vic2NyaWJlIHRvIC9zc2Ugb3IgL3NzZS88c3Vic2NyaXB0aW9uSWQ+XG4gICAgcmV0dXJuIG5ldyBFdmVudFNvdXJjZSh0aGlzLlZBTFRJTU9fRU5EUE9JTlRfVVJMICsgJ3YxL3NzZScgKyBzdWZmaXgpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWdpc3RlclNzZUV2ZW50SGFuZGxpbmcob2JzZXJ2YWJsZTogT2JzZXJ2YWJsZTxNZXNzYWdlRXZlbnQ8QmFzZVNzZUV2ZW50Pj4pIHtcbiAgICB0aGlzLmVzdGFibGlzaGVkRGF0YUhhbmRsZXIgPSBvYnNlcnZhYmxlLnN1YnNjcmliZShldmVudCA9PiB7XG4gICAgICB0aGlzLl9zc2VNZXNzYWdlcyQubmV4dChldmVudCk7XG4gICAgICB0aGlzLmludGVybmFsTGlzdGVuZXJFc3RhYmxpc2hDb25uZWN0aW9uKGV2ZW50KTtcbiAgICAgIC8vIG5vdGlmeSBhbGwgZ2VuZXJpYyBsaXN0ZW5lcnNcbiAgICAgIHRoaXMuYW55U3Vic2NyaWJlcnNCdWNrZXQuc2VuZEV2ZW50KGV2ZW50LmRhdGEpO1xuICAgICAgLy8gbm90aWZ5IHRoZSBzcGVjaWZpYyBldmVudCBsaXN0ZW5lciBidWNrZXRcbiAgICAgIHRoaXMuZXZlbnRTdWJzY3JpYmVyc0J1Y2tldHMuZm9yRWFjaChidWNrZXQgPT4ge1xuICAgICAgICBpZiAoYnVja2V0LmV2ZW50ID09PSBldmVudD8uZGF0YT8uZXZlbnRUeXBlKSB7XG4gICAgICAgICAgYnVja2V0LnNlbmRFdmVudChldmVudC5kYXRhKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGludGVybmFsTGlzdGVuZXJFc3RhYmxpc2hDb25uZWN0aW9uKGV2ZW50OiBNZXNzYWdlRXZlbnQ8QmFzZVNzZUV2ZW50Pikge1xuICAgIGlmIChldmVudD8uZGF0YT8uZXZlbnRUeXBlICE9PSAnRVNUQUJMSVNIRURfQ09OTkVDVElPTicpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoYGVzdGFibGlzaGVkIGNvbm5lY3Rpb246ICR7ZXZlbnR9YCk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25JZCA9IChldmVudC5kYXRhIGFzIEVzdGFibGlzaGVkQ29ubmVjdGlvblNzZUV2ZW50KS5zdWJzY3JpcHRpb25JZDtcbiAgfVxuXG4gIHByaXZhdGUgZXJyKG1lc3NhZ2U6IHN0cmluZywgLi4uZGF0YTogYW55KSB7XG4gICAgdGhpcy5lcnJvckJ1Y2tldC5zZW5kRXZlbnQoe1xuICAgICAgc3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICBtZXNzYWdlLFxuICAgICAgZGF0YSxcbiAgICB9KTtcbiAgfVxufVxuIl19
|