UNPKG

@alfresco/adf-content-services

Version:
181 lines 38.1 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 { AuthenticationService, HighlightPipe, SearchTextInputComponent, ThumbnailService } from '@alfresco/adf-core'; import { Component, ContentChild, EventEmitter, Input, Output, QueryList, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core'; import { Subject } from 'rxjs'; import { SearchComponent } from './search.component'; import { MatListItem, MatListModule } from '@angular/material/list'; import { EmptySearchResultComponent } from './empty-search-result.component'; import { CommonModule } from '@angular/common'; import { MatIconModule } from '@angular/material/icon'; import { TranslateModule } from '@ngx-translate/core'; import * as i0 from "@angular/core"; import * as i1 from "@alfresco/adf-core"; import * as i2 from "@angular/common"; import * as i3 from "@angular/material/list"; import * as i4 from "@angular/material/icon"; import * as i5 from "@ngx-translate/core"; export class SearchControlComponent { constructor(authService, thumbnailService) { this.authService = authService; this.thumbnailService = thumbnailService; /** Toggles highlighting of the search term in the results. */ this.highlight = false; /** Type of the input field to render, e.g. "search" or "text" (default). */ this.inputType = 'text'; /** Toggles "find-as-you-type" suggestions for possible matches. */ this.liveSearchEnabled = true; /** Toggles auto-completion of the search input field. */ this.autocomplete = false; /** * Toggles whether to use an expanding search control. If false * then a regular input is used. */ this.expandable = true; /** Maximum number of results to show in the live search. */ this.liveSearchMaxResults = 5; /** * Emitted when the search is submitted by pressing the ENTER key. * The search term is provided as the value of the event. */ this.submit = new EventEmitter(); /** * Emitted when the search term is changed. The search term is provided * in the 'value' property of the returned object. If the term is less * than three characters in length then it is truncated to an empty * string. */ this.searchChange = new EventEmitter(); /** Emitted when a file item from the list of "find-as-you-type" results is selected. */ this.optionClicked = new EventEmitter(); this.focusSubject = new Subject(); this.noSearchResultTemplate = null; this.searchTerm = ''; } isNoSearchTemplatePresent() { return !!this.emptySearchTemplate; } isLoggedIn() { return this.authService.isEcmLoggedIn(); } inputChange(value) { this.searchTerm = value; this.searchChange.emit(value); } getMimeTypeIcon(node) { const mimeType = this.getMimeType(node); return this.thumbnailService.getMimeTypeIcon(mimeType); } getMimeType(node) { let mimeType; if (node.entry.content?.mimeType) { mimeType = node.entry.content.mimeType; } if (node.entry.isFolder) { mimeType = 'folder'; } return mimeType; } elementClicked(item) { if (item.entry) { this.optionClicked.next(item); this.focusSubject.next(new FocusEvent('blur')); } } onFocus(event) { this.focusSubject.next(event); } onBlur(event) { const nextElement = this.getNextElementSibling(event.target); if (!nextElement && !this.isListElement(event)) { this.focusSubject.next(event); } } onSelectFirstResult() { if (this.listResultElement && this.listResultElement.length > 0) { const firstElement = this.listResultElement.first; // eslint-disable-next-line no-underscore-dangle firstElement._hostElement.focus(); } } onRowArrowDown(event) { const nextElement = this.getNextElementSibling(event.target); if (nextElement) { nextElement.focus(); } } onRowArrowUp(event) { const previousElement = this.getPreviousElementSibling(event.target); if (previousElement) { previousElement.focus(); } else { this.focusSubject.next(new FocusEvent('focus')); } } onReset(status) { if (status) { this.searchAutocomplete.resetResults(); } } isListElement(event) { return event.relatedTarget?.children[0] && event.relatedTarget.children[0].className === 'mat-list-item-content'; } getNextElementSibling(node) { return node.nextElementSibling; } getPreviousElementSibling(node) { return node.previousElementSibling; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: SearchControlComponent, deps: [{ token: i1.AuthenticationService }, { token: i1.ThumbnailService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.3", type: SearchControlComponent, isStandalone: true, selector: "adf-search-control", inputs: { highlight: "highlight", inputType: "inputType", liveSearchEnabled: "liveSearchEnabled", autocomplete: "autocomplete", expandable: "expandable", liveSearchMaxResults: "liveSearchMaxResults" }, outputs: { submit: "submit", searchChange: "searchChange", optionClicked: "optionClicked" }, host: { classAttribute: "adf-search-control" }, queries: [{ propertyName: "emptySearchTemplate", first: true, predicate: EmptySearchResultComponent, descendants: true }], viewQueries: [{ propertyName: "searchTextInput", first: true, predicate: ["searchTextInput"], descendants: true }, { propertyName: "searchAutocomplete", first: true, predicate: ["search"], descendants: true }, { propertyName: "listResultElement", predicate: MatListItem, descendants: true }], ngImport: i0, template: "<div *ngIf=\"isLoggedIn()\">\n <adf-search-text-input #searchTextInput\n [searchTerm]= \"searchTerm\"\n [expandable]=\"expandable\"\n [autocomplete]=\"autocomplete\"\n [liveSearchEnabled]=\"liveSearchEnabled\"\n [focusListener]=\"focusSubject.asObservable()\"\n [searchAutocomplete]=\"auto\"\n (searchChange)=\"inputChange($event)\"\n (reset)=\"onReset($event)\"\n (selectResult)=\"onSelectFirstResult()\"\n (submit)=\"submit.emit($event)\" />\n\n <adf-search #search\n #auto=\"searchAutocomplete\"\n class=\"adf-search-result-autocomplete\"\n [maxResults]=\"liveSearchMaxResults\">\n <ng-template let-data>\n <mat-list *ngIf=\"searchTextInput?.isSearchBarActive()\" id=\"autocomplete-search-result-list\">\n <mat-list-item\n *ngFor=\"let item of data?.list?.entries; let idx = index\"\n id=\"result_option_{{idx}}\"\n [attr.data-automation-id]=\"'autocomplete_for_' + item.entry.name\"\n [tabindex]=\"0\"\n (blur)=\"onBlur($event)\"\n (keyup.arrowdown)=\"onRowArrowDown($event)\"\n (keyup.arrowup)=\"onRowArrowUp($event)\"\n class=\"adf-search-autocomplete-item\"\n (click)=\"elementClicked(item)\"\n (keyup.enter)=\"elementClicked(item)\"\n (touchend)=\"elementClicked(item)\">\n <!-- This is a comment -->\n <mat-icon matListItemLine>\n <img [alt]=\"getMimeType(item)\" [src]=\"getMimeTypeIcon(item)\"/>\n </mat-icon>\n <h4 matListItemTitle id=\"result_name_{{idx}}\"\n *ngIf=\"highlight; else elseBlock\"\n class=\"adf-search-fixed-text\"\n [innerHtml]=\"item.entry.name | highlight: searchTerm\">\n {{ item?.entry.name }}\n </h4>\n <ng-template #elseBlock>\n <h4 class=\"adf-search-fixed-text\" matListItemTitle id=\"result_name_{{idx}}\"\n [innerHtml]=\"item.entry.name\"></h4>\n </ng-template>\n <p matListItemLine class=\"adf-search-fixed-text\"> {{item?.entry.createdByUser.displayName}} </p>\n </mat-list-item>\n <mat-list-item id=\"search_no_result\"\n data-automation-id=\"search_no_result_found\"\n *ngIf=\"data?.list?.entries.length === 0\">\n <ng-content\n selector=\"adf-empty-search-result\"\n *ngIf=\"isNoSearchTemplatePresent() else defaultNoResult\" />\n <ng-template #defaultNoResult>\n <p matListItemLine class=\"adf-search-fixed-text\">{{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm:\n searchTerm} }}</p>\n </ng-template>\n </mat-list-item>\n </mat-list>\n </ng-template>\n </adf-search>\n</div>\n", styles: [".adf-search-result-autocomplete{min-width:112px;max-width:280px;overflow:auto;-webkit-overflow-scrolling:touch;transform-origin:top left;transform:translate(-40px);position:absolute;max-height:400px;margin-left:45px;margin-top:-22px;font-size:var(--theme-subheading-1-font-size);z-index:5;color:var(--adf-theme-foreground-text-color);background-color:var(--adf-theme-background-card-color);border-radius:2px}.adf-search-result-autocomplete:not([class*=mat-elevation-z]){box-shadow:0 3px 1px -2px #0003,0 2px 2px #00000024,0 1px 5px #0000001f}@media (max-width: 959.9px){.adf-search-result-autocomplete{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}}.adf-search-autocomplete-item:hover{background-color:var(--adf-theme-background-hover-color);opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SearchTextInputComponent, selector: "adf-search-text-input", inputs: ["autocomplete", "expandable", "inputType", "liveSearchEnabled", "searchAutocomplete", "searchTerm", "debounceTime", "focusListener", "collapseOnSubmit", "defaultState", "collapseOnBlur", "showClearButton", "placeholder", "label", "hintLabel"], outputs: ["searchChange", "submit", "selectResult", "reset", "searchVisibility"] }, { kind: "component", type: SearchComponent, selector: "adf-search", inputs: ["displayWith", "maxResults", "skipResults", "searchTerm", "class"], outputs: ["resultLoaded", "error"], exportAs: ["searchAutocomplete"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i3.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i3.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: HighlightPipe, name: "highlight" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: SearchControlComponent, decorators: [{ type: Component, args: [{ selector: 'adf-search-control', standalone: true, imports: [CommonModule, SearchTextInputComponent, SearchComponent, MatListModule, MatIconModule, HighlightPipe, TranslateModule], encapsulation: ViewEncapsulation.None, host: { class: 'adf-search-control' }, template: "<div *ngIf=\"isLoggedIn()\">\n <adf-search-text-input #searchTextInput\n [searchTerm]= \"searchTerm\"\n [expandable]=\"expandable\"\n [autocomplete]=\"autocomplete\"\n [liveSearchEnabled]=\"liveSearchEnabled\"\n [focusListener]=\"focusSubject.asObservable()\"\n [searchAutocomplete]=\"auto\"\n (searchChange)=\"inputChange($event)\"\n (reset)=\"onReset($event)\"\n (selectResult)=\"onSelectFirstResult()\"\n (submit)=\"submit.emit($event)\" />\n\n <adf-search #search\n #auto=\"searchAutocomplete\"\n class=\"adf-search-result-autocomplete\"\n [maxResults]=\"liveSearchMaxResults\">\n <ng-template let-data>\n <mat-list *ngIf=\"searchTextInput?.isSearchBarActive()\" id=\"autocomplete-search-result-list\">\n <mat-list-item\n *ngFor=\"let item of data?.list?.entries; let idx = index\"\n id=\"result_option_{{idx}}\"\n [attr.data-automation-id]=\"'autocomplete_for_' + item.entry.name\"\n [tabindex]=\"0\"\n (blur)=\"onBlur($event)\"\n (keyup.arrowdown)=\"onRowArrowDown($event)\"\n (keyup.arrowup)=\"onRowArrowUp($event)\"\n class=\"adf-search-autocomplete-item\"\n (click)=\"elementClicked(item)\"\n (keyup.enter)=\"elementClicked(item)\"\n (touchend)=\"elementClicked(item)\">\n <!-- This is a comment -->\n <mat-icon matListItemLine>\n <img [alt]=\"getMimeType(item)\" [src]=\"getMimeTypeIcon(item)\"/>\n </mat-icon>\n <h4 matListItemTitle id=\"result_name_{{idx}}\"\n *ngIf=\"highlight; else elseBlock\"\n class=\"adf-search-fixed-text\"\n [innerHtml]=\"item.entry.name | highlight: searchTerm\">\n {{ item?.entry.name }}\n </h4>\n <ng-template #elseBlock>\n <h4 class=\"adf-search-fixed-text\" matListItemTitle id=\"result_name_{{idx}}\"\n [innerHtml]=\"item.entry.name\"></h4>\n </ng-template>\n <p matListItemLine class=\"adf-search-fixed-text\"> {{item?.entry.createdByUser.displayName}} </p>\n </mat-list-item>\n <mat-list-item id=\"search_no_result\"\n data-automation-id=\"search_no_result_found\"\n *ngIf=\"data?.list?.entries.length === 0\">\n <ng-content\n selector=\"adf-empty-search-result\"\n *ngIf=\"isNoSearchTemplatePresent() else defaultNoResult\" />\n <ng-template #defaultNoResult>\n <p matListItemLine class=\"adf-search-fixed-text\">{{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm:\n searchTerm} }}</p>\n </ng-template>\n </mat-list-item>\n </mat-list>\n </ng-template>\n </adf-search>\n</div>\n", styles: [".adf-search-result-autocomplete{min-width:112px;max-width:280px;overflow:auto;-webkit-overflow-scrolling:touch;transform-origin:top left;transform:translate(-40px);position:absolute;max-height:400px;margin-left:45px;margin-top:-22px;font-size:var(--theme-subheading-1-font-size);z-index:5;color:var(--adf-theme-foreground-text-color);background-color:var(--adf-theme-background-card-color);border-radius:2px}.adf-search-result-autocomplete:not([class*=mat-elevation-z]){box-shadow:0 3px 1px -2px #0003,0 2px 2px #00000024,0 1px 5px #0000001f}@media (max-width: 959.9px){.adf-search-result-autocomplete{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}}.adf-search-autocomplete-item:hover{background-color:var(--adf-theme-background-hover-color);opacity:1}\n"] }] }], ctorParameters: () => [{ type: i1.AuthenticationService }, { type: i1.ThumbnailService }], propDecorators: { highlight: [{ type: Input }], inputType: [{ type: Input }], liveSearchEnabled: [{ type: Input }], autocomplete: [{ type: Input }], expandable: [{ type: Input }], liveSearchMaxResults: [{ type: Input }], submit: [{ type: Output }], searchChange: [{ type: Output }], optionClicked: [{ type: Output }], searchTextInput: [{ type: ViewChild, args: ['searchTextInput'] }], searchAutocomplete: [{ type: ViewChild, args: ['search'] }], listResultElement: [{ type: ViewChildren, args: [MatListItem] }], emptySearchTemplate: [{ type: ContentChild, args: [EmptySearchResultComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLWNvbnRyb2wuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGliL2NvbnRlbnQtc2VydmljZXMvc3JjL2xpYi9zZWFyY2gvY29tcG9uZW50cy9zZWFyY2gtY29udHJvbC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9saWIvY29udGVudC1zZXJ2aWNlcy9zcmMvbGliL3NlYXJjaC9jb21wb25lbnRzL3NlYXJjaC1jb250cm9sLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxhQUFhLEVBQUUsd0JBQXdCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0SCxPQUFPLEVBQ0gsU0FBUyxFQUNULFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEVBRVQsU0FBUyxFQUNULFlBQVksRUFDWixpQkFBaUIsRUFDcEIsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNwRSxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM3RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7Ozs7OztBQVd0RCxNQUFNLE9BQU8sc0JBQXNCO0lBZ0UvQixZQUFtQixXQUFrQyxFQUFVLGdCQUFrQztRQUE5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QUNuQyxDQUFDO0lBRU8seUJBQXlCLENBQUMsSUFBYTtRQUMzQyxPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FBQztJQUN2QyxDQUFDOzhHQXpKUSxzQkFBc0I7a0dBQXRCLHNCQUFzQixzZEF5RGpCLDBCQUEwQiwwUkFIMUIsV0FBVyxnREN0RzdCLHM1R0E4REEsdXpCRHBCYyxZQUFZLGdRQUFFLHdCQUF3QixpWkFBRSxlQUFlLHlNQUFFLGFBQWEseWJBQUUsYUFBYSwrS0FBRSxhQUFhLGlEQUFFLGVBQWU7OzJGQU10SCxzQkFBc0I7a0JBVGxDLFNBQVM7K0JBQ0ksb0JBQW9CLGNBQ2xCLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSx3QkFBd0IsRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBRSxhQUFhLEVBQUUsZUFBZSxDQUFDLGlCQUdqSCxpQkFBaUIsQ0FBQyxJQUFJLFFBQy9CLEVBQUUsS0FBSyxFQUFFLG9CQUFvQixFQUFFO3lIQUtyQyxTQUFTO3NCQURSLEtBQUs7Z0JBS04sU0FBUztzQkFEUixLQUFLO2dCQUtOLGlCQUFpQjtzQkFEaEIsS0FBSztnQkFLTixZQUFZO3NCQURYLEtBQUs7Z0JBUU4sVUFBVTtzQkFEVCxLQUFLO2dCQUtOLG9CQUFvQjtzQkFEbkIsS0FBSztnQkFRTixNQUFNO3NCQURMLE1BQU07Z0JBVVAsWUFBWTtzQkFEWCxNQUFNO2dCQUtQLGFBQWE7c0JBRFosTUFBTTtnQkFJUCxlQUFlO3NCQURkLFNBQVM7dUJBQUMsaUJBQWlCO2dCQUk1QixrQkFBa0I7c0JBRGpCLFNBQVM7dUJBQUMsUUFBUTtnQkFJWCxpQkFBaUI7c0JBRHhCLFlBQVk7dUJBQUMsV0FBVztnQkFJekIsbUJBQW1CO3NCQURsQixZQUFZO3VCQUFDLDBCQUEwQiIsInNvdXJjZXNDb250ZW50IjpbIi8qIVxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCDCqSAyMDA1LTIwMjUgSHlsYW5kIFNvZnR3YXJlLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHsgQXV0aGVudGljYXRpb25TZXJ2aWNlLCBIaWdobGlnaHRQaXBlLCBTZWFyY2hUZXh0SW5wdXRDb21wb25lbnQsIFRodW1ibmFpbFNlcnZpY2UgfSBmcm9tICdAYWxmcmVzY28vYWRmLWNvcmUnO1xuaW1wb3J0IHtcbiAgICBDb21wb25lbnQsXG4gICAgQ29udGVudENoaWxkLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBJbnB1dCxcbiAgICBPdXRwdXQsXG4gICAgUXVlcnlMaXN0LFxuICAgIFRlbXBsYXRlUmVmLFxuICAgIFZpZXdDaGlsZCxcbiAgICBWaWV3Q2hpbGRyZW4sXG4gICAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOb2RlRW50cnkgfSBmcm9tICdAYWxmcmVzY28vanMtYXBpJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IFNlYXJjaENvbXBvbmVudCB9IGZyb20gJy4vc2VhcmNoLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBNYXRMaXN0SXRlbSwgTWF0TGlzdE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2xpc3QnO1xuaW1wb3J0IHsgRW1wdHlTZWFyY2hSZXN1bHRDb21wb25lbnQgfSBmcm9tICcuL2VtcHR5LXNlYXJjaC1yZXN1bHQuY29tcG9uZW50JztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBNYXRJY29uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvbic7XG5pbXBvcnQgeyBUcmFuc2xhdGVNb2R1bGUgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdhZGYtc2VhcmNoLWNvbnRyb2wnLFxuICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgU2VhcmNoVGV4dElucHV0Q29tcG9uZW50LCBTZWFyY2hDb21wb25lbnQsIE1hdExpc3RNb2R1bGUsIE1hdEljb25Nb2R1bGUsIEhpZ2hsaWdodFBpcGUsIFRyYW5zbGF0ZU1vZHVsZV0sXG4gICAgdGVtcGxhdGVVcmw6ICcuL3NlYXJjaC1jb250cm9sLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9zZWFyY2gtY29udHJvbC5jb21wb25lbnQuc2NzcyddLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gICAgaG9zdDogeyBjbGFzczogJ2FkZi1zZWFyY2gtY29udHJvbCcgfVxufSlcbmV4cG9ydCBjbGFzcyBTZWFyY2hDb250cm9sQ29tcG9uZW50IHtcbiAgICAvKiogVG9nZ2xlcyBoaWdobGlnaHRpbmcgb2YgdGhlIHNlYXJjaCB0ZXJtIGluIHRoZSByZXN1bHRzLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgaGlnaGxpZ2h0OiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogVHlwZSBvZiB0aGUgaW5wdXQgZmllbGQgdG8gcmVuZGVyLCBlLmcuIFwic2VhcmNoXCIgb3IgXCJ0ZXh0XCIgKGRlZmF1bHQpLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgaW5wdXRUeXBlOiBzdHJpbmcgPSAndGV4dCc7XG5cbiAgICAvKiogVG9nZ2xlcyBcImZpbmQtYXMteW91LXR5cGVcIiBzdWdnZXN0aW9ucyBmb3IgcG9zc2libGUgbWF0Y2hlcy4gKi9cbiAgICBASW5wdXQoKVxuICAgIGxpdmVTZWFyY2hFbmFibGVkOiBib29sZWFuID0gdHJ1ZTtcblxuICAgIC8qKiBUb2dnbGVzIGF1dG8tY29tcGxldGlvbiBvZiB0aGUgc2VhcmNoIGlucHV0IGZpZWxkLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgYXV0b2NvbXBsZXRlOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBUb2dnbGVzIHdoZXRoZXIgdG8gdXNlIGFuIGV4cGFuZGluZyBzZWFyY2ggY29udHJvbC4gSWYgZmFsc2VcbiAgICAgKiB0aGVuIGEgcmVndWxhciBpbnB1dCBpcyB1c2VkLlxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgZXhwYW5kYWJsZTogYm9vbGVhbiA9IHRydWU7XG5cbiAgICAvKiogTWF4aW11bSBudW1iZXIgb2YgcmVzdWx0cyB0byBzaG93IGluIHRoZSBsaXZlIHNlYXJjaC4gKi9cbiAgICBASW5wdXQoKVxuICAgIGxpdmVTZWFyY2hNYXhSZXN1bHRzOiBudW1iZXIgPSA1O1xuXG4gICAgLyoqXG4gICAgICogRW1pdHRlZCB3aGVuIHRoZSBzZWFyY2ggaXMgc3VibWl0dGVkIGJ5IHByZXNzaW5nIHRoZSBFTlRFUiBrZXkuXG4gICAgICogVGhlIHNlYXJjaCB0ZXJtIGlzIHByb3ZpZGVkIGFzIHRoZSB2YWx1ZSBvZiB0aGUgZXZlbnQuXG4gICAgICovXG4gICAgQE91dHB1dCgpXG4gICAgc3VibWl0OiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIC8qKlxuICAgICAqIEVtaXR0ZWQgd2hlbiB0aGUgc2VhcmNoIHRlcm0gaXMgY2hhbmdlZC4gVGhlIHNlYXJjaCB0ZXJtIGlzIHByb3ZpZGVkXG4gICAgICogaW4gdGhlICd2YWx1ZScgcHJvcGVydHkgb2YgdGhlIHJldHVybmVkIG9iamVjdC4gIElmIHRoZSB0ZXJtIGlzIGxlc3NcbiAgICAgKiB0aGFuIHRocmVlIGNoYXJhY3RlcnMgaW4gbGVuZ3RoIHRoZW4gaXQgaXMgdHJ1bmNhdGVkIHRvIGFuIGVtcHR5XG4gICAgICogc3RyaW5nLlxuICAgICAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHNlYXJjaENoYW5nZTogRXZlbnRFbWl0dGVyPHN0cmluZz4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICAvKiogRW1pdHRlZCB3aGVuIGEgZmlsZSBpdGVtIGZyb20gdGhlIGxpc3Qgb2YgXCJmaW5kLWFzLXlvdS10eXBlXCIgcmVzdWx0cyBpcyBzZWxlY3RlZC4gKi9cbiAgICBAT3V0cHV0KClcbiAgICBvcHRpb25DbGlja2VkOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIEBWaWV3Q2hpbGQoJ3NlYXJjaFRleHRJbnB1dCcpXG4gICAgc2VhcmNoVGV4dElucHV0OiBTZWFyY2hUZXh0SW5wdXRDb21wb25lbnQ7XG5cbiAgICBAVmlld0NoaWxkKCdzZWFyY2gnKVxuICAgIHNlYXJjaEF1dG9jb21wbGV0ZTogU2VhcmNoQ29tcG9uZW50O1xuXG4gICAgQFZpZXdDaGlsZHJlbihNYXRMaXN0SXRlbSlcbiAgICBwcml2YXRlIGxpc3RSZXN1bHRFbGVtZW50OiBRdWVyeUxpc3Q8TWF0TGlzdEl0ZW0+O1xuXG4gICAgQENvbnRlbnRDaGlsZChFbXB0eVNlYXJjaFJlc3VsdENvbXBvbmVudClcbiAgICBlbXB0eVNlYXJjaFRlbXBsYXRlOiBFbXB0eVNlYXJjaFJlc3VsdENvbXBvbmVudDtcblxuICAgIGZvY3VzU3ViamVjdCA9IG5ldyBTdWJqZWN0PEZvY3VzRXZlbnQ+KCk7XG4gICAgbm9TZWFyY2hSZXN1bHRUZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PiA9IG51bGw7XG4gICAgc2VhcmNoVGVybTogc3RyaW5nID0gJyc7XG5cbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgYXV0aFNlcnZpY2U6IEF1dGhlbnRpY2F0aW9uU2VydmljZSwgcHJpdmF0ZSB0aHVtYm5haWxTZXJ2aWNlOiBUaHVtYm5haWxTZXJ2aWNlKSB7fVxuXG4gICAgaXNOb1NlYXJjaFRlbXBsYXRlUHJlc2VudCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5lbXB0eVNlYXJjaFRlbXBsYXRlO1xuICAgIH1cbiAgICBpc0xvZ2dlZEluKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5hdXRoU2VydmljZS5pc0VjbUxvZ2dlZEluKCk7XG4gICAgfVxuXG4gICAgaW5wdXRDaGFuZ2UodmFsdWU6IHN0cmluZykge1xuICAgICAgICB0aGlzLnNlYXJjaFRlcm0gPSB2YWx1ZTtcbiAgICAgICAgdGhpcy5zZWFyY2hDaGFuZ2UuZW1pdCh2YWx1ZSk7XG4gICAgfVxuXG4gICAgZ2V0TWltZVR5cGVJY29uKG5vZGU6IE5vZGVFbnRyeSk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IG1pbWVUeXBlID0gdGhpcy5nZXRNaW1lVHlwZShub2RlKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudGh1bWJuYWlsU2VydmljZS5nZXRNaW1lVHlwZUljb24obWltZVR5cGUpO1xuICAgIH1cblxuICAgIGdldE1pbWVUeXBlKG5vZGU6IE5vZGVFbnRyeSk6IHN0cmluZyB7XG4gICAgICAgIGxldCBtaW1lVHlwZTogc3RyaW5nO1xuXG4gICAgICAgIGlmIChub2RlLmVudHJ5LmNvbnRlbnQ/Lm1pbWVUeXBlKSB7XG4gICAgICAgICAgICBtaW1lVHlwZSA9IG5vZGUuZW50cnkuY29udGVudC5taW1lVHlwZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobm9kZS5lbnRyeS5pc0ZvbGRlcikge1xuICAgICAgICAgICAgbWltZVR5cGUgPSAnZm9sZGVyJztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbWltZVR5cGU7XG4gICAgfVxuXG4gICAgZWxlbWVudENsaWNrZWQoaXRlbTogYW55KSB7XG4gICAgICAgIGlmIChpdGVtLmVudHJ5KSB7XG4gICAgICAgICAgICB0aGlzLm9wdGlvbkNsaWNrZWQubmV4dChpdGVtKTtcbiAgICAgICAgICAgIHRoaXMuZm9jdXNTdWJqZWN0Lm5leHQobmV3IEZvY3VzRXZlbnQoJ2JsdXInKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvbkZvY3VzKGV2ZW50OiBGb2N1c0V2ZW50KTogdm9pZCB7XG4gICAgICAgIHRoaXMuZm9jdXNTdWJqZWN0Lm5leHQoZXZlbnQpO1xuICAgIH1cblxuICAgIG9uQmx1cihldmVudDogRm9jdXNFdmVudCk6IHZvaWQge1xuICAgICAgICBjb25zdCBuZXh0RWxlbWVudDogYW55ID0gdGhpcy5nZXROZXh0RWxlbWVudFNpYmxpbmcoZXZlbnQudGFyZ2V0IGFzIEVsZW1lbnQpO1xuICAgICAgICBpZiAoIW5leHRFbGVtZW50ICYmICF0aGlzLmlzTGlzdEVsZW1lbnQoZXZlbnQpKSB7XG4gICAgICAgICAgICB0aGlzLmZvY3VzU3ViamVjdC5uZXh0KGV2ZW50KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uU2VsZWN0Rmlyc3RSZXN1bHQoKSB7XG4gICAgICAgIGlmICh0aGlzLmxpc3RSZXN1bHRFbGVtZW50ICYmIHRoaXMubGlzdFJlc3VsdEVsZW1lbnQubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc3QgZmlyc3RFbGVtZW50ID0gdGhpcy5saXN0UmVzdWx0RWxlbWVudC5maXJzdCBhcyBNYXRMaXN0SXRlbTtcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlcnNjb3JlLWRhbmdsZVxuICAgICAgICAgICAgZmlyc3RFbGVtZW50Ll9ob3N0RWxlbWVudC5mb2N1cygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25Sb3dBcnJvd0Rvd24oZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IG5leHRFbGVtZW50OiBhbnkgPSB0aGlzLmdldE5leHRFbGVtZW50U2libGluZyhldmVudC50YXJnZXQgYXMgRWxlbWVudCk7XG4gICAgICAgIGlmIChuZXh0RWxlbWVudCkge1xuICAgICAgICAgICAgbmV4dEVsZW1lbnQuZm9jdXMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uUm93QXJyb3dVcChldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNFbGVtZW50OiBhbnkgPSB0aGlzLmdldFByZXZpb3VzRWxlbWVudFNpYmxpbmcoZXZlbnQudGFyZ2V0IGFzIEVsZW1lbnQpO1xuICAgICAgICBpZiAocHJldmlvdXNFbGVtZW50KSB7XG4gICAgICAgICAgICBwcmV2aW91c0VsZW1lbnQuZm9jdXMoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZm9jdXNTdWJqZWN0Lm5leHQobmV3IEZvY3VzRXZlbnQoJ2ZvY3VzJykpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25SZXNldChzdGF0dXM6IGJvb2xlYW4pIHtcbiAgICAgICAgaWYgKHN0YXR1cykge1xuICAgICAgICAgICAgdGhpcy5zZWFyY2hBdXRvY29tcGxldGUucmVzZXRSZXN1bHRzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGlzTGlzdEVsZW1lbnQoZXZlbnQ6IGFueSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZXZlbnQucmVsYXRlZFRhcmdldD8uY2hpbGRyZW5bMF0gJiYgZXZlbnQucmVsYXRlZFRhcmdldC5jaGlsZHJlblswXS5jbGFzc05hbWUgPT09ICdtYXQtbGlzdC1pdGVtLWNvbnRlbnQnO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0TmV4dEVsZW1lbnRTaWJsaW5nKG5vZGU6IEVsZW1lbnQpOiBFbGVtZW50IHtcbiAgICAgICAgcmV0dXJuIG5vZGUubmV4dEVsZW1lbnRTaWJsaW5nO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0UHJldmlvdXNFbGVtZW50U2libGluZyhub2RlOiBFbGVtZW50KTogRWxlbWVudCB7XG4gICAgICAgIHJldHVybiBub2RlLnByZXZpb3VzRWxlbWVudFNpYmxpbmc7XG4gICAgfVxufVxuIiwiPGRpdiAqbmdJZj1cImlzTG9nZ2VkSW4oKVwiPlxuICAgIDxhZGYtc2VhcmNoLXRleHQtaW5wdXQgICNzZWFyY2hUZXh0SW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBbc2VhcmNoVGVybV09IFwic2VhcmNoVGVybVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgW2V4cGFuZGFibGVdPVwiZXhwYW5kYWJsZVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgW2F1dG9jb21wbGV0ZV09XCJhdXRvY29tcGxldGVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtsaXZlU2VhcmNoRW5hYmxlZF09XCJsaXZlU2VhcmNoRW5hYmxlZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgW2ZvY3VzTGlzdGVuZXJdPVwiZm9jdXNTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBbc2VhcmNoQXV0b2NvbXBsZXRlXT1cImF1dG9cIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChzZWFyY2hDaGFuZ2UpPVwiaW5wdXRDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlc2V0KT1cIm9uUmVzZXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHNlbGVjdFJlc3VsdCk9XCJvblNlbGVjdEZpcnN0UmVzdWx0KClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChzdWJtaXQpPVwic3VibWl0LmVtaXQoJGV2ZW50KVwiIC8+XG5cbiAgICA8YWRmLXNlYXJjaCAjc2VhcmNoXG4gICAgICAgICAgICAgICAgI2F1dG89XCJzZWFyY2hBdXRvY29tcGxldGVcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYWRmLXNlYXJjaC1yZXN1bHQtYXV0b2NvbXBsZXRlXCJcbiAgICAgICAgICAgICAgICBbbWF4UmVzdWx0c109XCJsaXZlU2VhcmNoTWF4UmVzdWx0c1wiPlxuICAgICAgICA8bmctdGVtcGxhdGUgbGV0LWRhdGE+XG4gICAgICAgICAgICA8bWF0LWxpc3QgKm5nSWY9XCJzZWFyY2hUZXh0SW5wdXQ/LmlzU2VhcmNoQmFyQWN0aXZlKClcIiBpZD1cImF1dG9jb21wbGV0ZS1zZWFyY2gtcmVzdWx0LWxpc3RcIj5cbiAgICAgICAgICAgICAgICA8bWF0LWxpc3QtaXRlbVxuICAgICAgICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgaXRlbSBvZiBkYXRhPy5saXN0Py5lbnRyaWVzOyBsZXQgaWR4ID0gaW5kZXhcIlxuICAgICAgICAgICAgICAgICAgICBpZD1cInJlc3VsdF9vcHRpb25fe3tpZHh9fVwiXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtYXV0b21hdGlvbi1pZF09XCInYXV0b2NvbXBsZXRlX2Zvcl8nICsgaXRlbS5lbnRyeS5uYW1lXCJcbiAgICAgICAgICAgICAgICAgICAgW3RhYmluZGV4XT1cIjBcIlxuICAgICAgICAgICAgICAgICAgICAoYmx1cik9XCJvbkJsdXIoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIChrZXl1cC5hcnJvd2Rvd24pPVwib25Sb3dBcnJvd0Rvd24oJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIChrZXl1cC5hcnJvd3VwKT1cIm9uUm93QXJyb3dVcCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJhZGYtc2VhcmNoLWF1dG9jb21wbGV0ZS1pdGVtXCJcbiAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cImVsZW1lbnRDbGlja2VkKGl0ZW0pXCJcbiAgICAgICAgICAgICAgICAgICAgKGtleXVwLmVudGVyKT1cImVsZW1lbnRDbGlja2VkKGl0ZW0pXCJcbiAgICAgICAgICAgICAgICAgICAgKHRvdWNoZW5kKT1cImVsZW1lbnRDbGlja2VkKGl0ZW0pXCI+XG4gICAgICAgICAgICAgICAgICAgIDwhLS0gVGhpcyBpcyBhIGNvbW1lbnQgLS0+XG4gICAgICAgICAgICAgICAgICAgIDxtYXQtaWNvbiBtYXRMaXN0SXRlbUxpbmU+XG4gICAgICAgICAgICAgICAgICAgICAgICA8aW1nIFthbHRdPVwiZ2V0TWltZVR5cGUoaXRlbSlcIiBbc3JjXT1cImdldE1pbWVUeXBlSWNvbihpdGVtKVwiLz5cbiAgICAgICAgICAgICAgICAgICAgPC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgICAgICAgPGg0IG1hdExpc3RJdGVtVGl0bGUgaWQ9XCJyZXN1bHRfbmFtZV97e2lkeH19XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICpuZ0lmPVwiaGlnaGxpZ2h0OyBlbHNlIGVsc2VCbG9ja1wiXG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImFkZi1zZWFyY2gtZml4ZWQtdGV4dFwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbaW5uZXJIdG1sXT1cIml0ZW0uZW50cnkubmFtZSB8IGhpZ2hsaWdodDogc2VhcmNoVGVybVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAge3sgaXRlbT8uZW50cnkubmFtZSB9fVxuICAgICAgICAgICAgICAgICAgICA8L2g0PlxuICAgICAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgI2Vsc2VCbG9jaz5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxoNCBjbGFzcz1cImFkZi1zZWFyY2gtZml4ZWQtdGV4dFwiIG1hdExpc3RJdGVtVGl0bGUgaWQ9XCJyZXN1bHRfbmFtZV97e2lkeH19XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBbaW5uZXJIdG1sXT1cIml0ZW0uZW50cnkubmFtZVwiPjwvaDQ+XG4gICAgICAgICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICAgICAgICAgIDxwIG1hdExpc3RJdGVtTGluZSBjbGFzcz1cImFkZi1zZWFyY2gtZml4ZWQtdGV4dFwiPiB7e2l0ZW0/LmVudHJ5LmNyZWF0ZWRCeVVzZXIuZGlzcGxheU5hbWV9fSA8L3A+XG4gICAgICAgICAgICAgICAgPC9tYXQtbGlzdC1pdGVtPlxuICAgICAgICAgICAgICAgIDxtYXQtbGlzdC1pdGVtIGlkPVwic2VhcmNoX25vX3Jlc3VsdFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS1hdXRvbWF0aW9uLWlkPVwic2VhcmNoX25vX3Jlc3VsdF9mb3VuZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCJkYXRhPy5saXN0Py5lbnRyaWVzLmxlbmd0aCA9PT0gMFwiPlxuICAgICAgICAgICAgICAgICAgICA8bmctY29udGVudFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0b3I9XCJhZGYtZW1wdHktc2VhcmNoLXJlc3VsdFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAqbmdJZj1cImlzTm9TZWFyY2hUZW1wbGF0ZVByZXNlbnQoKSBlbHNlIGRlZmF1bHROb1Jlc3VsdFwiIC8+XG4gICAgICAgICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjZGVmYXVsdE5vUmVzdWx0PlxuICAgICAgICAgICAgICAgICAgICAgICAgPHAgbWF0TGlzdEl0ZW1MaW5lIGNsYXNzPVwiYWRmLXNlYXJjaC1maXhlZC10ZXh0XCI+e3sgJ1NFQVJDSC5SRVNVTFRTLk5PTkUnIHwgdHJhbnNsYXRlOntzZWFyY2hUZXJtOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXJjaFRlcm19IH19PC9wPlxuICAgICAgICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgICAgIDwvbWF0LWxpc3QtaXRlbT5cbiAgICAgICAgICAgIDwvbWF0LWxpc3Q+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPC9hZGYtc2VhcmNoPlxuPC9kaXY+XG4iXX0=