UNPKG

carbon-components-angular

Version:
654 lines 74.2 kB
import { EventEmitter } from "@angular/core"; import { TableHeaderItem } from "./table-header-item.class"; import { TableItem } from "./table-item.class"; import { Subject } from "rxjs"; /** * TableModel represents a data model for two-dimensional data. It's used for all things table * (table component, table toolbar, pagination, etc) * * TableModel manages its internal data integrity very well if you use the provided helper * functions for modifying rows and columns and assigning header and data in that order. * * It also provides direct access to the data so you can read and modify it. * If you change the structure of the data (by directly pushing into the arrays or otherwise), * keep in mind to keep the data structure intact. * * Header length and length of every line in the data should be equal. * * If they are not consistent, unexpected things will happen. * * Use the provided functions when in doubt. */ export class TableModel { constructor() { this.dataChange = new EventEmitter(); this.rowsSelectedChange = new EventEmitter(); this.rowsExpandedChange = new EventEmitter(); /** * Gets emitted when `selectAll` is called. Emits false if all rows are deselected and true if * all rows are selected. */ this.selectAllChange = new Subject(); /** * Contains information about selection state of rows in the table. */ this.rowsSelected = []; /** * Contains information about expanded state of rows in the table. */ this.rowsExpanded = []; /** * Contains information about initial index of rows in the table */ this.rowsIndices = []; /** * Contains information about the context of the row. * * It affects styling of the row to reflect the context. * * string can be one of `"success" | "warning" | "info" | "error" | ""` and it's * empty or undefined by default */ this.rowsContext = []; /** * Contains class name(s) of the row. * * It affects styling of the row to reflect the appended class name(s). * * It's empty or undefined by default */ this.rowsClass = []; /** * Contains information about the header cells of the table. */ this.header = []; /** * Tracks the current page. */ this.currentPage = 1; /** * Length of page. */ this.pageLength = 10; /** * Set to true when there is no more data to load in the table */ this.isEnd = false; /** * Set to true when lazy loading to show loading indicator */ this.isLoading = false; /** * Used in `data` */ this._data = [[]]; /** * The number of models instantiated, this is to make sure each table has a different * model count for unique id generation. */ this.tableModelCount = 0; this.tableModelCount = TableModel.COUNT++; } /** * Sets data of the table. * * Make sure all rows are the same length to keep the column count accurate. */ set data(newData) { if (!newData || (Array.isArray(newData) && newData.length === 0)) { newData = [[]]; } this._data = newData; // init rowsSelected this.rowsSelected = new Array(this._data.length).fill(false); this.rowsExpanded = new Array(this._data.length).fill(false); // init rows indices this.rowsIndices = [...Array(this._data.length).keys()]; // init rowsContext this.rowsContext = new Array(this._data.length); // init rowsClass this.rowsClass = new Array(this._data.length); // only create a fresh header if necessary (header doesn't exist or differs in length) if (this.header == null || (this.header.length !== this._data[0].length && this._data[0].length > 0)) { let header = new Array(); for (let i = 0; i < this._data[0].length; i++) { header.push(new TableHeaderItem()); } this.header = header; } this.dataChange.emit(); } /** * Gets the full data. * * You can use it to alter individual `TableItem`s but if you need to change * table structure, use `addRow()` and/or `addColumn()` */ get data() { return this._data; } /** * Manually set data length in case the data in the table doesn't * correctly reflect all the data that table is to display. * * Example: if you have multiple pages of data that table will display * but you're loading one at a time. * * Set to `null` to reset to default behavior. */ set totalDataLength(length) { // if this function is called without a parameter we need to set to null to avoid having undefined != null this._totalDataLength = isNaN(length) ? null : length; } /** * Total length of data that table has access to, or the amount manually set */ get totalDataLength() { // if manually set data length if (this._totalDataLength !== null && this._totalDataLength >= 0) { return this._totalDataLength; } // if empty dataset if (this.data && this.data.length === 1 && this.data[0].length === 0) { return 0; } return this.data.length; } /** * Returns an id for the given column * * @param column the column to generate an id for * @param row the row of the header to generate an id for */ getId(column, row = 0) { return `table-header-${row}-${column}-${this.tableModelCount}`; } /** * Returns the id of the header. Used to link the cells with headers (or headers with headers) * * @param column the column to start getting headers for * @param colSpan the number of columns to get headers for (defaults to 1) */ getHeaderId(column, colSpan = 1) { if (column === "select" || column === "expand") { return this.getId(column); } let ids = []; for (let i = column; i >= 0; i--) { if (this.header[i]) { for (let j = 0; j < colSpan; j++) { ids.push(this.getId(i + j)); } break; } } return ids.join(" "); } /** * Finds closest header by trying the `column` and then working its way to the left * * @param column the target column */ getHeader(column) { if (!this.header) { return null; } for (let i = column; i >= 0; i--) { const headerCell = this.header[i]; if (headerCell) { return headerCell; } } return null; } /** * Returns how many rows is currently selected */ selectedRowsCount() { let count = 0; if (this.rowsSelected) { this.rowsSelected.forEach(rowSelected => { if (rowSelected) { count++; } }); } return count; } /** * Returns how many rows is currently expanded */ expandedRowsCount() { let count = 0; if (this.rowsExpanded) { this.rowsExpanded.forEach(rowExpanded => { if (rowExpanded) { count++; } }); } return count; } /** * Returns `index`th row of the table. * * Negative index starts from the end. -1 being the last element. * * @param index */ row(index) { return this.data[this.realRowIndex(index)]; } /** * Adds a row to the `index`th row or appends to table if index not provided. * * If row is shorter than other rows or not provided, it will be padded with * empty `TableItem` elements. * * If row is longer than other rows, others will be extended to match so no data is lost. * * If called on an empty table with no parameters, it creates a 1x1 table. * * Negative index starts from the end. -1 being the last element. * * @param [row] * @param [index] */ addRow(row, index) { // if table empty create table with row if (!this.data || this.data.length === 0 || this.data[0].length === 0) { let newData = new Array(); newData.push(row ? row : [new TableItem()]); // row or one empty one column row this.data = newData; return; } let realRow = row; const columnCount = this.data[0].length; if (row == null) { realRow = new Array(); for (let i = 0; i < columnCount; i++) { realRow.push(new TableItem()); } } if (realRow.length < columnCount) { // extend the length of realRow const difference = columnCount - realRow.length; for (let i = 0; i < difference; i++) { realRow.push(new TableItem()); } } else if (realRow.length > columnCount) { // extend the length of header let difference = realRow.length - this.header.length; for (let j = 0; j < difference; j++) { this.header.push(new TableHeaderItem()); } // extend the length of every other row for (let i = 0; i < this.data.length; i++) { let currentRow = this.data[i]; difference = realRow.length - currentRow.length; for (let j = 0; j < difference; j++) { currentRow.push(new TableItem()); } } } if (index == null) { this.data.push(realRow); // update rowsSelected property for length this.rowsSelected.push(false); // update rowsExpanded property for length this.rowsExpanded.push(false); // update rowsContext property for length this.rowsContext.push(undefined); // update rowsClass property for length this.rowsClass.push(undefined); // update rowsIndices property for length this.rowsIndices.push(this.data.length - 1); } else { const ri = this.realRowIndex(index); this.data.splice(ri, 0, realRow); // update rowsSelected property for length this.rowsSelected.splice(ri, 0, false); // update rowsExpanded property for length this.rowsExpanded.splice(ri, 0, false); // update rowsContext property for length this.rowsContext.splice(ri, 0, undefined); // update rowsClass property for length this.rowsClass.splice(ri, 0, undefined); // update rowsIndices property for length this.rowsIndices.splice(ri, 0, this.data.length - 1); } this.dataChange.emit(); } /** * Deletes `index`th row. * * Negative index starts from the end. -1 being the last element. * * @param index */ deleteRow(index) { const rri = this.realRowIndex(index); this.data.splice(rri, 1); this.rowsSelected.splice(rri, 1); this.rowsExpanded.splice(rri, 1); this.rowsContext.splice(rri, 1); this.rowsClass.splice(rri, 1); const rowIndex = this.rowsIndices[rri]; this.rowsIndices.splice(rri, 1); this.rowsIndices = this.rowsIndices.map((value) => (value > rowIndex) ? --value : value); this.dataChange.emit(); } hasExpandableRows() { return this.data.some(data => data.some(d => d && d.expandedData)); // checking for some in 2D array } isRowExpandable(index) { return this.data[index].some(d => d && d.expandedData); } isRowExpanded(index) { return this.rowsExpanded[index]; } getRowContext(index) { return this.rowsContext[index]; } /** * Returns `index`th column of the table. * * Negative index starts from the end. -1 being the last element. * * @param index */ column(index) { let column = new Array(); const ri = this.realColumnIndex(index); const rc = this.data.length; for (let i = 0; i < rc; i++) { const row = this.data[i]; column.push(row[ri]); } return column; } /** * Adds a column to the `index`th column or appends to table if index not provided. * * If column is shorter than other columns or not provided, it will be padded with * empty `TableItem` elements. * * If column is longer than other columns, others will be extended to match so no data is lost. * * If called on an empty table with no parameters, it creates a 1x1 table. * * Negative index starts from the end. -1 being the last element. * * @param [column] * @param [index] */ addColumn(column, index) { // if table empty create table with row if (!this.data || this.data.length === 0 || this.data[0].length === 0) { let newData = new Array(); if (column == null) { newData.push([new TableItem()]); } else { for (let i = 0; i < column.length; i++) { let item = column[i]; newData.push([item]); } } this.data = newData; return; } let rc = this.data.length; // row count let ci = this.realColumnIndex(index); // append missing rows for (let i = 0; column != null && i < column.length - rc; i++) { this.addRow(); } rc = this.data.length; if (index == null) { // append to end for (let i = 0; i < rc; i++) { let row = this.data[i]; row.push(column == null || column[i] == null ? new TableItem() : column[i]); } // update header if not already set by user if (this.header.length < this.data[0].length) { this.header.push(new TableHeaderItem()); } } else { if (index >= this.data[0].length) { // if trying to append ci++; } // insert for (let i = 0; i < rc; i++) { let row = this.data[i]; row.splice(ci, 0, column == null || column[i] == null ? new TableItem() : column[i]); } // update header if not already set by user if (this.header.length < this.data[0].length) { this.header.splice(ci, 0, new TableHeaderItem()); } } this.dataChange.emit(); } /** * Deletes `index`th column. * * Negative index starts from the end. -1 being the last element. * * @param index */ deleteColumn(index) { const rci = this.realColumnIndex(index); const rowCount = this.data.length; for (let i = 0; i < rowCount; i++) { this.data[i].splice(rci, 1); } // update header if not already set by user if (this.header.length > this.data[0].length) { this.header.splice(rci, 1); } this.dataChange.emit(); } moveColumn(indexFrom, indexTo) { const headerFrom = this.header[indexFrom]; this.addColumn(this.column(indexFrom), indexTo); this.deleteColumn(indexFrom + (indexTo < indexFrom ? 1 : 0)); this.header[indexTo + (indexTo > indexFrom ? -1 : 0)] = headerFrom; } /** * cycle through the three sort states * @param index */ cycleSortState(index) { // no sort provided so do the simple sort switch (this.header[index].sortDirection) { case "ASCENDING": this.header[index].sortDirection = "DESCENDING"; break; case "DESCENDING": this.header[index].sortDirection = "NONE"; break; default: this.header[index].sortDirection = "ASCENDING"; break; } } /** * Sorts the data currently present in the model based on `compare()` * * Direction is set by `ascending` and `descending` properties of `TableHeaderItem` * in `index`th column. * * @param index The column based on which it's sorting */ sort(index) { this.pushRowStateToModelData(); const headerSorted = this.header[index].sorted; // We only allow sorting by a single column, so reset sort state for all columns before specifying new sort state this.header.forEach(column => column.sorted = false); if (this.header[index].sortDirection === "NONE" && headerSorted) { // Restore initial order of rows const oldData = this._data; this._data = []; for (let i = 0; i < this.rowsIndices.length; i++) { const ri = this.rowsIndices[i]; this._data[ri] = oldData[i]; } } else { const descending = this.header[index].sortDirection === "DESCENDING" ? -1 : 1; this.data.sort((a, b) => { return descending * this.header[index].compare(a[index], b[index]); }); this.header[index].sorted = true; } this.popRowStateFromModelData(); } /** * Appends `rowsSelected` and `rowsExpanded` info to model data. * * When sorting rows, do this first so information about row selection * gets sorted with the other row info. * * Call `popRowSelectionFromModelData()` after sorting to make everything * right with the world again. */ pushRowStateToModelData() { for (let i = 0; i < this.data.length; i++) { const rowSelectedMark = new TableItem(); rowSelectedMark.data = this.rowsSelected[i]; this.data[i].push(rowSelectedMark); const rowExpandedMark = new TableItem(); rowExpandedMark.data = this.rowsExpanded[i]; this.data[i].push(rowExpandedMark); const rowContext = new TableItem(); rowContext.data = this.rowsContext[i]; this.data[i].push(rowContext); const rowClass = new TableItem(); rowClass.data = this.rowsClass[i]; this.data[i].push(rowClass); const rowIndex = new TableItem(); rowIndex.data = this.rowsIndices[i]; this.data[i].push(rowIndex); } } /** * Restores `rowsSelected` from data pushed by `pushRowSelectionToModelData()` * * Call after sorting data (if you previously pushed to maintain selection order) * to make everything right with the world again. */ popRowStateFromModelData() { for (let i = 0; i < this.data.length; i++) { this.rowsIndices[i] = this.data[i].pop().data; this.rowsClass[i] = this.data[i].pop().data; this.rowsContext[i] = this.data[i].pop().data; this.rowsExpanded[i] = !!this.data[i].pop().data; this.rowsSelected[i] = !!this.data[i].pop().data; } } /** * Checks if row is filtered out. * * @param index * @returns true if any of the filters in header filters out the `index`th row */ isRowFiltered(index) { const realIndex = this.realRowIndex(index); return this.header.some((item, i) => item && item.filter(this.row(realIndex)[i])); } /** * Select/deselect `index`th row based on value * * @param index index of the row to select * @param value state to set the row to. Defaults to `true` */ selectRow(index, value = true) { if (this.isRowDisabled(index)) { return; } this.rowsSelected[index] = value; this.rowsSelectedChange.emit(index); } /** * Selects or deselects all rows in the model * * @param value state to set all rows to. Defaults to `true` */ selectAll(value = true) { if (this.data.length >= 1 && this.data[0].length >= 1) { for (let i = 0; i < this.rowsSelected.length; i++) { this.selectRow(i, value); } } this.selectAllChange.next(value); } isRowSelected(index) { return this.rowsSelected[index]; } /** * Checks if row is disabled or not. */ isRowDisabled(index) { const row = this.data[index]; return !!row.disabled; } /** * Expands/Collapses `index`th row based on value * * @param index index of the row to expand or collapse * @param value expanded state of the row. `true` is expanded and `false` is collapsed */ expandRow(index, value = true) { this.rowsExpanded[index] = value; this.rowsExpandedChange.emit(index); } /** * Gets the true index of a row based on it's relative position. * Like in Python, positive numbers start from the top and * negative numbers start from the bottom. * * @param index */ realRowIndex(index) { return this.realIndex(index, this.data.length); } /** * Gets the true index of a column based on it's relative position. * Like in Python, positive numbers start from the top and * negative numbers start from the bottom. * * @param index */ realColumnIndex(index) { return this.realIndex(index, this.data[0].length); } /** * Generic function to calculate the real index of something. * Used by `realRowIndex()` and `realColumnIndex()` * * @param index * @param length */ realIndex(index, length) { if (index == null) { return length - 1; } else if (index >= 0) { return index >= length ? length - 1 : index; } else { return -index >= length ? 0 : length + index; } } } /** * The number of models instantiated, used for (among other things) unique id generation */ TableModel.COUNT = 0; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUtbW9kZWwuY2xhc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdGFibGUvdGFibGUtbW9kZWwuY2xhc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUc3QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRS9DLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFJL0I7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQXNLdEI7UUE3SEEsZUFBVSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFDaEMsdUJBQWtCLEdBQUcsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUNoRCx1QkFBa0IsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBQ2hEOzs7V0FHRztRQUNILG9CQUFlLEdBQUcsSUFBSSxPQUFPLEVBQVcsQ0FBQztRQVl6Qzs7V0FFRztRQUNILGlCQUFZLEdBQWMsRUFBRSxDQUFDO1FBRTdCOztXQUVHO1FBQ0gsaUJBQVksR0FBYyxFQUFFLENBQUM7UUFFN0I7O1dBRUc7UUFDSCxnQkFBVyxHQUFhLEVBQUUsQ0FBQztRQUUzQjs7Ozs7OztXQU9HO1FBQ0gsZ0JBQVcsR0FBYSxFQUFFLENBQUM7UUFFM0I7Ozs7OztXQU1HO1FBQ0gsY0FBUyxHQUFhLEVBQUUsQ0FBQztRQUV6Qjs7V0FFRztRQUNILFdBQU0sR0FBc0IsRUFBRSxDQUFDO1FBRS9COztXQUVHO1FBQ0gsZ0JBQVcsR0FBRyxDQUFDLENBQUM7UUFFaEI7O1dBRUc7UUFDSCxlQUFVLEdBQUcsRUFBRSxDQUFDO1FBRWhCOztXQUVHO1FBQ0gsVUFBSyxHQUFHLEtBQUssQ0FBQztRQUVkOztXQUVHO1FBQ0gsY0FBUyxHQUFHLEtBQUssQ0FB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LENBQUM7WUFDNUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7WUFFbkMsTUFBTSxVQUFVLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNuQyxVQUFVLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdEMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7WUFFOUIsTUFBTSxRQUFRLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNqQyxRQUFRLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbEMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7WUFFNUIsTUFBTSxRQUFRLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNqQyxRQUFRLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDNUI7SUFDRixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCx3QkFBd0I7UUFDdkIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUM7WUFDOUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFD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QUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ08sU0FBUyxDQUFDLEtBQWEsRUFBRSxNQUFjO1FBQ2hELElBQUksS0FBSyxJQUFJLElBQUksRUFBRTtZQUNsQixPQUFPLE1BQU0sR0FBRyxDQUFDLENBQUM7U0FDbEI7YUFBTSxJQUFJLEtBQUssSUFBSSxDQUFDLEVBQUU7WUFDdEIsT0FBTyxLQUFLLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7U0FDNUM7YUFBTTtZQUNOLE9BQU8sQ0FBQyxLQUFLLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7U0FDN0M7SUFDRixDQUFDOztBQTVzQkQ7O0dBRUc7QUFDYyxnQkFBSyxHQUFHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5cbmltcG9ydCB7IFBhZ2luYXRpb25Nb2RlbCB9IGZyb20gXCJjYXJib24tY29tcG9uZW50cy1hbmd1bGFyL3BhZ2luYXRpb25cIjtcbmltcG9ydCB7IFRhYmxlSGVhZGVySXRlbSB9IGZyb20gXCIuL3RhYmxlLWhlYWRlci1pdGVtLmNsYXNzXCI7XG5pbXBvcnQgeyBUYWJsZUl0ZW0gfSBmcm9tIFwiLi90YWJsZS1pdGVtLmNsYXNzXCI7XG5pbXBvcnQgeyBUYWJsZVJvdyB9IGZyb20gXCIuL3RhYmxlLXJvdy5jbGFzc1wiO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gXCJyeGpzXCI7XG5cbmV4cG9ydCB0eXBlIEhlYWRlclR5cGUgPSBudW1iZXIgfCBcInNlbGVjdFwiIHwgXCJleHBhbmRcIjtcblxuLyoqXG4gKiBUYWJsZU1vZGVsIHJlcHJlc2VudHMgYSBkYXRhIG1vZGVsIGZvciB0d28tZGltZW5zaW9uYWwgZGF0YS4gSXQncyB1c2VkIGZvciBhbGwgdGhpbmdzIHRhYmxlXG4gKiAodGFibGUgY29tcG9uZW50LCB0YWJsZSB0b29sYmFyLCBwYWdpbmF0aW9uLCBldGMpXG4gKlxuICogVGFibGVNb2RlbCBtYW5hZ2VzIGl0cyBpbnRlcm5hbCBkYXRhIGludGVncml0eSB2ZXJ5IHdlbGwgaWYgeW91IHVzZSB0aGUgcHJvdmlkZWQgaGVscGVyXG4gKiBmdW5jdGlvbnMgZm9yIG1vZGlmeWluZyByb3dzIGFuZCBjb2x1bW5zIGFuZCBhc3NpZ25pbmcgaGVhZGVyIGFuZCBkYXRhIGluIHRoYXQgb3JkZXIuXG4gKlxuICogSXQgYWxzbyBwcm92aWRlcyBkaXJlY3QgYWNjZXNzIHRvIHRoZSBkYXRhIHNvIHlvdSBjYW4gcmVhZCBhbmQgbW9kaWZ5IGl0LlxuICogSWYgeW91IGNoYW5nZSB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhIChieSBkaXJlY3RseSBwdXNoaW5nIGludG8gdGhlIGFycmF5cyBvciBvdGhlcndpc2UpLFxuICoga2VlcCBpbiBtaW5kIHRvIGtlZXAgdGhlIGRhdGEgc3RydWN0dXJlIGludGFjdC5cbiAqXG4gKiBIZWFkZXIgbGVuZ3RoIGFuZCBsZW5ndGggb2YgZXZlcnkgbGluZSBpbiB0aGUgZGF0YSBzaG91bGQgYmUgZXF1YWwuXG4gKlxuICogSWYgdGhleSBhcmUgbm90IGNvbnNpc3RlbnQsIHVuZXhwZWN0ZWQgdGhpbmdzIHdpbGwgaGFwcGVuLlxuICpcbiAqIFVzZSB0aGUgcHJvdmlkZWQgZnVuY3Rpb25zIHdoZW4gaW4gZG91YnQuXG4gKi9cbmV4cG9ydCBjbGFzcyBUYWJsZU1vZGVsIGltcGxlbWVudHMgUGFnaW5hdGlvbk1vZGVsIHtcblx0LyoqXG5cdCAqIFRoZSBudW1iZXIgb2YgbW9kZWxzIGluc3RhbnRpYXRlZCwgdXNlZCBmb3IgKGFtb25nIG90aGVyIHRoaW5ncykgdW5pcXVlIGlkIGdlbmVyYXRpb25cblx0ICovXG5cdHByb3RlY3RlZCBzdGF0aWMgQ09VTlQgPSAwO1xuXG5cdC8qKlxuXHQgKiBTZXRzIGRhdGEgb2YgdGhlIHRhYmxlLlxuXHQgKlxuXHQgKiBNYWtlIHN1cmUgYWxsIHJvd3MgYXJlIHRoZSBzYW1lIGxlbmd0aCB0byBrZWVwIHRoZSBjb2x1bW4gY291bnQgYWNjdXJhdGUuXG5cdCAqL1xuXHRzZXQgZGF0YShuZXdEYXRhOiBUYWJsZUl0ZW1bXVtdKSB7XG5cdFx0aWYgKCFuZXdEYXRhIHx8IChBcnJheS5pc0FycmF5KG5ld0RhdGEpICYmIG5ld0RhdGEubGVuZ3RoID09PSAwKSkge1xuXHRcdFx0bmV3RGF0YSA9IFtbXV07XG5cdFx0fVxuXG5cdFx0dGhpcy5fZGF0YSA9IG5ld0RhdGE7XG5cblx0XHQvLyBpbml0IHJvd3NTZWxlY3RlZFxuXHRcdHRoaXMucm93c1NlbGVjdGVkID0gbmV3IEFycmF5PGJvb2xlYW4+KHRoaXMuX2RhdGEubGVuZ3RoKS5maWxsKGZhbHNlKTtcblx0XHR0aGlzLnJvd3NFeHBhbmRlZCA9IG5ldyBBcnJheTxib29sZWFuPih0aGlzLl9kYXRhLmxlbmd0aCkuZmlsbChmYWxzZSk7XG5cdFx0Ly8gaW5pdCByb3dzIGluZGljZXNcblx0XHR0aGlzLnJvd3NJbmRpY2VzID0gWy4uLkFycmF5KHRoaXMuX2RhdGEubGVuZ3RoKS5rZXlzKCldO1xuXHRcdC8vIGluaXQgcm93c0NvbnRleHRcblx0XHR0aGlzLnJvd3NDb250ZXh0ID0gbmV3IEFycmF5PHN0cmluZz4odGhpcy5fZGF0YS5sZW5ndGgpO1xuXG5cdFx0Ly8gaW5pdCByb3dzQ2xhc3Ncblx0XHR0aGlzLnJvd3NDbGFzcyA9IG5ldyBBcnJheTxzdHJpbmc+KHRoaXMuX2RhdGEubGVuZ3RoKTtcblxuXHRcdC8vIG9ubHkgY3JlYXRlIGEgZnJlc2ggaGVhZGVyIGlmIG5lY2Vzc2FyeSAoaGVhZGVyIGRvZXNuJ3QgZXhpc3Qgb3IgZGlmZmVycyBpbiBsZW5ndGgpXG5cdFx0aWYgKHRoaXMuaGVhZGVyID09IG51bGwgfHwgKHRoaXMuaGVhZGVyLmxlbmd0aCAhPT0gdGhpcy5fZGF0YVswXS5sZW5ndGggJiYgdGhpcy5fZGF0YVswXS5sZW5ndGggPiAwKSkge1xuXHRcdFx0bGV0IGhlYWRlciA9IG5ldyBBcnJheTxUYWJsZUhlYWRlckl0ZW0+KCk7XG5cdFx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuX2RhdGFbMF0ubGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0aGVhZGVyLnB1c2gobmV3IFRhYmxlSGVhZGVySXRlbSgpKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuaGVhZGVyID0gaGVhZGVyO1xuXHRcdH1cblxuXHRcdHRoaXMuZGF0YUNoYW5nZS5lbWl0KCk7XG5cdH1cblxuXHRkYXRhQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXHRyb3dzU2VsZWN0ZWRDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcblx0cm93c0V4cGFuZGVkQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cdC8qKlxuXHQgKiBHZXRzIGVtaXR0ZWQgd2hlbiBgc2VsZWN0QWxsYCBpcyBjYWxsZWQuIEVtaXRzIGZhbHNlIGlmIGFsbCByb3dzIGFyZSBkZXNlbGVjdGVkIGFuZCB0cnVlIGlmXG5cdCAqIGFsbCByb3dzIGFyZSBzZWxlY3RlZC5cblx0ICovXG5cdHNlbGVjdEFsbENoYW5nZSA9IG5ldyBTdWJqZWN0PGJvb2xlYW4+KCk7XG5cblx0LyoqXG5cdCAqIEdldHMgdGhlIGZ1bGwgZGF0YS5cblx0ICpcblx0ICogWW91IGNhbiB1c2UgaXQgdG8gYWx0ZXIgaW5kaXZpZHVhbCBgVGFibGVJdGVtYHMgYnV0IGlmIHlvdSBuZWVkIHRvIGNoYW5nZVxuXHQgKiB0YWJsZSBzdHJ1Y3R1cmUsIHVzZSBgYWRkUm93KClgIGFuZC9vciBgYWRkQ29sdW1uKClgXG5cdCAqL1xuXHRnZXQgZGF0YSgpIHtcblx0XHRyZXR1cm4gdGhpcy5fZGF0YTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCBzZWxlY3Rpb24gc3RhdGUgb2Ygcm93cyBpbiB0aGUgdGFibGUuXG5cdCAqL1xuXHRyb3dzU2VsZWN0ZWQ6IGJvb2xlYW5bXSA9IFtdO1xuXG5cdC8qKlxuXHQgKiBDb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCBleHBhbmRlZCBzdGF0ZSBvZiByb3dzIGluIHRoZSB0YWJsZS5cblx0ICovXG5cdHJvd3NFeHBhbmRlZDogYm9vbGVhbltdID0gW107XG5cblx0LyoqXG5cdCAqIENvbnRhaW5zIGluZm9ybWF0aW9uIGFib3V0IGluaXRpYWwgaW5kZXggb2Ygcm93cyBpbiB0aGUgdGFibGVcblx0ICovXG5cdHJvd3NJbmRpY2VzOiBudW1iZXJbXSA9IFtdO1xuXG5cdC8qKlxuXHQgKiBDb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY29udGV4dCBvZiB0aGUgcm93LlxuXHQgKlxuXHQgKiBJdCBhZmZlY3RzIHN0eWxpbmcgb2YgdGhlIHJvdyB0byByZWZsZWN0IHRoZSBjb250ZXh0LlxuXHQgKlxuXHQgKiBzdHJpbmcgY2FuIGJlIG9uZSBvZiBgXCJzdWNjZXNzXCIgfCBcIndhcm5pbmdcIiB8IFwiaW5mb1wiIHwgXCJlcnJvclwiIHwgXCJcImAgYW5kIGl0J3Ncblx0ICogZW1wdHkgb3IgdW5kZWZpbmVkIGJ5IGRlZmF1bHRcblx0ICovXG5cdHJvd3NDb250ZXh0OiBzdHJpbmdbXSA9IFtdO1xuXG5cdC8qKlxuXHQgKiBDb25