UNPKG

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
/** * @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=