ng-d3-graphs
Version:
<img src="./assets/ng-d3.png" alt="drawing" width="250" height="250"/>
269 lines (261 loc) • 35.3 kB
JavaScript
import * as tslib_1 from "tslib";
import { Component, ElementRef, HostListener, Input, OnInit, ViewEncapsulation } from '@angular/core';
import * as d3 from 'd3';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { axisConfig } from '../shared/config/axis.config';
import { D3Service } from '../shared/services/d3.service';
let MultilineComponent = class MultilineComponent {
constructor(container, d3Service) {
this.container = container;
this.d3Service = d3Service;
this.data = [];
this.labels = [];
this.options = {};
this.labelsAndData = [];
this.utcParse = d3.utcParse('%Y-%m');
this.viewBox = {};
this._options = {
width: 879,
height: 804,
yAxisLabel: '',
xAxisLabel: '',
margin: { top: 50, right: 50, bottom: 50, left: 50 },
timeParser: axisConfig.xAxisTimeParser,
timeFormat: axisConfig.xAxisTimeFormat,
xAxisTicks: axisConfig.xAxisTicks,
};
this.parseTime = d3.timeParse(this.options.timeParser);
this.formatTime = d3.timeFormat(this.options.timeFormat);
this.onResize$ = new Subject();
}
onResize() {
this.onResize$.next();
}
ngOnInit() {
this.options = Object.assign({}, this._options, this.options);
this.viewBox = {
minX: -this.options.margin.left,
minY: -25,
width: this.options.width + this.options.margin.left +
this.options.margin.right,
height: this.options.height + this.options.margin.top,
};
this.parseTime = d3.timeParse(this.options.timeParser);
this.formatTime = d3.timeFormat(this.options.timeFormat);
this.labels = this.formatData();
this.labelsAndData = this.combineLabelsDataToOne();
this.onResizeEvent();
this.render();
}
formatData() {
return this.labels.map(d => this.parseTime(d));
}
combineLabelsDataToOne() {
const result = [];
const N = this.data.length;
for (let index = 0; index < N; index++) {
result.push({ x: this.labels, y: this.data[index] });
}
return result;
}
render() {
const currentWidth = parseInt(d3.select(this.container.nativeElement).select('div').style('width'), 10);
const currentHeight = parseInt(d3.select(this.container.nativeElement).select('div').style('height'), 10);
const width = this.options.width - this.options.margin.left -
this.options.margin.right;
const height = this.options.height - this.options.margin.top -
this.options.margin.bottom;
this.viewBox = {
minX: -this.options.margin.left,
minY: -10,
width: this.options.width,
height: this.options.height - this.options.margin.top,
};
const svg = d3.select(this.container.nativeElement)
.select('div')
.append('svg')
.attr('width', currentWidth)
.attr('height', currentHeight)
.attr('viewBox', `${this.viewBox.minX} ${this.viewBox.minY} ${this.viewBox.width} ${this.viewBox.height}`)
.classed('svg-content', true)
.append('g');
const xDomain = this.getXdomain();
const x = d3.scaleTime().domain(xDomain).range([0, width]);
const y = d3.scaleLinear()
.domain([0, d3.max(this.data, (d) => d3.max(d.values))])
.range([height, 0])
.nice();
// const xAxis = (g) =>
// g.attr('transform', `translate(0,${height})`).call(d3.axisBottom(x));
const xAxis = this.d3Service.getXaxisTime(svg, height, x, this.options.timeFormat, this.options.xAxisTicks);
const yAxis = (g) => g.call(d3.axisLeft(y));
const line = d3.line()
.defined((d) => !isNaN(d))
.x((d, i) => x(this.labels[i]))
.y((d) => y(d));
// add the X gridlines
svg.append('g')
.attr('class', 'grid')
.call(this.make_x_gridlines(x).tickSize(height)
// .tickFormat('')
);
// add the Y gridlines
svg.append('g')
.attr('class', 'grid')
.call(this.make_y_gridlines(y).tickSize(-width)
// .tickFormat('')
);
const _yAxis = svg.append('g').call(yAxis);
// text label for the x axis
this.addLabelAxisX(svg, width, height);
// text label for the y axis
this.addLabelAxisY(svg, height);
const path = svg.append('g')
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.selectAll('path')
.data(this.data)
.join('path')
.style('mix-blend-mode', 'multiply')
.attr('d', (d) => line(d.values))
.text('this is ');
this.removeAxisTicks(xAxis);
this.removeAxisTicks(_yAxis);
this.changeAxisColor(xAxis, axisConfig);
this.changeAxisColor(_yAxis, axisConfig);
// TODO: comment in when issue #61 is fixed
/* svg.call(hover, path, this);
function hover(svg, path, _this) {
if ('ontouchstart' in document) {
svg.style('-webkit-tap-highlight-color', 'transparent')
.on('touchmove', moved)
.on('touchstart', entered)
.on('touchend', left);
} else {
svg.on('mousemove', moved)
.on('mouseenter', entered)
.on('mouseleave', left);
}
const dot = svg.append('g').attr('display', 'none');
dot.append('circle').attr('r', 2.5);
dot.append('text')
.attr('font-family', 'sans-serif')
.attr('font-size', 10)
.attr('text-anchor', 'middle')
.attr('y', -8);
function moved() {
d3.event.preventDefault();
const ym = y.invert(d3.event.layerY) as any;
const xm = x.invert(d3.event.layerX) as any;
const i1 = d3.bisectLeft(_this.labels, xm, 1);
const i0 = i1 - 1;
const i = xm - _this.labels[i0] > _this.labels[i1] - xm ? i1 : i0;
// const s = d3.least(_this.data, d => Math.abs(d.values[i] - ym));
const s = _this.least(_this.data, d => Math.abs(d.values[i] - ym), i,
ym); path.attr('stroke', d => d === s ? null : '#ddd') .filter(d => d === s)
.raise();
dot.attr(
'transform', `translate(${x(_this.labels[i])},${y(s.values[i])})`);
dot.select('text').text(s.name);
}
function entered() {
path.style('mix-blend-mode', null).attr('stroke', '#ddd');
dot.attr('display', null);
}
function left() {
path.style('mix-blend-mode', 'multiply').attr('stroke', null);
dot.attr('display', 'none');
}
}
*/
}
changeAxisColor(axis, config) {
this.d3Service.changeAxisColor(axis, config);
}
removeAxisTicks(axis) {
this.d3Service.removeAxisTicks(axis);
}
addLabelAxisY(svg, height) {
svg.append('text')
.attr('transform', 'rotate(0)')
.attr('y', 0 - this.options.margin.top / 2)
.attr('x', 0)
.attr('dy', '1em')
.style('text-anchor', 'start')
.text(this.options.yAxisLabel);
}
addLabelAxisX(svg, width, height) {
svg.append('text')
.attr('transform', 'translate(' + width / 2 + ' ,' +
(height + this.options.margin.top - 15) + ')')
.style('text-anchor', 'middle')
.text(this.options.xAxisLabel);
}
getXdomain() {
const domainExtent = d3.extent(this.labels, (d) => d);
return domainExtent.map((d) => new Date(d));
}
least(arr, filterFun, pos, ym) {
const tempValues = arr.map((d) => filterFun(d));
const minNum = Math.min(...tempValues);
let graphHovered;
let minimax = tempValues[0];
let minPos = 0;
for (let i = 1; i < tempValues.length; i++) {
const element = tempValues[i];
if (element >= minimax) {
minPos = i;
minimax = element;
}
}
graphHovered = arr[minPos];
return graphHovered;
}
// gridlines in x axis function
make_x_gridlines(x) {
return d3.axisBottom(x).ticks(this.options.gridTicks);
}
// gridlines in y axis function
make_y_gridlines(y) {
return d3.axisLeft(y).ticks(this.options.gridTicks);
}
onResizeEvent() {
this.onResize$.pipe(debounceTime(200)).subscribe(() => {
const svgExist = d3.select(this.container.nativeElement).select('svg');
if (svgExist) {
svgExist.remove();
}
this.render();
});
}
};
MultilineComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: D3Service }
];
tslib_1.__decorate([
Input()
], MultilineComponent.prototype, "data", void 0);
tslib_1.__decorate([
Input()
], MultilineComponent.prototype, "labels", void 0);
tslib_1.__decorate([
Input()
], MultilineComponent.prototype, "options", void 0);
tslib_1.__decorate([
HostListener('window:resize')
], MultilineComponent.prototype, "onResize", null);
MultilineComponent = tslib_1.__decorate([
Component({
selector: 'ng-multiline',
template: "<div class=\"svg-container\"></div>\n",
encapsulation: ViewEncapsulation.None,
styles: [".svg-container{display:inline-block;position:relative;width:100%;height:100%;padding-bottom:100%;vertical-align:top;overflow:hidden}.svg-content{display:inline-block;position:absolute;top:0;left:0}.grid line{stroke:#d3d3d3;stroke-opacity:.4;shape-rendering:crispEdges}.grid path{stroke-width:0}.grid text{display:none}"]
})
], MultilineComponent);
export { MultilineComponent };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXVsdGlsaW5lLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25nLWQzLWdyYXBocy8iLCJzb3VyY2VzIjpbIm11bHRpbGluZS9tdWx0aWxpbmUuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxpQkFBaUIsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUNwRyxPQUFPLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQztBQUN6QixPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUU1QyxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFHeEQsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLCtCQUErQixDQUFDO0FBc0J4RCxJQUFhLGtCQUFrQixHQUEvQixNQUFhLGtCQUFrQjtJQThCN0IsWUFDWSxTQUFxQixFQUNyQixTQUFvQjtRQURwQixjQUFTLEdBQVQsU0FBUyxDQUFZO1FBQ3JCLGNBQVMsR0FBVCxTQUFTLENBQVc7UUEvQnZCLFNBQUksR0FBb0IsRUFBRSxDQUFDO1FBQzNCLFdBQU0sR0FBVSxFQUFFLENBQUM7UUFDbkIsWUFBTyxHQUFzQixFQUFzQixDQUFDO1FBQzdELGtCQUFhLEdBQW9CLEVBQUUsQ0FBQztRQUNwQyxhQUFRLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUdoQyxZQUFPLEdBQVksRUFBYSxDQUFDO1FBRWpDLGFBQVEsR0FBcUI7WUFDM0IsS0FBSyxFQUFFLEdBQUc7WUFDVixNQUFNLEVBQUUsR0FBRztZQUNYLFVBQVUsRUFBRSxFQUFFO1lBQ2QsVUFBVSxFQUFFLEVBQUU7WUFDZCxNQUFNLEVBQUUsRUFBQyxHQUFHLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFB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QUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDdkUsSUFBSSxRQUFRLEVBQUU7Z0JBQ1osUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQ25CO1lBQ0QsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ2hCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGLENBQUE7O1lBM1F3QixVQUFVO1lBQ1YsU0FBUzs7QUEvQnZCO0lBQVIsS0FBSyxFQUFFO2dEQUE0QjtBQUMzQjtJQUFSLEtBQUssRUFBRTtrREFBb0I7QUFDbkI7SUFBUixLQUFLLEVBQUU7bURBQXFEO0FBdUI3RDtJQURDLFlBQVksQ0FBQyxlQUFlLENBQUM7a0RBRzdCO0FBNUJVLGtCQUFrQjtJQU45QixTQUFTLENBQUM7UUFDVCxRQUFRLEVBQUUsY0FBYztRQUN4QixpREFBeUM7UUFFekMsYUFBYSxFQUFFLGlCQUFpQixDQUFDLElBQUk7O0tBQ3RDLENBQUM7R0FDVyxrQkFBa0IsQ0EwUzlCO1NBMVNZLGtCQUFrQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Q29tcG9uZW50LCBFbGVtZW50UmVmLCBIb3N0TGlzdGVuZXIsIElucHV0LCBPbkluaXQsIFZpZXdFbmNhcHN1bGF0aW9ufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCAqIGFzIGQzIGZyb20gJ2QzJztcbmltcG9ydCB7U3ViamVjdH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge2RlYm91bmNlVGltZX0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQge2F4aXNDb25maWd9IGZyb20gJy4uL3NoYXJlZC9jb25maWcvYXhpcy5jb25maWcnO1xuaW1wb3J0IHtHcmFwaE9wdGlvbnN9IGZyb20gJy4uL3NoYXJlZC9tb2RlbHMvZ3JhcGgtb3B0aW9ucy5pbnRlcmZhY2UnO1xuaW1wb3J0IHtWaWV3Qm94fSBmcm9tICcuLi9zaGFyZWQvbW9kZWxzL3ZpZXdib3guaW50ZXJmYWNlJztcbmltcG9ydCB7RDNTZXJ2aWNlfSBmcm9tICcuLi9zaGFyZWQvc2VydmljZXMvZDMuc2VydmljZSc7XG5cbmludGVyZmFjZSBMYWJlbHNBbmREYXRhIHtcbiAgeDogYW55O1xuICB5OiBhbnk7XG59XG5cbmludGVyZmFjZSBNdWx0aWxpbmVEYXRhIHtcbiAgbGFiZWw6IHN0cmluZztcbiAgdmFsdWVzOiBhbnlbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNdWx0aWxpbmVPcHRpb25zIGV4dGVuZHMgR3JhcGhPcHRpb25zIHtcbiAgZ3JpZFRpY2tzPzogbnVtYmVyO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZy1tdWx0aWxpbmUnLFxuICB0ZW1wbGF0ZVVybDogJy4vbXVsdGlsaW5lLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vbXVsdGlsaW5lLmNvbXBvbmVudC5zY3NzJ10sXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG59KVxuZXhwb3J0IGNsYXNzIE11bHRpbGluZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBJbnB1dCgpIGRhdGE6IE11bHRpbGluZURhdGFbXSA9IFtdO1xuICBASW5wdXQoKSBsYWJlbHM6IGFueVtdID0gW107XG4gIEBJbnB1dCgpIG9wdGlvbnM/OiBNdWx0aWxpbmVPcHRpb25zID0ge30gYXMgTXVsdGlsaW5lT3B0aW9ucztcbiAgbGFiZWxzQW5kRGF0YTogTGFiZWxzQW5kRGF0YVtdID0gW107XG4gIHV0Y1BhcnNlID0gZDMudXRjUGFyc2UoJyVZLSVtJyk7XG4gIHg6IGFueTtcbiAgeTogYW55O1xuICB2aWV3Qm94OiBWaWV3Qm94ID0ge30gYXMgVmlld0JveDtcblxuICBfb3B0aW9uczogTXVsdGlsaW5lT3B0aW9ucyA9IHtcbiAgICB3aWR0aDogODc5LFxuICAgIGhlaWdodDogODA0LFxuICAgIHlBeGlzTGFiZWw6ICcnLFxuICAgIHhBeGlzTGFiZWw6ICcnLFxuICAgIG1hcmdpbjoge3RvcDogNTAsIHJpZ2h0OiA1MCwgYm90dG9tOiA1MCwgbGVmdDogNTB9LFxuICAgIHRpbWVQYXJzZXI6IGF4aXNDb25maWcueEF4aXNUaW1lUGFyc2VyLFxuICAgIHRpbWVGb3JtYXQ6IGF4aXNDb25maWcueEF4aXNUaW1lRm9ybWF0LFxuICAgIHhBeGlzVGlja3M6IGF4aXNDb25maWcueEF4aXNUaWNrcyxcbiAgfTtcblxuICBwYXJzZVRpbWUgPSBkMy50aW1lUGFyc2UodGhpcy5vcHRpb25zLnRpbWVQYXJzZXIpO1xuICBmb3JtYXRUaW1lID0gZDMudGltZUZvcm1hdCh0aGlzLm9wdGlvbnMudGltZUZvcm1hdCk7XG5cbiAgb25SZXNpemUkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgQEhvc3RMaXN0ZW5lcignd2luZG93OnJlc2l6ZScpXG4gIG9uUmVzaXplKCk6IHZvaWQge1xuICAgIHRoaXMub25SZXNpemUkLm5leHQoKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKFxuICAgICAgcHJpdmF0ZSBjb250YWluZXI6IEVsZW1lbnRSZWYsXG4gICAgICBwcml2YXRlIGQzU2VydmljZTogRDNTZXJ2aWNlLFxuICApIHt9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5vcHRpb25zID0gey4uLnRoaXMuX29wdGlvbnMsIC4uLnRoaXMub3B0aW9uc307XG4gICAgdGhpcy52aWV3Qm94ID0ge1xuICAgICAgbWluWDogLXRoaXMub3B0aW9ucy5tYXJnaW4ubGVmdCxcbiAgICAgIG1pblk6IC0yNSxcbiAgICAgIHdpZHRoOiB0aGlzLm9wdGlvbnMud2lkdGggKyB0aGlzLm9wdGlvbnMubWFyZ2luLmxlZnQgK1xuICAgICAgICAgIHRoaXMub3B0aW9ucy5tYXJnaW4ucmlnaHQsXG4gICAgICBoZWlnaHQ6IHRoaXMub3B0aW9ucy5oZWlnaHQgKyB0aGlzLm9wdGlvbnMubWFyZ2luLnRvcCxcbiAgICB9O1xuXG4gICAgdGhpcy5wYXJzZVRpbWUgPSBkMy50aW1lUGFyc2UodGhpcy5vcHRpb25zLnRpbWVQYXJzZXIpO1xuICAgIHRoaXMuZm9ybWF0VGltZSA9IGQzLnRpbWVGb3JtYXQodGhpcy5vcHRpb25zLnRpbWVGb3JtYXQpO1xuXG5cbiAgICB0aGlzLmxhYmVscyA9IHRoaXMuZm9ybWF0RGF0YSgpO1xuICAgIHRoaXMubGFiZWxzQW5kRGF0YSA9IHRoaXMuY29tYmluZUxhYmVsc0RhdGFUb09uZSgpO1xuXG4gICAgdGhpcy5vblJlc2l6ZUV2ZW50KCk7XG5cbiAgICB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgcHJpdmF0ZSBmb3JtYXREYXRhKCkge1xuICAgIHJldHVybiB0aGlzLmxhYmVscy5tYXAoZCA9PiB0aGlzLnBhcnNlVGltZShkKSk7XG4gIH1cblxuICBwcml2YXRlIGNvbWJpbmVMYWJlbHNEYXRhVG9PbmUoKTogTGFiZWxzQW5kRGF0YVtdIHtcbiAgICBjb25zdCByZXN1bHQgPSBbXTtcbiAgICBjb25zdCBOID0gdGhpcy5kYXRhLmxlbmd0aDtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgTjsgaW5kZXgrKykge1xuICAgICAgcmVzdWx0LnB1c2goe3g6IHRoaXMubGFiZWxzLCB5OiB0aGlzLmRhdGFbaW5kZXhdfSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICByZW5kZXIoKTogdm9pZCB7XG4gICAgY29uc3QgY3VycmVudFdpZHRoID0gcGFyc2VJbnQoXG4gICAgICAgIGQzLnNlbGVjdCh0aGlzLmNvbnRhaW5lci5uYXRpdmVFbGVtZW50KS5zZWxlY3QoJ2RpdicpLnN0eWxlKCd3aWR0aCcpLFxuICAgICAgICAxMCk7XG4gICAgY29uc3QgY3VycmVudEhlaWdodCA9IHBhcnNlSW50KFxuICAgICAgICBkMy5zZWxlY3QodGhpcy5jb250YWluZXIubmF0aXZlRWxlbWVudCkuc2VsZWN0KCdkaXYnKS5zdHlsZSgnaGVpZ2h0JyksXG4gICAgICAgIDEwKTtcblxuICAgIGNvbnN0IHdpZHRoID0gdGhpcy5vcHRpb25zLndpZHRoIC0gdGhpcy5vcHRpb25zLm1hcmdpbi5sZWZ0IC1cbiAgICAgICAgdGhpcy5vcHRpb25zLm1hcmdpbi5yaWdodDtcbiAgICBjb25zdCBoZWlnaHQgPSB0aGlzLm9wdGlvbnMuaGVpZ2h0IC0gdGhpcy5vcHRpb25zLm1hcmdpbi50b3AgLVxuICAgICAgICB0aGlzLm9wdGlvbnMubWFyZ2luLmJvdHRvbTtcblxuICAgIHRoaXMudmlld0JveCA9IHtcbiAgICAgIG1pblg6IC10aGlzLm9wdGlvbnMubWFyZ2luLmxlZnQsXG4gICAgICBtaW5ZOiAtMTAsXG4gICAgICB3aWR0aDogdGhpcy5vcHRpb25zLndpZHRoLFxuICAgICAgaGVpZ2h0OiB0aGlzLm9wdGlvbnMuaGVpZ2h0IC0gdGhpcy5vcHRpb25zLm1hcmdpbi50b3AsXG4gICAgfTtcblxuICAgIGNvbnN0IHN2ZyA9IGQzLnNlbGVjdCh0aGlzLmNvbnRhaW5lci5uYXRpdmVFbGVtZW50KVxuICAgICAgICAgICAgICAgICAgICAuc2VsZWN0KCdkaXYnKVxuICAgICAgICAgICAgICAgICAgICAuYXBwZW5kKCdzdmcnKVxuICAgICAgICAgICAgICAgICAgICAuYXR0cignd2lkdGgnLCBjdXJyZW50V2lkdGgpXG4gICAgICAgICAgICAgICAgICAgIC5hdHRyKCdoZWlnaHQnLCBjdXJyZW50SGVpZ2h0KVxuICAgICAgICAgICAgICAgICAgICAuYXR0cihcbiAgICAgICAgICAgICAgICAgICAgICAgICd2aWV3Qm94JyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGAke3RoaXMudmlld0JveC5taW5YfSAke3RoaXMudmlld0JveC5taW5ZfSAke1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudmlld0JveC53aWR0aH0gJHt0aGlzLnZpZXdCb3guaGVpZ2h0fWApXG4gICAgICAgICAgICAgICAgICAgIC5jbGFzc2VkKCdzdmctY29udGVudCcsIHRydWUpXG4gICAgICAgICAgICAgICAgICAgIC5hcHBlbmQoJ2cnKTtcblxuICAgIGNvbnN0IHhEb21haW4gPSB0aGlzLmdldFhkb21haW4oKTtcbiAgICBjb25zdCB4ID0gZDMuc2NhbGVUaW1lKCkuZG9tYWluKHhEb21haW4pLnJhbmdlKFswLCB3aWR0aF0pO1xuXG4gICAgY29uc3QgeSA9IGQzLnNjYWxlTGluZWFyKClcbiAgICAgICAgICAgICAgICAgIC5kb21haW4oWzAsIGQzLm1heCh0aGlzLmRhdGEsIChkKSA9PiBkMy5tYXgoZC52YWx1ZXMpKV0pXG4gICAgICAgICAgICAgICAgICAucmFuZ2UoW2hlaWdodCwgMF0pXG4gICAgICAgICAgICAgICAgICAubmljZSgpO1xuXG4gICAgLy8gY29uc3QgeEF4aXMgPSAoZykgPT5cbiAgICAvLyAgICAgZy5hdHRyKCd0cmFuc2Zvcm0nLCBgdHJhbnNsYXRlKDAsJHtoZWlnaHR9KWApLmNhbGwoZDMuYXhpc0JvdHRvbSh4KSk7XG5cbiAgICBjb25zdCB4QXhpcyA9IHRoaXMuZDNTZXJ2aWNlLmdldFhheGlzVGltZShcbiAgICAgICAgc3ZnLCBoZWlnaHQsIHgsIHRoaXMub3B0aW9ucy50aW1lRm9ybWF0LCB0aGlzLm9wdGlvbnMueEF4aXNUaWNrcyk7XG5cblxuICAgIGNvbnN0IHlBeGlzID0gKGcpID0+IGcuY2FsbChkMy5heGlzTGVmdCh5KSk7XG5cbiAgICBjb25zdCBsaW5lID0gZDMubGluZTxhbnk+KClcbiAgICAgICAgICAgICAgICAgICAgIC5kZWZpbmVkKChkKSA9PiAhaXNOYU4oZCkpXG4gICAgICAgICAgICAgICAgICAgICAueCgoZCwgaSkgPT4geCh0aGlzLmxhYmVsc1tpXSkpXG4gICAgICAgICAgICAgICAgICAgICAueSgoZCkgPT4geShkKSk7XG5cbiAgICAvLyBhZGQgdGhlIFggZ3JpZGxpbmVzXG4gICAgc3ZnLmFwcGVuZCgnZycpXG4gICAgICAgIC5hdHRyKCdjbGFzcycsICdncmlkJylcbiAgICAgICAgLmNhbGwoXG4gICAgICAgICAgICB0aGlzLm1ha2VfeF9ncmlkbGluZXMoeCkudGlja1NpemUoaGVpZ2h0KVxuICAgICAgICAgICAgLy8gLnRpY2tGb3JtYXQoJycpXG4gICAgICAgICk7XG5cbiAgICAvLyBhZGQgdGhlIFkgZ3JpZGxpbmVzXG4gICAgc3ZnLmFwcGVuZCgnZycpXG4gICAgICAgIC5hdHRyKCdjbGFzcycsICdncmlkJylcbiAgICAgICAgLmNhbGwoXG4gICAgICAgICAgICB0aGlzLm1ha2VfeV9ncmlkbGluZXMoeSkudGlja1NpemUoLXdpZHRoKVxuICAgICAgICAgICAgLy8gLnRpY2tGb3JtYXQoJycpXG4gICAgICAgICk7XG5cbiAgICBjb25zdCBfeUF4aXMgPSBzdmcuYXBwZW5kKCdnJykuY2FsbCh5QXhpcyk7XG5cbiAgICAvLyB0ZXh0IGxhYmVsIGZvciB0aGUgeCBheGlzXG4gICAgdGhpcy5hZGRMYWJlbEF4aXNYKHN2Zywgd2lkdGgsIGhlaWdodCk7XG4gICAgLy8gdGV4dCBsYWJlbCBmb3IgdGhlIHkgYXhpc1xuICAgIHRoaXMuYWRkTGFiZWxBeGlzWShzdmcsIGhlaWdodCk7XG5cbiAgICBjb25zdCBwYXRoID0gc3ZnLmFwcGVuZCgnZycpXG4gICAgICAgICAgICAgICAgICAgICAuYXR0cignZmlsbCcsICdub25lJylcbiAgICAgICAgICAgICAgICAgICAgIC5hdHRyKCdzdHJva2UnLCAnc3RlZWxibHVlJylcbiAgICAgICAgICAgICAgICAgICAgIC5hdHRyKCdzdHJva2Utd2lkdGgnLCAxLjUpXG4gICAgICAgICAgICAgICAgICAgICAuYXR0cignc3Ryb2tlLWxpbmVqb2luJywgJ3JvdW5kJylcbiAgICAgICAgICAgICAgICAgICAgIC5hdHRyKCdzdHJva2UtbGluZWNhcCcsICdyb3VuZCcpXG4gICAgICAgICAgICAgICAgICAgICAuc2VsZWN0QWxsKCdwYXRoJylcbiAgICAgICAgICAgICAgICAgICAgIC5kYXRhKHRoaXMuZGF0YSlcbiAgICAgICAgICAgICAgICAgICAgIC5qb2luKCdwYXRoJylcbiAgICAgICAgICAgICAgICAgICAgIC5zdHlsZSgnbWl4LWJsZW5kLW1vZGUnLCAnbXVsdGlwbHknKVxuICAgICAgICAgICAgICAgICAgICAgLmF0dHIoJ2QnLCAoZCkgPT4gbGluZShkLnZhbHVlcykpXG4gICAgICAgICAgICAgICAgICAgICAudGV4dCgndGhpcyBpcyAnKTtcblxuICAgIHRoaXMucmVtb3ZlQXhpc1RpY2tzKHhBeGlzKTtcbiAgICB0aGlzLnJlbW92ZUF4aXNUaWNrcyhfeUF4aXMpO1xuXG4gICAgdGhpcy5jaGFuZ2VBeGlzQ29sb3IoeEF4aXMsIGF4aXNDb25maWcpO1xuICAgIHRoaXMuY2hhbmdlQXhpc0NvbG9yKF95QXhpcywgYXhpc0NvbmZpZyk7XG5cbiAgICAvLyBUT0RPOiBjb21tZW50IGluIHdoZW4gaXNzdWUgIzYxIGlzIGZpeGVkXG4gICAgLyogc3ZnLmNhbGwoaG92ZXIsIHBhdGgsIHRoaXMpO1xuXG4gICAgZnVuY3Rpb24gaG92ZXIoc3ZnLCBwYXRoLCBfdGhpcykge1xuXG4gICAgICBpZiAoJ29udG91Y2hzdGFydCcgaW4gZG9jdW1lbnQpIHtcbiAgICAgICAgc3ZnLnN0eWxlKCctd2Via2l0LXRhcC1oaWdobGlnaHQtY29sb3InLCAndHJhbnNwYXJlbnQnKVxuICAgICAgICAgIC5vbigndG91Y2htb3ZlJywgbW92ZWQpXG4gICAgICAgICAgLm9uKCd0b3VjaHN0YXJ0JywgZW50ZXJlZClcbiAgICAgICAgICAub24oJ3RvdWNoZW5kJywgbGVmdCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdmcub24oJ21vdXNlbW92ZScsIG1vdmVkKVxuICAgICAgICAgIC5vbignbW91c2VlbnRlcicsIGVudGVyZWQpXG4gICAgICAgICAgLm9uKCdtb3VzZWxlYXZlJywgbGVmdCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRvdCA9IHN2Zy5hcHBlbmQoJ2cnKS5hdHRyKCdkaXNwbGF5JywgJ25vbmUnKTtcblxuICAgICAgZG90LmFwcGVuZCgnY2lyY2xlJykuYXR0cigncicsIDIuNSk7XG5cbiAgICAgIGRvdC5hcHBlbmQoJ3RleHQnKVxuICAgICAgICAuYXR0cignZm9udC1mYW1pbHknLCAnc2Fucy1zZXJpZicpXG4gICAgICAgIC5hdHRyKCdmb250LXNpemUnLCAxMClcbiAgICAgICAgLmF0dHIoJ3RleHQtYW5jaG9yJywgJ21pZGRsZScpXG4gICAgICAgIC5hdHRyKCd5JywgLTgpO1xuXG4gICAgICBmdW5jdGlvbiBtb3ZlZCgpIHtcbiAgICAgICAgZDMuZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc3QgeW0gPSB5LmludmVydChkMy5ldmVudC5sYXllclkpIGFzIGFueTtcbiAgICAgICAgY29uc3QgeG0gPSB4LmludmVydChkMy5ldmVudC5sYXllclgpIGFzIGFueTtcbiAgICAgICAgY29uc3QgaTEgPSBkMy5iaXNlY3RMZWZ0KF90aGlzLmxhYmVscywgeG0sIDEpO1xuICAgICAgICBjb25zdCBpMCA9IGkxIC0gMTtcbiAgICAgICAgY29uc3QgaSA9IHhtIC0gX3RoaXMubGFiZWxzW2kwXSA+IF90aGlzLmxhYmVsc1tpMV0gLSB4bSA/IGkxIDogaTA7XG4gICAgICAgIC8vIGNvbnN0IHMgPSBkMy5sZWFzdChfdGhpcy5kYXRhLCBkID0+IE1hdGguYWJzKGQudmFsdWVzW2ldIC0geW0pKTtcbiAgICAgICAgY29uc3QgcyA9IF90aGlzLmxlYXN0KF90aGlzLmRhdGEsIGQgPT4gTWF0aC5hYnMoZC52YWx1ZXNbaV0gLSB5bSksIGksXG4gICAgeW0pOyBwYXRoLmF0dHIoJ3N0cm9rZScsIGQgPT4gZCA9PT0gcyA/IG51bGwgOiAnI2RkZCcpIC5maWx0ZXIoZCA9PiBkID09PSBzKVxuICAgICAgICAgIC5yYWlzZSgpO1xuICAgICAgICBkb3QuYXR0cihcbiAgICAgICAgICAndHJhbnNmb3JtJywgYHRyYW5zbGF0ZSgke3goX3RoaXMubGFiZWxzW2ldKX0sJHt5KHMudmFsdWVzW2ldKX0pYCk7XG4gICAgICAgIGRvdC5zZWxlY3QoJ3RleHQnKS50ZXh0KHMubmFtZSk7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGVudGVyZWQoKSB7XG4gICAgICAgIHBhdGguc3R5bGUoJ21peC1ibGVuZC1tb2RlJywgbnVsbCkuYXR0cignc3Ryb2tlJywgJyNkZGQnKTtcbiAgICAgICAgZG90LmF0dHIoJ2Rpc3BsYXknLCBudWxsKTtcbiAgICAgIH1cblxuICAgICAgZnVuY3Rpb24gbGVmdCgpIHtcbiAgICAgICAgcGF0aC5zdHlsZSgnbWl4LWJsZW5kLW1vZGUnLCAnbXVsdGlwbHknKS5hdHRyKCdzdHJva2UnLCBudWxsKTtcbiAgICAgICAgZG90LmF0dHIoJ2Rpc3BsYXknLCAnbm9uZScpO1xuICAgICAgfVxuICAgIH1cbiAgICAqL1xuICB9XG5cbiAgcHJpdmF0ZSBjaGFuZ2VBeGlzQ29sb3IoXG4gICAgICBheGlzOiBkMy5TZWxlY3Rpb248U1ZHR0VsZW1lbnQsIHVua25vd24sIG51bGwsIHVuZGVmaW5lZD4sIGNvbmZpZzogYW55KSB7XG4gICAgdGhpcy5kM1NlcnZpY2UuY2hhbmdlQXhpc0NvbG9yKGF4aXMsIGNvbmZpZyk7XG4gIH1cblxuICBwcml2YXRlIHJlbW92ZUF4aXNUaWNrcyhcbiAgICAgIGF4aXM6IGQzLlNlbGVjdGlvbjxTVkdHRWxlbWVudCwgdW5rbm93biwgbnVsbCwgdW5kZWZpbmVkPikge1xuICAgIHRoaXMuZDNTZXJ2aWNlLnJlbW92ZUF4aXNUaWNrcyhheGlzKTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkTGFiZWxBeGlzWShcbiAgICAgIHN2ZzogZDMuU2VsZWN0aW9uPFNWR0dFbGVtZW50LCB1bmtub3duLCBudWxsLCB1bmRlZmluZWQ+LFxuICAgICAgaGVpZ2h0OiBudW1iZXIpIHtcbiAgICBzdmcuYXBwZW5kKCd0ZXh0JylcbiAgICAgICAgLmF0dHIoJ3RyYW5zZm9ybScsICdyb3RhdGUoMCknKVxuICAgICAgICAuYXR0cigneScsIDAgLSB0aGlzLm9wdGlvbnMubWFyZ2luLnRvcCAvIDIpXG4gICAgICAgIC5hdHRyKCd4JywgMClcbiAgICAgICAgLmF0dHIoJ2R5JywgJzFlbScpXG4gICAgICAgIC5zdHlsZSgndGV4dC1hbmNob3InLCAnc3RhcnQnKVxuXG4gICAgICAgIC50ZXh0KHRoaXMub3B0aW9ucy55QXhpc0xhYmVsKTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkTGFiZWxBeGlzWChcbiAgICAgIHN2ZzogZDMuU2VsZWN0aW9uPFNWR0dFbGVtZW50LCB1bmtub3duLCBudWxsLCB1bmRlZmluZWQ+LCB3aWR0aDogbnVtYmVyLFxuICAgICAgaGVpZ2h0OiBudW1iZXIpIHtcbiAgICBzdmcuYXBwZW5kKCd0ZXh0JylcbiAgICAgICAgLmF0dHIoXG4gICAgICAgICAgICAndHJhbnNmb3JtJyxcbiAgICAgICAgICAgICd0cmFuc2xhdGUoJyArIHdpZHRoIC8gMiArICcgLCcgK1xuICAgICAgICAgICAgICAgIChoZWlnaHQgKyB0aGlzLm9wdGlvbnMubWFyZ2luLnRvcCAtIDE1KSArICcpJylcbiAgICAgICAgLnN0eWxlKCd0ZXh0LWFuY2hvcicsICdtaWRkbGUnKVxuICAgICAgICAudGV4dCh0aGlzLm9wdGlvbnMueEF4aXNMYWJlbCk7XG4gIH1cblxuICBwcml2YXRlIGdldFhkb21haW4oKTogRGF0ZVtdIHtcbiAgICBjb25zdCBkb21haW5FeHRlbnQgPSBkMy5leHRlbnQodGhpcy5sYWJlbHMsIChkKSA9PiBkKSBhcyBhbnlbXTtcbiAgICByZXR1cm4gZG9tYWluRXh0ZW50Lm1hcCgoZCkgPT4gbmV3IERhdGUoZCkpO1xuICB9XG5cbiAgbGVhc3QoYXJyOiBhbnlbXSwgZmlsdGVyRnVuOiBhbnksIHBvczogYW55LCB5bTogYW55KSB7XG4gICAgY29uc3QgdGVtcFZhbHVlcyA9IGFyci5tYXAoKGQpID0+IGZpbHRlckZ1bihkKSk7XG4gICAgY29uc3QgbWluTnVtID0gTWF0aC5taW4oLi4udGVtcFZhbHVlcyk7XG4gICAgbGV0IGdyYXBoSG92ZXJlZDtcbiAgICBsZXQgbWluaW1heCA9IHRlbXBWYWx1ZXNbMF07XG4gICAgbGV0IG1pblBvcyA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCB0ZW1wVmFsdWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBlbGVtZW50ID0gdGVtcFZhbHVlc1tpXTtcbiAgICAgIGlmIChlbGVtZW50ID49IG1pbmltYXgpIHtcbiAgICAgICAgbWluUG9zID0gaTtcbiAgICAgICAgbWluaW1heCA9IGVsZW1lbnQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZ3JhcGhIb3ZlcmVkID0gYXJyW21pblBvc107XG4gICAgcmV0dXJuIGdyYXBoSG92ZXJlZDtcbiAgfVxuXG4gIC8vIGdyaWRsaW5lcyBpbiB4IGF4aXMgZnVuY3Rpb25cbiAgcHJpdmF0ZSBtYWtlX3hfZ3JpZGxpbmVzKHgpIHtcbiAgICByZXR1cm4gZDMuYXhpc0JvdHRvbSh4KS50aWNrcyh0aGlzLm9wdGlvbnMuZ3JpZFRpY2tzKTtcbiAgfVxuXG4gIC8vIGdyaWRsaW5lcyBpbiB5IGF4aXMgZnVuY3Rpb25cbiAgcHJpdmF0ZSBtYWtlX3lfZ3JpZGxpbmVzKHkpIHtcbiAgICByZXR1cm4gZDMuYXhpc0xlZnQoeSkudGlja3ModGhpcy5vcHRpb25zLmdyaWRUaWNrcyk7XG4gIH1cblxuICBvblJlc2l6ZUV2ZW50KCk6IHZvaWQge1xuICAgIHRoaXMub25SZXNpemUkLnBpcGUoZGVib3VuY2VUaW1lKDIwMCkpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICBjb25zdCBzdmdFeGlzdCA9IGQzLnNlbGVjdCh0aGlzLmNvbnRhaW5lci5uYXRpdmVFbGVtZW50KS5zZWxlY3QoJ3N2ZycpO1xuICAgICAgaWYgKHN2Z0V4aXN0KSB7XG4gICAgICAgIHN2Z0V4aXN0LnJlbW92ZSgpO1xuICAgICAgfVxuICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICB9KTtcbiAgfVxufVxuIl19