@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
348 lines • 53.3 kB
JavaScript
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
import { Component, HostBinding, inject, Input } from '@angular/core';
import { Subject } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { DashboardService } from '../dashboard.service';
import { DashboardStackMode } from './dashboard-stack-mode.enum';
import * as i0 from "@angular/core";
import * as i1 from "../../../directives/drag/drag.directive";
import * as i2 from "@angular/common";
export class DashboardWidgetComponent {
/** Defines the column the widget is placed in */
set col(col) {
if (col !== null && col !== undefined) {
this.setColumn(coerceNumberProperty(col));
this.dashboardService.renderDashboard();
}
}
get col() {
return this.getColumn();
}
/** Defines the row the widget is placed in */
set row(row) {
if (row !== null && row !== undefined) {
this.setRow(coerceNumberProperty(row));
this.dashboardService.renderDashboard();
}
}
get row() {
return this.getRow();
}
/** Defines the number of columns this widget should occupy. */
get colSpan() {
return this.getColumnSpan();
}
set colSpan(colSpan) {
if (colSpan !== null && colSpan !== undefined) {
this.setColumnSpan(coerceNumberProperty(colSpan));
}
}
/** Defines the number of rows this widget should occupy. */
get rowSpan() {
return this.getRowSpan();
}
set rowSpan(rowSpan) {
if (rowSpan !== null && rowSpan !== undefined) {
this.setRowSpan(coerceNumberProperty(rowSpan));
}
}
/** Defines the minimum number of columns this widget should occupy. */
get minColSpan() {
return this._minColSpan;
}
set minColSpan(minColumns) {
this._minColSpan = coerceNumberProperty(minColumns);
}
/** Defines the minimum number of rows this widget should occupy. */
get minRowSpan() {
return this._minRowSpan;
}
set minRowSpan(minRows) {
this._minRowSpan = coerceNumberProperty(minRows);
}
/** Defines whether or not this widget will be automatically repositioned */
set autoPositioning(autoPositioning) {
this._autoPositioning = coerceBooleanProperty(autoPositioning);
}
get autoPositioning() {
return this._autoPositioning;
}
constructor() {
this.dashboardService = inject(DashboardService);
/** Defines whether or not this widget can be resized. */
this.resizable = false;
/** Defines a function that returns an aria label for the widget */
this.widgetAriaLabel = this.getDefaultAriaLabel;
this.x = 0;
this.y = 0;
this.width = 100;
this.height = 100;
this.padding = 0;
this.zIndex = null;
this.role = 'group';
this.isDragging = false;
this.isGrabbing = false;
this.isResizing = false;
this.isDraggable = false;
this._column = { regular: undefined, stacked: undefined };
this._row = { regular: undefined, stacked: undefined };
this._columnSpan = { regular: 1, stacked: 1 };
this._rowSpan = { regular: 1, stacked: 1 };
this._minColSpan = 1;
this._minRowSpan = 1;
this._autoPositioning = true;
this._onDestroy = new Subject();
// subscribe to option changes
this.dashboardService.options$.pipe(takeUntil(this._onDestroy))
.subscribe(() => this.update());
// every time the layout changes we want to update the aria label
this.dashboardService.layout$.pipe(takeUntil(this._onDestroy))
.subscribe(() => this.ariaLabel = this.getAriaLabel());
// allow widget movements to be animated
this.dashboardService.isDragging$.pipe(takeUntil(this._onDestroy), map(widget => widget === this))
.subscribe(isDragging => this.isDragging = isDragging);
// allow widget movements to be animated
this.dashboardService.isGrabbing$.pipe(takeUntil(this._onDestroy), map(widget => widget === this))
.subscribe(isGrabbing => this.isGrabbing = isGrabbing);
}
ngOnInit() {
this._columnSpan.regular = this.colSpan;
this._rowSpan.regular = this.rowSpan;
this._rowSpan.stacked = this.rowSpan;
this._row.regular = this.row;
this._row.stacked = this.row;
this._column.regular = this.col;
this._column.stacked = this.col;
if (!this.id) {
console.warn('Dashboard Widget is missing an ID.');
// set random id - keeps things working but prevents exporting of positions
this.id = Math.floor(Math.random() * 100000).toString();
}
}
ngAfterViewInit() {
// add the widget to the dashboard
this.dashboardService.addWidget(this);
// apply the current options
this.update();
}
ngOnChanges(changes) {
if (this.hasPosition() && (changes.colSpan || changes.rowSpan)) {
this.dashboardService.resizeWidget(this);
this.dashboardService.renderDashboard();
}
}
/**
* If component is removed, then unregister it from the service
*/
ngOnDestroy() {
this._onDestroy.next();
this._onDestroy.complete();
this.dashboardService.removeWidget(this);
}
/**
* Apply the current dashboard options
*/
update() {
// get the current options at the time
const { padding, columns } = this.dashboardService.options;
this.padding = padding;
this._columnSpan.stacked = columns;
}
/**
* Set the actual position and size values
*/
render() {
this.x = this.getColumn() * this.dashboardService.getColumnWidth();
this.y = this.getRow() * this.dashboardService.getRowHeight();
this.width = this.getColumnSpan() * this.dashboardService.getColumnWidth();
this.height = this.getRowSpan() * this.dashboardService.getRowHeight();
}
getColumn(mode = DashboardStackMode.Auto) {
switch (mode) {
case DashboardStackMode.Auto:
return this.getStackableValue(this._column);
case DashboardStackMode.Regular:
return this._column.regular;
case DashboardStackMode.Stacked:
return this._column.stacked;
}
}
getRow(mode = DashboardStackMode.Auto) {
switch (mode) {
case DashboardStackMode.Auto:
return this.getStackableValue(this._row);
case DashboardStackMode.Regular:
return this._row.regular;
case DashboardStackMode.Stacked:
return this._row.stacked;
}
}
setColumn(column, render = true) {
this.setStackableValue(this._column, column);
if (render) {
this.render();
}
}
setRow(row, render = true) {
this.setStackableValue(this._row, row);
if (render) {
this.render();
}
}
getColumnSpan() {
return this.getStackableValue(this._columnSpan);
}
getRowSpan() {
return this.getStackableValue(this._rowSpan);
}
setColumnSpan(columnSpan, render = true) {
if (columnSpan >= this.minColSpan) {
this.setStackableValue(this._columnSpan, columnSpan);
if (render) {
this.render();
}
}
}
setRowSpan(rowSpan, render = true) {
if (rowSpan >= this.minRowSpan) {
this.setStackableValue(this._rowSpan, rowSpan);
if (render) {
this.render();
}
}
}
bringToFront() {
this.zIndex = 1;
}
sendToBack() {
this.zIndex = null;
}
setBounds(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
dragstart(handle, event, direction) {
this.isResizing = true;
this.dashboardService.isGrabbing$.next(null);
this.dashboardService.onResizeStart({ widget: this, direction, event, handle });
}
drag(handle, event, direction) {
this.dashboardService.onResizeDrag({ widget: this, direction, event, handle });
}
dragend() {
this.isResizing = false;
this.dashboardService.onResizeEnd();
}
getAriaLabel() {
if (this.widgetAriaLabel && typeof this.widgetAriaLabel === 'string') {
return this.widgetAriaLabel;
}
else if (this.widgetAriaLabel && typeof this.widgetAriaLabel === 'function') {
return this.widgetAriaLabel(this);
}
return this.ariaLabel;
}
getDefaultAriaLabel(widget) {
let options = '';
if (widget.resizable && widget.isDraggable) {
options = 'It can be moved and resized.';
}
else if (widget.resizable) {
options = 'It can be resized.';
}
else if (widget.isDraggable) {
options = 'It can be moved.';
}
return `${widget.name} panel in row ${widget.getRow()}, column ${widget.getColumn()}, is ${widget.getColumnSpan()} columns wide and ${widget.getRowSpan()} rows high. ${options}`;
}
/**
* Allows automatic setting of stackable value
* @param property The current StackableValue object
* @param value The value to set in the appropriate field
*/
setStackableValue(property, value) {
if (this.dashboardService.stacked) {
property.stacked = value;
}
else {
property.regular = value;
}
}
/**
* Return the appropriate value from a stackable value
* @param property The Stackable value object
*/
getStackableValue(property) {
return this.dashboardService.stacked ? property.stacked : property.regular;
}
/** Determine if the layout has been performed yet */
hasPosition() {
return this.getColumn() !== undefined && this.getRow() !== undefined;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: DashboardWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.12", type: DashboardWidgetComponent, selector: "ux-dashboard-widget", inputs: { id: "id", name: "name", col: "col", row: "row", colSpan: "colSpan", rowSpan: "rowSpan", minColSpan: "minColSpan", minRowSpan: "minRowSpan", resizable: "resizable", autoPositioning: "autoPositioning", widgetAriaLabel: "widgetAriaLabel", role: "role" }, host: { properties: { "style.left.px": "this.x", "style.top.px": "this.y", "style.width.px": "this.width", "style.height.px": "this.height", "style.padding.px": "this.padding", "style.z-index": "this.zIndex", "attr.aria-label": "this.ariaLabel", "attr.role": "this.role", "class.dragging": "this.isDragging", "class.grabbing": "this.isGrabbing", "class.resizing": "this.isResizing" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"widget-content widget-col-span-{{ getColumnSpan() }} widget-row-span-{{ getRowSpan() }}\">\n <ng-content></ng-content>\n</div>\n\n<div uxDrag\n #handleTop\n class=\"resizer-handle handle-top\"\n (onDragStart)=\"dragstart(handleTop, $event, 0)\"\n (onDrag)=\"drag(handleTop, $event, 0)\"\n (onDragEnd)=\"dragend()\"\n [style.top.px]=\"padding\"\n [hidden]=\"!resizable\">\n</div>\n\n<div uxDrag\n #handleTopRight\n class=\"resizer-handle handle-top-right\"\n (onDragStart)=\"dragstart(handleTopRight, $event, 1)\"\n (onDrag)=\"drag(handleTopRight, $event, 1)\"\n (onDragEnd)=\"dragend()\"\n [style.top.px]=\"padding\"\n [style.right.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleRight\n class=\"resizer-handle handle-right\"\n (onDragStart)=\"dragstart(handleRight, $event, 2)\"\n (onDrag)=\"drag(handleRight, $event, 2)\"\n (onDragEnd)=\"dragend()\"\n [style.right.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleBottomRight\n class=\"resizer-handle handle-bottom-right\"\n (onDragStart)=\"dragstart(handleBottomRight, $event, 3)\"\n (onDrag)=\"drag(handleBottomRight, $event, 3)\"\n (onDragEnd)=\"dragend()\"\n [style.bottom.px]=\"padding\"\n [style.right.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleBottom\n class=\"resizer-handle handle-bottom\"\n (onDragStart)=\"dragstart(handleBottom, $event, 4)\"\n (onDrag)=\"drag(handleBottom, $event, 4)\"\n (onDragEnd)=\"dragend()\"\n [style.bottom.px]=\"padding\"\n [hidden]=\"!resizable\">\n</div>\n\n<div uxDrag\n #handleBottomLeft\n class=\"resizer-handle handle-bottom-left\"\n (onDragStart)=\"dragstart(handleBottomLeft, $event, 5)\"\n (onDrag)=\"drag(handleBottomLeft, $event, 5)\"\n (onDragEnd)=\"dragend()\"\n [style.bottom.px]=\"padding\"\n [style.left.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleLeft\n class=\"resizer-handle handle-left\"\n (onDragStart)=\"dragstart(handleLeft, $event, 6)\"\n (onDrag)=\"drag(handleLeft, $event, 6)\"\n (onDragEnd)=\"dragend()\"\n [style.left.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleTopLeft\n class=\"resizer-handle handle-top-left\"\n (onDragStart)=\"dragstart(handleTopLeft, $event, 7)\"\n (onDrag)=\"drag(handleTopLeft, $event, 7)\"\n (onDragEnd)=\"dragend()\"\n [style.top.px]=\"padding\"\n [style.left.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>", dependencies: [{ kind: "directive", type: i1.DragDirective, selector: "[uxDrag]", inputs: ["clone", "group", "model", "draggable"], outputs: ["onDragStart", "onDrag", "onDragScroll", "onDragEnd", "onDrop", "onDropEnter", "onDropLeave"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: DashboardWidgetComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-dashboard-widget', template: "<div class=\"widget-content widget-col-span-{{ getColumnSpan() }} widget-row-span-{{ getRowSpan() }}\">\n <ng-content></ng-content>\n</div>\n\n<div uxDrag\n #handleTop\n class=\"resizer-handle handle-top\"\n (onDragStart)=\"dragstart(handleTop, $event, 0)\"\n (onDrag)=\"drag(handleTop, $event, 0)\"\n (onDragEnd)=\"dragend()\"\n [style.top.px]=\"padding\"\n [hidden]=\"!resizable\">\n</div>\n\n<div uxDrag\n #handleTopRight\n class=\"resizer-handle handle-top-right\"\n (onDragStart)=\"dragstart(handleTopRight, $event, 1)\"\n (onDrag)=\"drag(handleTopRight, $event, 1)\"\n (onDragEnd)=\"dragend()\"\n [style.top.px]=\"padding\"\n [style.right.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleRight\n class=\"resizer-handle handle-right\"\n (onDragStart)=\"dragstart(handleRight, $event, 2)\"\n (onDrag)=\"drag(handleRight, $event, 2)\"\n (onDragEnd)=\"dragend()\"\n [style.right.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleBottomRight\n class=\"resizer-handle handle-bottom-right\"\n (onDragStart)=\"dragstart(handleBottomRight, $event, 3)\"\n (onDrag)=\"drag(handleBottomRight, $event, 3)\"\n (onDragEnd)=\"dragend()\"\n [style.bottom.px]=\"padding\"\n [style.right.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleBottom\n class=\"resizer-handle handle-bottom\"\n (onDragStart)=\"dragstart(handleBottom, $event, 4)\"\n (onDrag)=\"drag(handleBottom, $event, 4)\"\n (onDragEnd)=\"dragend()\"\n [style.bottom.px]=\"padding\"\n [hidden]=\"!resizable\">\n</div>\n\n<div uxDrag\n #handleBottomLeft\n class=\"resizer-handle handle-bottom-left\"\n (onDragStart)=\"dragstart(handleBottomLeft, $event, 5)\"\n (onDrag)=\"drag(handleBottomLeft, $event, 5)\"\n (onDragEnd)=\"dragend()\"\n [style.bottom.px]=\"padding\"\n [style.left.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleLeft\n class=\"resizer-handle handle-left\"\n (onDragStart)=\"dragstart(handleLeft, $event, 6)\"\n (onDrag)=\"drag(handleLeft, $event, 6)\"\n (onDragEnd)=\"dragend()\"\n [style.left.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>\n\n<div uxDrag\n #handleTopLeft\n class=\"resizer-handle handle-top-left\"\n (onDragStart)=\"dragstart(handleTopLeft, $event, 7)\"\n (onDrag)=\"drag(handleTopLeft, $event, 7)\"\n (onDragEnd)=\"dragend()\"\n [style.top.px]=\"padding\"\n [style.left.px]=\"padding\"\n [hidden]=\"!resizable || (dashboardService.stacked$ | async)\">\n</div>" }]
}], ctorParameters: () => [], propDecorators: { id: [{
type: Input
}], name: [{
type: Input
}], col: [{
type: Input
}], row: [{
type: Input
}], colSpan: [{
type: Input
}], rowSpan: [{
type: Input
}], minColSpan: [{
type: Input
}], minRowSpan: [{
type: Input
}], resizable: [{
type: Input
}], autoPositioning: [{
type: Input
}], widgetAriaLabel: [{
type: Input
}], x: [{
type: HostBinding,
args: ['style.left.px']
}], y: [{
type: HostBinding,
args: ['style.top.px']
}], width: [{
type: HostBinding,
args: ['style.width.px']
}], height: [{
type: HostBinding,
args: ['style.height.px']
}], padding: [{
type: HostBinding,
args: ['style.padding.px']
}], zIndex: [{
type: HostBinding,
args: ['style.z-index']
}], ariaLabel: [{
type: HostBinding,
args: ['attr.aria-label']
}], role: [{
type: HostBinding,
args: ['attr.role']
}, {
type: Input
}], isDragging: [{
type: HostBinding,
args: ['class.dragging']
}], isGrabbing: [{
type: HostBinding,
args: ['class.grabbing']
}], isResizing: [{
type: HostBinding,
args: ['class.resizing']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFzaGJvYXJkLXdpZGdldC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9kYXNoYm9hcmQvd2lkZ2V0L2Rhc2hib2FyZC13aWRnZXQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvZGFzaGJvYXJkL3dpZGdldC9kYXNoYm9hcmQtd2lkZ2V0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBZ0IscUJBQXFCLEVBQUUsb0JBQW9CLEVBQWUsTUFBTSx1QkFBdUIsQ0FBQztBQUMvRyxPQUFPLEVBQWlCLFNBQVMsRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBK0MsTUFBTSxlQUFlLENBQUM7QUFDbEksT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hELE9BQU8sRUFBbUIsZ0JBQWdCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQzs7OztBQU1qRSxNQUFNLE9BQU8sd0JBQXdCO0lBVWpDLGlEQUFpRDtJQUNqRCxJQUFhLEdBQUcsQ0FBQyxHQUFXO1FBQ3hCLElBQUksR0FBRyxLQUFLLElBQUksSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDcEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQzFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUM1QyxDQUFDO0lBQ0wsQ0FBQztJQUVELElBQUksR0FBRztRQUNILE9BQU8sSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFFRCw4Q0FBOEM7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VztRQUNmLE9BQU8sSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLEtBQUssU0FBUyxDQUFDO0lBQ3pFLENBQUM7K0dBeFZRLHdCQUF3QjttR0FBeEIsd0JBQXdCLHl0QkNYckMsNDBGQXNGTTs7NEZEM0VPLHdCQUF3QjtrQkFKcEMsU0FBUzsrQkFDSSxxQkFBcUI7d0RBUXRCLEVBQUU7c0JBQVYsS0FBSztnQkFHRyxJQUFJO3NCQUFaLEtBQUs7Z0JBR08sR0FBRztzQkFBZixLQUFLO2dCQVlPLEdBQUc7c0JBQWYsS0FBSztnQkFZTyxPQUFPO3NCQUFuQixLQUFLO2dCQVdPLE9BQU87c0JBQW5CLEtBQUs7Z0JBV08sVUFBVTtzQkFBdEIsS0FBSztnQkFTTyxVQUFVO3NCQUF0QixLQUFLO2dCQVNHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBR08sZUFBZTtzQkFBM0IsS0FBSztnQkFTRyxlQUFlO3NCQUF2QixLQUFLO2dCQUV3QixDQUFDO3NCQUE5QixXQUFXO3VCQUFDLGVBQWU7Z0JBQ0MsQ0FBQztzQkFBN0IsV0FBVzt1QkFBQyxjQUFjO2dCQUNJLEtBQUs7c0JBQW5DLFdBQVc7dUJBQUMsZ0JBQWdCO2dCQUNHLE1BQU07c0JBQXJDLFdBQVc7dUJBQUMsaUJBQWlCO2dCQUNHLE9BQU87c0JBQXZDLFdBQVc7dUJBQUMsa0JBQWtCO2dCQUNELE1BQU07c0JBQW5DLFdBQVc7dUJBQUMsZUFBZTtnQkFDSSxTQUFTO3NCQUF4QyxXQUFXO3VCQUFDLGlCQUFpQjtnQkFDSyxJQUFJO3NCQUF0QyxXQUFXO3VCQUFDLFdBQVc7O3NCQUFHLEtBQUs7Z0JBQ0QsVUFBVTtzQkFBeEMsV0FBVzt1QkFBQyxnQkFBZ0I7Z0JBQ0UsVUFBVTtzQkFBeEMsV0FBVzt1QkFBQyxnQkFBZ0I7Z0JBQ0UsVUFBVTtzQkFBeEMsV0FBVzt1QkFBQyxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCb29sZWFuSW5wdXQsIGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSwgY29lcmNlTnVtYmVyUHJvcGVydHksIE51bWJlcklucHV0IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvZXJjaW9uJztcbmltcG9ydCB7IEFmdGVyVmlld0luaXQsIENvbXBvbmVudCwgSG9zdEJpbmRpbmcsIGluamVjdCwgSW5wdXQsIE9uQ2hhbmdlcywgT25EZXN0cm95LCBPbkluaXQsIFNpbXBsZUNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgQWN0aW9uRGlyZWN0aW9uLCBEYXNoYm9hcmRTZXJ2aWNlIH0gZnJvbSAnLi4vZGFzaGJvYXJkLnNlcnZpY2UnO1xuaW1wb3J0IHsgRGFzaGJvYXJkU3RhY2tNb2RlIH0gZnJvbSAnLi9kYXNoYm9hcmQtc3RhY2stbW9kZS5lbnVtJztcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICd1eC1kYXNoYm9hcmQtd2lkZ2V0JyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vZGFzaGJvYXJkLXdpZGdldC5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgRGFzaGJvYXJkV2lkZ2V0Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XG5cbiAgICByZWFkb25seSBkYXNoYm9hcmRTZXJ2aWNlID0gaW5qZWN0KERhc2hib2FyZFNlcnZpY2UpO1xuXG4gICAgLyoqIFNldHMgdGhlIElEIG9mIHRoZSB3aWRnZXQuIEVhY2ggd2lkZ2V0IHNob3VsZCBiZSBnaXZlbiBhIHVuaXF1ZSBJRC4gKi9cbiAgICBASW5wdXQoKSBpZDogc3RyaW5nO1xuXG4gICAgLyoqIERlZmluZXMgYSBuYW1lIGZvciB0aGUgd2lkZ2V0IHVzZWQgZm9yIGFjY2Vzc2liaWxpdHkgKi9cbiAgICBASW5wdXQoKSBuYW1lOiBzdHJpbmc7XG5cbiAgICAvKiogRGVmaW5lcyB0aGUgY29sdW1uIHRoZSB3aWRnZXQgaXMgcGxhY2VkIGluICovXG4gICAgQElucHV0KCkgc2V0IGNvbChjb2w6IG51bWJlcikge1xuICAgICAgICBpZiAoY29sICE9PSBudWxsICYmIGNvbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLnNldENvbHVtbihjb2VyY2VOdW1iZXJQcm9wZXJ0eShjb2wpKTtcbiAgICAgICAgICAgIHRoaXMuZGFzaGJvYXJkU2VydmljZS5yZW5kZXJEYXNoYm9hcmQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldCBjb2woKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q29sdW1uKCk7XG4gICAgfVxuXG4gICAgLyoqIERlZmluZXMgdGhlIHJvdyB0aGUgd2lkZ2V0IGlzIHBsYWNlZCBpbiAqL1xuICAgIEBJbnB1dCgpIHNldCByb3cocm93OiBudW1iZXIpIHtcbiAgICAgICAgaWYgKHJvdyAhPT0gbnVsbCAmJiByb3cgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5zZXRSb3coY29lcmNlTnVtYmVyUHJvcGVydHkocm93KSk7XG4gICAgICAgICAgICB0aGlzLmRhc2hib2FyZFNlcnZpY2UucmVuZGVyRGFzaGJvYXJkKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBnZXQgcm93KCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFJvdygpO1xuICAgIH1cblxuICAgIC8qKiBEZWZpbmVzIHRoZSBudW1iZXIgb2YgY29sdW1ucyB0aGlzIHdpZGdldCBzaG91bGQgb2NjdXB5LiAqL1xuICAgIEBJbnB1dCgpIGdldCBjb2xTcGFuKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRDb2x1bW5TcGFuKCk7XG4gICAgfVxuXG4gICAgc2V0IGNvbFNwYW4oY29sU3BhbjogbnVtYmVyKSB7XG4gICAgICAgIGlmIChjb2xTcGFuICE9PSBudWxsICYmIGNvbFNwYW4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5zZXRDb2x1bW5TcGFuKGNvZXJjZU51bWJlclByb3BlcnR5KGNvbFNwYW4pKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBEZWZpbmVzIHRoZSBudW1iZXIgb2Ygcm93cyB0aGlzIHdpZGdldCBzaG91bGQgb2NjdXB5LiAqL1xuICAgIEBJbnB1dCgpIGdldCByb3dTcGFuKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRSb3dTcGFuKCk7XG4gICAgfVxuXG4gICAgc2V0IHJvd1NwYW4ocm93U3BhbjogbnVtYmVyKSB7XG4gICAgICAgIGlmIChyb3dTcGFuICE9PSBudWxsICYmIHJvd1NwYW4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5zZXRSb3dTcGFuKGNvZXJjZU51bWJlclByb3BlcnR5KHJvd1NwYW4pKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBEZWZpbmVzIHRoZSBtaW5pbXVtIG51bWJlciBvZiBjb2x1bW5zIHRoaXMgd2lkZ2V0IHNob3VsZCBvY2N1cHkuICovXG4gICAgQElucHV0KCkgZ2V0IG1pbkNvbFNwYW4oKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX21pbkNvbFNwYW47XG4gICAgfVxuXG4gICAgc2V0IG1pbkNvbFNwYW4obWluQ29sdW1uczogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuX21pbkNvbFNwYW4gPSBjb2VyY2VOdW1iZXJQcm9wZXJ0eShtaW5Db2x1bW5zKTtcbiAgICB9XG5cbiAgICAvKiogRGVmaW5lcyB0aGUgbWluaW11bSBudW1iZXIgb2Ygcm93cyB0aGlzIHdpZGdldCBzaG91bGQgb2NjdXB5LiAqL1xuICAgIEBJbnB1dCgpIGdldCBtaW5Sb3dTcGFuKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLl9taW5Sb3dTcGFuO1xuICAgIH1cblxuICAgIHNldCBtaW5Sb3dTcGFuKG1pblJvd3M6IG51bWJlcikge1xuICAgICAgICB0aGlzLl9taW5Sb3dTcGFuID0gY29lcmNlTnVtYmVyUHJvcGVydHkobWluUm93cyk7XG4gICAgfVxuXG4gICAgLyoqIERlZmluZXMgd2hldGhlciBvciBub3QgdGhpcyB3aWRnZXQgY2FuIGJlIHJlc2l6ZWQuICovXG4gICAgQElucHV0KCkgcmVzaXphYmxlOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogRGVmaW5lcyB3aGV0aGVyIG9yIG5vdCB0aGlzIHdpZGdldCB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgcmVwb3NpdGlvbmVkICovXG4gICAgQElucHV0KCkgc2V0IGF1dG9Qb3NpdGlvbmluZyhhdXRvUG9zaXRpb25pbmc6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5fYXV0b1Bvc2l0aW9uaW5nID0gY29lcmNlQm9vbGVhblByb3BlcnR5KGF1dG9Qb3NpdGlvbmluZyk7XG4gICAgfVxuXG4gICAgZ2V0IGF1dG9Qb3NpdGlvbmluZygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2F1dG9Qb3NpdGlvbmluZztcbiAgICB9XG5cbiAgICAvKiogRGVmaW5lcyBhIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBhcmlhIGxhYmVsIGZvciB0aGUgd2lkZ2V0ICovXG4gICAgQElucHV0KCkgd2lkZ2V0QXJpYUxhYmVsOiAod2lkZ2V0czogRGFzaGJvYXJkV2lkZ2V0Q29tcG9uZW50KSA9PiBzdHJpbmcgfCBzdHJpbmcgPSB0aGlzLmdldERlZmF1bHRBcmlhTGFiZWw7XG5cbiAgICBASG9zdEJpbmRpbmcoJ3N0eWxlLmxlZnQucHgnKSB4OiBudW1iZXIgPSAwO1xuICAgIEBIb3N0QmluZGluZygnc3R5bGUudG9wLnB4JykgeTogbnVtYmVyID0gMDtcbiAgICBASG9zdEJpbmRpbmcoJ3N0eWxlLndpZHRoLnB4Jykgd2lkdGg6IG51bWJlciA9IDEwMDtcbiAgICBASG9zdEJpbmRpbmcoJ3N0eWxlLmhlaWdodC5weCcpIGhlaWdodDogbnVtYmVyID0gMTAwO1xuICAgIEBIb3N0QmluZGluZygnc3R5bGUucGFkZGluZy5weCcpIHBhZGRpbmc6IG51bWJlciA9IDA7XG4gICAgQEhvc3RCaW5kaW5nKCdzdHlsZS56LWluZGV4JykgekluZGV4OiBudW1iZXIgPSBudWxsO1xuICAgIEBIb3N0QmluZGluZygnYXR0ci5hcmlhLWxhYmVsJykgYXJpYUxhYmVsOiBzdHJpbmc7XG4gICAgQEhvc3RCaW5kaW5nKCdhdHRyLnJvbGUnKSBASW5wdXQoKSByb2xlOiBzdHJpbmcgPSAnZ3JvdXAnO1xuICAgIEBIb3N0QmluZGluZygnY2xhc3MuZHJhZ2dpbmcnKSBpc0RyYWdnaW5nOiBib29sZWFuID0gZmFsc2U7XG4gICAgQEhvc3RCaW5kaW5nKCdjbGFzcy5ncmFiYmluZycpIGlzR3JhYmJpbmc6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLnJlc2l6aW5nJykgaXNSZXNpemluZzogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgaXNEcmFnZ2FibGU6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2NvbHVtbjogU3RhY2thYmxlVmFsdWUgPSB7IHJlZ3VsYXI6IHVuZGVmaW5lZCwgc3RhY2tlZDogdW5kZWZpbmVkIH07XG4gICAgcHJpdmF0ZSByZWFkb25seSBfcm93OiBTdGFja2FibGVWYWx1ZSA9IHsgcmVndWxhcjogdW5kZWZpbmVkLCBzdGFja2VkOiB1bmRlZmluZWQgfTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9jb2x1bW5TcGFuOiBTdGFja2FibGVWYWx1ZSA9IHsgcmVndWxhcjogMSwgc3RhY2tlZDogMSB9O1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3Jvd1NwYW46IFN0YWNrYWJsZVZhbHVlID0geyByZWd1bGFyOiAxLCBzdGFja2VkOiAxIH07XG4gICAgcHJpdmF0ZSBfbWluQ29sU3BhbjogbnVtYmVyID0gMTtcbiAgICBwcml2YXRlIF9taW5Sb3dTcGFuOiBudW1iZXIgPSAxO1xuICAgIHByaXZhdGUgX2F1dG9Qb3NpdGlvbmluZzogYm9vbGVhbiA9IHRydWU7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfb25EZXN0cm95ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICAvLyBzdWJzY3JpYmUgdG8gb3B0aW9uIGNoYW5nZXNcbiAgICAgICAgdGhpcy5kYXNoYm9hcmRTZXJ2aWNlLm9wdGlvbnMkLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMudXBkYXRlKCkpO1xuXG4gICAgICAgIC8vIGV2ZXJ5IHRpbWUgdGhlIGxheW91dCBjaGFuZ2VzIHdlIHdhbnQgdG8gdXBkYXRlIHRoZSBhcmlhIGxhYmVsXG4gICAgICAgIHRoaXMuZGFzaGJvYXJkU2VydmljZS5sYXlvdXQkLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuYXJpYUxhYmVsID0gdGhpcy5nZXRBcmlhTGFiZWwoKSk7XG5cbiAgICAgICAgLy8gYWxsb3cgd2lkZ2V0IG1vdmVtZW50cyB0byBiZSBhbmltYXRlZFxuICAgICAgICB0aGlzLmRhc2hib2FyZFNlcnZpY2UuaXNEcmFnZ2luZyQucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSwgbWFwKHdpZGdldCA9PiB3aWRnZXQgPT09IHRoaXMpKVxuICAgICAgICAgICAgLnN1YnNjcmliZShpc0RyYWdnaW5nID0+IHRoaXMuaXNEcmFnZ2luZyA9IGlzRHJhZ2dpbmcpO1xuXG4gICAgICAgIC8vIGFsbG93IHdpZGdldCBtb3ZlbWVudHMgdG8gYmUgYW5pbWF0ZWRcbiAgICAgICAgdGhpcy5kYXNoYm9hcmRTZXJ2aWNlLmlzR3JhYmJpbmckLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSksIG1hcCh3aWRnZXQgPT4gd2lkZ2V0ID09PSB0aGlzKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoaXNHcmFiYmluZyA9PiB0aGlzLmlzR3JhYmJpbmcgPSBpc0dyYWJiaW5nKTtcbiAgICB9XG5cbiAgICBuZ09uSW5pdCgpOiB2b2lkIHtcblxuICAgICAgICB0aGlzLl9jb2x1bW5TcGFuLnJlZ3VsYXIgPSB0aGlzLmNvbFNwYW47XG4gICAgICAgIHRoaXMuX3Jvd1NwYW4ucmVndWxhciA9IHRoaXMucm93U3BhbjtcbiAgICAgICAgdGhpcy5fcm93U3Bhbi5zdGFja2VkID0gdGhpcy5yb3dTcGFuO1xuICAgICAgICB0aGlzLl9yb3cucmVndWxhciA9IHRoaXMucm93O1xuICAgICAgICB0aGlzLl9yb3cuc3RhY2tlZCA9IHRoaXMucm93O1xuICAgICAgICB0aGlzLl9jb2x1bW4ucmVndWxhciA9IHRoaXMuY29sO1xuICAgICAgICB0aGlzLl9jb2x1bW4uc3RhY2tlZCA9IHRoaXMuY29sO1xuXG4gICAgICAgIGlmICghdGhpcy5pZCkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdEYXNoYm9hcmQgV2lkZ2V0IGlzIG1pc3NpbmcgYW4gSUQuJyk7XG5cbiAgICAgICAgICAgIC8vIHNldCByYW5kb20gaWQgLSBrZWVwcyB0aGluZ3Mgd29ya2luZyBidXQgcHJldmVudHMgZXhwb3J0aW5nIG9mIHBvc2l0aW9uc1xuICAgICAgICAgICAgdGhpcy5pZCA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMDAwMCkudG9TdHJpbmcoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICAgICAgLy8gYWRkIHRoZSB3aWRnZXQgdG8gdGhlIGRhc2hib2FyZFxuICAgICAgICB0aGlzLmRhc2hib2FyZFNlcnZpY2UuYWRkV2lkZ2V0KHRoaXMpO1xuXG4gICAgICAgIC8vIGFwcGx5IHRoZSBjdXJyZW50IG9wdGlvbnNcbiAgICAgICAgdGhpcy51cGRhdGUoKTtcbiAgICB9XG5cbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmhhc1Bvc2l0aW9uKCkgJiYgKGNoYW5nZXMuY29sU3BhbiB8fCBjaGFuZ2VzLnJvd1NwYW4pKSB7XG4gICAgICAgICAgICB0aGlzLmRhc2hib2FyZFNlcnZpY2UucmVzaXplV2lkZ2V0KHRoaXMpO1xuICAgICAgICAgICAgdGhpcy5kYXNoYm9hcmRTZXJ2aWNlLnJlbmRlckRhc2hib2FyZCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSWYgY29tcG9uZW50IGlzIHJlbW92ZWQsIHRoZW4gdW5yZWdpc3RlciBpdCBmcm9tIHRoZSBzZXJ2aWNlXG4gICAgICovXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX29uRGVzdHJveS5uZXh0KCk7XG4gICAgICAgIHRoaXMuX29uRGVzdHJveS5jb21wbGV0ZSgpO1xuICAgICAgICB0aGlzLmRhc2hib2FyZFNlcnZpY2UucmVtb3ZlV2lkZ2V0KHRoaXMpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFwcGx5IHRoZSBjdXJyZW50IGRhc2hib2FyZCBvcHRpb25zXG4gICAgICovXG4gICAgdXBkYXRlKCk6IHZvaWQge1xuXG4gICAgICAgIC8vIGdldCB0aGUgY3VycmVudCBvcHRpb25zIGF0IHRoZSB0aW1lXG4gICAgICAgIGNvbnN0IHsgcGFkZGluZywgY29sdW1ucyB9ID0gdGhpcy5kYXNoYm9hcmRTZXJ2aWNlLm9wdGlvbnM7XG5cbiAgICAgICAgdGhpcy5wYWRkaW5nID0gcGFkZGluZztcbiAgICAgICAgdGhpcy5fY29sdW1uU3Bhbi5zdGFja2VkID0gY29sdW1ucztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIGFjdHVhbCBwb3NpdGlvbiBhbmQgc2l6ZSB2YWx1ZXNcbiAgICAgKi9cbiAgICByZW5kZXIoKTogdm9pZCB7XG4gICAgICAgIHRoaXMueCA9IHRoaXMuZ2V0Q29sdW1uKCkgKiB0aGlzLmRhc2hib2FyZFNlcnZpY2UuZ2V0Q29sdW1uV2lkdGgoKTtcbiAgICAgICAgdGhpcy55ID0gdGhpcy5nZXRSb3coKSAqIHRoaXMuZGFzaGJvYXJkU2VydmljZS5nZXRSb3dIZWlnaHQoKTtcbiAgICAgICAgdGhpcy53aWR0aCA9IHRoaXMuZ2V0Q29sdW1uU3BhbigpICogdGhpcy5kYXNoYm9hcmRTZXJ2aWNlLmdldENvbHVtbldpZHRoKCk7XG4gICAgICAgIHRoaXMuaGVpZ2h0ID0gdGhpcy5nZXRSb3dTcGFuKCkgKiB0aGlzLmRhc2hib2FyZFNlcnZpY2UuZ2V0Um93SGVpZ2h0KCk7XG4gICAgfVxuXG4gICAgZ2V0Q29sdW1uKG1vZGU6IERhc2hib2FyZFN0YWNrTW9kZSA9IERhc2hib2FyZFN0YWNrTW9kZS5BdXRvKTogbnVtYmVyIHtcbiAgICAgICAgc3dpdGNoIChtb2RlKSB7XG4gICAgICAgICAgICBjYXNlIERhc2hib2FyZFN0YWNrTW9kZS5BdXRvOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmdldFN0YWNrYWJsZVZhbHVlKHRoaXMuX2NvbHVtbik7XG5cbiAgICAgICAgICAgIGNhc2UgRGFzaGJvYXJkU3RhY2tNb2RlLlJlZ3VsYXI6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NvbHVtbi5yZWd1bGFyO1xuXG4gICAgICAgICAgICBjYXNlIERhc2hib2FyZFN0YWNrTW9kZS5TdGFja2VkOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9jb2x1bW4uc3RhY2tlZDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldFJvdyhtb2RlOiBEYXNoYm9hcmRTdGFja01vZGUgPSBEYXNoYm9hcmRTdGFja01vZGUuQXV0byk6IG51bWJlciB7XG4gICAgICAgIHN3aXRjaCAobW9kZSkge1xuICAgICAgICAgICAgY2FzZSBEYXNoYm9hcmRTdGFja01vZGUuQXV0bzpcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRTdGFja2FibGVWYWx1ZSh0aGlzLl9yb3cpO1xuXG4gICAgICAgICAgICBjYXNlIERhc2hib2FyZFN0YWNrTW9kZS5SZWd1bGFyOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9yb3cucmVndWxhcjtcblxuICAgICAgICAgICAgY2FzZSBEYXNoYm9hcmRTdGFja01vZGUuU3RhY2tlZDpcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcm93LnN0YWNrZWQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzZXRDb2x1bW4oY29sdW1uOiBudW1iZXIsIHJlbmRlcjogYm9vbGVhbiA9IHRydWUpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5zZXRTdGFja2FibGVWYWx1ZSh0aGlzLl9jb2x1bW4sIGNvbHVtbik7XG5cbiAgICAgICAgaWYgKHJlbmRlcikge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHNldFJvdyhyb3c6IG51bWJlciwgcmVuZGVyOiBib29sZWFuID0gdHJ1ZSk6IHZvaWQge1xuICAgICAgICB0aGlzLnNldFN0YWNrYWJsZVZhbHVlKHRoaXMuX3Jvdywgcm93KTtcblxuICAgICAgICBpZiAocmVuZGVyKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2V0Q29sdW1uU3BhbigpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRTdGFja2FibGVWYWx1ZSh0aGlzLl9jb2x1bW5TcGFuKTtcbiAgICB9XG5cbiAgICBnZXRSb3dTcGFuKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFN0YWNrYWJsZVZhbHVlKHRoaXMuX3Jvd1NwYW4pO1xuICAgIH1cblxuICAgIHNldENvbHVtblNwYW4oY29sdW1uU3BhbjogbnVtYmVyLCByZW5kZXI6IGJvb2xlYW4gPSB0cnVlKTogdm9pZCB7XG4gICAgICAgIGlmIChjb2x1bW5TcGFuID49IHRoaXMubWluQ29sU3Bhbikge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGFja2FibGVWYWx1ZSh0aGlzLl9jb2x1bW5TcGFuLCBjb2x1bW5TcGFuKTtcblxuICAgICAgICAgICAgaWYgKHJlbmRlcikge1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzZXRSb3dTcGFuKHJvd1NwYW46IG51bWJlciwgcmVuZGVyOiBib29sZWFuID0gdHJ1ZSk6IHZvaWQge1xuICAgICAgICBpZiAocm93U3BhbiA+PSB0aGlzLm1pblJvd1NwYW4pIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhY2thYmxlVmFsdWUodGhpcy5fcm93U3Bhbiwgcm93U3Bhbik7XG5cbiAgICAgICAgICAgIGlmIChyZW5kZXIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgYnJpbmdUb0Zyb250KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnpJbmRleCA9IDE7XG4gICAgfVxuXG4gICAgc2VuZFRvQmFjaygpOiB2b2lkIHtcbiAgICAgICAgdGhpcy56SW5kZXggPSBudWxsO1xuICAgIH1cblxuICAgIHNldEJvdW5kcyh4OiBudW1iZXIsIHk6IG51bWJlciwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy54ID0geDtcbiAgICAgICAgdGhpcy55ID0geTtcbiAgICAgICAgdGhpcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICB0aGlzLmhlaWdodCA9IGhlaWdodDtcbiAgICB9XG5cbiAgICBkcmFnc3RhcnQoaGFuZGxlOiBIVE1MRWxlbWVudCwgZXZlbnQ6IE1vdXNlRXZlbnQsIGRpcmVjdGlvbjogQWN0aW9uRGlyZWN0aW9uKTogdm9pZCB7XG4gICAgICAgIHRoaXMuaXNSZXNpemluZyA9IHRydWU7XG4gICAgICAgIHRoaXMuZGFzaGJvYXJkU2VydmljZS5pc0dyYWJiaW5nJC5uZXh0KG51bGwpO1xuICAgICAgICB0aGlzLmRhc2hib2FyZFNlcnZpY2Uub25SZXNpemVTdGFydCh7IHdpZGdldDogdGhpcywgZGlyZWN0aW9uLCBldmVudCwgaGFuZGxlIH0pO1xuICAgIH1cblxuICAgIGRyYWcoaGFuZGxlOiBIVE1MRWxlbWVudCwgZXZlbnQ6IE1vdXNlRXZlbnQsIGRpcmVjdGlvbjogQWN0aW9uRGlyZWN0aW9uKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGFzaGJvYXJkU2VydmljZS5vblJlc2l6ZURyYWcoeyB3aWRnZXQ6IHRoaXMsIGRpcmVjdGlvbiwgZXZlbnQsIGhhbmRsZSB9KTtcbiAgICB9XG5cbiAgICBkcmFnZW5kKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmlzUmVzaXppbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5kYXNoYm9hcmRTZXJ2aWNlLm9uUmVzaXplRW5kKCk7XG4gICAgfVxuXG4gICAgZ2V0QXJpYUxhYmVsKCk6IHN0cmluZyB7XG4gICAgICAgIGlmICh0aGlzLndpZGdldEFyaWFMYWJlbCAmJiB0eXBlb2YgdGhpcy53aWRnZXRBcmlhTGFiZWwgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy53aWRnZXRBcmlhTGFiZWw7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy53aWRnZXRBcmlhTGFiZWwgJiYgdHlwZW9mIHRoaXMud2lkZ2V0QXJpYUxhYmVsID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy53aWRnZXRBcmlhTGFiZWwodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5hcmlhTGFiZWw7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXREZWZhdWx0QXJpYUxhYmVsKHdpZGdldDogRGFzaGJvYXJkV2lkZ2V0Q29tcG9uZW50KTogc3RyaW5nIHtcblxuICAgICAgICBsZXQgb3B0aW9uczogc3RyaW5nID0gJyc7XG5cbiAgICAgICAgaWYgKHdpZGdldC5yZXNpemFibGUgJiYgd2lkZ2V0LmlzRHJhZ2dhYmxlKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gJ0l0IGNhbiBiZSBtb3ZlZCBhbmQgcmVzaXplZC4nO1xuICAgICAgICB9IGVsc2UgaWYgKHdpZGdldC5yZXNpemFibGUpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAnSXQgY2FuIGJlIHJlc2l6ZWQuJztcbiAgICAgICAgfSBlbHNlIGlmICh3aWRnZXQuaXNEcmFnZ2FibGUpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAnSXQgY2FuIGJlIG1vdmVkLic7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYCR7d2lkZ2V0Lm5hbWV9IHBhbmVsIGluIHJvdyAke3dpZGdldC5nZXRSb3coKX0sIGNvbHVtbiAke3dpZGdldC5nZXRDb2x1bW4oKX0sIGlzICR7d2lkZ2V0LmdldENvbHVtblNwYW4oKX0gY29sdW1ucyB3aWRlIGFuZCAke3dpZGdldC5nZXRSb3dTcGFuKCl9IHJvd3MgaGlnaC4gJHtvcHRpb25zfWA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWxsb3dzIGF1dG9tYXRpYyBzZXR0aW5nIG9mIHN0YWNrYWJsZSB2YWx1ZVxuICAgICAqIEBwYXJhbSBwcm9wZXJ0eSBUaGUgY3VycmVudCBTdGFja2FibGVWYWx1ZSBvYmplY3RcbiAgICAgKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIHNldCBpbiB0aGUgYXBwcm9wcmlhdGUgZmllbGRcbiAgICAgKi9cbiAgICBwcml2YXRlIHNldFN0YWNrYWJsZVZhbHVlKHByb3BlcnR5OiBTdGFja2FibGVWYWx1ZSwgdmFsdWU6IG51bWJlcik6IHZvaWQge1xuXG4gICAgICAgIGlmICh0aGlzLmRhc2hib2FyZFNlcnZpY2Uuc3RhY2tlZCkge1xuICAgICAgICAgICAgcHJvcGVydHkuc3RhY2tlZCA9IHZhbHVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcHJvcGVydHkucmVndWxhciA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJuIHRoZSBhcHByb3ByaWF0ZSB2YWx1ZSBmcm9tIGEgc3RhY2thYmxlIHZhbHVlXG4gICAgICogQHBhcmFtIHByb3BlcnR5IFRoZSBTdGFja2FibGUgdmFsdWUgb2JqZWN0XG4gICAgICovXG4gICAgcHJpdmF0ZSBnZXRTdGFja2FibGVWYWx1ZShwcm9wZXJ0eTogU3RhY2thYmxlVmFsdWUpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXNoYm9hcmRTZXJ2aWNlLnN0YWNrZWQgPyBwcm9wZXJ0eS5zdGFja2VkIDogcHJvcGVydHkucmVndWxhcjtcbiAgICB9XG5cbiAgICAvKiogRGV0ZXJtaW5lIGlmIHRoZSBsYXlvdXQgaGFzIGJlZW4gcGVyZm9ybWVkIHlldCAqL1xuICAgIHByaXZhdGUgaGFzUG9zaXRpb24oKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldENvbHVtbigpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRSb3coKSAhPT0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHN0YXRpYyBuZ0FjY2VwdElucHV0VHlwZV9hdXRvUG9zaXRpb25pbmc6IEJvb2xlYW5JbnB1dDtcbiAgICBzdGF0aWMgbmdBY2NlcHRJbnB1dFR5cGVfY29sOiBOdW1iZXJJbnB1dDtcbiAgICBzdGF0aWMgbmdBY2NlcHRJbnB1dFR5cGVfcm93OiBOdW1iZXJJbnB1dDtcbiAgICBzdGF0aWMgbmdBY2NlcHRJbnB1dFR5cGVfY29sU3BhbjogTnVtYmVySW5wdXQ7XG4gICAgc3RhdGljIG5nQWNjZXB0SW5wdXRUeXBlX3Jvd1NwYW46IE51bWJlcklucHV0O1xuICAgIHN0YXRpYyBuZ0FjY2VwdElucHV0VHlwZV9taW5Db2xTcGFuOiBOdW1iZXJJbnB1dDtcbiAgICBzdGF0aWMgbmdBY2NlcHRJbnB1dFR5cGVfbWluUm93U3BhbjogTnVtYmVySW5wdXQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RhY2thYmxlVmFsdWUge1xuICAgIHJlZ3VsYXI6IG51bWJlcjtcbiAgICBzdGFja2VkOiBudW1iZXI7XG59XG4iLCI8ZGl2IGNsYXNzPVwid2lkZ2V0LWNvbnRlbnQgd2lkZ2V0LWNvbC1zcGFuLXt7IGdldENvbHVtblNwYW4oKSB9fSB3aWRnZXQtcm93LXNwYW4te3sgZ2V0Um93U3BhbigpIH19XCI+XG4gICAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuPC9kaXY+XG5cbjxkaXYgdXhEcmFnXG4gICAgICNoYW5kbGVUb3BcbiAgICAgY2xhc3M9XCJyZXNpemVyLWhhbmRsZSBoYW5kbGUtdG9wXCJcbiAgICAgKG9uRHJhZ1N0YXJ0KT1cImRyYWdzdGFydChoYW5kbGVUb3AsICRldmVudCwgMClcIlxuICAgICAob25EcmFnKT1cImRyYWcoaGFuZGxlVG9wLCAkZXZlbnQsIDApXCJcbiAgICAgKG9uRHJhZ0VuZCk9XCJkcmFnZW5kKClcIlxuICAgICBbc3R5bGUudG9wLnB4XT1cInBhZGRpbmdcIlxuICAgICBbaGlkZGVuXT1cIiFyZXNpemFibGVcIj5cbjwvZGl2PlxuXG48ZGl2IHV4RHJhZ1xuICA