carbon-components-angular
Version:
Next generation components
290 lines • 32.1 kB
JavaScript
/**
* An abstract class that represents a cell in a table
*/
export class TableCellAdapter {
}
/**
* An abstract class that represents a row in a table
*/
export class TableRowAdapter {
}
/**
* An abstract representation of a table that provides
* a standard interface to query 2d tables for cell and row information.
*/
export class TableAdapter {
/**
* The last accessible column in the table
*/
get lastColumnIndex() { return; }
/**
* The last accessible row in the table
*/
get lastRowIndex() { return; }
/**
* Returns a cell from the table
*
* @param row index of the row
* @param column index of the column
*/
getCell(row, column) { return; }
/**
* Returns a row from the table
*
* @param column index of the column
*/
getColumn(column) { return; }
/**
* Returns a row from the table
*
* @param row index of the row
*/
getRow(row) { return; }
/**
* Finds the column index of a given cell
*
* @param cell the cell to search for
*/
findColumnIndex(cell) { return; }
/**
* Finds the row index of a given cell
*
* @param cell the cell to search for
*/
findRowIndex(cell) { return; }
/**
* Finds the row and column index of a given cell
*
* @param cell the cell to search for
* @returns a tuple that follows the `[row, column]` convention
*/
findIndex(cell) { return; }
}
var TableDomSpanDirection;
(function (TableDomSpanDirection) {
TableDomSpanDirection["colSpan"] = "colSpan";
TableDomSpanDirection["rowSpan"] = "rowSpan";
})(TableDomSpanDirection || (TableDomSpanDirection = {}));
/**
* A concrete implementation of `TableAdapter`
*
* Provides standard and consistent access to table cells and rows
*/
export class TableDomAdapter {
/**
* `TableDomAdapter` works on a normal HTML table structure.
* Custom tables that don't follow the standard structure should use a custom implementation of `TableAdapter`.
*
* The standard structure allows us to directly query rows for cells and indexes - though we do have to handle colspans specially.
*
* @param tableElement the root HTML table element.
*/
constructor(tableElement) {
this.tableElement = tableElement;
}
/**
* The last accessible column in the table
*/
get lastColumnIndex() {
return this.getRealRowLength(this.tableElement.rows[0]);
}
/**
* The last accessible row in the table
*/
get lastRowIndex() {
return this.tableElement.rows.length - 1;
}
/**
* Returns a cell from the table taking colspans in to account.
*
* @param row index of the row
* @param column index of the column
*/
getCell(row, column) {
const col = this.getColumn(column);
return this.findCellInColumn(col, row).cell;
}
/**
* Returns a column from the table, using the `id` and `headers` attributes
*
* See here for more detail these attributes: https://www.w3.org/TR/WCAG20-TECHS/H43.html
*
* @param column the index of the column
*/
getColumn(column) {
const firstHeader = Array.from(this.tableElement.rows[0].cells);
const { cell: header, realIndex: realColumnIndex } = this.findCellInRow(firstHeader, column);
const linkedCells = [];
for (let i = 1; i < this.tableElement.rows.length; i++) {
const row = this.tableElement.rows[i];
// query for any cells that are linked to the given header id
// `~=` matches values in space separated lists - so `[headers~='foo']` would match `headers="foo bar"` and `headers="foo"`
// but not `headers="bar"` or `headers="bar baz"`
const linkedRowCells = row.querySelectorAll(`[headers~='${header.id}']`);
// if we have more than one cell, get the one that is closest to the column
if (linkedRowCells.length > 1) {
const { cell } = this.findCellInRow(Array.from(linkedRowCells), column - realColumnIndex);
linkedCells.push(cell);
}
else if (linkedRowCells[0]) {
linkedCells.push(linkedRowCells[0]);
}
}
// return an empty array if we can't find any linked cells
// returning anything else would be a lie
if (!linkedCells) {
return [];
}
return [header, ...linkedCells];
}
/**
* Returns a row from the table
*
* @param row index of the row
*/
getRow(row) {
return this.tableElement.rows[row];
}
/**
* Finds the column index of a given cell
*
* @param cell the cell to search for
*/
findColumnIndex(cell) {
const row = this.getRow(this.findRowIndex(cell));
if (!row) {
return;
}
// if the cell has linked headers we can do a more accurate lookup
if (cell && cell.headers) {
const ids = cell.headers.split(" ");
const headerRows = Array.from(this.tableElement.tHead.rows);
const indexes = [];
// start from the last row and work up
for (const headerRow of headerRows.reverse()) {
const headerCells = Array.from(headerRow.cells);
const header = headerCells.find(headerCell => ids.includes(headerCell.id));
// if we have a matching header, find it's index (adjusting for colspans)
if (header) {
// this is borrowed from below
let cellIndex = 0;
for (const c of headerCells) {
if (c === header) {
break;
}
cellIndex += c.colSpan;
}
indexes.push(cellIndex);
}
}
// sort the indexes largest to smallest to find the closest matching header index
const firstIndex = indexes.sort((a, b) => b - a)[0];
// search the row for cells that share the header
let similarCells = [];
for (const id of ids) {
// there's no selector that will match two space separated lists,
// so we have to iterate through the ids and query the row for each
const rowCells = Array.from(row.querySelectorAll(`[headers~='${id}']`));
for (const rowCell of rowCells) {
// only keep one set of cells
if (!similarCells.includes(rowCell)) {
similarCells.push(rowCell);
}
}
}
// DOM order is not preserved, so we have to sort the row
similarCells = similarCells.sort((a, b) => a.cellIndex - b.cellIndex);
// return the header index plus any adjustment within that headers column
return firstIndex + similarCells.indexOf(cell);
}
// fallback if the cell isn't linked to any headers
let cellIndex = 0;
for (const c of Array.from(row.cells)) {
if (c === cell) {
break;
}
cellIndex += c.colSpan;
}
return cellIndex;
}
/**
* Finds the row index of a given cell
*
* @param cell the cell to search for
*/
findRowIndex(cell) {
for (const row of Array.from(this.tableElement.rows)) {
if (row.contains(cell)) {
return row.rowIndex;
}
}
}
/**
* Finds the row and column index of a given cell
*
* @param cell the cell to search for
* @returns a tuple that follows the `[row, column]` convention
*/
findIndex(cell) {
return [this.findRowIndex(cell), this.findColumnIndex(cell)];
}
/**
* Helper function that returns the "real" length of a row.
* Only accurate with regard to colspans (though that's sufficient for it's uses here)
*
* TODO: Take rowSpan into account
*
* @param row the row to get the length of
*/
getRealRowLength(row) {
// start at -1 since the colspans will sum to 1 index greater than the total
return Array.from(row.cells).reduce((count, cell) => count + cell.colSpan, -1);
}
/**
* Finds a cell and it's real index given an array of cells, a target index, and the spanning direction
*
* @param cells An array of cells to search
* @param targetIndex The index we think the cell is located at
* @param spanDirection The direction of the cell spans. Should be `"colSpan"` for a row and `"rowSpan"` for a column
*/
findCell(cells, targetIndex, spanDirection) {
// rows/cols can have fewer total cells than the actual table
// the model pretends all rows/cols behave the same (with col/row spans > 1 being N cells long)
// this maps that view to the HTML view (col/row spans > 1 are one element, so the array is shorter)
let realIndex = 0;
// i is only used for iterating the cells
for (let i = 0; i < targetIndex;) {
// skip the next N cells
i += cells[realIndex][spanDirection];
// don't bump realIndex if i now exceeds the cell we're shooting for
if (i > targetIndex) {
break;
}
// finally, increment realIndex (to keep it generally in step with i)
realIndex++;
}
return {
cell: cells[realIndex],
realIndex
};
}
/**
* Helper method around `findCell`, searches based on a row of cells
*
* @param row the row of elements to search
* @param index the index of the element
*/
findCellInRow(row, index) {
return this.findCell(row, index, TableDomSpanDirection.colSpan);
}
/**
* Helper method around `findCell`, searches based on a column of cells
*
* @param col the column of elements to search
* @param index the index of the element
*/
findCellInColumn(col, index) {
return this.findCell(col, index, TableDomSpanDirection.rowSpan);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUtYWRhcHRlci5jbGFzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90YWJsZS90YWJsZS1hZGFwdGVyLmNsYXNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxPQUFnQixnQkFBZ0I7Q0FhckM7QUFFRDs7R0FFRztBQUNILE1BQU0sT0FBZ0IsZUFBZTtDQVNwQztBQUVEOzs7R0FHRztBQUNILE1BQU0sT0FBZ0IsWUFBWTtJQUNqQzs7T0FFRztJQUNILElBQVcsZUFBZSxLQUFhLE9BQU8sQ0FBQyxDQUFDO0lBRWhEOztPQUVHO0lBQ0gsSUFBVyxZQUFZLEtBQWEsT0FBTyxDQUFDLENBQUM7SUFFN0M7Ozs7O09BS0c7SUFDSCxPQUFPLENBQUMsR0FBVyxFQUFFLE1BQWMsSUFBc0IsT0FBTyxDQUFDLENBQUM7SUFFbEU7Ozs7T0FJRztJQUNILFNBQVMsQ0FBQyxNQUFjLElBQXdCLE9BQU8sQ0FBQyxDQUFDO0lBRXpEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsR0FBVyxJQUFxQixPQUFPLENBQUMsQ0FBQztJQUVoRDs7OztPQUlHO0lBQ0gsZUFBZSxDQUFDLElBQXNCLElBQVksT0FBTyxDQUFDLENBQUM7SUFFM0Q7Ozs7T0FJRztJQUNILFlBQVksQ0FBQyxJQUFzQixJQUFZLE9BQU8sQ0FBQyxDQUFDO0lBRXhEOzs7OztPQUtHO0lBQ0gsU0FBUyxDQUFDLElBQXNCLElBQXNCLE9BQU8sQ0FBQyxDQUFDO0NBQy9EO0FBRUQsSUFBSyxxQkFHSjtBQUhELFdBQUsscUJBQXFCO0lBQ3pCLDRDQUFtQixDQUFBO0lBQ25CLDRDQUFtQixDQUFBO0FBQ3BCLENBQUMsRUFISSxxQkFBcUIsS0FBckIscUJBQXFCLFFBR3pCO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBZTNCOzs7Ozs7O09BT0c7SUFDSCxZQUFtQixZQUE4QjtRQUE5QixpQkFBWSxHQUFaLFlBQVksQ0FBa0I7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QUtHO0lBQ08sZ0JBQWdCLENBQUMsR0FBMkIsRUFBRSxLQUFhO1FBQ3BFLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2pFLENBQUM7Q0FDRCIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQW4gYWJzdHJhY3QgY2xhc3MgdGhhdCByZXByZXNlbnRzIGEgY2VsbCBpbiBhIHRhYmxlXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBUYWJsZUNlbGxBZGFwdGVyIHtcblx0LyoqXG5cdCAqIFRoZSBpbmRleCBvZiB0aGUgY2VsbCBpbiB0aGUgdGFibGVcblx0ICovXG5cdGNlbGxJbmRleDogbnVtYmVyO1xuXHQvKipcblx0ICogVGhlIG51bWJlciBvZiBjb2x1bW5zIHNwYW5uZWQgYnkgdGhpcyBjZWxsXG5cdCAqL1xuXHRjb2xTcGFuOiBudW1iZXI7XG5cdC8qKlxuXHQgKiBUaGUgbnVtYmVyIG9mIHJvd3Mgc3Bhbm5lZCBieSB0aGlzIGNlbGxcblx0ICovXG5cdHJvd1NwYW46IG51bWJlcjtcbn1cblxuLyoqXG4gKiBBbiBhYnN0cmFjdCBjbGFzcyB0aGF0IHJlcHJlc2VudHMgYSByb3cgaW4gYSB0YWJsZVxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgVGFibGVSb3dBZGFwdGVyIHtcblx0LyoqXG5cdCAqIFRoZSBpbmRleCBvZiB0aGUgcm93IGluIHRoZSB0YWJsZVxuXHQgKi9cblx0cm93SW5kZXg6IG51bWJlcjtcblx0LyoqXG5cdCAqIEFuIGFycmF5IChvciBgSFRNTENvbGxlY3Rpb25gKSBvZiBgVGFibGVDZWxsQWRhcHRlcmBzXG5cdCAqL1xuXHRjZWxsczogSFRNTENvbGxlY3Rpb24gfCBUYWJsZUNlbGxBZGFwdGVyW107XG59XG5cbi8qKlxuICogQW4gYWJzdHJhY3QgcmVwcmVzZW50YXRpb24gb2YgYSB0YWJsZSB0aGF0IHByb3ZpZGVzXG4gKiBhIHN0YW5kYXJkIGludGVyZmFjZSB0byBxdWVyeSAyZCB0YWJsZXMgZm9yIGNlbGwgYW5kIHJvdyBpbmZvcm1hdGlvbi5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFRhYmxlQWRhcHRlciB7XG5cdC8qKlxuXHQgKiBUaGUgbGFzdCBhY2Nlc3NpYmxlIGNvbHVtbiBpbiB0aGUgdGFibGVcblx0ICovXG5cdHB1YmxpYyBnZXQgbGFzdENvbHVtbkluZGV4KCk6IG51bWJlciB7IHJldHVybjsgfVxuXG5cdC8qKlxuXHQgKiBUaGUgbGFzdCBhY2Nlc3NpYmxlIHJvdyBpbiB0aGUgdGFibGVcblx0ICovXG5cdHB1YmxpYyBnZXQgbGFzdFJvd0luZGV4KCk6IG51bWJlciB7IHJldHVybjsgfVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIGEgY2VsbCBmcm9tIHRoZSB0YWJsZVxuXHQgKlxuXHQgKiBAcGFyYW0gcm93IGluZGV4IG9mIHRoZSByb3dcblx0ICogQHBhcmFtIGNvbHVtbiBpbmRleCBvZiB0aGUgY29sdW1uXG5cdCAqL1xuXHRnZXRDZWxsKHJvdzogbnVtYmVyLCBjb2x1bW46IG51bWJlcik6IFRhYmxlQ2VsbEFkYXB0ZXIgeyByZXR1cm47IH1cblxuXHQvKipcblx0ICogUmV0dXJucyBhIHJvdyBmcm9tIHRoZSB0YWJsZVxuXHQgKlxuXHQgKiBAcGFyYW0gY29sdW1uIGluZGV4IG9mIHRoZSBjb2x1bW5cblx0ICovXG5cdGdldENvbHVtbihjb2x1bW46IG51bWJlcik6IFRhYmxlQ2VsbEFkYXB0ZXJbXSB7IHJldHVybjsgfVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIGEgcm93IGZyb20gdGhlIHRhYmxlXG5cdCAqXG5cdCAqIEBwYXJhbSByb3cgaW5kZXggb2YgdGhlIHJvd1xuXHQgKi9cblx0Z2V0Um93KHJvdzogbnVtYmVyKTogVGFibGVSb3dBZGFwdGVyIHsgcmV0dXJuOyB9XG5cblx0LyoqXG5cdCAqIEZpbmRzIHRoZSBjb2x1bW4gaW5kZXggb2YgYSBnaXZlbiBjZWxsXG5cdCAqXG5cdCAqIEBwYXJhbSBjZWxsIHRoZSBjZWxsIHRvIHNlYXJjaCBmb3Jcblx0ICovXG5cdGZpbmRDb2x1bW5JbmRleChjZWxsOiBUYWJsZUNlbGxBZGFwdGVyKTogbnVtYmVyIHsgcmV0dXJuOyB9XG5cblx0LyoqXG5cdCAqIEZpbmRzIHRoZSByb3cgaW5kZXggb2YgYSBnaXZlbiBjZWxsXG5cdCAqXG5cdCAqIEBwYXJhbSBjZWxsIHRoZSBjZWxsIHRvIHNlYXJjaCBmb3Jcblx0ICovXG5cdGZpbmRSb3dJbmRleChjZWxsOiBUYWJsZUNlbGxBZGFwdGVyKTogbnVtYmVyIHsgcmV0dXJuOyB9XG5cblx0LyoqXG5cdCAqIEZpbmRzIHRoZSByb3cgYW5kIGNvbHVtbiBpbmRleCBvZiBhIGdpdmVuIGNlbGxcblx0ICpcblx0ICogQHBhcmFtIGNlbGwgdGhlIGNlbGwgdG8gc2VhcmNoIGZvclxuXHQgKiBAcmV0dXJucyBhIHR1cGxlIHRoYXQgZm9sbG93cyB0aGUgYFtyb3csIGNvbHVtbl1gIGNvbnZlbnRpb25cblx0ICovXG5cdGZpbmRJbmRleChjZWxsOiBUYWJsZUNlbGxBZGFwdGVyKTogW251bWJlciwgbnVtYmVyXSB7IHJldHVybjsgfVxufVxuXG5lbnVtIFRhYmxlRG9tU3BhbkRpcmVjdGlvbiB7XG5cdGNvbFNwYW4gPSBcImNvbFNwYW5cIixcblx0cm93U3BhbiA9IFwicm93U3BhblwiXG59XG5cbi8qKlxuICogQSBjb25jcmV0ZSBpbXBsZW1lbnRhdGlvbiBvZiBgVGFibGVBZGFwdGVyYFxuICpcbiAqIFByb3ZpZGVzIHN0YW5kYXJkIGFuZCBjb25zaXN0ZW50IGFjY2VzcyB0byB0YWJsZSBjZWxscyBhbmQgcm93c1xuICovXG5leHBvcnQgY2xhc3MgVGFibGVEb21BZGFwdGVyIGltcGxlbWVudHMgVGFibGVBZGFwdGVyIHtcblx0LyoqXG5cdCAqIFRoZSBsYXN0IGFjY2Vzc2libGUgY29sdW1uIGluIHRoZSB0YWJsZVxuXHQgKi9cblx0cHVibGljIGdldCBsYXN0Q29sdW1uSW5kZXgoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0UmVhbFJvd0xlbmd0aCh0aGlzLnRhYmxlRWxlbWVudC5yb3dzWzBdKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBUaGUgbGFzdCBhY2Nlc3NpYmxlIHJvdyBpbiB0aGUgdGFibGVcblx0ICovXG5cdHB1YmxpYyBnZXQgbGFzdFJvd0luZGV4KCkge1xuXHRcdHJldHVybiB0aGlzLnRhYmxlRWxlbWVudC5yb3dzLmxlbmd0aCAtIDE7XG5cdH1cblxuXHQvKipcblx0ICogYFRhYmxlRG9tQWRhcHRlcmAgd29ya3Mgb24gYSBub3JtYWwgSFRNTCB0YWJsZSBzdHJ1Y3R1cmUuXG5cdCAqIEN1c3RvbSB0YWJsZXMgdGhhdCBkb24ndCBmb2xsb3cgdGhlIHN0YW5kYXJkIHN0cnVjdHVyZSBzaG91bGQgdXNlIGEgY3VzdG9tIGltcGxlbWVudGF0aW9uIG9mIGBUYWJsZUFkYXB0ZXJgLlxuXHQgKlxuXHQgKiBUaGUgc3RhbmRhcmQgc3RydWN0dXJlIGFsbG93cyB1cyB0byBkaXJlY3RseSBxdWVyeSByb3dzIGZvciBjZWxscyBhbmQgaW5kZXhlcyAtIHRob3VnaCB3ZSBkbyBoYXZlIHRvIGhhbmRsZSBjb2xzcGFucyBzcGVjaWFsbHkuXG5cdCAqXG5cdCAqIEBwYXJhbSB0YWJsZUVsZW1lbnQgdGhlIHJvb3QgSFRNTCB0YWJsZSBlbGVtZW50LlxuXHQgKi9cblx0Y29uc3RydWN0b3IocHVibGljIHRhYmxlRWxlbWVudDogSFRNTFRhYmxlRWxlbWVudCkgeyB9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgYSBjZWxsIGZyb20gdGhlIHRhYmxlIHRha2luZyBjb2xzcGFucyBpbiB0byBhY2NvdW50LlxuXHQgKlxuXHQgKiBAcGFyYW0gcm93IGluZGV4IG9mIHRoZSByb3dcblx0ICogQHBhcmFtIGNvbHVtbiBpbmRleCBvZiB0aGUgY29sdW1uXG5cdCAqL1xuXHRnZXRDZWxsKHJvdzogbnVtYmVyLCBjb2x1bW46IG51bWJlcik6IEhUTUxUYWJsZUNlbGxFbGVtZW50IHtcblx0XHRjb25zdCBjb2wgPSB0aGlzLmdldENvbHVtbihjb2x1bW4pO1xuXG5cdFx0cmV0dXJuIHRoaXMuZmluZENlbGxJbkNvbHVtbihjb2wsIHJvdykuY2VsbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIGEgY29sdW1uIGZyb20gdGhlIHRhYmxlLCB1c2luZyB0aGUgYGlkYCBhbmQgYGhlYWRlcnNgIGF0dHJpYnV0ZXNcblx0ICpcblx0ICogU2VlIGhlcmUgZm9yIG1vcmUgZGV0YWlsIHRoZXNlIGF0dHJpYnV0ZXM6IGh0dHBzOi8vd3d3LnczLm9yZy9UUi9XQ0FHMjAtVEVDSFMvSDQzLmh0bWxcblx0ICpcblx0ICogQHBhcmFtIGNvbHVtbiB0aGUgaW5kZXggb2YgdGhlIGNvbHVtblxuXHQgKi9cblx0Z2V0Q29sdW1uKGNvbHVtbjogbnVtYmVyKTogSFRNTFRhYmxlQ2VsbEVsZW1lbnRbXSB7XG5cdFx0Y29uc3QgZmlyc3RIZWFkZXIgPSBBcnJheS5mcm9tKHRoaXMudGFibGVFbGVtZW50LnJvd3NbMF0uY2VsbHMpO1xuXG5cdFx0Y29uc3QgeyBjZWxsOiBoZWFkZXIsIHJlYWxJbmRleDogcmVhbENvbHVtbkluZGV4IH0gPSB0aGlzLmZpbmRDZWxsSW5Sb3coZmlyc3RIZWFkZXIsIGNvbHVtbik7XG5cblx0XHRjb25zdCBsaW5rZWRDZWxsczogSFRNTFRhYmxlQ2VsbEVsZW1lbnRbXSA9IFtdO1xuXG5cdFx0Zm9yIChsZXQgaSA9IDE7IGkgPCB0aGlzLnRhYmxlRWxlbWVudC5yb3dzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRjb25zdCByb3cgPSB0aGlzLnRhYmxlRWxlbWVudC5yb3dzW2ldO1xuXHRcdFx0Ly8gcXVlcnkgZm9yIGFueSBjZWxscyB0aGF0IGFyZSBsaW5rZWQgdG8gdGhlIGdpdmVuIGhlYWRlciBpZFxuXHRcdFx0Ly8gYH49YCBtYXRjaGVzIHZhbHVlcyBpbiBzcGFjZSBzZXBhcmF0ZWQgbGlzdHMgLSBzbyBgW2hlYWRlcnN+PSdmb28nXWAgd291bGQgbWF0Y2ggYGhlYWRlcnM9XCJmb28gYmFyXCJgIGFuZCBgaGVhZGVycz1cImZvb1wiYFxuXHRcdFx0Ly8gYnV0IG5vdCBgaGVhZGVycz1cImJhclwiYCBvciBgaGVhZGVycz1cImJhciBiYXpcImBcblx0XHRcdGNvbnN0IGxpbmtlZFJvd0NlbGxzOiBOb2RlTGlzdE9mPEhUTUxUYWJsZUNlbGxFbGVtZW50PiA9IHJvdy5xdWVyeVNlbGVjdG9yQWxsKGBbaGVhZGVyc349JyR7aGVhZGVyLmlkfSddYCk7XG5cdFx0XHQvLyBpZiB3ZSBoYXZlIG1vcmUgdGhhbiBvbmUgY2VsbCwgZ2V0IHRoZSBvbmUgdGhhdCBpcyBjbG9zZXN0IHRvIHRoZSBjb2x1bW5cblx0XHRcdGlmIChsaW5rZWRSb3dDZWxscy5sZW5ndGggPiAxKSB7XG5cdFx0XHRcdGNvbnN0IHsgY2VsbCB9ID0gdGhpcy5maW5kQ2VsbEluUm93KEFycmF5LmZyb20obGlua2VkUm93Q2VsbHMpLCBjb2x1bW4gLSByZWFsQ29sdW1uSW5kZXgpO1xuXHRcdFx0XHRsaW5rZWRDZWxscy5wdXNoKGNlbGwpO1xuXHRcdFx0fSBlbHNlIGlmIChsaW5rZWRSb3dDZWxsc1swXSkge1xuXHRcdFx0XHRsaW5rZWRDZWxscy5wdXNoKGxpbmtlZFJvd0NlbGxzWzBdKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyByZXR1cm4gYW4gZW1wdHkgYXJyYXkgaWYgd2UgY2FuJ3QgZmluZCBhbnkgbGlua2VkIGNlbGxzXG5cdFx0Ly8gcmV0dXJuaW5nIGFueXRoaW5nIGVsc2Ugd291bGQgYmUgYSBsaWVcblx0XHRpZiAoIWxpbmtlZENlbGxzKSB7XG5cdFx0XHRyZXR1cm4gW107XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFtoZWFkZXIsIC4uLmxpbmtlZENlbGxzXTtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIGEgcm93IGZyb20gdGhlIHRhYmxlXG5cdCAqXG5cdCAqIEBwYXJhbSByb3cgaW5kZXggb2YgdGhlIHJvd1xuXHQgKi9cblx0Z2V0Um93KHJvdzogbnVtYmVyKTogSFRNTFRhYmxlUm93RWxlbWVudCB7XG5cdFx0cmV0dXJuIHRoaXMudGFibGVFbGVtZW50LnJvd3Nbcm93XTtcblx0fVxuXG5cdC8qKlxuXHQgKiBGaW5kcyB0aGUgY29sdW1uIGluZGV4IG9mIGEgZ2l2ZW4gY2VsbFxuXHQgKlxuXHQgKiBAcGFyYW0gY2VsbCB0aGUgY2VsbCB0byBzZWFyY2ggZm9yXG5cdCAqL1xuXHRmaW5kQ29sdW1uSW5kZXgoY2VsbDogSFRNTFRhYmxlQ2VsbEVsZW1lbnQpOiBudW1iZXIge1xuXHRcdGNvbnN0IHJvdyA9IHRoaXMuZ2V0Um93KHRoaXMuZmluZFJvd0luZGV4KGNlbGwpKTtcblx0XHRpZiAoIXJvdykge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHQvLyBpZiB0aGUgY2VsbCBoYXMgbGlua2VkIGhlYWRlcnMgd2UgY2FuIGRvIGEgbW9yZSBhY2N1cmF0ZSBsb29rdXBcblx0XHRpZiAoY2VsbCAmJiBjZWxsLmhlYWRlcnMpIHtcblx0XHRcdGNvbnN0IGlkcyA9IGNlbGwuaGVhZGVycy5zcGxpdChcIiBcIik7XG5cdFx0XHRjb25zdCBoZWFkZXJSb3dzID0gQXJyYXkuZnJvbSh0aGlzLnRhYmxlRWxlbWVudC50SGVhZC5yb3dzKTtcblx0XHRcdGNvbnN0IGluZGV4ZXMgPSBbXTtcblxuXHRcdFx0Ly8gc3RhcnQgZnJvbSB0aGUgbGFzdCByb3cgYW5kIHdvcmsgdXBcblx0XHRcdGZvciAoY29uc3QgaGVhZGVyUm93IG9mIGhlYWRlclJvd3MucmV2ZXJzZSgpKSB7XG5cdFx0XHRcdGNvbnN0IGhlYWRlckNlbGxzID0gQXJyYXkuZnJvbShoZWFkZXJSb3cuY2VsbHMpO1xuXHRcdFx0XHRjb25zdCBoZWFkZXIgPSBoZWFkZXJDZWxscy5maW5kKGhlYWRlckNlbGwgPT4gaWRzLmluY2x1ZGVzKGhlYWRlckNlbGwuaWQpKTtcblx0XHRcdFx0Ly8gaWYgd2UgaGF2ZSBhIG1hdGNoaW5nIGhlYWRlciwgZmluZCBpdCdzIGluZGV4IChhZGp1c3RpbmcgZm9yIGNvbHNwYW5zKVxuXHRcdFx0XHRpZiAoaGVhZGVyKSB7XG5cdFx0XHRcdFx0Ly8gdGhpcyBpcyBib3Jyb3dlZCBmcm9tIGJlbG93XG5cdFx0XHRcdFx0bGV0IGNlbGxJbmRleCA9IDA7XG5cdFx0XHRcdFx0Zm9yIChjb25zdCBjIG9mIGhlYWRlckNlbGxzKSB7XG5cdFx0XHRcdFx0XHRpZiAoYyA9PT0gaGVhZGVyKSB7IGJyZWFrOyB9XG5cdFx0XHRcdFx0XHRjZWxsSW5kZXggKz0gYy5jb2xTcGFuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpbmRleGVzLnB1c2goY2VsbEluZGV4KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBzb3J0IHRoZSBpbmRleGVzIGxhcmdlc3QgdG8gc21hbGxlc3QgdG8gZmluZCB0aGUgY2xvc2VzdCBtYXRjaGluZyBoZWFkZXIgaW5kZXhcblx0XHRcdGNvbnN0IGZpcnN0SW5kZXggPSBpbmRleGVzLnNvcnQoKGEsIGIpID0+IGIgLSBhKVswXTtcblxuXHRcdFx0Ly8gc2VhcmNoIHRoZSByb3cgZm9yIGNlbGxzIHRoYXQgc2hhcmUgdGhlIGhlYWRlclxuXHRcdFx0bGV0IHNpbWlsYXJDZWxscyA9IFtdO1xuXHRcdFx0Zm9yIChjb25zdCBpZCBvZiBpZHMpIHtcblx0XHRcdFx0Ly8gdGhlcmUncyBubyBzZWxlY3RvciB0aGF0IHdpbGwgbWF0Y2ggdHdvIHNwYWNlIHNlcGFyYXRlZCBsaXN0cyxcblx0XHRcdFx0Ly8gc28gd2UgaGF2ZSB0byBpdGVyYXRlIHRocm91Z2ggdGhlIGlkcyBhbmQgcXVlcnkgdGhlIHJvdyBmb3IgZWFjaFxuXHRcdFx0XHRjb25zdCByb3dDZWxscyA9IEFycmF5LmZyb20ocm93LnF1ZXJ5U2VsZWN0b3JBbGwoYFtoZWFkZXJzfj0nJHtpZH0nXWApKTtcblx0XHRcdFx0Zm9yIChjb25zdCByb3dDZWxsIG9mIHJvd0NlbGxzKSB7XG5cdFx0XHRcdFx0Ly8gb25seSBrZWVwIG9uZSBzZXQgb2YgY2VsbHNcblx0XHRcdFx0XHRpZiAoIXNpbWlsYXJDZWxscy5pbmNsdWRlcyhyb3dDZWxsKSkge1xuXHRcdFx0XHRcdFx0c2ltaWxhckNlbGxzLnB1c2gocm93Q2VsbCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIERPTSBvcmRlciBpcyBub3QgcHJlc2VydmVkLCBzbyB3ZSBoYXZlIHRvIHNvcnQgdGhlIHJvd1xuXHRcdFx0c2ltaWxhckNlbGxzID0gc2ltaWxhckNlbGxzLnNvcnQoKGE6IEhUTUxUYWJsZUNlbGxFbGVtZW50LCBiOiBIVE1MVGFibGVDZWxsRWxlbWVudCkgPT4gYS5jZWxsSW5kZXggLSBiLmNlbGxJbmRleCk7XG5cblx0XHRcdC8vIHJldHVybiB0aGUgaGVhZGVyIGluZGV4IHBsdXMgYW55IGFkanVzdG1lbnQgd2l0aGluIHRoYXQgaGVhZGVycyBjb2x1bW5cblx0XHRcdHJldHVybiBmaXJzdEluZGV4ICsgc2ltaWxhckNlbGxzLmluZGV4T2YoY2VsbCk7XG5cdFx0fVxuXG5cdFx0Ly8gZmFsbGJhY2sgaWYgdGhlIGNlbGwgaXNuJ3QgbGlua2VkIHRvIGFueSBoZWFkZXJzXG5cdFx0bGV0IGNlbGxJbmRleCA9IDA7XG5cdFx0Zm9yIChjb25zdCBjIG9mIEFycmF5LmZyb20ocm93LmNlbGxzKSkge1xuXHRcdFx0aWYgKGMgPT09IGNlbGwpIHsgYnJlYWs7IH1cblx0XHRcdGNlbGxJbmRleCArPSBjLmNvbFNwYW47XG5cdFx0fVxuXHRcdHJldHVybiBjZWxsSW5kZXg7XG5cdH1cblxuXHQvKipcblx0ICogRmluZHMgdGhlIHJvdyBpbmRleCBvZiBhIGdpdmVuIGNlbGxcblx0ICpcblx0ICogQHBhcmFtIGNlbGwgdGhlIGNlbGwgdG8gc2VhcmNoIGZvclxuXHQgKi9cblx0ZmluZFJvd0luZGV4KGNlbGw6IEhUTUxUYWJsZUNlbGxFbGVtZW50KTogbnVtYmVyIHtcblx0XHRmb3IgKGNvbnN0IHJvdyBvZiBBcnJheS5mcm9tKHRoaXMudGFibGVFbGVtZW50LnJvd3MpKSB7XG5cdFx0XHRpZiAocm93LmNvbnRhaW5zKGNlbGwpKSB7XG5cdFx0XHRcdHJldHVybiByb3cucm93SW5kZXg7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIEZpbmRzIHRoZSByb3cgYW5kIGNvbHVtbiBpbmRleCBvZiBhIGdpdmVuIGNlbGxcblx0ICpcblx0ICogQHBhcmFtIGNlbGwgdGhlIGNlbGwgdG8gc2VhcmNoIGZvclxuXHQgKiBAcmV0dXJucyBhIHR1cGxlIHRoYXQgZm9sbG93cyB0aGUgYFtyb3csIGNvbHVtbl1gIGNvbnZlbnRpb25cblx0ICovXG5cdGZpbmRJbmRleChjZWxsOiBIVE1MVGFibGVDZWxsRWxlbWVudCk6IFtudW1iZXIsIG51bWJlcl0ge1xuXHRcdHJldHVybiBbdGhpcy5maW5kUm93SW5kZXgoY2VsbCksIHRoaXMuZmluZENvbHVtbkluZGV4KGNlbGwpXTtcblx0fVxuXG5cdC8qKlxuXHQgKiBIZWxwZXIgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBcInJlYWxcIiBsZW5ndGggb2YgYSByb3cuXG5cdCAqIE9ubHkgYWNjdXJhdGUgd2l0aCByZWdhcmQgdG8gY29sc3BhbnMgKHRob3VnaCB0aGF0J3Mgc3VmZmljaWVudCBmb3IgaXQncyB1c2VzIGhlcmUpXG5cdCAqXG5cdCAqIFRPRE86IFRha2Ugcm93U3BhbiBpbnRvIGFjY291bnRcblx0ICpcblx0ICogQHBhcmFtIHJvdyB0aGUgcm93IHRvIGdldCB0aGUgbGVuZ3RoIG9mXG5cdCAqL1xuXHRwcm90ZWN0ZWQgZ2V0UmVhbFJvd0xlbmd0aChyb3c6IEhUTUxUYWJsZVJvd0VsZW1lbnQpOiBudW1iZXIge1xuXHRcdC8vIHN0YXJ0IGF0IC0xIHNpbmNlIHRoZSBjb2xzcGFucyB3aWxsIHN1bSB0byAxIGluZGV4IGdyZWF0ZXIgdGhhbiB0aGUgdG90YWxcblx0XHRyZXR1cm4gQXJyYXkuZnJvbShyb3cuY2VsbHMpLnJlZHVjZSgoY291bnQsIGNlbGwpID0+IGNvdW50ICsgY2VsbC5jb2xTcGFuLCAtMSk7XG5cdH1cblxuXHQvKipcblx0ICogRmluZHMgYSBjZWxsIGFuZCBpdCdzIHJlYWwgaW5kZXggZ2l2ZW4gYW4gYXJyYXkgb2YgY2VsbHMsIGEgdGFyZ2V0IGluZGV4LCBhbmQgdGhlIHNwYW5uaW5nIGRpcmVjdGlvblxuXHQgKlxuXHQgKiBAcGFyYW0gY2VsbHMgQW4gYXJyYXkgb2YgY2VsbHMgdG8gc2VhcmNoXG5cdCAqIEBwYXJhbSB0YXJnZXRJbmRleCBUaGUgaW5kZXggd2UgdGhpbmsgdGhlIGNlbGwgaXMgbG9jYXRlZCBhdFxuXHQgKiBAcGFyYW0gc3BhbkRpcmVjdGlvbiBUaGUgZGlyZWN0aW9uIG9mIHRoZSBjZWxsIHNwYW5zLiBTaG91bGQgYmUgYFwiY29sU3BhblwiYCBmb3IgYSByb3cgYW5kIGBcInJvd1NwYW5cImAgZm9yIGEgY29sdW1uXG5cdCAqL1xuXHRwcm90ZWN0ZWQgZmluZENlbGwoY2VsbHM6IEhUTUxUYWJsZUNlbGxFbGVtZW50W10sIHRhcmdldEluZGV4OiBudW1iZXIsIHNwYW5EaXJlY3Rpb246IFRhYmxlRG9tU3BhbkRpcmVjdGlvbikge1xuXHRcdC8vIHJvd3MvY29scyBjYW4gaGF2ZSBmZXdlciB0b3RhbCBjZWxscyB0aGFuIHRoZSBhY3R1YWwgdGFibGVcblx0XHQvLyB0aGUgbW9kZWwgcHJldGVuZHMgYWxsIHJvd3MvY29scyBiZWhhdmUgdGhlIHNhbWUgKHdpdGggY29sL3JvdyBzcGFucyA+IDEgYmVpbmcgTiBjZWxscyBsb25nKVxuXHRcdC8vIHRoaXMgbWFwcyB0aGF0IHZpZXcgdG8gdGhlIEhUTUwgdmlldyAoY29sL3JvdyBzcGFucyA+IDEgYXJlIG9uZSBlbGVtZW50LCBzbyB0aGUgYXJyYXkgaXMgc2hvcnRlcilcblx0XHRsZXQgcmVhbEluZGV4ID0gMDtcblx0XHQvLyBpIGlzIG9ubHkgdXNlZCBmb3IgaXRlcmF0aW5nIHRoZSBjZWxsc1xuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGFyZ2V0SW5kZXg7KSB7XG5cdFx0XHQvLyBza2lwIHRoZSBuZXh0IE4gY2VsbHNcblx0XHRcdGkgKz0gY2VsbHNbcmVhbEluZGV4XVtzcGFuRGlyZWN0aW9uXTtcblx0XHRcdC8vIGRvbid0IGJ1bXAgcmVhbEluZGV4IGlmIGkgbm93IGV4Y2VlZHMgdGhlIGNlbGwgd2UncmUgc2hvb3RpbmcgZm9yXG5cdFx0XHRpZiAoaSA+IHRhcmdldEluZGV4KSB7IGJyZWFrOyB9XG5cdFx0XHQvLyBmaW5hbGx5LCBpbmNyZW1lbnQgcmVhbEluZGV4ICh0byBrZWVwIGl0IGdlbmVyYWxseSBpbiBzdGVwIHdpdGggaSlcblx0XHRcdHJlYWxJbmRleCsrO1xuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHRjZWxsOiBjZWxsc1tyZWFsSW5kZXhdLFxuXHRcdFx0cmVhbEluZGV4XG5cdFx0fTtcblx0fVxuXG5cdC8qKlxuXHQgKiBIZWxwZXIgbWV0aG9kIGFyb3VuZCBgZmluZENlbGxgLCBzZWFyY2hlcyBiYXNlZCBvbiBhIHJvdyBvZiBjZWxsc1xuXHQgKlxuXHQgKiBAcGFyYW0gcm93IHRoZSByb3cgb2YgZWxlbWVudHMgdG8gc2VhcmNoXG5cdCAqIEBwYXJhbSBpbmRleCB0aGUgaW5kZXggb2YgdGhlIGVsZW1lbnRcblx0ICovXG5cdHByb3RlY3RlZCBmaW5kQ2VsbEluUm93KHJvdzogSFRNTFRhYmxlQ2VsbEVsZW1lbnRbXSwgaW5kZXg6IG51bWJlcikge1xuXHRcdHJldHVybiB0aGlzLmZpbmRDZWxsKHJvdywgaW5kZXgsIFRhYmxlRG9tU3BhbkRpcmVjdGlvbi5jb2xTcGFuKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBIZWxwZXIgbWV0aG9kIGFyb3VuZCBgZmluZENlbGxgLCBzZWFyY2hlcyBiYXNlZCBvbiBhIGNvbHVtbiBvZiBjZWxsc1xuXHQgKlxuXHQgKiBAcGFyYW0gY29sIHRoZSBjb2x1bW4gb2YgZWxlbWVudHMgdG8gc2VhcmNoXG5cdCAqIEBwYXJhbSBpbmRleCB0aGUgaW5kZXggb2YgdGhlIGVsZW1lbnRcblx0ICovXG5cdHByb3RlY3RlZCBmaW5kQ2VsbEluQ29sdW1uKGNvbDogSFRNTFRhYmxlQ2VsbEVsZW1lbnRbXSwgaW5kZXg6IG51bWJlcikge1xuXHRcdHJldHVybiB0aGlzLmZpbmRDZWxsKGNvbCwgaW5kZXgsIFRhYmxlRG9tU3BhbkRpcmVjdGlvbi5yb3dTcGFuKTtcblx0fVxufVxuIl19