concepto-user-controls 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/concepto-context-menu/concepto-context-menu.component.mjs +3 -7
- package/esm2022/lib/concepto-tree/concepto-tree.component.mjs +19 -0
- package/esm2022/lib/entity-comparison/components/entity-comparison.component.mjs +218 -0
- package/esm2022/lib/entity-comparison/core/services/entity-comparison.service.mjs +111 -0
- package/esm2022/public-api.mjs +4 -1
- package/fesm2022/concepto-user-controls.mjs +340 -6
- package/fesm2022/concepto-user-controls.mjs.map +1 -1
- package/lib/concepto-context-menu/concepto-context-menu.component.d.ts +2 -3
- package/lib/concepto-tree/concepto-tree.component.d.ts +5 -0
- package/lib/entity-comparison/components/entity-comparison.component.d.ts +49 -0
- package/lib/entity-comparison/core/services/entity-comparison.service.d.ts +10 -0
- package/package.json +1 -1
- package/public-api.d.ts +3 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { Component,
|
|
1
|
+
import { Component, HostListener, Input } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
import * as i1 from "@angular/common";
|
|
5
5
|
export class ConceptoContextMenuComponent {
|
|
6
6
|
elRef;
|
|
7
7
|
nodes = [];
|
|
8
|
-
itemSelected = new EventEmitter();
|
|
9
8
|
menuTree = [];
|
|
10
9
|
visible = false;
|
|
11
10
|
pos = { x: 0, y: 0 };
|
|
@@ -49,7 +48,6 @@ export class ConceptoContextMenuComponent {
|
|
|
49
48
|
onOptionClick(option) {
|
|
50
49
|
if (!option.children || option.children.length === 0) {
|
|
51
50
|
console.log('Selected:', option);
|
|
52
|
-
this.itemSelected.emit(option.NodesId);
|
|
53
51
|
this.hide();
|
|
54
52
|
}
|
|
55
53
|
}
|
|
@@ -57,17 +55,15 @@ export class ConceptoContextMenuComponent {
|
|
|
57
55
|
return !!option.children && option.children.length > 0;
|
|
58
56
|
}
|
|
59
57
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConceptoContextMenuComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
60
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ConceptoContextMenuComponent, isStandalone: true, selector: "concepto-context-menu", inputs: { nodes: "nodes" },
|
|
58
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ConceptoContextMenuComponent, isStandalone: true, selector: "concepto-context-menu", inputs: { nodes: "nodes" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"context-menu\" *ngIf=\"visible\" [ngStyle]=\"{ top: pos.y + 'px', left: pos.x + 'px' }\">\r\n <ul class=\"menu-root\">\r\n <ng-container *ngFor=\"let item of menuTree\">\r\n <ng-container *ngTemplateOutlet=\"renderNode; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n </ul>\r\n</div>\r\n\r\n<ng-template #renderNode let-node>\r\n <li class=\"menu-item\" [class.has-children]=\"hasChildren(node)\">\r\n <div (click)=\"onOptionClick(node)\">\r\n @if (node.NodesImg) {\r\n <img [src]=\"node.NodesImg\" class=\"icon\" />\r\n }\r\n @if (!node.NodesImg) {\r\n <div class=\"icon\"></div>\r\n }\r\n {{ node.NodesText }}\r\n </div>\r\n <ul class=\"submenu\" *ngIf=\"hasChildren(node)\">\r\n <ng-container *ngFor=\"let child of node.children\">\r\n <ng-container *ngTemplateOutlet=\"renderNode; context: { $implicit: child }\"></ng-container>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n</ng-template>", styles: [".context-menu{position:fixed;z-index:9999;background-color:#fff;border:1px solid #ccc;box-shadow:2px 2px 8px #00000026;min-width:200px;font-family:sans-serif}.menu-root,.submenu{list-style:none;margin:0;padding:0}.menu-item{position:relative}.menu-item>div{padding:8px 12px;cursor:pointer;display:flex;align-items:center;white-space:nowrap}.menu-item>div:hover{background-color:#f0f0f0}.menu-item.has-children>div:after{content:\"\\25b6\";margin-left:auto;font-size:10px}.submenu{display:none;position:absolute;top:0;left:100%;border:1px solid #ccc;background-color:#fff;min-width:180px;box-shadow:2px 2px 6px #0000001a}.menu-item:hover>.submenu{display:block}.icon{width:16px;height:16px;margin-right:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
|
|
61
59
|
}
|
|
62
60
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConceptoContextMenuComponent, decorators: [{
|
|
63
61
|
type: Component,
|
|
64
62
|
args: [{ selector: 'concepto-context-menu', standalone: true, imports: [CommonModule], template: "<div class=\"context-menu\" *ngIf=\"visible\" [ngStyle]=\"{ top: pos.y + 'px', left: pos.x + 'px' }\">\r\n <ul class=\"menu-root\">\r\n <ng-container *ngFor=\"let item of menuTree\">\r\n <ng-container *ngTemplateOutlet=\"renderNode; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n </ul>\r\n</div>\r\n\r\n<ng-template #renderNode let-node>\r\n <li class=\"menu-item\" [class.has-children]=\"hasChildren(node)\">\r\n <div (click)=\"onOptionClick(node)\">\r\n @if (node.NodesImg) {\r\n <img [src]=\"node.NodesImg\" class=\"icon\" />\r\n }\r\n @if (!node.NodesImg) {\r\n <div class=\"icon\"></div>\r\n }\r\n {{ node.NodesText }}\r\n </div>\r\n <ul class=\"submenu\" *ngIf=\"hasChildren(node)\">\r\n <ng-container *ngFor=\"let child of node.children\">\r\n <ng-container *ngTemplateOutlet=\"renderNode; context: { $implicit: child }\"></ng-container>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n</ng-template>", styles: [".context-menu{position:fixed;z-index:9999;background-color:#fff;border:1px solid #ccc;box-shadow:2px 2px 8px #00000026;min-width:200px;font-family:sans-serif}.menu-root,.submenu{list-style:none;margin:0;padding:0}.menu-item{position:relative}.menu-item>div{padding:8px 12px;cursor:pointer;display:flex;align-items:center;white-space:nowrap}.menu-item>div:hover{background-color:#f0f0f0}.menu-item.has-children>div:after{content:\"\\25b6\";margin-left:auto;font-size:10px}.submenu{display:none;position:absolute;top:0;left:100%;border:1px solid #ccc;background-color:#fff;min-width:180px;box-shadow:2px 2px 6px #0000001a}.menu-item:hover>.submenu{display:block}.icon{width:16px;height:16px;margin-right:8px}\n"] }]
|
|
65
63
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { nodes: [{
|
|
66
64
|
type: Input
|
|
67
|
-
}], itemSelected: [{
|
|
68
|
-
type: Output
|
|
69
65
|
}], onOutsideClick: [{
|
|
70
66
|
type: HostListener,
|
|
71
67
|
args: ['document:click', ['$event']]
|
|
72
68
|
}] } });
|
|
73
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
69
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uY2VwdG8tY29udGV4dC1tZW51LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbmNlcHRvLXVzZXItY29udHJvbHMvc3JjL2xpYi9jb25jZXB0by1jb250ZXh0LW1lbnUvY29uY2VwdG8tY29udGV4dC1tZW51LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbmNlcHRvLXVzZXItY29udHJvbHMvc3JjL2xpYi9jb25jZXB0by1jb250ZXh0LW1lbnUvY29uY2VwdG8tY29udGV4dC1tZW51LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQWMsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7OztBQWtCL0MsTUFBTSxPQUFPLDRCQUE0QjtJQU9uQjtJQUxYLEtBQUssR0FBaUIsRUFBRSxDQUFDO0lBQ2xDLFFBQVEsR0FBaUIsRUFBRSxDQUFDO0lBQzVCLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDaEIsR0FBRyxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFFckIsWUFBb0IsS0FBaUI7UUFBakIsVUFBSyxHQUFMLEtBQUssQ0FBWTtJQUFHLENBQUM7SUFFekMsV0FBVztRQUNULE1BQU0sR0FBRyxHQUFHLElBQUksR0FBRyxFQUFzQixDQUFDO1FBQzFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsR0FBRyxDQUFDLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUVwRSxNQUFNLEtBQUssR0FBaUIsRUFB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IENvbXBvbmVudCwgRWxlbWVudFJlZiwgSG9zdExpc3RlbmVyLCBJbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgTm9kZU9wdGlvbiB7XHJcbiAgTm9kZXNJZDogc3RyaW5nO1xyXG4gIE5vZGVzVGV4dDogc3RyaW5nO1xyXG4gIE5vZGVzUGFyZW50SWQ6IHN0cmluZztcclxuICBOb2Rlc0ltZzogc3RyaW5nO1xyXG4gIGNoaWxkcmVuPzogTm9kZU9wdGlvbltdO1xyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2NvbmNlcHRvLWNvbnRleHQtbWVudScsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vY29uY2VwdG8tY29udGV4dC1tZW51LmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybDogJy4vY29uY2VwdG8tY29udGV4dC1tZW51LmNvbXBvbmVudC5jc3MnXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBDb25jZXB0b0NvbnRleHRNZW51Q29tcG9uZW50IHtcclxuXHJcbiAgQElucHV0KCkgbm9kZXM6IE5vZGVPcHRpb25bXSA9IFtdO1xyXG4gIG1lbnVUcmVlOiBOb2RlT3B0aW9uW10gPSBbXTtcclxuICB2aXNpYmxlID0gZmFsc2U7XHJcbiAgcG9zID0geyB4OiAwLCB5OiAwIH07XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZWxSZWY6IEVsZW1lbnRSZWYpIHt9XHJcblxyXG4gIG5nT25DaGFuZ2VzKCk6IHZvaWQge1xyXG4gICAgY29uc3QgbWFwID0gbmV3IE1hcDxzdHJpbmcsIE5vZGVPcHRpb24+KCk7XHJcbiAgICB0aGlzLm5vZGVzLmZvckVhY2gobiA9PiBtYXAuc2V0KG4uTm9kZXNJZCwgeyAuLi5uLCBjaGlsZHJlbjogW10gfSkpO1xyXG5cclxuICAgIGNvbnN0IHJvb3RzOiBOb2RlT3B0aW9uW10gPSBbXTtcclxuICAgIG1hcC5mb3JFYWNoKG4gPT4ge1xyXG4gICAgICBpZiAobi5Ob2Rlc1BhcmVudElkICYmIG1hcC5oYXMobi5Ob2Rlc1BhcmVudElkKSkge1xyXG4gICAgICAgIG1hcC5nZXQobi5Ob2Rlc1BhcmVudElkKT8uY2hpbGRyZW4/LnB1c2gobik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcm9vdHMucHVzaChuKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICB0aGlzLm1lbnVUcmVlID0gcm9vdHM7XHJcbiAgfVxyXG5cclxuICBzaG93QXRFdmVudChldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xyXG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgIGNvbnN0IHggPSBldmVudC5jbGllbnRYO1xyXG4gICAgY29uc3QgeSA9IGV2ZW50LmNsaWVudFk7XHJcbiAgICB0aGlzLnZpc2libGUgPSB0cnVlO1xyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1lbnUgPSB0aGlzLmVsUmVmLm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcignLmNvbnRleHQtbWVudScpO1xyXG4gICAgICBjb25zdCByZWN0ID0gbWVudS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgICAgdGhpcy5wb3MueCA9IHggKyByZWN0LndpZHRoID4gd2luZG93LmlubmVyV2lkdGggPyB3aW5kb3cuaW5uZXJXaWR0aCAtIHJlY3Qud2lkdGggLSAxMCA6IHg7XHJcbiAgICAgIHRoaXMucG9zLnkgPSB5ICsgcmVjdC5oZWlnaHQgPiB3aW5kb3cuaW5uZXJIZWlnaHQgPyB3aW5kb3cuaW5uZXJIZWlnaHQgLSByZWN0LmhlaWdodCAtIDEwIDogeTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgaGlkZSgpOiB2b2lkIHtcclxuICAgIHRoaXMudmlzaWJsZSA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6Y2xpY2snLCBbJyRldmVudCddKVxyXG4gIG9uT3V0c2lkZUNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuZWxSZWYubmF0aXZlRWxlbWVudC5jb250YWlucyhldmVudC50YXJnZXQpKSB7XHJcbiAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgb25PcHRpb25DbGljayhvcHRpb246IE5vZGVPcHRpb24pOiB2b2lkIHtcclxuICAgIGlmICghb3B0aW9uLmNoaWxkcmVuIHx8IG9wdGlvbi5jaGlsZHJlbi5sZW5ndGggPT09IDApIHtcclxuICAgICAgY29uc29sZS5sb2coJ1NlbGVjdGVkOicsIG9wdGlvbik7XHJcbiAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgaGFzQ2hpbGRyZW4ob3B0aW9uOiBOb2RlT3B0aW9uKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gISFvcHRpb24uY2hpbGRyZW4gJiYgb3B0aW9uLmNoaWxkcmVuLmxlbmd0aCA+IDA7XHJcbiAgfVxyXG59XHJcblxyXG4iLCI8ZGl2IGNsYXNzPVwiY29udGV4dC1tZW51XCIgKm5nSWY9XCJ2aXNpYmxlXCIgW25nU3R5bGVdPVwieyB0b3A6IHBvcy55ICsgJ3B4JywgbGVmdDogcG9zLnggKyAncHgnIH1cIj5cclxuICAgIDx1bCBjbGFzcz1cIm1lbnUtcm9vdFwiPlxyXG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGl0ZW0gb2YgbWVudVRyZWVcIj5cclxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cInJlbmRlck5vZGU7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBpdGVtIH1cIj48L25nLWNvbnRhaW5lcj5cclxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cclxuICAgIDwvdWw+XHJcbjwvZGl2PlxyXG5cclxuPG5nLXRlbXBsYXRlICNyZW5kZXJOb2RlIGxldC1ub2RlPlxyXG4gICAgPGxpIGNsYXNzPVwibWVudS1pdGVtXCIgW2NsYXNzLmhhcy1jaGlsZHJlbl09XCJoYXNDaGlsZHJlbihub2RlKVwiPlxyXG4gICAgICAgIDxkaXYgKGNsaWNrKT1cIm9uT3B0aW9uQ2xpY2sobm9kZSlcIj5cclxuICAgICAgICAgICAgQGlmIChub2RlLk5vZGVzSW1nKSB7XHJcbiAgICAgICAgICAgIDxpbWcgW3NyY109XCJub2RlLk5vZGVzSW1nXCIgY2xhc3M9XCJpY29uXCIgLz5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBAaWYgKCFub2RlLk5vZGVzSW1nKSB7XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJpY29uXCI+PC9kaXY+XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAge3sgbm9kZS5Ob2Rlc1RleHQgfX1cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8dWwgY2xhc3M9XCJzdWJtZW51XCIgKm5nSWY9XCJoYXNDaGlsZHJlbihub2RlKVwiPlxyXG4gICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBjaGlsZCBvZiBub2RlLmNoaWxkcmVuXCI+XHJcbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwicmVuZGVyTm9kZTsgY29udGV4dDogeyAkaW1wbGljaXQ6IGNoaWxkIH1cIj48L25nLWNvbnRhaW5lcj5cclxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICAgICAgPC91bD5cclxuICAgIDwvbGk+XHJcbjwvbmctdGVtcGxhdGU+Il19
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class ConceptoTreeComponent {
|
|
4
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConceptoTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ConceptoTreeComponent, isStandalone: true, selector: "lib-concepto-tree", ngImport: i0, template: `
|
|
6
|
+
<p>
|
|
7
|
+
concepto-tree works!
|
|
8
|
+
</p>
|
|
9
|
+
`, isInline: true, styles: [""] });
|
|
10
|
+
}
|
|
11
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConceptoTreeComponent, decorators: [{
|
|
12
|
+
type: Component,
|
|
13
|
+
args: [{ selector: 'lib-concepto-tree', standalone: true, imports: [], template: `
|
|
14
|
+
<p>
|
|
15
|
+
concepto-tree works!
|
|
16
|
+
</p>
|
|
17
|
+
` }]
|
|
18
|
+
}] });
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uY2VwdG8tdHJlZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jb25jZXB0by11c2VyLWNvbnRyb2xzL3NyYy9saWIvY29uY2VwdG8tdHJlZS9jb25jZXB0by10cmVlLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQWExQyxNQUFNLE9BQU8scUJBQXFCO3dHQUFyQixxQkFBcUI7NEZBQXJCLHFCQUFxQiw2RUFQdEI7Ozs7R0FJVDs7NEZBR1UscUJBQXFCO2tCQVhqQyxTQUFTOytCQUNFLG1CQUFtQixjQUNqQixJQUFJLFdBQ1AsRUFBRSxZQUNEOzs7O0dBSVQiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbGliLWNvbmNlcHRvLXRyZWUnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW10sXHJcbiAgdGVtcGxhdGU6IGBcclxuICAgIDxwPlxyXG4gICAgICBjb25jZXB0by10cmVlIHdvcmtzIVxyXG4gICAgPC9wPlxyXG4gIGAsXHJcbiAgc3R5bGVzOiBgYFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQ29uY2VwdG9UcmVlQ29tcG9uZW50IHtcclxuXHJcbn1cclxuIl19
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { EntityComparisonService } from '../core/services/entity-comparison.service';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "../core/services/entity-comparison.service";
|
|
6
|
+
import * as i2 from "@angular/common";
|
|
7
|
+
export class EntityComparisonComponent {
|
|
8
|
+
comparisonService;
|
|
9
|
+
leftFile = '';
|
|
10
|
+
rightFile = '';
|
|
11
|
+
leftEntities = [];
|
|
12
|
+
rightEntities = [];
|
|
13
|
+
selectedLeftEntity = null;
|
|
14
|
+
selectedRightEntity = null;
|
|
15
|
+
comparisonResult = null;
|
|
16
|
+
expandedNodes = new Set();
|
|
17
|
+
isFullScreen = false;
|
|
18
|
+
currentDifferenceIndex = 0;
|
|
19
|
+
differences = [];
|
|
20
|
+
constructor(comparisonService) {
|
|
21
|
+
this.comparisonService = comparisonService;
|
|
22
|
+
}
|
|
23
|
+
onLeftFileSelected(event) {
|
|
24
|
+
const file = event.target.files[0];
|
|
25
|
+
if (!file)
|
|
26
|
+
return;
|
|
27
|
+
this.leftFile = file.name;
|
|
28
|
+
const reader = new FileReader();
|
|
29
|
+
reader.onload = (e) => {
|
|
30
|
+
const xmlContent = e.target.result;
|
|
31
|
+
this.leftEntities = this.comparisonService.parseEntities(xmlContent);
|
|
32
|
+
this.selectedLeftEntity = null;
|
|
33
|
+
this.comparisonResult = null;
|
|
34
|
+
};
|
|
35
|
+
reader.readAsText(file);
|
|
36
|
+
}
|
|
37
|
+
onRightFileSelected(event) {
|
|
38
|
+
const file = event.target.files[0];
|
|
39
|
+
if (!file)
|
|
40
|
+
return;
|
|
41
|
+
this.rightFile = file.name;
|
|
42
|
+
const reader = new FileReader();
|
|
43
|
+
reader.onload = (e) => {
|
|
44
|
+
const xmlContent = e.target.result;
|
|
45
|
+
this.rightEntities = this.comparisonService.parseEntities(xmlContent);
|
|
46
|
+
this.selectedRightEntity = null;
|
|
47
|
+
this.comparisonResult = null;
|
|
48
|
+
};
|
|
49
|
+
reader.readAsText(file);
|
|
50
|
+
}
|
|
51
|
+
selectLeftEntity(entity) {
|
|
52
|
+
this.selectedLeftEntity = entity;
|
|
53
|
+
this.compareIfBothSelected();
|
|
54
|
+
}
|
|
55
|
+
selectRightEntity(entity) {
|
|
56
|
+
this.selectedRightEntity = entity;
|
|
57
|
+
this.compareIfBothSelected();
|
|
58
|
+
}
|
|
59
|
+
compareIfBothSelected() {
|
|
60
|
+
if (this.selectedLeftEntity && this.selectedRightEntity) {
|
|
61
|
+
this.comparisonResult = this.comparisonService.compareStructures(this.selectedLeftEntity.structure, this.selectedRightEntity.structure);
|
|
62
|
+
this.buildDifferencesList();
|
|
63
|
+
this.currentDifferenceIndex = 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
buildDifferencesList() {
|
|
67
|
+
if (!this.comparisonResult) {
|
|
68
|
+
this.differences = [];
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.differences = [
|
|
72
|
+
...this.comparisonResult.leftOnly.map(node => ({ node, type: 'removed' })),
|
|
73
|
+
...this.comparisonResult.rightOnly.map(node => ({ node, type: 'added' })),
|
|
74
|
+
...this.comparisonResult.modified.map(node => ({ node, type: 'modified' }))
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
navigateToNextDifference() {
|
|
78
|
+
if (this.differences.length === 0)
|
|
79
|
+
return;
|
|
80
|
+
this.currentDifferenceIndex = (this.currentDifferenceIndex + 1) % this.differences.length;
|
|
81
|
+
this.scrollToDifference();
|
|
82
|
+
}
|
|
83
|
+
navigateToPreviousDifference() {
|
|
84
|
+
if (this.differences.length === 0)
|
|
85
|
+
return;
|
|
86
|
+
this.currentDifferenceIndex = this.currentDifferenceIndex === 0
|
|
87
|
+
? this.differences.length - 1
|
|
88
|
+
: this.currentDifferenceIndex - 1;
|
|
89
|
+
this.scrollToDifference();
|
|
90
|
+
}
|
|
91
|
+
scrollToDifference() {
|
|
92
|
+
if (this.differences.length === 0)
|
|
93
|
+
return;
|
|
94
|
+
const currentDiff = this.differences[this.currentDifferenceIndex];
|
|
95
|
+
const nodeId = `${currentDiff.node.Id}-${currentDiff.node.name}`;
|
|
96
|
+
// Expand parent nodes FIRST to make the difference visible
|
|
97
|
+
this.expandPathToNode(currentDiff.node);
|
|
98
|
+
// Wait for DOM to update after expansion, then scroll
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
const leftElement = document.querySelector(`[data-node-id="left-${nodeId}"]`);
|
|
101
|
+
const rightElement = document.querySelector(`[data-node-id="right-${nodeId}"]`);
|
|
102
|
+
if (leftElement) {
|
|
103
|
+
leftElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
104
|
+
}
|
|
105
|
+
if (rightElement) {
|
|
106
|
+
rightElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
107
|
+
}
|
|
108
|
+
}, 100);
|
|
109
|
+
}
|
|
110
|
+
expandPathToNode(node) {
|
|
111
|
+
// Find and expand all parent nodes in both structures
|
|
112
|
+
this.expandParentsInStructure(this.selectedLeftEntity.structure, node, 'left');
|
|
113
|
+
this.expandParentsInStructure(this.selectedRightEntity.structure, node, 'right');
|
|
114
|
+
}
|
|
115
|
+
expandParentsInStructure(structure, targetNode, side) {
|
|
116
|
+
for (const node of structure) {
|
|
117
|
+
const nodeId = `${side}-${node.Id}-${node.name}`;
|
|
118
|
+
const targetId = `${targetNode.Id}-${targetNode.name}`;
|
|
119
|
+
const currentId = `${node.Id}-${node.name}`;
|
|
120
|
+
// If this is the target node, we found it
|
|
121
|
+
if (currentId === targetId) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
// Check children if they exist
|
|
125
|
+
if (this.hasChildren(node)) {
|
|
126
|
+
const children = this.getChildren(node);
|
|
127
|
+
if (this.expandParentsInStructure(children, targetNode, side)) {
|
|
128
|
+
// If the target is in this branch, expand this node
|
|
129
|
+
this.expandedNodes.add(nodeId);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
get hasDifferences() {
|
|
137
|
+
return this.differences.length > 0;
|
|
138
|
+
}
|
|
139
|
+
get currentDifferenceNumber() {
|
|
140
|
+
return this.currentDifferenceIndex + 1;
|
|
141
|
+
}
|
|
142
|
+
get totalDifferences() {
|
|
143
|
+
return this.differences.length;
|
|
144
|
+
}
|
|
145
|
+
toggleNode(nodeId) {
|
|
146
|
+
if (this.expandedNodes.has(nodeId)) {
|
|
147
|
+
this.expandedNodes.delete(nodeId);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this.expandedNodes.add(nodeId);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
isExpanded(nodeId) {
|
|
154
|
+
return this.expandedNodes.has(nodeId);
|
|
155
|
+
}
|
|
156
|
+
getNodeId(node, prefix) {
|
|
157
|
+
return `${prefix}-${node.Id}-${node.name}`;
|
|
158
|
+
}
|
|
159
|
+
hasChildren(node) {
|
|
160
|
+
return node.Children && JSON.parse(node.Children).length > 0;
|
|
161
|
+
}
|
|
162
|
+
getChildren(node) {
|
|
163
|
+
if (!node.Children)
|
|
164
|
+
return [];
|
|
165
|
+
try {
|
|
166
|
+
return JSON.parse(node.Children);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
getProperties(node) {
|
|
173
|
+
if (!node.Properties)
|
|
174
|
+
return {};
|
|
175
|
+
try {
|
|
176
|
+
return JSON.parse(node.Properties);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
getPropertyKeys(node) {
|
|
183
|
+
const props = this.getProperties(node);
|
|
184
|
+
return Object.keys(props);
|
|
185
|
+
}
|
|
186
|
+
getChangeType(node) {
|
|
187
|
+
if (!this.comparisonResult)
|
|
188
|
+
return '';
|
|
189
|
+
const nodeId = `${node.Id}-${node.name}`;
|
|
190
|
+
if (this.comparisonResult.leftOnly.some(n => `${n.Id}-${n.name}` === nodeId)) {
|
|
191
|
+
return 'removed';
|
|
192
|
+
}
|
|
193
|
+
if (this.comparisonResult.rightOnly.some(n => `${n.Id}-${n.name}` === nodeId)) {
|
|
194
|
+
return 'added';
|
|
195
|
+
}
|
|
196
|
+
if (this.comparisonResult.modified.some(n => `${n.Id}-${n.name}` === nodeId)) {
|
|
197
|
+
return 'modified';
|
|
198
|
+
}
|
|
199
|
+
return 'unchanged';
|
|
200
|
+
}
|
|
201
|
+
getModifiedProperties(node) {
|
|
202
|
+
if (!this.comparisonResult)
|
|
203
|
+
return [];
|
|
204
|
+
const nodeId = `${node.Id}-${node.name}`;
|
|
205
|
+
const modified = this.comparisonResult.modified.find(n => `${n.Id}-${n.name}` === nodeId);
|
|
206
|
+
return modified?.modifiedProperties || [];
|
|
207
|
+
}
|
|
208
|
+
toggleFullScreen() {
|
|
209
|
+
this.isFullScreen = !this.isFullScreen;
|
|
210
|
+
}
|
|
211
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EntityComparisonComponent, deps: [{ token: i1.EntityComparisonService }], target: i0.ɵɵFactoryTarget.Component });
|
|
212
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EntityComparisonComponent, isStandalone: true, selector: "app-entity-comparison", providers: [EntityComparisonService], ngImport: i0, template: "<div class=\"comparison-container\" [class.fullscreen]=\"isFullScreen\">\r\n <header class=\"header\">\r\n <h1>Entity Structure Comparison</h1>\r\n <p class=\"subtitle\">Compare EntityStructureJson between two entity exports</p>\r\n </header>\r\n\r\n <div class=\"file-selection\">\r\n <div class=\"file-input-group\">\r\n <label class=\"file-label left\">\r\n <input type=\"file\" accept=\".xml\" (change)=\"onLeftFileSelected($event)\" hidden>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\r\n <polyline points=\"17 8 12 3 7 8\" />\r\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\r\n </svg>\r\n Load Left Entity\r\n </label>\r\n <span *ngIf=\"leftFile\" class=\"file-name\">{{ leftFile }}</span>\r\n </div>\r\n\r\n <div class=\"vs-separator\">VS</div>\r\n\r\n <div class=\"file-input-group\">\r\n <label class=\"file-label right\">\r\n <input type=\"file\" accept=\".xml\" (change)=\"onRightFileSelected($event)\" hidden>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\r\n <polyline points=\"17 8 12 3 7 8\" />\r\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\r\n </svg>\r\n Load Right Entity\r\n </label>\r\n <span *ngIf=\"rightFile\" class=\"file-name\">{{ rightFile }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"entity-selection\" *ngIf=\"leftEntities.length > 0 || rightEntities.length > 0\">\r\n <div class=\"entity-list\">\r\n <h3>Left Entities</h3>\r\n <div class=\"entities\">\r\n <div *ngFor=\"let entity of leftEntities\" class=\"entity-card\"\r\n [class.selected]=\"selectedLeftEntity === entity\" (click)=\"selectLeftEntity(entity)\">\r\n <div class=\"entity-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\">\r\n <path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\r\n </svg>\r\n </div>\r\n <div class=\"entity-info\">\r\n <div class=\"entity-name\">{{ entity.name }}</div>\r\n <div class=\"entity-id\">{{ entity.id }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"entity-list\">\r\n <h3>Right Entities</h3>\r\n <div class=\"entities\">\r\n <div *ngFor=\"let entity of rightEntities\" class=\"entity-card\"\r\n [class.selected]=\"selectedRightEntity === entity\" (click)=\"selectRightEntity(entity)\">\r\n <div class=\"entity-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\">\r\n <path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\r\n </svg>\r\n </div>\r\n <div class=\"entity-info\">\r\n <div class=\"entity-name\">{{ entity.name }}</div>\r\n <div class=\"entity-id\">{{ entity.id }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"summary-section\" *ngIf=\"comparisonResult\">\r\n <div class=\"summary\">\r\n <div class=\"summary-item added\">\r\n <span class=\"count\">{{ comparisonResult.rightOnly.length }}</span>\r\n <span class=\"label\">Added</span>\r\n </div>\r\n <div class=\"summary-item removed\">\r\n <span class=\"count\">{{ comparisonResult.leftOnly.length }}</span>\r\n <span class=\"label\">Removed</span>\r\n </div>\r\n <div class=\"summary-item modified\">\r\n <span class=\"count\">{{ comparisonResult.modified.length }}</span>\r\n <span class=\"label\">Modified</span>\r\n </div>\r\n <div class=\"summary-item unchanged\">\r\n <span class=\"count\">{{ comparisonResult.unchanged.length }}</span>\r\n <span class=\"label\">Unchanged</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"comparison-results\" *ngIf=\"comparisonResult\">\r\n <div class=\"results-header\">\r\n <div class=\"header-title\">\r\n <h2>Comparison Results</h2>\r\n <div class=\"header-actions\">\r\n <div class=\"diff-navigation\" *ngIf=\"hasDifferences\">\r\n <button class=\"nav-btn\" (click)=\"navigateToPreviousDifference()\" title=\"Previous Difference\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <polyline points=\"18 15 12 9 6 15\" />\r\n </svg>\r\n </button>\r\n <span class=\"diff-counter\">{{ currentDifferenceNumber }} / {{ totalDifferences }}</span>\r\n <button class=\"nav-btn\" (click)=\"navigateToNextDifference()\" title=\"Next Difference\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <polyline points=\"6 9 12 15 18 9\" />\r\n </svg>\r\n </button>\r\n </div>\r\n <button class=\"fullscreen-btn\" (click)=\"toggleFullScreen()\" [title]=\"isFullScreen ? 'Exit Full Screen' : 'Enter Full Screen'\">\r\n <svg *ngIf=\"!isFullScreen\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3\" />\r\n </svg>\r\n <svg *ngIf=\"isFullScreen\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"structure-comparison\">\r\n <div class=\"comparison-section\">\r\n <h3>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M9 11l3 3L22 4\" />\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\" />\r\n </svg>\r\n {{ selectedLeftEntity.name }}\r\n </h3>\r\n <div class=\"structure-tree\">\r\n <ng-container *ngFor=\"let node of selectedLeftEntity.structure\">\r\n <ng-container\r\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node, side: 'left' }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"comparison-section\">\r\n <h3>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M9 11l3 3L22 4\" />\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\" />\r\n </svg>\r\n {{ selectedRightEntity.name }}\r\n </h3>\r\n <div class=\"structure-tree\">\r\n <ng-container *ngFor=\"let node of selectedRightEntity.structure\">\r\n <ng-container\r\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node, side: 'right' }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<ng-template #nodeTemplate let-node let-side=\"side\">\r\n <div class=\"tree-node\" [class]=\"getChangeType(node)\" [attr.data-node-id]=\"getNodeId(node, side)\">\r\n <div class=\"node-header\">\r\n <button *ngIf=\"hasChildren(node)\" class=\"expand-btn\" (click)=\"toggleNode(getNodeId(node, side))\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <polyline *ngIf=\"!isExpanded(getNodeId(node, side))\" points=\"9 18 15 12 9 6\" />\r\n <polyline *ngIf=\"isExpanded(getNodeId(node, side))\" points=\"6 9 12 15 18 9\" />\r\n </svg>\r\n </button>\r\n <div *ngIf=\"!hasChildren(node)\" class=\"spacer\"></div>\r\n\r\n <div class=\"node-icon\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path *ngIf=\"node.nodeType === 'Group'\"\r\n d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\r\n <circle *ngIf=\"node.nodeType === 'Attribute'\" cx=\"12\" cy=\"12\" r=\"10\" />\r\n </svg>\r\n </div>\r\n\r\n <div class=\"node-content\">\r\n <span class=\"node-name\">{{ node.name }}</span>\r\n <span class=\"node-type\">{{ node.nodeType }}</span>\r\n <span class=\"change-badge\" *ngIf=\"getChangeType(node) !== 'unchanged'\">\r\n {{ getChangeType(node) }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"node-properties\" *ngIf=\"getPropertyKeys(node).length > 0\">\r\n <div *ngFor=\"let key of getPropertyKeys(node)\" class=\"property\"\r\n [class.modified]=\"getModifiedProperties(node).includes(key)\">\r\n <span class=\"property-key\">{{ key }}:</span>\r\n <span class=\"property-value\">{{ getProperties(node)[key] }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"node-children\" *ngIf=\"hasChildren(node) && isExpanded(getNodeId(node, side))\">\r\n <ng-container *ngFor=\"let child of getChildren(node)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: child, side: side }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n</ng-template>", styles: [".comparison-container{display:flex;flex-direction:column;height:100%;width:100%;background:#f9fafb}.header{background:#fff;padding:1.5rem;border-bottom:1px solid #e5e7eb;box-shadow:0 1px 3px #0000001a}.header h1{margin:0;font-size:1.5rem;font-weight:700;color:#1f2937}.subtitle{margin:.5rem 0 0;font-size:.875rem;color:#6b7280}.file-selection{display:flex;align-items:center;gap:2rem;padding:1.5rem;background:#fff;border-bottom:1px solid #e5e7eb}.file-input-group{flex:1;display:flex;flex-direction:column;gap:.5rem}.file-label{display:inline-flex;align-items:center;gap:.5rem;padding:.75rem 1.25rem;border:2px solid #2563eb;border-radius:.5rem;cursor:pointer;font-weight:500;transition:all .2s;justify-content:center}.file-label.left{background:#fff;color:#2563eb}.file-label.left:hover{background:#eff6ff}.file-label.right{background:#fff;color:#7c3aed;border-color:#7c3aed}.file-label.right:hover{background:#f5f3ff}.file-name{font-size:.875rem;color:#6b7280;text-align:center}.vs-separator{padding:.75rem 1.5rem;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;font-weight:700;border-radius:2rem;font-size:1.25rem;box-shadow:0 4px 6px #0000001a}.entity-selection{display:flex;gap:1rem;padding:1rem;background:#fff;border-bottom:1px solid #e5e7eb}.entity-list{flex:1}.entity-list h3{margin:0 0 .75rem;font-size:.875rem;font-weight:600;color:#6b7280;text-transform:uppercase}.entities{display:flex;flex-direction:column;gap:.5rem}.entity-card{display:flex;align-items:center;gap:.75rem;padding:.75rem;border:1px solid #e5e7eb;border-radius:.5rem;cursor:pointer;transition:all .2s}.entity-card:hover{background:#f9fafb;border-color:#d1d5db}.entity-card.selected{background:#eff6ff;border-color:#2563eb}.entity-icon{color:#6b7280}.entity-card.selected .entity-icon{color:#2563eb}.entity-info{flex:1}.entity-name{font-size:.875rem;font-weight:500;color:#1f2937}.entity-id{font-size:.75rem;color:#6b7280}.summary-section{padding:1.5rem 1.5rem 0;background:#f9fafb}.comparison-results{flex:1;overflow:auto;padding:1.5rem}.results-header{margin-bottom:1.5rem;position:sticky;top:0;background:#f9fafb;z-index:100;padding-top:1rem;padding-bottom:1rem;margin-top:-1rem}.header-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem}.results-header h2{margin:0;font-size:1.25rem;font-weight:700;color:#1f2937}.header-actions{display:flex;align-items:center;gap:1rem}.diff-navigation{display:flex;align-items:center;gap:.5rem;background:#fff;border:1px solid #e5e7eb;border-radius:.5rem;padding:.25rem}.nav-btn{background:#fff;border:1px solid #e5e7eb;border-radius:.375rem;padding:.5rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;color:#6b7280}.nav-btn:hover{background:#f9fafb;border-color:#2563eb;color:#2563eb}.diff-counter{font-size:.875rem;font-weight:600;color:#1f2937;padding:0 .5rem;white-space:nowrap;min-width:60px;text-align:center}.fullscreen-btn{background:#fff;border:1px solid #e5e7eb;border-radius:.5rem;padding:.5rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;color:#6b7280}.fullscreen-btn:hover{background:#f9fafb;border-color:#2563eb;color:#2563eb}.summary{display:flex;gap:1rem}.summary-item{flex:1;display:flex;flex-direction:column;align-items:center;padding:1rem;border-radius:.5rem;background:#fff;border:2px solid}.summary-item.added{border-color:#10b981;background:#ecfdf5}.summary-item.removed{border-color:#ef4444;background:#fef2f2}.summary-item.modified{border-color:#f59e0b;background:#fffbeb}.summary-item.unchanged{border-color:#6b7280;background:#f9fafb}.summary-item .count{font-size:1.5rem;font-weight:700}.summary-item.added .count{color:#10b981}.summary-item.removed .count{color:#ef4444}.summary-item.modified .count{color:#f59e0b}.summary-item.unchanged .count{color:#6b7280}.summary-item .label{font-size:.75rem;font-weight:600;text-transform:uppercase;margin-top:.25rem}.structure-comparison{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;height:100%}.comparison-section{background:#fff;border-radius:.5rem;padding:1rem;border:1px solid #e5e7eb;min-width:0;width:100%;overflow:auto}.comparison-section h3{display:flex;align-items:center;gap:.5rem;margin:0 0 1rem;font-size:1rem;font-weight:600;color:#1f2937;padding-bottom:.75rem;border-bottom:1px solid #e5e7eb}.structure-tree{display:flex;flex-direction:column;gap:.5rem}.tree-node{border-left:3px solid transparent;padding-left:.5rem;transition:all .2s;max-width:100%;overflow:hidden}.tree-node.added{background:#ecfdf5;border-left-color:#10b981}.tree-node.removed{background:#fef2f2;border-left-color:#ef4444}.tree-node.modified{background:#fffbeb;border-left-color:#f59e0b}.node-header{display:flex;align-items:center;gap:.5rem;padding:.5rem;border-radius:.375rem}.expand-btn{background:none;border:none;cursor:pointer;padding:.25rem;display:flex;align-items:center;justify-content:center;border-radius:.25rem;transition:background .2s}.expand-btn:hover{background:#f3f4f6}.spacer{width:24px}.node-icon{color:#6b7280}.node-content{display:flex;align-items:center;gap:.5rem;flex:1}.node-name{font-size:.875rem;font-weight:500;color:#1f2937}.node-type{font-size:.75rem;color:#6b7280;background:#f3f4f6;padding:.125rem .5rem;border-radius:.25rem}.change-badge{font-size:.625rem;font-weight:600;text-transform:uppercase;padding:.125rem .5rem;border-radius:.25rem;margin-left:auto}.tree-node.added .change-badge{background:#10b981;color:#fff}.tree-node.removed .change-badge{background:#ef4444;color:#fff}.tree-node.modified .change-badge{background:#f59e0b;color:#fff}.node-properties{margin-left:2.5rem;margin-top:.5rem;padding:.5rem;background:#f9fafb;border-radius:.375rem;font-size:.75rem;max-width:100%;overflow:hidden}.property{display:flex;flex-wrap:wrap;gap:.5rem;padding:.25rem 0;max-width:100%;overflow:hidden}.property.modified{background:#fef3c7;padding:.25rem .5rem;border-radius:.25rem;margin:.125rem 0}.property-key{font-weight:600;color:#374151;flex-shrink:0}.property-value{color:#6b7280;word-break:break-word;overflow:auto;overflow-wrap:break-word;flex:1;min-width:0}.node-children{margin-left:1.5rem;margin-top:.5rem;display:flex;flex-direction:column;gap:.5rem}.comparison-container.fullscreen{position:fixed;inset:0;z-index:9999;background:#f9fafb}.comparison-container.fullscreen .header,.comparison-container.fullscreen .file-selection,.comparison-container.fullscreen .entity-selection,.comparison-container.fullscreen .summary-section{display:none}.comparison-container.fullscreen .comparison-results{height:100vh;padding:2rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
213
|
+
}
|
|
214
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EntityComparisonComponent, decorators: [{
|
|
215
|
+
type: Component,
|
|
216
|
+
args: [{ selector: 'app-entity-comparison', standalone: true, imports: [CommonModule], providers: [EntityComparisonService], template: "<div class=\"comparison-container\" [class.fullscreen]=\"isFullScreen\">\r\n <header class=\"header\">\r\n <h1>Entity Structure Comparison</h1>\r\n <p class=\"subtitle\">Compare EntityStructureJson between two entity exports</p>\r\n </header>\r\n\r\n <div class=\"file-selection\">\r\n <div class=\"file-input-group\">\r\n <label class=\"file-label left\">\r\n <input type=\"file\" accept=\".xml\" (change)=\"onLeftFileSelected($event)\" hidden>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\r\n <polyline points=\"17 8 12 3 7 8\" />\r\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\r\n </svg>\r\n Load Left Entity\r\n </label>\r\n <span *ngIf=\"leftFile\" class=\"file-name\">{{ leftFile }}</span>\r\n </div>\r\n\r\n <div class=\"vs-separator\">VS</div>\r\n\r\n <div class=\"file-input-group\">\r\n <label class=\"file-label right\">\r\n <input type=\"file\" accept=\".xml\" (change)=\"onRightFileSelected($event)\" hidden>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\r\n <polyline points=\"17 8 12 3 7 8\" />\r\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\r\n </svg>\r\n Load Right Entity\r\n </label>\r\n <span *ngIf=\"rightFile\" class=\"file-name\">{{ rightFile }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"entity-selection\" *ngIf=\"leftEntities.length > 0 || rightEntities.length > 0\">\r\n <div class=\"entity-list\">\r\n <h3>Left Entities</h3>\r\n <div class=\"entities\">\r\n <div *ngFor=\"let entity of leftEntities\" class=\"entity-card\"\r\n [class.selected]=\"selectedLeftEntity === entity\" (click)=\"selectLeftEntity(entity)\">\r\n <div class=\"entity-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\">\r\n <path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\r\n </svg>\r\n </div>\r\n <div class=\"entity-info\">\r\n <div class=\"entity-name\">{{ entity.name }}</div>\r\n <div class=\"entity-id\">{{ entity.id }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"entity-list\">\r\n <h3>Right Entities</h3>\r\n <div class=\"entities\">\r\n <div *ngFor=\"let entity of rightEntities\" class=\"entity-card\"\r\n [class.selected]=\"selectedRightEntity === entity\" (click)=\"selectRightEntity(entity)\">\r\n <div class=\"entity-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\">\r\n <path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\r\n </svg>\r\n </div>\r\n <div class=\"entity-info\">\r\n <div class=\"entity-name\">{{ entity.name }}</div>\r\n <div class=\"entity-id\">{{ entity.id }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"summary-section\" *ngIf=\"comparisonResult\">\r\n <div class=\"summary\">\r\n <div class=\"summary-item added\">\r\n <span class=\"count\">{{ comparisonResult.rightOnly.length }}</span>\r\n <span class=\"label\">Added</span>\r\n </div>\r\n <div class=\"summary-item removed\">\r\n <span class=\"count\">{{ comparisonResult.leftOnly.length }}</span>\r\n <span class=\"label\">Removed</span>\r\n </div>\r\n <div class=\"summary-item modified\">\r\n <span class=\"count\">{{ comparisonResult.modified.length }}</span>\r\n <span class=\"label\">Modified</span>\r\n </div>\r\n <div class=\"summary-item unchanged\">\r\n <span class=\"count\">{{ comparisonResult.unchanged.length }}</span>\r\n <span class=\"label\">Unchanged</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"comparison-results\" *ngIf=\"comparisonResult\">\r\n <div class=\"results-header\">\r\n <div class=\"header-title\">\r\n <h2>Comparison Results</h2>\r\n <div class=\"header-actions\">\r\n <div class=\"diff-navigation\" *ngIf=\"hasDifferences\">\r\n <button class=\"nav-btn\" (click)=\"navigateToPreviousDifference()\" title=\"Previous Difference\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <polyline points=\"18 15 12 9 6 15\" />\r\n </svg>\r\n </button>\r\n <span class=\"diff-counter\">{{ currentDifferenceNumber }} / {{ totalDifferences }}</span>\r\n <button class=\"nav-btn\" (click)=\"navigateToNextDifference()\" title=\"Next Difference\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <polyline points=\"6 9 12 15 18 9\" />\r\n </svg>\r\n </button>\r\n </div>\r\n <button class=\"fullscreen-btn\" (click)=\"toggleFullScreen()\" [title]=\"isFullScreen ? 'Exit Full Screen' : 'Enter Full Screen'\">\r\n <svg *ngIf=\"!isFullScreen\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3\" />\r\n </svg>\r\n <svg *ngIf=\"isFullScreen\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"structure-comparison\">\r\n <div class=\"comparison-section\">\r\n <h3>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M9 11l3 3L22 4\" />\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\" />\r\n </svg>\r\n {{ selectedLeftEntity.name }}\r\n </h3>\r\n <div class=\"structure-tree\">\r\n <ng-container *ngFor=\"let node of selectedLeftEntity.structure\">\r\n <ng-container\r\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node, side: 'left' }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"comparison-section\">\r\n <h3>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path d=\"M9 11l3 3L22 4\" />\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\" />\r\n </svg>\r\n {{ selectedRightEntity.name }}\r\n </h3>\r\n <div class=\"structure-tree\">\r\n <ng-container *ngFor=\"let node of selectedRightEntity.structure\">\r\n <ng-container\r\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node, side: 'right' }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<ng-template #nodeTemplate let-node let-side=\"side\">\r\n <div class=\"tree-node\" [class]=\"getChangeType(node)\" [attr.data-node-id]=\"getNodeId(node, side)\">\r\n <div class=\"node-header\">\r\n <button *ngIf=\"hasChildren(node)\" class=\"expand-btn\" (click)=\"toggleNode(getNodeId(node, side))\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <polyline *ngIf=\"!isExpanded(getNodeId(node, side))\" points=\"9 18 15 12 9 6\" />\r\n <polyline *ngIf=\"isExpanded(getNodeId(node, side))\" points=\"6 9 12 15 18 9\" />\r\n </svg>\r\n </button>\r\n <div *ngIf=\"!hasChildren(node)\" class=\"spacer\"></div>\r\n\r\n <div class=\"node-icon\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n <path *ngIf=\"node.nodeType === 'Group'\"\r\n d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\r\n <circle *ngIf=\"node.nodeType === 'Attribute'\" cx=\"12\" cy=\"12\" r=\"10\" />\r\n </svg>\r\n </div>\r\n\r\n <div class=\"node-content\">\r\n <span class=\"node-name\">{{ node.name }}</span>\r\n <span class=\"node-type\">{{ node.nodeType }}</span>\r\n <span class=\"change-badge\" *ngIf=\"getChangeType(node) !== 'unchanged'\">\r\n {{ getChangeType(node) }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"node-properties\" *ngIf=\"getPropertyKeys(node).length > 0\">\r\n <div *ngFor=\"let key of getPropertyKeys(node)\" class=\"property\"\r\n [class.modified]=\"getModifiedProperties(node).includes(key)\">\r\n <span class=\"property-key\">{{ key }}:</span>\r\n <span class=\"property-value\">{{ getProperties(node)[key] }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"node-children\" *ngIf=\"hasChildren(node) && isExpanded(getNodeId(node, side))\">\r\n <ng-container *ngFor=\"let child of getChildren(node)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: child, side: side }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n</ng-template>", styles: [".comparison-container{display:flex;flex-direction:column;height:100%;width:100%;background:#f9fafb}.header{background:#fff;padding:1.5rem;border-bottom:1px solid #e5e7eb;box-shadow:0 1px 3px #0000001a}.header h1{margin:0;font-size:1.5rem;font-weight:700;color:#1f2937}.subtitle{margin:.5rem 0 0;font-size:.875rem;color:#6b7280}.file-selection{display:flex;align-items:center;gap:2rem;padding:1.5rem;background:#fff;border-bottom:1px solid #e5e7eb}.file-input-group{flex:1;display:flex;flex-direction:column;gap:.5rem}.file-label{display:inline-flex;align-items:center;gap:.5rem;padding:.75rem 1.25rem;border:2px solid #2563eb;border-radius:.5rem;cursor:pointer;font-weight:500;transition:all .2s;justify-content:center}.file-label.left{background:#fff;color:#2563eb}.file-label.left:hover{background:#eff6ff}.file-label.right{background:#fff;color:#7c3aed;border-color:#7c3aed}.file-label.right:hover{background:#f5f3ff}.file-name{font-size:.875rem;color:#6b7280;text-align:center}.vs-separator{padding:.75rem 1.5rem;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;font-weight:700;border-radius:2rem;font-size:1.25rem;box-shadow:0 4px 6px #0000001a}.entity-selection{display:flex;gap:1rem;padding:1rem;background:#fff;border-bottom:1px solid #e5e7eb}.entity-list{flex:1}.entity-list h3{margin:0 0 .75rem;font-size:.875rem;font-weight:600;color:#6b7280;text-transform:uppercase}.entities{display:flex;flex-direction:column;gap:.5rem}.entity-card{display:flex;align-items:center;gap:.75rem;padding:.75rem;border:1px solid #e5e7eb;border-radius:.5rem;cursor:pointer;transition:all .2s}.entity-card:hover{background:#f9fafb;border-color:#d1d5db}.entity-card.selected{background:#eff6ff;border-color:#2563eb}.entity-icon{color:#6b7280}.entity-card.selected .entity-icon{color:#2563eb}.entity-info{flex:1}.entity-name{font-size:.875rem;font-weight:500;color:#1f2937}.entity-id{font-size:.75rem;color:#6b7280}.summary-section{padding:1.5rem 1.5rem 0;background:#f9fafb}.comparison-results{flex:1;overflow:auto;padding:1.5rem}.results-header{margin-bottom:1.5rem;position:sticky;top:0;background:#f9fafb;z-index:100;padding-top:1rem;padding-bottom:1rem;margin-top:-1rem}.header-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem}.results-header h2{margin:0;font-size:1.25rem;font-weight:700;color:#1f2937}.header-actions{display:flex;align-items:center;gap:1rem}.diff-navigation{display:flex;align-items:center;gap:.5rem;background:#fff;border:1px solid #e5e7eb;border-radius:.5rem;padding:.25rem}.nav-btn{background:#fff;border:1px solid #e5e7eb;border-radius:.375rem;padding:.5rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;color:#6b7280}.nav-btn:hover{background:#f9fafb;border-color:#2563eb;color:#2563eb}.diff-counter{font-size:.875rem;font-weight:600;color:#1f2937;padding:0 .5rem;white-space:nowrap;min-width:60px;text-align:center}.fullscreen-btn{background:#fff;border:1px solid #e5e7eb;border-radius:.5rem;padding:.5rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;color:#6b7280}.fullscreen-btn:hover{background:#f9fafb;border-color:#2563eb;color:#2563eb}.summary{display:flex;gap:1rem}.summary-item{flex:1;display:flex;flex-direction:column;align-items:center;padding:1rem;border-radius:.5rem;background:#fff;border:2px solid}.summary-item.added{border-color:#10b981;background:#ecfdf5}.summary-item.removed{border-color:#ef4444;background:#fef2f2}.summary-item.modified{border-color:#f59e0b;background:#fffbeb}.summary-item.unchanged{border-color:#6b7280;background:#f9fafb}.summary-item .count{font-size:1.5rem;font-weight:700}.summary-item.added .count{color:#10b981}.summary-item.removed .count{color:#ef4444}.summary-item.modified .count{color:#f59e0b}.summary-item.unchanged .count{color:#6b7280}.summary-item .label{font-size:.75rem;font-weight:600;text-transform:uppercase;margin-top:.25rem}.structure-comparison{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;height:100%}.comparison-section{background:#fff;border-radius:.5rem;padding:1rem;border:1px solid #e5e7eb;min-width:0;width:100%;overflow:auto}.comparison-section h3{display:flex;align-items:center;gap:.5rem;margin:0 0 1rem;font-size:1rem;font-weight:600;color:#1f2937;padding-bottom:.75rem;border-bottom:1px solid #e5e7eb}.structure-tree{display:flex;flex-direction:column;gap:.5rem}.tree-node{border-left:3px solid transparent;padding-left:.5rem;transition:all .2s;max-width:100%;overflow:hidden}.tree-node.added{background:#ecfdf5;border-left-color:#10b981}.tree-node.removed{background:#fef2f2;border-left-color:#ef4444}.tree-node.modified{background:#fffbeb;border-left-color:#f59e0b}.node-header{display:flex;align-items:center;gap:.5rem;padding:.5rem;border-radius:.375rem}.expand-btn{background:none;border:none;cursor:pointer;padding:.25rem;display:flex;align-items:center;justify-content:center;border-radius:.25rem;transition:background .2s}.expand-btn:hover{background:#f3f4f6}.spacer{width:24px}.node-icon{color:#6b7280}.node-content{display:flex;align-items:center;gap:.5rem;flex:1}.node-name{font-size:.875rem;font-weight:500;color:#1f2937}.node-type{font-size:.75rem;color:#6b7280;background:#f3f4f6;padding:.125rem .5rem;border-radius:.25rem}.change-badge{font-size:.625rem;font-weight:600;text-transform:uppercase;padding:.125rem .5rem;border-radius:.25rem;margin-left:auto}.tree-node.added .change-badge{background:#10b981;color:#fff}.tree-node.removed .change-badge{background:#ef4444;color:#fff}.tree-node.modified .change-badge{background:#f59e0b;color:#fff}.node-properties{margin-left:2.5rem;margin-top:.5rem;padding:.5rem;background:#f9fafb;border-radius:.375rem;font-size:.75rem;max-width:100%;overflow:hidden}.property{display:flex;flex-wrap:wrap;gap:.5rem;padding:.25rem 0;max-width:100%;overflow:hidden}.property.modified{background:#fef3c7;padding:.25rem .5rem;border-radius:.25rem;margin:.125rem 0}.property-key{font-weight:600;color:#374151;flex-shrink:0}.property-value{color:#6b7280;word-break:break-word;overflow:auto;overflow-wrap:break-word;flex:1;min-width:0}.node-children{margin-left:1.5rem;margin-top:.5rem;display:flex;flex-direction:column;gap:.5rem}.comparison-container.fullscreen{position:fixed;inset:0;z-index:9999;background:#f9fafb}.comparison-container.fullscreen .header,.comparison-container.fullscreen .file-selection,.comparison-container.fullscreen .entity-selection,.comparison-container.fullscreen .summary-section{display:none}.comparison-container.fullscreen .comparison-results{height:100vh;padding:2rem}\n"] }]
|
|
217
|
+
}], ctorParameters: () => [{ type: i1.EntityComparisonService }] });
|
|
218
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LWNvbXBhcmlzb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY29uY2VwdG8tdXNlci1jb250cm9scy9zcmMvbGliL2VudGl0eS1jb21wYXJpc29uL2NvbXBvbmVudHMvZW50aXR5LWNvbXBhcmlzb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY29uY2VwdG8tdXNlci1jb250cm9scy9zcmMvbGliL2VudGl0eS1jb21wYXJpc29uL2NvbXBvbmVudHMvZW50aXR5LWNvbXBhcmlzb24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sNENBQTRDLENBQUM7Ozs7QUFpQnJGLE1BQU0sT0FBTyx5QkFBeUI7SUFhaEI7SUFacEIsUUFBUSxHQUFXLEVBQUUsQ0FBQztJQUN0QixTQUFTLEdBQVcsRUFBRSxDQUFDO0lBQ3ZCLFlBQVksR0FBVSxFQUFFLENBQUM7SUFDekIsYUFBYSxHQUFVLEVBQUUsQ0FBQztJQUMxQixrQkFBa0IsR0FBUSxJQUFJLENBQUM7SUFDL0IsbUJBQW1CLEdBQVEsSUFBSSxDQUFDO0lBQ2hDLGdCQUFnQixHQUE0QixJQUFJLENBQUM7SUFDakQsYUFBYSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDbEMsWUFBWSxHQUFHLEtBQUssQ0FBQztJQUNyQixzQkFBc0IsR0FBRyxDQUFDLENBQUM7SUFDM0IsV0FBVyxHQUFVLEVBQUUsQ0FBQztJQUV4QixZQUFvQixpQkFBMEM7UUFBMUMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUF5QjtJQUFHLENBQUM7SUFFbEUsa0JBQWtCLENBQUMsS0FBVTtRQUMz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QztRQUV0QyxNQUFNLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3pDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxNQUFNLENBQUMsQ0FBQztRQUUxRixPQUFPLFFBQVEsRUFBRSxrQkFBa0IsSUFBSSxFQUFFLENBQUM7SUFDNUMsQ0FBQztJQUVELGdCQUFnQjtRQUNkLElBQUksQ0FBQyxZQUFZLEdBQUcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQ3pDLENBQUM7d0dBNU9VLHlCQUF5Qjs0RkFBekIseUJBQXlCLG9FQUp6QixDQUFDLHVCQUF1QixDQUFDLDBCQ2Z0QyxxNFdBOE1jLGkvTURoTUYsWUFBWTs7NEZBS1gseUJBQXlCO2tCQVJyQyxTQUFTOytCQUNFLHVCQUF1QixjQUNyQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLENBQUMsYUFDWixDQUFDLHVCQUF1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEVudGl0eUNvbXBhcmlzb25TZXJ2aWNlIH0gZnJvbSAnLi4vY29yZS9zZXJ2aWNlcy9lbnRpdHktY29tcGFyaXNvbi5zZXJ2aWNlJztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGFyaXNvblJlc3VsdCB7XHJcbiAgbGVmdE9ubHk6IGFueVtdO1xyXG4gIHJpZ2h0T25seTogYW55W107XHJcbiAgbW9kaWZpZWQ6IGFueVtdO1xyXG4gIHVuY2hhbmdlZDogYW55W107XHJcbn1cclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnYXBwLWVudGl0eS1jb21wYXJpc29uJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxyXG4gIHByb3ZpZGVyczogW0VudGl0eUNvbXBhcmlzb25TZXJ2aWNlXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vZW50aXR5LWNvbXBhcmlzb24uY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL2VudGl0eS1jb21wYXJpc29uLmNvbXBvbmVudC5jc3MnXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgRW50aXR5Q29tcGFyaXNvbkNvbXBvbmVudCB7XHJcbiAgbGVmdEZpbGU6IHN0cmluZyA9ICcnO1xyXG4gIHJpZ2h0RmlsZTogc3RyaW5nID0gJyc7XHJcbiAgbGVmdEVudGl0aWVzOiBhbnlbXSA9IFtdO1xyXG4gIHJpZ2h0RW50aXRpZXM6IGFueVtdID0gW107XHJcbiAgc2VsZWN0ZWRMZWZ0RW50aXR5OiBhbnkgPSBudWxsO1xyXG4gIHNlbGVjdGVkUmlnaHRFbnRpdHk6IGFueSA9IG51bGw7XHJcbiAgY29tcGFyaXNvblJlc3VsdDogQ29tcGFyaXNvblJlc3VsdCB8IG51bGwgPSBudWxsO1xyXG4gIGV4cGFuZGVkTm9kZXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcclxuICBpc0Z1bGxTY3JlZW4gPSBmYWxzZTtcclxuICBjdXJyZW50RGlmZmVyZW5jZUluZGV4ID0gMDtcclxuICBkaWZmZXJlbmNlczogYW55W10gPSBbXTtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjb21wYXJpc29uU2VydmljZTogRW50aXR5Q29tcGFyaXNvblNlcnZpY2UpIHt9XHJcblxyXG4gIG9uTGVmdEZpbGVTZWxlY3RlZChldmVudDogYW55KTogdm9pZCB7XHJcbiAgICBjb25zdCBmaWxlOiBGaWxlID0gZXZlbnQudGFyZ2V0LmZpbGVzWzBdO1xyXG4gICAgaWYgKCFmaWxlKSByZXR1cm47XHJcblxyXG4gICAgdGhpcy5sZWZ0RmlsZSA9IGZpbGUubmFtZTtcclxuICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XHJcbiAgICBcclxuICAgIHJlYWRlci5vbmxvYWQgPSAoZTogYW55KSA9PiB7XHJcbiAgICAgIGNvbnN0IHhtbENvbnRlbnQgPSBlLnRhcmdldC5yZXN1bHQ7XHJcbiAgICAgIHRoaXMubGVmdEVudGl0aWVzID0gdGhpcy5jb21wYXJpc29uU2VydmljZS5wYXJzZUVudGl0aWVzKHhtbENvbnRlbnQpO1xyXG4gICAgICB0aGlzLnNlbGVjdGVkTGVmdEVudGl0eSA9IG51bGw7XHJcbiAgICAgIHRoaXMuY29tcGFyaXNvblJlc3VsdCA9IG51bGw7XHJcbiAgICB9O1xyXG4gICAgXHJcbiAgICByZWFkZXIucmVhZEFzVGV4dChmaWxlKTtcclxuICB9XHJcblxyXG4gIG9uUmlnaHRGaWxlU2VsZWN0ZWQoZXZlbnQ6IGFueSk6IHZvaWQge1xyXG4gICAgY29uc3QgZmlsZTogRmlsZSA9IGV2ZW50LnRhcmdldC5maWxlc1swXTtcclxuICAgIGlmICghZmlsZSkgcmV0dXJuO1xyXG5cclxuICAgIHRoaXMucmlnaHRGaWxlID0gZmlsZS5uYW1lO1xyXG4gICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcclxuICAgIFxyXG4gICAgcmVhZGVyLm9ubG9hZCA9IChlOiBhbnkpID0+IHtcclxuICAgICAgY29uc3QgeG1sQ29udGVudCA9IGUudGFyZ2V0LnJlc3VsdDtcclxuICAgICAgdGhpcy5yaWdodEVudGl0aWVzID0gdGhpcy5jb21wYXJpc29uU2VydmljZS5wYXJzZUVudGl0aWVzKHhtbENvbnRlbnQpO1xyXG4gICAgICB0aGlzLnNlbGVjdGVkUmlnaHRFbnRpdHkgPSBudWxsO1xyXG4gICAgICB0aGlzLmNvbXBhcmlzb25SZXN1bHQgPSBudWxsO1xyXG4gICAgfTtcclxuICAgIFxyXG4gICAgcmVhZGVyLnJlYWRBc1RleHQoZmlsZSk7XHJcbiAgfVxyXG5cclxuICBzZWxlY3RMZWZ0RW50aXR5KGVudGl0eTogYW55KTogdm9pZCB7XHJcbiAgICB0aGlzLnNlbGVjdGVkTGVmdEVudGl0eSA9IGVudGl0eTtcclxuICAgIHRoaXMuY29tcGFyZUlmQm90aFNlbGVjdGVkKCk7XHJcbiAgfVxyXG5cclxuICBzZWxlY3RSaWdodEVudGl0eShlbnRpdHk6IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5zZWxlY3RlZFJpZ2h0RW50aXR5ID0gZW50aXR5O1xyXG4gICAgdGhpcy5jb21wYXJlSWZCb3RoU2VsZWN0ZWQoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY29tcGFyZUlmQm90aFNlbGVjdGVkKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRMZWZ0RW50aXR5ICYmIHRoaXMuc2VsZWN0ZWRSaWdodEVudGl0eSkge1xyXG4gICAgICB0aGlzLmNvbXBhcmlzb25SZXN1bHQgPSB0aGlzLmNvbXBhcmlzb25TZXJ2aWNlLmNvbXBhcmVTdHJ1Y3R1cmVzKFxyXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRMZWZ0RW50aXR5LnN0cnVjdHVyZSxcclxuICAgICAgICB0aGlzLnNlbGVjdGVkUmlnaHRFbnRpdHkuc3RydWN0dXJlXHJcbiAgICAgICk7XHJcbiAgICAgIHRoaXMuYnVpbGREaWZmZXJlbmNlc0xpc3QoKTtcclxuICAgICAgdGhpcy5jdXJyZW50RGlmZmVyZW5jZUluZGV4ID0gMDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYnVpbGREaWZmZXJlbmNlc0xpc3QoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuY29tcGFyaXNvblJlc3VsdCkge1xyXG4gICAgICB0aGlzLmRpZmZlcmVuY2VzID0gW107XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmRpZmZlcmVuY2VzID0gW1xyXG4gICAgICAuLi50aGlzLmNvbXBhcmlzb25SZXN1bHQubGVmdE9ubHkubWFwKG5vZGUgPT4gKHsgbm9kZSwgdHlwZTogJ3JlbW92ZWQnIH0pKSxcclxuICAgICAgLi4udGhpcy5jb21wYXJpc29uUmVzdWx0LnJpZ2h0T25seS5tYXAobm9kZSA9PiAoeyBub2RlLCB0eXBlOiAnYWRkZWQnIH0pKSxcclxuICAgICAgLi4udGhpcy5jb21wYXJpc29uUmVzdWx0Lm1vZGlmaWVkLm1hcChub2RlID0+ICh7IG5vZGUsIHR5cGU6ICdtb2RpZmllZCcgfSkpXHJcbiAgICBdO1xyXG4gIH1cclxuXHJcbiAgbmF2aWdhdGVUb05leHREaWZmZXJlbmNlKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuZGlmZmVyZW5jZXMubGVuZ3RoID09PSAwKSByZXR1cm47XHJcblxyXG4gICAgdGhpcy5jdXJyZW50RGlmZmVyZW5jZUluZGV4ID0gKHRoaXMuY3VycmVudERpZmZlcmVuY2VJbmRleCArIDEpICUgdGhpcy5kaWZmZXJlbmNlcy5sZW5ndGg7XHJcbiAgICB0aGlzLnNjcm9sbFRvRGlmZmVyZW5jZSgpO1xyXG4gIH1cclxuXHJcbiAgbmF2aWdhdGVUb1ByZXZpb3VzRGlmZmVyZW5jZSgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmRpZmZlcmVuY2VzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xyXG5cclxuICAgIHRoaXMuY3VycmVudERpZmZlcmVuY2VJbmRleCA9IHRoaXMuY3VycmVudERpZmZlcmVuY2VJbmRleCA9PT0gMFxyXG4gICAgICA/IHRoaXMuZGlmZmVyZW5jZXMubGVuZ3RoIC0gMVxyXG4gICAgICA6IHRoaXMuY3VycmVudERpZmZlcmVuY2VJbmRleCAtIDE7XHJcbiAgICB0aGlzLnNjcm9sbFRvRGlmZmVyZW5jZSgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzY3JvbGxUb0RpZmZlcmVuY2UoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5kaWZmZXJlbmNlcy5sZW5ndGggPT09IDApIHJldHVybjtcclxuXHJcbiAgICBjb25zdCBjdXJyZW50RGlmZiA9IHRoaXMuZGlmZmVyZW5jZXNbdGhpcy5jdXJyZW50RGlmZmVyZW5jZUluZGV4XTtcclxuICAgIGNvbnN0IG5vZGVJZCA9IGAke2N1cnJlbnREaWZmLm5vZGUuSWR9LSR7Y3VycmVudERpZmYubm9kZS5uYW1lfWA7XHJcblxyXG4gICAgLy8gRXhwYW5kIHBhcmVudCBub2RlcyBGSVJTVCB0byBtYWtlIHRoZSBkaWZmZXJlbmNlIHZpc2libGVcclxuICAgIHRoaXMuZXhwYW5kUGF0aFRvTm9kZShjdXJyZW50RGlmZi5ub2RlKTtcclxuXHJcbiAgICAvLyBXYWl0IGZvciBET00gdG8gdXBkYXRlIGFmdGVyIGV4cGFuc2lvbiwgdGhlbiBzY3JvbGxcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICBjb25zdCBsZWZ0RWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYFtkYXRhLW5vZGUtaWQ9XCJsZWZ0LSR7bm9kZUlkfVwiXWApO1xyXG4gICAgICBjb25zdCByaWdodEVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBbZGF0YS1ub2RlLWlkPVwicmlnaHQtJHtub2RlSWR9XCJdYCk7XHJcblxyXG4gICAgICBpZiAobGVmdEVsZW1lbnQpIHtcclxuICAgICAgICBsZWZ0RWxlbWVudC5zY3JvbGxJbnRvVmlldyh7IGJlaGF2aW9yOiAnc21vb3RoJywgYmxvY2s6ICdjZW50ZXInIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChyaWdodEVsZW1lbnQpIHtcclxuICAgICAgICByaWdodEVsZW1lbnQuc2Nyb2xsSW50b1ZpZXcoeyBiZWhhdmlvcjogJ3Ntb290aCcsIGJsb2NrOiAnY2VudGVyJyB9KTtcclxuICAgICAgfVxyXG4gICAgfSwgMTAwKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZXhwYW5kUGF0aFRvTm9kZShub2RlOiBhbnkpOiB2b2lkIHtcclxuICAgIC8vIEZpbmQgYW5kIGV4cGFuZCBhbGwgcGFyZW50IG5vZGVzIGluIGJvdGggc3RydWN0dXJlc1xyXG4gICAgdGhpcy5leHBhbmRQYXJlbnRzSW5TdHJ1Y3R1cmUodGhpcy5zZWxlY3RlZExlZnRFbnRpdHkuc3RydWN0dXJlLCBub2RlLCAnbGVmdCcpO1xyXG4gICAgdGhpcy5leHBhbmRQYXJlbnRzSW5TdHJ1Y3R1cmUodGhpcy5zZWxlY3RlZFJpZ2h0RW50aXR5LnN0cnVjdHVyZSwgbm9kZSwgJ3JpZ2h0Jyk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGV4cGFuZFBhcmVudHNJblN0cnVjdHVyZShzdHJ1Y3R1cmU6IGFueVtdLCB0YXJnZXROb2RlOiBhbnksIHNpZGU6IHN0cmluZyk6IGJvb2xlYW4ge1xyXG4gICAgZm9yIChjb25zdCBub2RlIG9mIHN0cnVjdHVyZSkge1xyXG4gICAgICBjb25zdCBub2RlSWQgPSBgJHtzaWRlfS0ke25vZGUuSWR9LSR7bm9kZS5uYW1lfWA7XHJcbiAgICAgIGNvbnN0IHRhcmdldElkID0gYCR7dGFyZ2V0Tm9kZS5JZH0tJHt0YXJnZXROb2RlLm5hbWV9YDtcclxuICAgICAgY29uc3QgY3VycmVudElkID0gYCR7bm9kZS5JZH0tJHtub2RlLm5hbWV9YDtcclxuXHJcbiAgICAgIC8vIElmIHRoaXMgaXMgdGhlIHRhcmdldCBub2RlLCB3ZSBmb3VuZCBpdFxyXG4gICAgICBpZiAoY3VycmVudElkID09PSB0YXJnZXRJZCkge1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBjaGlsZHJlbiBpZiB0aGV5IGV4aXN0XHJcbiAgICAgIGlmICh0aGlzLmhhc0NoaWxkcmVuKG5vZGUpKSB7XHJcbiAgICAgICAgY29uc3QgY2hpbGRyZW4gPSB0aGlzLmdldENoaWxkcmVuKG5vZGUpO1xyXG4gICAgICAgIGlmICh0aGlzLmV4cGFuZFBhcmVudHNJblN0cnVjdHVyZShjaGlsZHJlbiwgdGFyZ2V0Tm9kZSwgc2lkZSkpIHtcclxuICAgICAgICAgIC8vIElmIHRoZSB0YXJnZXQgaXMgaW4gdGhpcyBicmFuY2gsIGV4cGFuZCB0aGlzIG5vZGVcclxuICAgICAgICAgIHRoaXMuZXhwYW5kZWROb2Rlcy5hZGQobm9kZUlkKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIGdldCBoYXNEaWZmZXJlbmNlcygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLmRpZmZlcmVuY2VzLmxlbmd0aCA+IDA7XHJcbiAgfVxyXG5cclxuICBnZXQgY3VycmVudERpZmZlcmVuY2VOdW1iZXIoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLmN1cnJlbnREaWZmZXJlbmNlSW5kZXggKyAxO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHRvdGFsRGlmZmVyZW5jZXMoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLmRpZmZlcmVuY2VzLmxlbmd0aDtcclxuICB9XHJcblxyXG4gIHRvZ2dsZU5vZGUobm9kZUlkOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmV4cGFuZGVkTm9kZXMuaGFzKG5vZGVJZCkpIHtcclxuICAgICAgdGhpcy5leHBhbmRlZE5vZGVzLmRlbGV0ZShub2RlSWQpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5leHBhbmRlZE5vZGVzLmFkZChub2RlSWQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgaXNFeHBhbmRlZChub2RlSWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuZXhwYW5kZWROb2Rlcy5oYXMobm9kZUlkKTtcclxuICB9XHJcblxyXG4gIGdldE5vZGVJZChub2RlOiBhbnksIHByZWZpeDogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBgJHtwcmVmaXh9LSR7bm9kZS5JZH0tJHtub2RlLm5hbWV9YDtcclxuICB9XHJcblxyXG4gIGhhc0NoaWxkcmVuKG5vZGU6IGFueSk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIG5vZGUuQ2hpbGRyZW4gJiYgSlNPTi5wYXJzZShub2RlLkNoaWxkcmVuKS5sZW5ndGggPiAwO1xyXG4gIH1cclxuXHJcbiAgZ2V0Q2hpbGRyZW4obm9kZTogYW55KTogYW55W10ge1xyXG4gICAgaWYgKCFub2RlLkNoaWxkcmVuKSByZXR1cm4gW107XHJcbiAgICB0cnkge1xyXG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShub2RlLkNoaWxkcmVuKTtcclxuICAgIH0gY2F0Y2gge1xyXG4gICAgICByZXR1cm4gW107XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXRQcm9wZXJ0aWVzKG5vZGU6IGFueSk6IGFueSB7XHJcbiAgICBpZiAoIW5vZGUuUHJvcGVydGllcykgcmV0dXJuIHt9O1xyXG4gICAgdHJ5IHtcclxuICAgICAgcmV0dXJuIEpTT04ucGFyc2Uobm9kZS5Qcm9wZXJ0aWVzKTtcclxuICAgIH0gY2F0Y2gge1xyXG4gICAgICByZXR1cm4ge307XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXRQcm9wZXJ0eUtleXMobm9kZTogYW55KTogc3RyaW5nW10ge1xyXG4gICAgY29uc3QgcHJvcHMgPSB0aGlzLmdldFByb3BlcnRpZXMobm9kZSk7XHJcbiAgICByZXR1cm4gT2JqZWN0LmtleXMocHJvcHMpO1xyXG4gIH1cclxuXHJcbiAgZ2V0Q2hhbmdlVHlwZShub2RlOiBhbnkpOiBzdHJpbmcge1xyXG4gICAgaWYgKCF0aGlzLmNvbXBhcmlzb25SZXN1bHQpIHJldHVybiAnJztcclxuICAgIFxyXG4gICAgY29uc3Qgbm9kZUlkID0gYCR7bm9kZS5JZH0tJHtub2RlLm5hbWV9YDtcclxuICAgIFxyXG4gICAgaWYgKHRoaXMuY29tcGFyaXNvblJlc3VsdC5sZWZ0T25seS5zb21lKG4gPT4gYCR7bi5JZH0tJHtuLm5hbWV9YCA9PT0gbm9kZUlkKSkge1xyXG4gICAgICByZXR1cm4gJ3JlbW92ZWQnO1xyXG4gICAgfVxyXG4gICAgaWYgKHRoaXMuY29tcGFyaXNvblJlc3VsdC5yaWdodE9ubHkuc29tZShuID0+IGAke24uSWR9LSR7bi5uYW1lfWAgPT09IG5vZGVJZCkpIHtcclxuICAgICAgcmV0dXJuICdhZGRlZCc7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5jb21wYXJpc29uUmVzdWx0Lm1vZGlmaWVkLnNvbWUobiA9PiBgJHtuLklkfS0ke24ubmFtZX1gID09PSBub2RlSWQpKSB7XHJcbiAgICAgIHJldHVybiAnbW9kaWZpZWQnO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuICd1bmNoYW5nZWQnO1xyXG4gIH1cclxuXHJcbiAgZ2V0TW9kaWZpZWRQcm9wZXJ0aWVzKG5vZGU6IGFueSk6IHN0cmluZ1tdIHtcclxuICAgIGlmICghdGhpcy5jb21wYXJpc29uUmVzdWx0KSByZXR1cm4gW107XHJcblxyXG4gICAgY29uc3Qgbm9kZUlkID0gYCR7bm9kZS5JZH0tJHtub2RlLm5hbWV9YDtcclxuICAgIGNvbnN0IG1vZGlmaWVkID0gdGhpcy5jb21wYXJpc29uUmVzdWx0Lm1vZGlmaWVkLmZpbmQobiA9PiBgJHtuLklkfS0ke24ubmFtZX1gID09PSBub2RlSWQpO1xyXG5cclxuICAgIHJldHVybiBtb2RpZmllZD8ubW9kaWZpZWRQcm9wZXJ0aWVzIHx8IFtdO1xyXG4gIH1cclxuXHJcbiAgdG9nZ2xlRnVsbFNjcmVlbigpOiB2b2lkIHtcclxuICAgIHRoaXMuaXNGdWxsU2NyZWVuID0gIXRoaXMuaXNGdWxsU2NyZWVuO1xyXG4gIH1cclxufSIsIjxkaXYgY2xhc3M9XCJjb21wYXJpc29uLWNvbnRhaW5lclwiIFtjbGFzcy5mdWxsc2NyZWVuXT1cImlzRnVsbFNjcmVlblwiPlxyXG4gICAgPGhlYWRlciBjbGFzcz1cImhlYWRlclwiPlxyXG4gICAgICAgIDxoMT5FbnRpdHkgU3RydWN0dXJlIENvbXBhcmlzb248L2gxPlxyXG4gICAgICAgIDxwIGNsYXNzPVwic3VidGl0bGVcIj5Db21wYXJlIEVudGl0eVN0cnVjdHVyZUpzb24gYmV0d2VlbiB0d28gZW50aXR5IGV4cG9ydHM8L3A+XHJcbiAgICA8L2hlYWRlcj5cclxuXHJcbiAgICA8ZGl2IGNsYXNzPVwiZmlsZS1zZWxlY3Rpb25cIj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmlsZS1pbnB1dC1ncm91cFwiPlxyXG4gICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWxlLWxhYmVsIGxlZnRcIj5cclxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiZmlsZVwiIGFjY2VwdD1cIi54bWxcIiAoY2hhbmdlKT1cIm9uTGVmdEZpbGVTZWxlY3RlZCgkZXZlbnQpXCIgaGlkZGVuPlxyXG4gICAgICAgICAgICAgICAgPHN2ZyB3aWR0aD1cIjE2XCIgaGVpZ2h0PVwiMTZcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD1cIk0yMSAxNXY0YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0ydi00XCIgLz5cclxuICAgICAgICAgICAgICAgICAgICA8cG9seWxpbmUgcG9pbnRzPVwiMTcgOCAxMiAzIDcgOFwiIC8+XHJcbiAgICAgICAgICAgICAgICAgICAgPGxpbmUgeDE9XCIxMlwiIHkxPVwiM1wiIHgyPVwiMTJcIiB5Mj1cIjE1XCIgLz5cclxuICAgICAgICAgICAgICAgIDwvc3ZnPlxyXG4gICAgICAgICAgICAgICAgTG9hZCBMZWZ0IEVudGl0eVxyXG4gICAgICAgICAgICA8L2xhYmVsPlxyXG4gICAgICAgICAgICA8c3BhbiAqbmdJZj1cImxlZnRGaWxlXCIgY2xhc3M9XCJmaWxlLW5hbWVcIj57eyBsZWZ0RmlsZSB9fTwvc3Bhbj5cclxuICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInZzLXNlcGFyYXRvclwiPlZTPC9kaXY+XHJcblxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWxlLWlucHV0LWdyb3VwXCI+XHJcbiAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZpbGUtbGFiZWwgcmlnaHRcIj5cclxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiZmlsZVwiIGFjY2VwdD1cIi54bWxcIiAoY2hhbmdlKT1cIm9uUmlnaHRGaWxlU2VsZWN0ZWQoJGV2ZW50KVwiIGhpZGRlbj5cclxuICAgICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIxNlwiIGhlaWdodD1cIjE2XCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiPlxyXG4gICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9XCJNMjEgMTV2NGEyIDIgMCAwIDEtMiAySDVhMiAyIDAgMCAxLTItMnYtNFwiIC8+XHJcbiAgICAgICAgICAgICAgICAgICAgPHBvbHlsaW5lIHBvaW50cz1cIjE3IDggMTIgMyA3IDhcIiAvPlxyXG4gICAgICAgICAgICAgICAgICAgIDxsaW5lIHgxPVwiMTJcIiB5MT1cIjNcIiB4Mj1cIjEyXCIgeTI9XCIxNVwiIC8+XHJcbiAgICAgICAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgICAgICAgIExvYWQgUmlnaHQgRW50aXR5XHJcbiAgICAgICAgICAgIDwvbGFiZWw+XHJcbiAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwicmlnaHRGaWxlXCIgY2xhc3M9XCJmaWxlLW5hbWVcIj57eyByaWdodEZpbGUgfX08L3NwYW4+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8ZGl2IGNsYXNzPVwiZW50aXR5LXNlbGVjdGlvblwiICpuZ0lmPVwibGVmdEVudGl0aWVzLmxlbmd0aCA+IDAgfHwgcmlnaHRFbnRpdGllcy5sZW5ndGggPiAwXCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImVudGl0eS1saXN0XCI+XHJcbiAgICAgICAgICAgIDxoMz5MZWZ0IEVudGl0aWVzPC9oMz5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImVudGl0aWVzXCI+XHJcbiAgICAgICAgICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBlbnRpdHkgb2YgbGVmdEVudGl0aWVzXCIgY2xhc3M9XCJlbnRpdHktY2FyZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgW2NsYXNzLnNlbGVjdGVkXT1cInNlbGVjdGVkTGVmdEVudGl0eSA9PT0gZW50aXR5XCIgKGNsaWNrKT1cInNlbGVjdExlZnRFbnRpdHkoZW50aXR5KVwiPlxyXG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnRpdHktaWNvblwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8c3ZnIHdpZHRoPVwiMjBcIiBoZWlnaHQ9XCIyMFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJva2Utd2lkdGg9XCIyXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPVwiTTIyIDE5YTIgMiAwIDAgMS0yIDJINGEyIDIgMCAwIDEtMi0yVjVhMiAyIDAgMCAxIDItMmg1bDIgM2g5YTIgMiAwIDAgMSAyIDJ6XCIgLz5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImVudGl0eS1pbmZvXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnRpdHktbmFtZVwiPnt7IGVudGl0eS5uYW1lIH19PC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnRpdHktaWRcIj57eyBlbnRpdHkuaWQgfX08L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImVudGl0eS1saXN0XCI+XHJcbiAgICAgICAgICAgIDxoMz5SaWdodCBFbnRpdGllczwvaDM+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnRpdGllc1wiPlxyXG4gICAgICAgICAgICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgZW50aXR5IG9mIHJpZ2h0RW50aXRpZXNcIiBjbGFzcz1cImVudGl0eS1jYXJkXCJcclxuICAgICAgICAgICAgICAgICAgICBbY2xhc3Muc2VsZWN0ZWRdPVwic2VsZWN0ZWRSaWdodEVudGl0eSA9PT0gZW50aXR5XCIgKGNsaWNrKT1cInNlbGVjdFJpZ2h0RW50aXR5KGVudGl0eSlcIj5cclxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZW50aXR5LWljb25cIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPHN2ZyB3aWR0aD1cIjIwXCIgaGVpZ2h0PVwiMjBcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Ryb2tlLXdpZHRoPVwiMlwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPHBhdGggZD1cIk0yMiAxOWEyIDIgMCAwIDEtMiAySDRhMiAyIDAgMCAxLTItMlY1YTIgMiAwIDAgMSAyLTJoNWwyIDNoOWEyIDIgMCAwIDEgMiAyelwiIC8+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvc3ZnPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnRpdHktaW5mb1wiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZW50aXR5LW5hbWVcIj57eyBlbnRpdHkubmFtZSB9fTwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZW50aXR5LWlkXCI+e3sgZW50aXR5LmlkIH19PC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8ZGl2IGNsYXNzPVwic3VtbWFyeS1zZWN0aW9uXCIgKm5nSWY9XCJjb21wYXJpc29uUmVzdWx0XCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInN1bW1hcnlcIj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN1bW1hcnktaXRlbSBhZGRlZFwiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjb3VudFwiPnt7IGNvbXBhcmlzb25SZXN1bHQucmlnaHRPbmx5Lmxlbmd0aCB9fTwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5BZGRlZDwvc3Bhbj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdW1tYXJ5LWl0ZW0gcmVtb3ZlZFwiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjb3VudFwiPnt7IGNvbXBhcmlzb25SZXN1bHQubGVmdE9ubHkubGVuZ3RoIH19PC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPlJlbW92ZWQ8L3NwYW4+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3VtbWFyeS1pdGVtIG1vZGlmaWVkXCI+XHJcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNvdW50XCI+e3sgY29tcGFyaXNvblJlc3VsdC5tb2RpZmllZC5sZW5ndGggfX08L3NwYW4+XHJcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+TW9kaWZpZWQ8L3NwYW4+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3VtbWFyeS1pdGVtIHVuY2hhbmdlZFwiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjb3VudFwiPnt7IGNvbXBhcmlzb25SZXN1bHQudW5jaGFuZ2VkLmxlbmd0aCB9fTwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5VbmNoYW5nZWQ8L3NwYW4+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cImNvbXBhcmlzb24tcmVzdWx0c1wiICpuZ0lmPVwiY29tcGFyaXNvblJlc3VsdFwiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJyZXN1bHRzLWhlYWRlclwiPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaGVhZGVyLXRpdGxlXCI+XHJcbiAgICAgICAgICAgICAgICA8aDI+Q29tcGFyaXNvbiBSZXN1bHRzPC9oMj5cclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJoZWFkZXItYWN0aW9uc1wiPlxyXG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkaWZmLW5hdmlnYXRpb25cIiAqbmdJZj1cImhhc0RpZmZlcmVuY2VzXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJuYXYtYnRuXCIgKGNsaWNrKT1cIm5hdmlnYXRlVG9QcmV2aW91c0RpZmZlcmVuY2UoKVwiIHRpdGxlPVwiUHJldmlvdXMgRGlmZmVyZW5jZVwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPHN2ZyB3aWR0aD1cIjIwXCIgaGVpZ2h0PVwiMjBcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHBvbHlsaW5lIHBvaW50cz1cIjE4IDE1IDEyIDkgNiAxNVwiIC8+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZGlmZi1jb3VudGVyXCI+e3sgY3VycmVudERpZmZlcmVuY2VOdW1iZXIgfX0gLyB7eyB0b3RhbERpZmZlcmVuY2VzIH19PC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwibmF2LWJ0blwiIChjbGljayk9XCJuYXZpZ2F0ZVRvTmV4dERpZmZlcmVuY2UoKVwiIHRpdGxlPVwiTmV4dCBEaWZmZXJlbmNlXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3ZnIHdpZHRoPVwiMjBcIiBoZWlnaHQ9XCIyMFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8cG9seWxpbmUgcG9pbnRzPVwiNiA5IDEyIDE1IDE4IDlcIiAvPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJmdWxsc2NyZWVuLWJ0blwiIChjbGljayk9XCJ0b2dnbGVGdWxsU2NyZWVuKClcIiBbdGl0bGVdPVwiaXNGdWxsU2NyZWVuID8gJ0V4aXQgRnVsbCBTY3JlZW4nIDogJ0VudGVyIEZ1bGwgU2NyZWVuJ1wiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8c3ZnICpuZ0lmPVwiIWlzRnVsbFNjcmVlblwiIHdpZHRoPVwiMjBcIiBoZWlnaHQ9XCIyMFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9XCJNOCAzSDVhMiAyIDAgMCAwLTIgMnYzbTE4IDBWNWEyIDIgMCAwIDAtMi0yaC0zbTAgMThoM2EyIDIgMCAwIDAgMi0ydi0zTTMgMTZ2M2EyIDIgMCAwIDAgMiAyaDNcIiAvPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPHN2ZyAqbmdJZj1cImlzRnVsbFNjcmVlblwiIHdpZHRoPVwiMjBcIiBoZWlnaHQ9XCIyMFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9XCJNOCAzdjNhMiAyIDAgMCAxLTIgMkgzbTE4IDBoLTNhMiAyIDAgMCAxLTItMlYzbTAgMTh2LTNhMiAyIDAgMCAxIDItMmgzTTMgMTZoM2EyIDIgMCAwIDEgMiAydjNcIiAvPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInN0cnVjdHVyZS1jb21wYXJpc29uXCI+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb21wYXJpc29uLXNlY3Rpb25cIj5cclxuICAgICAgICAgICAgICAgIDxoMz5cclxuICAgICAgICAgICAgICAgICAgICA8c3ZnIHdpZHRoPVwiMTZcIiBoZWlnaHQ9XCIxNlwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPHBhdGggZD1cIk05IDExbDMgM0wyMiA0XCIgLz5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPHBhdGggZD1cIk0yMSAxMnY3YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0yVjVhMiAyIDAgMCAxIDItMmgxMVwiIC8+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICAgICAgICAgICAge3sgc2VsZWN0ZWRMZWZ0RW50aXR5Lm5hbWUgfX1cclxuICAgICAgICAgICAgICAgIDwvaDM+XHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RydWN0dXJlLXRyZWVcIj5cclxuICAgICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBub2RlIG9mIHNlbGVjdGVkTGVmdEVudGl0eS5zdHJ1Y3R1cmVcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJub2RlVGVtcGxhdGU7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBub2RlLCBzaWRlOiAnbGVmdCcgfVwiPjwvbmctY29udGFpbmVyPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxyXG4gICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbXBhcmlzb24tc2VjdGlvblwiPlxyXG4gICAgICAgICAgICAgICAgPGgzPlxyXG4gICAgICAgICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIxNlwiIGhlaWdodD1cIjE2XCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPVwiTTkgMTFsMyAzTDIyIDRcIiAvPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPVwiTTIxIDEydjdhMiAyIDAgMCAxLTIgMkg1YTIgMiAwIDAgMS0yLTJWNWEyIDIgMCAwIDEgMi0yaDExXCIgLz5cclxuICAgICAgICAgICAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgICAgICAgICAgICB7eyBzZWxlY3RlZFJpZ2h0RW50aXR5Lm5hbWUgfX1cclxuICAgICAgICAgICAgICAgIDwvaDM+XHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RydWN0dXJlLXRyZWVcIj5cclxuICAgICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBub2RlIG9mIHNlbGVjdGVkUmlnaHRFbnRpdHkuc3RydWN0dXJlXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXJcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwibm9kZVRlbXBsYXRlOyBjb250ZXh0OiB7ICRpbXBsaWNpdDogbm9kZSwgc2lkZTogJ3JpZ2h0JyB9XCI+PC9uZy1jb250YWluZXI+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuPC9kaXY+XHJcblxyXG48bmctdGVtcGxhdGUgI25vZGVUZW1wbGF0ZSBsZXQtbm9kZSBsZXQtc2lkZT1cInNpZGVcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJ0cmVlLW5vZGVcIiBbY2xhc3NdPVwiZ2V0Q2hhbmdlVHlwZShub2RlKVwiIFthdHRyLmRhdGEtbm9kZS1pZF09XCJnZXROb2RlSWQobm9kZSwgc2lkZSlcIj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwibm9kZS1oZWFkZXJcIj5cclxuICAgICAgICAgICAgPGJ1dHRvbiAqbmdJZj1cImhhc0NoaWxkcmVuKG5vZGUpXCIgY2xhc3M9XCJleHBhbmQtYnRuXCIgKGNsaWNrKT1cInRvZ2dsZU5vZGUoZ2V0Tm9kZUlkKG5vZGUsIHNpZGUpKVwiPlxyXG4gICAgICAgICAgICAgICAgPHN2ZyB3aWR0aD1cIjEyXCIgaGVpZ2h0PVwiMTJcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPHBvbHlsaW5lICpuZ0lmPVwiIWlzRXhwYW5kZWQoZ2V0Tm9kZUlkKG5vZGUsIHNpZGUpKVwiIHBvaW50cz1cIjkgMTggMTUgMTIgOSA2XCIgLz5cclxuICAgICAgICAgICAgICAgICAgICA8cG9seWxpbmUgKm5nSWY9XCJpc0V4cGFuZGVkKGdldE5vZGVJZChub2RlLCBzaWRlKSlcIiBwb2ludHM9XCI2IDkgMTIgMTUgMTggOVwiIC8+XHJcbiAgICAgICAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICAgIDxkaXYgKm5nSWY9XCIhaGFzQ2hpbGRyZW4obm9kZSlcIiBjbGFzcz1cInNwYWNlclwiPjwvZGl2PlxyXG5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5vZGUtaWNvblwiPlxyXG4gICAgICAgICAgICAgICAgPHN2ZyB3aWR0aD1cIjE0XCIgaGVpZ2h0PVwiMTRcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPHBhdGggKm5nSWY9XCJub2RlLm5vZGVUeXBlID09PSAnR3JvdXAnXCJcclxuICAgICAgICAgICAgICAgICAgICAgICAgZD1cIk0yMiAxOWEyIDIgMCAwIDEtMiAySDRhMiAyIDAgMCAxLTItMlY1YTIgMiAwIDAgMSAyLTJoNWwyIDNoOWEyIDIgMCAwIDEgMiAyelwiIC8+XHJcbiAgICAgICAgICAgICAgICAgICAgPGNpcmNsZSAqbmdJZj1cIm5vZGUubm9kZVR5cGUgPT09ICdBdHRyaWJ1dGUnXCIgY3g9XCIxMlwiIGN5PVwiMTJcIiByPVwiMTBcIiAvPlxyXG4gICAgICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5vZGUtY29udGVudFwiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJub2RlLW5hbWVcIj57eyBub2RlLm5hbWUgfX08L3NwYW4+XHJcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5vZGUtdHlwZVwiPnt7IG5vZGUubm9kZVR5cGUgfX08L3NwYW4+XHJcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNoYW5nZS1iYWRnZVwiICpuZ0lmPVwiZ2V0Q2hhbmdlVHlwZShub2RlKSAhPT0gJ3VuY2hhbmdlZCdcIj5cclxuICAgICAgICAgICAgICAgICAgICB7eyBnZXRDaGFuZ2VUeXBlKG5vZGUpIH19XHJcbiAgICAgICAgICAgICAgICA8L3NwYW4+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwibm9kZS1wcm9wZXJ0aWVzXCIgKm5nSWY9XCJnZXRQcm9wZXJ0eUtleXMobm9kZSkubGVuZ3RoID4gMFwiPlxyXG4gICAgICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBrZXkgb2YgZ2V0UHJvcGVydHlLZXlzKG5vZGUpXCIgY2xhc3M9XCJwcm9wZXJ0eVwiXHJcbiAgICAgICAgICAgICAgICBbY2xhc3MubW9kaWZpZWRdPVwiZ2V0TW9kaWZpZWRQcm9wZXJ0aWVzKG5vZGUpLmluY2x1ZGVzKGtleSlcIj5cclxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicHJvcGVydHkta2V5XCI+e3sga2V5IH19Ojwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicHJvcGVydHktdmFsdWVcIj57eyBnZXRQcm9wZXJ0aWVzKG5vZGUpW2tleV0gfX08L3NwYW4+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwibm9kZS1jaGlsZHJlblwiICpuZ0lmPVwiaGFzQ2hpbGRyZW4obm9kZSkgJiYgaXNFeHBhbmRlZChnZXROb2RlSWQobm9kZSwgc2lkZSkpXCI+XHJcbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGNoaWxkIG9mIGdldENoaWxkcmVuKG5vZGUpXCI+XHJcbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyXHJcbiAgICAgICAgICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJub2RlVGVtcGxhdGU7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBjaGlsZCwgc2lkZTogc2lkZSB9XCI+PC9uZy1jb250YWluZXI+XHJcbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbjwvbmctdGVtcGxhdGU+Il19
|