ngx-text-diff
Version:
A Text Diff component for Angular.
270 lines • 41.1 kB
JavaScript
import { __awaiter, __decorate, __generator, __metadata } from "tslib";
import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, Output, EventEmitter, ViewChildren, QueryList, AfterViewInit } from '@angular/core';
import { NgxTextDiffService } from './ngx-text-diff.service';
import { Observable } from 'rxjs';
import { ContainerDirective } from './ngx-text-diff-container.directive';
import { ScrollDispatcher, CdkScrollable } from '@angular/cdk/scrolling';
var NgxTextDiffComponent = /** @class */ (function () {
function NgxTextDiffComponent(scrollService, diff, cd) {
this.scrollService = scrollService;
this.diff = diff;
this.cd = cd;
this._hideMatchingLines = false;
this.format = 'SideBySide';
this.left = '';
this.right = '';
this.loading = false;
this.showToolbar = true;
this.showBtnToolbar = true;
this.synchronizeScrolling = true;
this.compareResults = new EventEmitter();
this.subscriptions = [];
this.tableRows = [];
this.filteredTableRows = [];
this.tableRowsLineByLine = [];
this.filteredTableRowsLineByLine = [];
this.diffsCount = 0;
this.formatOptions = [
{
id: 'side-by-side',
name: 'side-by-side',
label: 'Side by Side',
value: 'SideBySide',
icon: 'la-code',
},
{
id: 'line-by-line',
name: 'line-by-line',
label: 'Line by Line',
value: 'LineByLine',
icon: 'la-file-text',
},
];
}
Object.defineProperty(NgxTextDiffComponent.prototype, "hideMatchingLines", {
get: function () {
return this._hideMatchingLines;
},
set: function (hide) {
this.hideMatchingLinesChanged(hide);
},
enumerable: true,
configurable: true
});
NgxTextDiffComponent.prototype.ngOnInit = function () {
var _this = this;
this.loading = true;
if (this.diffContent) {
this.subscriptions.push(this.diffContent.subscribe(function (content) {
_this.loading = true;
_this.left = content.leftContent;
_this.right = content.rightContent;
_this.renderDiffs()
.then(function () {
_this.cd.detectChanges();
_this.loading = false;
})
.catch(function () { return (_this.loading = false); });
}));
}
this.renderDiffs()
.then(function () { return (_this.loading = false); })
.catch(function (e) { return (_this.loading = false); });
};
NgxTextDiffComponent.prototype.ngAfterViewInit = function () {
this.initScrollListener();
};
NgxTextDiffComponent.prototype.ngOnDestroy = function () {
if (this.subscriptions) {
this.subscriptions.forEach(function (subscription) { return subscription.unsubscribe(); });
}
};
NgxTextDiffComponent.prototype.hideMatchingLinesChanged = function (value) {
this._hideMatchingLines = value;
if (this.hideMatchingLines) {
this.filteredTableRows = this.tableRows.filter(function (row) { return (row.leftContent && row.leftContent.prefix === '-') || (row.rightContent && row.rightContent.prefix === '+'); });
this.filteredTableRowsLineByLine = this.tableRowsLineByLine.filter(function (row) { return (row.leftContent && row.leftContent.prefix === '-') || (row.rightContent && row.rightContent.prefix === '+'); });
}
else {
this.filteredTableRows = this.tableRows;
this.filteredTableRowsLineByLine = this.tableRowsLineByLine;
}
};
NgxTextDiffComponent.prototype.setDiffTableFormat = function (format) {
this.format = format;
};
NgxTextDiffComponent.prototype.renderDiffs = function () {
return __awaiter(this, void 0, void 0, function () {
var _a, e_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, 2, , 3]);
this.diffsCount = 0;
_a = this;
return [4 /*yield*/, this.diff.getDiffsByLines(this.left, this.right)];
case 1:
_a.tableRows = _b.sent();
this.tableRowsLineByLine = this.tableRows.reduce(function (tableLineByLine, row) {
if (!tableLineByLine) {
tableLineByLine = [];
}
if (row.hasDiffs) {
if (row.leftContent) {
tableLineByLine.push({
leftContent: row.leftContent,
rightContent: null,
belongTo: row.belongTo,
hasDiffs: true,
numDiffs: row.numDiffs,
});
}
if (row.rightContent) {
tableLineByLine.push({
leftContent: null,
rightContent: row.rightContent,
belongTo: row.belongTo,
hasDiffs: true,
numDiffs: row.numDiffs,
});
}
}
else {
tableLineByLine.push(row);
}
return tableLineByLine;
}, []);
this.diffsCount = this.tableRows.filter(function (row) { return row.hasDiffs; }).length;
this.filteredTableRows = this.tableRows;
this.filteredTableRowsLineByLine = this.tableRowsLineByLine;
this.emitCompareResultsEvent();
return [3 /*break*/, 3];
case 2:
e_1 = _b.sent();
throw e_1;
case 3: return [2 /*return*/];
}
});
});
};
NgxTextDiffComponent.prototype.emitCompareResultsEvent = function () {
var diffResults = {
hasDiff: this.diffsCount > 0,
diffsCount: this.diffsCount,
rowsWithDiff: this.tableRows
.filter(function (row) { return row.hasDiffs; })
.map(function (row) { return ({
leftLineNumber: row.leftContent ? row.leftContent.lineNumber : null,
rightLineNumber: row.rightContent ? row.rightContent.lineNumber : null,
numDiffs: row.numDiffs,
}); }),
};
this.compareResults.next(diffResults);
};
NgxTextDiffComponent.prototype.trackTableRows = function (index, row) {
return row && row.leftContent ? row.leftContent.lineContent : row && row.rightContent ? row.rightContent.lineContent : undefined;
};
NgxTextDiffComponent.prototype.trackDiffs = function (index, diff) {
return diff && diff.content ? diff.content : undefined;
};
NgxTextDiffComponent.prototype.initScrollListener = function () {
var _this = this;
this.subscriptions.push(this.scrollService.scrolled().subscribe(function (scrollableEv) {
if (scrollableEv && _this.synchronizeScrolling) {
var scrollableId_1 = scrollableEv.getElementRef().nativeElement.id;
var nonScrolledContainer = _this.containers.find(function (container) { return container.id !== scrollableId_1; });
if (nonScrolledContainer) {
nonScrolledContainer.element.scrollTo({
top: scrollableEv.measureScrollOffset('top'),
left: scrollableEv.measureScrollOffset('left'),
});
}
}
}));
};
NgxTextDiffComponent.ctorParameters = function () { return [
{ type: ScrollDispatcher },
{ type: NgxTextDiffService },
{ type: ChangeDetectorRef }
]; };
__decorate([
ViewChildren(ContainerDirective),
__metadata("design:type", QueryList)
], NgxTextDiffComponent.prototype, "containers", void 0);
__decorate([
Input(),
__metadata("design:type", String)
], NgxTextDiffComponent.prototype, "format", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "left", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "right", void 0);
__decorate([
Input(),
__metadata("design:type", Observable)
], NgxTextDiffComponent.prototype, "diffContent", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "loading", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "showToolbar", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "showBtnToolbar", void 0);
__decorate([
Input(),
__metadata("design:type", Boolean),
__metadata("design:paramtypes", [Boolean])
], NgxTextDiffComponent.prototype, "hideMatchingLines", null);
__decorate([
Input(),
__metadata("design:type", String)
], NgxTextDiffComponent.prototype, "outerContainerClass", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "outerContainerStyle", void 0);
__decorate([
Input(),
__metadata("design:type", String)
], NgxTextDiffComponent.prototype, "toolbarClass", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "toolbarStyle", void 0);
__decorate([
Input(),
__metadata("design:type", String)
], NgxTextDiffComponent.prototype, "compareRowsClass", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "compareRowsStyle", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "synchronizeScrolling", void 0);
__decorate([
Output(),
__metadata("design:type", Object)
], NgxTextDiffComponent.prototype, "compareResults", void 0);
NgxTextDiffComponent = __decorate([
Component({
selector: 'td-ngx-text-diff',
template: "<td-loader-spinner [active]=\"loading\"></td-loader-spinner>\r\n<div class=\"td-wrapper\" [ngClass]=\"outerContainerClass\" [ngStyle]=\"outerContainerStyle\" *ngIf=\"!loading\">\r\n\r\n <div [ngClass]=\"toolbarClass\" [ngStyle]=\"toolbarStyle\" *ngIf=\"showToolbar\">\r\n <div class=\"td-toolbar-show-diff\">\r\n <label class=\"td-checkbox-container\">\r\n Only Show Lines with Differences ({{ diffsCount }})\r\n <input type=\"checkbox\" id=\"showDiffs\" [ngModel]=\"hideMatchingLines\" (ngModelChange)=\"hideMatchingLinesChanged($event)\" />\r\n <span class=\"checkmark\"></span>\r\n </label>\r\n </div>\r\n </div>\r\n\r\n <div class=\"td-toolbar-select-format\" *ngIf=\"showToolbar && showBtnToolbar\">\r\n <div class=\"td-btn-group td-btn-group-toggle\" data-toggle=\"buttons\">\r\n <button\r\n *ngFor=\"let option of formatOptions\"\r\n [ngClass]=\"{ active: format === option.value, disabled: !!option.disabled }\"\r\n [name]=\"option.name\"\r\n [id]=\"option.id\"\r\n [disabled]=\"!!option.disabled\"\r\n (click)=\"setDiffTableFormat(option.value)\"\r\n >\r\n {{ option.label }}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"td-table-wrapper\" [ngClass]=\"compareRowsClass\" [ngStyle]=\"compareRowsStyle\">\r\n <!-- Right side-by-side -->\r\n <div class=\"td-table-container side-by-side\" *ngIf=\"format === 'SideBySide'\" id=\"td-left-compare-container\" tdContainer cdkScrollable>\r\n <table class=\"td-table\">\r\n <tbody>\r\n <tr *ngFor=\"let row of filteredTableRows; trackBy: trackTableRows\">\r\n <td\r\n scope=\"row\"\r\n class=\"fit-column line-number-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'empty-row': !row.leftContent?.lineContent }\"\r\n >\r\n {{ row.leftContent?.lineNumber !== -1 ? row.leftContent?.lineNumber : ' ' }}\r\n </td>\r\n <td\r\n class=\"fit-column prefix-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'empty-row': !row.leftContent?.lineContent }\"\r\n >\r\n <span>{{ row.leftContent?.prefix || ' ' }}</span>\r\n </td>\r\n <td\r\n class=\"content-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'empty-row': !row.leftContent?.lineContent }\"\r\n *ngIf=\"!row.hasDiffs\"\r\n >\r\n <span [innerHTML]=\"row.leftContent?.lineContent | formatLine\"></span>\r\n </td>\r\n <td\r\n class=\"content-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'empty-row': !row.leftContent?.lineContent }\"\r\n *ngIf=\"row.hasDiffs\"\r\n >\r\n <span\r\n [innerHTML]=\"diff.content | formatLine\"\r\n [ngClass]=\"{ highlight: diff.isDiff }\"\r\n *ngFor=\"let diff of row.leftContent?.lineDiffs; trackBy: trackDiffs\"\r\n ></span>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <!-- Left side-by-side -->\r\n <div class=\"td-table-container side-by-side\" *ngIf=\"format === 'SideBySide'\" id=\"td-right-compare-container\" tdContainer cdkScrollable>\r\n <table class=\"td-table\">\r\n <tbody>\r\n <tr *ngFor=\"let row of filteredTableRows; trackBy: trackTableRows\">\r\n <td\r\n scope=\"row\"\r\n class=\"fit-column line-number-col\"\r\n [ngClass]=\"{ 'insert-row': row.rightContent?.prefix === '+', 'empty-row': !row.rightContent?.lineContent }\"\r\n >\r\n {{ row.rightContent?.lineNumber !== -1 ? row.rightContent?.lineNumber : ' ' }}\r\n </td>\r\n <td\r\n class=\"fit-column prefix-col\"\r\n [ngClass]=\"{ 'insert-row': row.rightContent?.prefix === '+', 'empty-row': !row.rightContent?.lineContent }\"\r\n >\r\n <span>{{ row.rightContent?.prefix || ' ' }}</span>\r\n </td>\r\n <td\r\n class=\"content-col\"\r\n [ngClass]=\"{ 'insert-row': row.rightContent?.prefix === '+', 'empty-row': !row.rightContent?.lineContent }\"\r\n *ngIf=\"!row.hasDiffs\"\r\n >\r\n <span [innerHTML]=\"row.rightContent?.lineContent | formatLine\"></span>\r\n </td>\r\n <td\r\n class=\"content-col\"\r\n [ngClass]=\"{ 'insert-row': row.rightContent?.prefix === '+', 'empty-row': !row.rightContent?.lineContent }\"\r\n *ngIf=\"row.hasDiffs\"\r\n >\r\n <span\r\n [innerHTML]=\"diff.content | formatLine\"\r\n [ngClass]=\"{ highlight: diff.isDiff }\"\r\n *ngFor=\"let diff of row.rightContent?.lineDiffs; trackBy: trackDiffs\"\r\n ></span>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <!-- Line By Line - combined table -->\r\n <div class=\"td-table-container line-by-line\" *ngIf=\"format === 'LineByLine'\">\r\n <table class=\"td-table\">\r\n <tbody>\r\n <tr *ngFor=\"let row of filteredTableRowsLineByLine; trackBy: trackTableRows\">\r\n <td scope=\"row\" class=\"fit-column line-number-col-left\">{{ row.leftContent?.lineNumber }}</td>\r\n <td scope=\"row\" class=\"fit-column line-number-col\">{{ row.rightContent?.lineNumber }}</td>\r\n <td\r\n class=\"fit-column prefix-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'insert-row': row.rightContent?.prefix === '+' }\"\r\n >\r\n <span>{{ row.leftContent?.prefix || row.rightContent?.prefix || ' ' }}</span>\r\n </td>\r\n <td\r\n class=\"content-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'insert-row': row.rightContent?.prefix === '+' }\"\r\n *ngIf=\"!row.hasDiffs\"\r\n >\r\n <span [innerHTML]=\"row.leftContent?.lineContent | formatLine\"></span>\r\n </td>\r\n <td\r\n class=\"content-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'insert-row': row.rightContent?.prefix === '+' }\"\r\n *ngIf=\"row.hasDiffs && row.leftContent && row.leftContent?.lineDiffs.length !== 0\"\r\n >\r\n <span\r\n [innerHTML]=\"diff.content | formatLine\"\r\n [ngClass]=\"{ highlight: diff.isDiff }\"\r\n *ngFor=\"let diff of row.leftContent?.lineDiffs; trackBy: trackDiffs\"\r\n ></span>\r\n </td>\r\n <td\r\n class=\"content-col\"\r\n [ngClass]=\"{ 'delete-row': row.leftContent?.prefix === '-', 'insert-row': row.rightContent?.prefix === '+' }\"\r\n *ngIf=\"row.hasDiffs && row.rightContent && row.rightContent?.lineDiffs.length !== 0\"\r\n >\r\n <span\r\n [innerHTML]=\"diff.content | formatLine\"\r\n [ngClass]=\"{ highlight: diff.isDiff }\"\r\n *ngFor=\"let diff of row.rightContent?.lineDiffs; trackBy: trackDiffs\"\r\n ></span>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n</div>\r\n",
styles: [".td-wrapper{display:grid;width:100%;grid-row-gap:10px;grid-template-columns:repeat(2,[col] 50%);grid-template-rows:repeat(2,[row] auto);background-color:#fff;color:#444}.td-toolbar-show-diff{grid-column:1;grid-row:1}.td-toolbar-select-format{margin-left:auto;grid-column:2;grid-row:1}.td-table-container{grid-column:1/2;grid-row:2;width:100%;max-width:100%;overflow-x:auto}.td-table-wrapper{display:flex;width:200%}.td-table{border:1px solid #a9a9a9;max-height:50vh;width:100%;max-width:100%}.fit-column{width:1px;white-space:nowrap}.line-number-col{position:relative;position:-webkit-sticky;position:sticky;left:0;top:auto;border-right:1px solid #ddd;color:#999;text-align:right;background-color:#f7f7f7;padding-left:10px;padding-right:10px;font-size:87.5%}.line-number-col-left{color:#999;padding-left:10px;padding-right:10px;text-align:right;background-color:#f7f7f7;font-size:87.5%}.insert-row,.insert-row>.line-number-col{background-color:#dfd;border-color:#b4e2b4}.delete-row,.delete-row>.line-number-col{background-color:#fee8e9;border-color:#e9aeae}.empty-row{background-color:#f7f7f7;height:24px}.td-table td{border-top:0;padding-top:0;padding-bottom:0;white-space:nowrap;max-width:50%}pre{margin-bottom:0}td.content-col{padding:0;margin:0;line-height:24px}td.prefix-col{padding-left:10px;padding-right:10px;line-height:24px}.td-btn-group{border-radius:4px}.td-btn-group button{background-color:rgba(23,162,184,.7);border:1px solid #17a2b8;color:#fff;cursor:pointer;float:left}.td-btn-group button:not(:last-child){border-right:none}.td-btn-group button:first-child{-webkit-border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-topleft:4px;-moz-border-radius-bottomleft:4px;border-top-left-radius:4px;border-bottom-left-radius:4px}.td-btn-group button:last-child{-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px;border-top-right-radius:4px;border-bottom-right-radius:4px}.td-btn-group:after{content:'';clear:both;display:table}.td-btn-group button.active,.td-btn-group button:hover{background-color:#17a2b8}.td-checkbox-container{display:block;position:relative;padding-left:21px;margin-bottom:0;cursor:pointer;font-size:16px;line-height:28px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.td-checkbox-container input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.checkmark{position:absolute;top:7px;left:0;height:16px;width:16px;background-color:#eee}.td-checkbox-container:hover input~.checkmark{background-color:#ccc}.td-checkbox-container input:checked~.checkmark{background-color:#17a2b8}.checkmark:after{content:\"\";position:absolute;display:none}.td-checkbox-container input:checked~.checkmark:after{display:block}.td-checkbox-container .checkmark:after{left:5px;top:3px;width:5px;height:10px;border:solid #fff;border-width:0 3px 3px 0;transform:rotate(45deg)}.insert-row>.highlight{background-color:#acf2bd!important}.delete-row>.highlight{background-color:#fdb8c0!important}"]
}),
__metadata("design:paramtypes", [ScrollDispatcher, NgxTextDiffService, ChangeDetectorRef])
], NgxTextDiffComponent);
return NgxTextDiffComponent;
}());
export { NgxTextDiffComponent };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXRleHQtZGlmZi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtdGV4dC1kaWZmLyIsInNvdXJjZXMiOlsibGliL25neC10ZXh0LWRpZmYuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxLQUFLLEVBQ0wsU0FBUyxFQUNULE1BQU0sRUFDTixNQUFNLEVBQ04sWUFBWSxFQUNaLFlBQVksRUFDWixTQUFTLEVBQ1QsYUFBYSxFQUNkLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzdELE9BQU8sRUFBRSxVQUFVLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBQ2hELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQU96RTtJQWtERSw4QkFBb0IsYUFBK0IsRUFBVSxJQUF3QixFQUFVLEVBQXFCO1FBQWhHLGtCQUFhLEdBQWIsYUFBYSxDQUFrQjtRQUFVLFNBQUksR0FBSixJQUFJLENBQW9CO1FBQVUsT0FBRSxHQUFGLEVBQUUsQ0FBbUI7UUFqRDVHLHVCQUFrQixHQUFHLEtBQUssQ0FBQztRQUUxQixXQUFNLEdBQW9CLFlBQVksQ0FBQztRQUN2QyxTQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ1YsVUFBSyxHQUFHLEVBQUUsQ0FBQztRQUVYLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFDaEIsZ0JBQVcsR0FBRyxJQUFJLENBQUM7UUFDbkIsbUJBQWMsR0FBRyxJQUFJLENBQUM7UUFldEIseUJBQW9CLEdBQUcsSUFBSSxDQUFDO1FBQzNCLG1CQUFjLEdBQUcsSUFBSSxZQUFZLEVBQWUsQ0FBQztRQUMzRCxrQkFBYSxHQUFtQixFQUFFLENBQUM7UUFDbkMsY0FBUyxHQUF5QixFQUFF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SyxFQUFFOztxRUFBMEI7SUFDekI7UUFBUixLQUFLLEVBQUU7OzhEQUFzQjtJQUNyQjtRQUFSLEtBQUssRUFBRTs7OERBQW1CO0lBQ2xCO1FBQVIsS0FBSyxFQUFFOztrRUFBMEI7SUFDekI7UUFBUixLQUFLLEVBQUU7O2tFQUF1QjtJQUN0QjtRQUFSLEtBQUssRUFBRTs7c0VBQTZCO0lBQzNCO1FBQVQsTUFBTSxFQUFFOztnRUFBa0Q7SUF6QmhELG9CQUFvQjtRQUxoQyxTQUFTLENBQUM7WUFDVCxRQUFRLEVBQUUsa0JBQWtCO1lBQzVCLHcvT0FBNkM7O1NBRTlDLENBQUM7eUNBbURtQyxnQkFBZ0IsRUFBZ0Isa0JBQWtCLEVBQWMsaUJBQWlCO09BbER6RyxvQkFBb0IsQ0F1TGhDO0lBQUQsMkJBQUM7Q0FBQSxBQXZMRCxJQXVMQztTQXZMWSxvQkFBb0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIENoYW5nZURldGVjdG9yUmVmLFxyXG4gIENvbXBvbmVudCxcclxuICBJbnB1dCxcclxuICBPbkRlc3Ryb3ksXHJcbiAgT25Jbml0LFxyXG4gIE91dHB1dCxcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgVmlld0NoaWxkcmVuLFxyXG4gIFF1ZXJ5TGlzdCxcclxuICBBZnRlclZpZXdJbml0XHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IERpZmZDb250ZW50LCBEaWZmUGFydCwgRGlmZlRhYmxlRm9ybWF0LCBEaWZmVGFibGVGb3JtYXRPcHRpb24sIERpZmZUYWJsZVJvd1Jlc3VsdCwgRGlmZlJlc3VsdHMgfSBmcm9tICcuL25neC10ZXh0LWRpZmYubW9kZWwnO1xyXG5pbXBvcnQgeyBOZ3hUZXh0RGlmZlNlcnZpY2UgfSBmcm9tICcuL25neC10ZXh0LWRpZmYuc2VydmljZSc7XHJcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBDb250YWluZXJEaXJlY3RpdmUgfSBmcm9tICcuL25neC10ZXh0LWRpZmYtY29udGFpbmVyLmRpcmVjdGl2ZSc7XHJcbmltcG9ydCB7IFNjcm9sbERpc3BhdGNoZXIsIENka1Njcm9sbGFibGUgfSBmcm9tICdAYW5ndWxhci9jZGsvc2Nyb2xsaW5nJztcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAndGQtbmd4LXRleHQtZGlmZicsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL25neC10ZXh0LWRpZmYuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL25neC10ZXh0LWRpZmYuY29tcG9uZW50LmNzcyddLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTmd4VGV4dERpZmZDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XHJcbiAgcHJpdmF0ZSBfaGlkZU1hdGNoaW5nTGluZXMgPSBmYWxzZTtcclxuICBAVmlld0NoaWxkcmVuKENvbnRhaW5lckRpcmVjdGl2ZSkgY29udGFpbmVyczogUXVlcnlMaXN0PENvbnRhaW5lckRpcmVjdGl2ZT47XHJcbiAgQElucHV0KCkgZm9ybWF0OiBEaWZmVGFibGVGb3JtYXQgPSAnU2lkZUJ5U2lkZSc7XHJcbiAgQElucHV0KCkgbGVmdCA9ICcnO1xyXG4gIEBJbnB1dCgpIHJpZ2h0ID0gJyc7XHJcbiAgQElucHV0KCkgZGlmZkNvbnRlbnQ6IE9ic2VydmFibGU8RGlmZkNvbnRlbnQ+O1xyXG4gIEBJbnB1dCgpIGxvYWRpbmcgPSBmYWxzZTtcclxuICBASW5wdXQoKSBzaG93VG9vbGJhciA9IHRydWU7XHJcbiAgQElucHV0KCkgc2hvd0J0blRvb2xiYXIgPSB0cnVlO1xyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IGhpZGVNYXRjaGluZ0xpbmVzKCkge1xyXG4gICAgcmV0dXJuIHRoaXMuX2hpZGVNYXRjaGluZ0xpbmVzO1xyXG4gIH1cclxuXHJcbiAgc2V0IGhpZGVNYXRjaGluZ0xpbmVzKGhpZGU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuaGlkZU1hdGNoaW5nTGluZXNDaGFuZ2VkKGhpZGUpO1xyXG4gIH1cclxuICBASW5wdXQoKSBvdXRlckNvbnRhaW5lckNsYXNzOiBzdHJpbmc7XHJcbiAgQElucHV0KCkgb3V0ZXJDb250YWluZXJTdHlsZTogYW55O1xyXG4gIEBJbnB1dCgpIHRvb2xiYXJDbGFzczogc3RyaW5nO1xyXG4gIEBJbnB1dCgpIHRvb2xiYXJTdHlsZTogYW55O1xyXG4gIEBJbnB1dCgpIGNvbXBhcmVSb3dzQ2xhc3M6IHN0cmluZztcclxuICBASW5wdXQoKSBjb21wYXJlUm93c1N0eWxlOiBhbnk7XHJcbiAgQElucHV0KCkgc3luY2hyb25pemVTY3JvbGxpbmcgPSB0cnVlO1xyXG4gIEBPdXRwdXQoKSBjb21wYXJlUmVzdWx0cyA9IG5ldyBFdmVudEVtaXR0ZXI8RGlmZlJlc3VsdHM+KCk7XHJcbiAgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcclxuICB0YWJsZVJvd3M6IERpZmZUYWJsZVJvd1Jlc3VsdFtdID0gW107XHJcbiAgZmlsdGVyZWRUYWJsZVJvd3M6IERpZmZUYWJsZVJvd1Jlc3VsdFtdID0gW107XHJcbiAgdGFibGVSb3dzTGluZUJ5TGluZTogRGlmZlRhYmxlUm93UmVzdWx0W10gPSBbXTtcclxuICBmaWx0ZXJlZFRhYmxlUm93c0xpbmVCeUxpbmU6IERpZmZUYWJsZVJvd1Jlc3VsdFtdID0gW107XHJcbiAgZGlmZnNDb3VudCA9IDA7XHJcblxyXG4gIGZvcm1hdE9wdGlvbnM6IERpZmZUYWJsZUZvcm1hdE9wdGlvbltdID0gW1xyXG4gICAge1xyXG4gICAgICBpZDogJ3NpZGUtYnktc2lkZScsXHJcbiAgICAgIG5hbWU6ICdzaWRlLWJ5LXNpZGUnLFxyXG4gICAgICBsYWJlbDogJ1NpZGUgYnkgU2lkZScsXHJcbiAgICAgIHZhbHVlOiAnU2lkZUJ5U2lkZScsXHJcbiAgICAgIGljb246ICdsYS1jb2RlJyxcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIGlkOiAnbGluZS1ieS1saW5lJyxcclxuICAgICAgbmFtZTogJ2xpbmUtYnktbGluZScsXHJcbiAgICAgIGxhYmVsOiAnTGluZSBieSBMaW5lJyxcclxuICAgICAgdmFsdWU6ICdMaW5lQnlMaW5lJyxcclxuICAgICAgaWNvbjogJ2xhLWZpbGUtdGV4dCcsXHJcbiAgICB9LFxyXG4gIF07XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgc2Nyb2xsU2VydmljZTogU2Nyb2xsRGlzcGF0Y2hlciwgcHJpdmF0ZSBkaWZmOiBOZ3hUZXh0RGlmZlNlcnZpY2UsIHByaXZhdGUgY2Q6IENoYW5nZURldGVjdG9yUmVmKSB7fVxyXG5cclxuICBuZ09uSW5pdCgpIHtcclxuICAgIHRoaXMubG9hZGluZyA9IHRydWU7XHJcbiAgICBpZiAodGhpcy5kaWZmQ29udGVudCkge1xyXG4gICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcclxuICAgICAgICB0aGlzLmRpZmZDb250ZW50LnN1YnNjcmliZShjb250ZW50ID0+IHtcclxuICAgICAgICAgIHRoaXMubG9hZGluZyA9IHRydWU7XHJcbiAgICAgICAgICB0aGlzLmxlZnQgPSBjb250ZW50LmxlZnRDb250ZW50O1xyXG4gICAgICAgICAgdGhpcy5yaWdodCA9IGNvbnRlbnQucmlnaHRDb250ZW50O1xyXG4gICAgICAgICAgdGhpcy5yZW5kZXJEaWZmcygpXHJcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcclxuICAgICAgICAgICAgICB0aGlzLmNkLmRldGVjdENoYW5nZXMoKTtcclxuICAgICAgICAgICAgICB0aGlzLmxvYWRpbmcgPSBmYWxzZTtcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgLmNhdGNoKCgpID0+ICh0aGlzLmxvYWRpbmcgPSBmYWxzZSkpO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnJlbmRlckRpZmZzKClcclxuICAgICAgLnRoZW4oKCkgPT4gKHRoaXMubG9hZGluZyA9IGZhbHNlKSlcclxuICAgICAgLmNhdGNoKGUgPT4gKHRoaXMubG9hZGluZyA9IGZhbHNlKSk7XHJcbiAgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKSB7XHJcbiAgICB0aGlzLmluaXRTY3JvbGxMaXN0ZW5lcigpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5zdWJzY3JpcHRpb25zKSB7XHJcbiAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5mb3JFYWNoKHN1YnNjcmlwdGlvbiA9PiBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBoaWRlTWF0Y2hpbmdMaW5lc0NoYW5nZWQodmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2hpZGVNYXRjaGluZ0xpbmVzID0gdmFsdWU7XHJcbiAgICBpZiAodGhpcy5oaWRlTWF0Y2hpbmdMaW5lcykge1xyXG4gICAgICB0aGlzLmZpbHRlcmVkVGFibGVSb3dzID0gdGhpcy50YWJsZVJvd3MuZmlsdGVyKFxyXG4gICAgICAgIHJvdyA9PiAocm93LmxlZnRDb250ZW50ICYmIHJvdy5sZWZ0Q29udGVudC5wcmVmaXggPT09ICctJykgfHwgKHJvdy5yaWdodENvbnRlbnQgJiYgcm93LnJpZ2h0Q29udGVudC5wcmVmaXggPT09ICcrJylcclxuICAgICAgKTtcclxuICAgICAgdGhpcy5maWx0ZXJlZFRhYmxlUm93c0xpbmVCeUxpbmUgPSB0aGlzLnRhYmxlUm93c0xpbmVCeUxpbmUuZmlsdGVyKFxyXG4gICAgICAgIHJvdyA9PiAocm93LmxlZnRDb250ZW50ICYmIHJvdy5sZWZ0Q29udGVudC5wcmVmaXggPT09ICctJykgfHwgKHJvdy5yaWdodENvbnRlbnQgJiYgcm93LnJpZ2h0Q29udGVudC5wcmVmaXggPT09ICcrJylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuZmlsdGVyZWRUYWJsZVJvd3MgPSB0aGlzLnRhYmxlUm93cztcclxuICAgICAgdGhpcy5maWx0ZXJlZFRhYmxlUm93c0xpbmVCeUxpbmUgPSB0aGlzLnRhYmxlUm93c0xpbmVCeUxpbmU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzZXREaWZmVGFibGVGb3JtYXQoZm9ybWF0OiBEaWZmVGFibGVGb3JtYXQpIHtcclxuICAgIHRoaXMuZm9ybWF0ID0gZm9ybWF0O1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgcmVuZGVyRGlmZnMoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICB0aGlzLmRpZmZzQ291bnQgPSAwO1xyXG4gICAgICB0aGlzLnRhYmxlUm93cyA9IGF3YWl0IHRoaXMuZGlmZi5nZXREaWZmc0J5TGluZXModGhpcy5sZWZ0LCB0aGlzLnJpZ2h0KTtcclxuICAgICAgdGhpcy50YWJsZVJvd3NMaW5lQnlMaW5lID0gdGhpcy50YWJsZVJvd3MucmVkdWNlKCh0YWJsZUxpbmVCeUxpbmU6IERpZmZUYWJsZVJvd1Jlc3VsdFtdLCByb3c6IERpZmZUYWJsZVJvd1Jlc3VsdCkgPT4ge1xyXG4gICAgICAgIGlmICghdGFibGVMaW5lQnlMaW5lKSB7XHJcbiAgICAgICAgICB0YWJsZUxpbmVCeUxpbmUgPSBbXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHJvdy5oYXNEaWZmcykge1xyXG4gICAgICAgICAgaWYgKHJvdy5sZWZ0Q29udGVudCkge1xyXG4gICAgICAgICAgICB0YWJsZUxpbmVCeUxpbmUucHVzaCh7XHJcbiAgICAgICAgICAgICAgbGVmdENvbnRlbnQ6IHJvdy5sZWZ0Q29udGVudCxcclxuICAgICAgICAgICAgICByaWdodENvbnRlbnQ6IG51bGwsXHJcbiAgICAgICAgICAgICAgYmVsb25nVG86IHJvdy5iZWxvbmdUbyxcclxuICAgICAgICAgICAgICBoYXNEaWZmczogdHJ1ZSxcclxuICAgICAgICAgICAgICBudW1EaWZmczogcm93Lm51bURpZmZzLFxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGlmIChyb3cucmlnaHRDb250ZW50KSB7XHJcbiAgICAgICAgICAgIHRhYmxlTGluZUJ5TGluZS5wdXNoKHtcclxuICAgICAgICAgICAgICBsZWZ0Q29udGVudDogbnVsbCxcclxuICAgICAgICAgICAgICByaWdodENvbnRlbnQ6IHJvdy5yaWdodENvbnRlbnQsXHJcbiAgICAgICAgICAgICAgYmVsb25nVG86IHJvdy5iZWxvbmdUbyxcclxuICAgICAgICAgICAgICBoYXNEaWZmczogdHJ1ZSxcclxuICAgICAgICAgICAgICBudW1EaWZmczogcm93Lm51bURpZmZzLFxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGFibGVMaW5lQnlMaW5lLnB1c2gocm93KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiB0YWJsZUxpbmVCeUxpbmU7XHJcbiAgICAgIH0sIFtdKTtcclxuICAgICAgdGhpcy5kaWZmc0NvdW50ID0gdGhpcy50YWJsZVJvd3MuZmlsdGVyKHJvdyA9PiByb3cuaGFzRGlmZnMpLmxlbmd0aDtcclxuICAgICAgdGhpcy5maWx0ZXJlZFRhYmxlUm93cyA9IHRoaXMudGFibGVSb3dzO1xyXG4gICAgICB0aGlzLmZpbHRlcmVkVGFibGVSb3dzTGluZUJ5TGluZSA9IHRoaXMudGFibGVSb3dzTGluZUJ5TGluZTtcclxuICAgICAgdGhpcy5lbWl0Q29tcGFyZVJlc3VsdHNFdmVudCgpO1xyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICB0aHJvdyBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZW1pdENvbXBhcmVSZXN1bHRzRXZlbnQoKSB7XHJcbiAgICBjb25zdCBkaWZmUmVzdWx0czogRGlmZlJlc3VsdHMgPSB7XHJcbiAgICAgIGhhc0RpZmY6IHRoaXMuZGlmZnNDb3VudCA+IDAsXHJcbiAgICAgIGRpZmZzQ291bnQ6IHRoaXMuZGlmZnNDb3VudCxcclxuICAgICAgcm93c1dpdGhEaWZmOiB0aGlzLnRhYmxlUm93c1xyXG4gICAgICAgIC5maWx0ZXIocm93ID0+IHJvdy5oYXNEaWZmcylcclxuICAgICAgICAubWFwKHJvdyA9PiAoe1xyXG4gICAgICAgICAgbGVmdExpbmVOdW1iZXI6IHJvdy5sZWZ0Q29udGVudCA/IHJvdy5sZWZ0Q29udGVudC5saW5lTnVtYmVyIDogbnVsbCxcclxuICAgICAgICAgIHJpZ2h0TGluZU51bWJlcjogcm93LnJpZ2h0Q29udGVudCA/IHJvdy5yaWdodENvbnRlbnQubGluZU51bWJlciA6IG51bGwsXHJcbiAgICAgICAgICBudW1EaWZmczogcm93Lm51bURpZmZzLFxyXG4gICAgICAgIH0pKSxcclxuICAgIH07XHJcblxyXG4gICAgdGhpcy5jb21wYXJlUmVzdWx0cy5uZXh0KGRpZmZSZXN1bHRzKTtcclxuICB9XHJcblxyXG4gIHRyYWNrVGFibGVSb3dzKGluZGV4LCByb3c6IERpZmZUYWJsZVJvd1Jlc3VsdCkge1xyXG4gICAgcmV0dXJuIHJvdyAmJiByb3cubGVmdENvbnRlbnQgPyByb3cubGVmdENvbnRlbnQubGluZUNvbnRlbnQgOiByb3cgJiYgcm93LnJpZ2h0Q29udGVudCA/IHJvdy5yaWdodENvbnRlbnQubGluZUNvbnRlbnQgOiB1bmRlZmluZWQ7XHJcbiAgfVxyXG5cclxuICB0cmFja0RpZmZzKGluZGV4LCBkaWZmOiBEaWZmUGFydCkge1xyXG4gICAgcmV0dXJuIGRpZmYgJiYgZGlmZi5jb250ZW50ID8gZGlmZi5jb250ZW50IDogdW5kZWZpbmVkO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0U2Nyb2xsTGlzdGVuZXIoKSB7XHJcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaCh0aGlzLnNjcm9sbFNlcnZpY2Uuc2Nyb2xsZWQoKS5zdWJzY3JpYmUoKHNjcm9sbGFibGVFdjogQ2RrU2Nyb2xsYWJsZSkgPT4ge1xyXG4gICAgICBpZiAoc2Nyb2xsYWJsZUV2ICYmIHRoaXMuc3luY2hyb25pemVTY3JvbGxpbmcpIHtcclxuICAgICAgICBjb25zdCBzY3JvbGxhYmxlSWQgPSBzY3JvbGxhYmxlRXYuZ2V0RWxlbWVudFJlZigpLm5hdGl2ZUVsZW1lbnQuaWQ7XHJcbiAgICAgICAgY29uc3Qgbm9uU2Nyb2xsZWRDb250YWluZXI6IENvbnRhaW5lckRpcmVjdGl2ZSA9IHRoaXMuY29udGFpbmVycy5maW5kKGNvbnRhaW5lciA9PiBjb250YWluZXIuaWQgIT09IHNjcm9sbGFibGVJZCk7XHJcbiAgICAgICAgaWYgKG5vblNjcm9sbGVkQ29udGFpbmVyKSB7XHJcbiAgICAgICAgICBub25TY3JvbGxlZENvbnRhaW5lci5lbGVtZW50LnNjcm9sbFRvKHtcclxuICAgICAgICAgICAgdG9wOiBzY3JvbGxhYmxlRXYubWVhc3VyZVNjcm9sbE9mZnNldCgndG9wJyksXHJcbiAgICAgICAgICAgIGxlZnQ6IHNjcm9sbGFibGVFdi5tZWFzdXJlU2Nyb2xsT2Zmc2V0KCdsZWZ0JyksXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pKTtcclxuICB9XHJcbn1cclxuIl19