vix-ui
Version:
433 lines • 40.8 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
import * as tslib_1 from "tslib";
import { Component, EventEmitter, Input, Output } from '@angular/core';
import * as _ from 'lodash';
var VixConfusionMatrixComponent = /** @class */ (function () {
function VixConfusionMatrixComponent() {
this.pageSize = 0;
this.data = {};
this.tableExport = new EventEmitter();
this.concepts = [];
this.selectedConcepts = [];
this.nPages = 1;
this.pageNums = [];
this.summaries = {};
this.overallSummaries = {};
this.summaryRows = ['TP', 'FP', 'FN', 'Support'];
this.sortCriteria = {};
this.rowOrdering = [];
this.taskIds = [];
this.page = 1;
this.conceptsFiltered = [];
}
/**
* @param {?=} init
* @return {?}
*/
VixConfusionMatrixComponent.prototype.getRowsToShow = /**
* @param {?=} init
* @return {?}
*/
function (init) {
var _this = this;
if (init === void 0) { init = false; }
this.conceptsFiltered = this.concepts.slice();
if (this.selectedConcepts.length) {
this.conceptsFiltered = this.conceptsFiltered.filter(function (concept) { return _this.selectedConcepts.indexOf(concept) !== -1; });
}
this.nPages = this.pageSize ? Math.ceil(this.conceptsFiltered.length / this.pageSize) : 1;
if (!init && this.conceptsFiltered.length === this.concepts.length) {
// Use overall summary which is cached in-memory
this.summaries = _.cloneDeep(this.overallSummaries);
}
else {
this.computeSummary(init);
}
this.toggleSort();
};
/**
* @return {?}
*/
VixConfusionMatrixComponent.prototype.toggleSort = /**
* @return {?}
*/
function () {
var _this = this;
if (this.sortCriteria.criteria === 'alpha') {
this.conceptsFiltered.sort();
if (this.sortCriteria.direction === 'desc') {
this.conceptsFiltered.reverse();
}
}
else {
/** @type {?} */
var direction_1 = this.sortCriteria.direction || 'desc';
this.conceptsFiltered.sort(function (a, b) {
/** @type {?} */
var first = _this.summaries[_this.sortCriteria.taskId][_this.sortCriteria.criteria][a] || 0;
/** @type {?} */
var second = _this.summaries[_this.sortCriteria.taskId][_this.sortCriteria.criteria][b] || 0;
return (first - second) * (direction_1 === 'desc' ? -1 : 1);
});
}
this.page = 1;
this.changePage();
};
/**
* @param {?} init
* @return {?}
*/
VixConfusionMatrixComponent.prototype.computeSummary = /**
* @param {?} init
* @return {?}
*/
function (init) {
var e_1, _a, e_2, _b, e_3, _c, e_4, _d, e_5, _e;
this.summaries = {};
try {
for (var _f = tslib_1.__values(this.taskIds), _g = _f.next(); !_g.done; _g = _f.next()) {
var taskId = _g.value;
this.summaries[taskId] = {
TP: {},
FP: {},
FN: {},
Support: {},
};
try {
for (var _h = tslib_1.__values(this.conceptsFiltered), _j = _h.next(); !_j.done; _j = _h.next()) {
var concept = _j.value;
this.summaries[taskId].TP[concept] = 0;
this.summaries[taskId].FP[concept] = 0;
this.summaries[taskId].FN[concept] = 0;
this.summaries[taskId].Support[concept] = 0;
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_j && !_j.done && (_b = _h.return)) _b.call(_h);
}
finally { if (e_2) throw e_2.error; }
}
try {
for (var _k = tslib_1.__values(this.conceptsFiltered), _l = _k.next(); !_l.done; _l = _k.next()) {
var concept1 = _l.value;
try {
for (var _m = tslib_1.__values(this.conceptsFiltered), _o = _m.next(); !_o.done; _o = _m.next()) {
var concept2 = _o.value;
/** @type {?} */
var count = void 0;
if (this.data[taskId].matrix[concept1]) {
count = this.data[taskId].matrix[concept1][concept2] || 0;
}
else {
count = 0;
}
if (concept1 === concept2) {
this.summaries[taskId].TP[concept1] += count;
}
else {
this.summaries[taskId].FN[concept1] += count;
this.summaries[taskId].FP[concept2] += count;
}
this.summaries[taskId].Support[concept1] += count;
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_o && !_o.done && (_d = _m.return)) _d.call(_m);
}
finally { if (e_4) throw e_4.error; }
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_l && !_l.done && (_c = _k.return)) _c.call(_k);
}
finally { if (e_3) throw e_3.error; }
}
if (init) {
this.overallSummaries[taskId] = {
TP: {},
FP: {},
FN: {},
Support: {},
};
try {
for (var _p = tslib_1.__values(this.conceptsFiltered), _q = _p.next(); !_q.done; _q = _p.next()) {
var concept = _q.value;
this.overallSummaries[taskId].TP[concept] = this.summaries[taskId].TP[concept];
this.overallSummaries[taskId].FP[concept] = this.summaries[taskId].FP[concept];
this.overallSummaries[taskId].FN[concept] = this.summaries[taskId].FN[concept];
this.overallSummaries[taskId].Support[concept] = this.summaries[taskId].Support[concept];
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_q && !_q.done && (_e = _p.return)) _e.call(_p);
}
finally { if (e_5) throw e_5.error; }
}
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_g && !_g.done && (_a = _f.return)) _a.call(_f);
}
finally { if (e_1) throw e_1.error; }
}
};
/**
* @param {?=} page
* @return {?}
*/
VixConfusionMatrixComponent.prototype.changePage = /**
* @param {?=} page
* @return {?}
*/
function (page) {
if (page) {
this.page = page;
}
this.page = Math.min(Math.max(+this.page, 1), this.nPages);
this.pageNums = [];
/** @type {?} */
var lowLimit;
/** @type {?} */
var uppLimit;
if (this.page <= 2) {
lowLimit = 1;
uppLimit = Math.min(5, this.nPages);
}
else if (Math.abs(this.page - this.nPages) <= 1) {
lowLimit = Math.max(1, this.nPages - 4);
uppLimit = this.nPages;
}
else {
lowLimit = this.page - 2;
uppLimit = this.page + 2;
}
for (var i = lowLimit; i <= uppLimit; i++) {
this.pageNums = this.pageNums.concat([i]);
}
this.rowOrdering = this.conceptsFiltered.slice();
if (!this.pageSize) {
// No paging required
return;
}
this.rowOrdering = this.rowOrdering.slice((this.page - 1) * this.pageSize, this.page * this.pageSize);
};
/**
* @param {?} event
* @return {?}
*/
VixConfusionMatrixComponent.prototype.onChange = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.selectedConcepts = event;
this.getRowsToShow();
};
/**
* @param {?} i
* @return {?}
*/
VixConfusionMatrixComponent.prototype.counter = /**
* @param {?} i
* @return {?}
*/
function (i) {
return new Array(i);
};
/**
* @return {?}
*/
VixConfusionMatrixComponent.prototype.getTableData = /**
* @return {?}
*/
function () {
var _this = this;
var e_6, _a;
/** @type {?} */
var tableHeader = ['concept'].concat(this.conceptsFiltered);
/** @type {?} */
var tableData = [];
var _loop_1 = function (concept) {
var e_7, _a;
/** @type {?} */
var row = { concept: concept };
var _loop_2 = function (concept1) {
row[concept1] = this_1.taskIds.map(function (taskId) {
/** @type {?} */
var count = _this.data[taskId].matrix[concept][concept1];
return count == null ? '-' : count;
}).join(' / ');
};
try {
for (var _b = tslib_1.__values(this_1.conceptsFiltered), _c = _b.next(); !_c.done; _c = _b.next()) {
var concept1 = _c.value;
_loop_2(concept1);
}
}
catch (e_7_1) { e_7 = { error: e_7_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_7) throw e_7.error; }
}
tableData.push(row);
};
var this_1 = this;
try {
for (var _b = tslib_1.__values(this.conceptsFiltered), _c = _b.next(); !_c.done; _c = _b.next()) {
var concept = _c.value;
_loop_1(concept);
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_6) throw e_6.error; }
}
this.tableExport.emit({ tableHeader: tableHeader, tableData: tableData });
};
/**
* @return {?}
*/
VixConfusionMatrixComponent.prototype.ngOnInit = /**
* @return {?}
*/
function () {
// Page size must be non-zero; page size = 0 means all to be displayed without paging
this.pageSize = Math.max(this.pageSize, 0);
this.initialize();
};
/**
* @return {?}
*/
VixConfusionMatrixComponent.prototype.ngOnChanges = /**
* @return {?}
*/
function () {
this.initialize();
};
/**
* @return {?}
*/
VixConfusionMatrixComponent.prototype.initialize = /**
* @return {?}
*/
function () {
var e_8, _a, e_9, _b, e_10, _c;
this.taskIds = Object.keys(this.data);
this.sortCriteria = {
criteria: 'alpha',
direction: 'asc',
taskId: this.taskIds[0],
};
this.selectedConcepts = [];
/** @type {?} */
var conceptsCombined = [];
try {
for (var _d = tslib_1.__values(this.taskIds), _e = _d.next(); !_e.done; _e = _d.next()) {
var taskId = _e.value;
conceptsCombined = conceptsCombined.concat(this.data[taskId].concepts);
}
}
catch (e_8_1) { e_8 = { error: e_8_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_8) throw e_8.error; }
}
this.concepts = Array.from(new Set(conceptsCombined));
try {
for (var _f = tslib_1.__values(this.taskIds), _g = _f.next(); !_g.done; _g = _f.next()) {
var taskId = _g.value;
try {
for (var _h = tslib_1.__values(this.concepts), _j = _h.next(); !_j.done; _j = _h.next()) {
var concept = _j.value;
this.data[taskId].matrix[concept] = this.data[taskId].matrix[concept] || {};
}
}
catch (e_10_1) { e_10 = { error: e_10_1 }; }
finally {
try {
if (_j && !_j.done && (_c = _h.return)) _c.call(_h);
}
finally { if (e_10) throw e_10.error; }
}
}
}
catch (e_9_1) { e_9 = { error: e_9_1 }; }
finally {
try {
if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
}
finally { if (e_9) throw e_9.error; }
}
this.getRowsToShow(true);
};
VixConfusionMatrixComponent.decorators = [
{ type: Component, args: [{
selector: 'vix-confusion-matrix',
template: "<ng-select\n style=\"margin-bottom: 15px; max-width: 600px;\"\n placeholder=\"Select concepts to display\"\n [dropdownPosition]=\"'top'\"\n [items]=\"concepts\"\n [multiple]=\"true\"\n [closeOnSelect]=\"false\"\n (ngModelChange)=\"onChange($event)\"\n [(ngModel)]=\"selectedConcepts\">\n</ng-select>\n<div style=\"margin-bottom: 15px;\">\n Sort by\n <select *ngIf=\"taskIds.length > 1\" [disabled]=\"sortCriteria.criteria == 'alpha'\" [(ngModel)]=\"sortCriteria.taskId\" (ngModelChange)=\"toggleSort()\">\n <option *ngFor=\"let taskId of taskIds\" value=\"{{ taskId }}\">Task {{ taskId }}</option>\n </select>\n <select [(ngModel)]=\"sortCriteria.criteria\" (ngModelChange)=\"toggleSort()\">\n <option value=\"alpha\">Alphabetical</option>\n <option *ngFor=\"let row of summaryRows\" value=\"{{ row }}\">{{ row }}</option>\n </select>\n <select [(ngModel)]=\"sortCriteria.direction\" (ngModelChange)=\"toggleSort()\">\n <option value=\"asc\">ascending</option>\n <option value=\"desc\">descending</option>\n </select>\n</div>\n<div class=\"table-container\">\n <table class=\"confusion-matrix-table\">\n <thead>\n <tr class=\"first-row\">\n <th class=\"first-col\">\n Concept\n <span *ngIf=\"taskIds.length > 1\">\n <br>\n ( {{ taskIds[0] }}\n <span *ngFor=\"let taskId of taskIds; let i = index\"><span *ngIf=\"i !== 0\">/ {{ taskId }}</span></span>\n )\n </span>\n </th>\n <th *ngFor=\"let concept of rowOrdering\">\n <div class=\"concept-header\" [ngbTooltip]=\"concept\">{{ concept }}</div>\n </th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let concept1 of rowOrdering\">\n <td class=\"first-col\">{{ concept1 }}</td>\n <td *ngFor=\"let concept2 of rowOrdering\" [ngClass]=\"{ 'single-number': taskIds.length === 1 }\">\n <div>\n <span *ngFor=\"let taskId of taskIds; let i = index\">\n <span *ngIf=\"i !== 0\"> / </span>{{ data[taskId].matrix[concept1][concept2] | noEntry }}\n </span>\n </div>\n <div>\n <ngb-progressbar *ngIf=\"taskIds.length === 1\"\n type=\"{{ concept1 === concept2 ? 'success' : 'warning' }}\"\n [value]=\"data[taskIds[0]].matrix[concept1][concept2] / summaries[taskIds[0]].Support[concept1] * 100\"\n height=\"0.5rem\">\n </ngb-progressbar>\n </div>\n </td>\n </tr>\n <!-- Summary row -->\n <tr style=\"height: 15px;\"></tr>\n <tr class=\"summary-row\" *ngFor=\"let row of summaryRows\">\n <td class=\"first-col\">{{ row }}</td>\n <td *ngFor=\"let concept of rowOrdering\">\n <span *ngFor=\"let taskId of taskIds; let i = index\">\n <span *ngIf=\"i !== 0\"> / </span>{{ summaries[taskId][row][concept] }}\n </span>\n </td>\n </tr>\n </tbody>\n </table>\n</div>\n<div *ngIf=\"nPages > 1\" style=\"margin-top: 15px\">\n <span class=\"paginator\" (click)=\"changePage(1)\">\n <i class=\"ion-ios-rewind\"></i>\n </span>\n <span class=\"paginator\" (click)=\"changePage(page - 1)\">\n <i class=\"ion-android-arrow-dropleft\"></i>\n </span>\n <span *ngFor=\"let pageNum of pageNums\">\n <span class=\"paginator\" [ngClass]=\"{'active': page === pageNum}\" (click)=\"changePage(pageNum)\">{{ pageNum }}</span>\n </span>\n <span class=\"paginator\" (click)=\"changePage(page + 1)\">\n <i class=\"ion-android-arrow-dropright\"></i>\n </span>\n <span class=\"paginator\" (click)=\"changePage(nPages)\">\n <i class=\"ion-ios-fastforward\"></i>\n </span>\n Jump to page:\n <select [(ngModel)]=\"page\" (ngModelChange)=\"changePage()\">\n <option *ngFor=\"let in of counter(nPages); let i = index\" value=\"{{ i + 1 }}\">{{ i + 1 }}</option>\n </select>\n</div>\n<div style=\"margin-top: 15px;\">\n <a href=\"javascript:;\" (click)=\"getTableData()\">\n Download Table as CSV\n </a>\n</div>\n",
styles: [".table-container{max-width:100%;overflow-x:auto}.confusion-matrix-table{border:1px solid gray}.confusion-matrix-table td,.confusion-matrix-table th{border:1px solid #d7d7d7;font-size:12px;min-width:60px;padding:6px}.confusion-matrix-table .single-number{padding:0}.confusion-matrix-table .single-number div:nth-child(1){padding:6px}.confusion-matrix-table th{text-align:center}.confusion-matrix-table .first-col{background-color:#f5f6f7}.confusion-matrix-table .summary-row .first-col{font-weight:600}.confusion-matrix-table .first-row{background-color:#f5f6f7;font-size:13px;font-weight:600}.confusion-matrix-table .concept-header{max-width:60px;overflow-x:hidden;text-overflow:ellipsis}.paginator{padding-left:7px;padding-right:7px}.paginator:hover{background-color:#eee;cursor:pointer}.paginator.active{background-color:#ddd}:host /deep/ .progress{background-color:#fff}:host /deep/ .ng-select .ng-dropdown-panel .ng-dropdown-panel-items .ng-option{font-size:12px}:host /deep/ .ng-select .ng-select-container .ng-value-container .ng-input,:host /deep/ .ng-select .ng-select-container .ng-value-container .ng-value-label{font-size:12px}:host /deep/ .ng-select .ng-select-container .ng-value-container .ng-placeholder{font-size:13px}"]
}] }
];
VixConfusionMatrixComponent.ctorParameters = function () { return []; };
VixConfusionMatrixComponent.propDecorators = {
pageSize: [{ type: Input }],
data: [{ type: Input }],
tableExport: [{ type: Output }]
};
return VixConfusionMatrixComponent;
}());
export { VixConfusionMatrixComponent };
if (false) {
/** @type {?} */
VixConfusionMatrixComponent.prototype.pageSize;
/** @type {?} */
VixConfusionMatrixComponent.prototype.data;
/** @type {?} */
VixConfusionMatrixComponent.prototype.tableExport;
/** @type {?} */
VixConfusionMatrixComponent.prototype.concepts;
/** @type {?} */
VixConfusionMatrixComponent.prototype.selectedConcepts;
/** @type {?} */
VixConfusionMatrixComponent.prototype.nPages;
/** @type {?} */
VixConfusionMatrixComponent.prototype.pageNums;
/** @type {?} */
VixConfusionMatrixComponent.prototype.summaries;
/** @type {?} */
VixConfusionMatrixComponent.prototype.overallSummaries;
/** @type {?} */
VixConfusionMatrixComponent.prototype.summaryRows;
/** @type {?} */
VixConfusionMatrixComponent.prototype.sortCriteria;
/** @type {?} */
VixConfusionMatrixComponent.prototype.rowOrdering;
/** @type {?} */
VixConfusionMatrixComponent.prototype.taskIds;
/** @type {?} */
VixConfusionMatrixComponent.prototype.page;
/** @type {?} */
VixConfusionMatrixComponent.prototype.conceptsFiltered;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidml4LWNvbmZ1c2lvbi1tYXRyaXguY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vdml4LXVpLyIsInNvdXJjZXMiOlsidml4LWNvbmZ1c2lvbi1tYXRyaXgvdml4LWNvbmZ1c2lvbi1tYXRyaXguY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFxQixNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUYsT0FBTyxLQUFLLENBQUMsTUFBTSxRQUFRLENBQUM7QUFFNUI7SUEwQkU7UUFuQlMsYUFBUSxHQUFHLENBQUMsQ0FBQztRQUNiLFNBQUksR0FBUSxFQUFFLENBQUM7UUFFZCxnQkFBVyxHQUFzQixJQUFJLFlBQVksRUFBTyxDQUFDO1FBRW5FLGFBQVEsR0FBYSxFQUFFLENBQUM7UUFDeEIscUJBQWdCLEdBQWEsRUFBRSxDQUFDO1FBQ2hDLFdBQU0sR0FBRyxDQUFDLENBQUM7UUFDWCxhQUFRLEdBQUcsRUFBRSxDQUFDO1FBQ2QsY0FBUyxHQUFRLEVBQUUsQ0FBQztRQUNwQixxQkFBZ0IsR0FBUSxFQUFFLENBQUM7UUFDM0IsZ0JBQVcsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQzVDLGlCQUFZLEdBQVEsRUFBRSxDQUFDO1FBQ3ZCLGdCQUFXLEdBQWEsRUFBRSxDQUFDO1FBQzNCLFlBQU8sR0FBVSxFQUFFLENBQUM7UUFDcEIsU0FBSSxHQUFHLENBQUMsQ0FBQztRQUVELHFCQUFnQixHQUFhLEVBQUUsQ0FBQztJQUV6QixDQUFDOzs7OztJQUVSLG1EQUFhOzs7O0lBQXJCLFVBQXNCLElBQVk7UUFBbEMsaUJBZ0JDO1FBaEJxQixxQkFBQSxFQUFBLFlBQVk7UUFDaEMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFOUMsSUFB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QTNNRCxJQTJNQztTQXRNWSwyQkFBMkI7OztJQUV0QywrQ0FBc0I7O0lBQ3RCLDJDQUF3Qjs7SUFFeEIsa0RBQW1FOztJQUVuRSwrQ0FBd0I7O0lBQ3hCLHVEQUFnQzs7SUFDaEMsNkNBQVc7O0lBQ1gsK0NBQWM7O0lBQ2QsZ0RBQW9COztJQUNwQix1REFBMkI7O0lBQzNCLGtEQUE0Qzs7SUFDNUMsbURBQXVCOztJQUN2QixrREFBMkI7O0lBQzNCLDhDQUFvQjs7SUFDcEIsMkNBQVM7O0lBRVQsdURBQXdDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkNoYW5nZXMsIE9uSW5pdCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3ZpeC1jb25mdXNpb24tbWF0cml4JyxcbiAgdGVtcGxhdGVVcmw6ICcuL3ZpeC1jb25mdXNpb24tbWF0cml4LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vdml4LWNvbmZ1c2lvbi1tYXRyaXguY29tcG9uZW50LnNjc3MnXSxcbn0pXG5leHBvcnQgY2xhc3MgVml4Q29uZnVzaW9uTWF0cml4Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMge1xuXG4gIEBJbnB1dCgpIHBhZ2VTaXplID0gMDtcbiAgQElucHV0KCkgZGF0YTogYW55ID0ge307XG5cbiAgQE91dHB1dCgpIHRhYmxlRXhwb3J0OiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIGNvbmNlcHRzOiBzdHJpbmdbXSA9IFtdO1xuICBzZWxlY3RlZENvbmNlcHRzOiBzdHJpbmdbXSA9IFtdO1xuICBuUGFnZXMgPSAxO1xuICBwYWdlTnVtcyA9IFtdO1xuICBzdW1tYXJpZXM6IGFueSA9IHt9O1xuICBvdmVyYWxsU3VtbWFyaWVzOiBhbnkgPSB7fTtcbiAgc3VtbWFyeVJvd3MgPSBbJ1RQJywgJ0ZQJywgJ0ZOJywgJ1N1cHBvcnQnXTtcbiAgc29ydENyaXRlcmlhOiBhbnkgPSB7fTtcbiAgcm93T3JkZXJpbmc6IHN0cmluZ1tdID0gW107XG4gIHRhc2tJZHM6IGFueVtdID0gW107XG4gIHBhZ2UgPSAxO1xuXG4gIHByaXZhdGUgY29uY2VwdHNGaWx0ZXJlZDogc3RyaW5nW10gPSBbXTtcblxuICBjb25zdHJ1Y3RvcigpIHt9XG5cbiAgcHJpdmF0ZSBnZXRSb3dzVG9TaG93KGluaXQgPSBmYWxzZSk6IHZvaWQge1xuICAgIHRoaXMuY29uY2VwdHNGaWx0ZXJlZCA9IHRoaXMuY29uY2VwdHMuc2xpY2UoKTtcblxuICAgIGlmICh0aGlzLnNlbGVjdGVkQ29uY2VwdHMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmNvbmNlcHRzRmlsdGVyZWQgPSB0aGlzLmNvbmNlcHRzRmlsdGVyZWQuZmlsdGVyKFxuICAgICAgICAgIGNvbmNlcHQgPT4gdGhpcy5zZWxlY3RlZENvbmNlcHRzLmluZGV4T2YoY29uY2VwdCkgIT09IC0xKTtcbiAgICB9XG5cbiAgICB0aGlzLm5QYWdlcyA9IHRoaXMucGFnZVNpemUgPyBNYXRoLmNlaWwodGhpcy5jb25jZXB0c0ZpbHRlcmVkLmxlbmd0aCAvIHRoaXMucGFnZVNpemUpIDogMTtcbiAgICBpZiAoIWluaXQgJiYgdGhpcy5jb25jZXB0c0ZpbHRlcmVkLmxlbmd0aCA9PT0gdGhpcy5jb25jZXB0cy5sZW5ndGgpIHtcbiAgICAgIC8vIFVzZSBvdmVyYWxsIHN1bW1hcnkgd2hpY2ggaXMgY2FjaGVkIGluLW1lbW9yeVxuICAgICAgdGhpcy5zdW1tYXJpZXMgPSBfLmNsb25lRGVlcCh0aGlzLm92ZXJhbGxTdW1tYXJpZXMpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmNvbXB1dGVTdW1tYXJ5KGluaXQpO1xuICAgIH1cbiAgICB0aGlzLnRvZ2dsZVNvcnQoKTtcbiAgfVxuXG4gIHRvZ2dsZVNvcnQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc29ydENyaXRlcmlhLmNyaXRlcmlhID09PSAnYWxwaGEnKSB7XG4gICAgICB0aGlzLmNvbmNlcHRzRmlsdGVyZWQuc29ydCgpO1xuICAgICAgaWYgKHRoaXMuc29ydENyaXRlcmlhLmRpcmVjdGlvbiA9PT0gJ2Rlc2MnKSB7XG4gICAgICAgIHRoaXMuY29uY2VwdHNGaWx0ZXJlZC5yZXZlcnNlKCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGRpcmVjdGlvbiA9IHRoaXMuc29ydENyaXRlcmlhLmRpcmVjdGlvbiB8fCAnZGVzYyc7XG4gICAgICB0aGlzLmNvbmNlcHRzRmlsdGVyZWQuc29ydCgoYSwgYikgPT4ge1xuICAgICAgICBjb25zdCBmaXJzdCA9IHRoaXMuc3VtbWFyaWVzW3RoaXMuc29ydENyaXRlcmlhLnRhc2tJZF1bdGhpcy5zb3J0Q3JpdGVyaWEuY3JpdGVyaWFdW2FdIHx8IDA7XG4gICAgICAgIGNvbnN0IHNlY29uZCA9IHRoaXMuc3VtbWFyaWVzW3RoaXMuc29ydENyaXRlcmlhLnRhc2tJZF1bdGhpcy5zb3J0Q3JpdGVyaWEuY3JpdGVyaWFdW2JdIHx8IDA7XG4gICAgICAgIHJldHVybiAoZmlyc3QgLSBzZWNvbmQpICogKGRpcmVjdGlvbiA9PT0gJ2Rlc2MnID8gLTEgOiAxKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHRoaXMucGFnZSA9IDE7XG4gICAgdGhpcy5jaGFuZ2VQYWdlKCk7XG4gIH1cblxuICBjb21wdXRlU3VtbWFyeShpbml0OiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5zdW1tYXJpZXMgPSB7fTtcbiAgICBmb3IgKGNvbnN0IHRhc2tJZCBvZiB0aGlzLnRhc2tJZHMpIHtcbiAgICAgIHRoaXMuc3VtbWFyaWVzW3Rhc2tJZF0gPSB7XG4gICAgICAgIFRQOiB7fSxcbiAgICAgICAgRlA6IHt9LFxuICAgICAgICBGTjoge30sXG4gICAgICAgIFN1cHBvcnQ6IHt9LFxuICAgICAgfTtcbiAgICAgIGZvciAoY29uc3QgY29uY2VwdCBvZiB0aGlzLmNvbmNlcHRzRmlsdGVyZWQpIHtcbiAgICAgICAgdGhpcy5zdW1tYXJpZXNbdGFza0lkXS5UUFtjb25jZXB0XSA9IDA7XG4gICAgICAgIHRoaXMuc3VtbWFyaWVzW3Rhc2tJZF0uRlBbY29uY2VwdF0gPSAwO1xuICAgICAgICB0aGlzLnN1bW1hcmllc1t0YXNrSWRdLkZOW2NvbmNlcHRdID0gMDtcbiAgICAgICAgdGhpcy5zdW1tYXJpZXNbdGFza0lkXS5TdXBwb3J0W2NvbmNlcHRdID0gMDtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgY29uY2VwdDEgb2YgdGhpcy5jb25jZXB0c0ZpbHRlcmVkKSB7XG4gICAgICAgIGZvciAoY29uc3QgY29uY2VwdDIgb2YgdGhpcy5jb25jZXB0c0ZpbHRlcmVkKSB7XG4gICAgICAgICAgbGV0IGNvdW50O1xuICAgICAgICAgIGlmICh0aGlzLmRhdGFbdGFza0lkXS5tYXRyaXhbY29uY2VwdDFdKSB7XG4gICAgICAgICAgICBjb3VudCA9IHRoaXMuZGF0YVt0YXNrSWRdLm1hdHJpeFtjb25jZXB0MV1bY29uY2VwdDJdIHx8IDA7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvdW50ID0gMDtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGNvbmNlcHQxID09PSBjb25jZXB0Mikge1xuICAgICAgICAgICAgdGhpcy5zdW1tYXJpZXNbdGFza0lkXS5UUFtjb25jZXB0MV0gKz0gY291bnQ7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc3VtbWFyaWVzW3Rhc2tJZF0uRk5bY29uY2VwdDFdICs9IGNvdW50O1xuICAgICAgICAgICAgdGhpcy5zdW1tYXJpZXNbdGFza0lkXS5GUFtjb25jZXB0Ml0gKz0gY291bnQ7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRoaXMuc3VtbWFyaWVzW3Rhc2tJZF0uU3VwcG9ydFtjb25jZXB0MV0gKz0gY291bnQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChpbml0KSB7XG4gICAgICAgIHRoaXMub3ZlcmFsbFN1bW1hcmllc1t0YXNrSWRdID0ge1xuICAgICAgICAgIFRQOiB7fSxcbiAgICAgICAgICBGUDoge30sXG4gICAgICAgICAgRk46IHt9LFxuICAgICAgICAgIFN1cHBvcnQ6IHt9LFxuICAgICAgICB9O1xuICAgICAgICBmb3IgKGNvbnN0IGNvbmNlcHQgb2YgdGhpcy5jb25jZXB0c0ZpbHRlcmVkKSB7XG4gICAgICAgICAgdGhpcy5vdmVyYWxsU3VtbWFyaWVzW3Rhc2tJZF0uVFBbY29uY2VwdF0gPSB0aGlzLnN1bW1hcmllc1t0YXNrSWRdLlRQW2NvbmNlcHRdO1xuICAgICAgICAgIHRoaXMub3ZlcmFsbFN1bW1hcmllc1t0YXNrSWRdLkZQW2NvbmNlcHRdID0gdGhpcy5zdW1tYXJpZXNbdGFza0lkXS5GUFtjb25jZXB0XTtcbiAgICAgICAgICB0aGlzLm92ZXJhbGxTdW1tYXJpZXNbdGFza0lkXS5GTltjb25jZXB0XSA9IHRoaXMuc3VtbWFyaWVzW3Rhc2tJZF0uRk5bY29uY2VwdF07XG4gICAgICAgICAgdGhpcy5vdmVyYWxsU3VtbWFyaWVzW3Rhc2tJZF0uU3VwcG9ydFtjb25jZXB0XSA9IHRoaXMuc3VtbWFyaWVzW3Rhc2tJZF0uU3VwcG9ydFtjb25jZXB0XTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNoYW5nZVBhZ2UocGFnZT86IG51bWJlcik6IHZvaWQge1xuICAgIGlmIChwYWdlKSB7XG4gICAgICB0aGlzLnBhZ2UgPSBwYWdlO1xuICAgIH1cbiAgICB0aGlzLnBhZ2UgPSBNYXRoLm1pbihNYXRoLm1heCgrdGhpcy5wYWdlLCAxKSwgdGhpcy5uUGFnZXMpO1xuICAgIHRoaXMucGFnZU51bXMgPSBbXTtcbiAgICBsZXQgbG93TGltaXQ7XG4gICAgbGV0IHVwcExpbWl0O1xuICAgIGlmICh0aGlzLnBhZ2UgPD0gMikge1xuICAgICAgbG93TGltaXQgPSAxO1xuICAgICAgdXBwTGltaXQgPSBNYXRoLm1pbig1LCB0aGlzLm5QYWdlcyk7XG4gICAgfSBlbHNlIGlmIChNYXRoLmFicyh0aGlzLnBhZ2UgLSB0aGlzLm5QYWdlcykgPD0gMSkge1xuICAgICAgbG93TGltaXQgPSBNYXRoLm1heCgxLCB0aGlzLm5QYWdlcyAtIDQpO1xuICAgICAgdXBwTGltaXQgPSB0aGlzLm5QYWdlcztcbiAgICB9IGVsc2Uge1xuICAgICAgbG93TGltaXQgPSB0aGlzLnBhZ2UgLSAyO1xuICAgICAgdXBwTGltaXQgPSB0aGlzLnBhZ2UgKyAyO1xuICAgIH1cbiAgICBmb3IgKGxldCBpID0gbG93TGltaXQ7IGkgPD0gdXBwTGltaXQ7IGkrKykge1xuICAgICAgdGhpcy5wYWdlTnVtcyA9IHRoaXMucGFnZU51bXMuY29uY2F0KFtpXSk7XG4gICAgfVxuICAgIHRoaXMucm93T3JkZXJpbmcgPSB0aGlzLmNvbmNlcHRzRmlsdGVyZWQuc2xpY2UoKTtcbiAgICBpZiAoIXRoaXMucGFnZVNpemUpIHtcbiAgICAgIC8vIE5vIHBhZ2luZyByZXF1aXJlZFxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnJvd09yZGVyaW5nID0gdGhpcy5yb3dPcmRlcmluZy5zbGljZSgodGhpcy5wYWdlIC0gMSkgKiB0aGlzLnBhZ2VTaXplLCB0aGlzLnBhZ2UgKiB0aGlzLnBhZ2VTaXplKTtcbiAgfVxuXG4gIG9uQ2hhbmdlKGV2ZW50OiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLnNlbGVjdGVkQ29uY2VwdHMgPSBldmVudDtcbiAgICB0aGlzLmdldFJvd3NUb1Nob3coKTtcbiAgfVxuXG4gIGNvdW50ZXIoaTogbnVtYmVyKTogQXJyYXk8YW55PiB7XG4gICAgcmV0dXJuIG5ldyBBcnJheShpKTtcbiAgfVxuXG4gIGdldFRhYmxlRGF0YSgpIHtcbiAgICBjb25zdCB0YWJsZUhlYWRlciA9IFsnY29uY2VwdCddLmNvbmNhdCh0aGlzLmNvbmNlcHRzRmlsdGVyZWQpO1xuICAgIGNvbnN0IHRhYmxlRGF0YSA9IFtdO1xuICAgIGZvciAoY29uc3QgY29uY2VwdCBvZiB0aGlzLmNvbmNlcHRzRmlsdGVyZWQpIHtcbiAgICAgIGNvbnN0IHJvdyA9IHsgY29uY2VwdCB9O1xuICAgICAgZm9yIChjb25zdCBjb25jZXB0MSBvZiB0aGlzLmNvbmNlcHRzRmlsdGVyZWQpIHtcbiAgICAgICAgcm93W2NvbmNlcHQxXSA9IHRoaXMudGFza0lkcy5tYXAodGFza0lkID0+IHtcbiAgICAgICAgICBjb25zdCBjb3VudCA9IHRoaXMuZGF0YVt0YXNrSWRdLm1hdHJpeFtjb25jZXB0XVtjb25jZXB0MV07XG4gICAgICAgICAgcmV0dXJuIGNvdW50ID09IG51bGwgPyAnLScgOiBjb3VudDtcbiAgICAgICAgfSkuam9pbignIC8gJyk7XG4gICAgICB9XG4gICAgICB0YWJsZURhdGEucHVzaChyb3cpO1xuICAgIH1cbiAgICB0aGlzLnRhYmxlRXhwb3J0LmVtaXQoeyB0YWJsZUhlYWRlciwgdGFibGVEYXRhIH0pO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgLy8gUGFnZSBzaXplIG11c3QgYmUgbm9uLXplcm87IHBhZ2Ugc2l6ZSA9IDAgbWVhbnMgYWxsIHRvIGJlIGRpc3BsYXllZCB3aXRob3V0IHBhZ2luZ1xuICAgIHRoaXMucGFnZVNpemUgPSBNYXRoLm1heCh0aGlzLnBhZ2VTaXplLCAwKTtcblxuICAgIHRoaXMuaW5pdGlhbGl6ZSgpO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoKTogdm9pZCB7XG4gICAgdGhpcy5pbml0aWFsaXplKCk7XG4gIH1cblxuICBpbml0aWFsaXplKCk6IHZvaWQge1xuICAgIHRoaXMudGFza0lkcyA9IE9iamVjdC5rZXlzKHRoaXMuZGF0YSk7XG4gICAgdGhpcy5zb3J0Q3JpdGVyaWEgPSB7XG4gICAgICBjcml0ZXJpYTogJ2FscGhhJyxcbiAgICAgIGRpcmVjdGlvbjogJ2FzYycsXG4gICAgICB0YXNrSWQ6IHRoaXMudGFza0lkc1swXSxcbiAgICB9O1xuICAgIHRoaXMuc2VsZWN0ZWRDb25jZXB0cyA9IFtdO1xuXG4gICAgbGV0IGNvbmNlcHRzQ29tYmluZWQgPSBbXTtcbiAgICBmb3IgKGNvbnN0IHRhc2tJZCBvZiB0aGlzLnRhc2tJZHMpIHtcbiAgICAgIGNvbmNlcHRzQ29tYmluZWQgPSBjb25jZXB0c0NvbWJpbmVkLmNvbmNhdCh0aGlzLmRhdGFbdGFza0lkXS5jb25jZXB0cyk7XG4gICAgfVxuICAgIHRoaXMuY29uY2VwdHMgPSBBcnJheS5mcm9tKG5ldyBTZXQoY29uY2VwdHNDb21iaW5lZCkpO1xuXG4gICAgZm9yIChjb25zdCB0YXNrSWQgb2YgdGhpcy50YXNrSWRzKSB7XG4gICAgICBmb3IgKGNvbnN0IGNvbmNlcHQgb2YgdGhpcy5jb25jZXB0cykge1xuICAgICAgICB0aGlzLmRhdGFbdGFza0lkXS5tYXRyaXhbY29uY2VwdF0gPSB0aGlzLmRhdGFbdGFza0lkXS5tYXRyaXhbY29uY2VwdF0gfHwge307XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5nZXRSb3dzVG9TaG93KHRydWUpO1xuICB9XG5cbn1cbiJdfQ==