ng-plan
Version:
This module will draw a 2D plan drawing from a geoJSON object. It was built to visualize 2D space boundaries from the Building Information Modeling (BIM) authring tool, Revit. It is quite generic, but does have some features that are mainly related to the
477 lines (467 loc) • 46.9 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core';
import { MatIconRegistry } from "@angular/material/icon";
import { DomSanitizer } from "@angular/platform-browser";
import * as d3 from 'd3-decompose';
import * as d3p from 'd3-polygon';
/**
* @record
*/
export function Room() { }
function Room_tsickle_Closure_declarations() {
/** @type {?} */
Room.prototype.name;
/** @type {?} */
Room.prototype.polygons;
}
export class PlanComponent {
/**
* @param {?} matIconRegistry
* @param {?} domSanitizer
*/
constructor(matIconRegistry, domSanitizer) {
this.matIconRegistry = matIconRegistry;
this.domSanitizer = domSanitizer;
this.clickedRoom = new EventEmitter();
this.clickedCanvas = new EventEmitter();
// Styles
this.selectedColor = '#ebefe4';
this.defaultColor = '#f2flec';
this.baseScale = 0.9;
this.baseOffsetX = 0;
this.baseOffsetY = 0;
this.transform = `translate(${this.baseOffsetX},${this.baseOffsetY}) scale(${this.baseScale},${this.baseScale})`;
this.movedX = 0;
this.movedY = 0;
this.scaled = 1;
this.panMode = false;
this.addNodeMode = false;
}
/**
* @return {?}
*/
ngAfterViewInit() {
this.getCanvasSize();
// this.addSVGicons();
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (changes["data"] && changes["data"].currentValue) {
this.data = changes["data"].currentValue;
this.extractRooms();
this.getScaleOffset();
this.zoomExtents();
}
if (changes["colors"] && changes["colors"].currentValue) {
this.defineColors();
}
if (changes["selected"]) {
this.updateSelection();
}
}
/**
* @return {?}
*/
updateSelection() {
if (!this.rooms)
return;
this.rooms = this.rooms.map(x => {
if (this.selected.indexOf(x.uri) != -1) {
x.selected = true;
}
else {
x.selected = false;
}
return x;
});
}
/**
* @return {?}
*/
defineColors() {
this.rooms.map(x => {
var /** @type {?} */ match = this.colors.filter(y => y.uri == x.uri);
if (match.length > 0) {
x.color = match[0].color;
x.description = match[0].value;
}
return x;
});
}
/**
* @return {?}
*/
getCanvasSize() {
const /** @type {?} */ element = this.planContainer.nativeElement;
const /** @type {?} */ size = element.getBoundingClientRect();
this.canvasWidth = size.width;
this.canvasHeight = size.height;
this.canvasCentroid = [this.canvasWidth / 2, this.canvasHeight / 2];
}
/**
* @return {?}
*/
extractRooms() {
if (!this.data.features)
return this.rooms = null;
// For bounding box [xMin, yMin, xMax, yMax]
var /** @type {?} */ xMin;
var /** @type {?} */ yMin;
var /** @type {?} */ xMax;
var /** @type {?} */ yMax;
this.rooms = this.data.features.map(room => {
var /** @type {?} */ polygons = [];
var /** @type {?} */ roomPath = '';
var /** @type {?} */ centroid;
if (room.geometry && room.geometry.type == "Polygon") {
var /** @type {?} */ roomPolygons = []; // Allow multi polygons if doughnut room
room.geometry.coordinates.forEach(polygon => {
var /** @type {?} */ points = '';
var /** @type {?} */ path = '';
// Reflect y coordinates to fit browser coordinate system and extract to polygon
polygon.map((coordinate, index) => {
var /** @type {?} */ x = coordinate[0];
var /** @type {?} */ y = -coordinate[1]; // reflect since SVG uses reflected coordinate system
points += `${x},${y} `;
path += (index == 0) ? `M${x},${y} ` : `L${x},${y} `;
coordinate[1] = y; // Update polygon with new y
// Get bounding box
if (!xMin || x < xMin)
xMin = x;
if (!xMax || x > xMax)
xMax = x;
if (!yMin || y < yMin)
yMin = y;
if (!yMax || y > yMax)
yMax = y;
return coordinate;
});
points = points.trim(); // remove last space
path = path.trim(); // remove last space
// Get polygon centroid from first polygon
if (roomPolygons.length < 1) {
centroid = d3p.polygonCentroid(polygon);
}
roomPolygons.push(points);
roomPath += path;
});
polygons.push(roomPolygons);
}
var /** @type {?} */ name = room.properties.name;
var /** @type {?} */ uri = room.properties.uri;
var /** @type {?} */ color = room.properties.color ? room.properties.color : this.defaultColor;
var /** @type {?} */ description = room.properties.description ? room.properties.description : '';
// Store bounding box
this.boundingBox = [xMin, yMin, xMax, yMax];
return { name: name, uri: uri, description: description, color: color, polygons: polygons, path: roomPath, centroid: centroid };
});
}
/**
* @return {?}
*/
getScaleOffset() {
// Calculate data size
var /** @type {?} */ bb = this.boundingBox;
var /** @type {?} */ dataWidth = bb[2] - bb[0];
var /** @type {?} */ dataHeight = bb[3] - bb[1];
// Calculate scale factors
var /** @type {?} */ scaleWidth = this.canvasWidth / dataWidth;
var /** @type {?} */ scaleHeight = this.canvasHeight / dataHeight;
var /** @type {?} */ scale = Math.min(scaleHeight, scaleWidth);
var /** @type {?} */ scaledDataCentroid = [scale * (bb[0] + dataWidth / 2), scale * (bb[1] + dataHeight / 2)];
// Calculate offset factors
var /** @type {?} */ offsetX = this.canvasCentroid[0] - scaledDataCentroid[0];
var /** @type {?} */ offsetY = this.canvasCentroid[1] - scaledDataCentroid[1];
// Set global variables
this.baseOffsetX = offsetX;
this.baseOffsetY = offsetY;
this.baseScale = scale;
return [scale, offsetX, offsetY];
}
/**
* @param {?} displacement
* @return {?}
*/
move(displacement) {
if (displacement) {
this.zoomHandler(undefined, displacement);
}
}
/**
* @param {?} displacement
* @return {?}
*/
moveEnd(displacement) {
// Update moved coordinates
this.movedX = this.movedX + displacement[0];
this.movedY = this.movedY + displacement[1];
}
/**
* @return {?}
*/
onWindowResize() {
this.getCanvasSize();
this.getScaleOffset();
this.zoomExtents();
}
/**
* @return {?}
*/
zoomExtents() {
this.scaled = this.baseScale * 0.95;
this.movedX = 0;
this.movedY = 0;
this.zoomHandler();
}
/**
* @param {?} ev
* @return {?}
*/
zoomOut(ev) {
// Calculate current scale
var /** @type {?} */ scaleFactor = this.baseScale / 5;
this.scaled = this.scaled - scaleFactor;
this.zoomHandler(ev);
}
/**
* @param {?} ev
* @return {?}
*/
zoomIn(ev) {
var /** @type {?} */ scaleFactor = this.baseScale / 5;
this.scaled = this.scaled + scaleFactor;
this.zoomHandler(ev);
}
/**
* @param {?=} ev
* @param {?=} displacement
* @return {?}
*/
zoomHandler(ev, displacement) {
var /** @type {?} */ trns1 = '';
if (displacement) {
var /** @type {?} */ dx = this.baseOffsetX + this.movedX + displacement[0];
var /** @type {?} */ dy = this.baseOffsetY + this.movedY + displacement[1];
}
else {
dx = this.baseOffsetX + this.movedX;
dy = this.baseOffsetY + this.movedY;
}
// This should be adjusted to center at mouse position while zooming
// if(ev && ev.offsetX){
// // Get mouse position relative to canvas center point and move
// var mx = ev.offsetX-this.canvasCentroid[0];
// var my = ev.offsetY-this.canvasCentroid[1];
// var dx2 = mx;
// var dy2 = my;
// trns1 = `translate(${dx2},${dy2})`;
// console.log(trns1)
// }
var /** @type {?} */ oldScale = d3.decompose(this.transform).scale;
var /** @type {?} */ oldTrns = d3.decompose(this.transform).translate;
var /** @type {?} */ scale = `scale(${this.scaled},${this.scaled})`;
var /** @type {?} */ trns = `translate(${dx},${dy})`;
// Update transform attribute
this.transform = trns + trns1 + scale;
// this.transform = this.transform.replace(oldScale,scale);
}
/**
* @param {?} ev
* @param {?} room
* @return {?}
*/
selectRoom(ev, room) {
// Get coordinates
var /** @type {?} */ scale = this.scaled;
var /** @type {?} */ offsetX = this.baseOffsetX + this.movedX;
var /** @type {?} */ offsetY = this.baseOffsetY + this.movedY;
var /** @type {?} */ screenX = ev.offsetX;
var /** @type {?} */ screenY = ev.offsetX;
var /** @type {?} */ x = (screenX - offsetX) / scale;
var /** @type {?} */ y = (screenY - offsetY) / scale;
var /** @type {?} */ coordinates = [x, -y];
// Emit event
this.clickedRoom.emit({ uri: room.uri, coordinates: coordinates });
}
/**
* @param {?} ev
* @return {?}
*/
onCanvasClick(ev) {
if (ev.target.id != 'canvas')
return;
this.clickedCanvas.emit();
}
}
PlanComponent.decorators = [
{ type: Component, args: [{
selector: 'ng-plan',
template: `<!-- Toolbar -->
<div class="toolbar" *ngIf="toolbar">
<div class="icon-div" (click)="zoomIn(null)" matTooltip="Zoom in">
<mat-icon>zoom_in</mat-icon>
</div>
<div class="icon-div" (click)="zoomOut(null)" matTooltip="Zoom out">
<mat-icon>zoom_out</mat-icon>
</div>
<div class="icon-div" (click)="zoomExtents()" matTooltip="Zoom extents">
<mat-icon svgIcon="zoom_extents"></mat-icon>
</div>
</div>
<div class="footer">
<p>Press and hold "Alt" to pan</p>
</div>
<svg canvasEvents
[style.cursor]="panMode ? 'move' : 'default'"
#canvas
class=canvas
(click)="onCanvasClick($event)"
(zoomOut)="zoomOut($event)"
(zoomIn)="zoomIn($event)"
(panMode)="panMode = $event"
(move)="move($event)"
(moveEnd)="moveEnd($event)"
(window:resize)="onWindowResize()"
(addNodeMode)="addNodeMode = $event"
id="canvas">
<!--Draw rooms-->
<g *ngFor="let room of rooms"
[attr.transform]="transform"
[id]="room.uri"
(click)="selectRoom($event, room)"
[attr.fill]="room.selected ? selectedColor : room.color"
class="room">
<!-- Draw polygons -->
<!-- <polygon *ngFor="let polygon of room.polygons"
[attr.points]="polygon"
class="polygon">
</polygon> -->
<!-- Draw paths -->
<path
[class.selected-space]="room.selected"
[attr.d]="room.path"
class="polygon">
</path>
<!-- Draw centroids -->
<circle
*ngIf="centroids"
[attr.cx]="room.centroid[0]"
fill="black"
[attr.cy]="room.centroid[1]"
[attr.r]="scaled*500">
</circle>
<!-- Add labels -->
<text
[style.font-size.em]="'12'"
style = "font-family:roboto; fill: black;"
text-anchor="middle"
alignment-baseline="central"
[attr.x]="room.centroid[0]"
[attr.dy]="room.description ? -150 : 0"
[attr.y]="room.centroid[1]">
{{room.name}}
</text>
<!-- Add description -->
<text
*ngIf = "room.description"
[style.font-size.em]="'10'"
style = "font-family:roboto; fill: black;"
text-anchor="middle"
alignment-baseline="central"
[attr.x]="room.centroid[0]"
[attr.y]="room.centroid[1]"
dy="150">
{{room.description}}
</text>
</g>
</svg>`,
styles: [`.canvas{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:100%;height:100%;position:fixed;top:0;left:0;bottom:0;right:0;z-index:-1}.polygon{stroke:#000;stroke-width:1;vector-effect:non-scaling-stroke;fill-rule:evenodd}.room:hover{opacity:.5;cursor:pointer}.selected-space{stroke-width:2}.toolbar{position:absolute;color:red;right:20px;width:100%}.icon-div>.mat-icon{float:right;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:rgba(220,220,220,.3);border-width:1px;border-radius:5px;margin-left:5px;padding:5px;z-index:1}.mat-icon{color:rgba(0,0,0,.6);font-size:30px;height:30px;width:30px;z-index:10}.mat-icon:hover{cursor:pointer;color:rgba(0,0,0,1)}.footer{background-color:rgba(220,220,220,.3);position:absolute;font-family:consolas;font-size:12px;padding:0 10px;border-radius:5px;bottom:10px}`]
},] },
];
/** @nocollapse */
PlanComponent.ctorParameters = () => [
{ type: MatIconRegistry, },
{ type: DomSanitizer, },
];
PlanComponent.propDecorators = {
"clickedRoom": [{ type: Output },],
"clickedCanvas": [{ type: Output },],
"data": [{ type: Input },],
"colors": [{ type: Input },],
"centroids": [{ type: Input },],
"toolbar": [{ type: Input },],
"selected": [{ type: Input },],
"selectedColor": [{ type: Input },],
"defaultColor": [{ type: Input },],
"planContainer": [{ type: ViewChild, args: ['canvas',] },],
};
function PlanComponent_tsickle_Closure_declarations() {
/** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */
PlanComponent.decorators;
/**
* @nocollapse
* @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
*/
PlanComponent.ctorParameters;
/** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */
PlanComponent.propDecorators;
/** @type {?} */
PlanComponent.prototype.clickedRoom;
/** @type {?} */
PlanComponent.prototype.clickedCanvas;
/** @type {?} */
PlanComponent.prototype.data;
/** @type {?} */
PlanComponent.prototype.colors;
/** @type {?} */
PlanComponent.prototype.centroids;
/** @type {?} */
PlanComponent.prototype.toolbar;
/** @type {?} */
PlanComponent.prototype.selected;
/** @type {?} */
PlanComponent.prototype.selectedColor;
/** @type {?} */
PlanComponent.prototype.defaultColor;
/** @type {?} */
PlanComponent.prototype.rooms;
/** @type {?} */
PlanComponent.prototype.canvasWidth;
/** @type {?} */
PlanComponent.prototype.canvasHeight;
/** @type {?} */
PlanComponent.prototype.canvasCentroid;
/** @type {?} */
PlanComponent.prototype.baseScale;
/** @type {?} */
PlanComponent.prototype.baseOffsetX;
/** @type {?} */
PlanComponent.prototype.baseOffsetY;
/** @type {?} */
PlanComponent.prototype.transform;
/** @type {?} */
PlanComponent.prototype.movedX;
/** @type {?} */
PlanComponent.prototype.movedY;
/** @type {?} */
PlanComponent.prototype.scaled;
/** @type {?} */
PlanComponent.prototype.boundingBox;
/** @type {?} */
PlanComponent.prototype.panMode;
/** @type {?} */
PlanComponent.prototype.addNodeMode;
/** @type {?} */
PlanComponent.prototype.planContainer;
/** @type {?} */
PlanComponent.prototype.matIconRegistry;
/** @type {?} */
PlanComponent.prototype.domSanitizer;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZy1wbGFuLyIsInNvdXJjZXMiOlsibGliL3BsYW4uY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUEyQyxTQUFTLEVBQUUsVUFBVSxFQUFnQixNQUFNLGVBQWUsQ0FBQztBQUNySixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDekQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRXpELE9BQU8sS0FBSyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ25DLE9BQU8sS0FBSyxHQUFHLE1BQU0sWUFBWSxDQUFDOzs7Ozs7Ozs7OztBQW1HbEMsTUFBTTs7Ozs7SUF5Q0YsWUFDVSxpQkFDQTtRQURBLG9CQUFlLEdBQWYsZUFBZTtRQUNmLGlCQUFZLEdBQVosWUFBWTsyQkF6Q0UsSUFBSSxZQUFZLEVBQUU7NkJBQ2hCLElBQUksWUFBWSxFQUFFOzs2QkFTSixTQUFTOzRCQUNWLFNBQVM7eUJBVzVCLEdBQUc7MkJBQ0QsQ0FBQzsyQkFDRCxDQUFDO3lCQUdKLGFBQWEsSUFBSSxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsV0FBVyxXQUFXLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLFNBQVMsR0FBRztzQkFDekYsQ0FBQztzQkFDRCxDQUFDO3NCQUNGLENBQUM7dUJBSUMsS0FBSzsyQkFDRCxLQUFLO0tBTy9COzs7O0lBRUosZUFBZTtRQUNYLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQzs7S0FFeEI7Ozs7O0lBRUQsV0FBVyxDQUFDLE9BQXNCO1FBQzlCLEVBQUUsQ0FBQyxDQUFDLE9BQU8sWUFBUyxPQUFPLFNBQU0sWUFBWSxDQUFDLENBQUMsQ0FBQztZQUM1QyxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sU0FBTSxZQUFZLENB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Ozs7WUF0R1EsZUFBZTtZQUNmLFlBQVk7Ozs0QkF3R2hCLE1BQU07OEJBQ04sTUFBTTtxQkFFTixLQUFLO3VCQUNMLEtBQUs7MEJBQ0wsS0FBSzt3QkFDTCxLQUFLO3lCQUNMLEtBQUs7OEJBR0wsS0FBSzs2QkFDTCxLQUFLOzhCQTBCTCxTQUFTLFNBQUMsUUFBUSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBBZnRlclZpZXdJbml0LCBPbkNoYW5nZXMsIFNpbXBsZUNoYW5nZXMsIFZpZXdDaGlsZCwgRWxlbWVudFJlZiwgSG9zdExpc3RlbmVyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBNYXRJY29uUmVnaXN0cnkgfSBmcm9tIFwiQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvblwiO1xuaW1wb3J0IHsgRG9tU2FuaXRpemVyIH0gZnJvbSBcIkBhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXJcIjtcblxuaW1wb3J0ICogYXMgZDMgZnJvbSAnZDMtZGVjb21wb3NlJzsgIC8vIHRha2VzIFNWRyBvciBDU1MzIHRyYW5zZm9ybSBzdHJpbmdzIGFuZCBjb252ZXJ0cyB0aGVtIGludG8gdXNhYmxlIHZhbHVlc1xuaW1wb3J0ICogYXMgZDNwIGZyb20gJ2QzLXBvbHlnb24nOyAgIC8vIE9wZXJhdGlvbnMgb24gcG9seWdvbnNcblxuZXhwb3J0IGludGVyZmFjZSBSb29tIHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgcG9seWdvbnM6IHN0cmluZ1tdO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ25nLXBsYW4nLFxuICAgIHRlbXBsYXRlOiBgPCEtLSBUb29sYmFyIC0tPlxyXG48ZGl2IGNsYXNzPVwidG9vbGJhclwiICpuZ0lmPVwidG9vbGJhclwiPlxyXG4gICAgPGRpdiBjbGFzcz1cImljb24tZGl2XCIgKGNsaWNrKT1cInpvb21JbihudWxsKVwiIG1hdFRvb2x0aXA9XCJab29tIGluXCI+XHJcbiAgICAgICAgPG1hdC1pY29uPnpvb21faW48L21hdC1pY29uPlxyXG4gICAgPC9kaXY+XHJcbiAgICA8ZGl2IGNsYXNzPVwiaWNvbi1kaXZcIiAoY2xpY2spPVwiem9vbU91dChudWxsKVwiIG1hdFRvb2x0aXA9XCJab29tIG91dFwiPlxyXG4gICAgICAgIDxtYXQtaWNvbj56b29tX291dDwvbWF0LWljb24+XHJcbiAgICA8L2Rpdj5cclxuICAgIDxkaXYgY2xhc3M9XCJpY29uLWRpdlwiIChjbGljayk9XCJ6b29tRXh0ZW50cygpXCIgbWF0VG9vbHRpcD1cIlpvb20gZXh0ZW50c1wiPlxyXG4gICAgICAgIDxtYXQtaWNvbiBzdmdJY29uPVwiem9vbV9leHRlbnRzXCI+PC9tYXQtaWNvbj5cclxuICAgIDwvZGl2PlxyXG48L2Rpdj5cclxuXHJcbjxkaXYgY2xhc3M9XCJmb290ZXJcIj5cclxuICAgIDxwPlByZXNzIGFuZCBob2xkIFwiQWx0XCIgdG8gcGFuPC9wPlxyXG48L2Rpdj5cclxuXHJcbjxzdmcgY2FudmFzRXZlbnRzXHJcbiAgICBbc3R5bGUuY3Vyc29yXT1cInBhbk1vZGUgPyAnbW92ZScgOiAnZGVmYXVsdCdcIlxyXG4gICAgI2NhbnZhc1xyXG4gICAgY2xhc3M9Y2FudmFzXHJcbiAgICAoY2xpY2spPVwib25DYW52YXNDbGljaygkZXZlbnQpXCJcclxuICAgICh6b29tT3V0KT1cInpvb21PdXQoJGV2ZW50KVwiXHJcbiAgICAoem9vbUluKT1cInpvb21JbigkZXZlbnQpXCJcclxuICAgIChwYW5Nb2RlKT1cInBhbk1vZGUgPSAkZXZlbnRcIlxyXG4gICAgKG1vdmUpPVwibW92ZSgkZXZlbnQpXCJcclxuICAgIChtb3ZlRW5kKT1cIm1vdmVFbmQoJGV2ZW50KVwiXHJcbiAgICAod2luZG93OnJlc2l6ZSk9XCJvbldpbmRvd1Jlc2l6ZSgpXCJcclxuICAgIChhZGROb2RlTW9kZSk9XCJhZGROb2RlTW9kZSA9ICRldmVudFwiXHJcbiAgICBpZD1cImNhbnZhc1wiPlxyXG5cclxuICAgIDwhLS1EcmF3IHJvb21zLS0+XHJcbiAgICA8ZyAqbmdGb3I9XCJsZXQgcm9vbSBvZiByb29tc1wiXHJcbiAgICAgICAgW2F0dHIudHJhbnNmb3JtXT1cInRyYW5zZm9ybVwiXHJcbiAgICAgICAgW2lkXT1cInJvb20udXJpXCJcclxuICAgICAgICAoY2xpY2spPVwic2VsZWN0Um9vbSgkZXZlbnQsIHJvb20pXCJcclxuICAgICAgICBbYXR0ci5maWxsXT1cInJvb20uc2VsZWN0ZWQgPyBzZWxlY3RlZENvbG9yIDogcm9vbS5jb2xvclwiXHJcbiAgICAgICAgY2xhc3M9XCJyb29tXCI+XHJcblxyXG4gICAgICAgIDwhLS0gRHJhdyBwb2x5Z29ucyAtLT5cclxuICAgICAgICA8IS0tIDxwb2x5Z29uICpuZ0Zvcj1cImxldCBwb2x5Z29uIG9mIHJvb20ucG9seWdvbnNcIiBcclxuICAgICAgICAgICAgW2F0dHIucG9pbnRzXT1cInBvbHlnb25cIiBcclxuICAgICAgICAgICAgY2xhc3M9XCJwb2x5Z29uXCI+XHJcbiAgICAgICAgPC9wb2x5Z29uPiAtLT5cclxuXHJcbiAgICAgICAgPCEtLSBEcmF3IHBhdGhzIC0tPlxyXG4gICAgICAgIDxwYXRoXHJcbiAgICAgICAgICAgIFtjbGFzcy5zZWxlY3RlZC1zcGFjZV09XCJyb29tLnNlbGVjdGVkXCJcclxuICAgICAgICAgICAgW2F0dHIuZF09XCJyb29tLnBhdGhcIlxyXG4gICAgICAgICAgICBjbGFzcz1cInBvbHlnb25cIj5cclxuICAgICAgICA8L3BhdGg+IFxyXG5cclxuICAgICAgICA8IS0tIERyYXcgY2VudHJvaWRzIC0tPlxyXG4gICAgICAgIDxjaXJjbGUgXHJcbiAgICAgICAgICAgICpuZ0lmPVwiY2VudHJvaWRzXCIgXHJcbiAgICAgICAgICAgIFthdHRyLmN4XT1cInJvb20uY2VudHJvaWRbMF1cIiBcclxuICAgICAgICAgICAgZmlsbD1cImJsYWNrXCIgXHJcbiAgICAgICAgICAgIFthdHRyLmN5XT1cInJvb20uY2VudHJvaWRbMV1cIiBcclxuICAgICAgICAgICAgW2F0dHIucl09XCJzY2FsZWQqNTAwXCI+XHJcbiAgICAgICAgPC9jaXJjbGU+XHJcblxyXG4gICAgICAgIDwhLS0gQWRkIGxhYmVscyAtLT5cclxuICAgICAgICA8dGV4dCBcclxuICAgICAgICAgICAgW3N0eWxlLmZvbnQtc2l6ZS5lbV09XCInMTInXCJcclxuICAgICAgICAgICAgc3R5bGUgPSBcImZvbnQtZmFtaWx5OnJvYm90bzsgZmlsbDogYmxhY2s7XCJcclxuICAgICAgICAgICAgdGV4dC1hbmNob3I9XCJtaWRkbGVcIiBcclxuICAgICAgICAgICAgYWxpZ25tZW50LWJhc2VsaW5lPVwiY2VudHJhbFwiXHJcbiAgICAgICAgICAgIFthdHRyLnhdPVwicm9vbS5jZW50cm9pZFswXVwiXHJcbiAgICAgICAgICAgIFthdHRyLmR5XT1cInJvb20uZGVzY3JpcHRpb24gPyAtMTUwIDogMFwiXHJcbiAgICAgICAgICAgIFthdHRyLnldPVwicm9vbS5jZW50cm9pZFsxXVwiPlxyXG4gICAgICAgICAgICB7e3Jvb20ubmFtZX19XHJcbiAgICAgICAgPC90ZXh0PlxyXG5cclxuICAgICAgICA8IS0tIEFkZCBkZXNjcmlwdGlvbiAtLT5cclxuICAgICAgICA8dGV4dCBcclxuICAgICAgICAgICAgKm5nSWYgPSBcInJvb20uZGVzY3JpcHRpb25cIlxyXG4gICAgICAgICAgICBbc3R5bGUuZm9udC1zaXplLmVtXT1cIicxMCdcIlxyXG4gICAgICAgICAgICBzdHlsZSA9IFwiZm9udC1mYW1pbHk6cm9ib3RvOyBmaWxsOiBibGFjaztcIlxyXG4gICAgICAgICAgICB0ZXh0LWFuY2hvcj1cIm1pZGRsZVwiIFxyXG4gICAgICAgICAgICBhbGlnbm1lbnQtYmFzZWxpbmU9XCJjZW50cmFsXCJcclxuICAgICAgICAgICAgW2F0dHIueF09XCJyb29tLmNlbnRyb2lkWzBdXCJcclxuICAgICAgICAgICAgW2F0dHIueV09XCJyb29tLmNlbnRyb2lkWzFdXCJcclxuICAgICAgICAgICAgZHk9XCIxNTBcIj5cclxuICAgICAgICAgICAge3tyb29tLmRlc2NyaXB0aW9ufX1cclxuICAgICAgICA8L3RleHQ+XHJcbiAgICA8L2c+XHJcblxyXG48L3N2Zz5gLFxuICAgIHN0eWxlczogW2AuY2FudmFzey13ZWJraXQtdXNlci1zZWxlY3Q6bm9uZTstbW96LXVzZXItc2VsZWN0Om5vbmU7LW1zLXVzZXItc2VsZWN0Om5vbmU7dXNlci1zZWxlY3Q6bm9uZTt3aWR0aDoxMDAlO2hlaWdodDoxMDAlO3Bvc2l0aW9uOmZpeGVkO3RvcDowO2xlZnQ6MDtib3R0b206MDtyaWdodDowO3otaW5kZXg6LTF9LnBvbHlnb257c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjE7dmVjdG9yLWVmZmVjdDpub24tc2NhbGluZy1zdHJva2U7ZmlsbC1ydWxlOmV2ZW5vZGR9LnJvb206aG92ZXJ7b3BhY2l0eTouNTtjdXJzb3I6cG9pbnRlcn0uc2VsZWN0ZWQtc3BhY2V7c3Ryb2tlLXdpZHRoOjJ9LnRvb2xiYXJ7cG9zaXRpb246YWJzb2x1dGU7Y29sb3I6cmVkO3JpZ2h0OjIwcHg7d2lkdGg6MTAwJX0uaWNvbi1kaXY+Lm1hdC1pY29ue2Zsb2F0OnJpZ2h0Oy13ZWJraXQtdXNlci1zZWxlY3Q6bm9uZTstbW96LXVzZXItc2VsZWN0Om5vbmU7LW1zLXVzZXItc2VsZWN0Om5vbmU7dXNlci1zZWxlY3Q6bm9uZTtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjIwLDIyMCwyMjAsLjMpO2JvcmRlci13aWR0aDoxcHg7Ym9yZGVyLXJhZGl1czo1cHg7bWFyZ2luLWxlZnQ6NXB4O3BhZGRpbmc6NXB4O3otaW5kZXg6MX0ubWF0LWljb257Y29sb3I6cmdiYSgwLDAsMCwuNik7Zm9udC1zaXplOjMwcHg7aGVpZ2h0OjMwcHg7d2lkdGg6MzBweDt6LWluZGV4OjEwfS5tYXQtaWNvbjpob3ZlcntjdXJzb3I6cG9pbnRlcjtjb2xvcjpyZ2JhKDAsMCwwLDEpfS5mb290ZXJ7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDIyMCwyMjAsMjIwLC4zKTtwb3NpdGlvbjphYnNvbHV0ZTtmb250LWZhbWlseTpjb25zb2xhcztmb250LXNpemU6MTJweDtwYWRkaW5nOjAgMTBweDtib3JkZXItcmFkaXVzOjVweDtib3R0b206MTBweH1gXVxufSlcbmV4cG9ydCBjbGFzcyBQbGFuQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCB7XG5cbiAgICBAT3V0cHV0KCkgY2xpY2tlZFJvb20gPSBuZXcgRXZlbnRFbWl0dGVyKCk7ICAgICAgICAgICAgIC8vIENsaWNrZWQgcm9vbVxuICAgIEBPdXRwdXQoKSBjbGlja2VkQ2FudmFzID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gICAgQElucHV0KCkgcHJpdmF0ZSBkYXRhOyAgICAgICAgICAgICAgICAgICAgICAgLy9nZW9KU09OXG4gICAgQElucHV0KCkgcHJpdmF0ZSBjb2xvcnM7ICAgICAgICAgICAgICAgICAgICAgLy9jb2xvciBzY2hlbWFcbiAgICBASW5wdXQoKSBwdWJsaWMgY2VudHJvaWRzOiBib29sZWFuOyAgICAgICAgICAvL2NvbG9yIHNjaGVtYVxuICAgIEBJbnB1dCgpIHB1YmxpYyB0b29sYmFyOiBib29sZWFuOyAgICAgICAgICAgIC8vdG9vbGJhciB2aXNpYmxlP1xuICAgIEBJbnB1dCgpIHByaXZhdGUgc2VsZWN0ZWQ6IHN0cmluZ1tdOyAgICAgICAgIC8vU3BhY2VzIHRvIGJlIGhpZ2hsaWdodGVkXG5cbiAgICAvLyBTdHlsZXNcbiAgICBASW5wdXQoKSBwdWJsaWMgc2VsZWN0ZWRDb2xvcjogc3RyaW5nID0gJyNlYmVmZTQnO1xuICAgIEBJbnB1dCgpIHB1YmxpYyBkZWZhdWx0Q29sb3I6IHN0cmluZyA9ICcjZjJmbGVjJztcblxuICAgIHB1YmxpYyByb29tcztcblxuICAgIC8vIENhbnZhc1xuICAgIHByaXZhdGUgY2FudmFzV2lkdGg7XG4gICAgcHJpdmF0ZSBjYW52YXNIZWlnaHQ7XG4gICAgcHJpdmF0ZSBjYW52YXNDZW50cm9pZDtcblxuICAgIC8vIFNjYWxlIC8gb2Zmc2V0XG4gICAgLy8gVGhlc2UgZmFjdG9ycyBhcmUgY2FsY3VsYXRlZCBmcm9tIGdlb21ldHJ5IGV4dGVuZHNcbiAgICBwcml2YXRlIGJhc2VTY2FsZSA9IDAuOTtcbiAgICBwcml2YXRlIGJhc2VPZmZzZXRYID0gMDtcbiAgICBwcml2YXRlIGJhc2VPZmZzZXRZID0gMDtcblxuICAgIC8vIGdlb21ldHJ5XG4gICAgcHVibGljIHRyYW5zZm9ybSA9IGB0cmFuc2xhdGUoJHt0aGlzLmJhc2VPZmZzZXRYfSwke3RoaXMuYmFzZU9mZnNldFl9KSBzY2FsZSgke3RoaXMuYmFzZVNjYWxlfSwke3RoaXMuYmFzZVNjYWxlfSlgO1xuICAgIHByaXZhdGUgbW92ZWRYOiBudW1iZXIgPSAwOyAvLyBzdG9yZSBtb3ZlIHN0YXRlXG4gICAgcHJpdmF0ZSBtb3ZlZFk6IG51bWJlciA9IDA7IC8vIHN0b3JlIG1vdmUgc3RhdGVcbiAgICBwdWJsaWMgc2NhbGVkOiBudW1iZXIgPSAxIC8vIHN0b3JlIHNjYWxlIHN0YXRlXG4gICAgcHVibGljIGJvdW5kaW5nQm94OyAgICAgICAgIC8vIFN0b3JlcyBib3VuZGluZ0JveCBhcyBbeE1pbiwgeU1pbiwgeE1heCwgeU1heF1cblxuICAgIC8vIG1vZGVzXG4gICAgcHVibGljIHBhbk1vZGU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBwdWJsaWMgYWRkTm9kZU1vZGU6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIEBWaWV3Q2hpbGQoJ2NhbnZhcycpIHByaXZhdGUgcGxhbkNvbnRhaW5lcjogRWxlbWVudFJlZjtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgcHJpdmF0ZSBtYXRJY29uUmVnaXN0cnk6IE1hdEljb25SZWdpc3RyeSxcbiAgICAgIHByaXZhdGUgZG9tU2FuaXRpemVyOiBEb21TYW5pdGl6ZXJcbiAgICApIHt9XG5cbiAgICBuZ0FmdGVyVmlld0luaXQoKXtcbiAgICAgICAgdGhpcy5nZXRDYW52YXNTaXplKCk7XG4gICAgICAgIC8vIHRoaXMuYWRkU1ZHaWNvbnMoKTtcbiAgICB9XG5cbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgICAgIGlmIChjaGFuZ2VzLmRhdGEgJiYgY2hhbmdlcy5kYXRhLmN1cnJlbnRWYWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5kYXRhID0gY2hhbmdlcy5kYXRhLmN1cnJlbnRWYWx1ZTtcbiAgICAgICAgICAgIHRoaXMuZXh0cmFjdFJvb21zKCk7XG4gICAgICAgICAgICB0aGlzLmdldFNjYWxlT2Zmc2V0KCk7XG4gICAgICAgICAgICB0aGlzLnpvb21FeHRlbnRzKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNoYW5nZXMuY29sb3JzICYmIGNoYW5nZXMuY29sb3JzLmN1cnJlbnRWYWx1ZSl7XG4gICAgICAgICAgICB0aGlzLmRlZmluZUNvbG9ycygpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjaGFuZ2VzLnNlbGVjdGVkKXtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlU2VsZWN0aW9uKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBhZGRTVkdpY29ucygpe1xuICAgIC8vICAgdGhpcy5tYXRJY29uUmVnaXN0cnkuYWRkU3ZnSWNvbihcbiAgICAvLyAgICAgXCJ6b29tX2V4dGVudHNcIixcbiAgICAvLyAgICAgdGhpcy5kb21TYW5pdGl6ZXIuYnlwYXNzU2VjdXJpdHlUcnVzdFJlc291cmNlVXJsKFwiLi4vYXNzZXRzL3pvb21fZXh0ZW50cy5zdmdcIilcbiAgICAvLyAgICk7XG4gICAgLy8gfVxuXG4gICAgdXBkYXRlU2VsZWN0aW9uKCl7XG4gICAgICAgIGlmKCF0aGlzLnJvb21zKSByZXR1cm47XG4gICAgICAgIHRoaXMucm9vbXMgPSB0aGlzLnJvb21zLm1hcCh4ID0+IHtcbiAgICAgICAgICAgIGlmKHRoaXMuc2VsZWN0ZWQuaW5kZXhPZih4LnVyaSkgIT0gLTEpe1xuICAgICAgICAgICAgICAgIHguc2VsZWN0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfWVsc2V7XG4gICAgICAgICAgICAgICAgeC5zZWxlY3RlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHg7XG4gICAgICAgIH0pXG4gICAgfVxuXG4gICAgZGVmaW5lQ29sb3JzKCl7XG4gICAgICAgIHRoaXMucm9vbXMubWFwKHggPT4ge1xuICAgICAgICAgICAgdmFyIG1hdGNoID0gdGhpcy5jb2xvcnMuZmlsdGVyKHkgPT4geS51cmkgPT0geC51cmkpO1xuICAgICAgICAgICAgaWYobWF0Y2gubGVuZ3RoID4gMCl7XG4gICAgICAgICAgICAgICAgeC5jb2xvciA9IG1hdGNoWzBdLmNvbG9yO1xuICAgICAgICAgICAgICAgIHguZGVzY3JpcHRpb24gPSBtYXRjaFswXS52YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBnZXRDYW52YXNTaXplKCl7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLnBsYW5Db250YWluZXIubmF0aXZlRWxlbWVudDtcbiAgICAgICAgY29uc3Qgc2l6ZSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIHRoaXMuY2FudmFzV2lkdGggPSBzaXplLndpZHRoO1xuICAgICAgICB0aGlzLmNhbnZhc0hlaWdodCA9IHNpemUuaGVpZ2h0O1xuICAgICAgICB0aGlzLmNhbnZhc0NlbnRyb2lkID0gW3RoaXMuY2FudmFzV2lkdGgvMiwgdGhpcy5jYW52YXNIZWlnaHQvMl07ICAgICAgICBcbiAgICB9XG5cbiAgICBleHRyYWN0Um9vbXMoKXtcbiAgICAgICAgaWYoIXRoaXMuZGF0YS5mZWF0dXJlcykgcmV0dXJuIHRoaXMucm9vbXMgPSBudWxsO1xuXG4gICAgICAgIC8vIEZvciBib3VuZGluZyBib3ggW3hNaW4sIHlNaW4sIHhNYXgsIHlNYXhdXG4gICAgICAgIHZhciB4TWluO1xuICAgICAgICB2YXIgeU1pbjtcbiAgICAgICAgdmFyIHhNYXg7XG4gICAgICAgIHZhciB5TWF4O1xuICAgICAgICBcbiAgICAgICAgdGhpcy5yb29tcyA9IHRoaXMuZGF0YS5mZWF0dXJlcy5tYXAocm9vbSA9PiB7XG4gICAgICAgICAgICB2YXIgcG9seWdvbnMgPSBbXTtcbiAgICAgICAgICAgIHZhciByb29tUGF0aCA9ICcnO1xuICAgICAgICAgICAgdmFyIGNlbnRyb2lkO1xuICAgICAgICAgICAgaWYocm9vbS5nZW9tZXRyeSAmJiByb29tLmdlb21ldHJ5LnR5cGUgPT0gXCJQb2x5Z29uXCIpe1xuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIHZhciByb29tUG9seWdvbnMgPSBbXTsgIC8vIEFsbG93IG11bHRpIHBvbHlnb25zIGlmIGRvdWdobnV0IHJvb21cbiAgICAgICAgICAgICAgICByb29tLmdlb21ldHJ5LmNvb3JkaW5hdGVzLmZvckVhY2gocG9seWdvbiA9PiB7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHBvaW50cyA9ICcnO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcGF0aCA9ICcnO1xuICAgICAgICAgICAgICAgICAgICAvLyBSZWZsZWN0IHkgY29vcmRpbmF0ZXMgdG8gZml0IGJyb3dzZXIgY29vcmRpbmF0ZSBzeXN0ZW0gYW5kIGV4dHJhY3QgdG8gcG9seWdvblxuICAgICAgICAgICAgICAgICAgICBwb2x5Z29uLm1hcCgoY29vcmRpbmF0ZSxpbmRleCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHggPSBjb29yZGluYXRlWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHkgPSAtY29vcmRpbmF0ZVsxXTsgLy8gcmVmbGVjdCBzaW5jZSBTVkcgdXNlcyByZWZsZWN0ZWQgY29vcmRpbmF0ZSBzeXN0ZW1cblxuICAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRzKz0gYCR7eH0sJHt5fSBgO1xuICAgICAgICAgICAgICAgICAgICAgICAgcGF0aCs9IChpbmRleCA9PSAwKSA/IGBNJHt4fSwke3l9IGAgOiBgTCR7eH0sJHt5fSBgO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb29yZGluYXRlWzFdID0geTsgLy8gVXBkYXRlIHBvbHlnb24gd2l0aCBuZXcgeVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBHZXQgYm91bmRpbmcgYm94XG4gICAgICAgICAgICAgICAgICAgICAgICBpZigheE1pbiB8fCB4IDwgeE1pbikgeE1pbiA9IHg7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZigheE1heCB8fCB4ID4geE1heCkgeE1heCA9IHg7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZigheU1pbiB8fCB5IDwgeU1pbikgeU1pbiA9IHk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZigheU1heCB8fCB5ID4geU1heCkgeU1heCA9IHk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb29yZGluYXRlO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICBwb2ludHMgPSBwb2ludHMudHJpbSgpOyAgICAvLyByZW1vdmUgbGFzdCBzcGFjZVxuICAgICAgICAgICAgICAgICAgICBwYXRoID0gcGF0aC50cmltKCk7ICAgICAgICAgLy8gcmVtb3ZlIGxhc3Qgc3BhY2VcblxuICAgICAgICAgICAgICAgICAgICAvLyBHZXQgcG9seWdvbiBjZW50cm9pZCBmcm9tIGZpcnN0IHBvbHlnb25cbiAgICAgICAgICAgICAgICAgICAgaWYocm9vbVBvbHlnb25zLmxlbmd0aCA8IDEpe1xuICAgICAgICAgICAgICAgICAgICAgICAgY2VudHJvaWQgPSBkM3AucG9seWdvbkNlbnRyb2lkKHBvbHlnb24pO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgcm9vbVBvbHlnb25zLnB1c2gocG9pbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcm9vbVBhdGgrPXBhdGg7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcG9seWdvbnMucHVzaChyb29tUG9seWdvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIG5hbWUgPSByb29tLnByb3BlcnRpZXMubmFtZTtcbiAgICAgICAgICAgIHZhciB1cmkgPSByb29tLnByb3BlcnRpZXMudXJpO1xuICAgICAgICAgICAgdmFyIGNvbG9yID0gcm9vbS5wcm9wZXJ0aWVzLmNvbG9yID8gcm9vbS5wcm9wZXJ0aWVzLmNvbG9yIDogdGhpcy5kZWZhdWx0Q29sb3I7XG4gICAgICAgICAgICB2YXIgZGVzY3JpcHRpb24gPSByb29tLnByb3BlcnRpZXMuZGVzY3JpcHRpb24gPyByb29tLnByb3BlcnRpZXMuZGVzY3JpcHRpb24gOiAnJztcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgLy8gU3RvcmUgYm91bmRpbmcgYm94XG4gICAgICAgICAgICB0aGlzLmJvdW5kaW5nQm94ID0gW3hNaW4sIHlNaW4sIHhNYXgsIHlNYXhdO1xuXG4gICAgICAgICAgICByZXR1cm4ge25hbWU6IG5hbWUsIHVyaTogdXJpLCBkZXNjcmlwdGlvbjogZGVzY3JpcHRpb24sIGNvbG9yOiBjb2xvciwgcG9seWdvbnM6IHBvbHlnb25zLCBwYXRoOnJvb21QYXRoLCBjZW50cm9pZDogY2VudHJvaWR9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGdldFNjYWxlT2Zmc2V0KCkgeyAgIFxuICAgICAgICAvLyBDYWxjdWxhdGUgZGF0YSBzaXplXG4gICAgICAgIHZhciBiYiA9IHRoaXMuYm91bmRpbmdCb3g7XG4gICAgICAgIHZhciBkYXRhV2lkdGggPSBiYlsyXS1iYlswXTtcbiAgICAgICAgdmFyIGRhdGFIZWlnaHQgPSBiYlszXS1iYlsxXTtcblxuICAgICAgICAvLyBDYWxjdWxhdGUgc2NhbGUgZmFjdG9yc1xuICAgICAgICB2YXIgc2NhbGVXaWR0aCA9IHRoaXMuY2FudmFzV2lkdGgvZGF0YVdpZHRoO1xuICAgICAgICB2YXIgc2NhbGVIZWlnaHQgPSB0aGlzLmNhbnZhc0hlaWdodC9kYXRhSGVpZ2h0O1xuICAgICAgICB2YXIgc2NhbGUgPSBNYXRoLm1pbihzY2FsZUhlaWdodCxzY2FsZVdpZHRoKTtcblxuICAgICAgICB2YXIgc2NhbGVkRGF0YUNlbnRyb2lkID0gW3NjYWxlKihiYlswXStkYXRhV2lkdGgvMiksIHNjYWxlKihiYlsxXStkYXRhSGVpZ2h0LzIpXTtcblxuICAgICAgICAvLyBDYWxjdWxhdGUgb2Zmc2V0IGZhY3RvcnNcbiAgICAgICAgdmFyIG9mZnNldFggPSB0aGlzLmNhbnZhc0NlbnRyb2lkWzBdLXNjYWxlZERhdGFDZW50cm9pZFswXTtcbiAgICAgICAgdmFyIG9mZnNldFkgPSB0aGlzLmNhbnZhc0NlbnRyb2lkWzFdLXNjYWxlZERhdGFDZW50cm9pZFsxXTtcblxuICAgICAgICAvLyBTZXQgZ2xvYmFsIHZhcmlhYmxlc1xuICAgICAgICB0aGlzLmJhc2VPZmZzZXRYID0gb2Zmc2V0WDtcbiAgICAgICAgdGhpcy5iYXNlT2Zmc2V0WSA9IG9mZnNldFk7XG4gICAgICAgIHRoaXMuYmFzZVNjYWxlID0gc2NhbGU7XG4gICAgXG4gICAgICAgIHJldHVybiBbc2NhbGUsb2Zmc2V0WCxvZmZzZXRZXVxuICAgIH1cblxuICAgIG1vdmUoZGlzcGxhY2VtZW50KXtcbiAgICAgICAgaWYoZGlzcGxhY2VtZW50KXtcbiAgICAgICAgICAgIHRoaXMuem9vbUhhbmRsZXIodW5kZWZpbmVkLGRpc3BsYWNlbWVudCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBtb3ZlRW5kKGRpc3BsYWNlbWVudCl7XG4gICAgICAgIC8vIFVwZGF0ZSBtb3ZlZCBjb29yZGluYXRlc1xuICAgICAgICB0aGlzLm1vdmVkWCA9IHRoaXMubW92ZWRYK2Rpc3BsYWNlbWVudFswXTtcbiAgICAgICAgdGhpcy5tb3ZlZFkgPSB0aGlzLm1vdmVkWStkaXNwbGFjZW1lbnRbMV07XG4gICAgfVxuXG4gICAgb25XaW5kb3dSZXNpemUoKXtcbiAgICAgICAgdGhpcy5nZXRDYW52YXNTaXplKCk7XG4gICAgICAgIHRoaXMuZ2V0U2NhbGVPZmZzZXQoKTtcbiAgICAgICAgdGhpcy56b29tRXh0ZW50cygpO1xuICAgIH1cblxuICAgIHpvb21FeHRlbnRzKCl7XG4gICAgICAgIHRoaXMuc2NhbGVkID0gdGhpcy5iYXNlU2NhbGUqMC45NTtcbiAgICAgICAgdGhpcy5tb3ZlZFggPSAwO1xuICAgICAgICB0aGlzLm1vdmVkWSA9IDA7XG4gICAgICAgIHRoaXMuem9vbUhhbmRsZXIoKTtcbiAgICB9XG5cbiAgICB6b29tT3V0KGV2KXtcbiAgICAgICAgLy8gQ2FsY3VsYXRlIGN1cnJlbnQgc2NhbGVcbiAgICAgICAgdmFyIHNjYWxlRmFjdG9yID0gdGhpcy5iYXNlU2NhbGUvNTtcbiAgICAgICAgdGhpcy5zY2FsZWQgPSB0aGlzLnNjYWxlZC1zY2FsZUZhY3RvcjtcbiAgICAgICAgdGhpcy56b29tSGFuZGxlcihldik7XG4gICAgfVxuXG4gICAgem9vbUluKGV2KXtcbiAgICAgICAgdmFyIHNjYWxlRmFjdG9yID0gdGhpcy5iYXNlU2NhbGUvNTtcbiAgICAgICAgdGhpcy5zY2FsZWQgPSB0aGlzLnNjYWxlZCtzY2FsZUZhY3RvcjtcbiAgICAgICAgdGhpcy56b29tSGFuZGxlcihldik7XG4gICAgfVxuXG4gICAgem9vbUhhbmRsZXIoZXY/LGRpc3BsYWNlbWVudD8pe1xuXG4gICAgICAgIHZhciB0cm5zMSA9ICcnO1xuXG4gICAgICAgIGlmKGRpc3BsYWNlbWVudCl7XG4gICAgICAgICAgICB2YXIgZHggPSB0aGlzLmJhc2VPZmZzZXRYICsgdGhpcy5tb3ZlZFggKyBkaXNwbGFjZW1lbnRbMF07XG4gICAgICAgICAgICB2YXIgZHkgPSB0aGlzLmJhc2VPZmZzZXRZICsgdGhpcy5tb3ZlZFkgKyBkaXNwbGFjZW1lbnRbMV07XG4gICAgICAgIH1lbHNle1xuICAgICAgICAgICAgZHggPSB0aGlzLmJhc2VPZmZzZXRYICsgdGhpcy5tb3ZlZFg7XG4gICAgICAgICAgICBkeSA9IHRoaXMuYmFzZU9mZnNldFkgKyB0aGlzLm1vdmVkWTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRoaXMgc2hvdWxkIGJlIGFkanVzdGVkIHRvIGNlbnRlciBhdCBtb3VzZSBwb3NpdGlvbiB3aGlsZSB6b29taW5nXG5cbiAgICAgICAgLy8gaWYoZXYgJiYgZXYub2Zmc2V0WCl7XG4gICAgICAgIC8vICAgICAvLyBHZXQgbW91c2UgcG9zaXRpb24gcmVsYXRpdmUgdG8gY2FudmFzIGNlbnRlciBwb2ludCBhbmQgbW92ZVxuICAgICAgICAvLyAgICAgdmFyIG14ID0gZXYub2Zmc2V0WC10aGlzLmNhbnZhc0NlbnRyb2lkWzBdO1xuICAgICAgICAvLyAgICAgdmFyIG15ID0gZXYub2Zmc2V0WS10aGlzLmNhbnZhc0NlbnRyb2lkWzFdO1xuICAgICAgICAvLyAgICAgdmFyIGR4MiA9IG14O1xuICAgICAgICAvLyAgICAgdmFyIGR5MiA9IG15O1xuICAgICAgICAvLyAgICAgdHJuczEgPSBgdHJhbnNsYXRlKCR7ZHgyfSwke2R5Mn0pYDtcbiAgICAgICAgLy8gICAgIGNvbnNvbGUubG9nKHRybnMxKVxuICAgICAgICAvLyB9XG5cbiAgICAgICAgdmFyIG9sZFNjYWxlID0gZDMuZGVjb21wb3NlKHRoaXMudHJhbnNmb3JtKS5zY2FsZTtcbiAgICAgICAgdmFyIG9sZFRybnMgPSBkMy5kZWNvbXBvc2UodGhpcy50cmFuc2Zvcm0pLnRyYW5zbGF0ZTtcbiAgICAgICAgdmFyIHNjYWxlID0gYHNjYWxlKCR7dGhpcy5zY2FsZWR9LCR7dGhpcy5zY2FsZWR9KWA7XG5cbiAgICAgICAgdmFyIHRybnMgPSBgdHJhbnNsYXRlKCR7ZHh9LCR7ZHl9KWA7XG5cbiAgICAgICAgLy8gVXBkYXRlIHRyYW5zZm9ybSBhdHRyaWJ1dGVcbiAgICAgICAgdGhpcy50cmFuc2Zvcm0gPSB0cm5zK3RybnMxK3NjYWxlO1xuICAgICAgICAvLyB0aGlzLnRyYW5zZm9ybSA9IHRoaXMudHJhbnNmb3JtLnJlcGxhY2Uob2xkU2NhbGUsc2NhbGUpO1xuICAgIH1cblxuICAgIHNlbGVjdFJvb20oZXYsIHJvb20pe1xuICAgICAgICAvLyBHZXQgY29vcmRpbmF0ZXNcbiAgICAgICAgdmFyIHNjYWxlID0gdGhpcy5zY2FsZWQ7XG4gICAgICAgIHZhciBvZmZzZXRYID0gdGhpcy5iYXNlT2Zmc2V0WCt0aGlzLm1vdmVkWDtcbiAgICAgICAgdmFyIG9mZnNldFkgPSB0aGlzLmJhc2VPZmZzZXRZK3RoaXMubW92ZWRZO1xuICAgICAgICB2YXIgc2NyZWVuWCA9IGV2Lm9mZnNldFg7XG4gICAgICAgIHZhciBzY3JlZW5ZID0gZXYub2Zmc2V0WDtcblxuICAgICAgICB2YXIgeCA9IChzY3JlZW5YLW9mZnNldFgpL3NjYWxlO1xuICAgICAgICB2YXIgeSA9IChzY3JlZW5ZLW9mZnNldFkpL3NjYWxlO1xuICAgICAgICB2YXIgY29vcmRpbmF0ZXMgPSBbeCwteV07XG5cbiAgICAgICAgLy8gRW1pdCBldmVudFxuICAgICAgICB0aGlzLmNsaWNrZWRSb29tLmVtaXQoe3VyaTogcm9vbS51cmksIGNvb3JkaW5hdGVzOiBjb29yZGluYXRlc30pO1xuICAgIH1cblxuICAgIG9uQ2FudmFzQ2xpY2soZXYpe1xuICAgICAgICBpZihldi50YXJnZXQuaWQgIT0gJ2NhbnZhcycpIHJldHVybjtcbiAgICAgICAgdGhpcy5jbGlja2VkQ2FudmFzLmVtaXQoKTtcbiAgICB9XG5cbn0iXX0=