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.
@@ -0,0 +1,516 @@
1
+ import { Component, signal, computed, inject, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { RecorderService } from '../services/recorder.service';
5
+ import { AiGeneratorService } from '../services/ai-generator.service';
6
+ import { RrwebRecorderService } from '../services/rrweb-recorder.service';
7
+ import { ActionListComponent } from '../action-list/action-list.component';
8
+ import { TestPreviewComponent } from '../test-preview/test-preview.component';
9
+ import { SettingsDialogComponent } from '../settings-dialog/settings-dialog.component';
10
+ import { SessionReplayComponent } from '../session-replay/session-replay.component';
11
+ import * as i0 from "@angular/core";
12
+ import * as i1 from "@angular/forms";
13
+ export class DebugPanelComponent {
14
+ constructor() {
15
+ this.recorder = inject(RecorderService);
16
+ this.aiService = inject(AiGeneratorService);
17
+ this.rrweb = inject(RrwebRecorderService);
18
+ this.panelOpen = signal(false);
19
+ this.activeTab = signal('actions');
20
+ this.position = signal('bottom-right');
21
+ this.panelWidth = signal(420);
22
+ this.showSettings = signal(false);
23
+ this.sessionName = '';
24
+ this.sessionDesc = '';
25
+ this.hasActions = computed(() => (this.recorder.currentSession()?.actions.length ?? 0) > 0 ||
26
+ (this.recorder.sessions().length > 0));
27
+ this.resizing = false;
28
+ this.resizeStartY = 0;
29
+ this.resizeStartH = 0;
30
+ this.handleHotkey = (e) => {
31
+ if (e.ctrlKey && e.shiftKey && e.key === 'D') {
32
+ e.preventDefault();
33
+ this.togglePanel();
34
+ }
35
+ if (e.ctrlKey && e.shiftKey && e.key === 'R') {
36
+ e.preventDefault();
37
+ if (this.recorder.isRecording()) {
38
+ this.stopRecording();
39
+ }
40
+ else {
41
+ this.startRecording();
42
+ }
43
+ }
44
+ };
45
+ }
46
+ ngOnInit() {
47
+ // Keyboard shortcut: Ctrl+Shift+D
48
+ document.addEventListener('keydown', this.handleHotkey);
49
+ }
50
+ ngOnDestroy() {
51
+ document.removeEventListener('keydown', this.handleHotkey);
52
+ }
53
+ togglePanel() {
54
+ this.panelOpen.update(v => !v);
55
+ if (this.panelOpen() && !this.recorder.currentSession()) {
56
+ this.activeTab.set('actions');
57
+ }
58
+ }
59
+ cyclePosition() {
60
+ const positions = ['bottom-right', 'bottom-left', 'top-right', 'top-left'];
61
+ const idx = positions.indexOf(this.position());
62
+ this.position.set(positions[(idx + 1) % positions.length]);
63
+ }
64
+ startRecording() {
65
+ this.recorder.startRecording(this.sessionName || undefined, this.sessionDesc || undefined);
66
+ // Start rrweb in parallel for visual replay
67
+ this.rrweb.startRecording();
68
+ this.activeTab.set('actions');
69
+ }
70
+ stopRecording() {
71
+ const session = this.recorder.stopRecording();
72
+ this.rrweb.stopRecording();
73
+ if (session) {
74
+ this.activeTab.set('actions');
75
+ }
76
+ }
77
+ async generateTest() {
78
+ const session = this.recorder.currentSession() ?? this.recorder.sessions().at(-1);
79
+ if (!session)
80
+ return;
81
+ await this.aiService.generateCypressTest(session);
82
+ this.activeTab.set('test');
83
+ }
84
+ async loadAndGenerate(session) {
85
+ await this.aiService.generateCypressTest(session);
86
+ this.activeTab.set('test');
87
+ }
88
+ // Drag to reposition
89
+ startDrag(e) {
90
+ if (e.target.closest('button'))
91
+ return;
92
+ const panel = e.currentTarget.parentElement;
93
+ const startX = e.clientX - panel.getBoundingClientRect().left;
94
+ const startY = e.clientY - panel.getBoundingClientRect().top;
95
+ const onMove = (ev) => {
96
+ panel.style.left = `${ev.clientX - startX}px`;
97
+ panel.style.top = `${ev.clientY - startY}px`;
98
+ panel.style.right = 'auto';
99
+ panel.style.bottom = 'auto';
100
+ };
101
+ const onUp = () => {
102
+ document.removeEventListener('mousemove', onMove);
103
+ document.removeEventListener('mouseup', onUp);
104
+ };
105
+ document.addEventListener('mousemove', onMove);
106
+ document.addEventListener('mouseup', onUp);
107
+ }
108
+ // Resize height
109
+ startResize(e) {
110
+ const panel = e.currentTarget.parentElement;
111
+ this.resizeStartY = e.clientY;
112
+ this.resizeStartH = panel.getBoundingClientRect().height;
113
+ const onMove = (ev) => {
114
+ const newH = Math.max(250, this.resizeStartH + (ev.clientY - this.resizeStartY));
115
+ panel.style.maxHeight = `${newH}px`;
116
+ };
117
+ const onUp = () => {
118
+ document.removeEventListener('mousemove', onMove);
119
+ document.removeEventListener('mouseup', onUp);
120
+ };
121
+ document.addEventListener('mousemove', onMove);
122
+ document.addEventListener('mouseup', onUp);
123
+ e.preventDefault();
124
+ }
125
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DebugPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
126
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: DebugPanelComponent, isStandalone: true, selector: "app-debug-panel", ngImport: i0, template: `
127
+ <!-- Toggle FAB -->
128
+ <button
129
+ data-debug-panel
130
+ class="debug-fab"
131
+ [class.recording]="recorder.isRecording()"
132
+ [class.pulse]="recorder.isRecording() && !recorder.isPaused()"
133
+ (click)="togglePanel()"
134
+ [title]="panelOpen() ? 'Debug Panel schließen' : 'Debug Panel öffnen'"
135
+ >
136
+ <span class="fab-icon">{{ recorder.isRecording() ? '⏺' : '🐛' }}</span>
137
+ @if (recorder.isRecording() && recorder.actionCount() > 0) {
138
+ <span class="fab-badge">{{ recorder.actionCount() }}</span>
139
+ }
140
+ </button>
141
+
142
+ <!-- Main Panel -->
143
+ @if (panelOpen()) {
144
+ <div
145
+ data-debug-panel
146
+ class="debug-panel"
147
+ [class]="'pos-' + position()"
148
+ [style.width.px]="panelWidth()"
149
+ >
150
+ <!-- Header -->
151
+ <div class="panel-header" (mousedown)="startDrag($event)">
152
+ <div class="header-left">
153
+ <span class="panel-icon">🐛</span>
154
+ <span class="panel-title">Debug Recorder</span>
155
+ @if (recorder.isRecording()) {
156
+ <span class="rec-indicator" [class.paused]="recorder.isPaused()">
157
+ {{ recorder.isPaused() ? '⏸ PAUSED' : '⏺ REC' }}
158
+ </span>
159
+ }
160
+ </div>
161
+ <div class="header-actions">
162
+ <button class="icon-btn" title="Einstellungen" (click)="showSettings.set(true)">⚙️</button>
163
+ <button class="icon-btn" title="Position wechseln" (click)="cyclePosition()">📌</button>
164
+ <button class="icon-btn" title="Schließen" (click)="togglePanel()">✕</button>
165
+ </div>
166
+ </div>
167
+
168
+ <!-- Session Name Input (only when not recording) -->
169
+ @if (!recorder.isRecording()) {
170
+ <div class="session-setup">
171
+ <input
172
+ data-debug-panel
173
+ class="session-input"
174
+ type="text"
175
+ [(ngModel)]="sessionName"
176
+ placeholder="Session-Name (optional)"
177
+ />
178
+ <textarea
179
+ data-debug-panel
180
+ class="session-desc"
181
+ [(ngModel)]="sessionDesc"
182
+ placeholder="Fehlerbeschreibung..."
183
+ rows="2"
184
+ ></textarea>
185
+ </div>
186
+ }
187
+
188
+ <!-- Recording Controls -->
189
+ <div class="recording-controls" data-debug-panel>
190
+ @if (!recorder.isRecording()) {
191
+ <button class="ctrl-btn start" (click)="startRecording()">
192
+ ▶ Aufnahme starten
193
+ </button>
194
+ } @else {
195
+ <button class="ctrl-btn pause" (click)="recorder.pauseRecording()">
196
+ {{ recorder.isPaused() ? '▶ Fortsetzen' : '⏸ Pause' }}
197
+ </button>
198
+ <button class="ctrl-btn stop" (click)="stopRecording()">
199
+ ⏹ Stoppen
200
+ </button>
201
+ <button class="ctrl-btn clear" title="Aktionen löschen" (click)="recorder.clearCurrentSession()">
202
+ 🗑
203
+ </button>
204
+ }
205
+
206
+ @if (hasActions()) {
207
+ <button
208
+ class="ctrl-btn generate"
209
+ [disabled]="aiService.isGenerating() || !aiService.webhookUrl()"
210
+ [title]="!aiService.webhookUrl() ? 'Webhook-URL in Einstellungen eintragen' : 'Cypress Test generieren'"
211
+ (click)="generateTest()"
212
+ >
213
+ @if (aiService.isGenerating()) {
214
+ <span class="spinner">⟳</span> Generiere...
215
+ } @else {
216
+ 🤖 → Cypress Test
217
+ }
218
+ </button>
219
+ }
220
+ </div>
221
+
222
+ <!-- Error Banner -->
223
+ @if (aiService.error()) {
224
+ <div class="error-banner" data-debug-panel>
225
+ ⚠️ {{ aiService.error() }}
226
+ </div>
227
+ }
228
+
229
+ <!-- Tabs -->
230
+ <div class="tab-bar" data-debug-panel>
231
+ <button
232
+ class="tab-btn"
233
+ [class.active]="activeTab() === 'actions'"
234
+ (click)="activeTab.set('actions')"
235
+ >
236
+ Aktionen
237
+ @if (recorder.actionCount() > 0) {
238
+ <span class="tab-badge">{{ recorder.actionCount() }}</span>
239
+ }
240
+ </button>
241
+ <button
242
+ class="tab-btn"
243
+ [class.active]="activeTab() === 'replay'"
244
+ (click)="activeTab.set('replay')"
245
+ title="rrweb Session Replay"
246
+ >
247
+ 📽️ Replay
248
+ @if (rrweb.events().length > 0) {
249
+ <span class="tab-badge">{{ rrweb.events().length }}</span>
250
+ }
251
+ </button>
252
+ <button
253
+ class="tab-btn"
254
+ [class.active]="activeTab() === 'test'"
255
+ [disabled]="!aiService.lastTest()"
256
+ (click)="activeTab.set('test')"
257
+ >
258
+ 🤖 Test
259
+ @if (aiService.lastTest()) {
260
+ <span class="tab-badge new">NEU</span>
261
+ }
262
+ </button>
263
+ <button
264
+ class="tab-btn"
265
+ [class.active]="activeTab() === 'sessions'"
266
+ [disabled]="recorder.sessions().length === 0"
267
+ (click)="activeTab.set('sessions')"
268
+ >
269
+ Sessions ({{ recorder.sessions().length }})
270
+ </button>
271
+ </div>
272
+
273
+ <!-- Tab Content -->
274
+ <div class="tab-content">
275
+ @if (activeTab() === 'actions') {
276
+ <app-action-list
277
+ [session]="recorder.currentSession()"
278
+ (removeAction)="recorder.removeAction($event)"
279
+ (addNote)="recorder.addNote($event.id, $event.note)"
280
+ />
281
+ }
282
+
283
+ @if (activeTab() === 'replay') {
284
+ <app-session-replay />
285
+ }
286
+
287
+ @if (activeTab() === 'test') {
288
+ <app-test-preview [test]="aiService.lastTest()" />
289
+ }
290
+
291
+ @if (activeTab() === 'sessions') {
292
+ <div class="sessions-list">
293
+ @for (session of recorder.sessions(); track session.id) {
294
+ <div class="session-card">
295
+ <div class="session-card-header">
296
+ <span class="session-name">{{ session.name }}</span>
297
+ <span class="session-meta">{{ session.actions.length }} Aktionen</span>
298
+ </div>
299
+ <div class="session-card-actions">
300
+ <button class="sm-btn" (click)="loadAndGenerate(session)">🤖 Neu generieren</button>
301
+ <button class="sm-btn danger" (click)="recorder.deleteSession(session.id)">🗑</button>
302
+ </div>
303
+ </div>
304
+ }
305
+ </div>
306
+ }
307
+ </div>
308
+
309
+ <!-- Resize Handle -->
310
+ <div class="resize-handle" (mousedown)="startResize($event)">⠿</div>
311
+ </div>
312
+ }
313
+
314
+ <!-- Settings Dialog -->
315
+ @if (showSettings()) {
316
+ <app-settings-dialog (close)="showSettings.set(false)" />
317
+ }
318
+ `, isInline: true, styles: [".debug-fab{bottom:24px;right:24px;z-index:99999;width:52px;height:52px;border-radius:50%;border:none;background:#1e293b;color:#fff;font-size:22px;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 20px #0006;transition:transform .2s,background .2s;position:fixed}.debug-fab:hover{transform:scale(1.1);background:#334155}.debug-fab.recording{background:#dc2626}.debug-fab.pulse{animation:fabPulse 1.5s ease-in-out infinite}@keyframes fabPulse{0%,to{box-shadow:0 4px 20px #dc262666}50%{box-shadow:0 4px 30px #dc2626e6,0 0 0 8px #dc262626}}.fab-badge{position:absolute;top:-4px;right:-4px;background:#f59e0b;color:#000;font-size:10px;font-weight:700;min-width:18px;height:18px;border-radius:9px;display:flex;align-items:center;justify-content:center;padding:0 4px}.debug-panel{position:fixed;z-index:99998;width:420px;max-height:80vh;background:#0f172a;color:#e2e8f0;border-radius:12px;border:1px solid #1e3a5f;box-shadow:0 25px 60px #0009;display:flex;flex-direction:column;font-family:Segoe UI,system-ui,sans-serif;font-size:13px;overflow:hidden}.pos-bottom-right{bottom:88px;right:24px}.pos-bottom-left{bottom:88px;left:24px}.pos-top-right{top:24px;right:24px}.pos-top-left{top:24px;left:24px}.panel-header{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:#1e293b;border-bottom:1px solid #334155;cursor:move;-webkit-user-select:none;user-select:none;flex-shrink:0}.header-left{display:flex;align-items:center;gap:8px}.panel-icon{font-size:16px}.panel-title{font-weight:600;font-size:14px;color:#f1f5f9}.rec-indicator{font-size:10px;font-weight:700;color:#ef4444;background:#ef444426;padding:2px 7px;border-radius:4px;animation:blink 1s step-end infinite}.rec-indicator.paused{color:#f59e0b;background:#f59e0b26;animation:none}@keyframes blink{50%{opacity:.4}}.header-actions{display:flex;gap:4px}.icon-btn{background:none;border:none;color:#94a3b8;cursor:pointer;padding:4px;border-radius:4px;font-size:14px;line-height:1;transition:color .15s,background .15s}.icon-btn:hover{color:#f1f5f9;background:#334155}.session-setup{padding:10px 14px;border-bottom:1px solid #1e293b;display:flex;flex-direction:column;gap:6px;flex-shrink:0}.session-input,.session-desc{background:#1e293b;border:1px solid #334155;color:#e2e8f0;border-radius:6px;padding:6px 10px;font-size:12px;width:100%;box-sizing:border-box;resize:vertical}.session-input:focus,.session-desc:focus{outline:none;border-color:#3b82f6}.recording-controls{display:flex;gap:6px;padding:10px 14px;border-bottom:1px solid #1e293b;flex-wrap:wrap;flex-shrink:0}.ctrl-btn{border:none;border-radius:6px;padding:6px 14px;font-size:12px;font-weight:600;cursor:pointer;transition:filter .15s,transform .1s;display:flex;align-items:center;gap:5px}.ctrl-btn:hover:not(:disabled){filter:brightness(1.15);transform:translateY(-1px)}.ctrl-btn:active:not(:disabled){transform:translateY(0)}.ctrl-btn:disabled{opacity:.5;cursor:not-allowed}.ctrl-btn.start{background:#16a34a;color:#fff}.ctrl-btn.stop{background:#dc2626;color:#fff}.ctrl-btn.pause{background:#d97706;color:#fff}.ctrl-btn.generate{background:#7c3aed;color:#fff;flex:1;justify-content:center}.ctrl-btn.clear{background:#374151;color:#9ca3af;padding:6px 10px}.spinner{display:inline-block;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error-banner{background:#dc262626;border-left:3px solid #dc2626;color:#fca5a5;padding:8px 14px;font-size:12px;flex-shrink:0}.tab-bar{display:flex;border-bottom:1px solid #1e293b;flex-shrink:0}.tab-btn{flex:1;background:none;border:none;color:#64748b;padding:8px 4px;font-size:12px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:5px;border-bottom:2px solid transparent;transition:color .15s}.tab-btn:hover:not(:disabled){color:#cbd5e1}.tab-btn.active{color:#60a5fa;border-bottom-color:#3b82f6}.tab-btn:disabled{opacity:.4;cursor:not-allowed}.tab-badge{background:#334155;color:#94a3b8;font-size:10px;padding:1px 5px;border-radius:3px}.tab-badge.new{background:#7c3aed;color:#e9d5ff}.tab-content{overflow-y:auto;flex:1;min-height:0}.tab-content::-webkit-scrollbar{width:5px}.tab-content::-webkit-scrollbar-track{background:transparent}.tab-content::-webkit-scrollbar-thumb{background:#334155;border-radius:3px}.sessions-list{padding:10px 14px;display:flex;flex-direction:column;gap:8px}.session-card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:10px}.session-card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.session-name{font-weight:600;color:#f1f5f9;font-size:13px}.session-meta{font-size:11px;color:#64748b}.session-card-actions{display:flex;gap:6px}.sm-btn{background:#334155;border:none;color:#cbd5e1;padding:4px 10px;border-radius:5px;font-size:11px;cursor:pointer;transition:background .15s}.sm-btn:hover{background:#475569}.sm-btn.danger{color:#fca5a5}.sm-btn.danger:hover{background:#dc262633}.resize-handle{text-align:center;color:#334155;cursor:ns-resize;font-size:16px;padding:2px;flex-shrink:0;background:#0f172a;-webkit-user-select:none;user-select:none}.resize-handle:hover{color:#64748b}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ActionListComponent, selector: "app-action-list", inputs: ["session"], outputs: ["removeAction", "addNote"] }, { kind: "component", type: TestPreviewComponent, selector: "app-test-preview", inputs: ["test"] }, { kind: "component", type: SettingsDialogComponent, selector: "app-settings-dialog", outputs: ["close"] }, { kind: "component", type: SessionReplayComponent, selector: "app-session-replay" }] }); }
319
+ }
320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DebugPanelComponent, decorators: [{
321
+ type: Component,
322
+ args: [{ selector: 'app-debug-panel', standalone: true, imports: [CommonModule, FormsModule, ActionListComponent, TestPreviewComponent, SettingsDialogComponent, SessionReplayComponent], template: `
323
+ <!-- Toggle FAB -->
324
+ <button
325
+ data-debug-panel
326
+ class="debug-fab"
327
+ [class.recording]="recorder.isRecording()"
328
+ [class.pulse]="recorder.isRecording() && !recorder.isPaused()"
329
+ (click)="togglePanel()"
330
+ [title]="panelOpen() ? 'Debug Panel schließen' : 'Debug Panel öffnen'"
331
+ >
332
+ <span class="fab-icon">{{ recorder.isRecording() ? '⏺' : '🐛' }}</span>
333
+ @if (recorder.isRecording() && recorder.actionCount() > 0) {
334
+ <span class="fab-badge">{{ recorder.actionCount() }}</span>
335
+ }
336
+ </button>
337
+
338
+ <!-- Main Panel -->
339
+ @if (panelOpen()) {
340
+ <div
341
+ data-debug-panel
342
+ class="debug-panel"
343
+ [class]="'pos-' + position()"
344
+ [style.width.px]="panelWidth()"
345
+ >
346
+ <!-- Header -->
347
+ <div class="panel-header" (mousedown)="startDrag($event)">
348
+ <div class="header-left">
349
+ <span class="panel-icon">🐛</span>
350
+ <span class="panel-title">Debug Recorder</span>
351
+ @if (recorder.isRecording()) {
352
+ <span class="rec-indicator" [class.paused]="recorder.isPaused()">
353
+ {{ recorder.isPaused() ? '⏸ PAUSED' : '⏺ REC' }}
354
+ </span>
355
+ }
356
+ </div>
357
+ <div class="header-actions">
358
+ <button class="icon-btn" title="Einstellungen" (click)="showSettings.set(true)">⚙️</button>
359
+ <button class="icon-btn" title="Position wechseln" (click)="cyclePosition()">📌</button>
360
+ <button class="icon-btn" title="Schließen" (click)="togglePanel()">✕</button>
361
+ </div>
362
+ </div>
363
+
364
+ <!-- Session Name Input (only when not recording) -->
365
+ @if (!recorder.isRecording()) {
366
+ <div class="session-setup">
367
+ <input
368
+ data-debug-panel
369
+ class="session-input"
370
+ type="text"
371
+ [(ngModel)]="sessionName"
372
+ placeholder="Session-Name (optional)"
373
+ />
374
+ <textarea
375
+ data-debug-panel
376
+ class="session-desc"
377
+ [(ngModel)]="sessionDesc"
378
+ placeholder="Fehlerbeschreibung..."
379
+ rows="2"
380
+ ></textarea>
381
+ </div>
382
+ }
383
+
384
+ <!-- Recording Controls -->
385
+ <div class="recording-controls" data-debug-panel>
386
+ @if (!recorder.isRecording()) {
387
+ <button class="ctrl-btn start" (click)="startRecording()">
388
+ ▶ Aufnahme starten
389
+ </button>
390
+ } @else {
391
+ <button class="ctrl-btn pause" (click)="recorder.pauseRecording()">
392
+ {{ recorder.isPaused() ? '▶ Fortsetzen' : '⏸ Pause' }}
393
+ </button>
394
+ <button class="ctrl-btn stop" (click)="stopRecording()">
395
+ ⏹ Stoppen
396
+ </button>
397
+ <button class="ctrl-btn clear" title="Aktionen löschen" (click)="recorder.clearCurrentSession()">
398
+ 🗑
399
+ </button>
400
+ }
401
+
402
+ @if (hasActions()) {
403
+ <button
404
+ class="ctrl-btn generate"
405
+ [disabled]="aiService.isGenerating() || !aiService.webhookUrl()"
406
+ [title]="!aiService.webhookUrl() ? 'Webhook-URL in Einstellungen eintragen' : 'Cypress Test generieren'"
407
+ (click)="generateTest()"
408
+ >
409
+ @if (aiService.isGenerating()) {
410
+ <span class="spinner">⟳</span> Generiere...
411
+ } @else {
412
+ 🤖 → Cypress Test
413
+ }
414
+ </button>
415
+ }
416
+ </div>
417
+
418
+ <!-- Error Banner -->
419
+ @if (aiService.error()) {
420
+ <div class="error-banner" data-debug-panel>
421
+ ⚠️ {{ aiService.error() }}
422
+ </div>
423
+ }
424
+
425
+ <!-- Tabs -->
426
+ <div class="tab-bar" data-debug-panel>
427
+ <button
428
+ class="tab-btn"
429
+ [class.active]="activeTab() === 'actions'"
430
+ (click)="activeTab.set('actions')"
431
+ >
432
+ Aktionen
433
+ @if (recorder.actionCount() > 0) {
434
+ <span class="tab-badge">{{ recorder.actionCount() }}</span>
435
+ }
436
+ </button>
437
+ <button
438
+ class="tab-btn"
439
+ [class.active]="activeTab() === 'replay'"
440
+ (click)="activeTab.set('replay')"
441
+ title="rrweb Session Replay"
442
+ >
443
+ 📽️ Replay
444
+ @if (rrweb.events().length > 0) {
445
+ <span class="tab-badge">{{ rrweb.events().length }}</span>
446
+ }
447
+ </button>
448
+ <button
449
+ class="tab-btn"
450
+ [class.active]="activeTab() === 'test'"
451
+ [disabled]="!aiService.lastTest()"
452
+ (click)="activeTab.set('test')"
453
+ >
454
+ 🤖 Test
455
+ @if (aiService.lastTest()) {
456
+ <span class="tab-badge new">NEU</span>
457
+ }
458
+ </button>
459
+ <button
460
+ class="tab-btn"
461
+ [class.active]="activeTab() === 'sessions'"
462
+ [disabled]="recorder.sessions().length === 0"
463
+ (click)="activeTab.set('sessions')"
464
+ >
465
+ Sessions ({{ recorder.sessions().length }})
466
+ </button>
467
+ </div>
468
+
469
+ <!-- Tab Content -->
470
+ <div class="tab-content">
471
+ @if (activeTab() === 'actions') {
472
+ <app-action-list
473
+ [session]="recorder.currentSession()"
474
+ (removeAction)="recorder.removeAction($event)"
475
+ (addNote)="recorder.addNote($event.id, $event.note)"
476
+ />
477
+ }
478
+
479
+ @if (activeTab() === 'replay') {
480
+ <app-session-replay />
481
+ }
482
+
483
+ @if (activeTab() === 'test') {
484
+ <app-test-preview [test]="aiService.lastTest()" />
485
+ }
486
+
487
+ @if (activeTab() === 'sessions') {
488
+ <div class="sessions-list">
489
+ @for (session of recorder.sessions(); track session.id) {
490
+ <div class="session-card">
491
+ <div class="session-card-header">
492
+ <span class="session-name">{{ session.name }}</span>
493
+ <span class="session-meta">{{ session.actions.length }} Aktionen</span>
494
+ </div>
495
+ <div class="session-card-actions">
496
+ <button class="sm-btn" (click)="loadAndGenerate(session)">🤖 Neu generieren</button>
497
+ <button class="sm-btn danger" (click)="recorder.deleteSession(session.id)">🗑</button>
498
+ </div>
499
+ </div>
500
+ }
501
+ </div>
502
+ }
503
+ </div>
504
+
505
+ <!-- Resize Handle -->
506
+ <div class="resize-handle" (mousedown)="startResize($event)">⠿</div>
507
+ </div>
508
+ }
509
+
510
+ <!-- Settings Dialog -->
511
+ @if (showSettings()) {
512
+ <app-settings-dialog (close)="showSettings.set(false)" />
513
+ }
514
+ `, styles: [".debug-fab{bottom:24px;right:24px;z-index:99999;width:52px;height:52px;border-radius:50%;border:none;background:#1e293b;color:#fff;font-size:22px;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 20px #0006;transition:transform .2s,background .2s;position:fixed}.debug-fab:hover{transform:scale(1.1);background:#334155}.debug-fab.recording{background:#dc2626}.debug-fab.pulse{animation:fabPulse 1.5s ease-in-out infinite}@keyframes fabPulse{0%,to{box-shadow:0 4px 20px #dc262666}50%{box-shadow:0 4px 30px #dc2626e6,0 0 0 8px #dc262626}}.fab-badge{position:absolute;top:-4px;right:-4px;background:#f59e0b;color:#000;font-size:10px;font-weight:700;min-width:18px;height:18px;border-radius:9px;display:flex;align-items:center;justify-content:center;padding:0 4px}.debug-panel{position:fixed;z-index:99998;width:420px;max-height:80vh;background:#0f172a;color:#e2e8f0;border-radius:12px;border:1px solid #1e3a5f;box-shadow:0 25px 60px #0009;display:flex;flex-direction:column;font-family:Segoe UI,system-ui,sans-serif;font-size:13px;overflow:hidden}.pos-bottom-right{bottom:88px;right:24px}.pos-bottom-left{bottom:88px;left:24px}.pos-top-right{top:24px;right:24px}.pos-top-left{top:24px;left:24px}.panel-header{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:#1e293b;border-bottom:1px solid #334155;cursor:move;-webkit-user-select:none;user-select:none;flex-shrink:0}.header-left{display:flex;align-items:center;gap:8px}.panel-icon{font-size:16px}.panel-title{font-weight:600;font-size:14px;color:#f1f5f9}.rec-indicator{font-size:10px;font-weight:700;color:#ef4444;background:#ef444426;padding:2px 7px;border-radius:4px;animation:blink 1s step-end infinite}.rec-indicator.paused{color:#f59e0b;background:#f59e0b26;animation:none}@keyframes blink{50%{opacity:.4}}.header-actions{display:flex;gap:4px}.icon-btn{background:none;border:none;color:#94a3b8;cursor:pointer;padding:4px;border-radius:4px;font-size:14px;line-height:1;transition:color .15s,background .15s}.icon-btn:hover{color:#f1f5f9;background:#334155}.session-setup{padding:10px 14px;border-bottom:1px solid #1e293b;display:flex;flex-direction:column;gap:6px;flex-shrink:0}.session-input,.session-desc{background:#1e293b;border:1px solid #334155;color:#e2e8f0;border-radius:6px;padding:6px 10px;font-size:12px;width:100%;box-sizing:border-box;resize:vertical}.session-input:focus,.session-desc:focus{outline:none;border-color:#3b82f6}.recording-controls{display:flex;gap:6px;padding:10px 14px;border-bottom:1px solid #1e293b;flex-wrap:wrap;flex-shrink:0}.ctrl-btn{border:none;border-radius:6px;padding:6px 14px;font-size:12px;font-weight:600;cursor:pointer;transition:filter .15s,transform .1s;display:flex;align-items:center;gap:5px}.ctrl-btn:hover:not(:disabled){filter:brightness(1.15);transform:translateY(-1px)}.ctrl-btn:active:not(:disabled){transform:translateY(0)}.ctrl-btn:disabled{opacity:.5;cursor:not-allowed}.ctrl-btn.start{background:#16a34a;color:#fff}.ctrl-btn.stop{background:#dc2626;color:#fff}.ctrl-btn.pause{background:#d97706;color:#fff}.ctrl-btn.generate{background:#7c3aed;color:#fff;flex:1;justify-content:center}.ctrl-btn.clear{background:#374151;color:#9ca3af;padding:6px 10px}.spinner{display:inline-block;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error-banner{background:#dc262626;border-left:3px solid #dc2626;color:#fca5a5;padding:8px 14px;font-size:12px;flex-shrink:0}.tab-bar{display:flex;border-bottom:1px solid #1e293b;flex-shrink:0}.tab-btn{flex:1;background:none;border:none;color:#64748b;padding:8px 4px;font-size:12px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:5px;border-bottom:2px solid transparent;transition:color .15s}.tab-btn:hover:not(:disabled){color:#cbd5e1}.tab-btn.active{color:#60a5fa;border-bottom-color:#3b82f6}.tab-btn:disabled{opacity:.4;cursor:not-allowed}.tab-badge{background:#334155;color:#94a3b8;font-size:10px;padding:1px 5px;border-radius:3px}.tab-badge.new{background:#7c3aed;color:#e9d5ff}.tab-content{overflow-y:auto;flex:1;min-height:0}.tab-content::-webkit-scrollbar{width:5px}.tab-content::-webkit-scrollbar-track{background:transparent}.tab-content::-webkit-scrollbar-thumb{background:#334155;border-radius:3px}.sessions-list{padding:10px 14px;display:flex;flex-direction:column;gap:8px}.session-card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:10px}.session-card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.session-name{font-weight:600;color:#f1f5f9;font-size:13px}.session-meta{font-size:11px;color:#64748b}.session-card-actions{display:flex;gap:6px}.sm-btn{background:#334155;border:none;color:#cbd5e1;padding:4px 10px;border-radius:5px;font-size:11px;cursor:pointer;transition:background .15s}.sm-btn:hover{background:#475569}.sm-btn.danger{color:#fca5a5}.sm-btn.danger:hover{background:#dc262633}.resize-handle{text-align:center;color:#334155;cursor:ns-resize;font-size:16px;padding:2px;flex-shrink:0;background:#0f172a;-webkit-user-select:none;user-select:none}.resize-handle:hover{color:#64748b}\n"] }]
515
+ }] });
516
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVidWctcGFuZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZGVidWctcmVjb3JkZXIvc3JjL2xpYi9kZWJ1Zy1wYW5lbC9kZWJ1Zy1wYW5lbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sR0FDcEMsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdEUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFFMUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDM0UsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDOUUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sOENBQThDLENBQUM7QUFDdkYsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sNENBQTRDLENBQUM7OztBQXVjcEYsTUFBTSxPQUFPLG1CQUFtQjtJQWxjaEM7UUFtY0UsYUFBUSxHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUNuQyxjQUFTLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDdkMsVUFBSyxHQUFHLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBRXJDLGNBQVMsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDMUIsY0FBUyxHQUFHLE1BQU0sQ0FBVyxTQUFTLENBQUMsQ0FBQztRQUN4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QVcsRUFBRSxtQkFBbUIsRUFBRSxvQkFBb0IsRUFBRSx1QkFBdUIsRUFBRSxzQkFBc0IsQ0FBQyxZQUN0SDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBZ01UIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LCBzaWduYWwsIGNvbXB1dGVkLCBpbmplY3QsIE9uSW5pdCwgT25EZXN0cm95LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IFJlY29yZGVyU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL3JlY29yZGVyLnNlcnZpY2UnO1xuaW1wb3J0IHsgQWlHZW5lcmF0b3JTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvYWktZ2VuZXJhdG9yLnNlcnZpY2UnO1xuaW1wb3J0IHsgUnJ3ZWJSZWNvcmRlclNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9ycndlYi1yZWNvcmRlci5zZXJ2aWNlJztcbmltcG9ydCB7IFJlY29yZGluZ1Nlc3Npb24gfSBmcm9tICcuLi9tb2RlbHMvcmVjb3JkZWQtYWN0aW9uLm1vZGVsJztcbmltcG9ydCB7IEFjdGlvbkxpc3RDb21wb25lbnQgfSBmcm9tICcuLi9hY3Rpb24tbGlzdC9hY3Rpb24tbGlzdC5jb21wb25lbnQnO1xuaW1wb3J0IHsgVGVzdFByZXZpZXdDb21wb25lbnQgfSBmcm9tICcuLi90ZXN0LXByZXZpZXcvdGVzdC1wcmV2aWV3LmNvbXBvbmVudCc7XG5pbXBvcnQgeyBTZXR0aW5nc0RpYWxvZ0NvbXBvbmVudCB9IGZyb20gJy4uL3NldHRpbmdzLWRpYWxvZy9zZXR0aW5ncy1kaWFsb2cuY29tcG9uZW50JztcbmltcG9ydCB7IFNlc3Npb25SZXBsYXlDb21wb25lbnQgfSBmcm9tICcuLi9zZXNzaW9uLXJlcGxheS9zZXNzaW9uLXJlcGxheS5jb21wb25lbnQnO1xuXG50eXBlIFBhbmVsVGFiID0gJ2FjdGlvbnMnIHwgJ3Rlc3QnIHwgJ3Nlc3Npb25zJyB8ICdyZXBsYXknO1xudHlwZSBQYW5lbFBvc2l0aW9uID0gJ2JvdHRvbS1yaWdodCcgfCAnYm90dG9tLWxlZnQnIHwgJ3RvcC1yaWdodCcgfCAndG9wLWxlZnQnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtZGVidWctcGFuZWwnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBGb3Jtc01vZHVsZSwgQWN0aW9uTGlzdENvbXBvbmVudCwgVGVzdFByZXZpZXdDb21wb25lbnQsIFNldHRpbmdzRGlhbG9nQ29tcG9uZW50LCBTZXNzaW9uUmVwbGF5Q29tcG9uZW50XSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8IS0tIFRvZ2dsZSBGQUIgLS0+XG4gICAgPGJ1dHRvblxuICAgICAgZGF0YS1kZWJ1Zy1wYW5lbFxuICAgICAgY2xhc3M9XCJkZWJ1Zy1mYWJcIlxuICAgICAgW2NsYXNzLnJlY29yZGluZ109XCJyZWNvcmRlci5pc1JlY29yZGluZygpXCJcbiAgICAgIFtjbGFzcy5wdWxzZV09XCJyZWNvcmRlci5pc1JlY29yZGluZygpICYmICFyZWNvcmRlci5pc1BhdXNlZCgpXCJcbiAgICAgIChjbGljayk9XCJ0b2dnbGVQYW5lbCgpXCJcbiAgICAgIFt0aXRsZV09XCJwYW5lbE9wZW4oKSA/ICdEZWJ1ZyBQYW5lbCBzY2hsaWXDn2VuJyA6ICdEZWJ1ZyBQYW5lbCDDtmZmbmVuJ1wiXG4gICAgPlxuICAgICAgPHNwYW4gY2xhc3M9XCJmYWItaWNvblwiPnt7IHJlY29yZGVyLmlzUmVjb3JkaW5nKCkgPyAn4o+6JyA6ICfwn5CbJyB9fTwvc3Bhbj5cbiAgICAgIEBpZiAocmVjb3JkZXIuaXNSZWNvcmRpbmcoKSAmJiByZWNvcmRlci5hY3Rpb25Db3VudCgpID4gMCkge1xuICAgICAgICA8c3BhbiBjbGFzcz1cImZhYi1iYWRnZVwiPnt7IHJlY29yZGVyLmFjdGlvbkNvdW50KCkgfX08L3NwYW4+XG4gICAgICB9XG4gICAgPC9idXR0b24+XG5cbiAgICA8IS0tIE1haW4gUGFuZWwgLS0+XG4gICAgQGlmIChwYW5lbE9wZW4oKSkge1xuICAgICAgPGRpdlxuICAgICAgICBkYXRhLWRlYnVnLXBhbmVsXG4gICAgICAgIGNsYXNzPVwiZGVidWctcGFuZWxcIlxuICAgICAgICBbY2xhc3NdPVwiJ3Bvcy0nICsgcG9zaXRpb24oKVwiXG4gICAgICAgIFtzdHlsZS53aWR0aC5weF09XCJwYW5lbFdpZHRoKClcIlxuICAgICAgPlxuICAgICAgICA8IS0tIEhlYWRlciAtLT5cbiAgICAgICAgPGRpdiBjbGFzcz1cInBhbmVsLWhlYWRlclwiIChtb3VzZWRvd24pPVwic3RhcnREcmFnKCRldmVudClcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiaGVhZGVyLWxlZnRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicGFuZWwtaWNvblwiPvCfkJs8L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInBhbmVsLXRpdGxlXCI+RGVidWcgUmVjb3JkZXI8L3NwYW4+XG4gICAgICAgICAgICBAaWYgKHJlY29yZGVyLmlzUmVjb3JkaW5nKCkpIHtcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJyZWMtaW5kaWNhdG9yXCIgW2NsYXNzLnBhdXNlZF09XCJyZWNvcmRlci5pc1BhdXNlZCgpXCI+XG4gICAgICAgICAgICAgICAge3sgcmVjb3JkZXIuaXNQYXVzZWQoKSA/ICfij7ggUEFVU0VEJyA6ICfij7ogUkVDJyB9fVxuICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImhlYWRlci1hY3Rpb25zXCI+XG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiaWNvbi1idG5cIiB0aXRsZT1cIkVpbnN0ZWxsdW5nZW5cIiAoY2xpY2spPVwic2hvd1NldHRpbmdzLnNldCh0cnVlKVwiPuKame+4jzwvYnV0dG9uPlxuICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImljb24tYnRuXCIgdGl0bGU9XCJQb3NpdGlvbiB3ZWNoc2VsblwiIChjbGljayk9XCJjeWNsZVBvc2l0aW9uKClcIj7wn5OMPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiaWNvbi1idG5cIiB0aXRsZT1cIlNjaGxpZcOfZW5cIiAoY2xpY2spPVwidG9nZ2xlUGFuZWwoKVwiPuKclTwvYnV0dG9uPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFNlc3Npb24gTmFtZSBJbnB1dCAob25seSB3aGVuIG5vdCByZWNvcmRpbmcpIC0tPlxuICAgICAgICBAaWYgKCFyZWNvcmRlci5pc1JlY29yZGluZygpKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInNlc3Npb24tc2V0dXBcIj5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICBkYXRhLWRlYnVnLXBhbmVsXG4gICAgICAgICAgICAgIGNsYXNzPVwic2Vzc2lvbi1pbnB1dFwiXG4gICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJzZXNzaW9uTmFtZVwiXG4gICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiU2Vzc2lvbi1OYW1lIChvcHRpb25hbClcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDx0ZXh0YXJlYVxuICAgICAgICAgICAgICBkYXRhLWRlYnVnLXBhbmVsXG4gICAgICAgICAgICAgIGNsYXNzPVwic2Vzc2lvbi1kZXNjXCJcbiAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJzZXNzaW9uRGVzY1wiXG4gICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiRmVobGVyYmVzY2hyZWlidW5nLi4uXCJcbiAgICAgICAgICAgICAgcm93cz1cIjJcIlxuICAgICAgICAgICAgPjwvdGV4dGFyZWE+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIFJlY29yZGluZyBDb250cm9scyAtLT5cbiAgICAgICAgPGRpdiBjbGFzcz1cInJlY29yZGluZy1jb250cm9sc1wiIGRhdGEtZGVidWctcGFuZWw+XG4gICAgICAgICAgQGlmICghcmVjb3JkZXIuaXNSZWNvcmRpbmcoKSkge1xuICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImN0cmwtYnRuIHN0YXJ0XCIgKGNsaWNrKT1cInN0YXJ0UmVjb3JkaW5nKClcIj5cbiAgICAgICAgICAgICAg4pa2IEF1Zm5haG1lIHN0YXJ0ZW5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImN0cmwtYnRuIHBhdXNlXCIgKGNsaWNrKT1cInJlY29yZGVyLnBhdXNlUmVjb3JkaW5nKClcIj5cbiAgICAgICAgICAgICAge3sgcmVjb3JkZXIuaXNQYXVzZWQoKSA/ICfilrYgRm9ydHNldHplbicgOiAn4o+4IFBhdXNlJyB9fVxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiY3RybC1idG4gc3RvcFwiIChjbGljayk9XCJzdG9wUmVjb3JkaW5nKClcIj5cbiAgICAgICAgICAgICAg4o+5IFN0b3BwZW5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImN0cmwtYnRuIGNsZWFyXCIgdGl0bGU9XCJBa3Rpb25lbiBsw7ZzY2hlblwiIChjbGljayk9XCJyZWNvcmRlci5jbGVhckN1cnJlbnRTZXNzaW9uKClcIj5cbiAgICAgICAgICAgICAg8J+XkVxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgQGlmIChoYXNBY3Rpb25zKCkpIHtcbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgY2xhc3M9XCJjdHJsLWJ0biBnZW5lcmF0ZVwiXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJhaVNlcnZpY2UuaXNHZW5lcmF0aW5nKCkgfHwgIWFpU2VydmljZS53ZWJob29rVXJsKClcIlxuICAgICAgICAgICAgICBbdGl0bGVdPVwiIWFpU2VydmljZS53ZWJob29rVXJsKCkgPyAnV2ViaG9vay1VUkwgaW4gRWluc3RlbGx1bmdlbiBlaW50cmFnZW4nIDogJ0N5cHJlc3MgVGVzdCBnZW5lcmllcmVuJ1wiXG4gICAgICAgICAgICAgIChjbGljayk9XCJnZW5lcmF0ZVRlc3QoKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIEBpZiAoYWlTZXJ2aWNlLmlzR2VuZXJhdGluZygpKSB7XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzcGlubmVyXCI+4p+zPC9zcGFuPiBHZW5lcmllcmUuLi5cbiAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAg8J+kliDihpIgQ3lwcmVzcyBUZXN0XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBFcnJvciBCYW5uZXIgLS0+XG4gICAgICAgIEBpZiAoYWlTZXJ2aWNlLmVycm9yKCkpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZXJyb3ItYmFubmVyXCIgZGF0YS1kZWJ1Zy1wYW5lbD5cbiAgICAgICAgICAgIOKaoO+4jyB7eyBhaVNlcnZpY2UuZXJyb3IoKSB9fVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG5cbiAgICAgICAgPCEtLSBUYWJzIC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwidGFiLWJhclwiIGRhdGEtZGVidWctcGFuZWw+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgY2xhc3M9XCJ0YWItYnRuXCJcbiAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiYWN0aXZlVGFiKCkgPT09ICdhY3Rpb25zJ1wiXG4gICAgICAgICAgICAoY2xpY2spPVwiYWN0aXZlVGFiLnNldCgnYWN0aW9ucycpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICBBa3Rpb25lblxuICAgICAgICAgICAgQGlmIChyZWNvcmRlci5hY3Rpb25Db3VudCgpID4gMCkge1xuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRhYi1iYWRnZVwiPnt7IHJlY29yZGVyLmFjdGlvbkNvdW50KCkgfX08L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgY2xhc3M9XCJ0YWItYnRuXCJcbiAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiYWN0aXZlVGFiKCkgPT09ICdyZXBsYXknXCJcbiAgICAgICAgICAgIChjbGljayk9XCJhY3RpdmVUYWIuc2V0KCdyZXBsYXknKVwiXG4gICAgICAgICAgICB0aXRsZT1cInJyd2ViIFNlc3Npb24gUmVwbGF5XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICDwn5O977iPIFJlcGxheVxuICAgICAgICAgICAgQGlmIChycndlYi5ldmVudHMoKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGFiLWJhZGdlXCI+e3sgcnJ3ZWIuZXZlbnRzKCkubGVuZ3RoIH19PC9zcGFuPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIGNsYXNzPVwidGFiLWJ0blwiXG4gICAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cImFjdGl2ZVRhYigpID09PSAndGVzdCdcIlxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFhaVNlcnZpY2UubGFzdFRlc3QoKVwiXG4gICAgICAgICAgICAoY2xpY2spPVwiYWN0aXZlVGFiLnNldCgndGVzdCcpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICDwn6SWIFRlc3RcbiAgICAgICAgICAgIEBpZiAoYWlTZXJ2aWNlLmxhc3RUZXN0KCkpIHtcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0YWItYmFkZ2UgbmV3XCI+TkVVPC9zcGFuPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIGNsYXNzPVwidGFiLWJ0blwiXG4gICAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cImFjdGl2ZVRhYigpID09PSAnc2Vzc2lvbnMnXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCJyZWNvcmRlci5zZXNzaW9ucygpLmxlbmd0aCA9PT0gMFwiXG4gICAgICAgICAgICAoY2xpY2spPVwiYWN0aXZlVGFiLnNldCgnc2Vzc2lvbnMnKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgU2Vzc2lvbnMgKHt7IHJlY29yZGVyLnNlc3Npb25zKCkubGVuZ3RoIH19KVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFRhYiBDb250ZW50IC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwidGFiLWNvbnRlbnRcIj5cbiAgICAgICAgICBAaWYgKGFjdGl2ZVRhYigpID09PSAnYWN0aW9ucycpIHtcbiAgICAgICAgICAgIDxhcHAtYWN0aW9uLWxpc3RcbiAgICAgICAgICAgICAgW3Nlc3Npb25dPVwicmVjb3JkZXIuY3VycmVudFNlc3Npb24oKVwiXG4gICAgICAgICAgICAgIChyZW1vdmVBY3Rpb24pPVwicmVjb3JkZXIucmVtb3ZlQWN0aW9uKCRldmVudClcIlxuICAgICAgICAgICAgICAoYWRkTm90ZSk9XCJyZWNvcmRlci5hZGROb3RlKCRldmVudC5pZCwgJGV2ZW50Lm5vdGUpXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgQGlmIChhY3RpdmVUYWIoKSA9PT0gJ3JlcGxheScpIHtcbiAgICAgICAgICAgIDxhcHAtc2Vzc2lvbi1yZXBsYXkgLz5cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBAaWYgKGFjdGl2ZVRhYigpID09PSAndGVzdCcpIHtcbiAgICAgICAgICAgIDxhcHAtdGVzdC1wcmV2aWV3IFt0ZXN0XT1cImFpU2VydmljZS5sYXN0VGVzdCgpXCIgLz5cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBAaWYgKGFjdGl2ZVRhYigpID09PSAnc2Vzc2lvbnMnKSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Vzc2lvbnMtbGlzdFwiPlxuICAgICAgICAgICAgICBAZm9yIChzZXNzaW9uIG9mIHJlY29yZGVyLnNlc3Npb25zKCk7IHRyYWNrIHNlc3Npb24uaWQpIHtcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Vzc2lvbi1jYXJkXCI+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Vzc2lvbi1jYXJkLWhlYWRlclwiPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNlc3Npb24tbmFtZVwiPnt7IHNlc3Npb24ubmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzZXNzaW9uLW1ldGFcIj57eyBzZXNzaW9uLmFjdGlvbnMubGVuZ3RoIH19IEFrdGlvbmVuPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Vzc2lvbi1jYXJkLWFjdGlvbnNcIj5cbiAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cInNtLWJ0blwiIChjbGljayk9XCJsb2FkQW5kR2VuZXJhdGUoc2Vzc2lvbilcIj7wn6SWIE5ldSBnZW5lcmllcmVuPC9idXR0b24+XG4gICAgICAgICAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJzbS1idG4gZGFuZ2VyXCIgKGNsaWNrKT1cInJlY29yZGVyLmRlbGV0ZVNlc3Npb24oc2Vzc2lvbi5pZClcIj7wn5eRPC9idXR0b24+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFJlc2l6ZSBIYW5kbGUgLS0+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJyZXNpemUtaGFuZGxlXCIgKG1vdXNlZG93bik9XCJzdGFydFJlc2l6ZSgkZXZlbnQpXCI+4qC/PC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICB9XG5cbiAgICA8IS0tIFNldHRpbmdzIERpYWxvZyAtLT5cbiAgICBAaWYgKHNob3dTZXR0aW5ncygpKSB7XG4gICAgICA8YXBwLXNldHRpbmdzLWRpYWxvZyAoY2xvc2UpPVwic2hvd1NldHRpbmdzLnNldChmYWxzZSlcIiAvPlxuICAgIH1cbiAgYCxcbiAgc3R5bGVzOiBbYFxuICAgIC5kZWJ1Zy1mYWIge1xuICAgICAgcG9zaXRpb246IGZpeGVkO1xuICAgICAgYm90dG9tOiAyNHB4O1xuICAgICAgcmlnaHQ6IDI0cHg7XG4gICAgICB6LWluZGV4OiA5OTk5OTtcbiAgICAgIHdpZHRoOiA1MnB4O1xuICAgICAgaGVpZ2h0OiA1MnB4O1xuICAgICAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAgICAgYm9yZGVyOiBub25lO1xuICAgICAgYmFja2dyb3VuZDogIzFlMjkzYjtcbiAgICAgIGNvbG9yOiB3aGl0ZTtcbiAgICAgIGZvbnQtc2l6ZTogMjJweDtcbiAgICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gICAgICBib3gtc2hhZG93OiAwIDRweCAyMHB4IHJnYmEoMCwwLDAsMC40KTtcbiAgICAgIHRyYW5zaXRpb246IHRyYW5zZm9ybSAwLjJzLCBiYWNrZ3JvdW5kIDAuMnM7XG4gICAgICBwb3NpdGlvbjogZml4ZWQ7XG4gICAgfVxuICAgIC5kZWJ1Zy1mYWI6aG92ZXIgeyB0cmFuc2Zvcm06IHNjYWxlKDEuMSk7IGJhY2tncm91bmQ6ICMzMzQxNTU7IH1cbiAgICAuZGVidWctZmFiLnJlY29yZGluZyB7IGJhY2tncm91bmQ6ICNkYzI2MjY7IH1cbiAgICAuZGVidWctZmFiLnB1bHNlIHsgYW5pbWF0aW9uOiBmYWJQdWxzZSAxLjVzIGVhc2UtaW4tb3V0IGluZmluaXRlOyB9XG4gICAgQGtleWZyYW1lcyBmYWJQdWxzZSB7XG4gICAgICAwJSwgMTAwJSB7IGJveC1zaGFkb3c6IDAgNHB4IDIwcHggcmdiYSgyMjAsMzgsMzgsMC40KTsgfVxuICAgICAgNTAlIHsgYm94LXNoYWRvdzogMCA0cHggMzBweCByZ2JhKDIyMCwzOCwzOCwwLjkpLCAwIDAgMCA4cHggcmdiYSgyMjAsMzgsMzgsMC4xNSk7IH1cbiAgICB9XG4gICAgLmZhYi1iYWRnZSB7XG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICB0b3A6IC00cHg7XG4gICAgICByaWdodDogLTRweDtcbiAgICAgIGJhY2tncm91bmQ6ICNmNTllMGI7XG4gICAgICBjb2xvcjogIzAwMDtcbiAgICAgIGZvbnQtc2l6ZTogMTBweDtcbiAgICAgIGZvbnQtd2VpZ2h0OiA3MDA7XG4gICAgICBtaW4td2lkdGg6IDE4cHg7XG4gICAgICBoZWlnaHQ6IDE4cHg7XG4gICAgICBib3JkZXItcmFkaXVzOiA5cHg7XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgICAgcGFkZGluZzogMCA0cHg7XG4gICAgfVxuXG4gICAgLmRlYnVnLXBhbmVsIHtcbiAgICAgIHBvc2l0aW9uOiBmaXhlZDtcbiAgICAgIHotaW5kZXg6IDk5OTk4O1xuICAgICAgd2lkdGg6IDQyMHB4O1xuICAgICAgbWF4LWhlaWdodDogODB2aDtcbiAgICAgIGJhY2tncm91bmQ6ICMwZjE3MmE7XG4gICAgICBjb2xvcjogI2UyZThmMDtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDEycHg7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjMWUzYTVmO1xuICAgICAgYm94LXNoYWRvdzogMCAyNXB4IDYwcHggcmdiYSgwLDAsMCwwLjYpO1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICBmb250LWZhbWlseTogJ1NlZ29lIFVJJywgc3lzdGVtLXVpLCBzYW5zLXNlcmlmO1xuICAgICAgZm9udC1zaXplOiAxM3B4O1xuICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICB9XG4gICAgLnBvcy1ib3R0b20tcmlnaHQgeyBib3R0b206IDg4cHg7IHJpZ2h0OiAyNHB4OyB9XG4gICAgLnBvcy1ib3R0b20tbGVmdCAgeyBib3R0b206IDg4cHg7IGxlZnQ6IDI0cHg7IH1cbiAgICAucG9zLXRvcC1yaWdodCAgICB7IHRvcDogMjRweDsgcmlnaHQ6IDI0cHg7IH1cbiAgICAucG9zLXRvcC1sZWZ0ICAgICB7IHRvcDogMjRweDsgbGVmdDogMjRweDsgfVxuXG4gICAgLnBhbmVsLWhlYWRlciB7XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgICAgIHBhZGRpbmc6IDEwcHggMTRweDtcbiAgICAgIGJhY2tncm91bmQ6ICMxZTI5M2I7XG4gICAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgIzMzNDE1NTtcbiAgICAgIGN1cnNvcjogbW92ZTtcbiAgICAgIHVzZXItc2VsZWN0OiBub25lO1xuICAgICAgZmxleC1zaHJpbms6IDA7XG4gICAgfVxuICAgIC5oZWFkZXItbGVmdCB7IGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGdhcDogOHB4OyB9XG4gICAgLnBhbmVsLWljb24geyBmb250LXNpemU6IDE2cHg7IH1cbiAgICAucGFuZWwtdGl0bGUgeyBmb250LXdlaWdodDogNjAwOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjZjFmNWY5OyB9XG4gICAgLnJlYy1pbmRpY2F0b3Ige1xuICAgICAgZm9udC1zaXplOiAxMHB4O1xuICAgICAgZm9udC13ZWlnaHQ6IDcwMDtcbiAgICAgIGNvbG9yOiAjZWY0NDQ0O1xuICAgICAgYmFja2dyb3VuZDogcmdiYSgyMzksNjgsNjgsMC4xNSk7XG4gICAgICBwYWRkaW5nOiAycHggN3B4O1xuICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xuICAgICAgYW5pbWF0aW9uOiBibGluayAxcyBzdGVwLWVuZCBpbmZpbml0ZTtcbiAgICB9XG4gICAgLnJlYy1pbmRpY2F0b3IucGF1c2VkIHsgY29sb3I6ICNmNTllMGI7IGJhY2tncm91bmQ6IHJnYmEoMjQ1LDE1OCwxMSwwLjE1KTsgYW5pbWF0aW9uOiBub25lOyB9XG4gICAgQGtleWZyYW1lcyBibGluayB7IDUwJSB7IG9wYWNpdHk6IDAuNDsgfSB9XG4gICAgLmhlYWRlci1hY3Rpb25zIHsgZGlzcGxheTogZmxleDsgZ2FwOiA0cHg7IH1cbiAgICAuaWNvbi1idG4ge1xuICAgICAgYmFja2dyb3VuZDogbm9uZTtcbiAgICAgIGJvcmRlcjogbm9uZTtcbiAgICAgIGNvbG9yOiAjOTRhM2I4O1xuICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgcGFkZGluZzogNHB4O1xuICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xuICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgbGluZS1oZWlnaHQ6IDE7XG4gICAgICB0cmFuc2l0aW9uOiBjb2xvciAwLjE1cywgYmFja2dyb3VuZCAwLjE1cztcbiAgICB9XG4gICAgLmljb24tYnRuOmhvdmVyIHsgY29sb3I6ICNmMWY1Zjk7IGJhY2tncm91bmQ6ICMzMzQxNTU7IH1cblxuICAgIC5zZXNzaW9uLXNldHVwIHtcbiAgICAgIHBhZGRpbmc6IDEwcHggMTRweDtcbiAgICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjMWUyOTNiO1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICBnYXA6IDZweDtcbiAgICAgIGZsZXgtc2hyaW5rOiAwO1xuICAgIH1cbiAgICAuc2Vzc2lvbi1pbnB1dCwgLnNlc3Npb24tZGVzYyB7XG4gICAgICBiYWNrZ3JvdW5kOiAjMWUyOTNiO1xuICAgICAgYm9yZGVyOiAxcHggc29saWQgIzMzNDE1NTtcbiAgICAgIGNvbG9yOiAjZTJlOGYwO1xuICAgICAgYm9yZGVyLXJhZGl1czogNnB4O1xuICAgICAgcGFkZGluZzogNnB4IDEwcHg7XG4gICAgICBmb250LXNpemU6IDEycHg7XG4gICAgICB3aWR0aDogMTAwJTtcbiAgICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gICAgICByZXNpemU6IHZlcnRpY2FsO1xuICAgIH1cbiAgICAuc2Vzc2lvbi1pbnB1dDpmb2N1cywgLnNlc3Npb24tZGVzYzpmb2N1cyB7XG4gICAgICBvdXRsaW5lOiBub25lO1xuICAgICAgYm9yZGVyLWNvbG9yOiAjM2I4MmY2O1xuICAgIH1cblxuICAgIC5yZWNvcmRpbmctY29udHJvbHMge1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIGdhcDogNnB4O1xuICAgICAgcGFkZGluZzogMTBweCAxNHB4O1xuICAgICAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICMxZTI5M2I7XG4gICAgICBmbGV4LXdyYXA6IHdyYXA7XG4gICAgICBmbGV4LXNocmluazogMDtcbiAgICB9XG4gICAgLmN0cmwtYnRuIHtcbiAgICAgIGJvcmRlcjogbm9uZTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDZweDtcbiAgICAgIHBhZGRpbmc6IDZweCAxNHB4O1xuICAgICAgZm9udC1zaXplOiAxMnB4O1xuICAgICAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICAgIHRyYW5zaXRpb246IGZpbHRlciAwLjE1cywgdHJhbnNmb3JtIDAuMXM7XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgIGdhcDogNXB4O1xuICAgIH1cbiAgICAuY3RybC1idG46aG92ZXI6bm90KDpkaXNhYmxlZCkgeyBmaWx0ZXI6IGJyaWdodG5lc3MoMS4xNSk7IHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtMXB4KTsgfVxuICAgIC5jdHJsLWJ0bjphY3RpdmU6bm90KDpkaXNhYmxlZCkgeyB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoMCk7IH1cbiAgICAuY3RybC1idG46ZGlzYWJsZWQgeyBvcGFjaXR5OiAwLjU7IGN1cnNvcjogbm90LWFsbG93ZWQ7IH1cbiAgICAuY3RybC1idG4uc3RhcnQgICAgeyBiYWNrZ3JvdW5kOiAjMTZhMzRhOyBjb2xvcjogI2ZmZjsgfVxuICAgIC5jdHJsLWJ0bi5zdG9wICAgICB7IGJhY2tncm91bmQ6ICNkYzI2MjY7IGNvbG9yOiAjZmZmOyB9XG4gICAgLmN0cmwtYnRuLnBhdXNlICAgIHsgYmFja2dyb3VuZDogI2Q5NzcwNjsgY29sb3I6ICNmZmY7IH1cbiAgICAuY3RybC1idG4uZ2VuZXJhdGUgeyBiYWNrZ3JvdW5kOiAjN2MzYWVkOyBjb2xvcjogI2ZmZjsgZmxleDogMTsganVzdGlmeS1jb250ZW50OiBjZW50ZXI7IH1cbiAgICAuY3RybC1idG4uY2xlYXIgICAgeyBiYWNrZ3JvdW5kOiAjMzc0MTUxOyBjb2xvcjogIzljYTNhZjsgcGFkZGluZzogNnB4IDEwcHg7IH1cbiAgICAuc3Bpbm5lciB7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgYW5pbWF0aW9uOiBzcGluIDAuOHMgbGluZWFyIGluZmluaXRlOyB9XG4gICAgQGtleWZyYW1lcyBzcGluIHsgdG8geyB0cmFuc2Zvcm06IHJvdGF0ZSgzNjBkZWcpOyB9IH1cblxuICAgIC5lcnJvci1iYW5uZXIge1xuICAgICAgYmFja2dyb3VuZDogcmdiYSgyMjAsMzgsMzgsMC4xNSk7XG4gICAgICBib3JkZXItbGVmdDogM3B4IHNvbGlkICNkYzI2MjY7XG4gICAgICBjb2xvcjogI2ZjYTVhNTtcbiAgICAgIHBhZGRpbmc6IDhweCAxNHB4O1xuICAgICAgZm9udC1zaXplOiAxMnB4O1xuICAgICAgZmxleC1zaHJpbms6IDA7XG4gICAgfVxuXG4gICAgLnRhYi1iYXIge1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjMWUyOTNiO1xuICAgICAgZmxleC1zaHJpbms6IDA7XG4gICAgfVxuICAgIC50YWItYnRuIHtcbiAgICAgIGZsZXg6IDE7XG4gICAgICBiYWNrZ3JvdW5kOiBub25lO1xuICAgICAgYm9yZGVyOiBub25lO1xuICAgICAgY29sb3I6ICM2NDc0OGI7XG4gICAgICBwYWRkaW5nOiA4cHggNHB4O1xuICAgICAgZm9udC1zaXplOiAxMnB4O1xuICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgICAgIGdhcDogNXB4O1xuICAgICAgYm9yZGVyLWJvdHRvbTogMnB4IHNvbGlkIHRyYW5zcGFyZW50O1xuICAgICAgdHJhbnNpdGlvbjogY29sb3IgMC4xNXM7XG4gICAgfVxuICAgIC50YWItYnRuOmhvdmVyOm5vdCg6ZGlzYWJsZWQpIHsgY29sb3I6ICNjYmQ1ZTE7IH1cbiAgICAudGFiLWJ0bi5hY3RpdmUgeyBjb2xvcjogIzYwYTVmYTsgYm9yZGVyLWJvdHRvbS1jb2xvcjogIzNiODJmNjsgfVxuICAgIC50YWItYnRuOmRpc2FibGVkIHsgb3BhY2l0eTogMC40OyBjdXJzb3I6IG5vdC1hbGxvd2VkOyB9XG4gICAgLnRhYi1iYWRnZSB7XG4gICAgICBiYWNrZ3JvdW5kOiAjMzM0MTU1O1xuICAgICAgY29sb3I6ICM5NGEzYjg7XG4gICAgICBmb250LXNpemU6IDEwcHg7XG4gICAgICBwYWRkaW5nOiAxcHggNXB4O1xuICAgICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgIH1cbiAgICAudGFiLWJhZGdlLm5ldyB7IGJhY2tncm91bmQ6ICM3YzNhZWQ7IGNvbG9yOiAjZTlkNWZmOyB9XG5cbiAgICAudGFiLWNvbnRlbnQge1xuICAgICAgb3ZlcmZsb3cteTogYXV0bztcbiAgICAgIGZsZXg6IDE7XG4gICAgICBtaW4taGVpZ2h0OiAwO1xuICAgIH1cbiAgICAudGFiLWNvbnRlbnQ6Oi13ZWJraXQtc2Nyb2xsYmFyIHsgd2lkdGg6IDVweDsgfVxuICAgIC50YWItY29udGVudDo6LXdlYmtpdC1zY3JvbGxiYXItdHJhY2sgeyBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDsgfVxuICAgIC50YWItY29udGVudDo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWIgeyBiYWNrZ3JvdW5kOiAjMzM0MTU1OyBib3JkZXItcmFkaXVzOiAzcHg7IH1cblxuICAgIC5zZXNzaW9ucy1saXN0IHsgcGFkZGluZzogMTBweCAxNHB4OyBkaXNwbGF5OiBmbGV4OyBmbGV4LWRpcmVjdGlvbjogY29sdW1uOyBnYXA6IDhweDsgfVxuICAgIC5zZXNzaW9uLWNhcmQge1xuICAgICAgYmFja2dyb3VuZDogIzFlMjkzYjtcbiAgICAgIGJvcmRlcjogMXB4IHNvbGlkICMzMzQxNTU7XG4gICAgICBib3JkZXItcmFkaXVzOiA4cHg7XG4gICAgICBwYWRkaW5nOiAxMHB4O1xuICAgIH1cbiAgICAuc2Vzc2lvbi1jYXJkLWhlYWRlciB7XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgIG1hcmdpbi1ib3R0b206IDhweDtcbiAgICB9XG4gICAgLnNlc3Npb24tbmFtZSB7IGZvbnQtd2VpZ2h0OiA2MDA7IGNvbG9yOiAjZjFmNWY5OyBmb250LXNpemU6IDEzcHg7IH1cbiAgICAuc2Vzc2lvbi1tZXRhIHsgZm9udC1zaXplOiAxMXB4OyBjb2xvcjogIzY0NzQ4YjsgfVxuICAgIC5zZXNzaW9uLWNhcmQtYWN0aW9ucyB7IGRpc3BsYXk6IGZsZXg7IGdhcDogNnB4OyB9XG4gICAgLnNtLWJ0biB7XG4gICAgICBiYWNrZ3JvdW5kOiAjMzM0MTU1O1xuICAgICAgYm9yZGVyOiBub25lO1xuICAgICAgY29sb3I6ICNjYmQ1ZTE7XG4gICAgICBwYWRkaW5nOiA0cHggMTBweDtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDVweDtcbiAgICAgIGZvbnQtc2l6ZTogMTFweDtcbiAgICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICAgIHRyYW5zaXRpb246IGJhY2tncm91bmQgMC4xNXM7XG4gICAgfVxuICAgIC5zbS1idG46aG92ZXIgeyBiYWNrZ3JvdW5kOiAjNDc1NTY5OyB9XG4gICAgLnNtLWJ0bi5kYW5nZXIgeyBjb2xvcjogI2ZjYTVhNTsgfVxuICAgIC5zbS1idG4uZGFuZ2VyOmhvdmVyIHsgYmFja2dyb3VuZDogcmdiYSgyMjAsMzgsMzgsMC4yKTsgfVxuXG4gICAgLnJlc2l6ZS1oYW5kbGUge1xuICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgY29sb3I6ICMzMzQxNTU7XG4gICAgICBjdXJzb3I6IG5zLXJlc2l6ZTtcbiAgICAgIGZvbnQtc2l6ZTogMTZweDtcbiAgICAgIHBhZGRpbmc6IDJweDtcbiAgICAgIGZsZXgtc2hyaW5rOiAwO1xuICAgICAgYmFja2dyb3VuZDogIzBmMTcyYTtcbiAgICAgIHVzZXItc2VsZWN0OiBub25lO1xuICAgIH1cbiAgICAucmVzaXplLWhhbmRsZTpob3ZlciB7IGNvbG9yOiAjNjQ3NDhiOyB9XG4gIGBdLFxufSlcbmV4cG9ydCBjbGFzcyBEZWJ1Z1BhbmVsQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICByZWNvcmRlciA9IGluamVjdChSZWNvcmRlclNlcnZpY2UpO1xuICBhaVNlcnZpY2UgPSBpbmplY3QoQWlHZW5lcmF0b3JTZXJ2aWNlKTtcbiAgcnJ3ZWIgPSBpbmplY3QoUnJ3ZWJSZWNvcmRlclNlcnZpY2UpO1xuXG4gIHBhbmVsT3BlbiA9IHNpZ25hbChmYWxzZSk7XG4gIGFjdGl2ZVRhYiA9IHNpZ25hbDxQYW5lbFRhYj4oJ2FjdGlvbnMnKTtcbiAgcG9zaXRpb24gPSBzaWduYWw8UGFuZWxQb3NpdGlvbj4oJ2JvdHRvbS1yaWdodCcpO1xuICBwYW5lbFdpZHRoID0gc2lnbmFsKDQyMCk7XG4gIHNob3dTZXR0aW5ncyA9IHNpZ25hbChmYWxzZSk7XG4gIHNlc3Npb25OYW1lID0gJyc7XG4gIHNlc3Npb25EZXNjID0gJyc7XG5cbiAgaGFzQWN0aW9ucyA9IGNvbXB1dGVkKFxuICAgICgpID0+ICh0aGlzLnJlY29yZGVyLmN1cnJlbnRTZXNzaW9uKCk/LmFjdGlvbnMubGVuZ3RoID8/IDApID4gMCB8fFxuICAgICAgICAgICh0aGlzLnJlY29yZGVyLnNlc3Npb25zKCkubGVuZ3RoID4gMClcbiAgKTtcblxuICBwcml2YXRlIHJlc2l6aW5nID0gZmFsc2U7XG4gIHByaXZhdGUgcmVzaXplU3RhcnRZID0gMDtcbiAgcHJpdmF0ZSByZXNpemVTdGFydEggPSAwO1xuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIC8vIEtleWJvYXJkIHNob3J0Y3V0OiBDdHJsK1NoaWZ0K0RcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgdGhpcy5oYW5kbGVIb3RrZXkpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIHRoaXMuaGFuZGxlSG90a2V5KTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlSG90a2V5ID0gKGU6IEtleWJvYXJkRXZlbnQpID0+IHtcbiAgICBpZiAoZS5jdHJsS2V5ICYmIGUuc2hpZnRLZXkgJiYgZS5rZXkgPT09ICdEJykge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgdGhpcy50b2dnbGVQYW5lbCgpO1xuICAgIH1cbiAgICBpZiAoZS5jdHJsS2V5ICYmIGUuc2hpZnRLZXkgJiYgZS5rZXkgPT09ICdSJykge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgaWYgKHRoaXMucmVjb3JkZXIuaXNSZWNvcmRpbmcoKSkge1xuICAgICAgICB0aGlzLnN0b3BSZWNvcmRpbmcoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc3RhcnRSZWNvcmRpbmcoKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgdG9nZ2xlUGFuZWwoKTogdm9pZCB7XG4gICAgdGhpcy5wYW5lbE9wZW4udXBkYXRlKHYgPT4gIXYpO1xuICAgIGlmICh0aGlzLnBhbmVsT3BlbigpICYmICF0aGlzLnJlY29yZGVyLmN1cnJlbnRTZXNzaW9uKCkpIHtcbiAgICAgIHRoaXMuYWN0aXZlVGFiLnNldCgnYWN0aW9ucycpO1xuICAgIH1cbiAgfVxuXG4gIGN5Y2xlUG9zaXRpb24oKTogdm9pZCB7XG4gICAgY29uc3QgcG9zaXRpb25zOiBQYW5lbFBvc2l0aW9uW10gPSBbJ2JvdHRvbS1yaWdodCcsICdib3R0b20tbGVmdCcsICd0b3AtcmlnaHQnLCAndG9wLWxlZnQnXTtcbiAgICBjb25zdCBpZHggPSBwb3NpdGlvbnMuaW5kZXhPZih0aGlzLnBvc2l0aW9uKCkpO1xuICAgIHRoaXMucG9zaXRpb24uc2V0KHBvc2l0aW9uc1soaWR4ICsgMSkgJSBwb3NpdGlvbnMubGVuZ3RoXSk7XG4gIH1cblxuICBzdGFydFJlY29yZGluZygpOiB2b2lkIHtcbiAgICB0aGlzLnJlY29yZGVyLnN0YXJ0UmVjb3JkaW5nKFxuICAgICAgdGhpcy5zZXNzaW9uTmFtZSB8fCB1bmRlZmluZWQsXG4gICAgICB0aGlzLnNlc3Npb25EZXNjIHx8IHVuZGVmaW5lZFxuICAgICk7XG4gICAgLy8gU3RhcnQgcnJ3ZWIgaW4gcGFyYWxsZWwgZm9yIHZpc3VhbCByZXBsYXlcbiAgICB0aGlzLnJyd2ViLnN0YXJ0UmVjb3JkaW5nKCk7XG4gICAgdGhpcy5hY3RpdmVUYWIuc2V0KCdhY3Rpb25zJyk7XG4gIH1cblxuICBzdG9wUmVjb3JkaW5nKCk6IHZvaWQge1xuICAgIGNvbnN0IHNlc3Npb24gPSB0aGlzLnJlY29yZGVyLnN0b3BSZWNvcmRpbmcoKTtcbiAgICB0aGlzLnJyd2ViLnN0b3BSZWNvcmRpbmcoKTtcbiAgICBpZiAoc2Vzc2lvbikge1xuICAgICAgdGhpcy5hY3RpdmVUYWIuc2V0KCdhY3Rpb25zJyk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZ2VuZXJhdGVUZXN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHNlc3Npb24gPSB0aGlzLnJlY29yZGVyLmN1cnJlbnRTZXNzaW9uKCkgPz8gdGhpcy5yZWNvcmRlci5zZXNzaW9ucygpLmF0KC0xKTtcbiAgICBpZiAoIXNlc3Npb24pIHJldHVybjtcbiAgICBhd2FpdCB0aGlzLmFpU2VydmljZS5nZW5lcmF0ZUN5cHJlc3NUZXN0KHNlc3Npb24pO1xuICAgIHRoaXMuYWN0aXZlVGFiLnNldCgndGVzdCcpO1xuICB9XG5cbiAgYXN5bmMgbG9hZEFuZEdlbmVyYXRlKHNlc3Npb246IFJlY29yZGluZ1Nlc3Npb24pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmFpU2VydmljZS5nZW5lcmF0ZUN5cHJlc3NUZXN0KHNlc3Npb24pO1xuICAgIHRoaXMuYWN0aXZlVGFiLnNldCgndGVzdCcpO1xuICB9XG5cbiAgLy8gRHJhZyB0byByZXBvc2l0aW9uXG4gIHN0YXJ0RHJhZyhlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKChlLnRhcmdldCBhcyBIVE1MRWxlbWVudCkuY2xvc2VzdCgnYnV0dG9uJykpIHJldHVybjtcbiAgICBjb25zdCBwYW5lbCA9IChlLmN1cnJlbnRUYXJnZXQgYXMgSFRNTEVsZW1lbnQpLnBhcmVudEVsZW1lbnQhO1xuICAgIGNvbnN0IHN0YXJ0WCA9IGUuY2xpZW50WCAtIHBhbmVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQ7XG4gICAgY29uc3Qgc3RhcnRZID0gZS5jbGllbnRZIC0gcGFuZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wO1xuXG4gICAgY29uc3Qgb25Nb3ZlID0gKGV2OiBNb3VzZUV2ZW50KSA9PiB7XG4gICAgICBwYW5lbC5zdHlsZS5sZWZ0ID0gYCR7ZXYuY2xpZW50WCAtIHN0YXJ0WH1weGA7XG4gICAgICBwYW5lbC5zdHlsZS50b3AgID0gYCR7ZXYuY2xpZW50WSAtIHN0YXJ0WX1weGA7XG4gICAgICBwYW5lbC5zdHlsZS5yaWdodCA9ICdhdXRvJztcbiAgICAgIHBhbmVsLnN0eWxlLmJvdHRvbSA9ICdhdXRvJztcbiAgICB9O1xuICAgIGNvbnN0IG9uVXAgPSAoKSA9PiB7XG4gICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCBvbk1vdmUpO1xuICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIG9uVXApO1xuICAgIH07XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgb25Nb3ZlKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgb25VcCk7XG4gIH1cblxuICAvLyBSZXNpemUgaGVpZ2h0XG4gIHN0YXJ0UmVzaXplKGU6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBwYW5lbCA9IChlLmN1cnJlbnRUYXJnZXQgYXMgSFRNTEVsZW1lbnQpLnBhcmVudEVsZW1lbnQhO1xuICAgIHRoaXMucmVzaXplU3RhcnRZID0gZS5jbGllbnRZO1xuICAgIHRoaXMucmVzaXplU3RhcnRIID0gcGFuZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0O1xuXG4gICAgY29uc3Qgb25Nb3ZlID0gKGV2OiBNb3VzZUV2ZW50KSA9PiB7XG4gICAgICBjb25zdCBuZXdIID0gTWF0aC5tYXgoMjUwLCB0aGlzLnJlc2l6ZVN0YXJ0SCArIChldi5jbGllbnRZIC0gdGhpcy5yZXNpemVTdGFydFkpKTtcbiAgICAgIHBhbmVsLnN0eWxlLm1heEhlaWdodCA9IGAke25ld0h9cHhgO1xuICAgIH07XG4gICAgY29uc3Qgb25VcCA9ICgpID0+IHtcbiAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIG9uTW92ZSk7XG4gICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgb25VcCk7XG4gICAgfTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCBvbk1vdmUpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCBvblVwKTtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb3JkZWQtYWN0aW9uLm1vZGVsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZGVidWctcmVjb3JkZXIvc3JjL2xpYi9tb2RlbHMvcmVjb3JkZWQtYWN0aW9uLm1vZGVsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgdHlwZSBBY3Rpb25UeXBlID1cclxuICB8ICdjbGljaydcclxuICB8ICdkYmxjbGljaydcclxuICB8ICdpbnB1dCdcclxuICB8ICdzZWxlY3QnXHJcbiAgfCAnc3VibWl0J1xyXG4gIHwgJ25hdmlnYXRpb24nXHJcbiAgfCAna2V5cHJlc3MnXHJcbiAgfCAnc2Nyb2xsJ1xyXG4gIHwgJ2hvdmVyJ1xyXG4gIHwgJ2Fzc2VydGlvbidcclxuICB8ICdzY3JlZW5zaG90JztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRWxlbWVudEluZm8ge1xyXG4gIHRhZ05hbWU6IHN0cmluZztcclxuICBpZD86IHN0cmluZztcclxuICBjbGFzc2VzOiBzdHJpbmdbXTtcclxuICBkYXRhVGVzdElkPzogc3RyaW5nO1xyXG4gIGRhdGFDeT86IHN0cmluZztcclxuICBuYW1lPzogc3RyaW5nO1xyXG4gIHR5cGU/OiBzdHJpbmc7XHJcbiAgcGxhY2Vob2xkZXI/OiBzdHJpbmc7XHJcbiAgdGV4dD86IHN0cmluZztcclxuICBocmVmPzogc3RyaW5nO1xyXG4gIGFyaWFMYWJlbD86IHN0cmluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBSZWNvcmRlZEFjdGlvbiB7XHJcbiAgaWQ6IHN0cmluZztcclxuICB0eXBlOiBBY3Rpb25UeXBlO1xyXG4gIHRpbWVzdGFtcDogbnVtYmVyO1xyXG4gIHNlbGVjdG9yOiBzdHJpbmc7XHJcbiAgc2VsZWN0b3JTdHJhdGVneTogJ2RhdGEtdGVzdGlkJyB8ICdkYXRhLWN5JyB8ICdpZCcgfCAnbmFtZScgfCAnY2xhc3MnIHwgJ3RleHQnIHwgJ250aCcgfCAnY29tYmluZWQnO1xyXG4gIHZhbHVlPzogc3RyaW5nO1xyXG4gIHVybDogc3RyaW5nO1xyXG4gIGRlc2NyaXB0aW9uOiBzdHJpbmc7XHJcbiAgZWxlbWVudD86IEVsZW1lbnRJbmZvO1xyXG4gIHNjcmVlbnNob3REYXRhVXJsPzogc3RyaW5nO1xyXG4gIG5vdGU/OiBzdHJpbmc7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUmVjb3JkaW5nU2Vzc2lvbiB7XHJcbiAgaWQ6IHN0cmluZztcclxuICBuYW1lOiBzdHJpbmc7XHJcbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XHJcbiAgc3RhcnRUaW1lOiBudW1iZXI7XHJcbiAgZW5kVGltZT86IG51bWJlcjtcclxuICBzdGFydFVybDogc3RyaW5nO1xyXG4gIGFjdGlvbnM6IFJlY29yZGVkQWN0aW9uW107XHJcbiAgdGFncz86IHN0cmluZ1tdO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIEdlbmVyYXRlZFRlc3Qge1xyXG4gIGNvZGU6IHN0cmluZztcclxuICBnZW5lcmF0ZWRBdDogbnVtYmVyO1xyXG4gIG1vZGVsOiBzdHJpbmc7XHJcbiAgc2Vzc2lvbklkOiBzdHJpbmc7XHJcbiAgcHJvbXB0VG9rZW5zPzogbnVtYmVyO1xyXG4gIGNvbXBsZXRpb25Ub2tlbnM/OiBudW1iZXI7XHJcbn1cclxuIl19