carbon-components-angular
Version:
Next generation components
654 lines • 74.2 kB
JavaScript
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