UNPKG

lemon-ngx-trend

Version:

ngx-trend Angular component for Lemoncloud

296 lines 29.4 kB
import * as tslib_1 from "tslib"; import { animate, keyframes, state, style, transition, trigger, } from '@angular/animations'; import { Component, ElementRef, Input, ViewChild, } from '@angular/core'; import { buildLinearPath, buildSmoothPath } from '../helpers/DOM.helpers'; import { normalize } from '../helpers/math.helpers'; import { generateId } from '../helpers/misc.helpers'; import { normalizeDataset } from './trend.helpers'; let TrendComponent = class TrendComponent { constructor() { this.autoDraw = false; this.autoDrawDuration = 2000; this.autoDrawEasing = 'ease'; this.padding = 8; this.radius = 10; this.stroke = 'black'; this.strokeLinecap = ''; this.strokeWidth = 1; this.gradient = []; this.svgHeight = '25%'; this.svgWidth = '100%'; // Added for Circle this.showCircle = false; this.circleColor = 'black'; this.circleWidth = 1; this.showLastLabel = false; this.labelColor = 'black'; this.animationState = ''; this.id = generateId(); this.gradientId = `ngx-trend-vertical-gradient-${this.id}`; } ngOnChanges() { // We need at least 2 points to draw a graph. if (!this.data || this.data.length < 2) { return; } // `data` can either be an array of numbers: // [1, 2, 3] // or, an array of objects containing a value: // [{ value: 1 }, { value: 2 }, { value: 3 }] // // For now, we're just going to convert the second form to the first. // Later on, if/when we support tooltips, we may adjust. const plainValues = this.data.map((point) => { if (typeof point === 'number') { return point; } return point.value; }); // reset to re-run animation this.animationState = 'inactive'; // Our viewbox needs to be in absolute units, so we'll default to 300x75 // Our SVG can be a %, though; this is what makes it scalable. // By defaulting to percentages, the SVG will grow to fill its parent // container, preserving a 1/4 aspect ratio. const viewBoxWidth = this.width || 300; const viewBoxHeight = this.height || 75; this.svgWidth = this.width || '100%'; this.svgHeight = this.height || '25%'; this.viewBox = `0 0 ${viewBoxWidth} ${viewBoxHeight}`; const root = location.href.split(location.hash || '#')[0]; this.pathStroke = (this.gradient && this.gradient.length) ? `url('${root}#${this.gradientId}')` : undefined; this.gradientTrimmed = this.gradient.slice().reverse().map((val, idx) => { return { idx, stopColor: val, offset: normalize(idx, 0, this.gradient.length - 1 || 1), }; }); const normalizedValues = normalizeDataset(plainValues, this.padding, viewBoxWidth - this.padding, // NOTE: Because SVGs are indexed from the top left, but most data is // indexed from the bottom left, we're inverting the Y min/max. viewBoxHeight - this.padding, this.padding, this.minValue, this.maxValue); this.circleCoordinates = normalizedValues; this.lastLabelCoordinates = this.getLabelCoordinateOfLast(); if (this.autoDraw && this.animationState !== 'active') { this.animationState = 'inactive'; setTimeout(() => { this.lineLength = this.pathEl.nativeElement.getTotalLength(); this.animationState = 'active'; }); } this.d = this.smooth ? buildSmoothPath(normalizedValues, this.radius) : buildLinearPath(normalizedValues); } getLabelCoordinateOfLast() { const lastIndex = this.circleCoordinates.length - 1; const { x, y } = this.circleCoordinates[lastIndex]; const result = { x, y: y + 15 }; return result; } }; tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Array) ], TrendComponent.prototype, "data", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Boolean) ], TrendComponent.prototype, "smooth", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "autoDraw", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "autoDrawDuration", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "autoDrawEasing", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Number) ], TrendComponent.prototype, "width", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Number) ], TrendComponent.prototype, "height", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "padding", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "radius", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "stroke", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "strokeLinecap", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "strokeWidth", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Array) ], TrendComponent.prototype, "gradient", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", String) ], TrendComponent.prototype, "preserveAspectRatio", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "svgHeight", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "svgWidth", void 0); tslib_1.__decorate([ ViewChild('pathEl'), tslib_1.__metadata("design:type", ElementRef) ], TrendComponent.prototype, "pathEl", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "showCircle", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "circleColor", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "circleWidth", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "showLastLabel", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "labelColor", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "maxValue", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], TrendComponent.prototype, "minValue", void 0); TrendComponent = tslib_1.__decorate([ Component({ selector: 'ngx-trend', template: ` <svg *ngIf="data && data.length >= 2" [attr.width]="svgWidth" [attr.height]="svgHeight" [attr.stroke]="stroke" [attr.stroke-width]="strokeWidth" [attr.stroke-linecap]="strokeLinecap" [attr.viewBox]="viewBox" [attr.preserveAspectRatio]="preserveAspectRatio" > <defs *ngIf="gradient && gradient.length"> <linearGradient [attr.id]="gradientId" x1="0%" y1="0%" x2="0%" y2="100%"> <stop *ngFor="let g of gradientTrimmed;" [attr.key]="g.idx" [attr.offset]="g.offset" [attr.stop-color]="g.stopColor" /> </linearGradient> </defs> <path fill="none" #pathEl [attr.stroke]="pathStroke" [attr.d]="d" [@pathAnimation]="{ value: animationState, params: { autoDrawDuration: autoDrawDuration, autoDrawEasing: autoDrawEasing, lineLength: lineLength } }" /> <ng-container *ngIf="showCircle" > <style> .small { font-size: 12px; font-weight: 400; text-anchor: end; stroke-width: 0;} </style> <ng-container *ngFor="let circle of circleCoordinates; index as i"> <circle [attr.cx]="circle.x" [attr.cy]="circle.y" [attr.r]="circleWidth" [attr.fill]="circleColor" [attr.stroke]="circleColor" [attr.strokeWidth]="circleWidth" [@circleAnimation]="{ value: animationState, params: { autoDrawDuration: autoDrawDuration } }" /> <text *ngIf="showLastLabel && i === circleCoordinates.length - 1" class="small" [@circleAnimation]="{ value: animationState, params: { autoDrawDuration: autoDrawDuration } }" [attr.fill]="labelColor" [attr.x]="lastLabelCoordinates.x" [attr.y]="lastLabelCoordinates.y">{{ data[data.length-1] | number }}</text> </ng-container> </ng-container> </svg> `, animations: [ trigger('pathAnimation', [ state('inactive', style({ display: 'none' })), transition('* => active', [ style({ display: 'initial' }), // We do the animation using the dash array/offset trick // https://css-tricks.com/svg-line-animation-works/ animate('{{ autoDrawDuration }}ms {{ autoDrawEasing }}', keyframes([ style({ 'stroke-dasharray': '{{ lineLength }}px', 'stroke-dashoffset': '{{ lineLength }}px', }), style({ 'stroke-dasharray': '{{ lineLength }}px', 'stroke-dashoffset': 0, }), ])), // One unfortunate side-effect of the auto-draw is that the line is // actually 1 big dash, the same length as the line itself. If the // line length changes (eg. radius change, new data), that dash won't // be the same length anymore. We can fix that by removing those // properties once the auto-draw is completed. style({ 'stroke-dashoffset': '', 'stroke-dasharray': '', }), ]), ]), trigger('circleAnimation', [ state('inactive', style({ visibility: 'hidden', opacity: 0 })), transition('* => active', [ style({ visibility: 'hidden' }), animate('{{ autoDrawDuration }}ms', keyframes([style({ visibility: 'visible' }), ])), ]), ]) ] }), tslib_1.__metadata("design:paramtypes", []) ], TrendComponent); export { TrendComponent }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlbmQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vbGVtb24tbmd4LXRyZW5kLyIsInNvdXJjZXMiOlsidHJlbmQvdHJlbmQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQ0wsT0FBTyxFQUNQLFNBQVMsRUFDVCxLQUFLLEVBQ0wsS0FBSyxFQUNMLFVBQVUsRUFDVixPQUFPLEdBQ1IsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQ0wsU0FBUyxFQUNULFVBQVUsRUFDVixLQUFLLEVBRUwsU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDMUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQTJHbkQsSUFBYSxjQUFjLEdBQTNCLE1BQWEsY0FBYztJQXNDekI7UUFsQ1MsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUNqQixxQkFBZ0IsR0FBRyxJQUFJLENBQUM7UUFDeEIsbUJBQWMsR0FBRyxNQUFNLENBQUM7UUFHeEIsWUFBTyxHQUFHLENBQUMsQ0FBQztRQUNaLFdBQU0sR0FBRyxFQUFFLENBQUM7UUFDWixXQUFNLEdBQUcsT0FBTyxDQUFDO1FBQ2pCLGtCQUFhLEdBQUcsRUFBRSxDQUFDO1FBQ25CLGdCQUFXLEdBQUcsQ0FBQyxDQUFDO1FBQ2hCLGFBQVEsR0FBYSxFQUFFLENBQUM7UUFFeEIsY0FBUyxHQUFvQixLQUFLLENBQUM7UUFDbkMsYUFBUSxHQUFvQixNQUFNLENBQUM7UUFFNUMsbUJBQW1CO1FBQ1YsZUFBVSxHQUFHLEtBQUssQ0FBQztRQUNuQixnQkFBVyxHQUFHLE9BQU8sQ0FBQztRQUN0QixnQkFBVyxHQUFH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RUFBRSxvQkFBb0I7NEJBQ3hDLG1CQUFtQixFQUFFLG9CQUFvQjt5QkFDMUMsQ0FBQzt3QkFDRixLQUFLLENBQUM7NEJBQ0osa0JBQWtCLEVBQUUsb0JBQW9COzRCQUN4QyxtQkFBbUIsRUFBRSxDQUFDO3lCQUN2QixDQUFDO3FCQUNILENBQUMsQ0FDSDtvQkFDRCxtRUFBbUU7b0JBQ25FLGtFQUFrRTtvQkFDbEUscUVBQXFFO29CQUNyRSxnRUFBZ0U7b0JBQ2hFLDhDQUE4QztvQkFDOUMsS0FBSyxDQUFDO3dCQUNKLG1CQUFtQixFQUFFLEVBQUU7d0JBQ3ZCLGtCQUFrQixFQUFFLEVBQUU7cUJBQ3ZCLENBQUM7aUJBQ0gsQ0FBQzthQUNILENBQUM7WUFDRixPQUFPLENBQUMsaUJBQWlCLEVBQUU7Z0JBQ3pCLEtBQUssQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDOUQsVUFBVSxDQUFDLGFBQWEsRUFBRTtvQkFDeEIsS0FBSyxDQUFDLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxDQUFDO29CQUMvQixPQUFPLENBQUMsMEJBQTBCLEVBQ2hDLFNBQVMsQ0FBQyxDQUFFLEtBQUssQ0FBQyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsQ0FBQztxQkFDM0MsQ0FBQyxDQUNIO2lCQUNGLENBQUM7YUFDSCxDQUFDO1NBQ0g7S0FDRixDQUFDOztHQUNXLGNBQWMsQ0EwSDFCO1NBMUhZLGNBQWMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBhbmltYXRlLFxuICBrZXlmcmFtZXMsXG4gIHN0YXRlLFxuICBzdHlsZSxcbiAgdHJhbnNpdGlvbixcbiAgdHJpZ2dlcixcbn0gZnJvbSAnQGFuZ3VsYXIvYW5pbWF0aW9ucyc7XG5pbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIFZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IGJ1aWxkTGluZWFyUGF0aCwgYnVpbGRTbW9vdGhQYXRoIH0gZnJvbSAnLi4vaGVscGVycy9ET00uaGVscGVycyc7XG5pbXBvcnQgeyBub3JtYWxpemUgfSBmcm9tICcuLi9oZWxwZXJzL21hdGguaGVscGVycyc7XG5pbXBvcnQgeyBnZW5lcmF0ZUlkIH0gZnJvbSAnLi4vaGVscGVycy9taXNjLmhlbHBlcnMnO1xuaW1wb3J0IHsgbm9ybWFsaXplRGF0YXNldCB9IGZyb20gJy4vdHJlbmQuaGVscGVycyc7XG5cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LXRyZW5kJyxcbiAgdGVtcGxhdGU6IGBcbiAgPHN2ZyAqbmdJZj1cImRhdGEgJiYgZGF0YS5sZW5ndGggPj0gMlwiXG4gICAgW2F0dHIud2lkdGhdPVwic3ZnV2lkdGhcIlxuICAgIFthdHRyLmhlaWdodF09XCJzdmdIZWlnaHRcIlxuICAgIFthdHRyLnN0cm9rZV09XCJzdHJva2VcIlxuICAgIFthdHRyLnN0cm9rZS13aWR0aF09XCJzdHJva2VXaWR0aFwiXG4gICAgW2F0dHIuc3Ryb2tlLWxpbmVjYXBdPVwic3Ryb2tlTGluZWNhcFwiXG4gICAgW2F0dHIudmlld0JveF09XCJ2aWV3Qm94XCJcbiAgICBbYXR0ci5wcmVzZXJ2ZUFzcGVjdFJhdGlvXT1cInByZXNlcnZlQXNwZWN0UmF0aW9cIlxuICA+XG4gICAgPGRlZnMgKm5nSWY9XCJncmFkaWVudCAmJiBncmFkaWVudC5sZW5ndGhcIj5cbiAgICAgIDxsaW5lYXJHcmFkaWVudCBbYXR0ci5pZF09XCJncmFkaWVudElkXCIgeDE9XCIwJVwiIHkxPVwiMCVcIiB4Mj1cIjAlXCIgeTI9XCIxMDAlXCI+XG4gICAgICAgIDxzdG9wXG4gICAgICAgICAgKm5nRm9yPVwibGV0IGcgb2YgZ3JhZGllbnRUcmltbWVkO1wiXG4gICAgICAgICAgW2F0dHIua2V5XT1cImcuaWR4XCJcbiAgICAgICAgICBbYXR0ci5vZmZzZXRdPVwiZy5vZmZzZXRcIlxuICAgICAgICAgIFthdHRyLnN0b3AtY29sb3JdPVwiZy5zdG9wQ29sb3JcIlxuICAgICAgICAvPlxuICAgICAgPC9saW5lYXJHcmFkaWVudD5cbiAgICA8L2RlZnM+XG4gICAgPHBhdGggZmlsbD1cIm5vbmVcIiAjcGF0aEVsXG4gICAgICBbYXR0ci5zdHJva2VdPVwicGF0aFN0cm9rZVwiIFthdHRyLmRdPVwiZFwiXG4gICAgICBbQHBhdGhBbmltYXRpb25dPVwie1xuICAgICAgICB2YWx1ZTogYW5pbWF0aW9uU3RhdGUsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIGF1dG9EcmF3RHVyYXRpb246IGF1dG9EcmF3RHVyYXRpb24sXG4gICAgICAgICAgYXV0b0RyYXdFYXNpbmc6IGF1dG9EcmF3RWFzaW5nLFxuICAgICAgICAgIGxpbmVMZW5ndGg6IGxpbmVMZW5ndGhcbiAgICAgICAgfVxuICAgICAgfVwiIC8+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNob3dDaXJjbGVcIiA+XG4gICAgICA8c3R5bGU+XG4gICAgICAgIC5zbWFsbCB7IGZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IDQwMDsgdGV4dC1hbmNob3I6IGVuZDsgc3Ryb2tlLXdpZHRoOiAwO31cbiAgICAgIDwvc3R5bGU+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBjaXJjbGUgb2YgY2lyY2xlQ29vcmRpbmF0ZXM7IGluZGV4IGFzIGlcIj5cbiAgICAgICAgPGNpcmNsZSBbYXR0ci5jeF09XCJjaXJjbGUueFwiIFthdHRyLmN5XT1cImNpcmNsZS55XCIgW2F0dHIucl09XCJjaXJjbGVXaWR0aFwiXG4gICAgICAgICAgICAgICAgW2F0dHIuZmlsbF09XCJjaXJjbGVDb2xvclwiIFthdHRyLnN0cm9rZV09XCJjaXJjbGVDb2xvclwiXG4gICAgICAgICAgICAgICAgW2F0dHIuc3Ryb2tlV2lkdGhdPVwiY2lyY2xlV2lkdGhcIlxuICAgICAgICAgICAgICAgIFtAY2lyY2xlQW5pbWF0aW9uXT1cIntcbiAgICAgICAgICAgICAgICAgIHZhbHVlOiBhbmltYXRpb25TdGF0ZSxcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xuICAgICAgICAgICAgICAgICAgICBhdXRvRHJhd0R1cmF0aW9uOiBhdXRvRHJhd0R1cmF0aW9uXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVwiXG4gICAgICAgIC8+XG4gICAgICAgIDx0ZXh0ICpuZ0lmPVwic2hvd0xhc3RMYWJlbCAmJiBpID09PSBjaXJjbGVDb29yZGluYXRlcy5sZW5ndGggLSAxXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJzbWFsbFwiXG4gICAgICAgICAgICAgIFtAY2lyY2xlQW5pbWF0aW9uXT1cIntcbiAgICAgICAgICAgICAgICAgIHZhbHVlOiBhbmltYXRpb25TdGF0ZSxcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xuICAgICAgICAgICAgICAgICAgICBhdXRvRHJhd0R1cmF0aW9uOiBhdXRvRHJhd0R1cmF0aW9uXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgIFthdHRyLmZpbGxdPVwibGFiZWxDb2xvclwiXG4gICAgICAgICAgICAgIFthdHRyLnhdPVwibGFzdExhYmVsQ29vcmRpbmF0ZXMueFwiXG4gICAgICAgICAgICAgIFthdHRyLnldPVwibGFzdExhYmVsQ29vcmRpbmF0ZXMueVwiPnt7IGRhdGFbZGF0YS5sZW5ndGgtMV0gfCBudW1iZXIgfX08L3RleHQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9zdmc+XG4gIGAsXG4gIGFuaW1hdGlvbnM6IFtcbiAgICB0cmlnZ2VyKCdwYXRoQW5pbWF0aW9uJywgW1xuICAgICAgc3RhdGUoJ2luYWN0aXZlJywgc3R5bGUoeyBkaXNwbGF5OiAnbm9uZScgfSkpLFxuICAgICAgdHJhbnNpdGlvbignKiA9PiBhY3RpdmUnLCBbXG4gICAgICAgIHN0eWxlKHsgZGlzcGxheTogJ2luaXRpYWwnIH0pLFxuICAgICAgICAvLyBXZSBkbyB0aGUgYW5pbWF0aW9uIHVzaW5nIHRoZSBkYXNoIGFycmF5L29mZnNldCB0cmlja1xuICAgICAgICAvLyBodHRwczovL2Nzcy10cmlja3MuY29tL3N2Zy1saW5lLWFuaW1hdGlvbi13b3Jrcy9cbiAgICAgICAgYW5pbWF0ZSgne3sgYXV0b0RyYXdEdXJhdGlvbiB9fW1zIHt7IGF1dG9EcmF3RWFzaW5nIH19JyxcbiAgICAgICAgICBrZXlmcmFtZXMoW1xuICAgICAgICAgICAgc3R5bGUoe1xuICAgICAgICAgICAgICAnc3Ryb2tlLWRhc2hhcnJheSc6ICd7eyBsaW5lTGVuZ3RoIH19cHgnLFxuICAgICAgICAgICAgICAnc3Ryb2tlLWRhc2hvZmZzZXQnOiAne3sgbGluZUxlbmd0aCB9fXB4JyxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgc3R5bGUoe1xuICAgICAgICAgICAgICAnc3Ryb2tlLWRhc2hhcnJheSc6ICd7eyBsaW5lTGVuZ3RoIH19cHgnLFxuICAgICAgICAgICAgICAnc3Ryb2tlLWRhc2hvZmZzZXQnOiAwLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgXSksXG4gICAgICAgICksXG4gICAgICAgIC8vIE9uZSB1bmZvcnR1bmF0ZSBzaWRlLWVmZmVjdCBvZiB0aGUgYXV0by1kcmF3IGlzIHRoYXQgdGhlIGxpbmUgaXNcbiAgICAgICAgLy8gYWN0dWFsbHkgMSBiaWcgZGFzaCwgdGhlIHNhbWUgbGVuZ3RoIGFzIHRoZSBsaW5lIGl0c2VsZi4gSWYgdGhlXG4gICAgICAgIC8vIGxpbmUgbGVuZ3RoIGNoYW5nZXMgKGVnLiByYWRpdXMgY2hhbmdlLCBuZXcgZGF0YSksIHRoYXQgZGFzaCB3b24ndFxuICAgICAgICAvLyBiZSB0aGUgc2FtZSBsZW5ndGggYW55bW9yZS4gV2UgY2FuIGZpeCB0aGF0IGJ5IHJlbW92aW5nIHRob3NlXG4gICAgICAgIC8vIHByb3BlcnRpZXMgb25jZSB0aGUgYXV0by1kcmF3IGlzIGNvbXBsZXRlZC5cbiAgICAgICAgc3R5bGUoe1xuICAgICAgICAgICdzdHJva2UtZGFzaG9mZnNldCc6ICcnLFxuICAgICAgICAgICdzdHJva2UtZGFzaGFycmF5JzogJycsXG4gICAgICAgIH0pLFxuICAgICAgXSksXG4gICAgXSksXG4gICAgdHJpZ2dlcignY2lyY2xlQW5pbWF0aW9uJywgW1xuICAgICAgc3RhdGUoJ2luYWN0aXZlJywgc3R5bGUoeyB2aXNpYmlsaXR5OiAnaGlkZGVuJywgb3BhY2l0eTogMCB9KSksXG4gICAgICB0cmFuc2l0aW9uKCcqID0+IGFjdGl2ZScsIFtcbiAgICAgICAgc3R5bGUoeyB2aXNpYmlsaXR5OiAnaGlkZGVuJyB9KSxcbiAgICAgICAgYW5pbWF0ZSgne3sgYXV0b0RyYXdEdXJhdGlvbiB9fW1zJyxcbiAgICAgICAgICBrZXlmcmFtZXMoWyBzdHlsZSh7IHZpc2liaWxpdHk6ICd2aXNpYmxlJyB9KSxcbiAgICAgICAgICBdKSxcbiAgICAgICAgKSxcbiAgICAgIF0pLFxuICAgIF0pXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIFRyZW5kQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgaWQ6IG51bWJlcjtcbiAgQElucHV0KCkgZGF0YTogKG51bWJlciB8IHt2YWx1ZTogbnVtYmVyfSlbXTtcbiAgQElucHV0KCkgc21vb3RoOiBib29sZWFuO1xuICBASW5wdXQoKSBhdXRvRHJhdyA9IGZhbHNlO1xuICBASW5wdXQoKSBhdXRvRHJhd0R1cmF0aW9uID0gMjAwMDtcbiAgQElucHV0KCkgYXV0b0RyYXdFYXNpbmcgPSAnZWFzZSc7XG4gIEBJbnB1dCgpIHdpZHRoOiBudW1iZXI7XG4gIEBJbnB1dCgpIGhlaWdodDogbnVtYmVyO1xuICBASW5wdXQoKSBwYWRkaW5nID0gODtcbiAgQElucHV0KCkgcmFkaXVzID0gMTA7XG4gIEBJbnB1dCgpIHN0cm9rZSA9ICdibGFjayc7XG4gIEBJbnB1dCgpIHN0cm9rZUxpbmVjYXAgPSAnJztcbiAgQElucHV0KCkgc3Ryb2tlV2lkdGggPSAxO1xuICBASW5wdXQoKSBncmFkaWVudDogc3RyaW5nW10gPSBbXTtcbiAgQElucHV0KCkgcHJlc2VydmVBc3BlY3RSYXRpbzogc3RyaW5nO1xuICBASW5wdXQoKSBzdmdIZWlnaHQ6IHN0cmluZyB8IG51bWJlciA9ICcyNSUnO1xuICBASW5wdXQoKSBzdmdXaWR0aDogc3RyaW5nIHwgbnVtYmVyID0gJzEwMCUnO1xuICBAVmlld0NoaWxkKCdwYXRoRWwnKSBwYXRoRWw6IEVsZW1lbnRSZWY7XG4gIC8vIEFkZGVkIGZvciBDaXJjbGVcbiAgQElucHV0KCkgc2hvd0NpcmNsZSA9IGZhbHNlO1xuICBASW5wdXQoKSBjaXJjbGVDb2xvciA9ICdibGFjayc7XG4gIEBJbnB1dCgpIGNpcmNsZVdpZHRoID0gMTtcbiAgQElucHV0KCkgc2hvd0xhc3RMYWJlbCA9IGZhbHNlO1xuICBASW5wdXQoKSBsYWJlbENvbG9yID0gJ2JsYWNrJztcbiAgQElucHV0KCkgbWF4VmFsdWU7XG4gIEBJbnB1dCgpIG1pblZhbHVlO1xuICBjaXJjbGVDb29yZGluYXRlczogYW55W107XG4gIGxhc3RMYWJlbENvb3JkaW5hdGVzOiB7IHg6IGFueSwgeTogYW55IH07XG5cbiAgZ3JhZGllbnRUcmltbWVkOiBhbnlbXTtcbiAgZDogYW55O1xuICB2aWV3Qm94OiBzdHJpbmc7XG4gIHBhdGhTdHJva2U6IGFueTtcbiAgZ3JhZGllbnRJZDogc3RyaW5nO1xuICBsaW5lTGVuZ3RoOiBudW1iZXI7XG4gIGFuaW1hdGlvblN0YXRlID0gJyc7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5pZCA9IGdlbmVyYXRlSWQoKTtcbiAgICB0aGlzLmdyYWRpZW50SWQgPSBgbmd4LXRyZW5kLXZlcnRpY2FsLWdyYWRpZW50LSR7dGhpcy5pZH1gO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoKSB7XG4gICAgLy8gV2UgbmVlZCBhdCBsZWFzdCAyIHBvaW50cyB0byBkcmF3IGEgZ3JhcGguXG4gICAgaWYgKCF0aGlzLmRhdGEgfHwgdGhpcy5kYXRhLmxlbmd0aCA8IDIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBgZGF0YWAgY2FuIGVpdGhlciBiZSBhbiBhcnJheSBvZiBudW1iZXJzOlxuICAgIC8vIFsxLCAyLCAzXVxuICAgIC8vIG9yLCBhbiBhcnJheSBvZiBvYmplY3RzIGNvbnRhaW5pbmcgYSB2YWx1ZTpcbiAgICAvLyBbeyB2YWx1ZTogMSB9LCB7IHZhbHVlOiAyIH0sIHsgdmFsdWU6IDMgfV1cbiAgICAvL1xuICAgIC8vIEZvciBub3csIHdlJ3JlIGp1c3QgZ29pbmcgdG8gY29udmVydCB0aGUgc2Vjb25kIGZvcm0gdG8gdGhlIGZpcnN0LlxuICAgIC8vIExhdGVyIG9uLCBpZi93aGVuIHdlIHN1cHBvcnQgdG9vbHRpcHMsIHdlIG1heSBhZGp1c3QuXG4gICAgY29uc3QgcGxhaW5WYWx1ZXMgPSB0aGlzLmRhdGEubWFwKChwb2ludCkgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBwb2ludCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgcmV0dXJuIHBvaW50O1xuICAgICAgfVxuICAgICAgcmV0dXJuIHBvaW50LnZhbHVlO1xuICAgIH0pO1xuXG4gICAgLy8gcmVzZXQgdG8gcmUtcnVuIGFuaW1hdGlvblxuICAgIHRoaXMuYW5pbWF0aW9uU3RhdGUgPSAnaW5hY3RpdmUnO1xuXG4gICAgLy8gT3VyIHZpZXdib3ggbmVlZHMgdG8gYmUgaW4gYWJzb2x1dGUgdW5pdHMsIHNvIHdlJ2xsIGRlZmF1bHQgdG8gMzAweDc1XG4gICAgLy8gT3VyIFNWRyBjYW4gYmUgYSAlLCB0aG91Z2g7IHRoaXMgaXMgd2hhdCBtYWtlcyBpdCBzY2FsYWJsZS5cbiAgICAvLyBCeSBkZWZhdWx0aW5nIHRvIHBlcmNlbnRhZ2VzLCB0aGUgU1ZHIHdpbGwgZ3JvdyB0byBmaWxsIGl0cyBwYXJlbnRcbiAgICAvLyBjb250YWluZXIsIHByZXNlcnZpbmcgYSAxLzQgYXNwZWN0IHJhdGlvLlxuICAgIGNvbnN0IHZpZXdCb3hXaWR0aCA9IHRoaXMud2lkdGggfHwgMzAwO1xuICAgIGNvbnN0IHZpZXdCb3hIZWlnaHQgPSB0aGlzLmhlaWdodCB8fCA3NTtcbiAgICB0aGlzLnN2Z1dpZHRoID0gdGhpcy53aWR0aCB8fCAnMTAwJSc7XG4gICAgdGhpcy5zdmdIZWlnaHQgPSB0aGlzLmhlaWdodCB8fCAnMjUlJztcbiAgICB0aGlzLnZpZXdCb3ggPSBgMCAwICR7dmlld0JveFdpZHRofSAke3ZpZXdCb3hIZWlnaHR9YDtcbiAgICBjb25zdCByb290ID0gbG9jYXRpb24uaHJlZi5zcGxpdChsb2NhdGlvbi5oYXNoIHx8ICcjJylbMF07XG4gICAgdGhpcy5wYXRoU3Ryb2tlID0gKHRoaXMuZ3JhZGllbnQgJiYgdGhpcy5ncmFkaWVudC5sZW5ndGgpID8gYHVybCgnJHtyb290fSMke3RoaXMuZ3JhZGllbnRJZH0nKWAgOiB1bmRlZmluZWQ7XG5cbiAgICB0aGlzLmdyYWRpZW50VHJpbW1lZCA9IHRoaXMuZ3JhZGllbnQuc2xpY2UoKS5yZXZlcnNlKCkubWFwKCh2YWwsIGlkeCkgPT4ge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaWR4LFxuICAgICAgICBzdG9wQ29sb3I6IHZhbCxcbiAgICAgICAgb2Zmc2V0OiBub3JtYWxpemUoaWR4LCAwLCB0aGlzLmdyYWRpZW50Lmxlbmd0aCAtIDEgfHwgMSksXG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgY29uc3Qgbm9ybWFsaXplZFZhbHVlcyA9IG5vcm1hbGl6ZURhdGFzZXQocGxhaW5WYWx1ZXMsXG4gICAgICB0aGlzLnBhZGRpbmcsXG4gICAgICB2aWV3Qm94V2lkdGggLSB0aGlzLnBhZGRpbmcsXG4gICAgICAvLyBOT1RFOiBCZWNhdXNlIFNWR3MgYXJlIGluZGV4ZWQgZnJvbSB0aGUgdG9wIGxlZnQsIGJ1dCBtb3N0IGRhdGEgaXNcbiAgICAgIC8vIGluZGV4ZWQgZnJvbSB0aGUgYm90dG9tIGxlZnQsIHdlJ3JlIGludmVydGluZyB0aGUgWSBtaW4vbWF4LlxuICAgICAgdmlld0JveEhlaWdodCAtIHRoaXMucGFkZGluZyxcbiAgICAgIHRoaXMucGFkZGluZyxcbiAgICAgIHRoaXMubWluVmFsdWUsXG4gICAgICB0aGlzLm1heFZhbHVlXG4gICAgKTtcbiAgICB0aGlzLmNpcmNsZUNvb3JkaW5hdGVzID0gbm9ybWFsaXplZFZhbHVlcztcbiAgICB0aGlzLmxhc3RMYWJlbENvb3JkaW5hdGVzID0gdGhpcy5nZXRMYWJlbENvb3JkaW5hdGVPZkxhc3QoKTtcblxuXG4gICAgaWYgKHRoaXMuYXV0b0RyYXcgJiYgdGhpcy5hbmltYXRpb25TdGF0ZSAhPT0gJ2FjdGl2ZScpIHtcbiAgICAgIHRoaXMuYW5pbWF0aW9uU3RhdGUgPSAnaW5hY3RpdmUnO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMubGluZUxlbmd0aCA9IHRoaXMucGF0aEVsLm5hdGl2ZUVsZW1lbnQuZ2V0VG90YWxMZW5ndGgoKTtcbiAgICAgICAgdGhpcy5hbmltYXRpb25TdGF0ZSA9ICdhY3RpdmUnO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5kID0gdGhpcy5zbW9vdGhcbiAgICAgID8gYnVpbGRTbW9vdGhQYXRoKG5vcm1hbGl6ZWRWYWx1ZXMsIHRoaXMucmFkaXVzKVxuICAgICAgOiBidWlsZExpbmVhclBhdGgobm9ybWFsaXplZFZhbHVlcyk7XG4gIH1cblxuICBwcml2YXRlIGdldExhYmVsQ29vcmRpbmF0ZU9mTGFzdCgpIHtcbiAgICBjb25zdCBsYXN0SW5kZXggPSB0aGlzLmNpcmNsZUNvb3JkaW5hdGVzLmxlbmd0aCAtIDE7XG4gICAgY29uc3QgeyB4LCB5IH0gPSB0aGlzLmNpcmNsZUNvb3JkaW5hdGVzW2xhc3RJbmRleF07XG4gICAgY29uc3QgcmVzdWx0ID0ge1xuICAgICAgeCxcbiAgICAgIHk6IHkgKyAxNVxuICAgIH07XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufVxuIl19