ngx-acuw
Version:
Angular components using WEBGL (threejs)
81 lines • 15.1 kB
JavaScript
import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class PerformanceMonitorComponent {
constructor(changeDetector) {
this.changeDetector = changeDetector;
this.fps = -1;
this.fpsMin = -1;
this.fpsMax = -1;
this.framesCnt = 0;
this.timeLastFpsCalc = 0;
this.fpsHistory = new Array();
this.maxHistoryLength = 60;
}
/**
* Method to be called at the end of a frame
*/
end() {
// When called the first time, set the current time and return
if (this.timeLastFpsCalc === 0) {
this.timeLastFpsCalc = Date.now();
return;
}
// Increase the frames counter
this.framesCnt++;
// Get the milliseconds elapsed since January 1, 1970 for the current frame
const currentFrameTime = Date.now();
// Calculate the FPS only every second
if (currentFrameTime >= this.timeLastFpsCalc + 1000) {
// Calculate the frames per second
this.fps = this.framesCnt / (currentFrameTime - this.timeLastFpsCalc) * 1000;
// Calculate the min. frames per second
if (this.fpsMin === -1 || this.fps < this.fpsMin) {
this.fpsMin = this.fps;
}
// Calculate the max. frames per second
if (this.fpsMax === -1 || this.fps > this.fpsMax) {
this.fpsMax = this.fps;
}
// Trigger the change detection
this.changeDetector.detectChanges();
// Set the elapsed time to the timeLastFpsCalc
this.timeLastFpsCalc = currentFrameTime;
// Reset the frames counter
this.framesCnt = 0;
// Add fps to the history array
this.fpsHistory.push(this.fps);
if (this.fpsHistory.length >= this.maxHistoryLength) {
this.fpsHistory.shift();
}
// Create / Update chart
const canvasEl = this.chart.nativeElement;
const ctx = canvasEl.getContext('2d');
if (ctx) {
ctx.fillStyle = 'rgb(30, 30, 30)';
ctx.fillRect(0, 0, canvasEl.width, canvasEl.height);
ctx.strokeStyle = 'rgb(255, 255, 255)';
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.beginPath();
ctx.moveTo(0, canvasEl.height);
for (let idx = 0; idx <= this.fpsHistory.length; idx++) {
ctx.lineTo(canvasEl.width / this.maxHistoryLength * idx, canvasEl.height - (this.fpsHistory[idx] / this.fpsMax * canvasEl.height));
if (idx === this.fpsHistory.length - 1) {
ctx.lineTo(canvasEl.width / this.maxHistoryLength * idx, canvasEl.height);
}
}
ctx.fill();
}
}
}
}
PerformanceMonitorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: PerformanceMonitorComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
PerformanceMonitorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: PerformanceMonitorComponent, selector: "acuw-performance-monitor", viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true }], ngImport: i0, template: "<div id=\"pm-container\">\r\n <div id=\"fps-display-container\">\r\n <span id=\"fps-display\">FPS: {{ fps != -1 ? (fps | number: '1.0-0') : '-' }}</span>\r\n <div id=\"min-max-display\">\r\n <span id=\"max-fps-display\">{{ fpsMax != -1 ? (fpsMax | number: '1.0-0') : '-' }} max</span>\r\n <span id=\"min-fps-display\">{{ fpsMin != -1 ? (fpsMin | number: '1.0-0') : '-' }} min</span>\r\n </div>\r\n </div>\r\n <canvas #chart width=\"90\" height=\"40\"></canvas>\r\n</div>", styles: [":host{--position: absolute;--color: rgb(255, 255, 255);--background-color: rgba(0, 0, 0, .8);--top: 5px;--left: 5px;--width: 100px;--padding: 5px;--display: flex;--flex-direction: column;--align-items: center}#pm-container{position:var(--position);color:var(--color);background-color:var(--background-color);top:5px;left:5px;width:100px;padding:5px;display:var(--display);flex-direction:var(--flex-direction);align-items:var(--align-items)}#fps-display-container{display:flex;flex-direction:row;align-items:center}#min-max-display{display:flex;flex-direction:column;font-size:10px;padding-left:5px}\n"], pipes: { "number": i1.DecimalPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: PerformanceMonitorComponent, decorators: [{
type: Component,
args: [{ selector: 'acuw-performance-monitor', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div id=\"pm-container\">\r\n <div id=\"fps-display-container\">\r\n <span id=\"fps-display\">FPS: {{ fps != -1 ? (fps | number: '1.0-0') : '-' }}</span>\r\n <div id=\"min-max-display\">\r\n <span id=\"max-fps-display\">{{ fpsMax != -1 ? (fpsMax | number: '1.0-0') : '-' }} max</span>\r\n <span id=\"min-fps-display\">{{ fpsMin != -1 ? (fpsMin | number: '1.0-0') : '-' }} min</span>\r\n </div>\r\n </div>\r\n <canvas #chart width=\"90\" height=\"40\"></canvas>\r\n</div>", styles: [":host{--position: absolute;--color: rgb(255, 255, 255);--background-color: rgba(0, 0, 0, .8);--top: 5px;--left: 5px;--width: 100px;--padding: 5px;--display: flex;--flex-direction: column;--align-items: center}#pm-container{position:var(--position);color:var(--color);background-color:var(--background-color);top:5px;left:5px;width:100px;padding:5px;display:var(--display);flex-direction:var(--flex-direction);align-items:var(--align-items)}#fps-display-container{display:flex;flex-direction:row;align-items:center}#min-max-display{display:flex;flex-direction:column;font-size:10px;padding-left:5px}\n"] }]
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { chart: [{
type: ViewChild,
args: ['chart']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVyZm9ybWFuY2UtbW9uaXRvci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtYWN1dy9zcmMvbGliL3BlcmZvcm1hbmNlLW1vbml0b3IvcGVyZm9ybWFuY2UtbW9uaXRvci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtYWN1dy9zcmMvbGliL3BlcmZvcm1hbmNlLW1vbml0b3IvcGVyZm9ybWFuY2UtbW9uaXRvci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQXFCLFNBQVMsRUFBYyxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7OztBQVE3RyxNQUFNLE9BQU8sMkJBQTJCO0lBWXRDLFlBQW9CLGNBQWlDO1FBQWpDLG1CQUFjLEdBQWQsY0FBYyxDQUFtQjtRQVJyRCxRQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDVCxXQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDWixXQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDSixjQUFTLEdBQUcsQ0FBQyxDQUFDO1FBQ2Qsb0JBQWUsR0FBRyxDQUFDLENBQUM7UUFDcEIsZUFBVSxHQUFHLElBQUksS0FBSyxFQUFVLENBQUE7UUFDdkIscUJBQWdCLEdBQUcsRUFBRSxDQUFDO0lBR3ZDLENBQUM7SUFFRDs7T0FFRztJQUNILEdBQUc7UUFDRCw4REFBOEQ7UUFDOUQsSUFBSSxJQUFJLENBQUMsZUFBZSxLQUFLLENBQUMsRUFBRTtZQUM5QixJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNsQyxPQUFPO1NBQ1I7UUFDRCw4QkFBOEI7UUFDOUIsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2pCLDRFQUE0RTtRQUM1RSxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNwQyxzQ0FBc0M7UUFDdEMsSUFBSSxnQkFBZ0IsSUFBSSxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksRUFBRTtZQUNuRCxrQ0FBa0M7WUFDbEMsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsU0FBUyxHQUFHLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUM3RSx1Q0FBdUM7WUFDdkMsSUFBRyxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBQztnQkFDOUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDO2FBQ3hCO1lBQ0QsdUNBQXVDO1lBQ3ZDLElBQUcsSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUM7Z0JBQzlDLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQzthQUN4QjtZQUNELCtCQUErQjtZQUMvQixJQUFJLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3BDLDhDQUE4QztZQUM5QyxJQUFJLENBQUMsZUFBZSxHQUFHLGdCQUFnQixDQUFDO1lBQ3hDLDJCQUEyQjtZQUMzQixJQUFJLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQztZQUNuQiwrQkFBK0I7WUFDL0IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQy9CLElBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFO2dCQUNsRCxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO2FBQ3pCO1lBQ0Qsd0JBQXdCO1lBQ3hCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBa0MsQ0FBQztZQUMvRCxNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3RDLElBQUcsR0FBRyxFQUFFO2dCQUNOLEdBQUcsQ0FBQyxTQUFTLEdBQUcsaUJBQWlCLENBQUM7Z0JBQ2xDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxRQUFRLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDcEQsR0FBRyxDQUFDLFdBQVcsR0FBRyxvQkFBb0IsQ0FBQztnQkFDdkMsR0FBRyxDQUFDLFNBQVMsR0FBRyxvQkFBb0IsQ0FBQztnQkFDckMsR0FBRyxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNoQixHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQy9CLEtBQUksSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsRUFBQztvQkFDcEQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxHQUFHLEVBQ3JELFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7b0JBQzVFLElBQUcsR0FBRyxLQUFLLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBQzt3QkFDcEMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxHQUFHLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO3FCQUMzRTtpQkFDRjtnQkFDRCxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7YUFDWjtTQUNGO0lBQ0gsQ0FBQzs7d0hBdkVVLDJCQUEyQjs0R0FBM0IsMkJBQTJCLGdLQ1J4Qyw0Z0JBU007MkZERE8sMkJBQTJCO2tCQU52QyxTQUFTOytCQUNFLDBCQUEwQixtQkFDbkIsdUJBQXVCLENBQUMsTUFBTTt3R0FNM0IsS0FBSztzQkFBeEIsU0FBUzt1QkFBQyxPQUFPIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsIEVsZW1lbnRSZWYsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdhY3V3LXBlcmZvcm1hbmNlLW1vbml0b3InLFxyXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9wZXJmb3JtYW5jZS1tb25pdG9yLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9wZXJmb3JtYW5jZS1tb25pdG9yLmNvbXBvbmVudC5jc3MnXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgUGVyZm9ybWFuY2VNb25pdG9yQ29tcG9uZW50IHtcclxuXHJcbiAgQFZpZXdDaGlsZCgnY2hhcnQnKSBjaGFydCE6IEVsZW1lbnRSZWY7XHJcblxyXG4gIGZwcyA9IC0xO1xyXG4gIGZwc01pbiA9IC0xO1xyXG4gIGZwc01heCA9IC0xO1xyXG4gIHByaXZhdGUgZnJhbWVzQ250ID0gMDtcclxuICBwcml2YXRlIHRpbWVMYXN0RnBzQ2FsYyA9IDA7XHJcbiAgcHJpdmF0ZSBmcHNIaXN0b3J5ID0gbmV3IEFycmF5PG51bWJlcj4oKVxyXG4gIHByaXZhdGUgcmVhZG9ubHkgbWF4SGlzdG9yeUxlbmd0aCA9IDYwO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGNoYW5nZURldGVjdG9yOiBDaGFuZ2VEZXRlY3RvclJlZikge1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogTWV0aG9kIHRvIGJlIGNhbGxlZCBhdCB0aGUgZW5kIG9mIGEgZnJhbWVcclxuICAgKi9cclxuICBlbmQoKTogdm9pZCB7XHJcbiAgICAvLyBXaGVuIGNhbGxlZCB0aGUgZmlyc3QgdGltZSwgc2V0IHRoZSBjdXJyZW50IHRpbWUgYW5kIHJldHVyblxyXG4gICAgaWYgKHRoaXMudGltZUxhc3RGcHNDYWxjID09PSAwKSB7XHJcbiAgICAgIHRoaXMudGltZUxhc3RGcHNDYWxjID0gRGF0ZS5ub3coKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgLy8gSW5jcmVhc2UgdGhlIGZyYW1lcyBjb3VudGVyXHJcbiAgICB0aGlzLmZyYW1lc0NudCsrO1xyXG4gICAgLy8gR2V0IHRoZSBtaWxsaXNlY29uZHMgZWxhcHNlZCBzaW5jZSBKYW51YXJ5IDEsIDE5NzAgZm9yIHRoZSBjdXJyZW50IGZyYW1lIFxyXG4gICAgY29uc3QgY3VycmVudEZyYW1lVGltZSA9IERhdGUubm93KCk7XHJcbiAgICAvLyBDYWxjdWxhdGUgdGhlIEZQUyBvbmx5IGV2ZXJ5IHNlY29uZFxyXG4gICAgaWYgKGN1cnJlbnRGcmFtZVRpbWUgPj0gdGhpcy50aW1lTGFzdEZwc0NhbGMgKyAxMDAwKSB7XHJcbiAgICAgIC8vIENhbGN1bGF0ZSB0aGUgZnJhbWVzIHBlciBzZWNvbmRcclxuICAgICAgdGhpcy5mcHMgPSB0aGlzLmZyYW1lc0NudCAvIChjdXJyZW50RnJhbWVUaW1lIC0gdGhpcy50aW1lTGFzdEZwc0NhbGMpICogMTAwMDtcclxuICAgICAgLy8gQ2FsY3VsYXRlIHRoZSBtaW4uIGZyYW1lcyBwZXIgc2Vjb25kXHJcbiAgICAgIGlmKHRoaXMuZnBzTWluID09PSAtMSB8fCB0aGlzLmZwcyA8IHRoaXMuZnBzTWluKXtcclxuICAgICAgICB0aGlzLmZwc01pbiA9IHRoaXMuZnBzO1xyXG4gICAgICB9XHJcbiAgICAgIC8vIENhbGN1bGF0ZSB0aGUgbWF4LiBmcmFtZXMgcGVyIHNlY29uZFxyXG4gICAgICBpZih0aGlzLmZwc01heCA9PT0gLTEgfHwgdGhpcy5mcHMgPiB0aGlzLmZwc01heCl7XHJcbiAgICAgICAgdGhpcy5mcHNNYXggPSB0aGlzLmZwcztcclxuICAgICAgfVxyXG4gICAgICAvLyBUcmlnZ2VyIHRoZSBjaGFuZ2UgZGV0ZWN0aW9uXHJcbiAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgICAvLyBTZXQgdGhlIGVsYXBzZWQgdGltZSB0byB0aGUgdGltZUxhc3RGcHNDYWxjXHJcbiAgICAgIHRoaXMudGltZUxhc3RGcHNDYWxjID0gY3VycmVudEZyYW1lVGltZTtcclxuICAgICAgLy8gUmVzZXQgdGhlIGZyYW1lcyBjb3VudGVyXHJcbiAgICAgIHRoaXMuZnJhbWVzQ250ID0gMDtcclxuICAgICAgLy8gQWRkIGZwcyB0byB0aGUgaGlzdG9yeSBhcnJheVxyXG4gICAgICB0aGlzLmZwc0hpc3RvcnkucHVzaCh0aGlzLmZwcyk7XHJcbiAgICAgIGlmKHRoaXMuZnBzSGlzdG9yeS5sZW5ndGggPj0gdGhpcy5tYXhIaXN0b3J5TGVuZ3RoKSB7XHJcbiAgICAgICAgdGhpcy5mcHNIaXN0b3J5LnNoaWZ0KCk7XHJcbiAgICAgIH1cclxuICAgICAgLy8gQ3JlYXRlIC8gVXBkYXRlIGNoYXJ0XHJcbiAgICAgIGNvbnN0IGNhbnZhc0VsID0gdGhpcy5jaGFydC5uYXRpdmVFbGVtZW50IGFzIEhUTUxDYW52YXNFbGVtZW50O1xyXG4gICAgICBjb25zdCBjdHggPSBjYW52YXNFbC5nZXRDb250ZXh0KCcyZCcpO1xyXG4gICAgICBpZihjdHgpIHtcclxuICAgICAgICBjdHguZmlsbFN0eWxlID0gJ3JnYigzMCwgMzAsIDMwKSc7XHJcbiAgICAgICAgY3R4LmZpbGxSZWN0KDAsIDAsIGNhbnZhc0VsLndpZHRoLCBjYW52YXNFbC5oZWlnaHQpO1xyXG4gICAgICAgIGN0eC5zdHJva2VTdHlsZSA9ICdyZ2IoMjU1LCAyNTUsIDI1NSknO1xyXG4gICAgICAgIGN0eC5maWxsU3R5bGUgPSAncmdiKDI1NSwgMjU1LCAyNTUpJztcclxuICAgICAgICBjdHguYmVnaW5QYXRoKCk7XHJcbiAgICAgICAgY3R4Lm1vdmVUbygwLCBjYW52YXNFbC5oZWlnaHQpO1xyXG4gICAgICAgIGZvcihsZXQgaWR4ID0gMDsgaWR4IDw9IHRoaXMuZnBzSGlzdG9yeS5sZW5ndGg7IGlkeCsrKXtcclxuICAgICAgICAgIGN0eC5saW5lVG8oY2FudmFzRWwud2lkdGggLyB0aGlzLm1heEhpc3RvcnlMZW5ndGggKiBpZHgsIFxyXG4gICAgICAgICAgICBjYW52YXNFbC5oZWlnaHQgLSAodGhpcy5mcHNIaXN0b3J5W2lkeF0gLyB0aGlzLmZwc01heCAqIGNhbnZhc0VsLmhlaWdodCkpO1xyXG4gICAgICAgICAgaWYoaWR4ID09PSB0aGlzLmZwc0hpc3RvcnkubGVuZ3RoIC0gMSl7XHJcbiAgICAgICAgICAgIGN0eC5saW5lVG8oY2FudmFzRWwud2lkdGggLyB0aGlzLm1heEhpc3RvcnlMZW5ndGggKiBpZHgsIGNhbnZhc0VsLmhlaWdodCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGN0eC5maWxsKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiPGRpdiBpZD1cInBtLWNvbnRhaW5lclwiPlxyXG4gICAgPGRpdiBpZD1cImZwcy1kaXNwbGF5LWNvbnRhaW5lclwiPlxyXG4gICAgICAgIDxzcGFuIGlkPVwiZnBzLWRpc3BsYXlcIj5GUFM6IHt7IGZwcyAhPSAtMSA/IChmcHMgfCBudW1iZXI6ICcxLjAtMCcpIDogJy0nIH19PC9zcGFuPlxyXG4gICAgICAgIDxkaXYgaWQ9XCJtaW4tbWF4LWRpc3BsYXlcIj5cclxuICAgICAgICAgICAgPHNwYW4gaWQ9XCJtYXgtZnBzLWRpc3BsYXlcIj57eyBmcHNNYXggIT0gLTEgPyAoZnBzTWF4IHwgbnVtYmVyOiAnMS4wLTAnKSA6ICctJyB9fSBtYXg8L3NwYW4+XHJcbiAgICAgICAgICAgIDxzcGFuIGlkPVwibWluLWZwcy1kaXNwbGF5XCI+e3sgZnBzTWluICE9IC0xID8gKGZwc01pbiB8IG51bWJlcjogJzEuMC0wJykgOiAnLScgfX0gbWluPC9zcGFuPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgICA8Y2FudmFzICNjaGFydCB3aWR0aD1cIjkwXCIgaGVpZ2h0PVwiNDBcIj48L2NhbnZhcz5cclxuPC9kaXY+Il19