UNPKG

cytoscape-angular-ng17

Version:
319 lines 32.1 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 "@angular/common"; import * as i2 from "@angular/forms"; import * as i3 from "primeng/button"; import * as i4 from "primeng/autocomplete"; import * as i5 from "../fluid-form/fluid-form.component"; export class CytoscapeStyleToolComponent { styleForm; selectorDropDown; _styles; enableAdd = false; lastValidSelectorModelText; get styles() { return this._styles; } set styles(styles) { this._styles = styles; } stylesChange = new EventEmitter(); styleSelectorChange = new EventEmitter(); nodeFormInfo; edgeFormInfo; coreFormInfo; selectedStyleSheet; selectors; changed = false; constructor() { } 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); if (this.selectors && this.selectors.length > 0) { 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); if (this.selectors && this.selectors.length > 0) { 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 = undefined; } } } getStylesheetForSelector(selectorName) { const stylesheet = this.selectors?.find((selector) => selector.selector === selectorName); return stylesheet; } isValidSelector(text) { console.log('isValidSelector:', text); if (text?.startsWith('node') || text?.startsWith('edge') || 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; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.3", ngImport: i0, type: CytoscapeStyleToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.3", type: CytoscapeStyleToolComponent, selector: "cytoscape-style-tool", inputs: { styles: "styles" }, outputs: { stylesChange: "stylesChange", styleSelectorChange: "styleSelectorChange" }, viewQueries: [{ propertyName: "styleForm", first: true, predicate: ["styleForm"], descendants: true }, { propertyName: "selectorDropDown", first: true, predicate: ["selectorDropDown"], descendants: true }], usesOnChanges: true, ngImport: i0, 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> `, isInline: true, styles: [".selectors-container{display:flex;align-items:baseline;flex-wrap:nowrap;flex-grow:0}label[for=selectorDropDown]{font-size:125%;font-weight:700}.selector-drop-down{flex-grow:1;padding:10px}.selector-span{padding:10px;font-size:125%;font-weight:700}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading"] }, { kind: "component", type: i4.AutoComplete, selector: "p-autoComplete", inputs: ["minLength", "delay", "style", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "disabled", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "maxlength", "name", "required", "size", "appendTo", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "field", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "itemSize", "optionLabel", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover"], outputs: ["completeMethod", "onSelect", "onUnselect", "onFocus", "onBlur", "onDropdownClick", "onClear", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "component", type: i5.FluidFormComponent, selector: "cyng-fluid-form", inputs: ["model", "modelProperty", "formInfo"], outputs: ["modelChange"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.3", ngImport: i0, type: CytoscapeStyleToolComponent, decorators: [{ 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:700}.selector-drop-down{flex-grow:1;padding:10px}.selector-span{padding:10px;font-size:125%;font-weight:700}\n"] }] }], ctorParameters: () => [], propDecorators: { styleForm: [{ type: ViewChild, args: ['styleForm'] }], selectorDropDown: [{ type: ViewChild, args: ['selectorDropDown'] }], styles: [{ type: Input }], stylesChange: [{ type: Output }], styleSelectorChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3l0b3NjYXBlLXN0eWxlLXRvb2wuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY3l0b3NjYXBlLWFuZ3VsYXIvc3JjL2xpYi9jeXRvc2NhcGUtc3R5bGUtdG9vbC9jeXRvc2NhcGUtc3R5bGUtdG9vbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUdMLFNBQVMsRUFDVCxZQUFZLEVBRVosS0FBSyxFQUdMLE1BQU0sRUFFTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUEyQixRQUFRLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLHdCQUF3QixFQUN4Qix3QkFBd0IsRUFDeEIsY0FBYyxHQUNmLE1BQU0sZ0JBQWdCLENBQUM7Ozs7Ozs7QUFxSHhCLE1BQU0sT0FBTywyQkFBMkI7SUFHZCxTQUFTLENBQUM7SUFDSCxnQkFBZ0IsQ0FBQztJQUVoRCxPQUFPLENBQWdDO0lBQ3ZDLFNBQVMsR0FBRyxLQUFLLENBQUM7SUFDViwwQkFBMEIsQ0FBcUI7SUFFdkQsSUFDSSxNQUFNO1FBQ1IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3RCLENBQUM7SUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFxQztRQUM5QyxJQUFJLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztJQUN4QixDQUFDO0lBRUQsWUFBWSxHQUFvQyxJQUFJLFlBQVksRUFFN0QsQ0FBQztJQUdKLG1CQUFtQixHQUF5QixJQUFJLFlBQVksRUFBVSxDQUFDO0lBRXZFLFlBQVksQ0FBWTtJQUN4QixZQUFZLENBQVk7SUFDeEIsWUFBWSxDQUFZO0lBRXhCLGtCQUFrQixDQUE4QjtJQUNoRCxTQUFTLENBQWdDO0lBQ3pDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFFaEIsZ0JBQWUsQ0FBQztJQUVoQixRQUFRO1FBQ04sSUFBSSxDQUFD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Ozs7Ozs7O0dBaUZUOzsyRkFnQ1UsMkJBQTJCO2tCQW5IdkMsU0FBUzsrQkFDRSxzQkFBc0IsWUFDdEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWlGVDt3REFtQ3VCLFNBQVM7c0JBQWhDLFNBQVM7dUJBQUMsV0FBVztnQkFDUyxnQkFBZ0I7c0JBQTlDLFNBQVM7dUJBQUMsa0JBQWtCO2dCQU96QixNQUFNO3NCQURULEtBQUs7Z0JBUU4sWUFBWTtzQkFEWCxNQUFNO2dCQU1QLG1CQUFtQjtzQkFEbEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyVmlld0NoZWNrZWQsXG4gIEFmdGVyVmlld0luaXQsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBIb3N0TGlzdGVuZXIsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzLFxuICBWaWV3Q2hpbGQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3R5bGVzaGVldCwgU3R5bGVzaGVldFN0eWxlIH0gZnJvbSAnY3l0b3NjYXBlJztcbmltcG9ydCB7IEZpZWxkSW5mbywgRmllbGRzZXRJbmZvLCBGb3JtSW5mbyB9IGZyb20gJy4uL2ZsdWlkLWZvcm0vZm9ybS1pbmZvJztcbmltcG9ydCB7XG4gIGNyZWF0ZVN0eWxlQ29yZUZvcm1JbmZvLFxuICBjcmVhdGVTdHlsZUVkZ2VGaWVsZFNldHMsXG4gIGNyZWF0ZVN0eWxlTm9kZUZpZWxkU2V0cyxcbiAgU3R5bGVzaGVldEltcGwsXG59IGZyb20gJy4uL3N0eWxlL3N0eWxlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY3l0b3NjYXBlLXN0eWxlLXRvb2wnLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXY+XG4gICAgICA8ZGl2IHN0eWxlPVwiZGlzcGxheTogZmxleDtcIj5cbiAgICAgICAgPGgzIGNsYXNzPVwic3R5bGUtaGVhZGVyXCI+RWRpdCBTdHlsZXM8L2gzPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwic2VsZWN0b3JzLWNvbnRhaW5lclwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJhZGQtYnV0dG9uXCJcbiAgICAgICAgICBwQnV0dG9uXG4gICAgICAgICAgbGFiZWw9XCImbmJzcDsmbmJzcDtBZGQmbmJzcDsmbmJzcDtcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCIhZW5hYmxlQWRkXCJcbiAgICAgICAgICAoY2xpY2spPVwib25BZGRTZWxlY3RvcigpXCJcbiAgICAgICAgPjwvYnV0dG9uPlxuICAgICAgICA8c3Bhbj4mbmJzcDsmbmJzcDs8L3NwYW4+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJzZWxlY3RvckRyb3BEb3duXCJcbiAgICAgICAgICA+PGEgaHJlZj1cImh0dHBzOi8vanMuY3l0b3NjYXBlLm9yZy8jc2VsZWN0b3JzXCI+U2VsZWN0b3JzPC9hPjwvbGFiZWxcbiAgICAgICAgPlxuICAgICAgICA8cC1hdXRvQ29tcGxldGVcbiAgICAgICAgICAjc2VsZWN0b3JEcm9wRG93blxuICAgICAgICAgIGlkPVwic2VsZWN0b3JEcm9wRG93blwiXG4gICAgICAgICAgY2xhc3M9XCJzZWxlY3Rvci1kcm9wLWRvd25cIlxuICAgICAgICAgIHBsYWNlaG9sZGVyPVwiU2VsZWN0b3JcIlxuICAgICAgICAgIFsobmdNb2RlbCldPVwic2VsZWN0ZWRTdHlsZVNoZWV0XCJcbiAgICAgICAgICBbc3VnZ2VzdGlvbnNdPVwic2VsZWN0b3JzIHx8IFtdXCJcbiAgICAgICAgICBmaWVsZD1cInNlbGVjdG9yXCJcbiAgICAgICAgICBkYXRhS2V5PVwic2VsZWN0b3JcIlxuICAgICAgICAgIFtjb21wbGV0ZU9uRm9jdXNdPVwidHJ1ZVwiXG4gICAgICAgICAgW2Ryb3Bkb3duXT1cInRydWVcIlxuICAgICAgICAgIFthdXRvZm9jdXNdPVwidHJ1ZVwiXG4gICAgICAgICAgW3N0eWxlXT1cInsgd2lkdGg6ICc3MCUnIH1cIlxuICAgICAgICAgIFtpbnB1dFN0eWxlXT1cInsgd2lkdGg6ICc3MCUnIH1cIlxuICAgICAgICAgIChjb21wbGV0ZU1ldGhvZCk9XCJzZWFyY2goJGV2ZW50KVwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25TZWxlY3Rvck1vZGVsQ2hhbmdlKCRldmVudClcIlxuICAgICAgICA+XG4gICAgICAgIDwvcC1hdXRvQ29tcGxldGU+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8aHIgLz5cbiAgICA8ZGl2IGNsYXNzPVwiYXBwbHktZGl2XCI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIGNsYXNzPVwiYXBwbHktYnV0dG9uXCJcbiAgICAgICAgcEJ1dHRvblxuICAgICAgICBsYWJlbD1cIkFwcGx5XCJcbiAgICAgICAgW2Rpc2FibGVkXT1cIiFjaGFuZ2VkXCJcbiAgICAgICAgKGNsaWNrKT1cIm9uQXBwbHlTdHlsZSgpXCJcbiAgICAgID48L2J1dHRvbj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2VsZWN0b3Itc3BhblwiPlNlbGVjdG9yIDwvc3BhblxuICAgICAgPjxzcGFuPnt7IHNlbGVjdGVkU3R5bGVTaGVldD8uc2VsZWN0b3IgfX08L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzZWxlY3RlZFN0eWxlU2hlZXRcIj5cbiAgICAgIDxkaXY+XG4gICAgICAgIFBsZWFzZSBzZWxlY3QgYVxuICAgICAgICA8YSBocmVmPVwiaHR0cHM6Ly9qcy5jeXRvc2NhcGUub3JnLyNzZWxlY3RvcnNcIj5zZWxlY3RvcjwvYT4gYWJvdmUgb3IgdHlwZVxuICAgICAgICBhIHNlbGVjdG9yIG5hbWUgYW5kIGNsaWNrIFwiQWRkXCIgdG8gY3JlYXRlIGEgbmV3IHN0eWxlc2hlZXQgZm9yIHRoYXRcbiAgICAgICAgc2VsZWN0b3IuXG4gICAgICA8L2Rpdj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwic2VsZWN0ZWRTdHlsZVNoZWV0Py5zZWxlY3Rvcj8uc3RhcnRzV2l0aCgnbm9kZScpXCI+XG4gICAgICA8Y3luZy1mbHVpZC1mb3JtXG4gICAgICAgIFttb2RlbF09XCJzZWxlY3RlZFN0eWxlU2hlZXQ/LnN0eWxlXCJcbiAgICAgICAgW2Zvcm1JbmZvXT1cIm5vZGVGb3JtSW5mb1wiXG4gICAgICAgIChtb2RlbENoYW5nZSk9XCJvbkZvcm1Nb2RlbENoYW5nZSgpXCJcbiAgICAgID5cbiAgICAgIDwvY3luZy1mbHVpZC1mb3JtPlxuICAgIDwvbmctY29udGFpbmVyPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJzZWxlY3RlZFN0eWxlU2hlZXQ/LnNlbGVjdG9yPy5zdGFydHNXaXRoKCdlZGdlJylcIj5cbiAgICAgIDxjeW5nLWZsdWlkLWZvcm1cbiAgICAgICAgW21vZGVsXT1cInNlbGVjdGVkU3R5bGVTaGVldD8uc3R5bGVcIlxuICAgICAgICBbZm9ybUluZm9dPVwiZWRnZUZvcm1JbmZvXCJcbiAgICAgICAgKG1vZGVsQ2hhbmdlKT1cIm9uRm9ybU1vZGVsQ2hhbmdlKClcIlxuICAgICAgPlxuICAgICAgPC9jeW5nLWZsdWlkLWZvcm0+XG4gICAgPC9uZy1jb250YWluZXI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNlbGVjdGVkU3R5bGVTaGVldD8uc2VsZWN0b3I/LnN0YXJ0c1dpdGgoJ2NvcmUnKVwiPlxuICAgICAgPGN5bmctZmx1aWQtZm9ybVxuICAgICAgICBbbW9kZWxdPVwic2VsZWN0ZWRTdHlsZVNoZWV0Py5zdHlsZVwiXG4gICAgICAgIFtmb3JtSW5mb109XCJjb3JlRm9ybUluZm9cIlxuICAgICAgICAobW9kZWxDaGFuZ2UpPVwib25Gb3JtTW9kZWxDaGFuZ2UoKVwiXG4gICAgICA+XG4gICAgICA8L2N5bmctZmx1aWQtZm9ybT5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgYCxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgLnNlbGVjdG9ycy1jb250YWluZXIge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBhbGlnbi1pdGVtczogYmFzZWxpbmU7XG4gICAgICAgIGZsZXgtd3JhcDogbm93cmFwO1xuICAgICAgICBmbGV4LWdyb3c6IDA7XG4gICAgICB9XG5cbiAgICAgIGxhYmVsW2Zvcj0nc2VsZWN0b3JEcm9wRG93biddIHtcbiAgICAgICAgZm9udC1zaXplOiAxMjUlO1xuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICAgIH1cblxuICAgICAgLnNlbGVjdG9yLWRyb3AtZG93biB7XG4gICAgICAgIGZsZXgtZ3JvdzogMTtcbiAgICAgICAgcGFkZGluZzogMTBweDtcbiAgICAgIH1cblxuICAgICAgLnNlbGVjdG9yLXNwYW4ge1xuICAgICAgICBwYWRkaW5nOiAxMHB4O1xuICAgICAgICBmb250LXNpemU6IDEyNSU7XG4gICAgICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xuICAgICAgfVxuICAgICAgLmFkZC1idXR0b24ge1xuICAgICAgfVxuICAgICAgLmFwcGx5LWJ1dHRvbiB7XG4gICAgICB9XG4gICAgYCxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgQ3l0b3NjYXBlU3R5bGVUb29sQ29tcG9uZW50XG4gIGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIEFmdGVyVmlld0luaXQsIEFmdGVyVmlld0NoZWNrZWRcbntcbiAgQFZpZXdDaGlsZCgnc3R5bGVGb3JtJykgc3R5bGVGb3JtO1xuICBAVmlld0NoaWxkKCdzZWxlY3RvckRyb3BEb3duJykgc2VsZWN0b3JEcm9wRG93bjtcblxuICBfc3R5bGVzOiBTdHlsZXNoZWV0U3R5bGVbXSB8IHVuZGVmaW5lZDtcbiAgZW5hYmxlQWRkID0gZmFsc2U7XG4gIHByaXZhdGUgbGFzdFZhbGlkU2VsZWN0b3JNb2RlbFRleHQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBASW5wdXQoKVxuICBnZXQgc3R5bGVzKCk6IFN0eWxlc2hlZXRTdHlsZVtdIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fc3R5bGVzO1xuICB9XG4gIHNldCBzdHlsZXMoc3R5bGVzOiBTdHlsZXNoZWV0U3R5bGVbXSB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMuX3N0eWxlcyA9IHN0eWxlcztcbiAgfVxuICBAT3V0cHV0KClcbiAgc3R5bGVzQ2hhbmdlOiBFdmVudEVtaXR0ZXI8U3R5bGVzaGVldFN0eWxlW10+ID0gbmV3IEV2ZW50RW1pdHRlcjxcbiAgICBTdHlsZXNoZWV0U3R5bGVbXVxuICA+KCk7XG5cbiAgQE91dHB1dCgpXG4gIHN0eWxlU2VsZWN0b3JDaGFuZ2U6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cbiAgbm9kZUZvcm1JbmZvITogRm9ybUluZm87XG4gIGVkZ2VGb3JtSW5mbyE6IEZvcm1JbmZvO1xuICBjb3JlRm9ybUluZm8hOiBGb3JtSW5mbztcblxuICBzZWxlY3RlZFN0eWxlU2hlZXQ6IFN0eWxlc2hlZXRTdHlsZSB8IHVuZGVmaW5lZDtcbiAgc2VsZWN0b3JzOiBTdHlsZXNoZWV0U3R5bGVbXSB8IHVuZGVmaW5lZDtcbiAgY2hhbmdlZCA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKCkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmNvcmVGb3JtSW5mbyA9IGNyZWF0ZVN0eWxlQ29yZUZvcm1JbmZvKCk7XG4gICAgdGhpcy5ub2RlRm9ybUluZm8gPSBuZXcgRm9ybUluZm8oJ05vZGUnLCBjcmVhdGVTdHlsZU5vZGVGaWVsZFNldHMoKSk7XG4gICAgdGhpcy5lZGdlRm9ybUluZm8gPSBuZXcgRm9ybUluZm8oJ0VkZ2UnLCBjcmVhdGVTdHlsZUVkZ2VGaWVsZFNldHMoKSk7XG4gICAgaWYgKCF0aGlzLnN0eWxlcykge1xuICAgICAgdGhpcy5zdHlsZXMgPSBbbmV3IFN0eWxlc2hlZXRJbXBsKCldO1xuICAgIH1cbiAgICB0aGlzLnNldFNlbGVjdG9yc0Zyb21TdHlsZXMobnVsbCk7XG4gICAgaWYgKHRoaXMuc2VsZWN0b3JzICYmIHRoaXMuc2VsZWN0b3JzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWRTdHlsZVNoZWV0ID0gdGhpcy5zZWxlY3RvcnNbMF07XG4gICAgICBjb25zb2xlLmxvZyhgdGhpcy5zZWxlY3RvcnMubGVuZ3RoOmAsIHRoaXMuc2VsZWN0b3JzLmxlbmd0aCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKCduZ09uQ2hhbmdlcyBzdHlsZSBjaGFuZ2VzOicsIEpTT04uc3RyaW5naWZ5KGNoYW5nZXMpKTtcbiAgICBpZiAoY2hhbmdlc1snc3R5bGVzJ10pIHtcbiAgICAgIHRoaXMuc2V0U2VsZWN0b3JzRnJvbVN0eWxlcyhudWxsKTtcbiAgICAgIGlmICh0aGlzLnNlbGVjdG9ycyAmJiB0aGlzLnNlbGVjdG9ycy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuc2VsZWN0ZWRTdHlsZVNoZWV0ID0gdGhpcy5zZWxlY3RvcnNbMF07XG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGBzdHlsZXMgdXBkYXRlZCB0aGlzLnNlbGVjdG9ycy5sZW5ndGg6YCxcbiAgICAgICAgICB0aGlzLnNlbGVjdG9ycy5sZW5ndGhcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgLy8gY29uc29sZS5kZWJ1ZyhcIm5nQWZ0ZXJWaWV3SW5pdFwiKVxuICB9XG5cbiAgbmdBZnRlclZpZXdDaGVja2VkKCk6IHZvaWQge1xuICAgIC8vIGNvbnNvbGUuZGVidWcoXCJuZ0FmdGVyVmlld0NoZWNrZWRcIilcbiAgfVxuXG4gIG9uRm9ybU1vZGVsQ2hhbmdlKCkge1xuICAgIGNvbnNvbGUubG9nKCdvbkZvcm1Nb2RlbENoYW5nZScpO1xuICAgIHRoaXMuY2hhbmdlZCA9IHRydWU7XG4gIH1cblxuICBvbkFwcGx5U3R5bGUoKSB7XG4gICAgdGhpcy5jaGFuZ2VkID0gZmFsc2U7XG4gICAgdGhpcy5zdHlsZXNDaGFuZ2UuZW1pdCh0aGlzLnN0eWxlcyk7XG4gIH1cblxuICBzZWFyY2goZXZlbnQpIHtcbiAgICBsZXQgc2VhcmNoU3RyaW5nID0gZXZlbnQucXVlcnk7XG4gICAgdGhpcy5zZXRTZWxlY3RvcnNGcm9tU3R5bGVzKHNlYXJjaFN0cmluZyk7XG4gIH1cblxuICBwcml2YXRlIHNldFNlbGVjdG9yc0Zyb21TdHlsZXMoc2VhcmNoU3RyaW5nOiBzdHJpbmcgfCBudWxsKSB7XG4gICAgdGhpcy5zZWxlY3RvcnMgPSB0aGlzLnN0eWxlcz8uZmlsdGVyKChzdHlsZXNoZWV0OiBTdHlsZXNoZWV0U3R5bGUpID0+IHtcbiAgICAgIHJldHVybiBzZWFyY2hTdHJpbmcgPyBzdHlsZXNoZWV0LnNlbGVjdG9yLmluY2x1ZGVzKHNlYXJjaFN0cmluZykgOiB0cnVlO1xuICAgIH0pO1xuICB9XG5cbiAgb25BZGRTZWxlY3RvcigpIHtcbiAgICBjb25zdCBuZXdTdHlsZXNoZWV0U3R5bGU6IFN0eWxlc2hlZXRTdHlsZSA9IG5ldyBTdHlsZXNoZWV0SW1wbCgpO1xuICAgIG5ld1N0eWxlc2hlZXRTdHlsZS5zZWxlY3RvciA9IHRoaXMubGFzdFZhbGlkU2VsZWN0b3JNb2RlbFRleHQgfHwgJyc7XG4gICAgY29uc29sZS5sb2coXG4gICAgICAnQWRkaW5nIG5ldyBzdHlsZSB3aXRoIHNlbGVjdG9yOicsXG4gICAgICB0aGlzLmxhc3RWYWxpZFNlbGVjdG9yTW9kZWxUZXh0XG4gICAgKTtcbiAgICB0aGlzLnN0eWxlcz8udW5zaGlmdChuZXdTdHlsZXNoZWV0U3R5bGUpO1xuICAgIHRoaXMuc2VsZWN0ZWRTdHlsZVNoZWV0ID0gbmV3U3R5bGVzaGVldFN0eWxlO1xuICB9XG5cbiAgLypcbiAgICogVGhlIHBhcmFtIGNhbiBiZSBhIHNlbGVjdG9yIG9iamVjdCB3aGVuIHRoZSB1c2VyIHNlbGVjdHMgYSBzdHlsZXNoZWV0IGVudHJ5IGZyb20gdGhlIGRyb3Bkb3duIGFuZCBjaGFuZ2VzIHRoZVxuICAgKiBzZWxlY3Rpb24gKHdoaWNoIHdpbGwgZmlyZSBhIHNlbGVjdGlvbiBjaGFuZ2UgdG8gbGV0IHRoZSBncmFwaCwgc2F5LCBmb2N1cyBvbiB0aGUgc2VsZWN0ZWQgbm9kZSkuXG4gICAqIG9yIHRoZSBwYXJhbSBpcyB0ZXh0IGlmIHRoZSB1c2VyIGlzIGp1c3QgdHlwaW5nIGluIHRoZSBmaWVsZCwgd2hpY2ggZG9lbnMndCBjaGFuZ2UgdGhlIHNlbGVjdG9yIHVudGwgdGhlIHVzZXJcbiAgICogY2xpY2tzIEFkZC5cbiAgICovXG4gIG9uU2VsZWN0b3JNb2RlbENoYW5nZShwYXJhbTogYW55KSB7XG4gICAgY29uc29sZS5sb2coYHNlbGVjdG9yTW9kZWxDaGFuZ2VkOiR7SlNPTi5zdHJpbmdpZnkocGFyYW0pfWApO1xuICAgIGNvbnN0IHNlbGVjdG9yID0gcGFyYW0uc2VsZWN0b3IgPyBwYXJhbS5zZWxlY3RvciA6IHBhcmFtO1xuICAgIGNvbnN0IHN0eWxlc2hlZXQgPSBwYXJhbS5zZWxlY3RvclxuICAgICAgPyBwYXJhbVxuICAgICAgOiB0aGlzLmdldFN0eWxlc2hlZXRGb3JTZWxlY3RvcihzZWxlY3Rvcik7XG4gICAgaWYgKHN0eWxlc2hlZXQpIHtcbiAgICAgIGlmICh0aGlzLmNoYW5nZWQpIHtcbiAgICAgICAgdGhpcy5vbkFwcGx5U3R5bGUoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMuc3R5bGVTZWxlY3RvckNoYW5nZS5lbWl0KHNlbGVjdG9yKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5lbmFibGVBZGQgPSB0aGlzLmlzVmFsaWRTZWxlY3RvcihzZWxlY3Rvcik7XG4gICAgICBpZiAodGhpcy5lbmFibGVBZGQpIHtcbiAgICAgICAgdGhpcy5sYXN0VmFsaWRTZWxlY3Rvck1vZGVsVGV4dCA9IHNlbGVjdG9yO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sYXN0VmFsaWRTZWxlY3Rvck1vZGVsVGV4dCA9IHVuZGVmaW5lZDtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBnZXRTdHlsZXNoZWV0Rm9yU2VsZWN0b3Ioc2VsZWN0b3JOYW1lKTogU3R5bGVzaGVldCB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3Qgc3R5bGVzaGVldCA9IHRoaXMuc2VsZWN0b3JzPy5maW5kKFxuICAgICAgKHNlbGVjdG9yKSA9PiBzZWxlY3Rvci5zZWxlY3RvciA9PT0gc2VsZWN0b3JOYW1lXG4gICAgKTtcbiAgICByZXR1cm4gc3R5bGVzaGVldDtcbiAgfVxuXG4gIGlzVmFsaWRTZWxlY3Rvcih0ZXh0OiBzdHJpbmcpIHtcbiAgICBjb25zb2xlLmxvZygnaXNWYWxpZFNlbGVjdG9yOicsIHRleHQpO1xuICAgIGlmIChcbiAgICAgIHRleHQ/LnN0YXJ0c1dpdGgoJ25vZGUnKSB8fFxuICAgICAgdGV4dD8uc3RhcnRzV2l0aCgnZWRnZScpIHx8XG4gICAgICB0ZXh0Py5zdGFydHNXaXRoKCdjb3JlJylcbiAgICApIHtcbiAgICAgIGNvbnN0IG9wZW5CcmFja2V0ID0gdGV4dC5pbmRleE9mKCdbJyk7XG4gICAgICBpZiAob3BlbkJyYWNrZXQgPiAtMSkge1xuICAgICAgICBpZiAodGV4dC5pbmRleE9mKCddJykgPCBvcGVuQnJhY2tldCkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3Qgb3BlblF1b3RlID0gdGV4dC5pbmRleE9mKFwiJ1wiKTtcbiAgICAgIGlmIChvcGVuUXVvdGUgPiAtMSkge1xuICAgICAgICBsZXQgY2xvc2VRdW90ZSA9IHRleHQuaW5kZXhPZihcIidcIiwgb3BlblF1b3RlICsgMSk7XG4gICAgICAgIGlmIChjbG9zZVF1b3RlIDwgb3BlblF1b3RlKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG4iXX0=