UNPKG

cytoscape-angular

Version:
345 lines (341 loc) 35.6 kB
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="&nbsp;&nbsp;Add&nbsp;&nbsp;" [disabled]="!enableAdd" (click)="onAddSelector()"></button> <span>&nbsp;&nbsp;</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