@nova-ui/bits
Version:
SolarWinds Nova Framework
561 lines • 71.8 kB
JavaScript
// © 2022 SolarWinds Worldwide, LLC. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import { forwardRef, Inject, Injectable, NgZone, } from "@angular/core";
import _includes from "lodash/includes";
import _isNil from "lodash/isNil";
import _isNumber from "lodash/isNumber";
import { Subject } from "rxjs";
import { TableSelectionMode } from "./types";
import { SelectorService } from "../selector/selector.service";
import { SorterDirection } from "../sorter/public-api";
import * as i0 from "@angular/core";
import * as i1 from "../selector/selector.service";
/** @ignore */
const MIN_COLUMN_WIDTH_PX = 46;
/** @ignore */
const ICON_CELL_WIDTH_PX = 40;
/** @ignore */
const SELECTABLE_CELL_WIDTH_PX = 75;
/** @ignore */
const DEFAULT_TRACK_BY = (i, d) => d;
export class TableStateHandlerService {
constructor(zone, selectorService) {
this.zone = zone;
this.selectorService = selectorService;
this.columnsState = new Subject();
this.sortingState = new Subject();
this.draggedOverCell = new Subject();
this.shouldHighlightEdge = new Subject();
this.dataSourceChanged = new Subject();
this.selectionChanged = new Subject();
this.selectableChanged = new Subject();
this.selectionModeChanged = new Subject();
this.columnWidthSubject = new Subject();
this.stickyHeaderChangedSubject = new Subject();
this._selection = {
isAllPages: false,
include: [],
exclude: [],
};
this.state = {
columnAlignments: {},
columns: [],
columnsWidths: {},
widthCalculationPerformed: false,
columnsTypes: [],
};
this.sortIcons = {
asc: "triangle-up",
desc: "triangle-down",
};
}
/**
* Used to sync directives and components in table to apply additional styles and logic
*/
set sortable(isSortable) {
this._sortable = isSortable;
}
get sortable() {
return this._sortable;
}
set dragCellIndex(cellIndex) {
this._dragCellIndex = cellIndex;
}
get dragCellIndex() {
return this._dragCellIndex;
}
set draggedOverCellIndex(cellIndex) {
this._draggedOverCellIndex = cellIndex;
}
get draggedOverCellIndex() {
return this._draggedOverCellIndex;
}
set newCellIndex(cellIndex) {
this._newCellIndex = cellIndex;
}
get newCellIndex() {
return this._newCellIndex;
}
set dropCellOffsetX(cellIndex) {
this._dropCellOffsetX = cellIndex;
}
get dropCellOffsetX() {
return this._dropCellOffsetX;
}
set dropCellWidth(cellIndex) {
this._dropCellWidth = cellIndex;
}
get dropCellWidth() {
return this._dropCellWidth;
}
set dragOverDirection(cellIndex) {
this._dragOverDirection = cellIndex;
}
get dragOverDirection() {
return this._dragOverDirection;
}
set reorderable(isDraggable) {
this._reorderable = isDraggable;
}
get reorderable() {
return this._reorderable;
}
set resizable(isResizable) {
this._resizable = isResizable;
}
get resizable() {
return this._resizable;
}
set tableColumns(columns) {
this.state.columns = columns;
}
get tableColumns() {
return this.state.columns;
}
set columnType(column) {
const columnIndex = this.state.columns.indexOf(column.columnName);
this.state.columnsTypes[columnIndex] = column.columnType;
}
get columnsTypes() {
return this.state.columnsTypes;
}
set sortedColumn(columnToSort) {
this.state.sortedColumn = columnToSort;
}
set selectable(isSelectable) {
if (isSelectable !== this._selectable) {
this.selectableChanged.next(isSelectable);
}
this._selectable = isSelectable;
}
get selectable() {
return this._selectable;
}
set selectionMode(mode) {
if (mode !== this._selectionMode) {
this.selectionModeChanged.next(mode);
}
this._selectionMode = mode;
}
get selectionMode() {
return this._selectionMode;
}
get hasVirtualScroll() {
return this._hasVirtualScroll;
}
set hasVirtualScroll(value) {
this._hasVirtualScroll = value;
}
set totalItems(paginationTotal) {
this._totalItems = paginationTotal;
}
get totalItems() {
return this._totalItems;
}
set dataSource(dataSource) {
this._dataSource = dataSource;
}
get dataSource() {
return this._dataSource;
}
set selection(selection) {
this._selection = selection;
}
get selection() {
return this._selection;
}
get trackBy() {
return this._trackBy || DEFAULT_TRACK_BY;
}
set trackBy(value) {
this._trackBy = value;
}
get selectionEnabled() {
return (this.selectable ||
(this.selectionMode &&
this.selectionMode !== TableSelectionMode.None));
}
/**
* Gets the width of the specified column
*
* @param column The id for the column being queried
*
* @returns The state's column width
*/
getColumnWidth(column) {
if (!this.state.widthCalculationPerformed) {
this.calculateWidthsOfColumns();
}
return this.state.columnsWidths[column].width;
}
/**
* Updates the width of the specified column,
* then broadcasts that a width change has occurred to all listeners of columnWidthSubject
*
* @param column The id for the column
* @param width The new width of the column
*
*/
setColumnWidth(column, width) {
this.state.columnsWidths[column] = { width };
this.columnWidthSubject.next();
}
/**
* Returns the current alignment direction for the queried column
*
* @param column The id of the column
*
* @returns The current alignment direction
*/
getAlignment(column) {
return this.state.columnAlignments[column];
}
/**
* Updates the specified column's alignment with the given alignment direction
*
* @param column the id for the column that is being updated
* @param alignment the new alignment direction
*
*/
setAlignment(column, alignment = "align-left" /* AlignmentClasses.LEFT */) {
this.state.columnAlignments[column] =
alignment || this.state.columnAlignments[column];
}
/**
* Determines the alignment for a column based on the type of the provided value.
* Returns AlignmentClasses.RIGHT if the value given is a number; otherwise, returns 'undefined'.
*
* @param value The data for a given column
*
* @returns The alignment direction for that column
*/
defineAlignment(value) {
if (_isNumber(value)) {
return "align-right" /* AlignmentClasses.RIGHT */;
}
}
/**
* Updates the state's columnWidths for each column and sets the state's widthCalculationPerformed property
* to true once the calculation is complete
*/
calculateWidthsOfColumns() {
// Apply width of 40px for non-resizable columns of type "icon"
this.state.columns
.filter((columnName) => {
const columnIndex = this.state.columns.indexOf(columnName);
return this.state.columnsTypes[columnIndex] === "icon";
})
.forEach((column) => {
this.state.columnsWidths[column] = {
width: ICON_CELL_WIDTH_PX,
};
});
// "selectable" adding one more column with 75px width which is not in the "this.state.columns", so we need take it to the consideration
const accumulator = this.resizable && this.selectable ? SELECTABLE_CELL_WIDTH_PX : 0;
const userColumnsWidths = this.state.columns
.filter((columnName) => this.state.columnsWidths[columnName])
.reduce((total, curr) => total + this.state.columnsWidths[curr].width, accumulator);
const widthConsideringUserInputs = userColumnsWidths > this.tableParentWidth
? 0
: this.tableParentWidth - userColumnsWidths - 1;
const columnsToCalculateWidth = this.state.columns.filter((columnName) => !this.state.columnsWidths[columnName]).length;
const calculatedWidth = Math.floor(widthConsideringUserInputs / columnsToCalculateWidth);
const widthOfColumn = calculatedWidth > MIN_COLUMN_WIDTH_PX
? calculatedWidth
: MIN_COLUMN_WIDTH_PX;
this.state.columns
.filter((columnName) => !this.state.columnsWidths[columnName])
.forEach((column) => {
// There is a case when sum of columns can exceed width of parent
// Then width of other columns should be set to min width
this.state.columnsWidths[column] = { width: widthOfColumn };
});
this.state.widthCalculationPerformed = true;
}
/**
* Updates the state's sortedColumn and sortedColumn.direction properties and then broadcasts the
* state object to all listeners of sortingState
*
* @param sortCellIndex the index of the column to sort by
*/
sortColumn(sortCellIndex) {
const newSortedColumn = this.state.columns[sortCellIndex];
const prevSortedColumn = this.state.sortedColumn && this.state.sortedColumn.sortBy;
const prevSortDirection = this.state.sortedColumn && this.state.sortedColumn.direction;
let newSortDirection = SorterDirection.original;
if (newSortedColumn === prevSortedColumn) {
newSortDirection =
prevSortDirection === SorterDirection.ascending
? SorterDirection.descending
: SorterDirection.ascending;
}
else {
newSortDirection = SorterDirection.ascending;
}
this.state.sortedColumn = {
sortBy: newSortedColumn,
direction: newSortDirection,
};
this.sortingState.next(this.state.sortedColumn);
}
/**
* Updates the state's column order and broadcasts the state's columns to all listeners of columnsState
*
* @param dragCellIndex
* @param newCellIndex
*/
reorderColumns(dragCellIndex, newCellIndex) {
const dragCellValue = this.state.columns[dragCellIndex];
this.state.columns.splice(dragCellIndex, 1);
this.state.columns.splice(newCellIndex, 0, dragCellValue);
this.columnsState.next(this.state.columns);
}
/**
* Checks to see if there has been any change in the column's order
* If there was it calls reorderColumns to update the state's column order
*/
reorderColumnsOnDrop() {
this.getNewCellIndex();
if (!_isNil(this.newCellIndex) &&
this.newCellIndex !== this.dragCellIndex &&
this.dragCellIndex !== this.draggedOverCellIndex) {
this.reorderColumns(this.dragCellIndex, this.newCellIndex);
}
}
/**
* Updates the newCellIndex property if the current value is different from draggedOverCellIndex
*/
getNewCellIndex() {
if (this.dragCellIndex !== this.draggedOverCellIndex) {
this.newCellIndex =
this.dragCellIndex < this.draggedOverCellIndex
? this.dropCellOffsetX < this.dropCellWidth / 2
? this.draggedOverCellIndex - 1
: this.draggedOverCellIndex
: this.dropCellOffsetX < this.dropCellWidth / 2
? this.draggedOverCellIndex
: this.draggedOverCellIndex + 1;
}
}
/**
* Finds the index for the column that the event happened to
*
* @param event
*
* @returns The column index
*/
getTargetElementCellIndex(event) {
// When we have selectable table we need to decrease index of event.target.id by one because we added new column to html but not adding column to
// this.state.columns. Because of that cellIndex in event will be greater than index in this.state.columns by one.
const cellIndex = parseInt(event.target.cellIndex, 10);
return this.selectable ? cellIndex - 1 : cellIndex;
}
/**
* Returns the DropAlignment direction for the recently dragged column
*
* @returns The drop alignment direction
*/
getDropCellAlignment() {
return this.dragCellIndex < this.draggedOverCellIndex
? this.newCellIndex < this.draggedOverCellIndex
? "left" /* DropAlignment.left */
: "right" /* DropAlignment.right */
: this.newCellIndex > this.draggedOverCellIndex
? "right" /* DropAlignment.right */
: "left" /* DropAlignment.left */;
}
/**
* Checks to see if the recent drag event changed the order of the columns
* then broadcasts the results to all listeners of draggedOverCell
*/
emitDraggedOverCell() {
this.zone.run(() => {
if (this.dragCellIndex !== this.draggedOverCellIndex &&
this.dragCellIndex !== this.newCellIndex) {
this.draggedOverCell.next({
cellIndex: this.draggedOverCellIndex,
dropAlignment: this.getDropCellAlignment(),
});
}
else {
this.draggedOverCell.next(undefined);
}
});
}
/**
* Broadcasts the given resize information to all listeners of shouldHighlightEdge
*
* @param columnIndex
* @param eventPhase
*/
emitResizeEvent(columnIndex, eventPhase) {
this.shouldHighlightEdge.next({
columnIndex,
side: "right" /* DropAlignment.right */,
eventPhase,
});
}
/**
* Updates the draggedOverCellIndex
*
* @param event
*/
setDraggedOverCell(event) {
const dropCellOffsetX = event.offsetX;
const dropCellWidth = event.target.clientWidth;
const dragOverDirection = dropCellOffsetX < dropCellWidth / 2 ? "left-right" : "right-left";
const draggedOverCellIndex = this.getTargetElementCellIndex(event);
const draggedOverCellChanged = _isNil(this.dragOverDirection) ||
_isNil(this.draggedOverCellIndex) ||
draggedOverCellIndex !== this.draggedOverCellIndex ||
dragOverDirection !== this.dragOverDirection;
if (draggedOverCellChanged) {
this.dropCellOffsetX = dropCellOffsetX;
this.dropCellWidth = dropCellWidth;
this.dragOverDirection = dragOverDirection;
this.draggedOverCellIndex = draggedOverCellIndex;
this.getNewCellIndex();
this.emitDraggedOverCell();
}
}
/**
* Updates the dataSource property and broadcasts the change to all listeners of dataSourceChanged
*
* @param dataSource
*/
changeDataSource(dataSource) {
this.dataSource = dataSource;
this.dataSourceChanged.next(dataSource);
}
/**
* Returns an array of the selected items
*
* @returns An array of all currently selected items
*/
getSelectedItems() {
const trackedItems = this.dataSource.map((d) => this.trackBy(d?.id, d));
return this.selectorService.getSelectedItems(this.selection, trackedItems);
}
/**
* Returns the current state of the selector
*
* @returns
*/
getSelectorState() {
return this.selectorService.getSelectorState(this.selection, this.dataSource.length, this.getSelectedItems().length, this.totalItems, this.selection.include.length, this.hasVirtualScroll);
}
/**
* Updates the selection type and returns a new selection object based on that new selection type
*
* @param selectorValue
*
* @returns The newly applied selection
*/
applySelector(selectorValue) {
return this.selectorService.applySelector(this.selection, this.dataSource, selectorValue, this.totalItems, this.trackBy, this.hasVirtualScroll);
}
/**
* Updates the selection object to either include or exclude the row based on the current selection
* type and the row's current selection state
* Then the selection object is broadcast to all listeners of selectionChanged
*
* @param rowObject
*/
handleRowSelect(rowObject) {
switch (this._selectionMode) {
case TableSelectionMode.Single:
case TableSelectionMode.Radio:
this.handleRowSelectSingle(rowObject);
break;
case TableSelectionMode.Multi:
this.handleRowSelectMulti(rowObject);
break;
default:
console.error("Unknown table selection mode.");
}
}
handleRowSelectSingle(rowObject) {
const rowObjectTrackBy = this.trackBy(rowObject?.id, rowObject);
this.selection = {
isAllPages: false,
exclude: [],
include: [rowObjectTrackBy],
};
this.selectionChanged.next(this.selection);
}
handleRowSelectMulti(rowObject) {
const excludedRows = this.selection.exclude;
const includedRows = this.selection.include;
const rowObjectTrackBy = this.trackBy(rowObject?.id, rowObject);
if (this.selection.isAllPages) {
if (!_includes(excludedRows, rowObjectTrackBy)) {
excludedRows.push(rowObjectTrackBy);
}
else {
excludedRows.splice(excludedRows.indexOf(rowObjectTrackBy), 1);
}
}
else {
if (!_includes(includedRows, rowObjectTrackBy)) {
includedRows.push(rowObjectTrackBy);
}
else {
includedRows.splice(includedRows.indexOf(rowObjectTrackBy), 1);
}
}
this.selectionChanged.next(this.selection);
}
/**
* Returns the current sorting state of the specified cell index
*
* @param cellIndex
*
* @returns The current sorting state
*/
getSortingState(cellIndex) {
if (this.state.sortedColumn) {
return {
sortingIcon: this.sortIcons[this.state.sortedColumn.direction],
// comparing column index with index of sorted column
isColumnSorted: cellIndex ===
this.state.columns.indexOf(this.state.sortedColumn.sortBy) && this.sortable,
};
}
return {
sortingIcon: undefined,
isColumnSorted: false,
};
}
/**
* Broadcasts to all listeners of stickyHeaderChangedSubject that a change has occurred
*/
applyStickyStyles() {
this.stickyHeaderChangedSubject.next();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableStateHandlerService, deps: [{ token: i0.NgZone }, { token: forwardRef(() => SelectorService) }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableStateHandlerService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableStateHandlerService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i0.NgZone }, { type: i1.SelectorService, decorators: [{
type: Inject,
args: [forwardRef(() => SelectorService)]
}] }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUtc3RhdGUtaGFuZGxlci5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi90YWJsZS90YWJsZS1zdGF0ZS1oYW5kbGVyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseURBQXlEO0FBQ3pELEVBQUU7QUFDRiwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLDhFQUE4RTtBQUM5RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLDREQUE0RDtBQUM1RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLDRFQUE0RTtBQUM1RSwrRUFBK0U7QUFDL0UsMEVBQTBFO0FBQzFFLGlGQUFpRjtBQUNqRiw2RUFBNkU7QUFDN0UsaUJBQWlCO0FBRWpCLE9BQU8sRUFDSCxVQUFVLEVBQ1YsTUFBTSxFQUNOLFVBQVUsRUFDVixNQUFNLEdBRVQsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxTQUFTLE1BQU0saUJBQWlCLENBQUM7QUFDeEMsT0FBTyxNQUFNLE1BQU0sY0FBYyxDQUFDO0FBQ2xDLE9BQU8sU0FBUyxNQUFNLGlCQUFpQixDQUFDO0FBQ3hDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFHL0IsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRzdDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxPQUFPLEVBQWUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7OztBQWtEcEUsY0FBYztBQUNkLE1BQU0sbUJBQW1CLEdBQUcsRUFBRSxDQUFDO0FBQy9CLGNBQWM7QUFDZCxNQUFNLGtCQUFrQixHQUFHLEVBQUUsQ0FBQztBQUM5QixjQUFjO0FBQ2QsTUFBTSx3QkFBd0IsR0FBRyxFQUFFLENBQUM7QUFFcEMsY0FBYztBQUNkLE1BQU0sZ0JBQWdCLEdB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YUFDbEU7U0FDSjtRQUVELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSSxlQUFlLENBQUMsU0FBaUI7UUFDcEMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksRUFBRTtZQUN6QixPQUFPO2dCQUNILFdBQVcsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQztnQkFDOUQscURBQXFEO2dCQUNyRCxjQUFjLEVBQ1YsU0FBUztvQkFDTCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQ3RCLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FDakMsSUFBSSxJQUFJLENBQUMsUUFBUTthQUM3QixDQUFDO1NBQ0w7UUFDRCxPQUFPO1lBQ0gsV0FBVyxFQUFFLFNBQVM7WUFDdEIsY0FBYyxFQUFFLEtBQUs7U0FDeEIsQ0FBQztJQUNOLENBQUM7SUFFRDs7T0FFRztJQUNJLGlCQUFpQjtRQUNwQixJQUFJLENBQUMsMEJBQTBCLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDM0MsQ0FBQzsrR0FucEJRLHdCQUF3Qix3Q0FrRHJCLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxlQUFlLENBQUM7bUhBbERwQyx3QkFBd0I7OzRGQUF4Qix3QkFBd0I7a0JBRHBDLFVBQVU7OzBCQW1ERixNQUFNOzJCQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxlQUFlLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHtcbiAgICBmb3J3YXJkUmVmLFxuICAgIEluamVjdCxcbiAgICBJbmplY3RhYmxlLFxuICAgIE5nWm9uZSxcbiAgICBUcmFja0J5RnVuY3Rpb24sXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgX2luY2x1ZGVzIGZyb20gXCJsb2Rhc2gvaW5jbHVkZXNcIjtcbmltcG9ydCBfaXNOaWwgZnJvbSBcImxvZGFzaC9pc05pbFwiO1xuaW1wb3J0IF9pc051bWJlciBmcm9tIFwibG9kYXNoL2lzTnVtYmVyXCI7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSBcInJ4anNcIjtcblxuaW1wb3J0IHsgVGFibGVSZXNpemVQaGFzZSB9IGZyb20gXCIuL3RhYmxlLXJlc2l6ZXIvdGFibGUtcmVzaXplci5kaXJlY3RpdmVcIjtcbmltcG9ydCB7IFRhYmxlU2VsZWN0aW9uTW9kZSB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBJU2VsZWN0aW9uLCBJU2VsZWN0b3JTdGF0ZSB9IGZyb20gXCIuLi8uLi9zZXJ2aWNlcy9wdWJsaWMtYXBpXCI7XG5pbXBvcnQgeyBTZWxlY3Rpb25UeXBlIH0gZnJvbSBcIi4uL3NlbGVjdG9yL3B1YmxpYy1hcGlcIjtcbmltcG9ydCB7IFNlbGVjdG9yU2VydmljZSB9IGZyb20gXCIuLi9zZWxlY3Rvci9zZWxlY3Rvci5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBJU29ydGVkSXRlbSwgU29ydGVyRGlyZWN0aW9uIH0gZnJvbSBcIi4uL3NvcnRlci9wdWJsaWMtYXBpXCI7XG5cbmV4cG9ydCBjb25zdCBlbnVtIEFsaWdubWVudENsYXNzZXMge1xuICAgIFJJR0hUID0gXCJhbGlnbi1yaWdodFwiLFxuICAgIExFRlQgPSBcImFsaWduLWxlZnRcIixcbiAgICBDRU5URVIgPSBcImFsaWduLWNlbnRlclwiLFxufVxuXG5leHBvcnQgY29uc3QgZW51bSBEcm9wQWxpZ25tZW50IHtcbiAgICBsZWZ0ID0gXCJsZWZ0XCIsXG4gICAgcmlnaHQgPSBcInJpZ2h0XCIsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29sdW1uV2lkdGhJbmZvIHtcbiAgICB3aWR0aDogbnVtYmVyO1xuICAgIGF1dG9DYWxjdWxhdGVkPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJVGFibGVTdGF0ZSB7XG4gICAgY29sdW1uQWxpZ25tZW50czogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcbiAgICBjb2x1bW5zV2lkdGhzOiB7XG4gICAgICAgIFtrZXk6IHN0cmluZ106IENvbHVtbldpZHRoSW5mbztcbiAgICB9O1xuICAgIGNvbHVtbnM6IHN0cmluZ1tdO1xuICAgIHNvcnRlZENvbHVtbj86IElTb3J0ZWRJdGVtO1xuICAgIHdpZHRoQ2FsY3VsYXRpb25QZXJmb3JtZWQ6IGJvb2xlYW47XG4gICAgY29sdW1uc1R5cGVzOiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEcmFnZ2VkT3ZlckNlbGwge1xuICAgIGNlbGxJbmRleDogbnVtYmVyO1xuICAgIGRyb3BBbGlnbm1lbnQ6IERyb3BBbGlnbm1lbnQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGFibGVDZWxsRWRnZUhpZ2hsaWdodCB7XG4gICAgY29sdW1uSW5kZXg6IG51bWJlcjtcbiAgICBzaWRlOiBEcm9wQWxpZ25tZW50O1xuICAgIGV2ZW50UGhhc2U6IFRhYmxlUmVzaXplUGhhc2U7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29sdW1uVHlwZSB7XG4gICAgY29sdW1uTmFtZTogc3RyaW5nO1xuICAgIGNvbHVtblR5cGU6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJVGFibGVTb3J0aW5nU3RhdGUge1xuICAgIHNvcnRpbmdJY29uPzogc3RyaW5nO1xuICAgIGlzQ29sdW1uU29ydGVkOiBib29sZWFuO1xufVxuXG4vKiogQGlnbm9yZSAqL1xuY29uc3QgTUlOX0NPTFVNTl9XSURUSF9QWCA9IDQ2O1xuLyoqIEBpZ25vcmUgKi9cbmNvbnN0IElDT05fQ0VMTF9XSURUSF9QWCA9IDQwO1xuLyoqIEBpZ25vcmUgKi9cbmNvbnN0IFNFTEVDVEFCTEVfQ0VMTF9XSURUSF9QWCA9IDc1O1xuXG4vKiogQGlnbm9yZSAqL1xuY29uc3QgREVGQVVMVF9UUkFDS19CWTogVHJhY2tCeUZ1bmN0aW9uPGFueT4gPSAoaSwgZCkgPT4gZDtcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFRhYmxlU3RhdGVIYW5kbGVyU2VydmljZSB7XG4gICAgcHVibGljIHRhYmxlUGFyZW50V2lkdGg6IG51bWJlcjtcbiAgICBwdWJsaWMgY29sdW1uc1N0YXRlID0gbmV3IFN1YmplY3Q8c3RyaW5nW10+KCk7XG4gICAgcHVibGljIHNvcnRpbmdTdGF0ZSA9IG5ldyBTdWJqZWN0PElTb3J0ZWRJdGVtPigpO1xuICAgIHB1YmxpYyBkcmFnZ2VkT3ZlckNlbGwgPSBuZXcgU3ViamVjdDxEcmFnZ2VkT3ZlckNlbGwgfCB1bmRlZmluZWQ+KCk7XG4gICAgcHVibGljIHNob3VsZEhpZ2hsaWdodEVkZ2UgPSBuZXcgU3ViamVjdDxUYWJsZUNlbGxFZGdlSGlnaGxpZ2h0PigpO1xuICAgIHB1YmxpYyBkYXRhU291cmNlQ2hhbmdlZCA9IG5ldyBTdWJqZWN0PEFycmF5PGFueT4+KCk7XG4gICAgcHVibGljIHNlbGVjdGlvbkNoYW5nZWQgPSBuZXcgU3ViamVjdDxJU2VsZWN0aW9uPigpO1xuICAgIHB1YmxpYyBzZWxlY3RhYmxlQ2hhbmdlZCA9IG5ldyBTdWJqZWN0PGJvb2xlYW4+KCk7XG4gICAgcHVibGljIHNlbGVjdGlvbk1vZGVDaGFuZ2VkID0gbmV3IFN1YmplY3Q8VGFibGVTZWxlY3Rpb25Nb2RlPigpO1xuICAgIHB1YmxpYyBjb2x1bW5XaWR0aFN1YmplY3QgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuICAgIHB1YmxpYyBzdGlja3lIZWFkZXJDaGFuZ2VkU3ViamVjdCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICBwcml2YXRlIF9yZW9yZGVyYWJsZTogYm9vbGVhbjtcbiAgICBwcml2YXRlIF9zb3J0YWJsZTogYm9vbGVhbjtcbiAgICBwcml2YXRlIF9yZXNpemFibGU6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSBfZHJhZ0NlbGxJbmRleDogbnVtYmVyO1xuICAgIHByaXZhdGUgX2RyYWdnZWRPdmVyQ2VsbEluZGV4OiBudW1iZXI7XG4gICAgcHJpdmF0ZSBfbmV3Q2VsbEluZGV4OiBudW1iZXI7XG4gICAgcHJpdmF0ZSBfZHJvcENlbGxPZmZzZXRYOiBudW1iZXI7XG4gICAgcHJpdmF0ZSBfZHJvcENlbGxXaWR0aDogbnVtYmVyO1xuICAgIHByaXZhdGUgX2RyYWdPdmVyRGlyZWN0aW9uOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBfc2VsZWN0YWJsZTogYm9vbGVhbjtcbiAgICBwcml2YXRlIF9zZWxlY3Rpb25Nb2RlOiBUYWJsZVNlbGVjdGlvbk1vZGU7XG4gICAgLy8gTm90ZTogVXNlZCB0byB0ZWxsIHRvIHRoZSBTZWxlY3RvclNlcnZpY2UgdG8gc2tpcCBwYWdpbmF0aW9uIGxvZ2ljXG4gICAgcHJpdmF0ZSBfaGFzVmlydHVhbFNjcm9sbDogYm9vbGVhbjtcbiAgICBwcml2YXRlIF90b3RhbEl0ZW1zOiBudW1iZXI7XG4gICAgcHJpdmF0ZSBfZGF0YVNvdXJjZTogYW55W107XG4gICAgcHJpdmF0ZSBfc2VsZWN0aW9uOiBJU2VsZWN0aW9uID0ge1xuICAgICAgICBpc0FsbFBhZ2VzOiBmYWxzZSxcbiAgICAgICAgaW5jbHVkZTogW10sXG4gICAgICAgIGV4Y2x1ZGU6IFtdLFxuICAgIH07XG4gICAgcHVibGljIF90cmFja0J5OiBUcmFja0J5RnVuY3Rpb248YW55PjtcblxuICAgIHByb3RlY3RlZCBzdGF0ZTogSVRhYmxlU3RhdGUgPSB7XG4gICAgICAgIGNvbHVtbkFsaWdubWVudHM6IHt9LFxuICAgICAgICBjb2x1bW5zOiBbXSxcbiAgICAgICAgY29sdW1uc1dpZHRoczoge30sXG4gICAgICAgIHdpZHRoQ2FsY3VsYXRpb25QZXJmb3JtZWQ6IGZhbHNlLFxuICAgICAgICBjb2x1bW5zVHlwZXM6IFtdLFxuICAgIH07XG5cbiAgICBwcm90ZWN0ZWQgc29ydEljb25zOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge1xuICAgICAgICBhc2M6IFwidHJpYW5nbGUtdXBcIixcbiAgICAgICAgZGVzYzogXCJ0cmlhbmdsZS1kb3duXCIsXG4gICAgfTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcm90ZWN0ZWQgem9uZTogTmdab25lLFxuICAgICAgICBASW5qZWN0KGZvcndhcmRSZWYoKCkgPT4gU2VsZWN0b3JTZXJ2aWNlKSlcbiAgICAgICAgcHJvdGVjdGVkIHNlbGVjdG9yU2VydmljZTogU2VsZWN0b3JTZXJ2aWNlXG4gICAgKSB7fVxuXG4gICAgLyoqXG4gICAgICogVXNlZCB0byBzeW5jIGRpcmVjdGl2ZXMgYW5kIGNvbXBvbmVudHMgaW4gdGFibGUgdG8gYXBwbHkgYWRkaXRpb25hbCBzdHlsZXMgYW5kIGxvZ2ljXG4gICAgICovXG4gICAgc2V0IHNvcnRhYmxlKGlzU29ydGFibGU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5fc29ydGFibGUgPSBpc1NvcnRhYmxlO1xuICAgIH1cblxuICAgIGdldCBzb3J0YWJsZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3NvcnRhYmxlO1xuICAgIH1cblxuICAgIHNldCBkcmFnQ2VsbEluZGV4KGNlbGxJbmRleDogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuX2RyYWdDZWxsSW5kZXggPSBjZWxsSW5kZXg7XG4gICAgfVxuXG4gICAgZ2V0IGRyYWdDZWxsSW5kZXgoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RyYWdDZWxsSW5kZXg7XG4gICAgfVxuXG4gICAgc2V0IGRyYWdnZWRPdmVyQ2VsbEluZGV4KGNlbGxJbmRleDogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuX2RyYWdnZWRPdmVyQ2VsbEluZGV4ID0gY2VsbEluZGV4O1xuICAgIH1cblxuICAgIGdldCBkcmFnZ2VkT3ZlckNlbGxJbmRleCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fZHJhZ2dlZE92ZXJDZWxsSW5kZXg7XG4gICAgfVxuXG4gICAgc2V0IG5ld0NlbGxJbmRleChjZWxsSW5kZXg6IG51bWJlcikge1xuICAgICAgICB0aGlzLl9uZXdDZWxsSW5kZXggPSBjZWxsSW5kZXg7XG4gICAgfVxuXG4gICAgZ2V0IG5ld0NlbGxJbmRleCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fbmV3Q2VsbEluZGV4O1xuICAgIH1cblxuICAgIHNldCBkcm9wQ2VsbE9mZnNldFgoY2VsbEluZGV4OiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy5fZHJvcENlbGxPZmZzZXRYID0gY2VsbEluZGV4O1xuICAgIH1cblxuICAgIGdldCBkcm9wQ2VsbE9mZnNldFgoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2Ryb3BDZWxsT2Zmc2V0WDtcbiAgICB9XG5cbiAgICBzZXQgZHJvcENlbGxXaWR0aChjZWxsSW5kZXg6IG51bWJlcikge1xuICAgICAgICB0aGlzLl9kcm9wQ2VsbFdpZHRoID0gY2VsbEluZGV4O1xuICAgIH1cblxuICAgIGdldCBkcm9wQ2VsbFdpZHRoKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kcm9wQ2VsbFdpZHRoO1xuICAgIH1cblxuICAgIHNldCBkcmFnT3ZlckRpcmVjdGlvbihjZWxsSW5kZXg6IHN0cmluZykge1xuICAgICAgICB0aGlzLl9kcmFnT3ZlckRpcmVjdGlvbiA9IGNlbGxJbmRleDtcbiAgICB9XG5cbiAgICBnZXQgZHJhZ092ZXJEaXJlY3Rpb24oKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RyYWdPdmVyRGlyZWN0aW9uO1xuICAgIH1cblxuICAgIHNldCByZW9yZGVyYWJsZShpc0RyYWdnYWJsZTogYm9vbGVhbikge1xuICAgICAgICB0aGlzLl9yZW9yZGVyYWJsZSA9IGlzRHJhZ2dhYmxlO1xuICAgIH1cblxuICAgIGdldCByZW9yZGVyYWJsZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3Jlb3JkZXJhYmxlO1xuICAgIH1cblxuICAgIHNldCByZXNpemFibGUoaXNSZXNpemFibGU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5fcmVzaXphYmxlID0gaXNSZXNpemFibGU7XG4gICAgfVxuXG4gICAgZ2V0IHJlc2l6YWJsZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3Jlc2l6YWJsZTtcbiAgICB9XG5cbiAgICBzZXQgdGFibGVDb2x1bW5zKGNvbHVtbnM6IHN0cmluZ1tdKSB7XG4gICAgICAgIHRoaXMuc3RhdGUuY29sdW1ucyA9IGNvbHVtbnM7XG4gICAgfVxuXG4gICAgZ2V0IHRhYmxlQ29sdW1ucygpOiBzdHJpbmdbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0YXRlLmNvbHVtbnM7XG4gICAgfVxuXG4gICAgc2V0IGNvbHVtblR5cGUoY29sdW1uOiBDb2x1bW5UeXBlKSB7XG4gICAgICAgIGNvbnN0IGNvbHVtbkluZGV4ID0gdGhpcy5zdGF0ZS5jb2x1bW5zLmluZGV4T2YoY29sdW1uLmNvbHVtbk5hbWUpO1xuICAgICAgICB0aGlzLnN0YXRlLmNvbHVtbnNUeXBlc1tjb2x1bW5JbmRleF0gPSBjb2x1bW4uY29sdW1uVHlwZTtcbiAgICB9XG5cbiAgICBnZXQgY29sdW1uc1R5cGVzKCk6IHN0cmluZ1tdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGUuY29sdW1uc1R5cGVzO1xuICAgIH1cblxuICAgIHNldCBzb3J0ZWRDb2x1bW4oY29sdW1uVG9Tb3J0OiBJU29ydGVkSXRlbSkge1xuICAgICAgICB0aGlzLnN0YXRlLnNvcnRlZENvbHVtbiA9IGNvbHVtblRvU29ydDtcbiAgICB9XG5cbiAgICBzZXQgc2VsZWN0YWJsZShpc1NlbGVjdGFibGU6IGJvb2xlYW4pIHtcbiAgICAgICAgaWYgKGlzU2VsZWN0YWJsZSAhPT0gdGhpcy5fc2VsZWN0YWJsZSkge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RhYmxlQ2hhbmdlZC5uZXh0KGlzU2VsZWN0YWJsZSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fc2VsZWN0YWJsZSA9IGlzU2VsZWN0YWJsZTtcbiAgICB9XG5cbiAgICBnZXQgc2VsZWN0YWJsZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3NlbGVjdGFibGU7XG4gICAgfVxuXG4gICAgc2V0IHNlbGVjdGlvbk1vZGUobW9kZTogVGFibGVTZWxlY3Rpb25Nb2RlKSB7XG4gICAgICAgIGlmIChtb2RlICE9PSB0aGlzLl9zZWxlY3Rpb25Nb2RlKSB7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGlvbk1vZGVDaGFuZ2VkLm5leHQobW9kZSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fc2VsZWN0aW9uTW9kZSA9IG1vZGU7XG4gICAgfVxuXG4gICAgZ2V0IHNlbGVjdGlvbk1vZGUoKTogVGFibGVTZWxlY3Rpb25Nb2RlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3NlbGVjdGlvbk1vZGU7XG4gICAgfVxuXG4gICAgZ2V0IGhhc1ZpcnR1YWxTY3JvbGwoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9oYXNWaXJ0dWFsU2Nyb2xsO1xuICAgIH1cblxuICAgIHNldCBoYXNWaXJ0dWFsU2Nyb2xsKHZhbHVlOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuX2hhc1ZpcnR1YWxTY3JvbGwgPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBzZXQgdG90YWxJdGVtcyhwYWdpbmF0aW9uVG90YWw6IG51bWJlcikge1xuICAgICAgICB0aGlzLl90b3RhbEl0ZW1zID0gcGFnaW5hdGlvblRvdGFsO1xuICAgIH1cblxuICAgIGdldCB0b3RhbEl0ZW1zKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLl90b3RhbEl0ZW1zO1xuICAgIH1cblxuICAgIHNldCBkYXRhU291cmNlKGRhdGFTb3VyY2U6IGFueVtdKSB7XG4gICAgICAgIHRoaXMuX2RhdGFTb3VyY2UgPSBkYXRhU291cmNlO1xuIC