angular-debug-recorder 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/esm2022/angular-debug-recorder.mjs +5 -0
- package/esm2022/lib/action-list/action-list.component.mjs +220 -0
- package/esm2022/lib/debug-panel/debug-panel.component.mjs +516 -0
- package/esm2022/lib/models/recorded-action.model.mjs +2 -0
- package/esm2022/lib/services/ai-generator.service.mjs +61 -0
- package/esm2022/lib/services/recorder.service.mjs +354 -0
- package/esm2022/lib/services/rrweb-recorder.service.mjs +108 -0
- package/esm2022/lib/session-replay/session-replay.component.mjs +166 -0
- package/esm2022/lib/settings-dialog/settings-dialog.component.mjs +105 -0
- package/esm2022/lib/test-preview/test-preview.component.mjs +120 -0
- package/esm2022/public-api.mjs +17 -0
- package/fesm2022/angular-debug-recorder.mjs +1631 -0
- package/fesm2022/angular-debug-recorder.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/action-list/action-list.component.d.ts +21 -0
- package/lib/debug-panel/debug-panel.component.d.ts +38 -0
- package/lib/models/recorded-action.model.d.ts +45 -0
- package/lib/services/ai-generator.service.d.ts +20 -0
- package/lib/services/recorder.service.d.ts +46 -0
- package/lib/services/rrweb-recorder.service.d.ts +27 -0
- package/lib/session-replay/session-replay.component.d.ts +19 -0
- package/lib/settings-dialog/settings-dialog.component.d.ts +11 -0
- package/lib/test-preview/test-preview.component.d.ts +13 -0
- package/package.json +37 -0
- package/public-api.d.ts +9 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Injectable, signal } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import * as i1 from "@angular/common/http";
|
|
4
|
+
export class AiGeneratorService {
|
|
5
|
+
constructor(http) {
|
|
6
|
+
this.http = http;
|
|
7
|
+
this._webhookUrl = signal(localStorage.getItem('debugRecorder_webhookUrl') ?? '');
|
|
8
|
+
this._isGenerating = signal(false);
|
|
9
|
+
this._error = signal(null);
|
|
10
|
+
this._lastTest = signal(null);
|
|
11
|
+
this.webhookUrl = this._webhookUrl.asReadonly();
|
|
12
|
+
this.isGenerating = this._isGenerating.asReadonly();
|
|
13
|
+
this.error = this._error.asReadonly();
|
|
14
|
+
this.lastTest = this._lastTest.asReadonly();
|
|
15
|
+
}
|
|
16
|
+
setWebhookUrl(url) {
|
|
17
|
+
this._webhookUrl.set(url);
|
|
18
|
+
localStorage.setItem('debugRecorder_webhookUrl', url);
|
|
19
|
+
}
|
|
20
|
+
async generateCypressTest(session) {
|
|
21
|
+
const url = this._webhookUrl();
|
|
22
|
+
if (!url)
|
|
23
|
+
throw new Error('Keine Webhook-URL konfiguriert');
|
|
24
|
+
this._isGenerating.set(true);
|
|
25
|
+
this._error.set(null);
|
|
26
|
+
try {
|
|
27
|
+
const code = await this.postSession(url, session);
|
|
28
|
+
const test = {
|
|
29
|
+
code,
|
|
30
|
+
generatedAt: Date.now(),
|
|
31
|
+
model: url,
|
|
32
|
+
sessionId: session.id,
|
|
33
|
+
};
|
|
34
|
+
this._lastTest.set(test);
|
|
35
|
+
return test;
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
const msg = err?.error?.message || err?.message || 'Fehler beim Senden';
|
|
39
|
+
this._error.set(msg);
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
this._isGenerating.set(false);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
postSession(url, session) {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
this.http.post(url, session, { responseType: 'text' }).subscribe({
|
|
49
|
+
next: (res) => resolve(res),
|
|
50
|
+
error: reject,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AiGeneratorService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
55
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AiGeneratorService, providedIn: 'root' }); }
|
|
56
|
+
}
|
|
57
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AiGeneratorService, decorators: [{
|
|
58
|
+
type: Injectable,
|
|
59
|
+
args: [{ providedIn: 'root' }]
|
|
60
|
+
}], ctorParameters: () => [{ type: i1.HttpClient }] });
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktZ2VuZXJhdG9yLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9kZWJ1Zy1yZWNvcmRlci9zcmMvbGliL3NlcnZpY2VzL2FpLWdlbmVyYXRvci5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7QUFLbkQsTUFBTSxPQUFPLGtCQUFrQjtJQVc3QixZQUFvQixJQUFnQjtRQUFoQixTQUFJLEdBQUosSUFBSSxDQUFZO1FBVjVCLGdCQUFXLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsMEJBQTBCLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUM3RSxrQkFBYSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5QixXQUFNLEdBQUcsTUFBTSxDQUFnQixJQUFJLENBQUMsQ0FBQztRQUNyQyxjQUFTLEdBQUcsTUFBTSxDQUF1QixJQUFJLENBQUMsQ0FBQztRQUV2RCxlQUFVLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUMzQyxpQkFBWSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDL0MsVUFBSyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDakMsYUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLENBQUM7SUFFQSxDQUFDO0lBRXhDLGFBQWEsQ0FBQyxHQUFXO1FBQ3ZCLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzFCLFlBQVksQ0FBQyxPQUFPLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxPQUF5QjtRQUNqRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDL0IsSUFBSSxDQUFDLEdBQUc7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7UUFFNUQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFdEIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUNsRCxNQUFNLElBQUksR0FBa0I7Z0JBQzFCLElBQUk7Z0JBQ0osV0FBVyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7Z0JBQ3ZCLEtBQUssRUFBRSxHQUFHO2dCQUNWLFNBQVMsRUFBRSxPQUFPLENBQUMsRUFBRTthQUN0QixDQUFDO1lBQ0YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDekIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsT0FBTyxHQUFRLEVBQUUsQ0FBQztZQUNsQixNQUFNLEdBQUcsR0FBRyxHQUFHLEVBQUUsS0FBSyxFQUFFLE9BQU8sSUFBSSxHQUFHLEVBQUUsT0FBTyxJQUFJLG9CQUFvQixDQUFDO1lBQ3hFLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3JCLE1BQU0sR0FBRyxDQUFDO1FBQ1osQ0FBQztnQkFBUyxDQUFDO1lBQ1QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDaEMsQ0FBQztJQUNILENBQUM7SUFFTyxXQUFXLENBQUMsR0FBVyxFQUFFLE9BQXlCO1FBQ3hELE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDckMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLE9BQU8sRUFBRSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQztnQkFDL0QsSUFBSSxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDO2dCQUMzQixLQUFLLEVBQUUsTUFBTTthQUNkLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzsrR0FuRFUsa0JBQWtCO21IQUFsQixrQkFBa0IsY0FETCxNQUFNOzs0RkFDbkIsa0JBQWtCO2tCQUQ5QixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIHNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xyXG5pbXBvcnQgeyBHZW5lcmF0ZWRUZXN0LCBSZWNvcmRpbmdTZXNzaW9uIH0gZnJvbSAnLi4vbW9kZWxzL3JlY29yZGVkLWFjdGlvbi5tb2RlbCc7XHJcblxyXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxyXG5leHBvcnQgY2xhc3MgQWlHZW5lcmF0b3JTZXJ2aWNlIHtcclxuICBwcml2YXRlIF93ZWJob29rVXJsID0gc2lnbmFsKGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdkZWJ1Z1JlY29yZGVyX3dlYmhvb2tVcmwnKSA/PyAnJyk7XHJcbiAgcHJpdmF0ZSBfaXNHZW5lcmF0aW5nID0gc2lnbmFsKGZhbHNlKTtcclxuICBwcml2YXRlIF9lcnJvciA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcclxuICBwcml2YXRlIF9sYXN0VGVzdCA9IHNpZ25hbDxHZW5lcmF0ZWRUZXN0IHwgbnVsbD4obnVsbCk7XHJcblxyXG4gIHdlYmhvb2tVcmwgPSB0aGlzLl93ZWJob29rVXJsLmFzUmVhZG9ubHkoKTtcclxuICBpc0dlbmVyYXRpbmcgPSB0aGlzLl9pc0dlbmVyYXRpbmcuYXNSZWFkb25seSgpO1xyXG4gIGVycm9yID0gdGhpcy5fZXJyb3IuYXNSZWFkb25seSgpO1xyXG4gIGxhc3RUZXN0ID0gdGhpcy5fbGFzdFRlc3QuYXNSZWFkb25seSgpO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGh0dHA6IEh0dHBDbGllbnQpIHt9XHJcblxyXG4gIHNldFdlYmhvb2tVcmwodXJsOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuX3dlYmhvb2tVcmwuc2V0KHVybCk7XHJcbiAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSgnZGVidWdSZWNvcmRlcl93ZWJob29rVXJsJywgdXJsKTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGdlbmVyYXRlQ3lwcmVzc1Rlc3Qoc2Vzc2lvbjogUmVjb3JkaW5nU2Vzc2lvbik6IFByb21pc2U8R2VuZXJhdGVkVGVzdD4ge1xyXG4gICAgY29uc3QgdXJsID0gdGhpcy5fd2ViaG9va1VybCgpO1xyXG4gICAgaWYgKCF1cmwpIHRocm93IG5ldyBFcnJvcignS2VpbmUgV2ViaG9vay1VUkwga29uZmlndXJpZXJ0Jyk7XHJcblxyXG4gICAgdGhpcy5faXNHZW5lcmF0aW5nLnNldCh0cnVlKTtcclxuICAgIHRoaXMuX2Vycm9yLnNldChudWxsKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCBjb2RlID0gYXdhaXQgdGhpcy5wb3N0U2Vzc2lvbih1cmwsIHNlc3Npb24pO1xyXG4gICAgICBjb25zdCB0ZXN0OiBHZW5lcmF0ZWRUZXN0ID0ge1xyXG4gICAgICAgIGNvZGUsXHJcbiAgICAgICAgZ2VuZXJhdGVkQXQ6IERhdGUubm93KCksXHJcbiAgICAgICAgbW9kZWw6IHVybCxcclxuICAgICAgICBzZXNzaW9uSWQ6IHNlc3Npb24uaWQsXHJcbiAgICAgIH07XHJcbiAgICAgIHRoaXMuX2xhc3RUZXN0LnNldCh0ZXN0KTtcclxuICAgICAgcmV0dXJuIHRlc3Q7XHJcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xyXG4gICAgICBjb25zdCBtc2cgPSBlcnI/LmVycm9yPy5tZXNzYWdlIHx8IGVycj8ubWVzc2FnZSB8fCAnRmVobGVyIGJlaW0gU2VuZGVuJztcclxuICAgICAgdGhpcy5fZXJyb3Iuc2V0KG1zZyk7XHJcbiAgICAgIHRocm93IGVycjtcclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIHRoaXMuX2lzR2VuZXJhdGluZy5zZXQoZmFsc2UpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwb3N0U2Vzc2lvbih1cmw6IHN0cmluZywgc2Vzc2lvbjogUmVjb3JkaW5nU2Vzc2lvbik6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgICB0aGlzLmh0dHAucG9zdCh1cmwsIHNlc3Npb24sIHsgcmVzcG9uc2VUeXBlOiAndGV4dCcgfSkuc3Vic2NyaWJlKHtcclxuICAgICAgICBuZXh0OiAocmVzKSA9PiByZXNvbHZlKHJlcyksXHJcbiAgICAgICAgZXJyb3I6IHJlamVjdCxcclxuICAgICAgfSk7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuIl19
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { Injectable, signal, computed } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class RecorderService {
|
|
4
|
+
constructor(zone) {
|
|
5
|
+
this.zone = zone;
|
|
6
|
+
this._isRecording = signal(false);
|
|
7
|
+
this._currentSession = signal(null);
|
|
8
|
+
this._sessions = signal([]);
|
|
9
|
+
this._isPaused = signal(false);
|
|
10
|
+
this.isRecording = computed(() => this._isRecording());
|
|
11
|
+
this.isPaused = computed(() => this._isPaused());
|
|
12
|
+
this.currentSession = computed(() => this._currentSession());
|
|
13
|
+
this.sessions = computed(() => this._sessions());
|
|
14
|
+
this.actionCount = computed(() => this._currentSession()?.actions.length ?? 0);
|
|
15
|
+
this.listeners = [];
|
|
16
|
+
this.lastScrollTime = 0;
|
|
17
|
+
}
|
|
18
|
+
startRecording(name, description) {
|
|
19
|
+
const session = {
|
|
20
|
+
id: this.generateId(),
|
|
21
|
+
name: name || `Session ${new Date().toLocaleTimeString()}`,
|
|
22
|
+
description,
|
|
23
|
+
startTime: Date.now(),
|
|
24
|
+
startUrl: window.location.href,
|
|
25
|
+
actions: [],
|
|
26
|
+
tags: [],
|
|
27
|
+
};
|
|
28
|
+
this._currentSession.set(session);
|
|
29
|
+
this._isRecording.set(true);
|
|
30
|
+
this._isPaused.set(false);
|
|
31
|
+
this.attachListeners();
|
|
32
|
+
this.recordNavigation('navigation', window.location.href);
|
|
33
|
+
}
|
|
34
|
+
stopRecording() {
|
|
35
|
+
const session = this._currentSession();
|
|
36
|
+
if (!session)
|
|
37
|
+
return null;
|
|
38
|
+
const completed = { ...session, endTime: Date.now() };
|
|
39
|
+
this._sessions.update(s => [...s, completed]);
|
|
40
|
+
this._currentSession.set(null);
|
|
41
|
+
this._isRecording.set(false);
|
|
42
|
+
this._isPaused.set(false);
|
|
43
|
+
this.detachListeners();
|
|
44
|
+
return completed;
|
|
45
|
+
}
|
|
46
|
+
pauseRecording() {
|
|
47
|
+
if (this._isRecording()) {
|
|
48
|
+
this._isPaused.set(!this._isPaused());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
clearCurrentSession() {
|
|
52
|
+
this._currentSession.update(s => s ? { ...s, actions: [] } : null);
|
|
53
|
+
}
|
|
54
|
+
removeAction(actionId) {
|
|
55
|
+
this._currentSession.update(s => s ? { ...s, actions: s.actions.filter(a => a.id !== actionId) } : null);
|
|
56
|
+
}
|
|
57
|
+
addNote(actionId, note) {
|
|
58
|
+
this._currentSession.update(s => s ? {
|
|
59
|
+
...s,
|
|
60
|
+
actions: s.actions.map(a => a.id === actionId ? { ...a, note } : a)
|
|
61
|
+
} : null);
|
|
62
|
+
}
|
|
63
|
+
deleteSession(sessionId) {
|
|
64
|
+
this._sessions.update(s => s.filter(x => x.id !== sessionId));
|
|
65
|
+
}
|
|
66
|
+
loadSession(session) {
|
|
67
|
+
this._currentSession.set(session);
|
|
68
|
+
}
|
|
69
|
+
// ─── Event Listeners ──────────────────────────────────────────────────────
|
|
70
|
+
attachListeners() {
|
|
71
|
+
const opts = { capture: true, passive: true };
|
|
72
|
+
const onClick = (e) => this.zone.run(() => this.handleClick(e));
|
|
73
|
+
const onDblClick = (e) => this.zone.run(() => this.handleDblClick(e));
|
|
74
|
+
const onInput = (e) => this.zone.run(() => this.handleInput(e));
|
|
75
|
+
const onChange = (e) => this.zone.run(() => this.handleChange(e));
|
|
76
|
+
const onSubmit = (e) => this.zone.run(() => this.handleSubmit(e));
|
|
77
|
+
const onKeydown = (e) => this.zone.run(() => this.handleKeydown(e));
|
|
78
|
+
const onScroll = (e) => this.zone.run(() => this.handleScroll(e));
|
|
79
|
+
document.addEventListener('click', onClick, opts);
|
|
80
|
+
document.addEventListener('dblclick', onDblClick, opts);
|
|
81
|
+
document.addEventListener('input', onInput, opts);
|
|
82
|
+
document.addEventListener('change', onChange, opts);
|
|
83
|
+
document.addEventListener('submit', onSubmit, opts);
|
|
84
|
+
document.addEventListener('keydown', onKeydown, opts);
|
|
85
|
+
document.addEventListener('scroll', onScroll, { capture: true, passive: true });
|
|
86
|
+
this.listeners = [
|
|
87
|
+
{ type: 'click', fn: onClick },
|
|
88
|
+
{ type: 'dblclick', fn: onDblClick },
|
|
89
|
+
{ type: 'input', fn: onInput },
|
|
90
|
+
{ type: 'change', fn: onChange },
|
|
91
|
+
{ type: 'submit', fn: onSubmit },
|
|
92
|
+
{ type: 'keydown', fn: onKeydown },
|
|
93
|
+
{ type: 'scroll', fn: onScroll },
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
detachListeners() {
|
|
97
|
+
this.listeners.forEach(({ type, fn }) => document.removeEventListener(type, fn, true));
|
|
98
|
+
this.listeners = [];
|
|
99
|
+
this.mutationObserver?.disconnect();
|
|
100
|
+
}
|
|
101
|
+
// ─── Handlers ─────────────────────────────────────────────────────────────
|
|
102
|
+
handleClick(e) {
|
|
103
|
+
if (!this.shouldRecord(e.target))
|
|
104
|
+
return;
|
|
105
|
+
const el = e.target;
|
|
106
|
+
const info = this.getElementInfo(el);
|
|
107
|
+
const selector = this.buildSelector(el);
|
|
108
|
+
this.addAction({
|
|
109
|
+
type: 'click',
|
|
110
|
+
selector,
|
|
111
|
+
selectorStrategy: this.getSelectorStrategy(el),
|
|
112
|
+
element: info,
|
|
113
|
+
description: `Click on ${this.describeElement(info)}`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
handleDblClick(e) {
|
|
117
|
+
if (!this.shouldRecord(e.target))
|
|
118
|
+
return;
|
|
119
|
+
const el = e.target;
|
|
120
|
+
const info = this.getElementInfo(el);
|
|
121
|
+
const selector = this.buildSelector(el);
|
|
122
|
+
this.addAction({
|
|
123
|
+
type: 'dblclick',
|
|
124
|
+
selector,
|
|
125
|
+
selectorStrategy: this.getSelectorStrategy(el),
|
|
126
|
+
element: info,
|
|
127
|
+
description: `Double-click on ${this.describeElement(info)}`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
handleInput(e) {
|
|
131
|
+
if (!this.shouldRecord(e.target))
|
|
132
|
+
return;
|
|
133
|
+
const el = e.target;
|
|
134
|
+
if (['checkbox', 'radio'].includes(el.type))
|
|
135
|
+
return; // handled by change
|
|
136
|
+
const info = this.getElementInfo(el);
|
|
137
|
+
const selector = this.buildSelector(el);
|
|
138
|
+
this.addAction({
|
|
139
|
+
type: 'input',
|
|
140
|
+
selector,
|
|
141
|
+
selectorStrategy: this.getSelectorStrategy(el),
|
|
142
|
+
element: info,
|
|
143
|
+
value: el.value,
|
|
144
|
+
description: `Type "${el.value}" in ${this.describeElement(info)}`,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
handleChange(e) {
|
|
148
|
+
if (!this.shouldRecord(e.target))
|
|
149
|
+
return;
|
|
150
|
+
const el = e.target;
|
|
151
|
+
const info = this.getElementInfo(el);
|
|
152
|
+
const selector = this.buildSelector(el);
|
|
153
|
+
if (el.tagName === 'SELECT') {
|
|
154
|
+
this.addAction({
|
|
155
|
+
type: 'select',
|
|
156
|
+
selector,
|
|
157
|
+
selectorStrategy: this.getSelectorStrategy(el),
|
|
158
|
+
element: info,
|
|
159
|
+
value: el.value,
|
|
160
|
+
description: `Select "${el.value}" in ${this.describeElement(info)}`,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else if (el.type === 'checkbox') {
|
|
164
|
+
this.addAction({
|
|
165
|
+
type: 'click',
|
|
166
|
+
selector,
|
|
167
|
+
selectorStrategy: this.getSelectorStrategy(el),
|
|
168
|
+
element: info,
|
|
169
|
+
value: String(el.checked),
|
|
170
|
+
description: `${el.checked ? 'Check' : 'Uncheck'} ${this.describeElement(info)}`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
handleSubmit(e) {
|
|
175
|
+
if (!this.shouldRecord(e.target))
|
|
176
|
+
return;
|
|
177
|
+
const form = e.target;
|
|
178
|
+
const info = this.getElementInfo(form);
|
|
179
|
+
const selector = this.buildSelector(form);
|
|
180
|
+
this.addAction({
|
|
181
|
+
type: 'submit',
|
|
182
|
+
selector,
|
|
183
|
+
selectorStrategy: this.getSelectorStrategy(form),
|
|
184
|
+
element: info,
|
|
185
|
+
description: `Submit form ${info.id ? '#' + info.id : info.name ? info.name : ''}`.trim(),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
handleScroll(e) {
|
|
189
|
+
if (!this.shouldRecord(e.target))
|
|
190
|
+
return;
|
|
191
|
+
const now = Date.now();
|
|
192
|
+
if (now - this.lastScrollTime < 1000)
|
|
193
|
+
return; // debounce 1s
|
|
194
|
+
this.lastScrollTime = now;
|
|
195
|
+
const el = e.target;
|
|
196
|
+
const isDoc = !el.tagName || el.tagName === 'HTML';
|
|
197
|
+
const scrollY = isDoc ? window.scrollY : el.scrollTop;
|
|
198
|
+
const scrollX = isDoc ? window.scrollX : el.scrollLeft;
|
|
199
|
+
const selector = el.tagName === 'HTML' || el.tagName === 'BODY'
|
|
200
|
+
? 'window'
|
|
201
|
+
: this.buildSelector(el);
|
|
202
|
+
this.addAction({
|
|
203
|
+
type: 'scroll',
|
|
204
|
+
selector,
|
|
205
|
+
selectorStrategy: 'combined',
|
|
206
|
+
value: `${scrollX},${scrollY}`,
|
|
207
|
+
description: `Scroll to (${scrollX}, ${scrollY})`,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
handleKeydown(e) {
|
|
211
|
+
const specialKeys = ['Enter', 'Escape', 'Tab', 'F5', 'F12'];
|
|
212
|
+
if (!specialKeys.includes(e.key))
|
|
213
|
+
return;
|
|
214
|
+
if (!this.shouldRecord(e.target))
|
|
215
|
+
return;
|
|
216
|
+
const el = e.target;
|
|
217
|
+
const selector = this.buildSelector(el);
|
|
218
|
+
this.addAction({
|
|
219
|
+
type: 'keypress',
|
|
220
|
+
selector,
|
|
221
|
+
selectorStrategy: this.getSelectorStrategy(el),
|
|
222
|
+
value: e.key,
|
|
223
|
+
description: `Press "${e.key}" on ${el.tagName.toLowerCase()}`,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
recordNavigation(type, navUrl) {
|
|
227
|
+
const action = {
|
|
228
|
+
id: this.generateId(),
|
|
229
|
+
timestamp: Date.now(),
|
|
230
|
+
url: navUrl,
|
|
231
|
+
type,
|
|
232
|
+
selector: 'window',
|
|
233
|
+
selectorStrategy: 'combined',
|
|
234
|
+
description: `Navigate to ${navUrl}`,
|
|
235
|
+
};
|
|
236
|
+
this._currentSession.update(s => s ? { ...s, actions: [...s.actions, action] } : s);
|
|
237
|
+
}
|
|
238
|
+
// ─── Selector Building ────────────────────────────────────────────────────
|
|
239
|
+
buildSelector(el) {
|
|
240
|
+
// Priority: data-testid > data-cy > id > name > aria-label > combined
|
|
241
|
+
const testId = el.getAttribute('data-testid');
|
|
242
|
+
if (testId)
|
|
243
|
+
return `[data-testid="${testId}"]`;
|
|
244
|
+
const cy = el.getAttribute('data-cy');
|
|
245
|
+
if (cy)
|
|
246
|
+
return `[data-cy="${cy}"]`;
|
|
247
|
+
if (el.id && !el.id.includes(':'))
|
|
248
|
+
return `#${el.id}`;
|
|
249
|
+
const name = el.getAttribute('name');
|
|
250
|
+
if (name)
|
|
251
|
+
return `${el.tagName.toLowerCase()}[name="${name}"]`;
|
|
252
|
+
const ariaLabel = el.getAttribute('aria-label');
|
|
253
|
+
if (ariaLabel)
|
|
254
|
+
return `[aria-label="${ariaLabel}"]`;
|
|
255
|
+
// Class-based fallback
|
|
256
|
+
const relevantClasses = Array.from(el.classList)
|
|
257
|
+
.filter(c => !c.startsWith('ng-') && !c.startsWith('cdk-') && c.length > 0)
|
|
258
|
+
.slice(0, 3);
|
|
259
|
+
if (relevantClasses.length > 0) {
|
|
260
|
+
return `${el.tagName.toLowerCase()}.${relevantClasses.join('.')}`;
|
|
261
|
+
}
|
|
262
|
+
// Text content for buttons/links
|
|
263
|
+
if (['BUTTON', 'A'].includes(el.tagName)) {
|
|
264
|
+
const text = el.textContent?.trim().slice(0, 30);
|
|
265
|
+
if (text)
|
|
266
|
+
return `${el.tagName.toLowerCase()}:contains("${text}")`;
|
|
267
|
+
}
|
|
268
|
+
return el.tagName.toLowerCase();
|
|
269
|
+
}
|
|
270
|
+
getSelectorStrategy(el) {
|
|
271
|
+
if (el.getAttribute('data-testid'))
|
|
272
|
+
return 'data-testid';
|
|
273
|
+
if (el.getAttribute('data-cy'))
|
|
274
|
+
return 'data-cy';
|
|
275
|
+
if (el.id)
|
|
276
|
+
return 'id';
|
|
277
|
+
if (el.getAttribute('name'))
|
|
278
|
+
return 'name';
|
|
279
|
+
return 'class';
|
|
280
|
+
}
|
|
281
|
+
getElementInfo(el) {
|
|
282
|
+
return {
|
|
283
|
+
tagName: el.tagName.toLowerCase(),
|
|
284
|
+
id: el.id || undefined,
|
|
285
|
+
classes: Array.from(el.classList).filter(c => !c.startsWith('ng-')),
|
|
286
|
+
dataTestId: el.getAttribute('data-testid') || undefined,
|
|
287
|
+
dataCy: el.getAttribute('data-cy') || undefined,
|
|
288
|
+
name: el.getAttribute('name') || undefined,
|
|
289
|
+
type: el.getAttribute('type') || undefined,
|
|
290
|
+
placeholder: el.getAttribute('placeholder') || undefined,
|
|
291
|
+
text: el.textContent?.trim().slice(0, 50) || undefined,
|
|
292
|
+
href: el.href || undefined,
|
|
293
|
+
ariaLabel: el.getAttribute('aria-label') || undefined,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
describeElement(info) {
|
|
297
|
+
if (info.dataTestId)
|
|
298
|
+
return `[data-testid="${info.dataTestId}"]`;
|
|
299
|
+
if (info.dataCy)
|
|
300
|
+
return `[data-cy="${info.dataCy}"]`;
|
|
301
|
+
if (info.id)
|
|
302
|
+
return `#${info.id}`;
|
|
303
|
+
if (info.ariaLabel)
|
|
304
|
+
return `"${info.ariaLabel}"`;
|
|
305
|
+
if (info.placeholder)
|
|
306
|
+
return `"${info.placeholder}" input`;
|
|
307
|
+
if (info.text)
|
|
308
|
+
return `"${info.text}"`;
|
|
309
|
+
return info.tagName;
|
|
310
|
+
}
|
|
311
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
312
|
+
shouldRecord(target) {
|
|
313
|
+
if (!this._isRecording() || this._isPaused())
|
|
314
|
+
return false;
|
|
315
|
+
if (!target)
|
|
316
|
+
return false;
|
|
317
|
+
// Ignore the debug panel itself
|
|
318
|
+
if (target.closest('[data-debug-panel]'))
|
|
319
|
+
return false;
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
addAction(partial) {
|
|
323
|
+
const action = {
|
|
324
|
+
id: this.generateId(),
|
|
325
|
+
timestamp: Date.now(),
|
|
326
|
+
url: window.location.href,
|
|
327
|
+
...partial,
|
|
328
|
+
};
|
|
329
|
+
// Deduplicate consecutive identical inputs (keep only latest value)
|
|
330
|
+
if (action.type === 'input') {
|
|
331
|
+
this._currentSession.update(s => {
|
|
332
|
+
if (!s)
|
|
333
|
+
return s;
|
|
334
|
+
const last = s.actions[s.actions.length - 1];
|
|
335
|
+
if (last?.type === 'input' && last.selector === action.selector) {
|
|
336
|
+
return { ...s, actions: [...s.actions.slice(0, -1), action] };
|
|
337
|
+
}
|
|
338
|
+
return { ...s, actions: [...s.actions, action] };
|
|
339
|
+
});
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
this._currentSession.update(s => s ? { ...s, actions: [...s.actions, action] } : s);
|
|
343
|
+
}
|
|
344
|
+
generateId() {
|
|
345
|
+
return Math.random().toString(36).slice(2, 11);
|
|
346
|
+
}
|
|
347
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RecorderService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
348
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RecorderService, providedIn: 'root' }); }
|
|
349
|
+
}
|
|
350
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RecorderService, decorators: [{
|
|
351
|
+
type: Injectable,
|
|
352
|
+
args: [{ providedIn: 'root' }]
|
|
353
|
+
}], ctorParameters: () => [{ type: i0.NgZone }] });
|
|
354
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb3JkZXIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2RlYnVnLXJlY29yZGVyL3NyYy9saWIvc2VydmljZXMvcmVjb3JkZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFVLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBSXJFLE1BQU0sT0FBTyxlQUFlO0lBZTFCLFlBQW9CLElBQVk7UUFBWixTQUFJLEdBQUosSUFBSSxDQUFRO1FBZHhCLGlCQUFZLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdCLG9CQUFlLEdBQUcsTUFBTSxDQUEwQixJQUFJLENBQUMsQ0FBQztRQUN4RCxjQUFTLEdBQUcsTUFBTSxDQUFxQixFQUFFLENBQUMsQ0FBQztRQUMzQyxjQUFTLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWxDLGdCQUFXLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELGFBQVEsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDNUMsbUJBQWMsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDLENBQUM7UUFDeEQsYUFBUSxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUM1QyxnQkFBVyxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLEVBQUUsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsQ0FBQztRQUVsRSxjQUFTLEdBQStDLEVBQUUsQ0FBQztRQXdNM0QsbUJBQWMsR0FBRyxDQUFD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TUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgTmdab25lLCBzaWduYWwsIGNvbXB1dGVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEFjdGlvblR5cGUsIEVsZW1lbnRJbmZvLCBSZWNvcmRlZEFjdGlvbiwgUmVjb3JkaW5nU2Vzc2lvbiB9IGZyb20gJy4uL21vZGVscy9yZWNvcmRlZC1hY3Rpb24ubW9kZWwnO1xyXG5cclxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcclxuZXhwb3J0IGNsYXNzIFJlY29yZGVyU2VydmljZSB7XHJcbiAgcHJpdmF0ZSBfaXNSZWNvcmRpbmcgPSBzaWduYWwoZmFsc2UpO1xyXG4gIHByaXZhdGUgX2N1cnJlbnRTZXNzaW9uID0gc2lnbmFsPFJlY29yZGluZ1Nlc3Npb24gfCBudWxsPihudWxsKTtcclxuICBwcml2YXRlIF9zZXNzaW9ucyA9IHNpZ25hbDxSZWNvcmRpbmdTZXNzaW9uW10+KFtdKTtcclxuICBwcml2YXRlIF9pc1BhdXNlZCA9IHNpZ25hbChmYWxzZSk7XHJcblxyXG4gIGlzUmVjb3JkaW5nID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5faXNSZWNvcmRpbmcoKSk7XHJcbiAgaXNQYXVzZWQgPSBjb21wdXRlZCgoKSA9PiB0aGlzLl9pc1BhdXNlZCgpKTtcclxuICBjdXJyZW50U2Vzc2lvbiA9IGNvbXB1dGVkKCgpID0+IHRoaXMuX2N1cnJlbnRTZXNzaW9uKCkpO1xyXG4gIHNlc3Npb25zID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5fc2Vzc2lvbnMoKSk7XHJcbiAgYWN0aW9uQ291bnQgPSBjb21wdXRlZCgoKSA9PiB0aGlzLl9jdXJyZW50U2Vzc2lvbigpPy5hY3Rpb25zLmxlbmd0aCA/PyAwKTtcclxuXHJcbiAgcHJpdmF0ZSBsaXN0ZW5lcnM6IEFycmF5PHsgdHlwZTogc3RyaW5nOyBmbjogRXZlbnRMaXN0ZW5lciB9PiA9IFtdO1xyXG4gIHByaXZhdGUgbXV0YXRpb25PYnNlcnZlcj86IE11dGF0aW9uT2JzZXJ2ZXI7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgem9uZTogTmdab25lKSB7fVxyXG5cclxuICBzdGFydFJlY29yZGluZyhuYW1lPzogc3RyaW5nLCBkZXNjcmlwdGlvbj86IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3Qgc2Vzc2lvbjogUmVjb3JkaW5nU2Vzc2lvbiA9IHtcclxuICAgICAgaWQ6IHRoaXMuZ2VuZXJhdGVJZCgpLFxyXG4gICAgICBuYW1lOiBuYW1lIHx8IGBTZXNzaW9uICR7bmV3IERhdGUoKS50b0xvY2FsZVRpbWVTdHJpbmcoKX1gLFxyXG4gICAgICBkZXNjcmlwdGlvbixcclxuICAgICAgc3RhcnRUaW1lOiBEYXRlLm5vdygpLFxyXG4gICAgICBzdGFydFVybDogd2luZG93LmxvY2F0aW9uLmhyZWYsXHJcbiAgICAgIGFjdGlvbnM6IFtdLFxyXG4gICAgICB0YWdzOiBbXSxcclxuICAgIH07XHJcblxyXG4gICAgdGhpcy5fY3VycmVudFNlc3Npb24uc2V0KHNlc3Npb24pO1xyXG4gICAgdGhpcy5faXNSZWNvcmRpbmcuc2V0KHRydWUpO1xyXG4gICAgdGhpcy5faXNQYXVzZWQuc2V0KGZhbHNlKTtcclxuICAgIHRoaXMuYXR0YWNoTGlzdGVuZXJzKCk7XHJcbiAgICB0aGlzLnJlY29yZE5hdmlnYXRpb24oJ25hdmlnYXRpb24nLCB3aW5kb3cubG9jYXRpb24uaHJlZik7XHJcbiAgfVxyXG5cclxuICBzdG9wUmVjb3JkaW5nKCk6IFJlY29yZGluZ1Nlc3Npb24gfCBudWxsIHtcclxuICAgIGNvbnN0IHNlc3Npb24gPSB0aGlzLl9jdXJyZW50U2Vzc2lvbigpO1xyXG4gICAgaWYgKCFzZXNzaW9uKSByZXR1cm4gbnVsbDtcclxuXHJcbiAgICBjb25zdCBjb21wbGV0ZWQgPSB7IC4uLnNlc3Npb24sIGVuZFRpbWU6IERhdGUubm93KCkgfTtcclxuICAgIHRoaXMuX3Nlc3Npb25zLnVwZGF0ZShzID0+IFsuLi5zLCBjb21wbGV0ZWRdKTtcclxuICAgIHRoaXMuX2N1cnJlbnRTZXNzaW9uLnNldChudWxsKTtcclxuICAgIHRoaXMuX2lzUmVjb3JkaW5nLnNldChmYWxzZSk7XHJcbiAgICB0aGlzLl9pc1BhdXNlZC5zZXQoZmFsc2UpO1xyXG4gICAgdGhpcy5kZXRhY2hMaXN0ZW5lcnMoKTtcclxuICAgIHJldHVybiBjb21wbGV0ZWQ7XHJcbiAgfVxyXG5cclxuICBwYXVzZVJlY29yZGluZygpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLl9pc1JlY29yZGluZygpKSB7XHJcbiAgICAgIHRoaXMuX2lzUGF1c2VkLnNldCghdGhpcy5faXNQYXVzZWQoKSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjbGVhckN1cnJlbnRTZXNzaW9uKCk6IHZvaWQge1xyXG4gICAgdGhpcy5fY3VycmVudFNlc3Npb24udXBkYXRlKHMgPT4gcyA/IHsgLi4ucywgYWN0aW9uczogW10gfSA6IG51bGwpO1xyXG4gIH1cclxuXHJcbiAgcmVtb3ZlQWN0aW9uKGFjdGlvbklkOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuX2N1cnJlbnRTZXNzaW9uLnVwZGF0ZShzID0+XHJcbiAgICAgIHMgPyB7IC4uLnMsIGFjdGlvbnM6IHMuYWN0aW9ucy5maWx0ZXIoYSA9PiBhLmlkICE9PSBhY3Rpb25JZCkgfSA6IG51bGxcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBhZGROb3RlKGFjdGlvbklkOiBzdHJpbmcsIG5vdGU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5fY3VycmVudFNlc3Npb24udXBkYXRlKHMgPT5cclxuICAgICAgcyA/IHtcclxuICAgICAgICAuLi5zLFxyXG4gICAgICAgIGFjdGlvbnM6IHMuYWN0aW9ucy5tYXAoYSA9PiBhLmlkID09PSBhY3Rpb25JZCA/IHsgLi4uYSwgbm90ZSB9IDogYSlcclxuICAgICAgfSA6IG51bGxcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBkZWxldGVTZXNzaW9uKHNlc3Npb25JZDogc3RyaW5nKTogdm9pZCB7XHJcbiAgICB0aGlzLl9zZXNzaW9ucy51cGRhdGUocyA9PiBzLmZpbHRlcih4ID0+IHguaWQgIT09IHNlc3Npb25JZCkpO1xyXG4gIH1cclxuXHJcbiAgbG9hZFNlc3Npb24oc2Vzc2lvbjogUmVjb3JkaW5nU2Vzc2lvbik6IHZvaWQge1xyXG4gICAgdGhpcy5fY3VycmVudFNlc3Npb24uc2V0KHNlc3Npb24pO1xyXG4gIH1cclxuXHJcbiAgLy8g4pSA4pSA4pSAIEV2ZW50IExpc3RlbmVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuXHJcbiAgcHJpdmF0ZSBhdHRhY2hMaXN0ZW5lcnMoKTogdm9pZCB7XHJcbiAgICBjb25zdCBvcHRzID0geyBjYXB0dXJlOiB0cnVlLCBwYXNzaXZlOiB0cnVlIH07XHJcblxyXG4gICAgY29uc3Qgb25DbGljayA9IChlOiBNb3VzZUV2ZW50KSA9PiB0aGlzLnpvbmUucnVuKCgpID0+IHRoaXMuaGFuZGxlQ2xpY2soZSkpO1xyXG4gICAgY29uc3Qgb25EYmxDbGljayA9IChlOiBNb3VzZUV2ZW50KSA9PiB0aGlzLnpvbmUucnVuKCgpID0+IHRoaXMuaGFuZGxlRGJsQ2xpY2soZSkpO1xyXG4gICAgY29uc3Qgb25JbnB1dCA9IChlOiBFdmVudCkgPT4gdGhpcy56b25lLnJ1bigoKSA9PiB0aGlzLmhhbmRsZUlucHV0KGUpKTtcclxuICAgIGNvbnN0IG9uQ2hhbmdlID0gKGU6IEV2ZW50KSA9PiB0aGlzLnpvbmUucnVuKCgpID0+IHRoaXMuaGFuZGxlQ2hhbmdlKGUpKTtcclxuICAgIGNvbnN0IG9uU3VibWl0ID0gKGU6IFN1Ym1pdEV2ZW50KSA9PiB0aGlzLnpvbmUucnVuKCgpID0+IHRoaXMuaGFuZGxlU3VibWl0KGUpKTtcclxuICAgIGNvbnN0IG9uS2V5ZG93biA9IChlOiBLZXlib2FyZEV2ZW50KSA9PiB0aGlzLnpvbmUucnVuKCgpID0+IHRoaXMuaGFuZGxlS2V5ZG93bihlKSk7XHJcbiAgICBjb25zdCBvblNjcm9sbCA9IChlOiBFdmVudCkgPT4gdGhpcy56b25lLnJ1bigoKSA9PiB0aGlzLmhhbmRsZVNjcm9sbChlKSk7XHJcblxyXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBvbkNsaWNrLCBvcHRzKTtcclxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2RibGNsaWNrJywgb25EYmxDbGljaywgb3B0cyk7XHJcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsIG9uSW5wdXQsIG9wdHMpO1xyXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgb25DaGFuZ2UsIG9wdHMpO1xyXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignc3VibWl0Jywgb25TdWJtaXQsIG9wdHMpO1xyXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIG9uS2V5ZG93biwgb3B0cyk7XHJcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdzY3JvbGwnLCBvblNjcm9sbCwgeyBjYXB0dXJlOiB0cnVlLCBwYXNzaXZlOiB0cnVlIH0pO1xyXG5cclxuICAgIHRoaXMubGlzdGVuZXJzID0gW1xyXG4gICAgICB7IHR5cGU6ICdjbGljaycsIGZuOiBvbkNsaWNrIGFzIEV2ZW50TGlzdGVuZXIgfSxcclxuICAgICAgeyB0eXBlOiAnZGJsY2xpY2snLCBmbjogb25EYmxDbGljayBhcyBFdmVudExpc3RlbmVyIH0sXHJcbiAgICAgIHsgdHlwZTogJ2lucHV0JywgZm46IG9uSW5wdXQgYXMgRXZlbnRMaXN0ZW5lciB9LFxyXG4gICAgICB7IHR5cGU6ICdjaGFuZ2UnLCBmbjogb25DaGFuZ2UgYXMgRXZlbnRMaXN0ZW5lciB9LFxyXG4gICAgICB7IHR5cGU6ICdzdWJtaXQnLCBmbjogb25TdWJtaXQgYXMgRXZlbnRMaXN0ZW5lciB9LFxyXG4gICAgICB7IHR5cGU6ICdrZXlkb3duJywgZm46IG9uS2V5ZG93biBhcyBFdmVudExpc3RlbmVyIH0sXHJcbiAgICAgIHsgdHlwZTogJ3Njcm9sbCcsIGZuOiBvblNjcm9sbCBhcyBFdmVudExpc3RlbmVyIH0sXHJcbiAgICBdO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBkZXRhY2hMaXN0ZW5lcnMoKTogdm9pZCB7XHJcbiAgICB0aGlzLmxpc3RlbmVycy5mb3JFYWNoKCh7IHR5cGUsIGZuIH0pID0+XHJcbiAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIodHlwZSwgZm4sIHRydWUpXHJcbiAgICApO1xyXG4gICAgdGhpcy5saXN0ZW5lcnMgPSBbXTtcclxuICAgIHRoaXMubXV0YXRpb25PYnNlcnZlcj8uZGlzY29ubmVjdCgpO1xyXG4gIH1cclxuXHJcbiAgLy8g4pSA4pSA4pSAIEhhbmRsZXJzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxyXG5cclxuICBwcml2YXRlIGhhbmRsZUNsaWNrKGU6IE1vdXNlRXZlbnQpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5zaG91bGRSZWNvcmQoZS50YXJnZXQgYXMgRWxlbWVudCkpIHJldHVybjtcclxuICAgIGNvbnN0IGVsID0gZS50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBjb25zdCBpbmZvID0gdGhpcy5nZXRFbGVtZW50SW5mbyhlbCk7XHJcbiAgICBjb25zdCBzZWxlY3RvciA9IHRoaXMuYnVpbGRTZWxlY3RvcihlbCk7XHJcblxyXG4gICAgdGhpcy5hZGRBY3Rpb24oe1xyXG4gICAgICB0eXBlOiAnY2xpY2snLFxyXG4gICAgICBzZWxlY3RvcixcclxuICAgICAgc2VsZWN0b3JTdHJhdGVneTogdGhpcy5nZXRTZWxlY3RvclN0cmF0ZWd5KGVsKSxcclxuICAgICAgZWxlbWVudDogaW5mbyxcclxuICAgICAgZGVzY3JpcHRpb246IGBDbGljayBvbiAke3RoaXMuZGVzY3JpYmVFbGVtZW50KGluZm8pfWAsXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGFuZGxlRGJsQ2xpY2soZTogTW91c2VFdmVudCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnNob3VsZFJlY29yZChlLnRhcmdldCBhcyBFbGVtZW50KSkgcmV0dXJuO1xyXG4gICAgY29uc3QgZWwgPSBlLnRhcmdldCBhcyBIVE1MRWxlbWVudDtcclxuICAgIGNvbnN0IGluZm8gPSB0aGlzLmdldEVsZW1lbnRJbmZvKGVsKTtcclxuICAgIGNvbnN0IHNlbGVjdG9yID0gdGhpcy5idWlsZFNlbGVjdG9yKGVsKTtcclxuXHJcbiAgICB0aGlzLmFkZEFjdGlvbih7XHJcbiAgICAgIHR5cGU6ICdkYmxjbGljaycsXHJcbiAgICAgIHNlbGVjdG9yLFxyXG4gICAgICBzZWxlY3RvclN0cmF0ZWd5OiB0aGlzLmdldFNlbGVjdG9yU3RyYXRlZ3koZWwpLFxyXG4gICAgICBlbGVtZW50OiBpbmZvLFxyXG4gICAgICBkZXNjcmlwdGlvbjogYERvdWJsZS1jbGljayBvbiAke3RoaXMuZGVzY3JpYmVFbGVtZW50KGluZm8pfWAsXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGFuZGxlSW5wdXQoZTogRXZlbnQpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5zaG91bGRSZWNvcmQoZS50YXJnZXQgYXMgRWxlbWVudCkpIHJldHVybjtcclxuICAgIGNvbnN0IGVsID0gZS50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCB8IEhUTUxUZXh0QXJlYUVsZW1lbnQ7XHJcbiAgICBpZiAoWydjaGVja2JveCcsICdyYWRpbyddLmluY2x1ZGVzKGVsLnR5cGUpKSByZXR1cm47IC8vIGhhbmRsZWQgYnkgY2hhbmdlXHJcbiAgICBjb25zdCBpbmZvID0gdGhpcy5nZXRFbGVtZW50SW5mbyhlbCk7XHJcbiAgICBjb25zdCBzZWxlY3RvciA9IHRoaXMuYnVpbGRTZWxlY3RvcihlbCk7XHJcblxyXG4gICAgdGhpcy5hZGRBY3Rpb24oe1xyXG4gICAgICB0eXBlOiAnaW5wdXQnLFxyXG4gICAgICBzZWxlY3RvcixcclxuICAgICAgc2VsZWN0b3JTdHJhdGVneTogdGhpcy5nZXRTZWxlY3RvclN0cmF0ZWd5KGVsKSxcclxuICAgICAgZWxlbWVudDogaW5mbyxcclxuICAgICAgdmFsdWU6IGVsLnZhbHVlLFxyXG4gICAgICBkZXNjcmlwdGlvbjogYFR5cGUgXCIke2VsLnZhbHVlfVwiIGluICR7dGhpcy5kZXNjcmliZUVsZW1lbnQoaW5mbyl9YCxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVDaGFuZ2UoZTogRXZlbnQpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5zaG91bGRSZWNvcmQoZS50YXJnZXQgYXMgRWxlbWVudCkpIHJldHVybjtcclxuICAgIGNvbnN0IGVsID0gZS50YXJnZXQgYXMgSFRNTFNlbGVjdEVsZW1lbnQgfCBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgY29uc3QgaW5mbyA9IHRoaXMuZ2V0RWxlbWVudEluZm8oZWwpO1xyXG4gICAgY29uc3Qgc2VsZWN0b3IgPSB0aGlzLmJ1aWxkU2VsZWN0b3IoZWwpO1xyXG5cclxuICAgIGlmIChlbC50YWdOYW1lID09PSAnU0VMRUNUJykge1xyXG4gICAgICB0aGlzLmFkZEFjdGlvbih7XHJcbiAgICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgICAgc2VsZWN0b3IsXHJcbiAgICAgICAgc2VsZWN0b3JTdHJhdGVneTogdGhpcy5nZXRTZWxlY3RvclN0cmF0ZWd5KGVsKSxcclxuICAgICAgICBlbGVtZW50OiBpbmZvLFxyXG4gICAgICAgIHZhbHVlOiBlbC52YWx1ZSxcclxuICAgICAgICBkZXNjcmlwdGlvbjogYFNlbGVjdCBcIiR7ZWwudmFsdWV9XCIgaW4gJHt0aGlzLmRlc2NyaWJlRWxlbWVudChpbmZvKX1gLFxyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSBpZiAoKGVsIGFzIEhUTUxJbnB1dEVsZW1lbnQpLnR5cGUgPT09ICdjaGVja2JveCcpIHtcclxuICAgICAgdGhpcy5hZGRBY3Rpb24oe1xyXG4gICAgICAgIHR5cGU6ICdjbGljaycsXHJcbiAgICAgICAgc2VsZWN0b3IsXHJcbiAgICAgICAgc2VsZWN0b3JTdHJhdGVneTogdGhpcy5nZXRTZWxlY3RvclN0cmF0ZWd5KGVsKSxcclxuICAgICAgICBlbGVtZW50OiBpbmZvLFxyXG4gICAgICAgIHZhbHVlOiBTdHJpbmcoKGVsIGFzIEhUTUxJbnB1dEVsZW1lbnQpLmNoZWNrZWQpLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHsoZWwgYXMgSFRNTElucHV0RWxlbWVudCkuY2hlY2tlZCA/ICdDaGVjaycgOiAnVW5jaGVjayd9ICR7dGhpcy5kZXNjcmliZUVsZW1lbnQoaW5mbyl9YCxcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZVN1Ym1pdChlOiBTdWJtaXRFdmVudCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnNob3VsZFJlY29yZChlLnRhcmdldCBhcyBFbGVtZW50KSkgcmV0dXJuO1xyXG4gICAgY29uc3QgZm9ybSA9IGUudGFyZ2V0IGFzIEhUTUxGb3JtRWxlbWVudDtcclxuICAgIGNvbnN0IGluZm8gPSB0aGlzLmdldEVsZW1lbnRJbmZvKGZvcm0pO1xyXG4gICAgY29uc3Qgc2VsZWN0b3IgPSB0aGlzLmJ1aWxkU2VsZWN0b3IoZm9ybSk7XHJcblxyXG4gICAgdGhpcy5hZGRBY3Rpb24oe1xyXG4gICAgICB0eXBlOiAnc3VibWl0JyxcclxuICAgICAgc2VsZWN0b3IsXHJcbiAgICAgIHNlbGVjdG9yU3RyYXRlZ3k6IHRoaXMuZ2V0U2VsZWN0b3JTdHJhdGVneShmb3JtKSxcclxuICAgICAgZWxlbWVudDogaW5mbyxcclxuICAgICAgZGVzY3JpcHRpb246IGBTdWJtaXQgZm9ybSAke2luZm8uaWQgPyAnIycgKyBpbmZvLmlkIDogaW5mby5uYW1lID8gaW5mby5uYW1lIDogJyd9YC50cmltKCksXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgbGFzdFNjcm9sbFRpbWUgPSAwO1xyXG4gIHByaXZhdGUgaGFuZGxlU2Nyb2xsKGU6IEV2ZW50KTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuc2hvdWxkUmVjb3JkKGUudGFyZ2V0IGFzIEVsZW1lbnQpKSByZXR1cm47XHJcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xyXG4gICAgaWYgKG5vdyAtIHRoaXMubGFzdFNjcm9sbFRpbWUgPCAxMDAwKSByZXR1cm47IC8vIGRlYm91bmNlIDFzXHJcbiAgICB0aGlzLmxhc3RTY3JvbGxUaW1lID0gbm93O1xyXG5cclxuICAgIGNvbnN0IGVsID0gZS50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBjb25zdCBpc0RvYyA9ICFlbC50YWdOYW1lIHx8IGVsLnRhZ05hbWUgPT09ICdIVE1MJztcclxuICAgIGNvbnN0IHNjcm9sbFkgPSBpc0RvYyA/IHdpbmRvdy5zY3JvbGxZIDogZWwuc2Nyb2xsVG9wO1xyXG4gICAgY29uc3Qgc2Nyb2xsWCA9IGlzRG9jID8gd2luZG93LnNjcm9sbFggOiBlbC5zY3JvbGxMZWZ0O1xyXG5cclxuICAgIGNvbnN0IHNlbGVjdG9yID0gZWwudGFnTmFtZSA9PT0gJ0hUTUwnIHx8IGVsLnRhZ05hbWUgPT09ICdCT0RZJ1xyXG4gICAgICA/ICd3aW5kb3cnXHJcbiAgICAgIDogdGhpcy5idWlsZFNlbGVjdG9yKGVsKTtcclxuXHJcbiAgICB0aGlzLmFkZEFjdGlvbih7XHJcbiAgICAgIHR5cGU6ICdzY3JvbGwnLFxyXG4gICAgICBzZWxlY3RvcixcclxuICAgICAgc2VsZWN0b3JTdHJhdGVneTogJ2NvbWJpbmVkJyxcclxuICAgICAgdmFsdWU6IGAke3Njcm9sbFh9LCR7c2Nyb2xsWX1gLFxyXG4gICAgICBkZXNjcmlwdGlvbjogYFNjcm9sbCB0byAoJHtzY3JvbGxYfSwgJHtzY3JvbGxZfSlgLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZUtleWRvd24oZTogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xyXG4gICAgY29uc3Qgc3BlY2lhbEtleXMgPSBbJ0VudGVyJywgJ0VzY2FwZScsICdUYWInLCAnRjUnLCAnRjEyJ107XHJcbiAgICBpZiAoIXNwZWNpYWxLZXlzLmluY2x1ZGVzKGUua2V5KSkgcmV0dXJuO1xyXG4gICAgaWYgKCF0aGlzLnNob3VsZFJlY29yZChlLnRhcmdldCBhcyBFbGVtZW50KSkgcmV0dXJuO1xyXG5cclxuICAgIGNvbnN0IGVsID0gZS50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBjb25zdCBzZWxlY3RvciA9IHRoaXMuYnVpbGRTZWxlY3RvcihlbCk7XHJcblxyXG4gICAgdGhpcy5hZGRBY3Rpb24oe1xyXG4gICAgICB0eXBlOiAna2V5cHJlc3MnLFxyXG4gICAgICBzZWxlY3RvcixcclxuICAgICAgc2VsZWN0b3JTdHJhdGVneTogdGhpcy5nZXRTZWxlY3RvclN0cmF0ZWd5KGVsKSxcclxuICAgICAgdmFsdWU6IGUua2V5LFxyXG4gICAgICBkZXNjcmlwdGlvbjogYFByZXNzIFwiJHtlLmtleX1cIiBvbiAke2VsLnRhZ05hbWUudG9Mb3dlckNhc2UoKX1gLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlY29yZE5hdmlnYXRpb24odHlwZTogQWN0aW9uVHlwZSwgbmF2VXJsOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGNvbnN0IGFjdGlvbjogUmVjb3JkZWRBY3Rpb24gPSB7XHJcbiAgICAgIGlkOiB0aGlzLmdlbmVyYXRlSWQoKSxcclxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxyXG4gICAgICB1cmw6IG5hdlVybCxcclxuICAgICAgdHlwZSxcclxuICAgICAgc2VsZWN0b3I6ICd3aW5kb3cnLFxyXG4gICAgICBzZWxlY3RvclN0cmF0ZWd5OiAnY29tYmluZWQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogYE5hdmlnYXRlIHRvICR7bmF2VXJsfWAsXHJcbiAgICB9O1xyXG4gICAgdGhpcy5fY3VycmVudFNlc3Npb24udXBkYXRlKHMgPT5cclxuICAgICAgcyA/IHsgLi4ucywgYWN0aW9uczogWy4uLnMuYWN0aW9ucywgYWN0aW9uXSB9IDogc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIOKUgOKUgOKUgCBTZWxlY3RvciBCdWlsZGluZyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuXHJcbiAgcHJpdmF0ZSBidWlsZFNlbGVjdG9yKGVsOiBIVE1MRWxlbWVudCk6IHN0cmluZyB7XHJcbiAgICAvLyBQcmlvcml0eTogZGF0YS10ZXN0aWQgPiBkYXRhLWN5ID4gaWQgPiBuYW1lID4gYXJpYS1sYWJlbCA+IGNvbWJpbmVkXHJcbiAgICBjb25zdCB0ZXN0SWQgPSBlbC5nZXRBdHRyaWJ1dGUoJ2RhdGEtdGVzdGlkJyk7XHJcbiAgICBpZiAodGVzdElkKSByZXR1cm4gYFtkYXRhLXRlc3RpZD1cIiR7dGVzdElkfVwiXWA7XHJcblxyXG4gICAgY29uc3QgY3kgPSBlbC5nZXRBdHRyaWJ1dGUoJ2RhdGEtY3knKTtcclxuICAgIGlmIChjeSkgcmV0dXJuIGBbZGF0YS1jeT1cIiR7Y3l9XCJdYDtcclxuXHJcbiAgICBpZiAoZWwuaWQgJiYgIWVsLmlkLmluY2x1ZGVzKCc6JykpIHJldHVybiBgIyR7ZWwuaWR9YDtcclxuXHJcbiAgICBjb25zdCBuYW1lID0gZWwuZ2V0QXR0cmlidXRlKCduYW1lJyk7XHJcbiAgICBpZiAobmFtZSkgcmV0dXJuIGAke2VsLnRhZ05hbWUudG9Mb3dlckNhc2UoKX1bbmFtZT1cIiR7bmFtZX1cIl1gO1xyXG5cclxuICAgIGNvbnN0IGFyaWFMYWJlbCA9IGVsLmdldEF0dHJpYnV0ZSgnYXJpYS1sYWJlbCcpO1xyXG4gICAgaWYgKGFyaWFMYWJlbCkgcmV0dXJuIGBbYXJpYS1sYWJlbD1cIiR7YXJpYUxhYmVsfVwiXWA7XHJcblxyXG4gICAgLy8gQ2xhc3MtYmFzZWQgZmFsbGJhY2tcclxuICAgIGNvbnN0IHJlbGV2YW50Q2xhc3NlcyA9IEFycmF5LmZyb20oZWwuY2xhc3NMaXN0KVxyXG4gICAgICAuZmlsdGVyKGMgPT4gIWMuc3RhcnRzV2l0aCgnbmctJykgJiYgIWMuc3RhcnRzV2l0aCgnY2RrLScpICYmIGMubGVuZ3RoID4gMClcclxuICAgICAgLnNsaWNlKDAsIDMpO1xyXG4gICAgaWYgKHJlbGV2YW50Q2xhc3Nlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIHJldHVybiBgJHtlbC50YWdOYW1lLnRvTG93ZXJDYXNlKCl9LiR7cmVsZXZhbnRDbGFzc2VzLmpvaW4oJy4nKX1gO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRleHQgY29udGVudCBmb3IgYnV0dG9ucy9saW5rc1xyXG4gICAgaWYgKFsnQlVUVE9OJywgJ0EnXS5pbmNsdWRlcyhlbC50YWdOYW1lKSkge1xyXG4gICAgICBjb25zdCB0ZXh0ID0gZWwudGV4dENvbnRlbnQ/LnRyaW0oKS5zbGljZSgwLCAzMCk7XHJcbiAgICAgIGlmICh0ZXh0KSByZXR1cm4gYCR7ZWwudGFnTmFtZS50b0xvd2VyQ2FzZSgpfTpjb250YWlucyhcIiR7dGV4dH1cIilgO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBlbC50YWdOYW1lLnRvTG93ZXJDYXNlKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldFNlbGVjdG9yU3RyYXRlZ3koZWw6IEhUTUxFbGVtZW50KTogUmVjb3JkZWRBY3Rpb25bJ3NlbGVjdG9yU3RyYXRlZ3knXSB7XHJcbiAgICBpZiAoZWwuZ2V0QXR0cmlidXRlKCdkYXRhLXRlc3RpZCcpKSByZXR1cm4gJ2RhdGEtdGVzdGlkJztcclxuICAgIGlmIChlbC5nZXRBdHRyaWJ1dGUoJ2RhdGEtY3knKSkgcmV0dXJuICdkYXRhLWN5JztcclxuICAgIGlmIChlbC5pZCkgcmV0dXJuICdpZCc7XHJcbiAgICBpZiAoZWwuZ2V0QXR0cmlidXRlKCduYW1lJykpIHJldHVybiAnbmFtZSc7XHJcbiAgICByZXR1cm4gJ2NsYXNzJztcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0RWxlbWVudEluZm8oZWw6IEhUTUxFbGVtZW50KTogRWxlbWVudEluZm8ge1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdGFnTmFtZTogZWwudGFnTmFtZS50b0xvd2VyQ2FzZSgpLFxyXG4gICAgICBpZDogZWwuaWQgfHwgdW5kZWZpbmVkLFxyXG4gICAgICBjbGFzc2VzOiBBcnJheS5mcm9tKGVsLmNsYXNzTGlzdCkuZmlsdGVyKGMgPT4gIWMuc3RhcnRzV2l0aCgnbmctJykpLFxyXG4gICAgICBkYXRhVGVzdElkOiBlbC5nZXRBdHRyaWJ1dGUoJ2RhdGEtdGVzdGlkJykgfHwgdW5kZWZpbmVkLFxyXG4gICAgICBkYXRhQ3k6IGVsLmdldEF0dHJpYnV0ZSgnZGF0YS1jeScpIHx8IHVuZGVmaW5lZCxcclxuICAgICAgbmFtZTogZWwuZ2V0QXR0cmlidXRlKCduYW1lJykgfHwgdW5kZWZpbmVkLFxyXG4gICAgICB0eXBlOiBlbC5nZXRBdHRyaWJ1dGUoJ3R5cGUnKSB8fCB1bmRlZmluZWQsXHJcbiAgICAgIHBsYWNlaG9sZGVyOiBlbC5nZXRBdHRyaWJ1dGUoJ3BsYWNlaG9sZGVyJykgfHwgdW5kZWZpbmVkLFxyXG4gICAgICB0ZXh0OiBlbC50ZXh0Q29udGVudD8udHJpbSgpLnNsaWNlKDAsIDUwKSB8fCB1bmRlZmluZWQsXHJcbiAgICAgIGhyZWY6IChlbCBhcyBIVE1MQW5jaG9yRWxlbWVudCkuaHJlZiB8fCB1bmRlZmluZWQsXHJcbiAgICAgIGFyaWFMYWJlbDogZWwuZ2V0QXR0cmlidXRlKCdhcmlhLWxhYmVsJykgfHwgdW5kZWZpbmVkLFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZGVzY3JpYmVFbGVtZW50KGluZm86IEVsZW1lbnRJbmZvKTogc3RyaW5nIHtcclxuICAgIGlmIChpbmZvLmRhdGFUZXN0SWQpIHJldHVybiBgW2RhdGEtdGVzdGlkPVwiJHtpbmZvLmRhdGFUZXN0SWR9XCJdYDtcclxuICAgIGlmIChpbmZvLmRhdGFDeSkgcmV0dXJuIGBbZGF0YS1jeT1cIiR7aW5mby5kYXRhQ3l9XCJdYDtcclxuICAgIGlmIChpbmZvLmlkKSByZXR1cm4gYCMke2luZm8uaWR9YDtcclxuICAgIGlmIChpbmZvLmFyaWFMYWJlbCkgcmV0dXJuIGBcIiR7aW5mby5hcmlhTGFiZWx9XCJgO1xyXG4gICAgaWYgKGluZm8ucGxhY2Vob2xkZXIpIHJldHVybiBgXCIke2luZm8ucGxhY2Vob2xkZXJ9XCIgaW5wdXRgO1xyXG4gICAgaWYgKGluZm8udGV4dCkgcmV0dXJuIGBcIiR7aW5mby50ZXh0fVwiYDtcclxuICAgIHJldHVybiBpbmZvLnRhZ05hbWU7XHJcbiAgfVxyXG5cclxuICAvLyDilIDilIDilIAgSGVscGVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuXHJcbiAgcHJpdmF0ZSBzaG91bGRSZWNvcmQodGFyZ2V0OiBFbGVtZW50IHwgbnVsbCk6IGJvb2xlYW4ge1xyXG4gICAgaWYgKCF0aGlzLl9pc1JlY29yZGluZygpIHx8IHRoaXMuX2lzUGF1c2VkKCkpIHJldHVybiBmYWxzZTtcclxuICAgIGlmICghdGFyZ2V0KSByZXR1cm4gZmFsc2U7XHJcbiAgICAvLyBJZ25vcmUgdGhlIGRlYnVnIHBhbmVsIGl0c2VsZlxyXG4gICAgaWYgKHRhcmdldC5jbG9zZXN0KCdbZGF0YS1kZWJ1Zy1wYW5lbF0nKSkgcmV0dXJuIGZhbHNlO1xyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFkZEFjdGlvbihwYXJ0aWFsOiBPbWl0PFJlY29yZGVkQWN0aW9uLCAnaWQnIHwgJ3RpbWVzdGFtcCcgfCAndXJsJz4pOiB2b2lkIHtcclxuICAgIGNvbnN0IGFjdGlvbjogUmVjb3JkZWRBY3Rpb24gPSB7XHJcbiAgICAgIGlkOiB0aGlzLmdlbmVyYXRlSWQoKSxcclxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxyXG4gICAgICB1cmw6IHdpbmRvdy5sb2NhdGlvbi5ocmVmLFxyXG4gICAgICAuLi5wYXJ0aWFsLFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBEZWR1cGxpY2F0ZSBjb25zZWN1dGl2ZSBpZGVudGljYWwgaW5wdXRzIChrZWVwIG9ubHkgbGF0ZXN0IHZhbHVlKVxyXG4gICAgaWYgKGFjdGlvbi50eXBlID09PSAnaW5wdXQnKSB7XHJcbiAgICAgIHRoaXMuX2N1cnJlbnRTZXNzaW9uLnVwZGF0ZShzID0+IHtcclxuICAgICAgICBpZiAoIXMpIHJldHVybiBzO1xyXG4gICAgICAgIGNvbnN0IGxhc3QgPSBzLmFjdGlvbnNbcy5hY3Rpb25zLmxlbmd0aCAtIDFdO1xyXG4gICAgICAgIGlmIChsYXN0Py50eXBlID09PSAnaW5wdXQnICYmIGxhc3Quc2VsZWN0b3IgPT09IGFjdGlvbi5zZWxlY3Rvcikge1xyXG4gICAgICAgICAgcmV0dXJuIHsgLi4ucywgYWN0aW9uczogWy4uLnMuYWN0aW9ucy5zbGljZSgwLCAtMSksIGFjdGlvbl0gfTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHsgLi4ucywgYWN0aW9uczogWy4uLnMuYWN0aW9ucywgYWN0aW9uXSB9O1xyXG4gICAgICB9KTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX2N1cnJlbnRTZXNzaW9uLnVwZGF0ZShzID0+XHJcbiAgICAgIHMgPyB7IC4uLnMsIGFjdGlvbnM6IFsuLi5zLmFjdGlvbnMsIGFjdGlvbl0gfSA6IHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdlbmVyYXRlSWQoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zbGljZSgyLCAxMSk7XHJcbiAgfVxyXG59XHJcbiJdfQ==
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Injectable, signal } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class RrwebRecorderService {
|
|
4
|
+
constructor(zone) {
|
|
5
|
+
this.zone = zone;
|
|
6
|
+
this._events = signal([]);
|
|
7
|
+
this._isRecording = signal(false);
|
|
8
|
+
this.events = this._events.asReadonly();
|
|
9
|
+
this.isRecording = this._isRecording.asReadonly();
|
|
10
|
+
}
|
|
11
|
+
async startRecording() {
|
|
12
|
+
// Dynamically import rrweb to avoid SSR issues and reduce initial bundle
|
|
13
|
+
const { record } = await import('rrweb');
|
|
14
|
+
this._events.set([]);
|
|
15
|
+
this._isRecording.set(true);
|
|
16
|
+
this.stopFn = record({
|
|
17
|
+
emit: (event) => {
|
|
18
|
+
this.zone.run(() => {
|
|
19
|
+
this._events.update(ev => [...ev, event]);
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
// Note: blockSelector is omitted — rrweb 2.0.0-alpha.4 calls node.matches()
|
|
23
|
+
// on TextNodes/CommentNodes which don't have that method, crashing the recorder.
|
|
24
|
+
maskTextSelector: 'input[type="password"]',
|
|
25
|
+
checkoutEveryNth: 200,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
stopRecording() {
|
|
29
|
+
if (this.stopFn) {
|
|
30
|
+
this.stopFn();
|
|
31
|
+
this.stopFn = undefined;
|
|
32
|
+
}
|
|
33
|
+
this._isRecording.set(false);
|
|
34
|
+
return this._events();
|
|
35
|
+
}
|
|
36
|
+
getEvents() {
|
|
37
|
+
return this._events();
|
|
38
|
+
}
|
|
39
|
+
clearEvents() {
|
|
40
|
+
this._events.set([]);
|
|
41
|
+
}
|
|
42
|
+
hasEvents() {
|
|
43
|
+
return this._events().length > 0;
|
|
44
|
+
}
|
|
45
|
+
// ─── Replay ──────────────────────────────────────────────────────────────
|
|
46
|
+
async startReplay(container, events) {
|
|
47
|
+
const { Replayer } = await import('rrweb');
|
|
48
|
+
const eventsToReplay = events ?? this._events();
|
|
49
|
+
if (eventsToReplay.length === 0)
|
|
50
|
+
return;
|
|
51
|
+
// Destroy previous replayer
|
|
52
|
+
this.destroyReplayer();
|
|
53
|
+
this.replayer = new Replayer(eventsToReplay, {
|
|
54
|
+
root: container,
|
|
55
|
+
skipInactive: true,
|
|
56
|
+
showWarning: false,
|
|
57
|
+
showDebug: false,
|
|
58
|
+
blockClass: 'debug-panel',
|
|
59
|
+
});
|
|
60
|
+
this.replayer.play();
|
|
61
|
+
}
|
|
62
|
+
pauseReplay() {
|
|
63
|
+
this.replayer?.pause();
|
|
64
|
+
}
|
|
65
|
+
resumeReplay() {
|
|
66
|
+
this.replayer?.play();
|
|
67
|
+
}
|
|
68
|
+
destroyReplayer() {
|
|
69
|
+
if (this.replayer) {
|
|
70
|
+
try {
|
|
71
|
+
this.replayer.pause();
|
|
72
|
+
}
|
|
73
|
+
catch { }
|
|
74
|
+
this.replayer = undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// ─── Export ───────────────────────────────────────────────────────────────
|
|
78
|
+
exportEvents() {
|
|
79
|
+
return JSON.stringify(this._events(), null, 2);
|
|
80
|
+
}
|
|
81
|
+
downloadEvents(filename = 'rrweb-session.json') {
|
|
82
|
+
const blob = new Blob([this.exportEvents()], { type: 'application/json' });
|
|
83
|
+
const url = URL.createObjectURL(blob);
|
|
84
|
+
const a = document.createElement('a');
|
|
85
|
+
a.href = url;
|
|
86
|
+
a.download = filename;
|
|
87
|
+
a.click();
|
|
88
|
+
URL.revokeObjectURL(url);
|
|
89
|
+
}
|
|
90
|
+
importEvents(json) {
|
|
91
|
+
try {
|
|
92
|
+
const events = JSON.parse(json);
|
|
93
|
+
this._events.set(events);
|
|
94
|
+
return events;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
console.error('Invalid rrweb events JSON');
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RrwebRecorderService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
102
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RrwebRecorderService, providedIn: 'root' }); }
|
|
103
|
+
}
|
|
104
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RrwebRecorderService, decorators: [{
|
|
105
|
+
type: Injectable,
|
|
106
|
+
args: [{ providedIn: 'root' }]
|
|
107
|
+
}], ctorParameters: () => [{ type: i0.NgZone }] });
|
|
108
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnJ3ZWItcmVjb3JkZXIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2RlYnVnLXJlY29yZGVyL3NyYy9saWIvc2VydmljZXMvcnJ3ZWItcmVjb3JkZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFVLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUFJM0QsTUFBTSxPQUFPLG9CQUFvQjtJQVMvQixZQUFvQixJQUFZO1FBQVosU0FBSSxHQUFKLElBQUksQ0FBUTtRQVJ4QixZQUFPLEdBQUcsTUFBTSxDQUFrQixFQUFFLENBQUMsQ0FBQztRQUN0QyxpQkFBWSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUlyQyxXQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNuQyxnQkFBVyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLENBQUM7SUFFVixDQUFDO0lBRXBDLEtBQUssQ0FBQyxjQUFjO1FBQ2xCLHlFQUF5RTtRQUN6RSxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDekMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDckIsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFNUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7WUFDbkIsSUFBSSxFQUFFLENBQUMsS0FBb0IsRUFBRSxFQUFFO2dCQUM3QixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7b0JBQ2pCLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxLQUFLLENBQUMs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UUFDdEIsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1YsR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMzQixDQUFDO0lBRUQsWUFBWSxDQUFDLElBQVk7UUFDdkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQW9CLENBQUM7WUFDbkQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDekIsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQztZQUMzQyxPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7SUFDSCxDQUFDOytHQWpIVSxvQkFBb0I7bUhBQXBCLG9CQUFvQixjQURQLE1BQU07OzRGQUNuQixvQkFBb0I7a0JBRGhDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgTmdab25lLCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHR5cGUgeyBldmVudFdpdGhUaW1lIH0gZnJvbSAnQHJyd2ViL3R5cGVzJztcclxuXHJcbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXHJcbmV4cG9ydCBjbGFzcyBScndlYlJlY29yZGVyU2VydmljZSB7XHJcbiAgcHJpdmF0ZSBfZXZlbnRzID0gc2lnbmFsPGV2ZW50V2l0aFRpbWVbXT4oW10pO1xyXG4gIHByaXZhdGUgX2lzUmVjb3JkaW5nID0gc2lnbmFsKGZhbHNlKTtcclxuICBwcml2YXRlIHN0b3BGbj86ICgpID0+IHZvaWQ7XHJcbiAgcHJpdmF0ZSByZXBsYXllcj86IGFueTtcclxuXHJcbiAgZXZlbnRzID0gdGhpcy5fZXZlbnRzLmFzUmVhZG9ubHkoKTtcclxuICBpc1JlY29yZGluZyA9IHRoaXMuX2lzUmVjb3JkaW5nLmFzUmVhZG9ubHkoKTtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSB6b25lOiBOZ1pvbmUpIHt9XHJcblxyXG4gIGFzeW5jIHN0YXJ0UmVjb3JkaW5nKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgLy8gRHluYW1pY2FsbHkgaW1wb3J0IHJyd2ViIHRvIGF2b2lkIFNTUiBpc3N1ZXMgYW5kIHJlZHVjZSBpbml0aWFsIGJ1bmRsZVxyXG4gICAgY29uc3QgeyByZWNvcmQgfSA9IGF3YWl0IGltcG9ydCgncnJ3ZWInKTtcclxuICAgIHRoaXMuX2V2ZW50cy5zZXQoW10pO1xyXG4gICAgdGhpcy5faXNSZWNvcmRpbmcuc2V0KHRydWUpO1xyXG5cclxuICAgIHRoaXMuc3RvcEZuID0gcmVjb3JkKHtcclxuICAgICAgZW1pdDogKGV2ZW50OiBldmVudFdpdGhUaW1lKSA9PiB7XHJcbiAgICAgICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgICAgICB0aGlzLl9ldmVudHMudXBkYXRlKGV2ID0+IFsuLi5ldiwgZXZlbnRdKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSxcclxuICAgICAgLy8gTm90ZTogYmxvY2tTZWxlY3RvciBpcyBvbWl0dGVkIOKAlCBycndlYiAyLjAuMC1hbHBoYS40IGNhbGxzIG5vZGUubWF0Y2hlcygpXHJcbiAgICAgIC8vIG9uIFRleHROb2Rlcy9Db21tZW50Tm9kZXMgd2hpY2ggZG9uJ3QgaGF2ZSB0aGF0IG1ldGhvZCwgY3Jhc2hpbmcgdGhlIHJlY29yZGVyLlxyXG4gICAgICBtYXNrVGV4dFNlbGVjdG9yOiAnaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdJyxcclxuICAgICAgY2hlY2tvdXRFdmVyeU50aDogMjAwLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBzdG9wUmVjb3JkaW5nKCk6IGV2ZW50V2l0aFRpbWVbXSB7XHJcbiAgICBpZiAodGhpcy5zdG9wRm4pIHtcclxuICAgICAgdGhpcy5zdG9wRm4oKTtcclxuICAgICAgdGhpcy5zdG9wRm4gPSB1bmRlZmluZWQ7XHJcbiAgICB9XHJcbiAgICB0aGlzLl9pc1JlY29yZGluZy5zZXQoZmFsc2UpO1xyXG4gICAgcmV0dXJuIHRoaXMuX2V2ZW50cygpO1xyXG4gIH1cclxuXHJcbiAgZ2V0RXZlbnRzKCk6IGV2ZW50V2l0aFRpbWVbXSB7XHJcbiAgICByZXR1cm4gdGhpcy5fZXZlbnRzKCk7XHJcbiAgfVxyXG5cclxuICBjbGVhckV2ZW50cygpOiB2b2lkIHtcclxuICAgIHRoaXMuX2V2ZW50cy5zZXQoW10pO1xyXG4gIH1cclxuXHJcbiAgaGFzRXZlbnRzKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2V2ZW50cygpLmxlbmd0aCA+IDA7XHJcbiAgfVxyXG5cclxuICAvLyDilIDilIDilIAgUmVwbGF5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxyXG5cclxuICBhc3luYyBzdGFydFJlcGxheShjb250YWluZXI6IEhUTUxFbGVtZW50LCBldmVudHM/OiBldmVudFdpdGhUaW1lW10pOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGNvbnN0IHsgUmVwbGF5ZXIgfSA9IGF3YWl0IGltcG9ydCgncnJ3ZWInKTtcclxuICAgIGNvbnN0IGV2ZW50c1RvUmVwbGF5ID0gZXZlbnRzID8/IHRoaXMuX2V2ZW50cygpO1xyXG5cclxuICAgIGlmIChldmVudHNUb1JlcGxheS5sZW5ndGggPT09IDApIHJldHVybjtcclxuXHJcbiAgICAvLyBEZXN0cm95IHByZXZpb3VzIHJlcGxheWVyXHJcbiAgICB0aGlzLmRlc3Ryb3lSZXBsYXllcigpO1xyXG5cclxuICAgIHRoaXMucmVwbGF5ZXIgPSBuZXcgUmVwbGF5ZXIoZXZlbnRzVG9SZXBsYXksIHtcclxuICAgICAgcm9vdDogY29udGFpbmVyLFxyXG4gICAgICBza2lwSW5hY3RpdmU6IHRydWUsXHJcbiAgICAgIHNob3dXYXJuaW5nOiBmYWxzZSxcclxuICAgICAgc2hvd0RlYnVnOiBmYWxzZSxcclxuICAgICAgYmxvY2tDbGFzczogJ2RlYnVnLXBhbmVsJyxcclxuICAgIH0pO1xyXG5cclxuICAgIHRoaXMucmVwbGF5ZXIucGxheSgpO1xyXG4gIH1cclxuXHJcbiAgcGF1c2VSZXBsYXkoKTogdm9pZCB7XHJcbiAgICB0aGlzLnJlcGxheWVyPy5wYXVzZSgpO1xyXG4gIH1cclxuXHJcbiAgcmVzdW1lUmVwbGF5KCk6IHZvaWQge1xyXG4gICAgdGhpcy5yZXBsYXllcj8ucGxheSgpO1xyXG4gIH1cclxuXHJcbiAgZGVzdHJveVJlcGxheWVyKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMucmVwbGF5ZXIpIHtcclxuICAgICAgdHJ5IHsgdGhpcy5yZXBsYXllci5wYXVzZSgpOyB9IGNhdGNoIHt9XHJcbiAgICAgIHRoaXMucmVwbGF5ZXIgPSB1bmRlZmluZWQ7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyDilIDilIDilIAgRXhwb3J0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxyXG5cclxuICBleHBvcnRFdmVudHMoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh0aGlzLl9ldmVudHMoKSwgbnVsbCwgMik7XHJcbiAgfVxyXG5cclxuICBkb3dubG9hZEV2ZW50cyhmaWxlbmFtZSA9ICdycndlYi1zZXNzaW9uLmpzb24nKTogdm9pZCB7XHJcbiAgICBjb25zdCBibG9iID0gbmV3IEJsb2IoW3RoaXMuZXhwb3J0RXZlbnRzKCldLCB7IHR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyB9KTtcclxuICAgIGNvbnN0IHVybCA9IFVSTC5jcmVhdGVPYmplY3RVUkwoYmxvYik7XHJcbiAgICBjb25zdCBhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xyXG4gICAgYS5ocmVmID0gdXJsO1xyXG4gICAgYS5kb3dubG9hZCA9IGZpbGVuYW1lO1xyXG4gICAgYS5jbGljaygpO1xyXG4gICAgVVJMLnJldm9rZU9iamVjdFVSTCh1cmwpO1xyXG4gIH1cclxuXHJcbiAgaW1wb3J0RXZlbnRzKGpzb246IHN0cmluZyk6IGV2ZW50V2l0aFRpbWVbXSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCBldmVudHMgPSBKU09OLnBhcnNlKGpzb24pIGFzIGV2ZW50V2l0aFRpbWVbXTtcclxuICAgICAgdGhpcy5fZXZlbnRzLnNldChldmVudHMpO1xyXG4gICAgICByZXR1cm4gZXZlbnRzO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ludmFsaWQgcnJ3ZWIgZXZlbnRzIEpTT04nKTtcclxuICAgICAgcmV0dXJuIFtdO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0=
|