@ruc-lib/screen-recorder 3.1.0 → 3.2.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyZWVuLXJlY29yZGVyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL3NjcmVlbi1yZWNvcmRlci5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLGVBQWUsRUFBYyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ25FLE9BQU8sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDOzs7QUFJdEYsTUFBTSxPQUFPLHFCQUFxQjtJQXNCaEMsWUFBbUIsdUJBQWdEO1FBQWhELDRCQUF1QixHQUF2Qix1QkFBdUIsQ0FBeUI7UUFyQjNELFdBQU0sR0FBdUIsSUFBSSxDQUFDO1FBQ2xDLGtCQUFhLEdBQXlCLElBQUksQ0FBQztRQUMzQyxrQkFBYSxHQUFXLEVBQUUsQ0FBQztRQUUzQix3QkFBbUIsR0FBVyxDQUFDLENBQUM7UUFFdkIsMEJBQXFCLEdBQUcsSUFBSSxlQUFlLENBQWlCLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN6RixvQkFBZSxHQUErQixJQUFJLENBQUMscUJBQXFCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFaEYsd0JBQW1CLEdBQUcsSUFBSSxlQUFlLENBQVMsQ0FBQyxDQUFDLENBQUM7UUFDN0Qsa0JBQWEsR0FBdUIsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXBFLHVCQUFrQixHQUFHLElBQUksZUFBZSxDQUFnQixJQUFJLENBQUMsQ0FBQztRQUN0RSxpQkFBWSxHQUE4QixJQUFJLENBQUMsa0JBQWtCLENBQUMsWUFBWSxF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QWEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztTQUMzQjtRQUNELElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDO0lBQzVCLENBQUM7SUFHRDs7OztLQUlDO0lBQ0QsV0FBVztRQUNULElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsNEJBQTRCO0lBQzFELENBQUM7SUFHRDs7Ozs7O0tBTUM7SUFDTyxXQUFXLENBQUMsS0FBYTtRQUMvQixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNoQyxDQUFDOzttSEFwV1UscUJBQXFCO3VIQUFyQixxQkFBcUIsY0FGcEIsTUFBTTs0RkFFUCxxQkFBcUI7a0JBSGpDLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU0sRUFBRSx5Q0FBeUM7aUJBQzlEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIFN1YmplY3QsIHRpbWVyIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IHRha2VXaGlsZSwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBSZWNvcmRpbmdTdGF0ZSB9IGZyb20gJy4uL21vZGVscy9zY3JlZW4tcmVjb3JkZXIubW9kZWxzJztcclxuaW1wb3J0IHsgU2NyZWVuUmVjb3JkZXJDb25zdGFudHMgfSBmcm9tICcuLi9zY3JlZW4tcmVjb3JkZXIvc2NyZWVuLXJlY29yZGVyLWNvbnN0YW50JztcclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290JywgLy8gT3IgcHJvdmlkZSBpbiB5b3VyIG1vZHVsZSBpZiBwcmVmZXJyZWRcclxufSlcclxuZXhwb3J0IGNsYXNzIFNjcmVlblJlY29yZGVyU2VydmljZSB7XHJcbiAgcHJpdmF0ZSBzdHJlYW06IE1lZGlhU3RyZWFtIHwgbnVsbCA9IG51bGw7XHJcbiAgcHJpdmF0ZSBtZWRpYVJlY29yZGVyOiBNZWRpYVJlY29yZGVyIHwgbnVsbCA9IG51bGw7XHJcbiAgcHJpdmF0ZSByZWNvcmRlZEJsb2JzOiBCbG9iW10gPSBbXTtcclxuICBwcml2YXRlIHRpbWVyU3Vic2NyaXB0aW9uOiBhbnk7XHJcbiAgcHJpdmF0ZSBjdXJyZW50UmVjb3JkZWRUaW1lOiBudW1iZXIgPSAwO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IHJlY29yZGluZ1N0YXRlU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8UmVjb3JkaW5nU3RhdGU+KFJlY29yZGluZ1N0YXRlLklkbGUpO1xyXG4gIHJlYWRvbmx5IHJlY29yZGluZ1N0YXRlJDogT2JzZXJ2YWJsZTxSZWNvcmRpbmdTdGF0ZT4gPSB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSByZWNvcmRlZFRpbWVTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KDApO1xyXG4gIHJlYWRvbmx5IHJlY29yZGVkVGltZSQ6IE9ic2VydmFibGU8bnVtYmVyPiA9IHRoaXMucmVjb3JkZWRUaW1lU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSByZWNvcmRlZFVybFN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZyB8IG51bGw+KG51bGwpO1xyXG4gIHJlYWRvbmx5IHJlY29yZGVkVXJsJDogT2JzZXJ2YWJsZTxzdHJpbmcgfCBudWxsPiA9IHRoaXMucmVjb3JkZWRVcmxTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IHJlY29yZGluZ1RpbWVzdGFtcFN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpO1xyXG4gIHJlYWRvbmx5IHJlY29yZGluZ1RpbWVzdGFtcCQ6IE9ic2VydmFibGU8c3RyaW5nPiA9IHRoaXMucmVjb3JkaW5nVGltZXN0YW1wU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBlcnJvclN1YmplY3QgPSBuZXcgU3ViamVjdDxzdHJpbmc+KCk7XHJcbiAgcmVhZG9ubHkgZXJyb3IkOiBPYnNlcnZhYmxlPHN0cmluZz4gPSB0aGlzLmVycm9yU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgY29uc3RydWN0b3IocHVibGljIHNjcmVlblJlY29yZGluZ0NvbnN0YW50OiBTY3JlZW5SZWNvcmRlckNvbnN0YW50cykgeyB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFN0YXJ0cyB0aGUgc2NyZWVuIHJlY29yZGluZyB3aXRoIG9wdGlvbmFsIGF1ZGlvXHJcbiAgICogXHJcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJlY29yZGluZ1xyXG4gICAqIEBwYXJhbSBvcHRpb25zLmF1ZGlvIC0gV2hldGhlciB0byBpbmNsdWRlIGF1ZGlvIGluIHRoZSByZWNvcmRpbmdcclxuICAgKiBcclxuICAgKiBAdGhyb3dzIEVycm9yIGlmIHJlY29yZGluZyBpcyBhbHJlYWR5IGluIHByb2dyZXNzIG9yIGlmIG1lZGlhIGFjY2VzcyBpcyBkZW5pZWRcclxuICAgKiBAcmV0dXJucyBQcm9taXNlPHZvaWQ+XHJcbiAgICovXHJcbiAgYXN5bmMgc3RhcnRSZWNvcmRpbmcob3B0aW9uczogeyBhdWRpbzogYm9vbGVhbiB9KTogUHJvbWlzZTx2b2lkPiB7XHJcblxyXG4gICAgaWYgKHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5SZWNvcmRpbmcgfHwgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QudmFsdWUgPT09IFJlY29yZGluZ1N0YXRlLlBhdXNlZCkge1xyXG4gICAgICB0aGlzLmhhbmRsZUVycm9yKHRoaXMuc2NyZWVuUmVjb3JkaW5nQ29uc3RhbnQuUkVDT1JESU5HX0lOX1BST0dSRVNTX0VSUk9SKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuY2xlYW51cFByZXZpb3VzUmVjb3JkaW5nKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVGhlIGJyb3dzZXIncyBuYXRpdmUgcGlja2VyIGhhbmRsZXMgXCJzcGVjaWZpYyBhcmVhXCIgc2VsZWN0aW9uICh3aW5kb3csIHRhYiwgc2NyZWVuKS5cclxuICAgICAgY29uc3QgZGlzcGxheVN0cmVhbSA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0RGlzcGxheU1lZGlhKHtcclxuICAgICAgICB2aWRlbzogdHJ1ZVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIElmIGF1ZGlvIGlzIGVuYWJsZWQsIGdldCB0aGUgYXVkaW8gc3RyZWFtXHJcbiAgICAgIGxldCBhdWRpb1N0cmVhbTogTWVkaWFTdHJlYW0gfCBudWxsID0gbnVsbDtcclxuICAgICAgaWYgKG9wdGlvbnMuYXVkaW8pIHtcclxuICAgICAgICBhdWRpb1N0cmVhbSA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKHtcclxuICAgICAgICAgIGF1ZGlvOiB7XHJcbiAgICAgICAgICAgIGVjaG9DYW5jZWxsYXRpb246IHRydWUsXHJcbiAgICAgICAgICAgIG5vaXNlU3VwcHJlc3Npb246IHRydWUsXHJcbiAgICAgICAgICAgIHNhbXBsZVJhdGU6IDQ0MTAwXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbWJpbmUgdGhlIHN0cmVhbXMgaWYgYXVkaW8gaXMgZW5hYmxlZFxyXG4gICAgICBpZiAoYXVkaW9TdHJlYW0pIHtcclxuICAgICAgICB0aGlzLnN0cmVhbSA9IG5ldyBNZWRpYVN0cmVhbShbLi4uZGlzcGxheVN0cmVhbS5nZXRUcmFja3MoKSwgLi4uYXVkaW9TdHJlYW0uZ2V0VHJhY2tzKCldKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLnN0cmVhbSA9IGRpc3BsYXlTdHJlYW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIExpc3RlbiBmb3Igd2hlbiB0aGUgdXNlciBzdG9wcyBzaGFyaW5nIHZpYSBicm93c2VyIFVJXHJcbiAgICAgIHRoaXMuc3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0ub25lbmRlZCA9ICgpID0+IHtcclxuICAgICAgICBpZiAodGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QudmFsdWUgPT09IFJlY29yZGluZ1N0YXRlLlJlY29yZGluZyB8fCB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC52YWx1ZSA9PT0gUmVjb3JkaW5nU3RhdGUuUGF1c2VkKSB7XHJcbiAgICAgICAgICB0aGlzLnN0b3BSZWNvcmRpbmdJbnRlcm5hbCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfTtcclxuXHJcbiAgICAgIC8vIEhhbmRsZSBlcnJvcnNcclxuICAgICAgaWYgKCF0aGlzLnN0cmVhbSkge1xyXG4gICAgICAgIHRoaXMuaGFuZGxlRXJyb3IodGhpcy5zY3JlZW5SZWNvcmRpbmdDb25zdGFudC5GQUlMRURfVE9fR0VUX0RJU1BMQVlfTUVESUFfU1RSRUFNX0VSUk9SKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFNldCByZWNvcmRpbmcgdGltZXN0YW1wXHJcbiAgICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XHJcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IG5vdy50b0xvY2FsZVN0cmluZygnZW4tSU4nLCB7XHJcbiAgICAgICAgeWVhcjogJ251bWVyaWMnLFxyXG4gICAgICAgIG1vbnRoOiAnMi1kaWdpdCcsXHJcbiAgICAgICAgZGF5OiAnMi1kaWdpdCcsXHJcbiAgICAgICAgaG91cjogJzItZGlnaXQnLFxyXG4gICAgICAgIG1pbnV0ZTogJzItZGlnaXQnLFxyXG4gICAgICAgIGhvdXIxMjogdHJ1ZVxyXG4gICAgICB9KTtcclxuICAgICAgdGhpcy5yZWNvcmRpbmdUaW1lc3RhbXBTdWJqZWN0Lm5leHQodGltZXN0YW1wKTtcclxuXHJcblxyXG4gICAgICB0aGlzLnJlY29yZGVkQmxvYnMgPSBbXTtcclxuICAgICAgY29uc3QgbWltZVR5cGUgPSB0aGlzLmdldFN1cHBvcnRlZE1pbWVUeXBlKCk7XHJcbiAgICAgIGlmICghbWltZVR5cGUpIHtcclxuICAgICAgICB0aGlzLmhhbmRsZUVycm9yKHRoaXMuc2NyZWVuUmVjb3JkaW5nQ29uc3RhbnQuTk9fU1VQUE9SVF9NSU1FKTtcclxuICAgICAgICB0aGlzLnN0cmVhbT8uZ2V0VHJhY2tzKCkuZm9yRWFjaCh0cmFjayA9PiB0cmFjay5zdG9wKCkpO1xyXG4gICAgICAgIHRoaXMuc3RyZWFtID0gbnVsbDtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENyZWF0ZSBhIGNhbnZhcyBmb3IgdGltZXN0YW1wIG92ZXJsYXlcclxuICAgICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XHJcbiAgICAgIGNvbnN0IHZpZGVvVHJhY2sgPSB0aGlzLnN0cmVhbT8uZ2V0VmlkZW9UcmFja3MoKVswXTtcclxuICAgICAgaWYgKHZpZGVvVHJhY2spIHtcclxuICAgICAgICBjb25zdCB2aWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3ZpZGVvJyk7XHJcbiAgICAgICAgdmlkZW8uc3JjT2JqZWN0ID0gdGhpcy5zdHJlYW07XHJcblxyXG4gICAgICAgIC8vIFdhaXQgZm9yIHZpZGVvIHRvIGxvYWQgbWV0YWRhdGFcclxuICAgICAgICB2aWRlby5vbmxvYWRlZG1ldGFkYXRhID0gKCkgPT4ge1xyXG4gICAgICAgICAgY2FudmFzLndpZHRoID0gdmlkZW8udmlkZW9XaWR0aDtcclxuICAgICAgICAgIGNhbnZhcy5oZWlnaHQgPSB2aWRlby52aWRlb0hlaWdodDtcclxuICAgICAgICAgIGNvbnN0IGN0eCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xyXG4gICAgICAgICAgaWYgKGN0eCkge1xyXG4gICAgICAgICAgICAvLyBEcmF3IHZpZGVvIGZyYW1lXHJcbiAgICAgICAgICAgIGN0eC5kcmF3SW1hZ2UodmlkZW8sIDAsIDApO1xyXG5cclxuICAgICAgICAgICAgLy8gRHJhdyB0aW1lc3RhbXBcclxuICAgICAgICAgICAgY3R4LmZvbnQgPSAnMTZweCBBcmlhbCc7XHJcbiAgICAgICAgICAgIGN0eC5maWxsU3R5bGUgPSAnd2hpdGUnO1xyXG4gICAgICAgICAgICBjdHgudGV4dEFsaWduID0gJ3JpZ2h0JztcclxuICAgICAgICAgICAgY3R4LnRleHRCYXNlbGluZSA9ICd0b3AnO1xyXG4gICAgICAgICAgICBjdHguZmlsbFRleHQoYFJlY29yZGVkIG9uOiAke3RoaXMucmVjb3JkaW5nVGltZXN0YW1wU3ViamVjdC52YWx1ZX1gLCBjYW52YXMud2lkdGggLSAxMCwgMTApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENyZWF0ZSBhIG5ldyBzdHJlYW0gd2l0aCB0aGUgY2FudmFzXHJcbiAgICAgIGNvbnN0IGNhbnZhc1N0cmVhbSA9IGNhbnZhcy5jYXB0dXJlU3RyZWFtKCk7XHJcbiAgICAgIGNvbnN0IGNvbWJpbmVkU3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKFsuLi50aGlzLnN0cmVhbT8uZ2V0VHJhY2tzKCkgPz8gW10sIGNhbnZhc1N0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdXSk7XHJcblxyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIgPSBuZXcgTWVkaWFSZWNvcmRlcihjb21iaW5lZFN0cmVhbSwgeyBtaW1lVHlwZSB9KTtcclxuXHJcbiAgICAgIHRoaXMubWVkaWFSZWNvcmRlci5vbmRhdGFhdmFpbGFibGUgPSAoZXZlbnQpID0+IHtcclxuICAgICAgICBpZiAoZXZlbnQuZGF0YSAmJiBldmVudC5kYXRhLnNpemUgPiAwKSB7XHJcbiAgICAgICAgICB0aGlzLnJlY29yZGVkQmxvYnMucHVzaChldmVudC5kYXRhKTtcclxuICAgICAgICB9XHJcbiAgICAgIH07XHJcblxyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIub25zdG9wID0gKCkgPT4ge1xyXG4gICAgICAgIGNvbnN0IHN1cGVyQnVmZmVyID0gbmV3IEJsb2IodGhpcy5yZWNvcmRlZEJsb2JzLCB7IHR5cGU6IG1pbWVUeXBlIH0pO1xyXG4gICAgICAgIGNvbnN0IHVybCA9IHdpbmRvdy5VUkwuY3JlYXRlT2JqZWN0VVJMKHN1cGVyQnVmZmVyKTtcclxuICAgICAgICB0aGlzLnJlY29yZGVkVXJsU3ViamVjdC5uZXh0KHVybCk7XHJcbiAgICAgICAgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QubmV4dChSZWNvcmRpbmdTdGF0ZS5TdG9wcGVkKTtcclxuICAgICAgICB0aGlzLnN0b3BUaW1lcigpO1xyXG5cclxuICAgICAgfTtcclxuXHJcbiAgICAgIHRoaXMubWVkaWFSZWNvcmRlci5vbmVycm9yID0gKGV2ZW50OiBFdmVudCkgPT4ge1xyXG4gICAgICAgIGNvbnN0IGVycm9yRXZlbnQgPSBldmVudCBhcyBFcnJvckV2ZW50OyAvLyBNb3JlIHNwZWNpZmljIHR5cGUgaWYgYXZhaWxhYmxlXHJcbiAgICAgICAgbGV0IG1lc3NhZ2UgPSB0aGlzLnNjcmVlblJlY29yZGluZ0NvbnN0YW50Lk1FRElBX0VSUk9SO1xyXG4gICAgICAgIGlmIChlcnJvckV2ZW50LmVycm9yICYmIGVycm9yRXZlbnQuZXJyb3IubmFtZSkge1xyXG4gICAgICAgICAgbWVzc2FnZSArPSBgOiAke2Vycm9yRXZlbnQuZXJyb3IubmFtZX1gO1xyXG4gICAgICAgICAgaWYgKGVycm9yRXZlbnQuZXJyb3IubWVzc2FnZSkgbWVzc2FnZSArPSBgIC0gJHtlcnJvckV2ZW50LmVycm9yLm1lc3NhZ2V9YDtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5oYW5kbGVFcnJvcihtZXNzYWdlKTtcclxuICAgICAgICB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC5uZXh0KFJlY29yZGluZ1N0YXRlLklkbGUpO1xyXG4gICAgICAgIHRoaXMuc3RvcFRpbWVyKCk7XHJcbiAgICAgIH07XHJcblxyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIuc3RhcnQoKTsgLy8gU3RhcnQgcmVjb3JkaW5nXHJcbiAgICAgIHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0Lm5leHQoUmVjb3JkaW5nU3RhdGUuUmVjb3JkaW5nKTtcclxuICAgICAgdGhpcy5zdGFydFRpbWVyKCk7XHJcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xyXG4gICAgICB0aGlzLmhhbmRsZUVycm9yKGBFcnJvciBzdGFydGluZyBzY3JlZW4gcmVjb3JkaW5nOiAke2Vyci5uYW1lfSAtICR7ZXJyLm1lc3NhZ2V9YCk7XHJcbiAgICAgIHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0Lm5leHQoUmVjb3JkaW5nU3RhdGUuSWRsZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICogR2V0cyB0aGUgZmlyc3Qgc3VwcG9ydGVkIE1JTUUgdHlwZSBmb3IgTWVkaWFSZWNvcmRlclxyXG4gKiBcclxuICogQHJldHVybnMgc3RyaW5nfG51bGwgLSBUaGUgc3VwcG9ydGVkIE1JTUUgdHlwZSBvciBudWxsIGlmIG5vbmUgZm91bmRcclxuICovXHJcbiAgcHJpdmF0ZSBnZXRTdXBwb3J0ZWRNaW1lVHlwZSgpOiBzdHJpbmcgfCBudWxsIHtcclxuICAgIGNvbnN0IG1pbWVUeXBlcyA9IFtcclxuICAgICAgJ3ZpZGVvL3dlYm07Y29kZWNzPXZwOSxvcHVzJyxcclxuICAgICAgJ3ZpZGVvL3dlYm07Y29kZWNzPXZwOCxvcHVzJyxcclxuICAgICAgJ3ZpZGVvL3dlYm07Y29kZWNzPWgyNjQsb3B1cycsXHJcbiAgICAgICd2aWRlby9tcDQ7Y29kZWNzPWgyNjQsYWFjJywgLy8gTVA0IG1pZ2h0IGhhdmUgYnJvYWRlciBjb21wYXRpYmlsaXR5IGJ1dCBsZXNzIGJyb3dzZXIgc3VwcG9ydCBmb3IgcmVjb3JkaW5nXHJcbiAgICAgICd2aWRlby93ZWJtJyxcclxuICAgIF07XHJcbiAgICBmb3IgKGNvbnN0IG1pbWVUeXBlIG9mIG1pbWVUeXBlcykge1xyXG4gICAgICBpZiAoTWVkaWFSZWNvcmRlci5pc1R5cGVTdXBwb3J0ZWQobWltZVR5cGUpKSB7XHJcbiAgICAgICAgcmV0dXJuIG1pbWVUeXBlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEludGVybmFsIG1ldGhvZCB0byBzdG9wIHRoZSByZWNvcmRpbmcgcHJvY2Vzc1xyXG4gICAqIFxyXG4gICAqIEBwcml2YXRlXHJcbiAgICogQHJldHVybnMgdm9pZFxyXG4gICAqL1xyXG4gIHByaXZhdGUgc3RvcFJlY29yZGluZ0ludGVybmFsKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMubWVkaWFSZWNvcmRlciAmJiAodGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QudmFsdWUgPT09IFJlY29yZGluZ1N0YXRlLlJlY29yZGluZyB8fCB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC52YWx1ZSA9PT0gUmVjb3JkaW5nU3RhdGUuUGF1c2VkKSkge1xyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIuc3RvcCgpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5zdHJlYW0/LmdldFRyYWNrcygpLmZvckVhY2godHJhY2sgPT4gdHJhY2suc3RvcCgpKTtcclxuICAgIHRoaXMuc3RyZWFtID0gbnVsbDtcclxuICAgIC8vIFN0YXRlIHdpbGwgYmUgdXBkYXRlZCBieSBvbnN0b3AgaGFuZGxlclxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogXHJcbiAgICogQHJldHVybnMgUHJvbWlzZTx2b2lkPlxyXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgcmVjb3JkaW5nIGlzIG5vdCBpbiBwcm9ncmVzc1xyXG4gICAqL1xyXG4gIHN0b3BSZWNvcmRpbmcoKTogdm9pZCB7XHJcbiAgICB0aGlzLnN0b3BSZWNvcmRpbmdJbnRlcm5hbCgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUGF1c2VzIHRoZSBjdXJyZW50IHJlY29yZGluZ1xyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIFByb21pc2U8dm9pZD5cclxuICAgKiBAdGhyb3dzIEVycm9yIGlmIHJlY29yZGluZyBpcyBub3QgaW4gcHJvZ3Jlc3NcclxuICAgKi9cclxuICBwYXVzZVJlY29yZGluZygpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLm1lZGlhUmVjb3JkZXIgJiYgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QudmFsdWUgPT09IFJlY29yZGluZ1N0YXRlLlJlY29yZGluZykge1xyXG4gICAgICB0aGlzLm1lZGlhUmVjb3JkZXIucGF1c2UoKTtcclxuICAgICAgdGhpcy5yZWNvcmRpbmdTdGF0ZVN1YmplY3QubmV4dChSZWNvcmRpbmdTdGF0ZS5QYXVzZWQpO1xyXG4gICAgICB0aGlzLnN0b3BUaW1lcigpOyAvLyBQYXVzZXMgdGhlIHRpbWVyIGRpc3BsYXlcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlc3VtZXMgYSBwYXVzZWQgcmVjb3JkaW5nXHJcbiAgICogXHJcbiAgICogQHJldHVybnMgUHJvbWlzZTx2b2lkPlxyXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgcmVjb3JkaW5nIGlzIG5vdCBwYXVzZWRcclxuICAgKi9cclxuICByZXN1bWVSZWNvcmRpbmcoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5tZWRpYVJlY29yZGVyICYmIHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5QYXVzZWQpIHtcclxuICAgICAgdGhpcy5tZWRpYVJlY29yZGVyLnJlc3VtZSgpO1xyXG4gICAgICB0aGlzLnJlY29yZGluZ1N0YXRlU3ViamVjdC5uZXh0KFJlY29yZGluZ1N0YXRlLlJlY29yZGluZyk7XHJcbiAgICAgIHRoaXMuc3RhcnRUaW1lcih0aGlzLmN1cnJlbnRSZWNvcmRlZFRpbWUpOyAvLyBSZXN1bWVzIHRpbWVyIGRpc3BsYXlcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSBmaWxlTmFtZSBcclxuICAgKi9cclxuICBkb3dubG9hZFJlY29yZGluZyhmaWxlTmFtZTogc3RyaW5nID0gJ3JlY29yZGluZy53ZWJtJyk6IHZvaWQge1xyXG4gICAgY29uc3QgdXJsID0gdGhpcy5yZWNvcmRlZFVybFN1YmplY3QudmFsdWU7XHJcbiAgICBjb25zdCB0aW1lc3RhbXAgPSB0aGlzLnJlY29yZGluZ1RpbWVzdGFtcFN1YmplY3QudmFsdWU7XHJcblxyXG4gICAgaWYgKHVybCAmJiB0aW1lc3RhbXApIHtcclxuICAgICAgLy8gRm9ybWF0IHRoZSB0aW1lc3RhbXAgZm9yIGZpbGVuYW1lIChyZW1vdmUgc3BhY2VzIGFuZCBzcGVjaWFsIGNoYXJhY3RlcnMpXHJcbiAgICAgIGNvbnN0IGZvcm1hdHRlZFRpbWVzdGFtcCA9IHRpbWVzdGFtcC5yZXBsYWNlKC9bXmEtekEtWjAtOV0vZywgJ18nKTtcclxuICAgICAgLy8gQ3JlYXRlIGZpbGVuYW1lIHdpdGggdGltZXN0YW1wXHJcbiAgICAgIGNvbnN0IGZpbGVFeHRlbnNpb24gPSBmaWxlTmFtZS5zcGxpdCgnLicpLnBvcCgpIHx8ICd3ZWJtJztcclxuICAgICAgY29uc3QgbmV3RmlsZU5hbWUgPSBgc2NyZWVuX3JlY29yZGluZ18ke2Zvcm1hdHRlZFRpbWVzdGFtcH0uJHtmaWxlRXh0ZW5zaW9ufWA7XHJcblxyXG4gICAgICBjb25zdCBhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xyXG4gICAgICBhLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgIGEuaHJlZiA9IHVybDtcclxuICAgICAgYS5kb3dubG9hZCA9IG5ld0ZpbGVOYW1lO1xyXG4gICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGEpO1xyXG4gICAgICBhLmNsaWNrKCk7XHJcbiAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQoYSk7XHJcbiAgICAgIC8vIE5vIG5lZWQgdG8gcmV2b2tlIFVSTCBoZXJlIGlmIHVzZXIgbWlnaHQgd2FudCB0byBwbGF5IGl0IGFnYWluLlxyXG4gICAgICAvLyBSZXZva2Ugb24gY2xlYW51cCBvciBuZXcgcmVjb3JkaW5nLlxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5oYW5kbGVFcnJvcih0aGlzLnNjcmVlblJlY29yZGluZ0NvbnN0YW50Lk5PX1JFQ09SRElOR19ET1dOTE9BRCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICogU3RhcnRzIHRoZSByZWNvcmRpbmcgdGltZXJcclxuICogXHJcbiAqIEBwYXJhbSBzdGFydFRpbWUgLSBPcHRpb25hbCBzdGFydCB0aW1lIGZvciB0aGUgdGltZXJcclxuICogQHByaXZhdGVcclxuICogQHJldHVybnMgdm9pZFxyXG4gKi9cclxuICBwcml2YXRlIHN0YXJ0VGltZXIoc3RhcnRUaW1lOiBudW1iZXIgPSAwKTogdm9pZCB7XHJcbiAgICB0aGlzLnN0b3BUaW1lcigpOyAvLyBFbnN1cmUgbm8gbXVsdGlwbGUgdGltZXJzXHJcbiAgICB0aGlzLmN1cnJlbnRSZWNvcmRlZFRpbWUgPSBzdGFydFRpbWU7XHJcbiAgICB0aGlzLnJlY29yZGVkVGltZVN1YmplY3QubmV4dCh0aGlzLmN1cnJlbnRSZWNvcmRlZFRpbWUpO1xyXG5cclxuICAgIHRoaXMudGltZXJTdWJzY3JpcHRpb24gPSB0aW1lcigwLCAxMDAwKVxyXG4gICAgICAucGlwZShcclxuICAgICAgICB0YXAoKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5SZWNvcmRpbmcpIHtcclxuICAgICAgICAgICAgdGhpcy5jdXJyZW50UmVjb3JkZWRUaW1lKys7XHJcbiAgICAgICAgICAgIHRoaXMucmVjb3JkZWRUaW1lU3ViamVjdC5uZXh0KHRoaXMuY3VycmVudFJlY29yZGVkVGltZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSksXHJcbiAgICAgICAgdGFrZVdoaWxlKCgpID0+IHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0LnZhbHVlID09PSBSZWNvcmRpbmdTdGF0ZS5SZWNvcmRpbmcpXHJcbiAgICAgIClcclxuICAgICAgLnN1YnNjcmliZSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU3RvcHMgdGhlIHJlY29yZGluZyB0aW1lclxyXG4gICAqIFxyXG4gICAqIEBwcml2YXRlXHJcbiAgICogQHJldHVybnMgdm9pZFxyXG4gICAqL1xyXG4gIHByaXZhdGUgc3RvcFRpbWVyKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMudGltZXJTdWJzY3JpcHRpb24pIHtcclxuICAgICAgdGhpcy50aW1lclN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xyXG4gICAgICB0aGlzLnRpbWVyU3Vic2NyaXB0aW9uID0gbnVsbDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENsZWFucyB1cCByZXNvdXJjZXMgZnJvbSBwcmV2aW91cyByZWNvcmRpbmdcclxuICAgKiBcclxuICAgKiBAcHJpdmF0ZVxyXG4gICAqIEByZXR1cm5zIHZvaWRcclxuICAgKi9cclxuICBwcml2YXRlIGNsZWFudXBQcmV2aW91c1JlY29yZGluZygpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnJlY29yZGVkVXJsU3ViamVjdC52YWx1ZSkge1xyXG4gICAgICB3aW5kb3cuVVJMLnJldm9rZU9iamVjdFVSTCh0aGlzLnJlY29yZGVkVXJsU3ViamVjdC52YWx1ZSk7XHJcbiAgICAgIHRoaXMucmVjb3JkZWRVcmxTdWJqZWN0Lm5leHQobnVsbCk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnJlY29yZGVkQmxvYnMgPSBbXTtcclxuICAgIHRoaXMuY3VycmVudFJlY29yZGVkVGltZSA9IDA7XHJcbiAgICB0aGlzLnJlY29yZGVkVGltZVN1YmplY3QubmV4dCgwKTtcclxuICAgIGlmICh0aGlzLnN0cmVhbSkge1xyXG4gICAgICB0aGlzLnN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IHRyYWNrLnN0b3AoKSk7XHJcbiAgICAgIHRoaXMuc3RyZWFtID0gbnVsbDtcclxuICAgIH1cclxuICAgIGlmICh0aGlzLm1lZGlhUmVjb3JkZXIgJiYgdGhpcy5tZWRpYVJlY29yZGVyLnN0YXRlICE9PSB0aGlzLnNjcmVlblJlY29yZGluZ0NvbnN0YW50LklOQUNUSVZFKSB7XHJcbiAgICAgIHRoaXMubWVkaWFSZWNvcmRlci5zdG9wKCk7XHJcbiAgICB9XHJcbiAgICB0aGlzLm1lZGlhUmVjb3JkZXIgPSBudWxsO1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKlxyXG4gKiBSZXNldHMgdGhlIHJlY29yZGluZyBzdGF0ZSB0byBpZGxlXHJcbiAqIFxyXG4gKiBAcmV0dXJucyB2b2lkXHJcbiAqL1xyXG4gIHJlc2V0VG9JZGxlKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jbGVhbnVwUHJldmlvdXNSZWNvcmRpbmcoKTtcclxuICAgIHRoaXMucmVjb3JkaW5nU3RhdGVTdWJqZWN0Lm5leHQoUmVjb3JkaW5nU3RhdGUuSWRsZSk7XHJcbiAgICB0aGlzLmVycm9yU3ViamVjdC5uZXh0KCcnKTsgLy8gQ2xlYXIgYW55IHByZXZpb3VzIGVycm9yc1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKlxyXG4gKiBIYW5kbGVzIGFuZCBicm9hZGNhc3RzIHJlY29yZGluZyBlcnJvcnNcclxuICogXHJcbiAqIEBwcml2YXRlXHJcbiAqIEBwYXJhbSBlcnJvciAtIFRoZSBlcnJvciBtZXNzYWdlIHRvIGhhbmRsZVxyXG4gKiBAcmV0dXJucyB2b2lkXHJcbiAqL1xyXG4gIHByaXZhdGUgaGFuZGxlRXJyb3IoZXJyb3I6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5lcnJvclN1YmplY3QubmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcbiJdfQ==
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVjLWxpYi1zY3JlZW4tcmVjb3JkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVjLWxpYi1zY3JlZW4tcmVjb3JkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0=