UNPKG

@nova-ui/bits

Version:

SolarWinds Nova Framework

561 lines 71.8 kB
// © 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