cytoscape-angular
Version:
Angular 12+ components for cytoscape charting.
345 lines (341 loc) • 35.6 kB
JavaScript
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { FormInfo } from '../fluid-form/form-info';
import { createStyleCoreFormInfo, createStyleEdgeFieldSets, createStyleNodeFieldSets, StylesheetImpl } from '../style/style';
import * as i0 from "@angular/core";
import * as i1 from "primeng/button";
import * as i2 from "primeng/autocomplete";
import * as i3 from "@angular/forms";
import * as i4 from "@angular/common";
import * as i5 from "../fluid-form/fluid-form.component";
const _c0 = ["styleForm"];
const _c1 = ["selectorDropDown"];
function CytoscapeStyleToolComponent_ng_container_20_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelementContainerStart(0);
i0.ɵɵelementStart(1, "div");
i0.ɵɵtext(2, " Please select a ");
i0.ɵɵelementStart(3, "a", 5);
i0.ɵɵtext(4, "selector");
i0.ɵɵelementEnd();
i0.ɵɵtext(5, " above or type a selector name and click \"Add\" to create a new stylesheet for that selector.");
i0.ɵɵelementEnd();
i0.ɵɵelementContainerEnd();
} }
function CytoscapeStyleToolComponent_ng_container_21_Template(rf, ctx) { if (rf & 1) {
const _r6 = i0.ɵɵgetCurrentView();
i0.ɵɵelementContainerStart(0);
i0.ɵɵelementStart(1, "cyng-fluid-form", 12);
i0.ɵɵlistener("modelChange", function CytoscapeStyleToolComponent_ng_container_21_Template_cyng_fluid_form_modelChange_1_listener() { i0.ɵɵrestoreView(_r6); const ctx_r5 = i0.ɵɵnextContext(); return ctx_r5.onFormModelChange(); });
i0.ɵɵelementEnd();
i0.ɵɵelementContainerEnd();
} if (rf & 2) {
const ctx_r2 = i0.ɵɵnextContext();
i0.ɵɵadvance(1);
i0.ɵɵproperty("model", ctx_r2.selectedStyleSheet.style)("formInfo", ctx_r2.nodeFormInfo);
} }
function CytoscapeStyleToolComponent_ng_container_22_Template(rf, ctx) { if (rf & 1) {
const _r8 = i0.ɵɵgetCurrentView();
i0.ɵɵelementContainerStart(0);
i0.ɵɵelementStart(1, "cyng-fluid-form", 12);
i0.ɵɵlistener("modelChange", function CytoscapeStyleToolComponent_ng_container_22_Template_cyng_fluid_form_modelChange_1_listener() { i0.ɵɵrestoreView(_r8); const ctx_r7 = i0.ɵɵnextContext(); return ctx_r7.onFormModelChange(); });
i0.ɵɵelementEnd();
i0.ɵɵelementContainerEnd();
} if (rf & 2) {
const ctx_r3 = i0.ɵɵnextContext();
i0.ɵɵadvance(1);
i0.ɵɵproperty("model", ctx_r3.selectedStyleSheet.style)("formInfo", ctx_r3.edgeFormInfo);
} }
function CytoscapeStyleToolComponent_ng_container_23_Template(rf, ctx) { if (rf & 1) {
const _r10 = i0.ɵɵgetCurrentView();
i0.ɵɵelementContainerStart(0);
i0.ɵɵelementStart(1, "cyng-fluid-form", 12);
i0.ɵɵlistener("modelChange", function CytoscapeStyleToolComponent_ng_container_23_Template_cyng_fluid_form_modelChange_1_listener() { i0.ɵɵrestoreView(_r10); const ctx_r9 = i0.ɵɵnextContext(); return ctx_r9.onFormModelChange(); });
i0.ɵɵelementEnd();
i0.ɵɵelementContainerEnd();
} if (rf & 2) {
const ctx_r4 = i0.ɵɵnextContext();
i0.ɵɵadvance(1);
i0.ɵɵproperty("model", ctx_r4.selectedStyleSheet.style)("formInfo", ctx_r4.coreFormInfo);
} }
const _c2 = function () { return { "width": "70%" }; };
export class CytoscapeStyleToolComponent {
constructor() {
this.enableAdd = false;
this.stylesChange = new EventEmitter();
this.styleSelectorChange = new EventEmitter();
this.changed = false;
}
get styles() {
return this._styles;
}
set styles(styles) {
this._styles = styles;
}
ngOnInit() {
this.coreFormInfo = createStyleCoreFormInfo();
this.nodeFormInfo = new FormInfo('Node', createStyleNodeFieldSets());
this.edgeFormInfo = new FormInfo('Edge', createStyleEdgeFieldSets());
if (!this.styles) {
this.styles = [new StylesheetImpl()];
}
this.setSelectorsFromStyles(null);
this.selectedStyleSheet = this.selectors[0];
console.log(`this.selectors.length:`, this.selectors.length);
}
ngOnChanges(changes) {
console.log('ngOnChanges style changes:', JSON.stringify(changes));
if (changes['styles']) {
this.setSelectorsFromStyles(null);
this.selectedStyleSheet = this.selectors[0];
console.log(`styles updated this.selectors.length:`, this.selectors.length);
}
}
ngAfterViewInit() {
// console.debug("ngAfterViewInit")
}
ngAfterViewChecked() {
// console.debug("ngAfterViewChecked")
}
onFormModelChange() {
console.log('onFormModelChange');
this.changed = true;
}
onApplyStyle() {
this.changed = false;
this.stylesChange.emit(this.styles);
}
search(event) {
let searchString = event.query;
this.setSelectorsFromStyles(searchString);
}
setSelectorsFromStyles(searchString) {
this.selectors = this.styles.filter((stylesheet) => {
return searchString ? stylesheet.selector.includes(searchString) : true;
});
}
onAddSelector() {
const newStylesheetStyle = new StylesheetImpl();
newStylesheetStyle.selector = this.lastValidSelectorModelText;
console.log('Adding new style with selector:', this.lastValidSelectorModelText);
this.styles.unshift(newStylesheetStyle);
this.selectedStyleSheet = newStylesheetStyle;
}
/*
* The param can be a selector object when the user selects a stylesheet entry from the dropdown and changes the
* selection (which will fire a selection change to let the graph, say, focus on the selected node).
* or the param is text if the user is just typing in the field, which doens't change the selector untl the user
* clicks Add.
*/
onSelectorModelChange(param) {
console.log(`selectorModelChanged:${JSON.stringify(param)}`);
const selector = param.selector ? param.selector : param;
const stylesheet = param.selector ? param : this.getStylesheetForSelector(selector);
if (stylesheet) {
if (this.changed) {
this.onApplyStyle();
}
this.styleSelectorChange.emit(selector);
}
else {
this.enableAdd = this.isValidSelector(selector);
if (this.enableAdd) {
this.lastValidSelectorModelText = selector;
}
else {
this.lastValidSelectorModelText = null;
}
}
}
getStylesheetForSelector(selectorName) {
this.selectors.forEach(selector => {
if (selector.selector === selectorName) {
return selector;
}
});
return null;
}
isValidSelector(text) {
console.log('isValidSelector:', text);
if ((text === null || text === void 0 ? void 0 : text.startsWith('node')) || (text === null || text === void 0 ? void 0 : text.startsWith('edge')) || (text === null || text === void 0 ? void 0 : text.startsWith('core'))) {
const openBracket = text.indexOf('[');
if (openBracket > -1) {
if (text.indexOf(']') < openBracket) {
return false;
}
}
const openQuote = text.indexOf('\'');
if (openQuote > -1) {
let closeQuote = text.indexOf('\'', openQuote + 1);
if (closeQuote < openQuote) {
return false;
}
}
return true;
}
return false;
}
}
CytoscapeStyleToolComponent.ɵfac = function CytoscapeStyleToolComponent_Factory(t) { return new (t || CytoscapeStyleToolComponent)(); };
CytoscapeStyleToolComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CytoscapeStyleToolComponent, selectors: [["cytoscape-style-tool"]], viewQuery: function CytoscapeStyleToolComponent_Query(rf, ctx) { if (rf & 1) {
i0.ɵɵviewQuery(_c0, 5);
i0.ɵɵviewQuery(_c1, 5);
} if (rf & 2) {
let _t;
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.styleForm = _t.first);
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.selectorDropDown = _t.first);
} }, inputs: { styles: "styles" }, outputs: { stylesChange: "stylesChange", styleSelectorChange: "styleSelectorChange" }, features: [i0.ɵɵNgOnChangesFeature], decls: 24, vars: 14, consts: [[2, "display", "flex"], [1, "style-header"], [1, "selectors-container"], ["pButton", "", "label", "\u00A0\u00A0Add\u00A0\u00A0", 1, "add-button", 3, "disabled", "click"], ["for", "selectorDropDown"], ["href", "https://js.cytoscape.org/#selectors"], ["id", "selectorDropDown", "placeholder", "Selector", "field", "selector", "dataKey", "selector", "completeOnFocus", "true", "dropdown", "true", "autofocus", "true", 1, "selector-drop-down", 3, "ngModel", "suggestions", "inputStyle", "ngModelChange", "completeMethod"], ["selectorDropDown", ""], [1, "apply-div"], ["pButton", "", "label", "Apply", 1, "apply-button", 3, "disabled", "click"], [1, "selector-span"], [4, "ngIf"], [3, "model", "formInfo", "modelChange"]], template: function CytoscapeStyleToolComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelementStart(0, "div");
i0.ɵɵelementStart(1, "div", 0);
i0.ɵɵelementStart(2, "h3", 1);
i0.ɵɵtext(3, "Edit Styles");
i0.ɵɵelementEnd();
i0.ɵɵelementEnd();
i0.ɵɵelementStart(4, "div", 2);
i0.ɵɵelementStart(5, "button", 3);
i0.ɵɵlistener("click", function CytoscapeStyleToolComponent_Template_button_click_5_listener() { return ctx.onAddSelector(); });
i0.ɵɵelementEnd();
i0.ɵɵelementStart(6, "span");
i0.ɵɵtext(7, "\u00A0\u00A0");
i0.ɵɵelementEnd();
i0.ɵɵelementStart(8, "label", 4);
i0.ɵɵelementStart(9, "a", 5);
i0.ɵɵtext(10, "Selectors");
i0.ɵɵelementEnd();
i0.ɵɵelementEnd();
i0.ɵɵelementStart(11, "p-autoComplete", 6, 7);
i0.ɵɵlistener("ngModelChange", function CytoscapeStyleToolComponent_Template_p_autoComplete_ngModelChange_11_listener($event) { return ctx.selectedStyleSheet = $event; })("completeMethod", function CytoscapeStyleToolComponent_Template_p_autoComplete_completeMethod_11_listener($event) { return ctx.search($event); })("ngModelChange", function CytoscapeStyleToolComponent_Template_p_autoComplete_ngModelChange_11_listener($event) { return ctx.onSelectorModelChange($event); });
i0.ɵɵelementEnd();
i0.ɵɵelementEnd();
i0.ɵɵelementEnd();
i0.ɵɵelement(13, "hr");
i0.ɵɵelementStart(14, "div", 8);
i0.ɵɵelementStart(15, "button", 9);
i0.ɵɵlistener("click", function CytoscapeStyleToolComponent_Template_button_click_15_listener() { return ctx.onApplyStyle(); });
i0.ɵɵelementEnd();
i0.ɵɵelementStart(16, "span", 10);
i0.ɵɵtext(17, "Selector ");
i0.ɵɵelementEnd();
i0.ɵɵelementStart(18, "span");
i0.ɵɵtext(19);
i0.ɵɵelementEnd();
i0.ɵɵelementEnd();
i0.ɵɵtemplate(20, CytoscapeStyleToolComponent_ng_container_20_Template, 6, 0, "ng-container", 11);
i0.ɵɵtemplate(21, CytoscapeStyleToolComponent_ng_container_21_Template, 2, 2, "ng-container", 11);
i0.ɵɵtemplate(22, CytoscapeStyleToolComponent_ng_container_22_Template, 2, 2, "ng-container", 11);
i0.ɵɵtemplate(23, CytoscapeStyleToolComponent_ng_container_23_Template, 2, 2, "ng-container", 11);
} if (rf & 2) {
i0.ɵɵadvance(5);
i0.ɵɵproperty("disabled", !ctx.enableAdd);
i0.ɵɵadvance(6);
i0.ɵɵstyleMap(i0.ɵɵpureFunction0(12, _c2));
i0.ɵɵproperty("ngModel", ctx.selectedStyleSheet)("suggestions", ctx.selectors)("inputStyle", i0.ɵɵpureFunction0(13, _c2));
i0.ɵɵadvance(4);
i0.ɵɵproperty("disabled", !ctx.changed);
i0.ɵɵadvance(4);
i0.ɵɵtextInterpolate(ctx.selectedStyleSheet.selector);
i0.ɵɵadvance(1);
i0.ɵɵproperty("ngIf", !ctx.selectedStyleSheet);
i0.ɵɵadvance(1);
i0.ɵɵproperty("ngIf", ctx.selectedStyleSheet == null ? null : ctx.selectedStyleSheet.selector == null ? null : ctx.selectedStyleSheet.selector.startsWith("node"));
i0.ɵɵadvance(1);
i0.ɵɵproperty("ngIf", ctx.selectedStyleSheet == null ? null : ctx.selectedStyleSheet.selector == null ? null : ctx.selectedStyleSheet.selector.startsWith("edge"));
i0.ɵɵadvance(1);
i0.ɵɵproperty("ngIf", ctx.selectedStyleSheet == null ? null : ctx.selectedStyleSheet.selector == null ? null : ctx.selectedStyleSheet.selector.startsWith("core"));
} }, directives: [i1.ButtonDirective, i2.AutoComplete, i3.NgControlStatus, i3.NgModel, i4.NgIf, i5.FluidFormComponent], styles: [".selectors-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n flex-wrap: nowrap;\n flex-grow: 0;\n }\n\n label[for=\"selectorDropDown\"][_ngcontent-%COMP%] {\n font-size: 125%;\n font-weight: bold;\n }\n\n .selector-drop-down[_ngcontent-%COMP%] {\n flex-grow: 1;\n padding: 10px;\n }\n\n .selector-span[_ngcontent-%COMP%] {\n padding: 10px;\n font-size: 125%;\n font-weight: bold;\n }\n .add-button[_ngcontent-%COMP%] {\n\n }\n .apply-button[_ngcontent-%COMP%] {\n }"] });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CytoscapeStyleToolComponent, [{
type: Component,
args: [{
selector: 'cytoscape-style-tool',
template: `
<div>
<div style="display: flex;">
<h3 class="style-header">Edit Styles</h3>
</div>
<div class="selectors-container">
<button class="add-button" pButton label=" Add "
[disabled]="!enableAdd" (click)="onAddSelector()"></button>
<span> </span>
<label for="selectorDropDown"><a href="https://js.cytoscape.org/#selectors">Selectors</a></label>
<p-autoComplete #selectorDropDown id="selectorDropDown" class="selector-drop-down"
placeholder="Selector"
[(ngModel)]="selectedStyleSheet"
[suggestions]="selectors"
field="selector"
dataKey="selector"
completeOnFocus="true"
dropdown="true"
autofocus="true"
[style]="{'width':'70%'}"
[inputStyle]="{'width':'70%'}"
(completeMethod)="search($event)"
(ngModelChange)="onSelectorModelChange($event)">
</p-autoComplete>
</div>
</div>
<hr>
<div class="apply-div">
<button class="apply-button" pButton label="Apply" [disabled]="!changed" (click)="onApplyStyle()"></button>
<span class="selector-span">Selector </span><span>{{selectedStyleSheet.selector}}</span>
</div>
<ng-container *ngIf="!selectedStyleSheet">
<div> Please select a <a href="https://js.cytoscape.org/#selectors">selector</a> above or type a selector name
and click "Add" to create a new stylesheet for that selector.</div>
</ng-container>
<ng-container *ngIf="selectedStyleSheet?.selector?.startsWith('node')">
<cyng-fluid-form [model]="selectedStyleSheet.style"
[formInfo]="nodeFormInfo"
(modelChange)="onFormModelChange()">
</cyng-fluid-form>
</ng-container>
<ng-container *ngIf="selectedStyleSheet?.selector?.startsWith('edge')">
<cyng-fluid-form [model]="selectedStyleSheet.style"
[formInfo]="edgeFormInfo"
(modelChange)="onFormModelChange()">
</cyng-fluid-form>
</ng-container>
<ng-container *ngIf="selectedStyleSheet?.selector?.startsWith('core')">
<cyng-fluid-form [model]="selectedStyleSheet.style"
[formInfo]="coreFormInfo"
(modelChange)="onFormModelChange()">
</cyng-fluid-form>
</ng-container>
`,
styles: [`
.selectors-container {
display: flex;
align-items: baseline;
flex-wrap: nowrap;
flex-grow: 0;
}
label[for="selectorDropDown"] {
font-size: 125%;
font-weight: bold;
}
.selector-drop-down {
flex-grow: 1;
padding: 10px;
}
.selector-span {
padding: 10px;
font-size: 125%;
font-weight: bold;
}
.add-button {
}
.apply-button {
}
`]
}]
}], function () { return []; }, { styleForm: [{
type: ViewChild,
args: ['styleForm']
}], selectorDropDown: [{
type: ViewChild,
args: ['selectorDropDown']
}], styles: [{
type: Input
}], stylesChange: [{
type: Output
}], styleSelectorChange: [{
type: Output
}] }); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3l0b3NjYXBlLXN0eWxlLXRvb2wuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY3l0b3NjYXBlLWFuZ3VsYXIvc3JjL2xpYi9jeXRvc2NhcGUtc3R5bGUtdG9vbC9jeXRvc2NhcGUtc3R5bGUtdG9vbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFtQyxTQUFTLEVBQUUsWUFBWSxFQUFnQixLQUFLLEVBQXFCLE1BQU0sRUFBaUIsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBRWxLLE9BQU8sRUFBMkIsUUFBUSxFQUFFLE1BQU0seUJBQXlCLENBQUE7QUFDM0UsT0FBTyxFQUNMLHVCQUF1QixFQUN2Qix3QkFBd0IsRUFDeEIsd0JBQXdCLEVBQ3hCLGNBQWMsRUFDZixNQUFNLGdCQUFnQixDQUFBOzs7Ozs7Ozs7O0lBb0NuQiw2QkFBMEM7SUFDeEMsMkJBQUs7SUFBQyxpQ0FBZ0I7SUFBQSw0QkFBOEM7SUFBQSx3QkFBUTtJQUFBLGlCQUFJO0lBQUMsOEdBQ2Q7SUFBQSxpQkFBTTtJQUMzRSwwQkFBZTs7OztJQUNmLDZCQUF1RTtJQUNyRSwyQ0FFcUQ7SUFBcEMscU9BQW1DO0lBQ3BELGlCQUFrQjtJQUNwQiwwQkFBZTs7O0lBSkksZUFBa0M7SUFBbEMsdURBQWtDLGlDQUFBOzs7O0lBS3JELDZCQUF1RTtJQUNyRSwyQ0FFcUQ7SUFBcEMscU9BQW1DO0lBQ3BELGlCQUFrQjtJQUNwQiwwQkFBZTs7O0lBSkksZUFBa0M7SUFBbEMsdURBQWtDLGlDQUFBOzs7O0lBS3JELDZCQUF1RTtJQUNyRSwyQ0FFcUQ7SUFBcEMsc09BQW1DO0lBQ3BELGlCQUFrQjtJQUNwQiwwQkFBZTs7O0lBSkksZUFBa0M7SUFBbEMsdURBQWtDLGlDQUFBOzs7QUFvQ3pELE1BQU0sT0FBTywyQkFBMkI7SUE2QnRDO1FBeEJBLGNBQVMsR0FBRyxLQUFLLENBQUE7UUFXakIs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Ozs7R0E0QlIsQ0FBQzthQUNIO3NDQUV5QixTQUFTO2tCQUFoQyxTQUFTO21CQUFDLFdBQVc7WUFDUyxnQkFBZ0I7a0JBQTlDLFNBQVM7bUJBQUMsa0JBQWtCO1lBT3pCLE1BQU07a0JBRFQsS0FBSztZQVFOLFlBQVk7a0JBRFgsTUFBTTtZQUlQLG1CQUFtQjtrQkFEbEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFmdGVyVmlld0NoZWNrZWQsIEFmdGVyVmlld0luaXQsIENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBIb3N0TGlzdGVuZXIsIElucHV0LCBPbkNoYW5nZXMsIE9uSW5pdCwgT3V0cHV0LCBTaW1wbGVDaGFuZ2VzLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJ1xuaW1wb3J0IHsgU3R5bGVzaGVldCwgU3R5bGVzaGVldFN0eWxlIH0gZnJvbSAnY3l0b3NjYXBlJ1xuaW1wb3J0IHsgRmllbGRJbmZvLCBGaWVsZHNldEluZm8sIEZvcm1JbmZvIH0gZnJvbSAnLi4vZmx1aWQtZm9ybS9mb3JtLWluZm8nXG5pbXBvcnQge1xuICBjcmVhdGVTdHlsZUNvcmVGb3JtSW5mbyxcbiAgY3JlYXRlU3R5bGVFZGdlRmllbGRTZXRzLFxuICBjcmVhdGVTdHlsZU5vZGVGaWVsZFNldHMsXG4gIFN0eWxlc2hlZXRJbXBsXG59IGZyb20gJy4uL3N0eWxlL3N0eWxlJ1xuXG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2N5dG9zY2FwZS1zdHlsZS10b29sJyxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2PlxuICAgICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7XCI+XG4gICAgICAgIDxoMyBjbGFzcz1cInN0eWxlLWhlYWRlclwiPkVkaXQgU3R5bGVzPC9oMz5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cInNlbGVjdG9ycy1jb250YWluZXJcIj5cbiAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImFkZC1idXR0b25cIiBwQnV0dG9uIGxhYmVsPVwiJm5ic3A7Jm5ic3A7QWRkJm5ic3A7Jm5ic3A7XCJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWVuYWJsZUFkZFwiIChjbGljayk9XCJvbkFkZFNlbGVjdG9yKClcIj48L2J1dHRvbj5cbiAgICAgICAgPHNwYW4+Jm5ic3A7Jm5ic3A7PC9zcGFuPlxuICAgICAgICA8bGFiZWwgZm9yPVwic2VsZWN0b3JEcm9wRG93blwiPjxhIGhyZWY9XCJodHRwczovL2pzLmN5dG9zY2FwZS5vcmcvI3NlbGVjdG9yc1wiPlNlbGVjdG9yczwvYT48L2xhYmVsPlxuICAgICAgICA8cC1hdXRvQ29tcGxldGUgI3NlbGVjdG9yRHJvcERvd24gaWQ9XCJzZWxlY3RvckRyb3BEb3duXCIgY2xhc3M9XCJzZWxlY3Rvci1kcm9wLWRvd25cIlxuICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJTZWxlY3RvclwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cInNlbGVjdGVkU3R5bGVTaGVldFwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbc3VnZ2VzdGlvbnNdPVwic2VsZWN0b3JzXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkPVwic2VsZWN0b3JcIlxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YUtleT1cInNlbGVjdG9yXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBsZXRlT25Gb2N1cz1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgZHJvcGRvd249XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9mb2N1cz1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW3N0eWxlXT1cInsnd2lkdGgnOic3MCUnfVwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbaW5wdXRTdHlsZV09XCJ7J3dpZHRoJzonNzAlJ31cIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGNvbXBsZXRlTWV0aG9kKT1cInNlYXJjaCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uU2VsZWN0b3JNb2RlbENoYW5nZSgkZXZlbnQpXCI+XG4gICAgICAgIDwvcC1hdXRvQ29tcGxldGU+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8aHI+XG4gICAgPGRpdiBjbGFzcz1cImFwcGx5LWRpdlwiPlxuICAgICAgPGJ1dHRvbiBjbGFzcz1cImFwcGx5LWJ1dHRvblwiIHBCdXR0b24gbGFiZWw9XCJBcHBseVwiIFtkaXNhYmxlZF09XCIhY2hhbmdlZFwiIChjbGljayk9XCJvbkFwcGx5U3R5bGUoKVwiPjwvYnV0dG9uPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzZWxlY3Rvci1zcGFuXCI+U2VsZWN0b3IgPC9zcGFuPjxzcGFuPnt7c2VsZWN0ZWRTdHlsZVNoZWV0LnNlbGVjdG9yfX08L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzZWxlY3RlZFN0eWxlU2hlZXRcIj5cbiAgICAgIDxkaXY+IFBsZWFzZSBzZWxlY3QgYSA8YSBocmVmPVwiaHR0cHM6Ly9qcy5jeXRvc2NhcGUub3JnLyNzZWxlY3RvcnNcIj5zZWxlY3RvcjwvYT4gYWJvdmUgb3IgdHlwZSBhIHNlbGVjdG9yIG5hbWVcbiAgICAgICAgICAgIGFuZCBjbGljayBcIkFkZFwiIHRvIGNyZWF0ZSBhIG5ldyBzdHlsZXNoZWV0IGZvciB0aGF0IHNlbGVjdG9yLjwvZGl2PlxuICAgIDwvbmctY29udGFpbmVyPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJzZWxlY3RlZFN0eWxlU2hlZXQ/LnNlbGVjdG9yPy5zdGFydHNXaXRoKCdub2RlJylcIj5cbiAgICAgIDxjeW5nLWZsdWlkLWZvcm0gW21vZGVsXT1cInNlbGVjdGVkU3R5bGVTaGVldC5zdHlsZVwiXG4gICAgICAgICAgICAgICAgICAgICAgIFtmb3JtSW5mb109XCJub2RlRm9ybUluZm9cIlxuICAgICAgICAgICAgICAgICAgICAgICAobW9kZWxDaGFuZ2UpPVwib25Gb3JtTW9kZWxDaGFuZ2UoKVwiPlxuICAgICAgPC9jeW5nLWZsdWlkLWZvcm0+XG4gICAgPC9uZy1jb250YWluZXI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNlbGVjdGVkU3R5bGVTaGVldD8uc2VsZWN0b3I/LnN0YXJ0c1dpdGgoJ2VkZ2UnKVwiPlxuICAgICAgPGN5bmctZmx1aWQtZm9ybSBbbW9kZWxdPVwic2VsZWN0ZWRTdHlsZVNoZWV0LnN0eWxlXCJcbiAgICAgICAgICAgICAgICAgICAgICAgW2Zvcm1JbmZvXT1cImVkZ2VGb3JtSW5mb1wiXG4gICAgICAgICAgICAgICAgICAgICAgIChtb2RlbENoYW5nZSk9XCJvbkZvcm1Nb2RlbENoYW5nZSgpXCI+XG4gICAgICA8L2N5bmctZmx1aWQtZm9ybT5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwic2VsZWN0ZWRTdHlsZVNoZWV0Py5zZWxlY3Rvcj8uc3RhcnRzV2l0aCgnY29yZScpXCI+XG4gICAgICA8Y3luZy1mbHVpZC1mb3JtIFttb2RlbF09XCJzZWxlY3RlZFN0eWxlU2hlZXQuc3R5bGVcIlxuICAgICAgICAgICAgICAgICAgICAgICBbZm9ybUluZm9dPVwiY29yZUZvcm1JbmZvXCJcbiAgICAgICAgICAgICAgICAgICAgICAgKG1vZGVsQ2hhbmdlKT1cIm9uRm9ybU1vZGVsQ2hhbmdlKClcIj5cbiAgICAgIDwvY3luZy1mbHVpZC1mb3JtPlxuICAgIDwvbmctY29udGFpbmVyPlxuICBgLFxuICBzdHlsZXM6IFtgXG4gICAgLnNlbGVjdG9ycy1jb250YWluZXIge1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIGFsaWduLWl0ZW1zOiBiYXNlbGluZTtcbiAgICAgIGZsZXgtd3JhcDogbm93cmFwO1xuICAgICAgZmxleC1ncm93OiAwO1xuICAgIH1cblxuICAgIGxhYmVsW2Zvcj1cInNlbGVjdG9yRHJvcERvd25cIl0ge1xuICAgICAgZm9udC1zaXplOiAxMjUlO1xuICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XG4gICAgfVxuXG4gICAgLnNlbGVjdG9yLWRyb3AtZG93biB7XG4gICAgICBmbGV4LWdyb3c6IDE7XG4gICAgICBwYWRkaW5nOiAxMHB4O1xuICAgIH1cblxuICAgIC5zZWxlY3Rvci1zcGFuIHtcbiAgICAgIHBhZGRpbmc6IDEwcHg7XG4gICAgICBmb250LXNpemU6IDEyNSU7XG4gICAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICB9XG4gICAgLmFkZC1idXR0b24ge1xuXG4gICAgfVxuICAgIC5hcHBseS1idXR0b24ge1xuICAgIH1cbiAgYF1cbn0pXG5leHBvcnQgY2xhc3MgQ3l0b3NjYXBlU3R5bGVUb29sQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIEFmdGVyVmlld0luaXQsIEFmdGVyVmlld0NoZWNrZWQge1xuICBAVmlld0NoaWxkKCdzdHlsZUZvcm0nKSBzdHlsZUZvcm07XG4gIEBWaWV3Q2hpbGQoJ3NlbGVjdG9yRHJvcERvd24nKSBzZWxlY3RvckRyb3BEb3duO1xuXG4gIF9zdHlsZXM6IFN0eWxlc2hlZXRTdHlsZVtdXG4gIGVuYWJsZUFkZCA9IGZhbHNlXG4gIHByaXZhdGUgbGFzdFZhbGlkU2VsZWN0b3JNb2RlbFRleHQ6IHN0cmluZ1xuXG4gIEBJbnB1dCgpXG4gIGdldCBzdHlsZXMoKSA6IFN0eWxlc2hlZXRTdHlsZVtdIHtcbiAgICByZXR1cm4gdGhpcy5fc3R5bGVzXG4gIH1cbiAgc2V0IHN0eWxlcyhzdHlsZXM6IFN0eWxlc2hlZXRTdHlsZVtdKSB7XG4gICAgdGhpcy5fc3R5bGVzID0gc3R5bGVzXG4gIH1cbiAgQE91dHB1dCgpXG4gIHN0eWxlc0NoYW5nZTpFdmVudEVtaXR0ZXI8U3R5bGVzaGVldFN0eWxlW10+ID0gbmV3IEV2ZW50RW1pdHRlcjxTdHlsZXNoZWV0U3R5bGVbXT4oKVxuXG4gIEBPdXRwdXQoKVxuICBzdHlsZVNlbGVjdG9yQ2hhbmdlOiBFdmVudEVtaXR0ZXI8c3RyaW5nPiA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpXG5cbiAgbm9kZUZvcm1JbmZvOiBGb3JtSW5mb1xuICBlZGdlRm9ybUluZm86IEZvcm1JbmZvXG4gIGNvcmVGb3JtSW5mbzogRm9ybUluZm9cblxuICBzZWxlY3RlZFN0eWxlU2hlZXQ6IFN0eWxlc2hlZXRTdHlsZVxuICBzZWxlY3RvcnM6IFN0eWxlc2hlZXRTdHlsZVtdXG4gIGNoYW5nZWQgPSBmYWxzZVxuXG4gIGNvbnN0cnVjdG9yKCkge1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5jb3JlRm9ybUluZm8gPSBjcmVhdGVTdHlsZUNvcmVGb3JtSW5mbygpXG4gICAgdGhpcy5ub2RlRm9ybUluZm8gPSBuZXcgRm9ybUluZm8oJ05vZGUnLCBjcmVhdGVTdHlsZU5vZGVGaWVsZFNldHMoKSlcbiAgICB0aGlzLmVkZ2VGb3JtSW5mbyA9IG5ldyBGb3JtSW5mbygnRWRnZScsIGNyZWF0ZVN0eWxlRWRnZUZpZWxkU2V0cygpKVxuICAgIGlmICghdGhpcy5zdHlsZXMpIHtcbiAgICAgIHRoaXMuc3R5bGVzID0gW25ldyBTdHlsZXNoZWV0SW1wbCgpXVxuICAgIH1cbiAgICB0aGlzLnNldFNlbGVjdG9yc0Zyb21TdHlsZXMobnVsbClcbiAgICB0aGlzLnNlbGVjdGVkU3R5bGVTaGVldCA9IHRoaXMuc2VsZWN0b3JzWzBdXG4gICAgY29uc29sZS5sb2coYHRoaXMuc2VsZWN0b3JzLmxlbmd0aDpgLCB0aGlzLnNlbGVjdG9ycy5sZW5ndGgpXG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgY29uc29sZS5sb2coJ25nT25DaGFuZ2VzIHN0eWxlIGNoYW5nZXM6JywgSlNPTi5zdHJpbmdpZnkoY2hhbmdlcykpXG4gICAgaWYgKGNoYW5nZXNbJ3N0eWxlcyddKSB7XG4gICAgICB0aGlzLnNldFNlbGVjdG9yc0Zyb21TdHlsZXMobnVsbClcbiAgICAgIHRoaXMuc2VsZWN0ZWRTdHlsZVNoZWV0ID0gdGhpcy5zZWxlY3RvcnNbMF1cbiAgICAgIGNvbnNvbGUubG9nKGBzdHlsZXMgdXBkYXRlZCB0aGlzLnNlbGVjdG9ycy5sZW5ndGg6YCwgdGhpcy5zZWxlY3RvcnMubGVuZ3RoKVxuICAgIH1cbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICAvLyBjb25zb2xlLmRlYnVnKFwibmdBZnRlclZpZXdJbml0XCIpXG4gIH1cblxuICBuZ0FmdGVyVmlld0NoZWNrZWQoKTogdm9pZCB7XG4gICAgLy8gY29uc29sZS5kZWJ1ZyhcIm5nQWZ0ZXJWaWV3Q2hlY2tlZFwiKVxuICB9XG5cbiAgb25Gb3JtTW9kZWxDaGFuZ2UoKSB7XG4gICAgY29uc29sZS5sb2coJ29uRm9ybU1vZGVsQ2hhbmdlJylcbiAgICB0aGlzLmNoYW5nZWQgPSB0cnVlXG4gIH1cblxuICBvbkFwcGx5U3R5bGUoKSB7XG4gICAgdGhpcy5jaGFuZ2VkID0gZmFsc2VcbiAgICB0aGlzLnN0eWxlc0NoYW5nZS5lbWl0KHRoaXMuc3R5bGVzKVxuICB9XG5cbiAgc2VhcmNoKGV2ZW50KSB7XG4gICAgbGV0IHNlYXJjaFN0cmluZyA9IGV2ZW50LnF1ZXJ5XG4gICAgdGhpcy5zZXRTZWxlY3RvcnNGcm9tU3R5bGVzKHNlYXJjaFN0cmluZylcbiAgfVxuXG4gIHByaXZhdGUgc2V0U2VsZWN0b3JzRnJvbVN0eWxlcyhzZWFyY2hTdHJpbmc6IHN0cmluZykge1xuICAgIHRoaXMuc2VsZWN0b3JzID0gdGhpcy5zdHlsZXMuZmlsdGVyKChzdHlsZXNoZWV0OiBTdHlsZXNoZWV0U3R5bGUpID0+IHtcbiAgICAgIHJldHVybiBzZWFyY2hTdHJpbmcgPyBzdHlsZXNoZWV0LnNlbGVjdG9yLmluY2x1ZGVzKHNlYXJjaFN0cmluZykgOiB0cnVlXG4gICAgfSlcbiAgfVxuXG5cbiAgb25BZGRTZWxlY3RvcigpIHtcbiAgICBjb25zdCBuZXdTdHlsZXNoZWV0U3R5bGU6IFN0eWxlc2hlZXRTdHlsZSA9IG5ldyBTdHlsZXNoZWV0SW1wbCgpXG4gICAgbmV3U3R5bGVzaGVldFN0eWxlLnNlbGVjdG9yID0gdGhpcy5sYXN0VmFsaWRTZWxlY3Rvck1vZGVsVGV4dFxuICAgIGNvbnNvbGUubG9nKCdBZGRpbmcgbmV3IHN0eWxlIHdpdGggc2VsZWN0b3I6JywgdGhpcy5sYXN0VmFsaWRTZWxlY3Rvck1vZGVsVGV4dClcbiAgICB0aGlzLnN0eWxlcy51bnNoaWZ0KG5ld1N0eWxlc2hlZXRTdHlsZSlcbiAgICB0aGlzLnNlbGVjdGVkU3R5bGVTaGVldCA9IG5ld1N0eWxlc2hlZXRTdHlsZVxuICB9XG5cbiAgLypcbiAgICogVGhlIHBhcmFtIGNhbiBiZSBhIHNlbGVjdG9yIG9iamVjdCB3aGVuIHRoZSB1c2VyIHNlbGVjdHMgYSBzdHlsZXNoZWV0IGVudHJ5IGZyb20gdGhlIGRyb3Bkb3duIGFuZCBjaGFuZ2VzIHRoZVxuICAgKiBzZWxlY3Rpb24gKHdoaWNoIHdpbGwgZmlyZSBhIHNlbGVjdGlvbiBjaGFuZ2UgdG8gbGV0IHRoZSBncmFwaCwgc2F5LCBmb2N1cyBvbiB0aGUgc2VsZWN0ZWQgbm9kZSkuXG4gICAqIG9yIHRoZSBwYXJhbSBpcyB0ZXh0IGlmIHRoZSB1c2VyIGlzIGp1c3QgdHlwaW5nIGluIHRoZSBmaWVsZCwgd2hpY2ggZG9lbnMndCBjaGFuZ2UgdGhlIHNlbGVjdG9yIHVudGwgdGhlIHVzZXJcbiAgICogY2xpY2tzIEFkZC5cbiAgICovXG4gIG9uU2VsZWN0b3JNb2RlbENoYW5nZShwYXJhbTogYW55KSB7XG4gICAgY29uc29sZS5sb2coYHNlbGVjdG9yTW9kZWxDaGFuZ2VkOiR7SlNPTi5zdHJpbmdpZnkocGFyYW0pfWApXG4gICAgY29uc3Qgc2VsZWN0b3IgPSBwYXJhbS5zZWxlY3RvciA/IHBhcmFtLnNlbGVjdG9yIDogcGFyYW1cbiAgICBjb25zdCBzdHlsZXNoZWV0ID0gcGFyYW0uc2VsZWN0b3IgPyBwYXJhbSA6IHRoaXMuZ2V0U3R5bGVzaGVldEZvclNlbGVjdG9yKHNlbGVjdG9yKVxuICAgIGlmIChzdHlsZXNoZWV0KSB7XG4gICAgICBpZiAodGhpcy5jaGFuZ2VkKSB7XG4gICAgICAgIHRoaXMub25BcHBseVN0eWxlKClcbiAgICAgIH1cbiAgICAgIHRoaXMuc3R5bGVTZWxlY3RvckNoYW5nZS5lbWl0KHNlbGVjdG9yKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmVuYWJsZUFkZCA9ICB0aGlzLmlzVmFsaWRTZWxlY3RvcihzZWxlY3RvcilcbiAgICAgIGlmICh0aGlzLmVuYWJsZUFkZCkge1xuICAgICAgICB0aGlzLmxhc3RWYWxpZFNlbGVjdG9yTW9kZWxUZXh0ID0gc2VsZWN0b3JcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubGFzdFZhbGlkU2VsZWN0b3JNb2RlbFRleHQgPSBudWxsXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0U3R5bGVzaGVldEZvclNlbGVjdG9yKHNlbGVjdG9yTmFtZSk6IFN0eWxlc2hlZXQge1xuICAgIHRoaXMuc2VsZWN0b3JzLmZvckVhY2goc2VsZWN0b3IgPT4ge1xuICAgICAgaWYgKHNlbGVjdG9yLnNlbGVjdG9yID09PSBzZWxlY3Rvck5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHNlbGVjdG9yXG4gICAgICB9XG4gICAgfSlcbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgaXNWYWxpZFNlbGVjdG9yKHRleHQ6IHN0cmluZykge1xuICAgIGNvbnNvbGUubG9nKCdpc1ZhbGlkU2VsZWN0b3I6JywgdGV4dClcbiAgICBpZiAodGV4dD8uc3RhcnRzV2l0aCgnbm9kZScpIHx8IHRleHQ/LnN0YXJ0c1dpdGgoJ2VkZ2UnKSB8fCB0ZXh0Py5zdGFydHNXaXRoKCdjb3JlJykpIHtcbiAgICAgIGNvbnN0IG9wZW5CcmFja2V0ID0gdGV4dC5pbmRleE9mKCdbJylcbiAgICAgIGlmIChvcGVuQnJhY2tldCA+IC0xKSB7XG4gICAgICAgIGlmICh0ZXh0LmluZGV4T2YoJ10nKSA8IG9wZW5CcmFja2V0KSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGNvbnN0IG9wZW5RdW90ZSA9IHRleHQuaW5kZXhPZignXFwnJylcbiAgICAgIGlmIChvcGVuUXVvdGUgPiAtMSkge1xuICAgICAgICBsZXQgY2xvc2VRdW90ZSA9IHRleHQuaW5kZXhPZignXFwnJywgb3BlblF1b3RlICsxKVxuICAgICAgICBpZiAoY2xvc2VRdW90ZSA8IG9wZW5RdW90ZSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuIl19