UNPKG

dozee-ecg-chart

Version:

A library for drawing ECG charts with real-time data

217 lines 28.1 kB
import { Component, Input } from '@angular/core'; import { Chart, CategoryScale, LinearScale, LineController, LineElement, PointElement, Title, Tooltip, Legend, } from 'chart.js'; import * as i0 from "@angular/core"; export class DozeeEcgChartComponent { renderer; ngZone; accessToken; userId; stage; strokeColor = '#00ff00'; backgroundColor = '#000000'; eventSource = null; buffer = []; chart; frequency = 256; // Hz duration = 8; // seconds maxPoints = this.frequency * this.duration; // 2048 points ecgData = Array(this.maxPoints).fill(null); bufferLimit = 64 * 64; isPageActive = true; intervalId; inactivityTimeout; // Timer to track inactivity INACTIVE_DELAY = 30000; RETRY_DELAY = 6000; constructor(renderer, ngZone) { this.renderer = renderer; this.ngZone = ngZone; } ngOnInit() { // Register necessary chart components Chart.register(CategoryScale, LinearScale, LineController, LineElement, PointElement, Title, Tooltip, Legend); const ctx = document.getElementById('ecgChart'); ctx.style.backgroundColor = this.backgroundColor; this.chart = new Chart(ctx, { type: 'line', data: { labels: Array(this.maxPoints).fill(0.0), // Empty labels as X axis is fixed datasets: [ { label: 'ECG Data', data: this.ecgData, borderColor: this.strokeColor, borderWidth: 1, fill: false, pointRadius: 0, // Hide points for smooth line }, ], }, options: { animation: false, responsive: true, maintainAspectRatio: false, scales: { x: { type: 'linear', min: 0, max: this.maxPoints, // Set fixed X-axis range (8 seconds) display: false, // Hide the x-axis grid: { display: false }, }, y: { max: 4000, // Adjust based on ECG value range min: 0, type: 'linear', beginAtZero: true, grid: { display: false }, display: false, }, }, plugins: { legend: { display: false, }, }, elements: { line: { tension: 0.4, }, }, }, }); // Initialize SSE connection this.initializeSse(); this.renderer.listen('document', 'visibilitychange', () => { if (document.hidden) { console.log('Page became inactive, starting 30s timeout...'); this.startInactivityTimer(); } else { console.log('Page is active again, canceling inactivity timeout'); this.cancelInactivityTimer(); this.startInterval(); } }); // Start interval initially this.startInterval(); } startInterval() { if (!this.intervalId) { // Update chart data at regular intervals this.intervalId = setInterval(() => { if (this.buffer.length > this.bufferLimit && this.currentIndex === 0) { if (this.stage === 'sit') { console.warn(`Buffer overflow: Skipping ${this.buffer.length - 64} old entries`); } this.buffer.splice(0, this.buffer.length - 64); } if (this.buffer.length > 0) { const entry = this.buffer.shift(); for (const e of entry) { this.addData(e); } } }, 16); // Update frequency (256 Hz) } } startInactivityTimer() { this.inactivityTimeout = setTimeout(() => { console.log('Page has been inactive for 30 seconds, stopping updates.'); this.isPageActive = false; this.clearInterval(); }, this.INACTIVE_DELAY); } cancelInactivityTimer() { if (this.inactivityTimeout) { clearTimeout(this.inactivityTimeout); this.inactivityTimeout = null; } this.isPageActive = true; } clearInterval() { if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; } } currentIndex = 0; addData(e) { if (this.chart.data.labels) { this.ecgData[this.currentIndex] = e.Value; this.chart.data.labels[this.currentIndex] = this.currentIndex; for (let i = this.currentIndex + 1; i < Math.min(this.currentIndex + 64, this.maxPoints); i++) { this.ecgData[i] = null; } // Advance the index, and wrap around if it exceeds maxPoints this.currentIndex = (this.currentIndex + 1) % this.maxPoints; if (this.stage === 'sit') { console.log('Current index:', this.currentIndex); } // Update the chart data this.chart.data.datasets[0].data = this.ecgData; this.chart.update(); } } initializeSse() { const sseUrl = `https://ecgsse${this.stage ? `-${this.stage}` : ''}.dozee.cloud/sse/ecgstream?userId=${this.userId}&accessToken=${this.accessToken}&ngsw-bypass=true`; this.ngZone.runOutsideAngular(() => { this.eventSource = new EventSource(sseUrl); this.eventSource.onmessage = (e) => { const data = JSON.parse(e.data); if (data.Key === 'SIGNAL' && this.isPageActive) { this.ngZone.run(() => { // Angular will detect this change and update bindings let entry = []; data.Values.forEach((s, i) => { entry.push({ Timestamp: data.Timestamp + i * (1000 / this.frequency), // Adjust timestamp for frequency Value: s, }); if (entry.length === 4) { this.buffer.push(entry); if (this.stage === 'sit') { console.log('Buffer length:', this.buffer.length); } entry = []; } }); }); } }; this.eventSource.onerror = (error) => { console.error('SSE error, will retry in 6s', error); this.closeConnection(); // schedule a reconnect setTimeout(() => { this.initializeSse(); }, this.RETRY_DELAY); }; }); } ngOnDestroy() { this.closeConnection(); } closeConnection() { if (this.eventSource) { this.eventSource.close(); this.eventSource = null; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DozeeEcgChartComponent, deps: [{ token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DozeeEcgChartComponent, selector: "app-ecg-chart", inputs: { accessToken: "accessToken", userId: "userId", stage: "stage", strokeColor: "strokeColor", backgroundColor: "backgroundColor" }, ngImport: i0, template: "<div class=\"chart-container\">\n <canvas id=\"ecgChart\"></canvas>\n</div>\n", styles: [".chart-container{width:100%;height:100%;position:relative}canvas{width:100%!important;height:100%!important}\n"] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DozeeEcgChartComponent, decorators: [{ type: Component, args: [{ selector: 'app-ecg-chart', template: "<div class=\"chart-container\">\n <canvas id=\"ecgChart\"></canvas>\n</div>\n", styles: [".chart-container{width:100%;height:100%;position:relative}canvas{width:100%!important;height:100%!important}\n"] }] }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.NgZone }], propDecorators: { accessToken: [{ type: Input }], userId: [{ type: Input }], stage: [{ type: Input }], strokeColor: [{ type: Input }], backgroundColor: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG96ZWUtZWNnLWNoYXJ0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2RvemVlLWVjZy1jaGFydC9zcmMvbGliL2RvemVlLWVjZy1jaGFydC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9kb3plZS1lY2ctY2hhcnQvc3JjL2xpYi9kb3plZS1lY2ctY2hhcnQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBVSxLQUFLLEVBQXFCLE1BQU0sZUFBZSxDQUFDO0FBQzVFLE9BQU8sRUFDTCxLQUFLLEVBQ0wsYUFBYSxFQUNiLFdBQVcsRUFDWCxjQUFjLEVBQ2QsV0FBVyxFQUNYLFlBQVksRUFDWixLQUFLLEVBQ0wsT0FBTyxFQUNQLE1BQU0sR0FDUCxNQUFNLFVBQVUsQ0FBQzs7QUFrQmxCLE1BQU0sT0FBTyxzQkFBc0I7SUFxQmI7SUFBNkI7SUFwQnhDLFdBQVcsQ0FBVTtJQUNyQixNQUFNLENBQVU7SUFDaEIsS0FBSyxDQUFVO0lBQ2YsV0FBVyxHQUFXLFNBQVMsQ0FBQztJQUNoQyxlQUFlLEdBQVcsU0FBUyxDQUFDO0lBRXJDLFdBQVcsR0FBdUIsSUFBSSxDQUFDO0lBQ3ZDLE1BQU0sR0FBVyxFQUFFLENBQUM7SUFDcEIsS0FBSyxDQUFTO0lBQ2QsU0FBUyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEtBQUs7SUFDdEIsUUFBUSxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVU7SUFDeEIsU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLGNBQWM7SUFDMUQsT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNDLFdBQVcsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBQ3RCLFlBQVksR0FBRyxJ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LENBQUMsQ0FBQztZQUN2QixDQUFDLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFTyxlQUFlO1FBQ3JCLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3JCLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7UUFDMUIsQ0FBQztJQUNILENBQUM7dUdBbk9VLHNCQUFzQjsyRkFBdEIsc0JBQXNCLCtMQzdCbkMsZ0ZBR0E7OzJGRDBCYSxzQkFBc0I7a0JBTGxDLFNBQVM7K0JBQ0UsZUFBZTttR0FLaEIsV0FBVztzQkFBbkIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csZUFBZTtzQkFBdkIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgUmVuZGVyZXIyLCBOZ1pvbmUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIENoYXJ0LFxuICBDYXRlZ29yeVNjYWxlLFxuICBMaW5lYXJTY2FsZSxcbiAgTGluZUNvbnRyb2xsZXIsXG4gIExpbmVFbGVtZW50LFxuICBQb2ludEVsZW1lbnQsXG4gIFRpdGxlLFxuICBUb29sdGlwLFxuICBMZWdlbmQsXG59IGZyb20gJ2NoYXJ0LmpzJztcblxuaW50ZXJmYWNlIEVjZ1NpZ25hbERhdGEge1xuICBLZXk6IHN0cmluZztcbiAgVGltZXN0YW1wOiBudW1iZXI7XG4gIFZhbHVlczogbnVtYmVyW107XG59XG5cbmludGVyZmFjZSBYeSB7XG4gIFRpbWVzdGFtcDogbnVtYmVyO1xuICBWYWx1ZTogbnVtYmVyO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtZWNnLWNoYXJ0JyxcbiAgdGVtcGxhdGVVcmw6ICcuL2RvemVlLWVjZy1jaGFydC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2RvemVlLWVjZy1jaGFydC5jb21wb25lbnQuY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIERvemVlRWNnQ2hhcnRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBASW5wdXQoKSBhY2Nlc3NUb2tlbiE6IHN0cmluZztcbiAgQElucHV0KCkgdXNlcklkITogc3RyaW5nO1xuICBASW5wdXQoKSBzdGFnZSE6IHN0cmluZztcbiAgQElucHV0KCkgc3Ryb2tlQ29sb3I6IHN0cmluZyA9ICcjMDBmZjAwJztcbiAgQElucHV0KCkgYmFja2dyb3VuZENvbG9yOiBzdHJpbmcgPSAnIzAwMDAwMCc7XG5cbiAgcHJpdmF0ZSBldmVudFNvdXJjZTogRXZlbnRTb3VyY2UgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBidWZmZXI6IFh5W11bXSA9IFtdO1xuICBwcml2YXRlIGNoYXJ0ITogQ2hhcnQ7XG4gIHByaXZhdGUgZnJlcXVlbmN5ID0gMjU2OyAvLyBIelxuICBwcml2YXRlIGR1cmF0aW9uID0gODsgLy8gc2Vjb25kc1xuICBwcml2YXRlIG1heFBvaW50cyA9IHRoaXMuZnJlcXVlbmN5ICogdGhpcy5kdXJhdGlvbjsgLy8gMjA0OCBwb2ludHNcbiAgcHJpdmF0ZSBlY2dEYXRhID0gQXJyYXkodGhpcy5tYXhQb2ludHMpLmZpbGwobnVsbCk7XG4gIHByaXZhdGUgYnVmZmVyTGltaXQgPSA2NCAqIDY0O1xuICBwcml2YXRlIGlzUGFnZUFjdGl2ZSA9IHRydWU7XG4gIHByaXZhdGUgaW50ZXJ2YWxJZDogYW55O1xuICBwcml2YXRlIGluYWN0aXZpdHlUaW1lb3V0OiBhbnk7IC8vIFRpbWVyIHRvIHRyYWNrIGluYWN0aXZpdHlcbiAgcHJpdmF0ZSByZWFkb25seSBJTkFDVElWRV9ERUxBWSA9IDMwMDAwO1xuICBwcml2YXRlIHJlYWRvbmx5IFJFVFJZX0RFTEFZID0gNjAwMDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsIHByaXZhdGUgbmdab25lOiBOZ1pvbmUpIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgLy8gUmVnaXN0ZXIgbmVjZXNzYXJ5IGNoYXJ0IGNvbXBvbmVudHNcbiAgICBDaGFydC5yZWdpc3RlcihcbiAgICAgIENhdGVnb3J5U2NhbGUsXG4gICAgICBMaW5lYXJTY2FsZSxcbiAgICAgIExpbmVDb250cm9sbGVyLFxuICAgICAgTGluZUVsZW1lbnQsXG4gICAgICBQb2ludEVsZW1lbnQsXG4gICAgICBUaXRsZSxcbiAgICAgIFRvb2x0aXAsXG4gICAgICBMZWdlbmRcbiAgICApO1xuXG4gICAgY29uc3QgY3R4ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2VjZ0NoYXJ0JykgYXMgSFRNTENhbnZhc0VsZW1lbnQ7XG4gICAgY3R4LnN0eWxlLmJhY2tncm91bmRDb2xvciA9IHRoaXMuYmFja2dyb3VuZENvbG9yO1xuXG4gICAgdGhpcy5jaGFydCA9IG5ldyBDaGFydChjdHgsIHtcbiAgICAgIHR5cGU6ICdsaW5lJyxcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgbGFiZWxzOiBBcnJheSh0aGlzLm1heFBvaW50cykuZmlsbCgwLjApLCAvLyBFbXB0eSBsYWJlbHMgYXMgWCBheGlzIGlzIGZpeGVkXG4gICAgICAgIGRhdGFzZXRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgbGFiZWw6ICdFQ0cgRGF0YScsXG4gICAgICAgICAgICBkYXRhOiB0aGlzLmVjZ0RhdGEsXG4gICAgICAgICAgICBib3JkZXJDb2xvcjogdGhpcy5zdHJva2VDb2xvcixcbiAgICAgICAgICAgIGJvcmRlcldpZHRoOiAxLFxuICAgICAgICAgICAgZmlsbDogZmFsc2UsXG4gICAgICAgICAgICBwb2ludFJhZGl1czogMCwgLy8gSGlkZSBwb2ludHMgZm9yIHNtb290aCBsaW5lXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgICBvcHRpb25zOiB7XG4gICAgICAgIGFuaW1hdGlvbjogZmFsc2UsXG4gICAgICAgIHJlc3BvbnNpdmU6IHRydWUsXG4gICAgICAgIG1haW50YWluQXNwZWN0UmF0aW86IGZhbHNlLFxuICAgICAgICBzY2FsZXM6IHtcbiAgICAgICAgICB4OiB7XG4gICAgICAgICAgICB0eXBlOiAnbGluZWFyJyxcbiAgICAgICAgICAgIG1pbjogMCxcbiAgICAgICAgICAgIG1heDogdGhpcy5tYXhQb2ludHMsIC8vIFNldCBmaXhlZCBYLWF4aXMgcmFuZ2UgKDggc2Vjb25kcylcbiAgICAgICAgICAgIGRpc3BsYXk6IGZhbHNlLCAvLyBIaWRlIHRoZSB4LWF4aXNcbiAgICAgICAgICAgIGdyaWQ6IHsgZGlzcGxheTogZmFsc2UgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHk6IHtcbiAgICAgICAgICAgIG1heDogNDAwMCwgLy8gQWRqdXN0IGJhc2VkIG9uIEVDRyB2YWx1ZSByYW5nZVxuICAgICAgICAgICAgbWluOiAwLFxuICAgICAgICAgICAgdHlwZTogJ2xpbmVhcicsXG4gICAgICAgICAgICBiZWdpbkF0WmVybzogdHJ1ZSxcbiAgICAgICAgICAgIGdyaWQ6IHsgZGlzcGxheTogZmFsc2UgfSxcbiAgICAgICAgICAgIGRpc3BsYXk6IGZhbHNlLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHBsdWdpbnM6IHtcbiAgICAgICAgICBsZWdlbmQ6IHtcbiAgICAgICAgICAgIGRpc3BsYXk6IGZhbHNlLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGVsZW1lbnRzOiB7XG4gICAgICAgICAgbGluZToge1xuICAgICAgICAgICAgdGVuc2lvbjogMC40LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gSW5pdGlhbGl6ZSBTU0UgY29ubmVjdGlvblxuICAgIHRoaXMuaW5pdGlhbGl6ZVNzZSgpO1xuXG4gICAgdGhpcy5yZW5kZXJlci5saXN0ZW4oJ2RvY3VtZW50JywgJ3Zpc2liaWxpdHljaGFuZ2UnLCAoKSA9PiB7XG4gICAgICBpZiAoZG9jdW1lbnQuaGlkZGVuKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdQYWdlIGJlY2FtZSBpbmFjdGl2ZSwgc3RhcnRpbmcgMzBzIHRpbWVvdXQuLi4nKTtcbiAgICAgICAgdGhpcy5zdGFydEluYWN0aXZpdHlUaW1lcigpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1BhZ2UgaXMgYWN0aXZlIGFnYWluLCBjYW5jZWxpbmcgaW5hY3Rpdml0eSB0aW1lb3V0Jyk7XG4gICAgICAgIHRoaXMuY2FuY2VsSW5hY3Rpdml0eVRpbWVyKCk7XG4gICAgICAgIHRoaXMuc3RhcnRJbnRlcnZhbCgpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gU3RhcnQgaW50ZXJ2YWwgaW5pdGlhbGx5XG4gICAgdGhpcy5zdGFydEludGVydmFsKCk7XG4gIH1cblxuICBwcml2YXRlIHN0YXJ0SW50ZXJ2YWwoKSB7XG4gICAgaWYgKCF0aGlzLmludGVydmFsSWQpIHtcbiAgICAgIC8vIFVwZGF0ZSBjaGFydCBkYXRhIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzXG4gICAgICB0aGlzLmludGVydmFsSWQgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG5cbiAgICAgICAgaWYgKHRoaXMuYnVmZmVyLmxlbmd0aCA+IHRoaXMuYnVmZmVyTGltaXQgJiYgdGhpcy5jdXJyZW50SW5kZXggPT09IDApIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGFnZSA9PT0gJ3NpdCcpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihgQnVmZmVyIG92ZXJmbG93OiBTa2lwcGluZyAke3RoaXMuYnVmZmVyLmxlbmd0aCAtIDY0fSBvbGQgZW50cmllc2ApO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmJ1ZmZlci5zcGxpY2UoMCwgdGhpcy5idWZmZXIubGVuZ3RoIC0gNjQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuYnVmZmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBjb25zdCBlbnRyeSA9IHRoaXMuYnVmZmVyLnNoaWZ0KCkgYXMgWHlbXTtcbiAgICAgICAgICBmb3IgKGNvbnN0IGUgb2YgZW50cnkpIHtcbiAgICAgICAgICAgIHRoaXMuYWRkRGF0YShlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0sIDE2KTsgLy8gVXBkYXRlIGZyZXF1ZW5jeSAoMjU2IEh6KVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3RhcnRJbmFjdGl2aXR5VGltZXIoKSB7XG4gICAgdGhpcy5pbmFjdGl2aXR5VGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coJ1BhZ2UgaGFzIGJlZW4gaW5hY3RpdmUgZm9yIDMwIHNlY29uZHMsIHN0b3BwaW5nIHVwZGF0ZXMuJyk7XG4gICAgICB0aGlzLmlzUGFnZUFjdGl2ZSA9IGZhbHNlO1xuICAgICAgdGhpcy5jbGVhckludGVydmFsKCk7XG4gICAgfSwgdGhpcy5JTkFDVElWRV9ERUxBWSk7XG4gIH1cblxuICBwcml2YXRlIGNhbmNlbEluYWN0aXZpdHlUaW1lcigpIHtcbiAgICBpZiAodGhpcy5pbmFjdGl2aXR5VGltZW91dCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuaW5hY3Rpdml0eVRpbWVvdXQpO1xuICAgICAgdGhpcy5pbmFjdGl2aXR5VGltZW91dCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuaXNQYWdlQWN0aXZlID0gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgY2xlYXJJbnRlcnZhbCgpIHtcbiAgICBpZiAodGhpcy5pbnRlcnZhbElkKSB7XG4gICAgICBjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWxJZCk7XG4gICAgICB0aGlzLmludGVydmFsSWQgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY3VycmVudEluZGV4ID0gMDtcbiAgYWRkRGF0YShlOiBYeSkge1xuICAgIGlmICh0aGlzLmNoYXJ0LmRhdGEubGFiZWxzKSB7XG4gICAgICB0aGlzLmVjZ0RhdGFbdGhpcy5jdXJyZW50SW5kZXhdID0gZS5WYWx1ZTtcbiAgICAgIHRoaXMuY2hhcnQuZGF0YS5sYWJlbHNbdGhpcy5jdXJyZW50SW5kZXhdID0gdGhpcy5jdXJyZW50SW5kZXg7XG5cbiAgICAgIGZvciAoXG4gICAgICAgIGxldCBpID0gdGhpcy5jdXJyZW50SW5kZXggKyAxO1xuICAgICAgICBpIDwgTWF0aC5taW4odGhpcy5jdXJyZW50SW5kZXggKyA2NCwgdGhpcy5tYXhQb2ludHMpO1xuICAgICAgICBpKytcbiAgICAgICkge1xuICAgICAgICB0aGlzLmVjZ0RhdGFbaV0gPSBudWxsO1xuICAgICAgfVxuXG4gICAgICAvLyBBZHZhbmNlIHRoZSBpbmRleCwgYW5kIHdyYXAgYXJvdW5kIGlmIGl0IGV4Y2VlZHMgbWF4UG9pbnRzXG4gICAgICB0aGlzLmN1cnJlbnRJbmRleCA9ICh0aGlzLmN1cnJlbnRJbmRleCArIDEpICUgdGhpcy5tYXhQb2ludHM7XG4gICAgICBpZiAodGhpcy5zdGFnZSA9PT0gJ3NpdCcpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdDdXJyZW50IGluZGV4OicsIHRoaXMuY3VycmVudEluZGV4KTtcbiAgICAgIH1cblxuICAgICAgLy8gVXBkYXRlIHRoZSBjaGFydCBkYXRhXG4gICAgICB0aGlzLmNoYXJ0LmRhdGEuZGF0YXNldHNbMF0uZGF0YSA9IHRoaXMuZWNnRGF0YTtcbiAgICAgIHRoaXMuY2hhcnQudXBkYXRlKCk7XG4gICAgfVxuICB9XG5cbiAgaW5pdGlhbGl6ZVNzZSgpOiB2b2lkIHtcbiAgICBjb25zdCBzc2VVcmwgPSBgaHR0cHM6Ly9lY2dzc2Uke3RoaXMuc3RhZ2UgPyBgLSR7dGhpcy5zdGFnZX1gOiAnJ30uZG96ZWUuY2xvdWQvc3NlL2VjZ3N0cmVhbT91c2VySWQ9JHt0aGlzLnVzZXJJZH0mYWNjZXNzVG9rZW49JHt0aGlzLmFjY2Vzc1Rva2VufSZuZ3N3LWJ5cGFzcz10cnVlYDtcblxuICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgIHRoaXMuZXZlbnRTb3VyY2UgPSBuZXcgRXZlbnRTb3VyY2Uoc3NlVXJsKTtcbiAgICAgIHRoaXMuZXZlbnRTb3VyY2Uub25tZXNzYWdlID0gKGU6IE1lc3NhZ2VFdmVudCkgPT4ge1xuICAgICAgICBjb25zdCBkYXRhID0gSlNPTi5wYXJzZShlLmRhdGEpIGFzIEVjZ1NpZ25hbERhdGE7XG4gICAgICAgIGlmIChkYXRhLktleSA9PT0gJ1NJR05BTCcgJiYgdGhpcy5pc1BhZ2VBY3RpdmUpIHtcbiAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgLy8gQW5ndWxhciB3aWxsIGRldGVjdCB0aGlzIGNoYW5nZSBhbmQgdXBkYXRlIGJpbmRpbmdzXG4gICAgICAgICAgICBsZXQgZW50cnk6IFh5W10gPSBbXTtcbiAgICAgICAgICAgIGRhdGEuVmFsdWVzLmZvckVhY2goKHM6IG51bWJlciwgaTogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICAgIGVudHJ5LnB1c2goe1xuICAgICAgICAgICAgICAgIFRpbWVzdGFtcDogZGF0YS5UaW1lc3RhbXAgKyBpICogKDEwMDAgLyB0aGlzLmZyZXF1ZW5jeSksIC8vIEFkanVzdCB0aW1lc3RhbXAgZm9yIGZyZXF1ZW5jeVxuICAgICAgICAgICAgICAgIFZhbHVlOiBzLFxuICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICBpZiAoZW50cnkubGVuZ3RoID09PSA0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5idWZmZXIucHVzaChlbnRyeSk7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhZ2UgPT09ICdzaXQnKSB7XG4gICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnQnVmZmVyIGxlbmd0aDonLCB0aGlzLmJ1ZmZlci5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbnRyeSA9IFtdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgdGhpcy5ldmVudFNvdXJjZS5vbmVycm9yID0gKGVycm9yKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ1NTRSBlcnJvciwgd2lsbCByZXRyeSBpbiA2cycsIGVycm9yKTtcbiAgICAgICAgdGhpcy5jbG9zZUNvbm5lY3Rpb24oKTtcblxuICAgICAgICAvLyBzY2hlZHVsZSBhIHJlY29ubmVjdFxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVTc2UoKTtcbiAgICAgICAgfSwgdGhpcy5SRVRSWV9ERUxBWSk7XG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5jbG9zZUNvbm5lY3Rpb24oKTtcbiAgfVxuXG4gIHByaXZhdGUgY2xvc2VDb25uZWN0aW9uKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmV2ZW50U291cmNlKSB7XG4gICAgICB0aGlzLmV2ZW50U291cmNlLmNsb3NlKCk7XG4gICAgICB0aGlzLmV2ZW50U291cmNlID0gbnVsbDtcbiAgICB9XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJjaGFydC1jb250YWluZXJcIj5cbiAgPGNhbnZhcyBpZD1cImVjZ0NoYXJ0XCI+PC9jYW52YXM+XG48L2Rpdj5cbiJdfQ==