@ruc-lib/screen-recorder 2.9.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.
@@ -0,0 +1,333 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject, Subject, timer } from 'rxjs';
3
+ import { takeWhile, tap } from 'rxjs/operators';
4
+ import { RecordingState } from '../models/screen-recorder.models';
5
+ import { ScreenRecorderConstants } from '../screen-recorder/screen-recorder-constant';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "../screen-recorder/screen-recorder-constant";
8
+ export class ScreenRecorderService {
9
+ constructor(screenRecordingConstant) {
10
+ this.screenRecordingConstant = screenRecordingConstant;
11
+ this.stream = null;
12
+ this.mediaRecorder = null;
13
+ this.recordedBlobs = [];
14
+ this.currentRecordedTime = 0;
15
+ this.recordingStateSubject = new BehaviorSubject(RecordingState.Idle);
16
+ this.recordingState$ = this.recordingStateSubject.asObservable();
17
+ this.recordedTimeSubject = new BehaviorSubject(0);
18
+ this.recordedTime$ = this.recordedTimeSubject.asObservable();
19
+ this.recordedUrlSubject = new BehaviorSubject(null);
20
+ this.recordedUrl$ = this.recordedUrlSubject.asObservable();
21
+ this.recordingTimestampSubject = new BehaviorSubject('');
22
+ this.recordingTimestamp$ = this.recordingTimestampSubject.asObservable();
23
+ this.errorSubject = new Subject();
24
+ this.error$ = this.errorSubject.asObservable();
25
+ }
26
+ /**
27
+ * Starts the screen recording with optional audio
28
+ *
29
+ * @param options - Configuration options for recording
30
+ * @param options.audio - Whether to include audio in the recording
31
+ *
32
+ * @throws Error if recording is already in progress or if media access is denied
33
+ * @returns Promise<void>
34
+ */
35
+ async startRecording(options) {
36
+ if (this.recordingStateSubject.value === RecordingState.Recording || this.recordingStateSubject.value === RecordingState.Paused) {
37
+ this.handleError(this.screenRecordingConstant.RECORDING_IN_PROGRESS_ERROR);
38
+ return;
39
+ }
40
+ this.cleanupPreviousRecording();
41
+ try {
42
+ // The browser's native picker handles "specific area" selection (window, tab, screen).
43
+ const displayStream = await navigator.mediaDevices.getDisplayMedia({
44
+ video: true
45
+ });
46
+ // If audio is enabled, get the audio stream
47
+ let audioStream = null;
48
+ if (options.audio) {
49
+ audioStream = await navigator.mediaDevices.getUserMedia({
50
+ audio: {
51
+ echoCancellation: true,
52
+ noiseSuppression: true,
53
+ sampleRate: 44100
54
+ }
55
+ });
56
+ }
57
+ // Combine the streams if audio is enabled
58
+ if (audioStream) {
59
+ this.stream = new MediaStream([...displayStream.getTracks(), ...audioStream.getTracks()]);
60
+ }
61
+ else {
62
+ this.stream = displayStream;
63
+ }
64
+ // Listen for when the user stops sharing via browser UI
65
+ this.stream.getVideoTracks()[0].onended = () => {
66
+ if (this.recordingStateSubject.value === RecordingState.Recording || this.recordingStateSubject.value === RecordingState.Paused) {
67
+ this.stopRecordingInternal();
68
+ }
69
+ };
70
+ // Handle errors
71
+ if (!this.stream) {
72
+ this.handleError(this.screenRecordingConstant.FAILED_TO_GET_DISPLAY_MEDIA_STREAM_ERROR);
73
+ return;
74
+ }
75
+ // Set recording timestamp
76
+ const now = new Date();
77
+ const timestamp = now.toLocaleString('en-IN', {
78
+ year: 'numeric',
79
+ month: '2-digit',
80
+ day: '2-digit',
81
+ hour: '2-digit',
82
+ minute: '2-digit',
83
+ hour12: true
84
+ });
85
+ this.recordingTimestampSubject.next(timestamp);
86
+ this.recordedBlobs = [];
87
+ const mimeType = this.getSupportedMimeType();
88
+ if (!mimeType) {
89
+ this.handleError(this.screenRecordingConstant.NO_SUPPORT_MIME);
90
+ this.stream?.getTracks().forEach(track => track.stop());
91
+ this.stream = null;
92
+ return;
93
+ }
94
+ // Create a canvas for timestamp overlay
95
+ const canvas = document.createElement('canvas');
96
+ const videoTrack = this.stream?.getVideoTracks()[0];
97
+ if (videoTrack) {
98
+ const video = document.createElement('video');
99
+ video.srcObject = this.stream;
100
+ // Wait for video to load metadata
101
+ video.onloadedmetadata = () => {
102
+ canvas.width = video.videoWidth;
103
+ canvas.height = video.videoHeight;
104
+ const ctx = canvas.getContext('2d');
105
+ if (ctx) {
106
+ // Draw video frame
107
+ ctx.drawImage(video, 0, 0);
108
+ // Draw timestamp
109
+ ctx.font = '16px Arial';
110
+ ctx.fillStyle = 'white';
111
+ ctx.textAlign = 'right';
112
+ ctx.textBaseline = 'top';
113
+ ctx.fillText(`Recorded on: ${this.recordingTimestampSubject.value}`, canvas.width - 10, 10);
114
+ }
115
+ };
116
+ }
117
+ // Create a new stream with the canvas
118
+ const canvasStream = canvas.captureStream();
119
+ const combinedStream = new MediaStream([...this.stream?.getTracks() ?? [], canvasStream.getVideoTracks()[0]]);
120
+ this.mediaRecorder = new MediaRecorder(combinedStream, { mimeType });
121
+ this.mediaRecorder.ondataavailable = (event) => {
122
+ if (event.data && event.data.size > 0) {
123
+ this.recordedBlobs.push(event.data);
124
+ }
125
+ };
126
+ this.mediaRecorder.onstop = () => {
127
+ const superBuffer = new Blob(this.recordedBlobs, { type: mimeType });
128
+ const url = window.URL.createObjectURL(superBuffer);
129
+ this.recordedUrlSubject.next(url);
130
+ this.recordingStateSubject.next(RecordingState.Stopped);
131
+ this.stopTimer();
132
+ };
133
+ this.mediaRecorder.onerror = (event) => {
134
+ const errorEvent = event; // More specific type if available
135
+ let message = this.screenRecordingConstant.MEDIA_ERROR;
136
+ if (errorEvent.error && errorEvent.error.name) {
137
+ message += `: ${errorEvent.error.name}`;
138
+ if (errorEvent.error.message)
139
+ message += ` - ${errorEvent.error.message}`;
140
+ }
141
+ this.handleError(message);
142
+ this.recordingStateSubject.next(RecordingState.Idle);
143
+ this.stopTimer();
144
+ };
145
+ this.mediaRecorder.start(); // Start recording
146
+ this.recordingStateSubject.next(RecordingState.Recording);
147
+ this.startTimer();
148
+ }
149
+ catch (err) {
150
+ this.handleError(`Error starting screen recording: ${err.name} - ${err.message}`);
151
+ this.recordingStateSubject.next(RecordingState.Idle);
152
+ }
153
+ }
154
+ /**
155
+ * Gets the first supported MIME type for MediaRecorder
156
+ *
157
+ * @returns string|null - The supported MIME type or null if none found
158
+ */
159
+ getSupportedMimeType() {
160
+ const mimeTypes = [
161
+ 'video/webm;codecs=vp9,opus',
162
+ 'video/webm;codecs=vp8,opus',
163
+ 'video/webm;codecs=h264,opus',
164
+ 'video/mp4;codecs=h264,aac',
165
+ 'video/webm',
166
+ ];
167
+ for (const mimeType of mimeTypes) {
168
+ if (MediaRecorder.isTypeSupported(mimeType)) {
169
+ return mimeType;
170
+ }
171
+ }
172
+ return null;
173
+ }
174
+ /**
175
+ * Internal method to stop the recording process
176
+ *
177
+ * @private
178
+ * @returns void
179
+ */
180
+ stopRecordingInternal() {
181
+ if (this.mediaRecorder && (this.recordingStateSubject.value === RecordingState.Recording || this.recordingStateSubject.value === RecordingState.Paused)) {
182
+ this.mediaRecorder.stop();
183
+ }
184
+ this.stream?.getTracks().forEach(track => track.stop());
185
+ this.stream = null;
186
+ // State will be updated by onstop handler
187
+ }
188
+ /**
189
+ *
190
+ * @returns Promise<void>
191
+ * @throws Error if recording is not in progress
192
+ */
193
+ stopRecording() {
194
+ this.stopRecordingInternal();
195
+ }
196
+ /**
197
+ * Pauses the current recording
198
+ *
199
+ * @returns Promise<void>
200
+ * @throws Error if recording is not in progress
201
+ */
202
+ pauseRecording() {
203
+ if (this.mediaRecorder && this.recordingStateSubject.value === RecordingState.Recording) {
204
+ this.mediaRecorder.pause();
205
+ this.recordingStateSubject.next(RecordingState.Paused);
206
+ this.stopTimer(); // Pauses the timer display
207
+ }
208
+ }
209
+ /**
210
+ * Resumes a paused recording
211
+ *
212
+ * @returns Promise<void>
213
+ * @throws Error if recording is not paused
214
+ */
215
+ resumeRecording() {
216
+ if (this.mediaRecorder && this.recordingStateSubject.value === RecordingState.Paused) {
217
+ this.mediaRecorder.resume();
218
+ this.recordingStateSubject.next(RecordingState.Recording);
219
+ this.startTimer(this.currentRecordedTime); // Resumes timer display
220
+ }
221
+ }
222
+ /**
223
+ *
224
+ * @param fileName
225
+ */
226
+ downloadRecording(fileName = 'recording.webm') {
227
+ const url = this.recordedUrlSubject.value;
228
+ const timestamp = this.recordingTimestampSubject.value;
229
+ if (url && timestamp) {
230
+ // Format the timestamp for filename (remove spaces and special characters)
231
+ const formattedTimestamp = timestamp.replace(/[^a-zA-Z0-9]/g, '_');
232
+ // Create filename with timestamp
233
+ const fileExtension = fileName.split('.').pop() || 'webm';
234
+ const newFileName = `screen_recording_${formattedTimestamp}.${fileExtension}`;
235
+ const a = document.createElement('a');
236
+ a.style.display = 'none';
237
+ a.href = url;
238
+ a.download = newFileName;
239
+ document.body.appendChild(a);
240
+ a.click();
241
+ document.body.removeChild(a);
242
+ // No need to revoke URL here if user might want to play it again.
243
+ // Revoke on cleanup or new recording.
244
+ }
245
+ else {
246
+ this.handleError(this.screenRecordingConstant.NO_RECORDING_DOWNLOAD);
247
+ }
248
+ }
249
+ /**
250
+ * Starts the recording timer
251
+ *
252
+ * @param startTime - Optional start time for the timer
253
+ * @private
254
+ * @returns void
255
+ */
256
+ startTimer(startTime = 0) {
257
+ this.stopTimer(); // Ensure no multiple timers
258
+ this.currentRecordedTime = startTime;
259
+ this.recordedTimeSubject.next(this.currentRecordedTime);
260
+ this.timerSubscription = timer(0, 1000)
261
+ .pipe(tap(() => {
262
+ if (this.recordingStateSubject.value === RecordingState.Recording) {
263
+ this.currentRecordedTime++;
264
+ this.recordedTimeSubject.next(this.currentRecordedTime);
265
+ }
266
+ }), takeWhile(() => this.recordingStateSubject.value === RecordingState.Recording))
267
+ .subscribe();
268
+ }
269
+ /**
270
+ * Stops the recording timer
271
+ *
272
+ * @private
273
+ * @returns void
274
+ */
275
+ stopTimer() {
276
+ if (this.timerSubscription) {
277
+ this.timerSubscription.unsubscribe();
278
+ this.timerSubscription = null;
279
+ }
280
+ }
281
+ /**
282
+ * Cleans up resources from previous recording
283
+ *
284
+ * @private
285
+ * @returns void
286
+ */
287
+ cleanupPreviousRecording() {
288
+ if (this.recordedUrlSubject.value) {
289
+ window.URL.revokeObjectURL(this.recordedUrlSubject.value);
290
+ this.recordedUrlSubject.next(null);
291
+ }
292
+ this.recordedBlobs = [];
293
+ this.currentRecordedTime = 0;
294
+ this.recordedTimeSubject.next(0);
295
+ if (this.stream) {
296
+ this.stream.getTracks().forEach(track => track.stop());
297
+ this.stream = null;
298
+ }
299
+ if (this.mediaRecorder && this.mediaRecorder.state !== this.screenRecordingConstant.INACTIVE) {
300
+ this.mediaRecorder.stop();
301
+ }
302
+ this.mediaRecorder = null;
303
+ }
304
+ /**
305
+ * Resets the recording state to idle
306
+ *
307
+ * @returns void
308
+ */
309
+ resetToIdle() {
310
+ this.cleanupPreviousRecording();
311
+ this.recordingStateSubject.next(RecordingState.Idle);
312
+ this.errorSubject.next(''); // Clear any previous errors
313
+ }
314
+ /**
315
+ * Handles and broadcasts recording errors
316
+ *
317
+ * @private
318
+ * @param error - The error message to handle
319
+ * @returns void
320
+ */
321
+ handleError(error) {
322
+ this.errorSubject.next(error);
323
+ }
324
+ }
325
+ ScreenRecorderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ScreenRecorderService, deps: [{ token: i1.ScreenRecorderConstants }], target: i0.ɵɵFactoryTarget.Injectable });
326
+ ScreenRecorderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ScreenRecorderService, providedIn: 'root' });
327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ScreenRecorderService, decorators: [{
328
+ type: Injectable,
329
+ args: [{
330
+ providedIn: 'root', // Or provide in your module if preferred
331
+ }]
332
+ }], ctorParameters: function () { return [{ type: i1.ScreenRecorderConstants }]; } });
333
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyZWVuLXJlY29yZGVyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9saWJzL3J1Y2xpYi9zY3JlZW4tcmVjb3JkZXIvc3JjL2xpYi9zZXJ2aWNlcy9zY3JlZW4tcmVjb3JkZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxlQUFlLEVBQWMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNuRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNsRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQzs7O0FBSXRGLE1BQU0sT0FBTyxxQkFBcUI7SUFzQmhDLFlBQW1CLHVCQUFnRDtRQUFoRCw0QkFBdUIsR0FBdkIsdUJBQXVCLENBQXlCO1FBckIzRCxXQUFNLEdBQXVCLElBQUksQ0FBQztRQUNsQyxrQkFBYSxHQUF5QixJQUFJLENBQUM7UUFDM0Msa0JBQWEsR0FBVyxFQUFFLENBQUM7UUFFM0Isd0JBQW1CLEdBQVcsQ0FBQyxDQUFDO1FBRXZCLDBCQUFxQixHQUFHLElBQUksZUFBZSxDQUFpQixjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDekYsb0JBQWUsR0FBK0IsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRWhGLHdCQUFtQixHQUFHLElBQUksZUFBZSxDQUFTLENBQUMsQ0FBQyxDQUFDO1FBQzdELGtCQUFhLEdBQXVCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUVwRSx1QkFBa0IsR0FBRyxJQUFJLGVBQWUsQ0FBZ0IsSUFBSSxDQUFDLENBQUM7UUFDdEUsaUJBQVksR0FBOEIsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXpFLDhCQUF5QixHQUFHLElBQUksZUFBZSxDQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ3BFLHdCQUFtQixHQUF1QixJQUFJLENBQUMseUJBQXlCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFaEYsaUJBQVksR0FBRyxJQUFJLE9BQU8sRUFBVSxDQUFDO1FBQzdDLFdBQU0sR0FBdUIsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUVBLENBQUM7SUFFeEU7Ozs7Ozs7O09BUUc7SUFDSCxLQUFLLENBQUMsY0FBYyxDQUFDLE9BQTJCO1FBRTlDLElBQUksSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssS0FBSyxjQUFjLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLEtBQUssY0FBYyxDQUFDLE1BQU0sRUFBRTtZQUMvSCxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1lBQzNFLE9BQU87U0FDUjtRQUVELElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBRWhDLElBQUk7WUFDRix1RkFBdUY7WUFDdkYsTUFBTSxhQUFhLEdBQUcsTUFBTSxTQUFTLENBQUMsWUFBWSxDQUFDLGVBQWUsQ0FBQztnQkFDakUsS0FBSyxFQUFFLElBQUk7YUFDWixDQUFDLENBQUM7WUFFSCw0Q0FBNEM7WUFDNUMsSUFBSSxXQUFXLEdBQXVCLElBQUksQ0FBQztZQUMzQyxJQUFJLE9BQU8sQ0FBQyxLQUFLLEVBQUU7Z0JBQ2pCLFdBQVcsR0FBRyxNQUFNLFNBQVMsQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDO29CQUN0RCxLQUFLLEVBQUU7d0JBQ0wsZ0JBQWdCLEVBQUUsSUFBSTt3QkFDdEIsZ0JBQWdCLEVBQUUsSUFBSTt3QkFDdEIsVUFBVSxFQUFFLEtBQUs7cUJBQ2xCO2lCQUNGLENBQUMsQ0FBQzthQUNKO1lBRUQsMENBQTBDO1lBQzFDLElBQUksV0FBVyxFQUFFO2dCQUNmLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxXQUFXLENBQUMsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxTQUFTLEVBQUUsRUFBRSxHQUFHLFdBQVcsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUM7YUFDM0Y7aUJBQU07Z0JBQ0wsSUFBSSxDQUFDLE1BQU0sR0FBRyxhQUFhLENBQUM7YUFDN0I7WUFFRCx3REFBd0Q7WUFDeEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUcsR0FBRyxFQUFFO2dCQUM3QyxJQUFJLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLEtBQUssY0FBYyxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxLQUFLLGNBQWMsQ0FBQyxNQUFNLEVBQUU7b0JBQy9ILElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO2lCQUM5QjtZQUNILENBQUMsQ0FBQztZQUVGLGdCQUFnQjtZQUNoQixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtnQkFDaEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsdUJBQXVCLENBQUMsd0NBQXdDLENBQUMsQ0FBQztnQkFDeEYsT0FBTzthQUNSO1lBRUQsMEJBQTBCO1lBQzFCLE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7WUFDdkIsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUU7Z0JBQzVDLElBQUksRUFBRSxTQUFTO2dCQUNmLEtBQUssRUFBRSxTQUFTO2dCQUNoQixHQUFHLEVBQUUsU0FBUztnQkFDZCxJQUFJLEVBQUUsU0FBUztnQkFDZixNQUFNLEVBQUUsU0FBUztnQkFDakIsTUFBTSxFQUFFLElBQUk7YUFDYixDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRy9DLElBQUksQ0FBQyxhQUFhLEdBQUcsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1lBQzdDLElBQUksQ0FBQyxRQUFRLEVBQUU7Z0JBQ2IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsdUJBQXVCLENBQUMsZUFBZSxDQUFDLENBQUM7Z0JBQy9ELElBQUksQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQ3hELElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO2dCQUNuQixPQUFPO2FBQ1I7WUFFRCx3Q0FBd0M7WUFDeEMsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUNoRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3BELElBQUksVUFBVSxFQUFFO2dCQUNkLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQzlDLEtBQUssQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztnQkFFOUIsa0NBQWtDO2dCQUNsQyxLQUFLLENBQUMsZ0JBQWdCLEdBQUcsR0FBRyxFQUFFO29CQUM1QixNQUFNLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUM7b0JBQ2hDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQztvQkFDbEMsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDcEMsSUFBSSxHQUFHLEVBQUU7d0JBQ1AsbUJBQW1CO3dCQUNuQixHQUFHLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7d0JBRTNCLGlCQUFpQjt3QkFDakIsR0FBRyxDQUFDLElBQUksR0FBRyxZQUFZLENBQUM7d0JBQ3hCLEdBQUcsQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDO3dCQUN4QixHQUFHLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQzt3QkFDeEIsR0FBRyxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUM7d0JBQ3pCLEdBQUcsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxLQUFLLEVBQUUsRUFBRSxNQUFNLENBQUMsS0FBSyxHQUFHLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztxQkFDN0Y7Z0JBQ0gsQ0FBQyxDQUFDO2FBQ0g7WUFFRCxzQ0FBc0M7WUFDdEMsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzVDLE1BQU0sY0FBYyxHQUFHLElBQUksV0FBVyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsRUFBRSxZQUFZLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTlHLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxhQUFhLENBQUMsY0FBYyxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUVyRSxJQUFJLENBQUMsYUFBYSxDQUFDLGVBQWUsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUM3QyxJQUFJLEtBQUssQ0FBQyxJQUFJLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxFQUFFO29CQUNyQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQ3JDO1lBQ0gsQ0FBQyxDQUFDO1lBRUYsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFO2dCQUMvQixNQUFNLFdBQVcsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQ3JFLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUNwRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNsQyxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDeEQsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBRW5CLENBQUMsQ0FBQztZQUVGLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxHQUFHLENBQUMsS0FBWSxFQUFFLEVBQUU7Z0JBQzVDLE1BQU0sVUFBVSxHQUFHLEtBQW1CLENBQUMsQ0FBQyxrQ0FBa0M7Z0JBQzFFLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxXQUFXLENBQUM7Z0JBQ3ZELElBQUksVUFBVSxDQUFDLEtBQUssSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRTtvQkFDN0MsT0FBTyxJQUFJLEtBQUssVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDeEMsSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLE9BQU87d0JBQUUsT0FBTyxJQUFJLE1BQU0sVUFBVSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztpQkFDM0U7Z0JBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDMUIsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ3JELElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNuQixDQUFDLENBQUM7WUFFRixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsa0JBQWtCO1lBQzlDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzFELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztTQUNuQjtRQUFDLE9BQU8sR0FBUSxFQUFFO1lBQ2pCLElBQUksQ0FBQyxXQUFXLENBQUMsb0NBQW9DLEdBQUcsQ0FBQyxJQUFJLE1BQU0sR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDbEYsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdEQ7SUFDSCxDQUFDO0lBRUQ7Ozs7S0FJQztJQUNPLG9CQUFvQjtRQUMxQixNQUFNLFNBQVMsR0FBRztZQUNoQiw0QkFBNEI7WUFDNUIsNEJBQTRCO1lBQzVCLDZCQUE2QjtZQUM3QiwyQkFBMkI7WUFDM0IsWUFBWTtTQUNiLENBQUM7UUFDRixLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRTtZQUNoQyxJQUFJLGFBQWEsQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLEVBQUU7Z0JBQzNDLE9BQU8sUUFBUSxDQUFDO2FBQ2pCO1NBQ0Y7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLHFCQUFxQjtRQUMzQixJQUFJLElBQUksQ0FBQyxhQUFhLElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxLQUFLLGNBQWMsQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssS0FBSyxjQUFjLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDdkosSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztTQUMzQjtRQUNELElBQUksQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDeEQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7UUFDbkIsMENBQTBDO0lBQzVDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsYUFBYTtRQUNYLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILGNBQWM7UUFDWixJQUFJLElBQUksQ0FBQyxhQUFhLElBQUksSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssS0FBSyxjQUFjLENBQUMsU0FBUyxFQUFFO1lBQ3ZGLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDM0IsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdkQsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsMkJBQTJCO1NBQzlDO0lBQ0gsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsZUFBZTtRQUNiLElBQUksSUFBSSxDQUFDLGFBQWEsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxLQUFLLGNBQWMsQ0FBQyxNQUFNLEVBQUU7WUFDcEYsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUM1QixJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMxRCxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsd0JBQXdCO1NBQ3BFO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNILGlCQUFpQixDQUFDLFdBQW1CLGdCQUFnQjtRQUNuRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsS0FBSyxDQUFDO1FBQzFDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxLQUFLLENBQUM7UUFFdkQsSUFBSSxHQUFHLElBQUksU0FBUyxFQUFFO1lBQ3BCLDJFQUEyRTtZQUMzRSxNQUFNLGtCQUFrQixHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBZSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ25FLGlDQUFpQztZQUNqQyxNQUFNLGFBQWEsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLE1BQU0sQ0FBQztZQUMxRCxNQUFNLFdBQVcsR0FBRyxvQkFBb0Isa0JBQWtCLElBQUksYUFBYSxFQUFFLENBQUM7WUFFOUUsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN0QyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7WUFDekIsQ0FBQyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUM7WUFDYixDQUFDLENBQUMsUUFBUSxHQUFHLFdBQVcsQ0FBQztZQUN6QixRQUFRLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM3QixDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDVixRQUFRLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM3QixrRUFBa0U7WUFDbEUsc0NBQXNDO1NBQ3ZDO2FBQU07WUFDTCxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1NBQ3RFO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7S0FNQztJQUNPLFVBQVUsQ0FBQyxZQUFvQixDQUFDO1FBQ3RDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLDRCQUE0QjtRQUM5QyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsU0FBUyxDQUFDO1FBQ3JDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFFeEQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO2FBQ3BDLElBQUksQ0FDSCxHQUFHLENBQUMsR0FBRyxFQUFFO1lBQ1AsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxLQUFLLGNBQWMsQ0FBQyxTQUFTLEVBQUU7Z0JBQ2pFLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO2dCQUMzQixJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO2FBQ3pEO1FBQ0gsQ0FBQyxDQUFDLEVBQ0YsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLEtBQUssY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUMvRTthQUNBLFNBQVMsRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLFNBQVM7UUFDZixJQUFJLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtZQUMxQixJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDckMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztTQUMvQjtJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLHdCQUF3QjtRQUM5QixJQUFJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUU7WUFDakMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzFELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDcEM7UUFDRCxJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO1FBQzdCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ2YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN2RCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztTQUNwQjtRQUNELElBQUksSUFBSSxDQUFDLGFBQWEsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUMsdUJBQXVCLENBQUMsUUFBUSxFQUFFO1lBQzVGLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDM0I7UUFDRCxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztJQUM1QixDQUFDO0lBR0Q7Ozs7S0FJQztJQUNELFdBQVc7UUFDVCxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLDRCQUE0QjtJQUMxRCxDQUFDO0lBR0Q7Ozs7OztLQU1DO0lBQ08sV0FBVyxDQUFDLEtBQWE7UUFDL0IsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEMsQ0FBQzs7bUhBcFdVLHFCQUFxQjt1SEFBckIscUJBQXFCLGNBRnBCLE1BQU07NEZBRVAscUJBQXFCO2tCQUhqQyxVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNLEVBQUUseUNBQXlDO2lCQUM5RCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBTdWJqZWN0LCB0aW1lciB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyB0YWtlV2hpbGUsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgUmVjb3JkaW5nU3RhdGUgfSBmcm9tICcuLi9tb2RlbHMvc2NyZWVuLXJlY29yZGVyLm1vZGVscyc7XHJcbmltcG9ydCB7IFNjcmVlblJlY29yZGVyQ29uc3RhbnRzIH0gZnJvbSAnLi4vc2NyZWVuLXJlY29yZGVyL3NjcmVlbi1yZWNvcmRlci1jb25zdGFudCc7XHJcbkBJbmplY3RhYmxlKHtcclxuICBwcm92aWRlZEluOiAncm9vdCcsIC8vIE9yIHByb3ZpZGUgaW4geW91ciBtb2R1bGUgaWYgcHJlZmVycmVkXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBTY3JlZW5SZWNvcmRlclNlcnZpY2Uge1xyXG4gIHByaXZhdGUgc3RyZWFtOiBNZWRpYVN0cmVhbSB8IG51bGwgPSBudWxsO1xyXG4gIHByaXZhdGUgbWVkaWFSZWNvcmRlcjogTWVkaWFSZWNvcmRlciB8IG51bGwgPSBudWxsO1xyXG4gIHByaXZhdGUgcmVjb3JkZWRCbG9iczogQmxvYltdID0gW107XHJcbiAgcHJpdmF0ZSB0aW1lclN1YnNjcmlwdGlvbjogYW55O1xyXG4gIHByaXZhdGUgY3VycmVudFJlY29yZGVkVGltZTogbnVtYmVyID0gMDtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSByZWNvcmRpbmdTdGF0ZVN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFJlY29yZGluZ1N0YXRlPihSZWNvcmRpbmdTdGF0ZS5JZGxlKTtcclxuICByZWFkb25seSByZWNvcmRpbmdTdGF0ZSQ6IE9ic2VydmFibGU8UmVjb3JkaW5nU3RhdGU+ID0gdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QuYXNPYnNlcnZhYmxlKCk7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVjb3JkZWRUaW1lU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigwKTtcclxuICByZWFkb25seSByZWNvcmRlZFRpbWUkOiBPYnNlcnZhYmxlPG51bWJlcj4gPSB0aGlzLnJlY29yZGVkVGltZVN1YmplY3QuYXNPYnNlcnZhYmxlKCk7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVjb3JkZWRVcmxTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmcgfCBudWxsPihudWxsKTtcclxuICByZWFkb25seSByZWNvcmRlZFVybCQ6IE9ic2VydmFibGU8c3RyaW5nIHwgbnVsbD4gPSB0aGlzLnJlY29yZGVkVXJsU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSByZWNvcmRpbmdUaW1lc3RhbXBTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmc+KCcnKTtcclxuICByZWFkb25seSByZWNvcmRpbmdUaW1lc3RhbXAkOiBPYnNlcnZhYmxlPHN0cmluZz4gPSB0aGlzLnJlY29yZGluZ1RpbWVzdGFtcFN1YmplY3QuYXNPYnNlcnZhYmxlKCk7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgZXJyb3JTdWJqZWN0ID0gbmV3IFN1YmplY3Q8c3RyaW5nPigpO1xyXG4gIHJlYWRvbmx5IGVycm9yJDogT2JzZXJ2YWJsZTxzdHJpbmc+ID0gdGhpcy5lcnJvclN1YmplY3QuYXNPYnNlcnZhYmxlKCk7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyBzY3JlZW5SZWNvcmRpbmdDb25zdGFudDogU2NyZWVuUmVjb3JkZXJDb25zdGFudHMpIHsgfVxyXG5cclxuICAvKipcclxuICAgKiBTdGFydHMgdGhlIHNjcmVlbiByZWNvcmRpbmcgd2l0aCBvcHRpb25hbCBhdWRpb1xyXG4gICAqIFxyXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByZWNvcmRpbmdcclxuICAgKiBAcGFyYW0gb3B0aW9ucy5hdWRpbyAtIFdoZXRoZXIgdG8gaW5jbHVkZSBhdWRpbyBpbiB0aGUgcmVjb3JkaW5nXHJcbiAgICogXHJcbiAgICogQHRocm93cyBFcnJvciBpZiByZWNvcmRpbmcgaXMgYWxyZWFkeSBpbiBwcm9ncmVzcyBvciBpZiBtZWRpYSBhY2Nlc3MgaXMgZGVuaWVkXHJcbiAgICogQHJldHVybnMgUHJvbWlzZTx2b2lkPlxyXG4gICAqL1xyXG4gIGFzeW5jIHN0YXJ0UmVjb3JkaW5nKG9wdGlvbnM6IHsgYXVkaW86IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD4ge1xyXG5cclxuICAgIGlmICh0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC52YWx1ZSA9PT0gUmVjb3JkaW5nU3RhdGUuUmVjb3JkaW5nIHx8IHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5QYXVzZWQpIHtcclxuICAgICAgdGhpcy5oYW5kbGVFcnJvcih0aGlzLnNjcmVlblJlY29yZGluZ0NvbnN0YW50LlJFQ09SRElOR19JTl9QUk9HUkVTU19FUlJPUik7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmNsZWFudXBQcmV2aW91c1JlY29yZGluZygpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRoZSBicm93c2VyJ3MgbmF0aXZlIHBpY2tlciBoYW5kbGVzIFwic3BlY2lmaWMgYXJlYVwiIHNlbGVjdGlvbiAod2luZG93LCB0YWIsIHNjcmVlbikuXHJcbiAgICAgIGNvbnN0IGRpc3BsYXlTdHJlYW0gPSBhd2FpdCBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldERpc3BsYXlNZWRpYSh7XHJcbiAgICAgICAgdmlkZW86IHRydWVcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBJZiBhdWRpbyBpcyBlbmFibGVkLCBnZXQgdGhlIGF1ZGlvIHN0cmVhbVxyXG4gICAgICBsZXQgYXVkaW9TdHJlYW06IE1lZGlhU3RyZWFtIHwgbnVsbCA9IG51bGw7XHJcbiAgICAgIGlmIChvcHRpb25zLmF1ZGlvKSB7XHJcbiAgICAgICAgYXVkaW9TdHJlYW0gPSBhd2FpdCBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSh7XHJcbiAgICAgICAgICBhdWRpbzoge1xyXG4gICAgICAgICAgICBlY2hvQ2FuY2VsbGF0aW9uOiB0cnVlLFxyXG4gICAgICAgICAgICBub2lzZVN1cHByZXNzaW9uOiB0cnVlLFxyXG4gICAgICAgICAgICBzYW1wbGVSYXRlOiA0NDEwMFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDb21iaW5lIHRoZSBzdHJlYW1zIGlmIGF1ZGlvIGlzIGVuYWJsZWRcclxuICAgICAgaWYgKGF1ZGlvU3RyZWFtKSB7XHJcbiAgICAgICAgdGhpcy5zdHJlYW0gPSBuZXcgTWVkaWFTdHJlYW0oWy4uLmRpc3BsYXlTdHJlYW0uZ2V0VHJhY2tzKCksIC4uLmF1ZGlvU3RyZWFtLmdldFRyYWNrcygpXSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5zdHJlYW0gPSBkaXNwbGF5U3RyZWFtO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMaXN0ZW4gZm9yIHdoZW4gdGhlIHVzZXIgc3RvcHMgc2hhcmluZyB2aWEgYnJvd3NlciBVSVxyXG4gICAgICB0aGlzLnN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdLm9uZW5kZWQgPSAoKSA9PiB7XHJcbiAgICAgICAgaWYgKHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5SZWNvcmRpbmcgfHwgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QudmFsdWUgPT09IFJlY29yZGluZ1N0YXRlLlBhdXNlZCkge1xyXG4gICAgICAgICAgdGhpcy5zdG9wUmVjb3JkaW5nSW50ZXJuYWwoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBIYW5kbGUgZXJyb3JzXHJcbiAgICAgIGlmICghdGhpcy5zdHJlYW0pIHtcclxuICAgICAgICB0aGlzLmhhbmRsZUVycm9yKHRoaXMuc2NyZWVuUmVjb3JkaW5nQ29uc3RhbnQuRkFJTEVEX1RPX0dFVF9ESVNQTEFZX01FRElBX1NUUkVBTV9FUlJPUik7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBTZXQgcmVjb3JkaW5nIHRpbWVzdGFtcFxyXG4gICAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xyXG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSBub3cudG9Mb2NhbGVTdHJpbmcoJ2VuLUlOJywge1xyXG4gICAgICAgIHllYXI6ICdudW1lcmljJyxcclxuICAgICAgICBtb250aDogJzItZGlnaXQnLFxyXG4gICAgICAgIGRheTogJzItZGlnaXQnLFxyXG4gICAgICAgIGhvdXI6ICcyLWRpZ2l0JyxcclxuICAgICAgICBtaW51dGU6ICcyLWRpZ2l0JyxcclxuICAgICAgICBob3VyMTI6IHRydWVcclxuICAgICAgfSk7XHJcbiAgICAgIHRoaXMucmVjb3JkaW5nVGltZXN0YW1wU3ViamVjdC5uZXh0KHRpbWVzdGFtcCk7XHJcblxyXG5cclxuICAgICAgdGhpcy5yZWNvcmRlZEJsb2JzID0gW107XHJcbiAgICAgIGNvbnN0IG1pbWVUeXBlID0gdGhpcy5nZXRTdXBwb3J0ZWRNaW1lVHlwZSgpO1xyXG4gICAgICBpZiAoIW1pbWVUeXBlKSB7XHJcbiAgICAgICAgdGhpcy5oYW5kbGVFcnJvcih0aGlzLnNjcmVlblJlY29yZGluZ0NvbnN0YW50Lk5PX1NVUFBPUlRfTUlNRSk7XHJcbiAgICAgICAgdGhpcy5zdHJlYW0/LmdldFRyYWNrcygpLmZvckVhY2godHJhY2sgPT4gdHJhY2suc3RvcCgpKTtcclxuICAgICAgICB0aGlzLnN0cmVhbSA9IG51bGw7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBjYW52YXMgZm9yIHRpbWVzdGFtcCBvdmVybGF5XHJcbiAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xyXG4gICAgICBjb25zdCB2aWRlb1RyYWNrID0gdGhpcy5zdHJlYW0/LmdldFZpZGVvVHJhY2tzKClbMF07XHJcbiAgICAgIGlmICh2aWRlb1RyYWNrKSB7XHJcbiAgICAgICAgY29uc3QgdmlkZW8gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd2aWRlbycpO1xyXG4gICAgICAgIHZpZGVvLnNyY09iamVjdCA9IHRoaXMuc3RyZWFtO1xyXG5cclxuICAgICAgICAvLyBXYWl0IGZvciB2aWRlbyB0byBsb2FkIG1ldGFkYXRhXHJcbiAgICAgICAgdmlkZW8ub25sb2FkZWRtZXRhZGF0YSA9ICgpID0+IHtcclxuICAgICAgICAgIGNhbnZhcy53aWR0aCA9IHZpZGVvLnZpZGVvV2lkdGg7XHJcbiAgICAgICAgICBjYW52YXMuaGVpZ2h0ID0gdmlkZW8udmlkZW9IZWlnaHQ7XHJcbiAgICAgICAgICBjb25zdCBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcclxuICAgICAgICAgIGlmIChjdHgpIHtcclxuICAgICAgICAgICAgLy8gRHJhdyB2aWRlbyBmcmFtZVxyXG4gICAgICAgICAgICBjdHguZHJhd0ltYWdlKHZpZGVvLCAwLCAwKTtcclxuXHJcbiAgICAgICAgICAgIC8vIERyYXcgdGltZXN0YW1wXHJcbiAgICAgICAgICAgIGN0eC5mb250ID0gJzE2cHggQXJpYWwnO1xyXG4gICAgICAgICAgICBjdHguZmlsbFN0eWxlID0gJ3doaXRlJztcclxuICAgICAgICAgICAgY3R4LnRleHRBbGlnbiA9ICdyaWdodCc7XHJcbiAgICAgICAgICAgIGN0eC50ZXh0QmFzZWxpbmUgPSAndG9wJztcclxuICAgICAgICAgICAgY3R4LmZpbGxUZXh0KGBSZWNvcmRlZCBvbjogJHt0aGlzLnJlY29yZGluZ1RpbWVzdGFtcFN1YmplY3QudmFsdWV9YCwgY2FudmFzLndpZHRoIC0gMTAsIDEwKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBuZXcgc3RyZWFtIHdpdGggdGhlIGNhbnZhc1xyXG4gICAgICBjb25zdCBjYW52YXNTdHJlYW0gPSBjYW52YXMuY2FwdHVyZVN0cmVhbSgpO1xyXG4gICAgICBjb25zdCBjb21iaW5lZFN0cmVhbSA9IG5ldyBNZWRpYVN0cmVhbShbLi4udGhpcy5zdHJlYW0/LmdldFRyYWNrcygpID8/IFtdLCBjYW52YXNTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKVswXV0pO1xyXG5cclxuICAgICAgdGhpcy5tZWRpYVJlY29yZGVyID0gbmV3IE1lZGlhUmVjb3JkZXIoY29tYmluZWRTdHJlYW0sIHsgbWltZVR5cGUgfSk7XHJcblxyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIub25kYXRhYXZhaWxhYmxlID0gKGV2ZW50KSA9PiB7XHJcbiAgICAgICAgaWYgKGV2ZW50LmRhdGEgJiYgZXZlbnQuZGF0YS5zaXplID4gMCkge1xyXG4gICAgICAgICAgdGhpcy5yZWNvcmRlZEJsb2JzLnB1c2goZXZlbnQuZGF0YSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdGhpcy5tZWRpYVJlY29yZGVyLm9uc3RvcCA9ICgpID0+IHtcclxuICAgICAgICBjb25zdCBzdXBlckJ1ZmZlciA9IG5ldyBCbG9iKHRoaXMucmVjb3JkZWRCbG9icywgeyB0eXBlOiBtaW1lVHlwZSB9KTtcclxuICAgICAgICBjb25zdCB1cmwgPSB3aW5kb3cuVVJMLmNyZWF0ZU9iamVjdFVSTChzdXBlckJ1ZmZlcik7XHJcbiAgICAgICAgdGhpcy5yZWNvcmRlZFVybFN1YmplY3QubmV4dCh1cmwpO1xyXG4gICAgICAgIHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0Lm5leHQoUmVjb3JkaW5nU3RhdGUuU3RvcHBlZCk7XHJcbiAgICAgICAgdGhpcy5zdG9wVGltZXIoKTtcclxuXHJcbiAgICAgIH07XHJcblxyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIub25lcnJvciA9IChldmVudDogRXZlbnQpID0+IHtcclxuICAgICAgICBjb25zdCBlcnJvckV2ZW50ID0gZXZlbnQgYXMgRXJyb3JFdmVudDsgLy8gTW9yZSBzcGVjaWZpYyB0eXBlIGlmIGF2YWlsYWJsZVxyXG4gICAgICAgIGxldCBtZXNzYWdlID0gdGhpcy5zY3JlZW5SZWNvcmRpbmdDb25zdGFudC5NRURJQV9FUlJPUjtcclxuICAgICAgICBpZiAoZXJyb3JFdmVudC5lcnJvciAmJiBlcnJvckV2ZW50LmVycm9yLm5hbWUpIHtcclxuICAgICAgICAgIG1lc3NhZ2UgKz0gYDogJHtlcnJvckV2ZW50LmVycm9yLm5hbWV9YDtcclxuICAgICAgICAgIGlmIChlcnJvckV2ZW50LmVycm9yLm1lc3NhZ2UpIG1lc3NhZ2UgKz0gYCAtICR7ZXJyb3JFdmVudC5lcnJvci5tZXNzYWdlfWA7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuaGFuZGxlRXJyb3IobWVzc2FnZSk7XHJcbiAgICAgICAgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QubmV4dChSZWNvcmRpbmdTdGF0ZS5JZGxlKTtcclxuICAgICAgICB0aGlzLnN0b3BUaW1lcigpO1xyXG4gICAgICB9O1xyXG5cclxuICAgICAgdGhpcy5tZWRpYVJlY29yZGVyLnN0YXJ0KCk7IC8vIFN0YXJ0IHJlY29yZGluZ1xyXG4gICAgICB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC5uZXh0KFJlY29yZGluZ1N0YXRlLlJlY29yZGluZyk7XHJcbiAgICAgIHRoaXMuc3RhcnRUaW1lcigpO1xyXG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcclxuICAgICAgdGhpcy5oYW5kbGVFcnJvcihgRXJyb3Igc3RhcnRpbmcgc2NyZWVuIHJlY29yZGluZzogJHtlcnIubmFtZX0gLSAke2Vyci5tZXNzYWdlfWApO1xyXG4gICAgICB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC5uZXh0KFJlY29yZGluZ1N0YXRlLklkbGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAqIEdldHMgdGhlIGZpcnN0IHN1cHBvcnRlZCBNSU1FIHR5cGUgZm9yIE1lZGlhUmVjb3JkZXJcclxuICogXHJcbiAqIEByZXR1cm5zIHN0cmluZ3xudWxsIC0gVGhlIHN1cHBvcnRlZCBNSU1FIHR5cGUgb3IgbnVsbCBpZiBub25lIGZvdW5kXHJcbiAqL1xyXG4gIHByaXZhdGUgZ2V0U3VwcG9ydGVkTWltZVR5cGUoKTogc3RyaW5nIHwgbnVsbCB7XHJcbiAgICBjb25zdCBtaW1lVHlwZXMgPSBbXHJcbiAgICAgICd2aWRlby93ZWJtO2NvZGVjcz12cDksb3B1cycsXHJcbiAgICAgICd2aWRlby93ZWJtO2NvZGVjcz12cDgsb3B1cycsXHJcbiAgICAgICd2aWRlby93ZWJtO2NvZGVjcz1oMjY0LG9wdXMnLFxyXG4gICAgICAndmlkZW8vbXA0O2NvZGVjcz1oMjY0LGFhYycsIC8vIE1QNCBtaWdodCBoYXZlIGJyb2FkZXIgY29tcGF0aWJpbGl0eSBidXQgbGVzcyBicm93c2VyIHN1cHBvcnQgZm9yIHJlY29yZGluZ1xyXG4gICAgICAndmlkZW8vd2VibScsXHJcbiAgICBdO1xyXG4gICAgZm9yIChjb25zdCBtaW1lVHlwZSBvZiBtaW1lVHlwZXMpIHtcclxuICAgICAgaWYgKE1lZGlhUmVjb3JkZXIuaXNUeXBlU3VwcG9ydGVkKG1pbWVUeXBlKSkge1xyXG4gICAgICAgIHJldHVybiBtaW1lVHlwZTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBJbnRlcm5hbCBtZXRob2QgdG8gc3RvcCB0aGUgcmVjb3JkaW5nIHByb2Nlc3NcclxuICAgKiBcclxuICAgKiBAcHJpdmF0ZVxyXG4gICAqIEByZXR1cm5zIHZvaWRcclxuICAgKi9cclxuICBwcml2YXRlIHN0b3BSZWNvcmRpbmdJbnRlcm5hbCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLm1lZGlhUmVjb3JkZXIgJiYgKHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5SZWNvcmRpbmcgfHwgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QudmFsdWUgPT09IFJlY29yZGluZ1N0YXRlLlBhdXNlZCkpIHtcclxuICAgICAgdGhpcy5tZWRpYVJlY29yZGVyLnN0b3AoKTtcclxuICAgIH1cclxuICAgIHRoaXMuc3RyZWFtPy5nZXRUcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IHRyYWNrLnN0b3AoKSk7XHJcbiAgICB0aGlzLnN0cmVhbSA9IG51bGw7XHJcbiAgICAvLyBTdGF0ZSB3aWxsIGJlIHVwZGF0ZWQgYnkgb25zdG9wIGhhbmRsZXJcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIFByb21pc2U8dm9pZD5cclxuICAgKiBAdGhyb3dzIEVycm9yIGlmIHJlY29yZGluZyBpcyBub3QgaW4gcHJvZ3Jlc3NcclxuICAgKi9cclxuICBzdG9wUmVjb3JkaW5nKCk6IHZvaWQge1xyXG4gICAgdGhpcy5zdG9wUmVjb3JkaW5nSW50ZXJuYWwoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFBhdXNlcyB0aGUgY3VycmVudCByZWNvcmRpbmdcclxuICAgKiBcclxuICAgKiBAcmV0dXJucyBQcm9taXNlPHZvaWQ+XHJcbiAgICogQHRocm93cyBFcnJvciBpZiByZWNvcmRpbmcgaXMgbm90IGluIHByb2dyZXNzXHJcbiAgICovXHJcbiAgcGF1c2VSZWNvcmRpbmcoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5tZWRpYVJlY29yZGVyICYmIHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5SZWNvcmRpbmcpIHtcclxuICAgICAgdGhpcy5tZWRpYVJlY29yZGVyLnBhdXNlKCk7XHJcbiAgICAgIHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0Lm5leHQoUmVjb3JkaW5nU3RhdGUuUGF1c2VkKTtcclxuICAgICAgdGhpcy5zdG9wVGltZXIoKTsgLy8gUGF1c2VzIHRoZSB0aW1lciBkaXNwbGF5XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZXN1bWVzIGEgcGF1c2VkIHJlY29yZGluZ1xyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIFByb21pc2U8dm9pZD5cclxuICAgKiBAdGhyb3dzIEVycm9yIGlmIHJlY29yZGluZyBpcyBub3QgcGF1c2VkXHJcbiAgICovXHJcbiAgcmVzdW1lUmVjb3JkaW5nKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMubWVkaWFSZWNvcmRlciAmJiB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC52YWx1ZSA9PT0gUmVjb3JkaW5nU3RhdGUuUGF1c2VkKSB7XHJcbiAgICAgIHRoaXMubWVkaWFSZWNvcmRlci5yZXN1bWUoKTtcclxuICAgICAgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QubmV4dChSZWNvcmRpbmdTdGF0ZS5SZWNvcmRpbmcpO1xyXG4gICAgICB0aGlzLnN0YXJ0VGltZXIodGhpcy5jdXJyZW50UmVjb3JkZWRUaW1lKTsgLy8gUmVzdW1lcyB0aW1lciBkaXNwbGF5XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBcclxuICAgKiBAcGFyYW0gZmlsZU5hbWUgXHJcbiAgICovXHJcbiAgZG93bmxvYWRSZWNvcmRpbmcoZmlsZU5hbWU6IHN0cmluZyA9ICdyZWNvcmRpbmcud2VibScpOiB2b2lkIHtcclxuICAgIGNvbnN0IHVybCA9IHRoaXMucmVjb3JkZWRVcmxTdWJqZWN0LnZhbHVlO1xyXG4gICAgY29uc3QgdGltZXN0YW1wID0gdGhpcy5yZWNvcmRpbmdUaW1lc3RhbXBTdWJqZWN0LnZhbHVlO1xyXG5cclxuICAgIGlmICh1cmwgJiYgdGltZXN0YW1wKSB7XHJcbiAgICAgIC8vIEZvcm1hdCB0aGUgdGltZXN0YW1wIGZvciBmaWxlbmFtZSAocmVtb3ZlIHNwYWNlcyBhbmQgc3BlY2lhbCBjaGFyYWN0ZXJzKVxyXG4gICAgICBjb25zdCBmb3JtYXR0ZWRUaW1lc3RhbXAgPSB0aW1lc3RhbXAucmVwbGFjZSgvW15hLXpBLVowLTldL2csICdfJyk7XHJcbiAgICAgIC8vIENyZWF0ZSBmaWxlbmFtZSB3aXRoIHRpbWVzdGFtcFxyXG4gICAgICBjb25zdCBmaWxlRXh0ZW5zaW9uID0gZmlsZU5hbWUuc3BsaXQoJy4nKS5wb3AoKSB8fCAnd2VibSc7XHJcbiAgICAgIGNvbnN0IG5ld0ZpbGVOYW1lID0gYHNjcmVlbl9yZWNvcmRpbmdfJHtmb3JtYXR0ZWRUaW1lc3RhbXB9LiR7ZmlsZUV4dGVuc2lvbn1gO1xyXG5cclxuICAgICAgY29uc3QgYSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTtcclxuICAgICAgYS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgICBhLmhyZWYgPSB1cmw7XHJcbiAgICAgIGEuZG93bmxvYWQgPSBuZXdGaWxlTmFtZTtcclxuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChhKTtcclxuICAgICAgYS5jbGljaygpO1xyXG4gICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGEpO1xyXG4gICAgICAvLyBObyBuZWVkIHRvIHJldm9rZSBVUkwgaGVyZSBpZiB1c2VyIG1pZ2h0IHdhbnQgdG8gcGxheSBpdCBhZ2Fpbi5cclxuICAgICAgLy8gUmV2b2tlIG9uIGNsZWFudXAgb3IgbmV3IHJlY29yZGluZy5cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuaGFuZGxlRXJyb3IodGhpcy5zY3JlZW5SZWNvcmRpbmdDb25zdGFudC5OT19SRUNPUkRJTkdfRE9XTkxPQUQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAqIFN0YXJ0cyB0aGUgcmVjb3JkaW5nIHRpbWVyXHJcbiAqIFxyXG4gKiBAcGFyYW0gc3RhcnRUaW1lIC0gT3B0aW9uYWwgc3RhcnQgdGltZSBmb3IgdGhlIHRpbWVyXHJcbiAqIEBwcml2YXRlXHJcbiAqIEByZXR1cm5zIHZvaWRcclxuICovXHJcbiAgcHJpdmF0ZSBzdGFydFRpbWVyKHN0YXJ0VGltZTogbnVtYmVyID0gMCk6IHZvaWQge1xyXG4gICAgdGhpcy5zdG9wVGltZXIoKTsgLy8gRW5zdXJlIG5vIG11bHRpcGxlIHRpbWVyc1xyXG4gICAgdGhpcy5jdXJyZW50UmVjb3JkZWRUaW1lID0gc3RhcnRUaW1lO1xyXG4gICAgdGhpcy5yZWNvcmRlZFRpbWVTdWJqZWN0Lm5leHQodGhpcy5jdXJyZW50UmVjb3JkZWRUaW1lKTtcclxuXHJcbiAgICB0aGlzLnRpbWVyU3Vic2NyaXB0aW9uID0gdGltZXIoMCwgMTAwMClcclxuICAgICAgLnBpcGUoXHJcbiAgICAgICAgdGFwKCgpID0+IHtcclxuICAgICAgICAgIGlmICh0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC52YWx1ZSA9PT0gUmVjb3JkaW5nU3RhdGUuUmVjb3JkaW5nKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFJlY29yZGVkVGltZSsrO1xyXG4gICAgICAgICAgICB0aGlzLnJlY29yZGVkVGltZVN1YmplY3QubmV4dCh0aGlzLmN1cnJlbnRSZWNvcmRlZFRpbWUpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pLFxyXG4gICAgICAgIHRha2VXaGlsZSgoKSA9PiB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC52YWx1ZSA9PT0gUmVjb3JkaW5nU3RhdGUuUmVjb3JkaW5nKVxyXG4gICAgICApXHJcbiAgICAgIC5zdWJzY3JpYmUoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFN0b3BzIHRoZSByZWNvcmRpbmcgdGltZXJcclxuICAgKiBcclxuICAgKiBAcHJpdmF0ZVxyXG4gICAqIEByZXR1cm5zIHZvaWRcclxuICAgKi9cclxuICBwcml2YXRlIHN0b3BUaW1lcigpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnRpbWVyU3Vic2NyaXB0aW9uKSB7XHJcbiAgICAgIHRoaXMudGltZXJTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcclxuICAgICAgdGhpcy50aW1lclN1YnNjcmlwdGlvbiA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDbGVhbnMgdXAgcmVzb3VyY2VzIGZyb20gcHJldmlvdXMgcmVjb3JkaW5nXHJcbiAgICogXHJcbiAgICogQHByaXZhdGVcclxuICAgKiBAcmV0dXJucyB2b2lkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjbGVhbnVwUHJldmlvdXNSZWNvcmRpbmcoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5yZWNvcmRlZFVybFN1YmplY3QudmFsdWUpIHtcclxuICAgICAgd2luZG93LlVSTC5yZXZva2VPYmplY3RVUkwodGhpcy5yZWNvcmRlZFVybFN1YmplY3QudmFsdWUpO1xyXG4gICAgICB0aGlzLnJlY29yZGVkVXJsU3ViamVjdC5uZXh0KG51bGwpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5yZWNvcmRlZEJsb2JzID0gW107XHJcbiAgICB0aGlzLmN1cnJlbnRSZWNvcmRlZFRpbWUgPSAwO1xyXG4gICAgdGhpcy5yZWNvcmRlZFRpbWVTdWJqZWN0Lm5leHQoMCk7XHJcbiAgICBpZiAodGhpcy5zdHJlYW0pIHtcclxuICAgICAgdGhpcy5zdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaCh0cmFjayA9PiB0cmFjay5zdG9wKCkpO1xyXG4gICAgICB0aGlzLnN0cmVhbSA9IG51bGw7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5tZWRpYVJlY29yZGVyICYmIHRoaXMubWVkaWFSZWNvcmRlci5zdGF0ZSAhPT0gdGhpcy5zY3JlZW5SZWNvcmRpbmdDb25zdGFudC5JTkFDVElWRSkge1xyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIuc3RvcCgpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5tZWRpYVJlY29yZGVyID0gbnVsbDtcclxuICB9XHJcblxyXG5cclxuICAvKipcclxuICogUmVzZXRzIHRoZSByZWNvcmRpbmcgc3RhdGUgdG8gaWRsZVxyXG4gKiBcclxuICogQHJldHVybnMgdm9pZFxyXG4gKi9cclxuICByZXNldFRvSWRsZSgpOiB2b2lkIHtcclxuICAgIHRoaXMuY2xlYW51cFByZXZpb3VzUmVjb3JkaW5nKCk7XHJcbiAgICB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC5uZXh0KFJlY29yZGluZ1N0YXRlLklkbGUpO1xyXG4gICAgdGhpcy5lcnJvclN1YmplY3QubmV4dCgnJyk7IC8vIENsZWFyIGFueSBwcmV2aW91cyBlcnJvcnNcclxuICB9XHJcblxyXG5cclxuICAvKipcclxuICogSGFuZGxlcyBhbmQgYnJvYWRjYXN0cyByZWNvcmRpbmcgZXJyb3JzXHJcbiAqIFxyXG4gKiBAcHJpdmF0ZVxyXG4gKiBAcGFyYW0gZXJyb3IgLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBoYW5kbGVcclxuICogQHJldHVybnMgdm9pZFxyXG4gKi9cclxuICBwcml2YXRlIGhhbmRsZUVycm9yKGVycm9yOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuZXJyb3JTdWJqZWN0Lm5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iXX0=
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVjLWxpYi1zY3JlZW4tcmVjb3JkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL3J1Y2xpYi9zY3JlZW4tcmVjb3JkZXIvc3JjL3J1Yy1saWItc2NyZWVuLXJlY29yZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVjbGliLXNjcmVlbi1yZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2xpYnMvcnVjbGliL3NjcmVlbi1yZWNvcmRlci9zcmMvcnVjbGliLXNjcmVlbi1yZWNvcmRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ==