@rangertechnologies/ngnxt
Version:
This library was used for creating dymanic UI based on the input JSON/data
213 lines • 38.5 kB
JavaScript
import { Component, Input, Output, EventEmitter, ViewChild, } from "@angular/core";
import { ChangeWrapper } from "../../model/changeWrapper";
import * as i0 from "@angular/core";
import * as i1 from "../../services/data.service";
import * as i2 from "../../i18n.service";
import * as i3 from "@angular/common";
import * as i4 from "@angular/forms";
export class SearchBoxComponent {
dataService;
i18nService;
placeHolderText;
auto;
question;
apiMeta;
id;
readOnly = false; // VD 12Jun24 - readonly change
searchValueChange = new EventEmitter();
apiObj;
SearchItem;
filterName; // VD 20Aug default filter value as input
finalResults = [];
searchKeyWord = '';
newResult;
showResult = false;
noResult = false;
showSuggestion = true;
el;
serv = 'api';
tkn = '';
constructor(dataService, i18nService) {
this.dataService = dataService;
this.i18nService = i18nService;
}
ngOnInit() {
// VD 03May- search changes
// AP-26MAR25 Ensure ques.subText is always an object by parsing it if it's a string
if (this.apiMeta) {
this.apiMeta = typeof this.apiMeta === 'object' ? this.apiMeta : JSON.parse(this.apiMeta);
let apiObj = this.apiMeta;
this.SearchItem = apiObj.field;
}
}
////RS 03FEB2025
// Resets state when filterName or apiMeta changes to reflect updated data
// AP-26MAR25 Ensure ques.subText is always an object by parsing it if it's a string
ngOnChanges(changes) {
if (changes['apiMeta'] && this.apiMeta) {
this.apiMeta = typeof this.apiMeta === 'object' ? this.apiMeta : JSON.parse(this.apiMeta);
this.apiObj = this.apiMeta;
this.SearchItem = this.apiObj?.field;
}
}
//RS 03FEB2025
// Clears search-related data, including results, search term, and suggestions.
resetComponentState() {
this.finalResults = [];
this.filterName = '';
this.searchKeyWord = '';
this.showSuggestion = false;
this.noResult = false;
}
clearList() {
setTimeout(() => {
this.finalResults = [];
}, 1000);
}
getSourceDataLocal(event) {
event.preventDefault();
if (event.target.value.length > 2) {
this.showSuggestion = true;
this.finalResults = [];
this.searchKeyWord = event.target.value;
this.showResult = false;
this.getSourceData(event.target.value);
}
else {
this.showSuggestion = false;
this.finalResults = [];
this.noResult = false;
}
}
// VD 03May- search changes
// VD 31NOV24 null check
// RS 29JAN25
//Multi-word search across all object values
getSourceData = (keyword) => {
// MSM-27MAR25 Ensure ques.subText is always an object by parsing it if it's a string
if (this.apiMeta) {
this.apiMeta = typeof this.apiMeta === 'object' ? this.apiMeta : JSON.parse(this.apiMeta);
let apiObj = this.apiMeta;
this.dataService.apiResponse(apiObj.endpoint).subscribe((apiResponse) => {
let response;
if (apiObj.variable) {
response = this.dataService.getValue(apiResponse, apiObj.variable);
}
else {
response = apiResponse;
}
let results = [];
let searchTerms = keyword.toLowerCase()?.split(" ");
for (let i = 0; i < response.length; i++) {
let obj = response[i];
let combinedValues = this.getCombinedValuesFromColumns(obj, apiObj.field);
let match = searchTerms.every(term => combinedValues.includes(term));
if (match) {
results.push(obj);
}
}
this.noResult = results.length === 0;
this.finalResults = results;
});
}
};
// SKS27FEB Helper functions
getNestedValue(obj, path) {
//SKS27FEB Convert array indexes to dot notation (e.g., [0] -> .0)
const processedPath = path.replace(/\[(\d+)\]/g, '.$1');
const parts = processedPath.split('.');
let current = obj;
for (const part of parts) {
if (!current || typeof current !== 'object')
return '';
current = current[part];
}
return current !== null && current !== undefined
? String(current).toLowerCase().trim()
: '';
}
getCombinedValuesFromColumns(obj, columns) {
const values = [];
// SKS28FEB check if columns is an array
if (typeof columns === 'string' && !Array.isArray(columns)) {
columns = [columns];
}
for (const column of columns) {
const value = this.getNestedValue(obj, column);
if (value) {
values.push(value);
}
}
return values.join(' ');
}
// SKS27FEB get value from data specific column
getValues(element, columns) {
const result = {};
// SKS28FEB check if columns is an array
if (typeof columns === 'string' && !Array.isArray(columns)) {
columns = [columns];
}
columns.forEach((column) => {
let tempElement = element;
let flds = column?.split('.');
for (let i = 0; i < flds.length; i++) {
let splitFlds = flds[i]?.split('[');
if (splitFlds.length === 1) {
tempElement = tempElement[flds[i]] || '';
}
else {
let index = Number(splitFlds[1]?.split(']')[0]);
tempElement = tempElement[splitFlds[0]]?.[index] || '';
}
}
result[column] = tempElement;
});
return result;
}
// SKS27FEB column value get funtion
getKeys(obj) {
return Object.keys(obj);
}
clickItem(event) {
// console.log('inside clickItem of ' + JSON.stringify(event, null, 2));
// MSM-27MAR25 Ensure ques.subText is always an object by parsing it if it's a string
if (this.apiMeta) {
this.apiMeta = typeof this.apiMeta === 'object' ? this.apiMeta : JSON.parse(this.apiMeta);
let apiObj = this.apiMeta;
// let apiObj: APIMeta = JSON.parse(this.apiMeta);
this.filterName = event[apiObj.defaultField || apiObj.field[0] || apiObj.field]; //SKS27FEB defaultField is used for showing a search field input if field have array of data
let change = new ChangeWrapper(); // ChangeWrapper = JSON.parse('{}');
change.fromQuestionId = this.id;
change.valueObj = event;
change.field = apiObj.field;
this.searchValueChange.emit(change);
}
}
//RS 03FEB2025
// Resets component state when the component is destroyed
ngOnDestroy() { this.resetComponentState(); }
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchBoxComponent, deps: [{ token: i1.DataService }, { token: i2.I18nService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: SearchBoxComponent, selector: "lib-search-box", inputs: { placeHolderText: "placeHolderText", question: "question", apiMeta: "apiMeta", id: "id", readOnly: "readOnly", filterName: "filterName" }, outputs: { searchValueChange: "searchValueChange" }, viewQueries: [{ propertyName: "auto", first: true, predicate: ["auto"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- // VD 12Jun24 - readonly change-->\n<div id=\"autocomplete-input\"> <!-- SKS5NOV25 search icon -->\n <input #auto id=\"searchbox-style\"\n (blur)=\"clearList()\"\n [(ngModel)]=\"filterName\"\n type=\"text\"\n name=\"name\"\n [readOnly]=\"readOnly\"\n [placeholder]=\"placeHolderText\"\n style=\"margin: 0 !important; padding-right: 30px;\"\n class=\"searchInput she-line-input form-control\"\n (focusin)=\"getSourceDataLocal($event)\"\n (input)=\"getSourceDataLocal($event)\">\n <div id=\"selectList\" style=\"position: absolute;position: absolute;background: white;z-index: 2;\">\n <div *ngIf=\"finalResults.length > 0 && showSuggestion\"\n style=\"max-height: 20vh;border: 1px solid #d2d4d6;overflow: scroll; min-width:100px\"\n class=\"suggestions-container\">\n <!-- HA 20DEC23 Uncommented the logic -->\n <!-- VD 03May- search changes -->\n <div *ngFor=\"let item of finalResults\" (click)='clickItem(item)' class=\"hoover\">\n <!-- VD 26Jun24 - id condition removed -->\n <div class=\"grid-x align-middle\" style=\"\">\n <div *ngIf=\"item.thumbnail\" class=\"cell shrink\" style=\"width: 60px; margin-right: 1.6rem;\">\n <img [src]=\"item.thumbnail\" style=\"width: 60px;\" alt=\"\">\n </div>\n <div class=\"cell auto\" style=\"text-align: left; padding:5px 8px 0 8px; display: flex; gap: 5px; \">\n <!--// VD 26JUN24 - pipe changes -->\n <!-- RS 29JAN25 -->\n <div style=\"display: flex;\" *ngFor=\"let key of getKeys(getValues(item, SearchItem))\">\n <div>\n {{ getValues(item, SearchItem)[key] }}\n </div>\n </div> \n </div>\n </div>\n </div>\n <!-- HA 20DEC23 For Commented this for future purpose -->\n <!-- <table class=\"table table-striped table-bordered\">\n <thead>\n <tr>\n <th>{{ 'firstName' | i18n:i18nService.currentLanguage }}</th>\n <th>{{ 'lastName' | i18n:i18nService.currentLanguage }}</th>\n <th>{{ 'division' | i18n:i18nService.currentLanguage }}</th>\n <th>{{ 'numberPlate' | i18n:i18nService.currentLanguage }}</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let item of finalResults\" (click)='clickItem(item)'>\n <td>{{ item.firstName }}</td>\n <td>{{ item.lastName }}</td>\n <td>{{ item.division }}</td>\n <td>{{ item.numberPlate }}</td>\n </tr>\n </tbody>\n </table> -->\n </div>\n</div>\n\n", styles: ["#searchbox-style{background-image:url('data:image/svg+xml;utf8,<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"%23434555\" stroke-opacity=\"0.65\" stroke-width=\"2\"/><path d=\"M20 20L17 17\" stroke=\"%23434555\" stroke-opacity=\"0.65\" stroke-width=\"2\" stroke-linecap=\"round\"/></svg>');background-position:right 5px center;background-repeat:no-repeat;background-size:24px;padding-right:35px}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchBoxComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-search-box', template: "<!-- // VD 12Jun24 - readonly change-->\n<div id=\"autocomplete-input\"> <!-- SKS5NOV25 search icon -->\n <input #auto id=\"searchbox-style\"\n (blur)=\"clearList()\"\n [(ngModel)]=\"filterName\"\n type=\"text\"\n name=\"name\"\n [readOnly]=\"readOnly\"\n [placeholder]=\"placeHolderText\"\n style=\"margin: 0 !important; padding-right: 30px;\"\n class=\"searchInput she-line-input form-control\"\n (focusin)=\"getSourceDataLocal($event)\"\n (input)=\"getSourceDataLocal($event)\">\n <div id=\"selectList\" style=\"position: absolute;position: absolute;background: white;z-index: 2;\">\n <div *ngIf=\"finalResults.length > 0 && showSuggestion\"\n style=\"max-height: 20vh;border: 1px solid #d2d4d6;overflow: scroll; min-width:100px\"\n class=\"suggestions-container\">\n <!-- HA 20DEC23 Uncommented the logic -->\n <!-- VD 03May- search changes -->\n <div *ngFor=\"let item of finalResults\" (click)='clickItem(item)' class=\"hoover\">\n <!-- VD 26Jun24 - id condition removed -->\n <div class=\"grid-x align-middle\" style=\"\">\n <div *ngIf=\"item.thumbnail\" class=\"cell shrink\" style=\"width: 60px; margin-right: 1.6rem;\">\n <img [src]=\"item.thumbnail\" style=\"width: 60px;\" alt=\"\">\n </div>\n <div class=\"cell auto\" style=\"text-align: left; padding:5px 8px 0 8px; display: flex; gap: 5px; \">\n <!--// VD 26JUN24 - pipe changes -->\n <!-- RS 29JAN25 -->\n <div style=\"display: flex;\" *ngFor=\"let key of getKeys(getValues(item, SearchItem))\">\n <div>\n {{ getValues(item, SearchItem)[key] }}\n </div>\n </div> \n </div>\n </div>\n </div>\n <!-- HA 20DEC23 For Commented this for future purpose -->\n <!-- <table class=\"table table-striped table-bordered\">\n <thead>\n <tr>\n <th>{{ 'firstName' | i18n:i18nService.currentLanguage }}</th>\n <th>{{ 'lastName' | i18n:i18nService.currentLanguage }}</th>\n <th>{{ 'division' | i18n:i18nService.currentLanguage }}</th>\n <th>{{ 'numberPlate' | i18n:i18nService.currentLanguage }}</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let item of finalResults\" (click)='clickItem(item)'>\n <td>{{ item.firstName }}</td>\n <td>{{ item.lastName }}</td>\n <td>{{ item.division }}</td>\n <td>{{ item.numberPlate }}</td>\n </tr>\n </tbody>\n </table> -->\n </div>\n</div>\n\n", styles: ["#searchbox-style{background-image:url('data:image/svg+xml;utf8,<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"%23434555\" stroke-opacity=\"0.65\" stroke-width=\"2\"/><path d=\"M20 20L17 17\" stroke=\"%23434555\" stroke-opacity=\"0.65\" stroke-width=\"2\" stroke-linecap=\"round\"/></svg>');background-position:right 5px center;background-repeat:no-repeat;background-size:24px;padding-right:35px}\n"] }]
}], ctorParameters: () => [{ type: i1.DataService }, { type: i2.I18nService }], propDecorators: { placeHolderText: [{
type: Input
}], auto: [{
type: ViewChild,
args: ['auto']
}], question: [{
type: Input
}], apiMeta: [{
type: Input
}], id: [{
type: Input
}], readOnly: [{
type: Input
}], searchValueChange: [{
type: Output
}], filterName: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLWJveC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9ueHQtYXBwL3NyYy9saWIvY29tcG9uZW50cy9zZWFyY2gtYm94L3NlYXJjaC1ib3guY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbnh0LWFwcC9zcmMvbGliL2NvbXBvbmVudHMvc2VhcmNoLWJveC9zZWFyY2gtYm94LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osU0FBUyxHQUVWLE1BQU0sZUFBZSxDQUFDO0FBSXZCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQzs7Ozs7O0FBUzFELE1BQU0sT0FBTyxrQkFBa0I7SUF1QlI7SUFBaUM7SUF0QjdDLGVBQWUsQ0FBUztJQUNkLElBQUksQ0FBQztJQUVmLFFBQVEsQ0FBQztJQUNULE9BQU8sQ0FBUztJQUNoQixFQUFFLENBQVM7SUFDWCxRQUFRLEdBQUcsS0FBSyxDQUFDLENBQUMsK0JBQStCO0lBQ2hELGlCQUFpQixHQUFnQyxJQUFJLFlBQVksRUFBaUIsQ0FBQztJQUM1RixNQUFNLENBQUs7SUFDWCxVQUFVLENBQU07SUFFUixVQUFVLENBQVMsQ0FBQyx5Q0FBeUM7SUFDL0QsWUFBWSxHQUFVLEVBQUUsQ0FBQztJQUN6QixhQUFhLEdBQVcsRUFBRSxDQUFDO0lBQzNCLFNBQVMsQ0FBTTtJQUNmLFVBQVUsR0FBRyxLQUFLLENBQUM7SUFDbkIsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUNqQixjQUFjLEdBQUcsSUFBSSxDQUFDO0lBQ3JCLEVBQUUsQ0FBYztJQUNoQixJQUFJLEdBQVcsS0FBSyxDQUFDO0lBQ3JCLEdBQUcsR0FBVyxFQUFFLENBQUM7SUFFekIsWUFBcUIsV0FBd0IsRUFBUyxXQUF3QjtR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QUFHLEtBQUssQ0FBQztZQUN4QixNQUFNLENBQUMsS0FBSyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUM7WUFDNUIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0QyxDQUFDO0lBQ0QsQ0FBQztJQUNELGNBQWM7SUFDZCx5REFBeUQ7SUFDekQsV0FBVyxLQUFXLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUUsQ0FBQzt3R0F2THpDLGtCQUFrQjs0RkFBbEIsa0JBQWtCLGtYQ3JCL0IsMnRGQTBEQTs7NEZEckNhLGtCQUFrQjtrQkFMOUIsU0FBUzsrQkFDRSxnQkFBZ0I7MEdBS2pCLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ2EsSUFBSTtzQkFBdEIsU0FBUzt1QkFBQyxNQUFNO2dCQUVSLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNHLEVBQUU7c0JBQVYsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNJLGlCQUFpQjtzQkFBMUIsTUFBTTtnQkFJRSxVQUFVO3NCQUFsQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBPbkluaXQsXG4gIElucHV0LFxuICBPdXRwdXQsXG4gIEV2ZW50RW1pdHRlcixcbiAgVmlld0NoaWxkLFxuICBTaW1wbGVDaGFuZ2VzLFxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgRGF0YVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9kYXRhLnNlcnZpY2UnO1xuLy8gVkQgMjNKQU4yNCByZW1vdmVkIGh0dHBDbGllbnQgaW1wb3J0IHVzZWQgc2VydmljZSBmaWxlIGZvciBjYWxsb3V0XG5pbXBvcnQgeyBBUElNZXRhIH0gZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvYXBpbWV0YVwiO1xuaW1wb3J0IHsgQ2hhbmdlV3JhcHBlciB9IGZyb20gXCIuLi8uLi9tb2RlbC9jaGFuZ2VXcmFwcGVyXCI7XG4vLyBIQSAxOURFQzIzIGltcG9ydGVkIHRyYW5zbGF0aW9uIHNlcnZpY2VcbmltcG9ydCB7IEkxOG5TZXJ2aWNlIH0gZnJvbSBcIi4uLy4uL2kxOG4uc2VydmljZVwiO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdsaWItc2VhcmNoLWJveCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9zZWFyY2gtYm94LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc2VhcmNoLWJveC5jb21wb25lbnQuY3NzJ11cbn0pXG5leHBvcnQgY2xhc3MgU2VhcmNoQm94Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgQElucHV0KCkgcGxhY2VIb2xkZXJUZXh0OiBzdHJpbmc7XG4gIEBWaWV3Q2hpbGQoJ2F1dG8nKSBhdXRvO1xuXG4gIEBJbnB1dCgpIHF1ZXN0aW9uO1xuICBASW5wdXQoKSBhcGlNZXRhOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGlkOiBzdHJpbmc7XG4gIEBJbnB1dCgpIHJlYWRPbmx5ID0gZmFsc2U7IC8vIFZEIDEySnVuMjQgLSByZWFkb25seSBjaGFuZ2VcbiAgQE91dHB1dCgpIHNlYXJjaFZhbHVlQ2hhbmdlOiBFdmVudEVtaXR0ZXI8Q2hhbmdlV3JhcHBlcj4gPSBuZXcgRXZlbnRFbWl0dGVyPENoYW5nZVdyYXBwZXI+KCk7XG4gICBhcGlPYmo6YW55O1xuICAgU2VhcmNoSXRlbTogYW55O1xuXG4gIEBJbnB1dCgpIGZpbHRlck5hbWU6IHN0cmluZzsgLy8gVkQgMjBBdWcgZGVmYXVsdCBmaWx0ZXIgdmFsdWUgYXMgaW5wdXRcbiAgcHVibGljIGZpbmFsUmVzdWx0czogYW55W10gPSBbXTtcbiAgcHVibGljIHNlYXJjaEtleVdvcmQ6IHN0cmluZyA9ICcnO1xuICBwdWJsaWMgbmV3UmVzdWx0OiBhbnk7XG4gIHB1YmxpYyBzaG93UmVzdWx0ID0gZmFsc2U7XG4gIHB1YmxpYyBub1Jlc3VsdCA9IGZhbHNlO1xuICBwdWJsaWMgc2hvd1N1Z2dlc3Rpb24gPSB0cnVlO1xuICBwcml2YXRlIGVsOiBIVE1MRWxlbWVudDtcbiAgcHJpdmF0ZSBzZXJ2OiBzdHJpbmcgPSAnYXBpJztcbiAgcHJpdmF0ZSB0a246IHN0cmluZyA9ICcnO1xuICBcbiAgY29uc3RydWN0b3IoIHByaXZhdGUgZGF0YVNlcnZpY2U6IERhdGFTZXJ2aWNlLCBwdWJsaWMgaTE4blNlcnZpY2U6IEkxOG5TZXJ2aWNlKSB7IH1cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgLy8gIFZEIDAzTWF5LSBzZWFyY2ggY2hhbmdlc1xuICAgICAvLyBBUC0yNk1BUjI1IEVuc3VyZSBxdWVzLnN1YlRleHQgaXMgYWx3YXlzIGFuIG9iamVjdCBieSBwYXJzaW5nIGl0IGlmIGl0J3MgYSBzdHJpbmdcbiAgICBpZih0aGlzLmFwaU1ldGEpe1xuICAgICAgdGhpcy5hcGlNZXRhID0gdHlwZW9mIHRoaXMuYXBpTWV0YSA9PT0gJ29iamVjdCcgPyB0aGlzLmFwaU1ldGEgOiBKU09OLnBhcnNlKHRoaXMuYXBpTWV0YSk7XG4gICAgICBsZXQgYXBpT2JqOiBhbnkgPSB0aGlzLmFwaU1ldGE7XG4gICAgICB0aGlzLlNlYXJjaEl0ZW0gPSBhcGlPYmouZmllbGQ7XG4gICAgfVxuICB9XG4vLy8vUlMgMDNGRUIyMDI1XG4vLyBSZXNldHMgc3RhdGUgd2hlbiBmaWx0ZXJOYW1lIG9yIGFwaU1ldGEgY2hhbmdlcyB0byByZWZsZWN0IHVwZGF0ZWQgZGF0YVxuIC8vIEFQLTI2TUFSMjUgRW5zdXJlIHF1ZXMuc3ViVGV4dCBpcyBhbHdheXMgYW4gb2JqZWN0IGJ5IHBhcnNpbmcgaXQgaWYgaXQncyBhIHN0cmluZ1xubmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICBpZiAoY2hhbmdlc1snYXBpTWV0YSddICYmIHRoaXMuYXBpTWV0YSkge1xuICAgIHRoaXMuYXBpTWV0YSA9IHR5cGVvZiB0aGlzLmFwaU1ldGEgPT09ICdvYmplY3QnID8gdGhpcy5hcGlNZXRhIDogSlNPTi5wYXJzZSh0aGlzLmFwaU1ldGEpO1xuICAgIHRoaXMuYXBpT2JqID0gdGhpcy5hcGlNZXRhO1xuICAgIHRoaXMuU2VhcmNoSXRlbSA9IHRoaXMuYXBpT2JqPy5maWVsZDtcbiAgfVxufVxuLy9SUyAwM0ZFQjIwMjVcbi8vIENsZWFycyBzZWFyY2gtcmVsYXRlZCBkYXRhLCBpbmNsdWRpbmcgcmVzdWx0cywgc2VhcmNoIHRlcm0sIGFuZCBzdWdnZXN0aW9ucy5cbnByaXZhdGUgcmVzZXRDb21wb25lbnRTdGF0ZSgpOiB2b2lkIHtcbiAgdGhpcy5maW5hbFJlc3VsdHMgPSBbXTtcbiAgdGhpcy5maWx0ZXJOYW1lID0gJyc7IFxuICB0aGlzLnNlYXJjaEtleVdvcmQgPSAnJzsgIFxuICB0aGlzLnNob3dTdWdnZXN0aW9uID0gZmFsc2U7XG4gIHRoaXMubm9SZXN1bHQgPSBmYWxzZTtcbn1cbmNsZWFyTGlzdCgpe1xuICBzZXRUaW1lb3V0KCgpPT4ge1xuICAgIHRoaXMuZmluYWxSZXN1bHRzID0gW107XG4gIH0sIDEwMDApO1xufVxuXG5nZXRTb3VyY2VEYXRhTG9jYWwoZXZlbnQ6IGFueSkgeyAvL3RvIGdldCByZXN1bHRzIGxpc3QgZnJvbSBiYWNrZW5kIEFQSSB3aGVuZXZlciBrZXkgaXMgdXAgYWZ0ZXIgdGhlIGVudGVyaW5nIGF0bGVhc3Qgb25lIGtleVxuICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICBpZihldmVudC50YXJnZXQudmFsdWUubGVuZ3RoID4gMil7XG4gICAgdGhpcy5zaG93U3VnZ2VzdGlvbj10cnVlO1xuICAgIHRoaXMuZmluYWxSZXN1bHRzPVtdO1xuICAgIHRoaXMuc2VhcmNoS2V5V29yZCA9IGV2ZW50LnRhcmdldC52YWx1ZTtcbiAgICB0aGlzLnNob3dSZXN1bHQgPSBmYWxzZTtcbiAgICB0aGlzLmdldFNvdXJjZURhdGEoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgfSBlbHNlIHtcbiAgICB0aGlzLnNob3dTdWdnZXN0aW9uPWZhbHNlO1xuICAgIHRoaXMuZmluYWxSZXN1bHRzID0gW107XG4gICAgdGhpcy5ub1Jlc3VsdCA9IGZhbHNlO1xuICB9XG59XG4vLyBWRCAwM01heS0gc2VhcmNoIGNoYW5nZXNcbi8vIFZEIDMxTk9WMjQgbnVsbCBjaGVja1xuLy8gUlMgMjlKQU4yNVxuLy9NdWx0aS13b3JkIHNlYXJjaCBhY3Jvc3MgYWxsIG9iamVjdCB2YWx1ZXNcbnB1YmxpYyBnZXRTb3VyY2VEYXRhID0gKGtleXdvcmQ6IHN0cmluZykgPT4ge1xuICAgLy8gTVNNLTI3TUFSMjUgRW5zdXJlIHF1ZXMuc3ViVGV4dCBpcyBhbHdheXMgYW4gb2JqZWN0IGJ5IHBhcnNpbmcgaXQgaWYgaXQncyBhIHN0cmluZ1xuICBpZiAodGhpcy5hcGlNZXRhKSB7XG4gICAgICB0aGlzLmFwaU1ldGEgPSB0eXBlb2YgdGhpcy5hcGlNZXRhID09PSAnb2JqZWN0JyA/IHRoaXMuYXBpTWV0YSA6IEpTT04ucGFyc2UodGhpcy5hcGlNZXRhKTtcbiAgICAgIGxldCBhcGlPYmo6IGFueSA9IHRoaXMuYXBpTWV0YTtcbiAgICBcbiAgICB0aGlzLmRhdGFTZXJ2aWNlLmFwaVJlc3BvbnNlKGFwaU9iai5lbmRwb2ludCkuc3Vic2NyaWJlKChhcGlSZXNwb25zZSkgPT4ge1xuICAgICAgbGV0IHJlc3BvbnNlO1xuICAgICAgaWYgKGFwaU9iai52YXJpYWJsZSkge1xuICAgICAgICByZXNwb25zZSA9IHRoaXMuZGF0YVNlcnZpY2UuZ2V0VmFsdWUoYXBpUmVzcG9uc2UsIGFwaU9iai52YXJpYWJsZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXNwb25zZSA9IGFwaVJlc3BvbnNlO1xuICAgICAgfSAgICAgIFxuICAgICAgbGV0IHJlc3VsdHMgPSBbXTtcbiAgICAgIGxldCBzZWFyY2hUZXJtcyA9IGtleXdvcmQudG9Mb3dlckNhc2UoKT8uc3BsaXQoXCIgXCIpO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXNwb25zZS5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgb2JqID0gcmVzcG9uc2VbaV07XG4gICAgICAgIGxldCBjb21iaW5lZFZhbHVlcyA9IHRoaXMuZ2V0Q29tYmluZWRWYWx1ZXNGcm9tQ29sdW1ucyhvYmosIGFwaU9iai5maWVsZCk7XG4gICAgICAgIGxldCBtYXRjaCA9IHNlYXJjaFRlcm1zLmV2ZXJ5KHRlcm0gPT4gY29tYmluZWRWYWx1ZXMuaW5jbHVkZXModGVybSkpO1xuICAgICAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgICByZXN1bHRzLnB1c2gob2JqKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdGhpcy5ub1Jlc3VsdCA9IHJlc3VsdHMubGVuZ3RoID09PSAwO1xuICAgICAgdGhpcy5maW5hbFJlc3VsdHMgPSByZXN1bHRzO1xuICAgIH0pO1xuICB9XG59O1xuLy8gU0tTMjdGRUIgSGVscGVyIGZ1bmN0aW9uc1xucHJpdmF0ZSBnZXROZXN0ZWRWYWx1ZShvYmo6IGFueSwgcGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgLy9TS1MyN0ZFQiBDb252ZXJ0IGFycmF5IGluZGV4ZXMgdG8gZG90IG5vdGF0aW9uIChlLmcuLCBbMF0gLT4gLjApXG4gIGNvbnN0IHByb2Nlc3NlZFBhdGggPSBwYXRoLnJlcGxhY2UoL1xcWyhcXGQrKVxcXS9nLCAnLiQxJyk7XG4gIGNvbnN0IHBhcnRzID0gcHJvY2Vzc2VkUGF0aC5zcGxpdCgnLicpO1xuICBsZXQgY3VycmVudCA9IG9iajtcbiAgXG4gIGZvciAoY29uc3QgcGFydCBvZiBwYXJ0cykge1xuICAgIGlmICghY3VycmVudCB8fCB0eXBlb2YgY3VycmVudCAhPT0gJ29iamVjdCcpIHJldHVybiAnJztcbiAgICBjdXJyZW50ID0gY3VycmVudFtwYXJ0XTtcbiAgfVxuICBcbiAgcmV0dXJuIGN1cnJlbnQgIT09IG51bGwgJiYgY3VycmVudCAhPT0gdW5kZWZpbmVkIFxuICAgID8gU3RyaW5nKGN1cnJlbnQpLnRvTG93ZXJDYXNlKCkudHJpbSgpIFxuICAgIDogJyc7XG59XG5cbnByaXZhdGUgZ2V0Q29tYmluZWRWYWx1ZXNGcm9tQ29sdW1ucyhvYmo6IGFueSwgY29sdW1uczogc3RyaW5nW10pOiBzdHJpbmcge1xuICBjb25zdCB2YWx1ZXM6IHN0cmluZ1tdID0gW107XG4gIC8vIFNLUzI4RkVCIGNoZWNrIGlmIGNvbHVtbnMgaXMgYW4gYXJyYXlcbiAgaWYodHlwZW9mIGNvbHVtbnMgPT09ICdzdHJpbmcnICYmICFBcnJheS5pc0FycmF5KGNvbHVtbnMpICApIHtcbiAgICBjb2x1bW5zID0gW2NvbHVtbnNdO1xuICB9XG4gIFxuICBmb3IgKGNvbnN0IGNvbHVtbiBvZiBjb2x1bW5zKSB7XG4gICAgY29uc3QgdmFsdWUgPSB0aGlzLmdldE5lc3RlZFZhbHVlKG9iaiwgY29sdW1uKTtcbiAgICBpZiAodmFsdWUpIHtcbiAgICAgIHZhbHVlcy5wdXNoKHZhbHVlKTtcbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiB2YWx1ZXMuam9pbignICcpO1xufVxuLy8gU0tTMjdGRUIgZ2V0IHZhbHVlIGZyb20gZGF0YSBzcGVjaWZpYyBjb2x1bW5cbnB1YmxpYyBnZXRWYWx1ZXMoZWxlbWVudDogYW55LCBjb2x1bW5zOiBhbnkpOiBhbnkge1xuICBjb25zdCByZXN1bHQ6IGFueSA9IHt9O1xuICAvLyBTS1MyOEZFQiBjaGVjayBpZiBjb2x1bW5zIGlzIGFuIGFycmF5XG4gIGlmKHR5cGVvZiBjb2x1bW5zID09PSAnc3RyaW5nJyAmJiAhQXJyYXkuaXNBcnJheShjb2x1bW5zKSAgKSB7XG4gICAgY29sdW1ucyA9IFtjb2x1bW5zXTtcbiAgfVxuICBjb2x1bW5zLmZvckVhY2goKGNvbHVtbikgPT4ge1xuICAgIGxldCB0ZW1wRWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgbGV0IGZsZHMgPSBjb2x1bW4/LnNwbGl0KCcuJyk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmbGRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZXQgc3BsaXRGbGRzID0gZmxkc1tpXT8uc3BsaXQoJ1snKTtcbiAgICAgIGlmIChzcGxpdEZsZHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHRlbXBFbGVtZW50ID0gdGVtcEVsZW1lbnRbZmxkc1tpXV0gfHwgJyc7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgaW5kZXggPSBOdW1iZXIoc3BsaXRGbGRzWzFdPy5zcGxpdCgnXScpWzBdKTtcbiAgICAgICAgdGVtcEVsZW1lbnQgPSB0ZW1wRWxlbWVudFtzcGxpdEZsZHNbMF1dPy5baW5kZXhdIHx8ICcnO1xuICAgICAgfVxuICAgIH1cbiAgICByZXN1bHRbY29sdW1uXSA9IHRlbXBFbGVtZW50O1xuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuLy8gU0tTMjdGRUIgY29sdW1uIHZhbHVlIGdldCBmdW50aW9uXG5nZXRLZXlzKG9iajogYW55KTogc3RyaW5nW10ge1xuICByZXR1cm4gT2JqZWN0LmtleXMob2JqKTtcbn1cbiAgcHVibGljIGNsaWNrSXRlbShldmVudCkge1xuICAgIC8vIGNvbnNvbGUubG9nKCdpbnNpZGUgY2xpY2tJdGVtIG9mICcgKyBKU09OLnN0cmluZ2lmeShldmVudCwgbnVsbCwgMikpO1xuICAgIC8vIE1TTS0yN01BUjI1IEVuc3VyZSBxdWVzLnN1YlRleHQgaXMgYWx3YXlzIGFuIG9iamVjdCBieSBwYXJzaW5nIGl0IGlmIGl0J3MgYSBzdHJpbmdcbiAgICBpZih0aGlzLmFwaU1ldGEpe1xuICAgICAgdGhpcy5hcGlNZXRhID0gdHlwZW9mIHRoaXMuYXBpTWV0YSA9PT0gJ29iamVjdCcgPyB0aGlzLmFwaU1ldGEgOiBKU09OLnBhcnNlKHRoaXMuYXBpTWV0YSk7XG4gICAgICBsZXQgYXBpT2JqOiBhbnkgPSB0aGlzLmFwaU1ldGE7XG4gICAgXG4gICAgLy8gbGV0IGFwaU9iajogQVBJTWV0YSA9IEpTT04ucGFyc2UodGhpcy5hcGlNZXRhKTtcbiAgICB0aGlzLmZpbHRlck5hbWUgPSBldmVudFthcGlPYmouZGVmYXVsdEZpZWxkIHx8IGFwaU9iai5maWVsZFswXSB8fCBhcGlPYmouZmllbGRdOyAvL1NLUzI3RkVCIGRlZmF1bHRGaWVsZCBpcyB1c2VkIGZvciBzaG93aW5nIGEgc2VhcmNoIGZpZWxkIGlucHV0IGlmIGZpZWxkIGhhdmUgYXJyYXkgb2YgZGF0YVxuICAgIGxldCBjaGFuZ2UgPSBuZXcgQ2hhbmdlV3JhcHBlcigpOyAvLyBDaGFuZ2VXcmFwcGVyID0gSlNPTi5wYXJzZSgne30nKTtcbiAgICBjaGFuZ2UuZnJvbVF1ZXN0aW9uSWQgPSB0aGlzLmlkO1xuICAgIGNoYW5nZS52YWx1ZU9iaiA9IGV2ZW50O1xuICAgIGNoYW5nZS5maWVsZCA9IGFwaU9iai5maWVsZDtcbiAgICB0aGlzLnNlYXJjaFZhbHVlQ2hhbmdlLmVtaXQoY2hhbmdlKTtcbiAgfVxuICB9XG4gIC8vUlMgMDNGRUIyMDI1XG4gIC8vIFJlc2V0cyBjb21wb25lbnQgc3RhdGUgd2hlbiB0aGUgY29tcG9uZW50IGlzIGRlc3Ryb3llZFxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHsgdGhpcy5yZXNldENvbXBvbmVudFN0YXRlKCk7ICB9XG59XG4gICAgIiwiPCEtLSAvLyBWRCAxMkp1bjI0IC0gcmVhZG9ubHkgY2hhbmdlLS0+XG48ZGl2IGlkPVwiYXV0b2NvbXBsZXRlLWlucHV0XCI+IDwhLS0gU0tTNU5PVjI1IHNlYXJjaCBpY29uIC0tPlxuICA8aW5wdXQgI2F1dG8gaWQ9XCJzZWFyY2hib3gtc3R5bGVcIlxuICAgICAgICAgIChibHVyKT1cImNsZWFyTGlzdCgpXCJcbiAgICAgICAgICBbKG5nTW9kZWwpXT1cImZpbHRlck5hbWVcIlxuICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICBuYW1lPVwibmFtZVwiXG4gICAgICAgICAgW3JlYWRPbmx5XT1cInJlYWRPbmx5XCJcbiAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwicGxhY2VIb2xkZXJUZXh0XCJcbiAgICAgICAgICBzdHlsZT1cIm1hcmdpbjogMCAhaW1wb3J0YW50OyBwYWRkaW5nLXJpZ2h0OiAzMHB4O1wiXG4gICAgICAgICAgY2xhc3M9XCJzZWFyY2hJbnB1dCBzaGUtbGluZS1pbnB1dCBmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgIChmb2N1c2luKT1cImdldFNvdXJjZURhdGFMb2NhbCgkZXZlbnQpXCJcbiAgICAgICAgICAoaW5wdXQpPVwiZ2V0U291cmNlRGF0YUxvY2FsKCRldmVudClcIj5cbiAgPGRpdiBpZD1cInNlbGVjdExpc3RcIiBzdHlsZT1cInBvc2l0aW9uOiBhYnNvbHV0ZTtwb3NpdGlvbjogYWJzb2x1dGU7YmFja2dyb3VuZDogd2hpdGU7ei1pbmRleDogMjtcIj5cbiAgPGRpdiAqbmdJZj1cImZpbmFsUmVzdWx0cy5sZW5ndGggPiAwICYmIHNob3dTdWdnZXN0aW9uXCJcbiAgICBzdHlsZT1cIm1heC1oZWlnaHQ6IDIwdmg7Ym9yZGVyOiAxcHggc29saWQgI2QyZDRkNjtvdmVyZmxvdzogc2Nyb2xsOyBtaW4td2lkdGg6MTAwcHhcIlxuICAgICAgIGNsYXNzPVwic3VnZ2VzdGlvbnMtY29udGFpbmVyXCI+XG4gICAgICA8IS0tIEhBIDIwREVDMjMgVW5jb21tZW50ZWQgdGhlIGxvZ2ljIC0tPlxuICAgICAgIDwhLS0gVkQgMDNNYXktIHNlYXJjaCBjaGFuZ2VzIC0tPlxuICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgaXRlbSBvZiBmaW5hbFJlc3VsdHNcIiAoY2xpY2spPSdjbGlja0l0ZW0oaXRlbSknIGNsYXNzPVwiaG9vdmVyXCI+XG4gICAgICAgIDwhLS0gVkQgMjZKdW4yNCAtIGlkIGNvbmRpdGlvbiByZW1vdmVkIC0tPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJncmlkLXggYWxpZ24tbWlkZGxlXCIgc3R5bGU9XCJcIj5cbiAgICAgICAgICAgICAgPGRpdiAqbmdJZj1cIml0ZW0udGh1bWJuYWlsXCIgY2xhc3M9XCJjZWxsIHNocmlua1wiIHN0eWxlPVwid2lkdGg6IDYwcHg7IG1hcmdpbi1yaWdodDogMS42cmVtO1wiPlxuICAgICAgICAgICAgICAgICAgPGltZyBbc3JjXT1cIml0ZW0udGh1bWJuYWlsXCIgc3R5bGU9XCJ3aWR0aDogNjBweDtcIiBhbHQ9XCJcIj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjZWxsIGF1dG9cIiBzdHlsZT1cInRleHQtYWxpZ246IGxlZnQ7IHBhZGRpbmc6NXB4IDhweCAwIDhweDsgZGlzcGxheTogZmxleDsgZ2FwOiA1cHg7IFwiPlxuICAgICAgICAgICAgICAgIDwhLS0vLyBWRCAyNkpVTjI0IC0gcGlwZSBjaGFuZ2VzIC0tPlxuICAgICAgICAgICAgICAgIDwhLS0gUlMgMjlKQU4yNSAtLT5cbiAgICAgICAgICAgICAgICA8ZGl2IHN0eWxlPVwiZGlzcGxheTogZmxleDtcIiAqbmdGb3I9XCJsZXQga2V5IG9mIGdldEtleXMoZ2V0VmFsdWVzKGl0ZW0sIFNlYXJjaEl0ZW0pKVwiPlxuICAgICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAge3sgZ2V0VmFsdWVzKGl0ZW0sIFNlYXJjaEl0ZW0pW2tleV0gfX1cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PiAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICAgIDwhLS0gSEEgMjBERUMyMyBGb3IgQ29tbWVudGVkIHRoaXMgZm9yIGZ1dHVyZSBwdXJwb3NlIC0tPlxuICAgICAgPCEtLSA8dGFibGUgY2xhc3M9XCJ0YWJsZSB0YWJsZS1zdHJpcGVkIHRhYmxlLWJvcmRlcmVkXCI+XG4gICAgICAgICAgPHRoZWFkPlxuICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICA8dGg+e3sgJ2ZpcnN0TmFtZScgfCBpMThuOmkxOG5TZXJ2aWNlLmN1cnJlbnRMYW5ndWFnZSB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aD57eyAnbGFzdE5hbWUnIHwgaTE4bjppMThuU2VydmljZS5jdXJyZW50TGFuZ3VhZ2UgfX08L3RoPlxuICAgICAgICAgICAgICA8dGg+e3sgJ2RpdmlzaW9uJyB8IGkxOG46aTE4blNlcnZpY2UuY3VycmVudExhbmd1YWdlIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoPnt7ICdudW1iZXJQbGF0ZScgfCBpMThuOmkxOG5TZXJ2aWNlLmN1cnJlbnRMYW5ndWFnZSB9fTwvdGg+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvdGhlYWQ+XG4gICAgICAgICAgPHRib2R5PlxuICAgICAgICAgICAgPHRyICpuZ0Zvcj1cImxldCBpdGVtIG9mIGZpbmFsUmVzdWx0c1wiIChjbGljayk9J2NsaWNrSXRlbShpdGVtKSc+XG4gICAgICAgICAgICAgIDx0ZD57eyBpdGVtLmZpcnN0TmFtZSB9fTwvdGQ+XG4gICAgICAgICAgICAgIDx0ZD57eyBpdGVtLmxhc3ROYW1lIH19PC90ZD5cbiAgICAgICAgICAgICAgPHRkPnt7IGl0ZW0uZGl2aXNpb24gfX08L3RkPlxuICAgICAgICAgICAgICA8dGQ+e3sgaXRlbS5udW1iZXJQbGF0ZSB9fTwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvdGJvZHk+XG4gICAgICAgIDwvdGFibGU+IC0tPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG4iXX0=