UNPKG

@alfresco/adf-content-services

Version:
170 lines 41.6 kB
/*! * @license * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { Component, DestroyRef, ElementRef, EventEmitter, inject, Input, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { ENTER } from '@angular/cdk/keycodes'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatChipsModule } from '@angular/material/chips'; import { EMPTY, Observable, timer } from 'rxjs'; import { debounce, startWith, tap } from 'rxjs/operators'; import { CommonModule } from '@angular/common'; import { MatFormFieldModule } from '@angular/material/form-field'; import { TranslateModule } from '@ngx-translate/core'; import { MatIconModule } from '@angular/material/icon'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@angular/material/form-field"; import * as i3 from "@angular/material/chips"; import * as i4 from "@ngx-translate/core"; import * as i5 from "@angular/material/icon"; import * as i6 from "@angular/forms"; import * as i7 from "@angular/material/autocomplete"; import * as i8 from "@angular/material/core"; export class SearchChipAutocompleteInputComponent { constructor() { this.autocompleteOptions = []; this.preselectedOptions = []; this.allowOnlyPredefinedValues = true; this.placeholder = 'SEARCH.FILTER.ACTIONS.ADD_OPTION'; this.filter = (options, value) => { const filterValue = value.toLowerCase(); return options.filter((option) => option.value.toLowerCase().includes(filterValue)).slice(0, 15); }; this.optionsChanged = new EventEmitter(); this.inputChanged = new EventEmitter(); this.separatorKeysCodes = [ENTER]; this.formCtrl = new FormControl(''); this.filteredOptions = []; this.selectedOptions = []; this._activeAnyOption = false; this.destroyRef = inject(DestroyRef); } set activeAnyOption(active) { this._activeAnyOption = active; } ngOnInit() { this.formCtrl.valueChanges .pipe(startWith(''), tap(() => (this.activeAnyOption = false)), debounce((value) => (value ? timer(300) : EMPTY)), takeUntilDestroyed(this.destroyRef)) .subscribe((value) => { this.filteredOptions = value ? this.filter(this.autocompleteOptions, value) : []; this.inputChanged.emit(value); }); this.onReset$?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.reset()); this.selectedOptions = this.preselectedOptions ?? []; } ngOnChanges(changes) { if (changes.autocompleteOptions) { this.filteredOptions = changes.autocompleteOptions.currentValue?.length > 0 ? this.filter(changes.autocompleteOptions.currentValue, this.formCtrl.value) : []; } } add(event) { if (!this._activeAnyOption) { let value = (event.value || '').trim(); if (this.formatChipValue) { value = this.formatChipValue(value); } if (value && this.isExists(value) && !this.isAdded(value)) { if (this.allowOnlyPredefinedValues) { const index = this.autocompleteOptions.findIndex((option) => option.value.toLowerCase() === value.toLowerCase()); this.selectedOptions.push(this.autocompleteOptions[index]); } else { this.selectedOptions.push({ value }); } this.optionsChanged.emit(this.selectedOptions); event.chipInput.clear(); this.formCtrl.setValue(''); } } } remove(value) { const index = this.selectedOptions.indexOf(value); if (index >= 0) { this.selectedOptions.splice(index, 1); this.optionsChanged.emit(this.selectedOptions); } } selected(event) { this.selectedOptions.push(event.option.value); this.optionInput.nativeElement.value = ''; this.formCtrl.setValue(''); this.optionsChanged.emit(this.selectedOptions); } /** * Determines if a given option is already selected. * * This method checks if the provided `option` is present in the `selectedOptions` array. * If a custom comparison function (`compareOption`) is provided, it uses this function to determine equality. * Otherwise, it falls back to using strict equality comparison. * * @param option - The option to check for selection. * @returns `true` if the option is selected, `false` otherwise. */ isOptionSelected(option) { const compare = this.compareOption; const array = this.selectedOptions; return compare ? array.some((arrayValue) => compare(option, arrayValue)) : array.includes(option); } isAdded(value) { const valueLowerCase = value.toLowerCase(); return this.selectedOptions.some((option) => option.value.toLowerCase() === valueLowerCase); } isExists(value) { const valueLowerCase = value.toLowerCase(); return this.allowOnlyPredefinedValues ? this.autocompleteOptions.some((option) => option.value.toLowerCase() === valueLowerCase) : true; } reset() { this.selectedOptions = []; this.optionsChanged.emit(this.selectedOptions); this.formCtrl.setValue(''); this.optionInput.nativeElement.value = ''; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: SearchChipAutocompleteInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.3", type: SearchChipAutocompleteInputComponent, isStandalone: true, selector: "adf-search-chip-autocomplete-input", inputs: { autocompleteOptions: "autocompleteOptions", preselectedOptions: "preselectedOptions", onReset$: "onReset$", allowOnlyPredefinedValues: "allowOnlyPredefinedValues", placeholder: "placeholder", compareOption: "compareOption", formatChipValue: "formatChipValue", filter: "filter" }, outputs: { optionsChanged: "optionsChanged", inputChanged: "inputChanged" }, viewQueries: [{ propertyName: "optionInput", first: true, predicate: ["optionInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<mat-form-field class=\"adf-chip-list\" appearance=\"outline\">\n <mat-chip-grid #chipList [attr.aria-label]=\"'SEARCH.FILTER.ARIA-LABEL.OPTIONS-SELECTION' | translate\">\n <mat-chip-row\n class=\"adf-option-chips adf-autocomplete-added-option-chips\"\n *ngFor=\"let option of selectedOptions\"\n (removed)=\"remove(option)\">\n <span [title]=\"option.fullPath ? ('SEARCH.RESULTS.WILL_CONTAIN' | translate:{searchTerm: option.fullPath}) : undefined\">\n {{ option.value }}\n </span>\n <button\n matChipRemove\n class=\"adf-option-chips-delete-button adf-autocomplete-added-option-chips-delete-button\"\n [title]=\"'SEARCH.FILTER.BUTTONS.REMOVE' | translate\"\n >\n <mat-icon class=\"adf-option-chips-delete-icon adf-autocomplete-added-option-chips-delete-icon\">close</mat-icon>\n </button>\n </mat-chip-row>\n <input\n placeholder=\"{{ placeholder | translate }}\"\n aria-controls=\"adf-search-chip-autocomplete\"\n #optionInput\n #autocompleteTrigger=\"matAutocompleteTrigger\"\n [formControl]=\"formCtrl\"\n [matAutocomplete]=\"auto\"\n [matChipInputFor]=\"chipList\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n [attr.aria-label]=\"placeholder | translate\"\n class=\"adf-search-properties-file-input\"\n (matChipInputTokenEnd)=\"add($event)\"\n (blur)=\"activeAnyOption = false; autocompleteTrigger.closePanel()\"\n data-automation-id=\"adf-search-chip-autocomplete-input\">\n </mat-chip-grid>\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event)\" id=\"adf-search-chip-autocomplete\"\n (optionActivated)=\"activeAnyOption = true\" (closed)=\"activeAnyOption = false\">\n <ng-container *ngIf=\"optionInput.value.length > 0\">\n <mat-option\n *ngFor=\"let option of filteredOptions\"\n [value]=\"option\"\n (mousedown)=$event.preventDefault()\n [disabled]=\"isOptionSelected(option)\"\n [attr.data-automation-id]=\"'option-' + option.value\"\n [title]=\"option.fullPath ? ('SEARCH.RESULTS.WILL_CONTAIN' | translate : { searchTerm: option.fullPath || option.value }) : undefined\"\n class=\"adf-search-chip-autocomplete-added-option\"\n [ngClass]=\"isOptionSelected(option) && 'adf-autocomplete-added-option'\"\n >\n {{ option.fullPath || option.value }}\n </mat-option>\n </ng-container>\n </mat-autocomplete>\n</mat-form-field>\n", styles: ["adf-search-chip-autocomplete-input .adf-chip-list{width:100%}adf-search-chip-autocomplete-input .adf-chip-list:has(.mdc-notched-outline){margin-top:4px}adf-search-chip-autocomplete-input .mat-mdc-form-text-infix{border:none}adf-search-chip-autocomplete-input .adf-chip-list.mat-mdc-form-field .mat-mdc-form-field-infix{padding-top:14px;padding-bottom:14px;min-height:unset}adf-search-chip-autocomplete-input .adf-search-properties-file-input{margin-left:3px}adf-search-chip-autocomplete-input .adf-autocomplete-added-option-chips.adf-option-chips{border:1px solid var(--theme-text-color);border-radius:10px;background-color:var(--theme-primary-color-default-contrast);height:auto;word-break:break-word;padding:4px 0}adf-search-chip-autocomplete-input .mdc-evolution-chip-set .mdc-evolution-chip{margin-left:0;margin-right:4px}adf-search-chip-autocomplete-input .adf-option-chips-delete-button.adf-autocomplete-added-option-chips-delete-button{font-size:13px;height:13px;width:13px}adf-search-chip-autocomplete-input .adf-option-chips-delete-button.adf-autocomplete-added-option-chips-delete-button .adf-option-chips-delete-icon.adf-autocomplete-added-option-chips-delete-icon{font-size:13px;height:13px;width:13px}.adf-search-chip-autocomplete-added-option.adf-autocomplete-added-option{background:var(--adf-theme-mat-grey-color-a200);color:var(--adf-theme-primary-300)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i3.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i3.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "directive", type: i3.MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: i3.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i7.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i8.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i7.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: SearchChipAutocompleteInputComponent, decorators: [{ type: Component, args: [{ selector: 'adf-search-chip-autocomplete-input', standalone: true, imports: [CommonModule, MatFormFieldModule, MatChipsModule, TranslateModule, MatIconModule, ReactiveFormsModule, MatAutocompleteModule], encapsulation: ViewEncapsulation.None, template: "<mat-form-field class=\"adf-chip-list\" appearance=\"outline\">\n <mat-chip-grid #chipList [attr.aria-label]=\"'SEARCH.FILTER.ARIA-LABEL.OPTIONS-SELECTION' | translate\">\n <mat-chip-row\n class=\"adf-option-chips adf-autocomplete-added-option-chips\"\n *ngFor=\"let option of selectedOptions\"\n (removed)=\"remove(option)\">\n <span [title]=\"option.fullPath ? ('SEARCH.RESULTS.WILL_CONTAIN' | translate:{searchTerm: option.fullPath}) : undefined\">\n {{ option.value }}\n </span>\n <button\n matChipRemove\n class=\"adf-option-chips-delete-button adf-autocomplete-added-option-chips-delete-button\"\n [title]=\"'SEARCH.FILTER.BUTTONS.REMOVE' | translate\"\n >\n <mat-icon class=\"adf-option-chips-delete-icon adf-autocomplete-added-option-chips-delete-icon\">close</mat-icon>\n </button>\n </mat-chip-row>\n <input\n placeholder=\"{{ placeholder | translate }}\"\n aria-controls=\"adf-search-chip-autocomplete\"\n #optionInput\n #autocompleteTrigger=\"matAutocompleteTrigger\"\n [formControl]=\"formCtrl\"\n [matAutocomplete]=\"auto\"\n [matChipInputFor]=\"chipList\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n [attr.aria-label]=\"placeholder | translate\"\n class=\"adf-search-properties-file-input\"\n (matChipInputTokenEnd)=\"add($event)\"\n (blur)=\"activeAnyOption = false; autocompleteTrigger.closePanel()\"\n data-automation-id=\"adf-search-chip-autocomplete-input\">\n </mat-chip-grid>\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event)\" id=\"adf-search-chip-autocomplete\"\n (optionActivated)=\"activeAnyOption = true\" (closed)=\"activeAnyOption = false\">\n <ng-container *ngIf=\"optionInput.value.length > 0\">\n <mat-option\n *ngFor=\"let option of filteredOptions\"\n [value]=\"option\"\n (mousedown)=$event.preventDefault()\n [disabled]=\"isOptionSelected(option)\"\n [attr.data-automation-id]=\"'option-' + option.value\"\n [title]=\"option.fullPath ? ('SEARCH.RESULTS.WILL_CONTAIN' | translate : { searchTerm: option.fullPath || option.value }) : undefined\"\n class=\"adf-search-chip-autocomplete-added-option\"\n [ngClass]=\"isOptionSelected(option) && 'adf-autocomplete-added-option'\"\n >\n {{ option.fullPath || option.value }}\n </mat-option>\n </ng-container>\n </mat-autocomplete>\n</mat-form-field>\n", styles: ["adf-search-chip-autocomplete-input .adf-chip-list{width:100%}adf-search-chip-autocomplete-input .adf-chip-list:has(.mdc-notched-outline){margin-top:4px}adf-search-chip-autocomplete-input .mat-mdc-form-text-infix{border:none}adf-search-chip-autocomplete-input .adf-chip-list.mat-mdc-form-field .mat-mdc-form-field-infix{padding-top:14px;padding-bottom:14px;min-height:unset}adf-search-chip-autocomplete-input .adf-search-properties-file-input{margin-left:3px}adf-search-chip-autocomplete-input .adf-autocomplete-added-option-chips.adf-option-chips{border:1px solid var(--theme-text-color);border-radius:10px;background-color:var(--theme-primary-color-default-contrast);height:auto;word-break:break-word;padding:4px 0}adf-search-chip-autocomplete-input .mdc-evolution-chip-set .mdc-evolution-chip{margin-left:0;margin-right:4px}adf-search-chip-autocomplete-input .adf-option-chips-delete-button.adf-autocomplete-added-option-chips-delete-button{font-size:13px;height:13px;width:13px}adf-search-chip-autocomplete-input .adf-option-chips-delete-button.adf-autocomplete-added-option-chips-delete-button .adf-option-chips-delete-icon.adf-autocomplete-added-option-chips-delete-icon{font-size:13px;height:13px;width:13px}.adf-search-chip-autocomplete-added-option.adf-autocomplete-added-option{background:var(--adf-theme-mat-grey-color-a200);color:var(--adf-theme-primary-300)}\n"] }] }], propDecorators: { optionInput: [{ type: ViewChild, args: ['optionInput'] }], autocompleteOptions: [{ type: Input }], preselectedOptions: [{ type: Input }], onReset$: [{ type: Input }], allowOnlyPredefinedValues: [{ type: Input }], placeholder: [{ type: Input }], compareOption: [{ type: Input }], formatChipValue: [{ type: Input }], filter: [{ type: Input }], optionsChanged: [{ type: Output }], inputChanged: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLWNoaXAtYXV0b2NvbXBsZXRlLWlucHV0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYi9jb250ZW50LXNlcnZpY2VzL3NyYy9saWIvc2VhcmNoL2NvbXBvbmVudHMvc2VhcmNoLWNoaXAtYXV0b2NvbXBsZXRlLWlucHV0L3NlYXJjaC1jaGlwLWF1dG9jb21wbGV0ZS1pbnB1dC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9saWIvY29udGVudC1zZXJ2aWNlcy9zcmMvbGliL3NlYXJjaC9jb21wb25lbnRzL3NlYXJjaC1jaGlwLWF1dG9jb21wbGV0ZS1pbnB1dC9zZWFyY2gtY2hpcC1hdXRvY29tcGxldGUtaW5wdXQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxFQUNILFNBQVMsRUFDVCxVQUFVLEVBQ1YsVUFBVSxFQUNWLFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUdMLE1BQU0sRUFFTixTQUFTLEVBQ1QsaUJBQWlCLEVBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsV0FBVyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEUsT0FBTyxFQUFFLHFCQUFxQixFQUFnQyxNQUFNLGdDQUFnQyxDQUFDO0FBQ3JHLE9BQU8sRUFBcUIsY0FBYyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUUsT0FBTyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTFELE9BQU8sRUFBRSxZQUFZLEVBQUUs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cUI7OzJGQUs3SCxvQ0FBb0M7a0JBUmhELFNBQVM7K0JBQ0ksb0NBQW9DLGNBQ2xDLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSxrQkFBa0IsRUFBRSxjQUFjLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxtQkFBbUIsRUFBRSxxQkFBcUIsQ0FBQyxpQkFHeEgsaUJBQWlCLENBQUMsSUFBSTs4QkFJckMsV0FBVztzQkFEVixTQUFTO3VCQUFDLGFBQWE7Z0JBSXhCLG1CQUFtQjtzQkFEbEIsS0FBSztnQkFJTixrQkFBa0I7c0JBRGpCLEtBQUs7Z0JBSU4sUUFBUTtzQkFEUCxLQUFLO2dCQUlOLHlCQUF5QjtzQkFEeEIsS0FBSztnQkFJTixXQUFXO3NCQURWLEtBQUs7Z0JBSU4sYUFBYTtzQkFEWixLQUFLO2dCQUlOLGVBQWU7c0JBRGQsS0FBSztnQkFJTixNQUFNO3NCQURMLEtBQUs7Z0JBT04sY0FBYztzQkFEYixNQUFNO2dCQUlQLFlBQVk7c0JBRFgsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbIi8qIVxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCDCqSAyMDA1LTIwMjUgSHlsYW5kIFNvZnR3YXJlLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHtcbiAgICBDb21wb25lbnQsXG4gICAgRGVzdHJveVJlZixcbiAgICBFbGVtZW50UmVmLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBpbmplY3QsXG4gICAgSW5wdXQsXG4gICAgT25DaGFuZ2VzLFxuICAgIE9uSW5pdCxcbiAgICBPdXRwdXQsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3Q2hpbGQsXG4gICAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBFTlRFUiB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9rZXljb2Rlcyc7XG5pbXBvcnQgeyBGb3JtQ29udHJvbCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE1hdEF1dG9jb21wbGV0ZU1vZHVsZSwgTWF0QXV0b2NvbXBsZXRlU2VsZWN0ZWRFdmVudCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2F1dG9jb21wbGV0ZSc7XG5pbXBvcnQgeyBNYXRDaGlwSW5wdXRFdmVudCwgTWF0Q2hpcHNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jaGlwcyc7XG5pbXBvcnQgeyBFTVBUWSwgT2JzZXJ2YWJsZSwgdGltZXIgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlYm91bmNlLCBzdGFydFdpdGgsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEF1dG9jb21wbGV0ZU9wdGlvbiB9IGZyb20gJy4uLy4uL21vZGVscy9hdXRvY29tcGxldGUtb3B0aW9uLmludGVyZmFjZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgTWF0Rm9ybUZpZWxkTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZm9ybS1maWVsZCc7XG5pbXBvcnQgeyBUcmFuc2xhdGVNb2R1bGUgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcbmltcG9ydCB7IHRha2VVbnRpbERlc3Ryb3llZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdhZGYtc2VhcmNoLWNoaXAtYXV0b2NvbXBsZXRlLWlucHV0JyxcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxuICAgIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIE1hdEZvcm1GaWVsZE1vZHVsZSwgTWF0Q2hpcHNNb2R1bGUsIFRyYW5zbGF0ZU1vZHVsZSwgTWF0SWNvbk1vZHVsZSwgUmVhY3RpdmVGb3Jtc01vZHVsZSwgTWF0QXV0b2NvbXBsZXRlTW9kdWxlXSxcbiAgICB0ZW1wbGF0ZVVybDogJy4vc2VhcmNoLWNoaXAtYXV0b2NvbXBsZXRlLWlucHV0LmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9zZWFyY2gtY2hpcC1hdXRvY29tcGxldGUtaW5wdXQuY29tcG9uZW50LnNjc3MnXSxcbiAgICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lXG59KVxuZXhwb3J0IGNsYXNzIFNlYXJjaENoaXBBdXRvY29tcGxldGVJbnB1dENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzIHtcbiAgICBAVmlld0NoaWxkKCdvcHRpb25JbnB1dCcpXG4gICAgb3B0aW9uSW5wdXQ6IEVsZW1lbnRSZWY8SFRNTElucHV0RWxlbWVudD47XG5cbiAgICBASW5wdXQoKVxuICAgIGF1dG9jb21wbGV0ZU9wdGlvbnM6IEF1dG9jb21wbGV0ZU9wdGlvbltdID0gW107XG5cbiAgICBASW5wdXQoKVxuICAgIHByZXNlbGVjdGVkT3B0aW9uczogQXV0b2NvbXBsZXRlT3B0aW9uW10gPSBbXTtcblxuICAgIEBJbnB1dCgpXG4gICAgb25SZXNldCQ6IE9ic2VydmFibGU8dm9pZD47XG5cbiAgICBASW5wdXQoKVxuICAgIGFsbG93T25seVByZWRlZmluZWRWYWx1ZXMgPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwbGFjZWhvbGRlciA9ICdTRUFSQ0guRklMVEVSLkFDVElPTlMuQUREX09QVElPTic7XG5cbiAgICBASW5wdXQoKVxuICAgIGNvbXBhcmVPcHRpb24/OiAob3B0aW9uMTogQXV0b2NvbXBsZXRlT3B0aW9uLCBvcHRpb24yOiBBdXRvY29tcGxldGVPcHRpb24pID0+IGJvb2xlYW47XG5cbiAgICBASW5wdXQoKVxuICAgIGZvcm1hdENoaXBWYWx1ZT86IChvcHRpb246IHN0cmluZykgPT4gc3RyaW5nO1xuXG4gICAgQElucHV0KClcbiAgICBmaWx0ZXIgPSAob3B0aW9uczogQXV0b2NvbXBsZXRlT3B0aW9uW10sIHZhbHVlOiBzdHJpbmcpOiBBdXRvY29tcGxldGVPcHRpb25bXSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbHRlclZhbHVlID0gdmFsdWUudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgcmV0dXJuIG9wdGlvbnMuZmlsdGVyKChvcHRpb24pID0+IG9wdGlvbi52YWx1ZS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKGZpbHRlclZhbHVlKSkuc2xpY2UoMCwgMTUpO1xuICAgIH07XG5cbiAgICBAT3V0cHV0KClcbiAgICBvcHRpb25zQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXI8QXV0b2NvbXBsZXRlT3B0aW9uW10+KCk7XG5cbiAgICBAT3V0cHV0KClcbiAgICBpbnB1dENoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICAgIHJlYWRvbmx5IHNlcGFyYXRvcktleXNDb2RlcyA9IFtFTlRFUl0gYXMgY29uc3Q7XG4gICAgZm9ybUN0cmwgPSBuZXcgRm9ybUNvbnRyb2woJycpO1xuICAgIGZpbHRlcmVkT3B0aW9uczogQXV0b2NvbXBsZXRlT3B0aW9uW10gPSBbXTtcbiAgICBzZWxlY3RlZE9wdGlvbnM6IEF1dG9jb21wbGV0ZU9wdGlvbltdID0gW107XG5cbiAgICBwcml2YXRlIF9hY3RpdmVBbnlPcHRpb24gPSBmYWxzZTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcblxuICAgIHNldCBhY3RpdmVBbnlPcHRpb24oYWN0aXZlOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuX2FjdGl2ZUFueU9wdGlvbiA9IGFjdGl2ZTtcbiAgICB9XG5cbiAgICBuZ09uSW5pdCgpIHtcbiAgICAgICAgdGhpcy5mb3JtQ3RybC52YWx1ZUNoYW5nZXNcbiAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgIHN0YXJ0V2l0aCgnJyksXG4gICAgICAgICAgICAgICAgdGFwKCgpID0+ICh0aGlzLmFjdGl2ZUFueU9wdGlvbiA9IGZhbHNlKSksXG4gICAgICAgICAgICAgICAgZGVib3VuY2UoKHZhbHVlOiBzdHJpbmcpID0+ICh2YWx1ZSA/IHRpbWVyKDMwMCkgOiBFTVBUWSkpLFxuICAgICAgICAgICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCh2YWx1ZTogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5maWx0ZXJlZE9wdGlvbnMgPSB2YWx1ZSA/IHRoaXMuZmlsdGVyKHRoaXMuYXV0b2NvbXBsZXRlT3B0aW9ucywgdmFsdWUpIDogW107XG4gICAgICAgICAgICAgICAgdGhpcy5pbnB1dENoYW5nZWQuZW1pdCh2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5vblJlc2V0JD8ucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5kZXN0cm95UmVmKSkuc3Vic2NyaWJlKCgpID0+IHRoaXMucmVzZXQoKSk7XG4gICAgICAgIHRoaXMuc2VsZWN0ZWRPcHRpb25zID0gdGhpcy5wcmVzZWxlY3RlZE9wdGlvbnMgPz8gW107XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcykge1xuICAgICAgICBpZiAoY2hhbmdlcy5hdXRvY29tcGxldGVPcHRpb25zKSB7XG4gICAgICAgICAgICB0aGlzLmZpbHRlcmVkT3B0aW9ucyA9XG4gICAgICAgICAgICAgICAgY2hhbmdlcy5hdXRvY29tcGxldGVPcHRpb25zLmN1cnJlbnRWYWx1ZT8ubGVuZ3RoID4gMFxuICAgICAgICAgICAgICAgICAgICA/IHRoaXMuZmlsdGVyKGNoYW5nZXMuYXV0b2NvbXBsZXRlT3B0aW9ucy5jdXJyZW50VmFsdWUsIHRoaXMuZm9ybUN0cmwudmFsdWUpXG4gICAgICAgICAgICAgICAgICAgIDogW107XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhZGQoZXZlbnQ6IE1hdENoaXBJbnB1dEV2ZW50KSB7XG4gICAgICAgIGlmICghdGhpcy5fYWN0aXZlQW55T3B0aW9uKSB7XG4gICAgICAgICAgICBsZXQgdmFsdWUgPSAoZXZlbnQudmFsdWUgfHwgJycpLnRyaW0oKTtcbiAgICAgICAgICAgIGlmICh0aGlzLmZvcm1hdENoaXBWYWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhbHVlID0gdGhpcy5mb3JtYXRDaGlwVmFsdWUodmFsdWUpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodmFsdWUgJiYgdGhpcy5pc0V4aXN0cyh2YWx1ZSkgJiYgIXRoaXMuaXNBZGRlZCh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5hbGxvd09ubHlQcmVkZWZpbmVkVmFsdWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5hdXRvY29tcGxldGVPcHRpb25zLmZpbmRJbmRleCgob3B0aW9uKSA9PiBvcHRpb24udmFsdWUudG9Mb3dlckNhc2UoKSA9PT0gdmFsdWUudG9Mb3dlckNhc2UoKSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRPcHRpb25zLnB1c2godGhpcy5hdXRvY29tcGxldGVPcHRpb25zW2luZGV4XSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZWxlY3RlZE9wdGlvbnMucHVzaCh7IHZhbHVlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnNDaGFuZ2VkLmVtaXQodGhpcy5zZWxlY3RlZE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIGV2ZW50LmNoaXBJbnB1dC5jbGVhcigpO1xuICAgICAgICAgICAgICAgIHRoaXMuZm9ybUN0cmwuc2V0VmFsdWUoJycpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmVtb3ZlKHZhbHVlOiBBdXRvY29tcGxldGVPcHRpb24pIHtcbiAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLnNlbGVjdGVkT3B0aW9ucy5pbmRleE9mKHZhbHVlKTtcblxuICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZE9wdGlvbnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgICAgIHRoaXMub3B0aW9uc0NoYW5nZWQuZW1pdCh0aGlzLnNlbGVjdGVkT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzZWxlY3RlZChldmVudDogTWF0QXV0b2NvbXBsZXRlU2VsZWN0ZWRFdmVudCkge1xuICAgICAgICB0aGlzLnNlbGVjdGVkT3B0aW9ucy5wdXNoKGV2ZW50Lm9wdGlvbi52YWx1ZSk7XG4gICAgICAgIHRoaXMub3B0aW9uSW5wdXQubmF0aXZlRWxlbWVudC52YWx1ZSA9ICcnO1xuICAgICAgICB0aGlzLmZvcm1DdHJsLnNldFZhbHVlKCcnKTtcbiAgICAgICAgdGhpcy5vcHRpb25zQ2hhbmdlZC5lbWl0KHRoaXMuc2VsZWN0ZWRPcHRpb25zKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEZXRlcm1pbmVzIGlmIGEgZ2l2ZW4gb3B0aW9uIGlzIGFscmVhZHkgc2VsZWN0ZWQuXG4gICAgICpcbiAgICAgKiBUaGlzIG1ldGhvZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGBvcHRpb25gIGlzIHByZXNlbnQgaW4gdGhlIGBzZWxlY3RlZE9wdGlvbnNgIGFycmF5LlxuICAgICAqIElmIGEgY3VzdG9tIGNvbXBhcmlzb24gZnVuY3Rpb24gKGBjb21wYXJlT3B0aW9uYCkgaXMgcHJvdmlkZWQsIGl0IHVzZXMgdGhpcyBmdW5jdGlvbiB0byBkZXRlcm1pbmUgZXF1YWxpdHkuXG4gICAgICogT3RoZXJ3aXNlLCBpdCBmYWxscyBiYWNrIHRvIHVzaW5nIHN0cmljdCBlcXVhbGl0eSBjb21wYXJpc29uLlxuICAgICAqXG4gICAgICogQHBhcmFtIG9wdGlvbiAtIFRoZSBvcHRpb24gdG8gY2hlY2sgZm9yIHNlbGVjdGlvbi5cbiAgICAgKiBAcmV0dXJucyBgdHJ1ZWAgaWYgdGhlIG9wdGlvbiBpcyBzZWxlY3RlZCwgYGZhbHNlYCBvdGhlcndpc2UuXG4gICAgICovXG4gICAgaXNPcHRpb25TZWxlY3RlZChvcHRpb246IEF1dG9jb21wbGV0ZU9wdGlvbik6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCBjb21wYXJlID0gdGhpcy5jb21wYXJlT3B0aW9uO1xuICAgICAgICBjb25zdCBhcnJheSA9IHRoaXMuc2VsZWN0ZWRPcHRpb25zO1xuXG4gICAgICAgIHJldHVybiBjb21wYXJlID8gYXJyYXkuc29tZSgoYXJyYXlWYWx1ZSkgPT4gY29tcGFyZShvcHRpb24sIGFycmF5VmFsdWUpKSA6IGFycmF5LmluY2x1ZGVzKG9wdGlvbik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpc0FkZGVkKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgdmFsdWVMb3dlckNhc2UgPSB2YWx1ZS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICByZXR1cm4gdGhpcy5zZWxlY3RlZE9wdGlvbnMuc29tZSgob3B0aW9uKSA9PiBvcHRpb24udmFsdWUudG9Mb3dlckNhc2UoKSA9PT0gdmFsdWVMb3dlckNhc2UpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaXNFeGlzdHModmFsdWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCB2YWx1ZUxvd2VyQ2FzZSA9IHZhbHVlLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHJldHVybiB0aGlzLmFsbG93T25seVByZWRlZmluZWRWYWx1ZXMgPyB0aGlzLmF1dG9jb21wbGV0ZU9wdGlvbnMuc29tZSgob3B0aW9uKSA9PiBvcHRpb24udmFsdWUudG9Mb3dlckNhc2UoKSA9PT0gdmFsdWVMb3dlckNhc2UpIDogdHJ1ZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlc2V0KCkge1xuICAgICAgICB0aGlzLnNlbGVjdGVkT3B0aW9ucyA9IFtdO1xuICAgICAgICB0aGlzLm9wdGlvbnNDaGFuZ2VkLmVtaXQodGhpcy5zZWxlY3RlZE9wdGlvbnMpO1xuICAgICAgICB0aGlzLmZvcm1DdHJsLnNldFZhbHVlKCcnKTtcbiAgICAgICAgdGhpcy5vcHRpb25JbnB1dC5uYXRpdmVFbGVtZW50LnZhbHVlID0gJyc7XG4gICAgfVxufVxuIiwiPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiYWRmLWNoaXAtbGlzdFwiIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCI+XG4gICAgPG1hdC1jaGlwLWdyaWQgI2NoaXBMaXN0IFthdHRyLmFyaWEtbGFiZWxdPVwiJ1NFQVJDSC5GSUxURVIuQVJJQS1MQUJFTC5PUFRJT05TLVNFTEVDVElPTicgfCB0cmFuc2xhdGVcIj5cbiAgICAgICAgPG1hdC1jaGlwLXJvd1xuICAgICAgICAgICAgY2xhc3M9XCJhZGYtb3B0aW9uLWNoaXBzIGFkZi1hdXRvY29tcGxldGUtYWRkZWQtb3B0aW9uLWNoaXBzXCJcbiAgICAgICAgICAgICpuZ0Zvcj1cImxldCBvcHRpb24gb2Ygc2VsZWN0ZWRPcHRpb25zXCJcbiAgICAgICAgICAgIChyZW1vdmVkKT1cInJlbW92ZShvcHRpb24pXCI+XG4gICAgICAgICAgICA8c3BhbiBbdGl0bGVdPVwib3B0aW9uLmZ1bGxQYXRoID8gKCdTRUFSQ0guUkVTVUxUUy5XSUxMX0NPTlRBSU4nIHwgdHJhbnNsYXRlOntzZWFyY2hUZXJtOiBvcHRpb24uZnVsbFBhdGh9KSA6IHVuZGVmaW5lZFwiPlxuICAgICAgICAgICAgICAgIHt7IG9wdGlvbi52YWx1ZSB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIG1hdENoaXBSZW1vdmVcbiAgICAgICAgICAgICAgICBjbGFzcz1cImFkZi1vcHRpb24tY2hpcHMtZGVsZXRlLWJ1dHRvbiBhZGYtYXV0b2NvbXBsZXRlLWFkZGVkLW9wdGlvbi1jaGlwcy1kZWxldGUtYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBbdGl0bGVdPVwiJ1NFQVJDSC5GSUxURVIuQlVUVE9OUy5SRU1PVkUnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJhZGYtb3B0aW9uLWNoaXBzLWRlbGV0ZS1pY29uIGFkZi1hdXRvY29tcGxldGUtYWRkZWQtb3B0aW9uLWNoaXBzLWRlbGV0ZS1pY29uXCI+Y2xvc2U8L21hdC1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDwvbWF0LWNoaXAtcm93PlxuICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwie3sgcGxhY2Vob2xkZXIgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgYXJpYS1jb250cm9scz1cImFkZi1zZWFyY2gtY2hpcC1hdXRvY29tcGxldGVcIlxuICAgICAgICAgICAgI29wdGlvbklucHV0XG4gICAgICAgICAgICAjYXV0b2NvbXBsZXRlVHJpZ2dlcj1cIm1hdEF1dG9jb21wbGV0ZVRyaWdnZXJcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImZvcm1DdHJsXCJcbiAgICAgICAgICAgIFttYXRBdXRvY29tcGxldGVdPVwiYXV0b1wiXG4gICAgICAgICAgICBbbWF0Q2hpcElucHV0Rm9yXT1cImNoaXBMaXN0XCJcbiAgICAgICAgICAgIFttYXRDaGlwSW5wdXRTZXBhcmF0b3JLZXlDb2Rlc109XCJzZXBhcmF0b3JLZXlzQ29kZXNcIlxuICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJwbGFjZWhvbGRlciB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICBjbGFzcz1cImFkZi1zZWFyY2gtcHJvcGVydGllcy1maWxlLWlucHV0XCJcbiAgICAgICAgICAgIChtYXRDaGlwSW5wdXRUb2tlbkVuZCk9XCJhZGQoJGV2ZW50KVwiXG4gICAgICAgICAgICAoYmx1cik9XCJhY3RpdmVBbnlPcHRpb24gPSBmYWxzZTsgYXV0b2NvbXBsZXRlVHJpZ2dlci5jbG9zZVBhbmVsKClcIlxuICAgICAgICAgICAgZGF0YS1hdXRvbWF0aW9uLWlkPVwiYWRmLXNlYXJjaC1jaGlwLWF1dG9jb21wbGV0ZS1pbnB1dFwiPlxuICAgIDwvbWF0LWNoaXAtZ3JpZD5cbiAgICA8bWF0LWF1dG9jb21wbGV0ZSAjYXV0bz1cIm1hdEF1dG9jb21wbGV0ZVwiIChvcHRpb25TZWxlY3RlZCk9XCJzZWxlY3RlZCgkZXZlbnQpXCIgaWQ9XCJhZGYtc2VhcmNoLWNoaXAtYXV0b2NvbXBsZXRlXCJcbiAgICAgICAgICAgICAgICAgICAgICAob3B0aW9uQWN0aXZhdGVkKT1cImFjdGl2ZUFueU9wdGlvbiA9IHRydWVcIiAoY2xvc2VkKT1cImFjdGl2ZUFueU9wdGlvbiA9IGZhbHNlXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJvcHRpb25JbnB1dC52YWx1ZS5sZW5ndGggPiAwXCI+XG4gICAgICAgICAgICA8bWF0LW9wdGlvblxuICAgICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBvcHRpb24gb2YgZmlsdGVyZWRPcHRpb25zXCJcbiAgICAgICAgICAgICAgICBbdmFsdWVdPVwib3B0aW9uXCJcbiAgICAgICAgICAgICAgICAobW91c2Vkb3duKT0kZXZlbnQucHJldmVudERlZmF1bHQoKVxuICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJpc09wdGlvblNlbGVjdGVkKG9wdGlvbilcIlxuICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtYXV0b21hdGlvbi1pZF09XCInb3B0aW9uLScgKyBvcHRpb24udmFsdWVcIlxuICAgICAgICAgICAgICAgIFt0aXRsZV09XCJvcHRpb24uZnVsbFBhdGggPyAoJ1NFQVJDSC5SRVNVTFRTLldJTExfQ09OVEFJTicgfCB0cmFuc2xhdGUgOiB7IHNlYXJjaFRlcm06IG9wdGlvbi5mdWxsUGF0aCB8fCBvcHRpb24udmFsdWUgfSkgOiB1bmRlZmluZWRcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYWRmLXNlYXJjaC1jaGlwLWF1dG9jb21wbGV0ZS1hZGRlZC1vcHRpb25cIlxuICAgICAgICAgICAgICAgIFtuZ0NsYXNzXT1cImlzT3B0aW9uU2VsZWN0ZWQob3B0aW9uKSAmJiAnYWRmLWF1dG9jb21wbGV0ZS1hZGRlZC1vcHRpb24nXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICB7eyBvcHRpb24uZnVsbFBhdGggfHwgb3B0aW9uLnZhbHVlIH19XG4gICAgICAgICAgICA8L21hdC1vcHRpb24+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgIDwvbWF0LWF1dG9jb21wbGV0ZT5cbjwvbWF0LWZvcm0tZmllbGQ+XG4iXX0=