@alfresco/adf-content-services
Version:
Alfresco ADF content services
225 lines • 50.9 kB
JavaScript
import { Component, DestroyRef, EventEmitter, inject, Output, ViewEncapsulation } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { QueriesApi } from '@alfresco/js-api';
import { NotificationService } from '@alfresco/adf-core';
import { debounceTime, finalize, mergeMap } from 'rxjs/operators';
import { SitesService } from '../../common/services/sites.service';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { AutoFocusDirective } from '../../directives';
import { MatRadioModule } from '@angular/material/radio';
import { MatButtonModule } from '@angular/material/button';
import { AlfrescoApiService } from '../../services';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import * as i0 from "@angular/core";
import * as i1 from "../../services";
import * as i2 from "../../common/services/sites.service";
import * as i3 from "@angular/forms";
import * as i4 from "@angular/material/dialog";
import * as i5 from "@alfresco/adf-core";
import * as i6 from "@angular/common";
import * as i7 from "@ngx-translate/core";
import * as i8 from "@angular/material/form-field";
import * as i9 from "@angular/material/input";
import * as i10 from "@angular/material/radio";
import * as i11 from "@angular/material/button";
export class LibraryDialogComponent {
get queriesApi() {
this._queriesApi = this._queriesApi ?? new QueriesApi(this.alfrescoApiService.getInstance());
return this._queriesApi;
}
constructor(alfrescoApiService, sitesService, formBuilder, dialog, notificationService) {
this.alfrescoApiService = alfrescoApiService;
this.sitesService = sitesService;
this.formBuilder = formBuilder;
this.dialog = dialog;
this.notificationService = notificationService;
/** Emitted when an error occurs. */
this.error = new EventEmitter();
/**
* Emitted when the new library is created successfully. The
* event parameter is a SiteEntry object with the details of the
* newly-created library.
*/
this.success = new EventEmitter();
this.createTitle = 'LIBRARY.DIALOG.CREATE_TITLE';
this.libraryTitleExists = false;
this.visibilityOptions = [
{ value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC', disabled: false },
{ value: 'PRIVATE', label: 'LIBRARY.VISIBILITY.PRIVATE', disabled: false },
{
value: 'MODERATED',
label: 'LIBRARY.VISIBILITY.MODERATED',
disabled: false
}
];
this.disableCreateButton = false;
this.destroyRef = inject(DestroyRef);
}
ngOnInit() {
const validators = {
id: [Validators.required, Validators.maxLength(72), this.forbidSpecialCharacters],
title: [Validators.required, this.forbidOnlySpaces, Validators.minLength(2), Validators.maxLength(256)],
description: [Validators.maxLength(512)]
};
this.form = this.formBuilder.group({
title: [null, validators.title],
id: [null, validators.id, this.createSiteIdValidator()],
description: ['', validators.description]
});
this.visibilityOption = this.visibilityOptions[0].value;
this.form.controls['title'].valueChanges
.pipe(debounceTime(500), mergeMap((title) => this.checkLibraryNameExists(title), (title) => title), takeUntilDestroyed(this.destroyRef))
.subscribe((title) => {
if (!this.form.controls['id'].dirty && this.canGenerateId(title)) {
this.form.patchValue({ id: this.sanitize(title.trim()) });
this.form.controls['id'].markAsTouched();
}
});
}
get title() {
const { title } = this.form.value;
return (title || '').trim();
}
get id() {
const { id } = this.form.value;
return (id || '').trim();
}
get description() {
const { description } = this.form.value;
return (description || '').trim();
}
get visibility() {
return this.visibilityOption || '';
}
submit() {
const { form, dialog } = this;
if (!form.valid) {
return;
}
this.disableCreateButton = true;
this.create()
.pipe(finalize(() => (this.disableCreateButton = false)))
.subscribe((node) => {
this.success.emit(node);
dialog.close(node);
}, (error) => this.handleError(error));
}
visibilityChangeHandler(event) {
this.visibilityOption = event.value;
}
create() {
const { title, id, description, visibility } = this;
const siteBody = {
id,
title,
description,
visibility
};
return this.sitesService.createSite(siteBody);
}
sanitize(input) {
return input.replace(/[\s\s]+/g, '-').replace(/[^A-Za-z0-9-]/g, '');
}
canGenerateId(title) {
return Boolean(title.replace(/[^A-Za-z0-9-]/g, '').length);
}
handleError(error) {
const errorMessage = 'CORE.MESSAGES.ERRORS.GENERIC';
try {
const { error: { statusCode } } = JSON.parse(error.message);
if (statusCode === 409) {
this.form.controls['id'].setErrors({
message: 'LIBRARY.ERRORS.CONFLICT'
});
}
else {
this.notificationService.showError(errorMessage);
}
}
catch {
this.notificationService.showError(errorMessage);
}
return error;
}
async checkLibraryNameExists(libraryTitle) {
let entries = [];
try {
entries = (await this.findLibraryByTitle(libraryTitle)).list.entries;
}
catch {
entries = [];
}
if (entries.length) {
this.libraryTitleExists = entries[0].entry.title.toLowerCase() === libraryTitle.toLowerCase();
}
else {
this.libraryTitleExists = false;
}
}
findLibraryByTitle(libraryTitle) {
return this.queriesApi.findSites(libraryTitle, {
maxItems: 1,
fields: ['title']
});
}
forbidSpecialCharacters({ value }) {
if (value === null || value.length === 0) {
return null;
}
const validCharacters = /[^A-Za-z0-9-]/;
const isValid = !validCharacters.test(value);
return isValid
? null
: {
message: 'LIBRARY.ERRORS.ILLEGAL_CHARACTERS'
};
}
forbidOnlySpaces({ value }) {
if (value === null || value.length === 0) {
return null;
}
const isValid = !!(value || '').trim();
return isValid
? null
: {
message: 'LIBRARY.ERRORS.ONLY_SPACES'
};
}
createSiteIdValidator() {
let timer;
return (control) => {
if (timer) {
clearTimeout(timer);
}
return new Promise((resolve) => {
timer = setTimeout(() => this.sitesService.getSite(control.value).subscribe(() => resolve({ message: 'LIBRARY.ERRORS.EXISTENT_SITE' }), () => resolve(null)), 300);
});
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: LibraryDialogComponent, deps: [{ token: i1.AlfrescoApiService }, { token: i2.SitesService }, { token: i3.UntypedFormBuilder }, { token: i4.MatDialogRef }, { token: i5.NotificationService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.3", type: LibraryDialogComponent, isStandalone: true, selector: "adf-library-dialog", outputs: { error: "error", success: "success" }, host: { classAttribute: "adf-library-dialog" }, ngImport: i0, template: "<h2 mat-dialog-title>{{ createTitle | translate }}</h2>\n\n<mat-dialog-content class=\"adf-library-dialog-content\">\n <form novalidate [formGroup]=\"form\" (submit)=\"submit()\">\n <mat-form-field class=\"adf-library-dialog-form-field\">\n <mat-label>{{ 'LIBRARY.DIALOG.FORM.NAME' | translate }}</mat-label>\n <input\n required\n matInput\n formControlName=\"title\"\n autocomplete=\"off\"\n adf-auto-focus\n />\n\n <mat-hint *ngIf=\"libraryTitleExists\">{{\n 'LIBRARY.HINTS.SITE_TITLE_EXISTS' | translate\n }}</mat-hint>\n <mat-error *ngIf=\"form.controls['title'].hasError('maxlength')\">\n {{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }}\n </mat-error>\n\n <mat-error *ngIf=\"form.controls['title'].hasError('minlength')\">\n {{ 'LIBRARY.ERRORS.TITLE_TOO_SHORT' | translate }}\n </mat-error>\n\n <mat-error *ngIf=\"form.controls['title'].errors?.message\">\n {{ form.controls['title'].errors?.message | translate }}\n </mat-error>\n </mat-form-field>\n\n <mat-form-field class=\"adf-library-dialog-form-field\">\n <mat-label>{{ 'LIBRARY.DIALOG.FORM.SITE_ID' | translate }}</mat-label>\n <input\n required\n matInput\n formControlName=\"id\"\n autocomplete=\"off\"\n />\n\n <mat-error *ngIf=\"form.controls['id'].errors?.message\">\n {{ form.controls['id'].errors?.message | translate }}\n </mat-error>\n\n <mat-error *ngIf=\"form.controls['id'].hasError('maxlength')\">\n {{ 'LIBRARY.ERRORS.ID_TOO_LONG' | translate }}\n </mat-error>\n </mat-form-field>\n\n <mat-form-field class=\"adf-library-dialog-form-field adf-library-dialog-form-field-description\">\n <mat-label>{{ 'LIBRARY.DIALOG.FORM.DESCRIPTION' | translate }}</mat-label>\n <textarea\n matInput\n rows=\"3\"\n formControlName=\"description\"\n ></textarea>\n\n <mat-error *ngIf=\"form.controls['description'].hasError('maxlength')\">\n {{ 'LIBRARY.ERRORS.DESCRIPTION_TOO_LONG' | translate }}\n </mat-error>\n </mat-form-field>\n\n <mat-radio-group\n class=\"adf-library-dialog-radio-group\"\n [ngModelOptions]=\"{ standalone: true }\"\n [(ngModel)]=\"visibilityOption\"\n (change)=\"visibilityChangeHandler($event)\"\n >\n <mat-radio-button\n color=\"primary\"\n class=\"adf-library-dialog-radio-group-button\"\n [disabled]=\"option.disabled\"\n *ngFor=\"let option of visibilityOptions\"\n [attr.data-automation-id]=\"option.value\"\n [value]=\"option.value\"\n [checked]=\"visibilityOption.value === option.value\"\n >\n {{ option.label | translate }}\n </mat-radio-button>\n </mat-radio-group>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions class=\"adf-action-buttons\">\n <button class=\"adf-action-button\" mat-button mat-dialog-close data-automation-id=\"cancel-library-id\">\n {{ 'LIBRARY.DIALOG.CANCEL' | translate }}\n </button>\n\n <button\n color=\"primary\"\n class=\"adf-action-button\"\n mat-button\n (click)=\"submit()\"\n [disabled]=\"!form.valid || disableCreateButton\"\n data-automation-id=\"create-library-id\"\n >\n {{ 'LIBRARY.DIALOG.CREATE' | translate }}\n </button>\n</mat-dialog-actions>\n", styles: [".adf-library-dialog .adf-library-dialog-content{padding:0;overflow:unset}.adf-library-dialog .adf-library-dialog-radio-group{display:flex;flex-direction:column;margin:0}.adf-library-dialog .adf-library-dialog-radio-group .adf-library-dialog-radio-group-button{margin:10px 0}.adf-library-dialog .adf-library-dialog-form-field{width:100%;padding-top:9.5px}.adf-library-dialog .adf-library-dialog-form-field:first-of-type{padding-top:13.5px}.adf-library-dialog .adf-library-dialog-form-field:last-of-type{padding-top:4.5px}.adf-library-dialog .adf-library-dialog-form-field .mdc-floating-label{-webkit-font-smoothing:subpixel-antialiased}.adf-library-dialog .adf-library-dialog-form-field.mat-form-field-hide-placeholder .mdc-floating-label,.adf-library-dialog .adf-library-dialog-form-field-description.mat-form-field-hide-placeholder .mdc-floating-label{padding-top:20px}.adf-library-dialog .adf-library-dialog-form-field .mat-mdc-form-field-infix{padding-bottom:3.5px}.adf-library-dialog .adf-library-dialog-form-field .mat-mdc-form-field-error-wrapper{margin-left:-2px;font-size:10.5px;-webkit-font-smoothing:subpixel-antialiased}.adf-library-dialog .adf-library-dialog-form-field .mat-mdc-form-field-error-wrapper .mat-mdc-form-field-error{height:13.125px}.adf-library-dialog .adf-action-buttons{display:flex;flex-direction:row;justify-content:flex-end}.adf-library-dialog .adf-action-buttons .adf-action-button{text-transform:uppercase}.adf-library-dialog .adf-action-buttons .adf-action-button span{font-weight:500}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i4.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i4.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i4.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i4.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i7.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatLabel, selector: "mat-label" }, { kind: "directive", type: i8.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i8.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i9.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: AutoFocusDirective, selector: "[adf-auto-focus]" }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i10.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i10.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i11.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: LibraryDialogComponent, decorators: [{
type: Component,
args: [{ selector: 'adf-library-dialog', standalone: true, imports: [
CommonModule,
MatDialogModule,
TranslateModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
AutoFocusDirective,
MatRadioModule,
FormsModule,
MatButtonModule
], encapsulation: ViewEncapsulation.None, host: { class: 'adf-library-dialog' }, template: "<h2 mat-dialog-title>{{ createTitle | translate }}</h2>\n\n<mat-dialog-content class=\"adf-library-dialog-content\">\n <form novalidate [formGroup]=\"form\" (submit)=\"submit()\">\n <mat-form-field class=\"adf-library-dialog-form-field\">\n <mat-label>{{ 'LIBRARY.DIALOG.FORM.NAME' | translate }}</mat-label>\n <input\n required\n matInput\n formControlName=\"title\"\n autocomplete=\"off\"\n adf-auto-focus\n />\n\n <mat-hint *ngIf=\"libraryTitleExists\">{{\n 'LIBRARY.HINTS.SITE_TITLE_EXISTS' | translate\n }}</mat-hint>\n <mat-error *ngIf=\"form.controls['title'].hasError('maxlength')\">\n {{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }}\n </mat-error>\n\n <mat-error *ngIf=\"form.controls['title'].hasError('minlength')\">\n {{ 'LIBRARY.ERRORS.TITLE_TOO_SHORT' | translate }}\n </mat-error>\n\n <mat-error *ngIf=\"form.controls['title'].errors?.message\">\n {{ form.controls['title'].errors?.message | translate }}\n </mat-error>\n </mat-form-field>\n\n <mat-form-field class=\"adf-library-dialog-form-field\">\n <mat-label>{{ 'LIBRARY.DIALOG.FORM.SITE_ID' | translate }}</mat-label>\n <input\n required\n matInput\n formControlName=\"id\"\n autocomplete=\"off\"\n />\n\n <mat-error *ngIf=\"form.controls['id'].errors?.message\">\n {{ form.controls['id'].errors?.message | translate }}\n </mat-error>\n\n <mat-error *ngIf=\"form.controls['id'].hasError('maxlength')\">\n {{ 'LIBRARY.ERRORS.ID_TOO_LONG' | translate }}\n </mat-error>\n </mat-form-field>\n\n <mat-form-field class=\"adf-library-dialog-form-field adf-library-dialog-form-field-description\">\n <mat-label>{{ 'LIBRARY.DIALOG.FORM.DESCRIPTION' | translate }}</mat-label>\n <textarea\n matInput\n rows=\"3\"\n formControlName=\"description\"\n ></textarea>\n\n <mat-error *ngIf=\"form.controls['description'].hasError('maxlength')\">\n {{ 'LIBRARY.ERRORS.DESCRIPTION_TOO_LONG' | translate }}\n </mat-error>\n </mat-form-field>\n\n <mat-radio-group\n class=\"adf-library-dialog-radio-group\"\n [ngModelOptions]=\"{ standalone: true }\"\n [(ngModel)]=\"visibilityOption\"\n (change)=\"visibilityChangeHandler($event)\"\n >\n <mat-radio-button\n color=\"primary\"\n class=\"adf-library-dialog-radio-group-button\"\n [disabled]=\"option.disabled\"\n *ngFor=\"let option of visibilityOptions\"\n [attr.data-automation-id]=\"option.value\"\n [value]=\"option.value\"\n [checked]=\"visibilityOption.value === option.value\"\n >\n {{ option.label | translate }}\n </mat-radio-button>\n </mat-radio-group>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions class=\"adf-action-buttons\">\n <button class=\"adf-action-button\" mat-button mat-dialog-close data-automation-id=\"cancel-library-id\">\n {{ 'LIBRARY.DIALOG.CANCEL' | translate }}\n </button>\n\n <button\n color=\"primary\"\n class=\"adf-action-button\"\n mat-button\n (click)=\"submit()\"\n [disabled]=\"!form.valid || disableCreateButton\"\n data-automation-id=\"create-library-id\"\n >\n {{ 'LIBRARY.DIALOG.CREATE' | translate }}\n </button>\n</mat-dialog-actions>\n", styles: [".adf-library-dialog .adf-library-dialog-content{padding:0;overflow:unset}.adf-library-dialog .adf-library-dialog-radio-group{display:flex;flex-direction:column;margin:0}.adf-library-dialog .adf-library-dialog-radio-group .adf-library-dialog-radio-group-button{margin:10px 0}.adf-library-dialog .adf-library-dialog-form-field{width:100%;padding-top:9.5px}.adf-library-dialog .adf-library-dialog-form-field:first-of-type{padding-top:13.5px}.adf-library-dialog .adf-library-dialog-form-field:last-of-type{padding-top:4.5px}.adf-library-dialog .adf-library-dialog-form-field .mdc-floating-label{-webkit-font-smoothing:subpixel-antialiased}.adf-library-dialog .adf-library-dialog-form-field.mat-form-field-hide-placeholder .mdc-floating-label,.adf-library-dialog .adf-library-dialog-form-field-description.mat-form-field-hide-placeholder .mdc-floating-label{padding-top:20px}.adf-library-dialog .adf-library-dialog-form-field .mat-mdc-form-field-infix{padding-bottom:3.5px}.adf-library-dialog .adf-library-dialog-form-field .mat-mdc-form-field-error-wrapper{margin-left:-2px;font-size:10.5px;-webkit-font-smoothing:subpixel-antialiased}.adf-library-dialog .adf-library-dialog-form-field .mat-mdc-form-field-error-wrapper .mat-mdc-form-field-error{height:13.125px}.adf-library-dialog .adf-action-buttons{display:flex;flex-direction:row;justify-content:flex-end}.adf-library-dialog .adf-action-buttons .adf-action-button{text-transform:uppercase}.adf-library-dialog .adf-action-buttons .adf-action-button span{font-weight:500}\n"] }]
}], ctorParameters: () => [{ type: i1.AlfrescoApiService }, { type: i2.SitesService }, { type: i3.UntypedFormBuilder }, { type: i4.MatDialogRef }, { type: i5.NotificationService }], propDecorators: { error: [{
type: Output
}], success: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlicmFyeS5kaWFsb2cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9saWIvY29udGVudC1zZXJ2aWNlcy9zcmMvbGliL2RpYWxvZ3MvbGlicmFyeS9saWJyYXJ5LmRpYWxvZy50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYi9jb250ZW50LXNlcnZpY2VzL3NyYy9saWIvZGlhbG9ncy9saWJyYXJ5L2xpYnJhcnkuZGlhbG9nLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBa0JBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQVUsTUFBTSxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9HLE9BQU8sRUFFSCxXQUFXLEVBQ1gsbUJBQW1CLEVBQ25CLGtCQUFrQixFQUdsQixVQUFVLEVBQ2IsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxVQUFVLEVBQXlDLE1BQU0sa0JBQWtCLENBQUM7QUFDckYsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDekQsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGtCQUFrQixD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O3dCQUNmLGVBQWU7d0JBQ2YsbUJBQW1CO3dCQUNuQixrQkFBa0I7d0JBQ2xCLGNBQWM7d0JBQ2Qsa0JBQWtCO3dCQUNsQixjQUFjO3dCQUNkLFdBQVc7d0JBQ1gsZUFBZTtxQkFDbEIsaUJBR2MsaUJBQWlCLENBQUMsSUFBSSxRQUMvQixFQUFFLEtBQUssRUFBRSxvQkFBb0IsRUFBRTtnTkFLckMsS0FBSztzQkFESixNQUFNO2dCQVNQLE9BQU87c0JBRE4sTUFBTSIsInNvdXJjZXNDb250ZW50IjpbIi8qIVxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCDCqSAyMDA1LTIwMjUgSHlsYW5kIFNvZnR3YXJlLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQ29tcG9uZW50LCBEZXN0cm95UmVmLCBFdmVudEVtaXR0ZXIsIGluamVjdCwgT25Jbml0LCBPdXRwdXQsIFZpZXdFbmNhcHN1bGF0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICAgIEFic3RyYWN0Q29udHJvbCxcbiAgICBGb3Jtc01vZHVsZSxcbiAgICBSZWFjdGl2ZUZvcm1zTW9kdWxlLFxuICAgIFVudHlwZWRGb3JtQnVpbGRlcixcbiAgICBVbnR5cGVkRm9ybUNvbnRyb2wsXG4gICAgVW50eXBlZEZvcm1Hcm91cCxcbiAgICBWYWxpZGF0b3JzXG59IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE1hdERpYWxvZ01vZHVsZSwgTWF0RGlhbG9nUmVmIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IFF1ZXJpZXNBcGksIFNpdGVCb2R5Q3JlYXRlLCBTaXRlRW50cnksIFNpdGVQYWdpbmcgfSBmcm9tICdAYWxmcmVzY28vanMtYXBpJztcbmltcG9ydCB7IE5vdGlmaWNhdGlvblNlcnZpY2UgfSBmcm9tICdAYWxmcmVzY28vYWRmLWNvcmUnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBmaW5hbGl6ZSwgbWVyZ2VNYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBTaXRlc1NlcnZpY2UgfSBmcm9tICcuLi8uLi9jb21tb24vc2VydmljZXMvc2l0ZXMuc2VydmljZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgVHJhbnNsYXRlTW9kdWxlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBNYXRGb3JtRmllbGRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9mb3JtLWZpZWxkJztcbmltcG9ydCB7IE1hdElucHV0TW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaW5wdXQnO1xuaW1wb3J0IHsgQXV0b0ZvY3VzRGlyZWN0aXZlIH0gZnJvbSAnLi4vLi4vZGlyZWN0aXZlcyc7XG5pbXBvcnQgeyBNYXRSYWRpb01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3JhZGlvJztcbmltcG9ydCB7IE1hdEJ1dHRvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbic7XG5pbXBvcnQgeyBBbGZyZXNjb0FwaVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcyc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnYWRmLWxpYnJhcnktZGlhbG9nJyxcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxuICAgIGltcG9ydHM6IFtcbiAgICAgICAgQ29tbW9uTW9kdWxlLFxuICAgICAgICBNYXREaWFsb2dNb2R1bGUsXG4gICAgICAgIFRyYW5zbGF0ZU1vZHVsZSxcbiAgICAgICAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcbiAgICAgICAgTWF0Rm9ybUZpZWxkTW9kdWxlLFxuICAgICAgICBNYXRJbnB1dE1vZHVsZSxcbiAgICAgICAgQXV0b0ZvY3VzRGlyZWN0aXZlLFxuICAgICAgICBNYXRSYWRpb01vZHVsZSxcbiAgICAgICAgRm9ybXNNb2R1bGUsXG4gICAgICAgIE1hdEJ1dHRvbk1vZHVsZVxuICAgIF0sXG4gICAgc3R5bGVVcmxzOiBbJy4vbGlicmFyeS5kaWFsb2cuc2NzcyddLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9saWJyYXJ5LmRpYWxvZy5odG1sJyxcbiAgICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICAgIGhvc3Q6IHsgY2xhc3M6ICdhZGYtbGlicmFyeS1kaWFsb2cnIH1cbn0pXG5leHBvcnQgY2xhc3MgTGlicmFyeURpYWxvZ0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gICAgLyoqIEVtaXR0ZWQgd2hlbiBhbiBlcnJvciBvY2N1cnMuICovXG4gICAgQE91dHB1dCgpXG4gICAgZXJyb3I6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgICAvKipcbiAgICAgKiBFbWl0dGVkIHdoZW4gdGhlIG5ldyBsaWJyYXJ5IGlzIGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5LiBUaGVcbiAgICAgKiBldmVudCBwYXJhbWV0ZXIgaXMgYSBTaXRlRW50cnkgb2JqZWN0IHdpdGggdGhlIGRldGFpbHMgb2YgdGhlXG4gICAgICogbmV3bHktY3JlYXRlZCBsaWJyYXJ5LlxuICAgICAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHN1Y2Nlc3M6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgICBjcmVhdGVUaXRsZSA9ICdMSUJSQVJZLkRJQUxPRy5DUkVBVEVfVElUTEUnO1xuICAgIGxpYnJhcnlUaXRsZUV4aXN0cyA9IGZhbHNlO1xuICAgIGZvcm06IFVudHlwZWRGb3JtR3JvdXA7XG4gICAgdmlzaWJpbGl0eU9wdGlvbjogYW55O1xuICAgIHZpc2liaWxpdHlPcHRpb25zID0gW1xuICAgICAgICB7IHZhbHVlOiAnUFVCTElDJywgbGFiZWw6ICdMSUJSQVJZLlZJU0lCSUxJVFkuUFVCTElDJywgZGlzYWJsZWQ6IGZhbHNlIH0sXG4gICAgICAgIHsgdmFsdWU6ICdQUklWQVRFJywgbGFiZWw6ICdMSUJSQVJZLlZJU0lCSUxJVFkuUFJJVkFURScsIGRpc2FibGVkOiBmYWxzZSB9LFxuICAgICAgICB7XG4gICAgICAgICAgICB2YWx1ZTogJ01PREVSQVRFRCcsXG4gICAgICAgICAgICBsYWJlbDogJ0xJQlJBUlkuVklTSUJJTElUWS5NT0RFUkFURUQnLFxuICAgICAgICAgICAgZGlzYWJsZWQ6IGZhbHNlXG4gICAgICAgIH1cbiAgICBdO1xuICAgIGRpc2FibGVDcmVhdGVCdXR0b24gPSBmYWxzZTtcblxuICAgIF9xdWVyaWVzQXBpOiBRdWVyaWVzQXBpO1xuICAgIGdldCBxdWVyaWVzQXBpKCk6IFF1ZXJpZXNBcGkge1xuICAgICAgICB0aGlzLl9xdWVyaWVzQXBpID0gdGhpcy5fcXVlcmllc0FwaSA/PyBuZXcgUXVlcmllc0FwaSh0aGlzLmFsZnJlc2NvQXBpU2VydmljZS5nZXRJbnN0YW5jZSgpKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3F1ZXJpZXNBcGk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgYWxmcmVzY29BcGlTZXJ2aWNlOiBBbGZyZXNjb0FwaVNlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgc2l0ZXNTZXJ2aWNlOiBTaXRlc1NlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgZm9ybUJ1aWxkZXI6IFVudHlwZWRGb3JtQnVpbGRlcixcbiAgICAgICAgcHJpdmF0ZSBkaWFsb2c6IE1hdERpYWxvZ1JlZjxMaWJyYXJ5RGlhbG9nQ29tcG9uZW50PixcbiAgICAgICAgcHJpdmF0ZSBub3RpZmljYXRpb25TZXJ2aWNlOiBOb3RpZmljYXRpb25TZXJ2aWNlXG4gICAgKSB7fVxuXG4gICAgbmdPbkluaXQoKSB7XG4gICAgICAgIGNvbnN0IHZhbGlkYXRvcnMgPSB7XG4gICAgICAgICAgICBpZDogW1ZhbGlkYXRvcnMucmVxdWlyZWQsIFZhbGlkYXRvcnMubWF4TGVuZ3RoKDcyKSwgdGhpcy5mb3JiaWRTcGVjaWFsQ2hhcmFjdGVyc10sXG4gICAgICAgICAgICB0aXRsZTogW1ZhbGlkYXRvcnMucmVxdWlyZWQsIHRoaXMuZm9yYmlkT25seVNwYWNlcywgVmFsaWRhdG9ycy5taW5MZW5ndGgoMiksIFZhbGlkYXRvcnMubWF4TGVuZ3RoKDI1NildLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IFtWYWxpZGF0b3JzLm1heExlbmd0aCg1MTIpXVxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuZm9ybSA9IHRoaXMuZm9ybUJ1aWxkZXIuZ3JvdXAoe1xuICAgICAgICAgICAgdGl0bGU6IFtudWxsLCB2YWxpZGF0b3JzLnRpdGxlXSxcbiAgICAgICAgICAgIGlkOiBbbnVsbCwgdmFsaWRhdG9ycy5pZCwgdGhpcy5jcmVhdGVTaXRlSWRWYWxpZGF0b3IoKV0sXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogWycnLCB2YWxpZGF0b3JzLmRlc2NyaXB0aW9uXVxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnZpc2liaWxpdHlPcHRpb24gPSB0aGlzLnZpc2liaWxpdHlPcHRpb25zWzBdLnZhbHVlO1xuXG4gICAgICAgIHRoaXMuZm9ybS5jb250cm9sc1sndGl0bGUnXS52YWx1ZUNoYW5nZXNcbiAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgIGRlYm91bmNlVGltZSg1MDApLFxuICAgICAgICAgICAgICAgIG1lcmdlTWFwKFxuICAgICAgICAgICAgICAgICAgICAodGl0bGUpID0+IHRoaXMuY2hlY2tMaWJyYXJ5TmFtZUV4aXN0cyh0aXRsZSksXG4gICAgICAgICAgICAgICAgICAgICh0aXRsZSkgPT4gdGl0bGVcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCh0aXRsZTogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmZvcm0uY29udHJvbHNbJ2lkJ10uZGlydHkgJiYgdGhpcy5jYW5HZW5lcmF0ZUlkKHRpdGxlKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZvcm0ucGF0Y2hWYWx1ZSh7IGlkOiB0aGlzLnNhbml0aXplKHRpdGxlLnRyaW0oKSkgfSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZm9ybS5jb250cm9sc1snaWQnXS5tYXJrQXNUb3VjaGVkKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZ2V0IHRpdGxlKCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHsgdGl0bGUgfSA9IHRoaXMuZm9ybS52YWx1ZTtcblxuICAgICAgICByZXR1cm4gKHRpdGxlIHx8ICcnKS50cmltKCk7XG4gICAgfVxuXG4gICAgZ2V0IGlkKCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHsgaWQgfSA9IHRoaXMuZm9ybS52YWx1ZTtcblxuICAgICAgICByZXR1cm4gKGlkIHx8ICcnKS50cmltKCk7XG4gICAgfVxuXG4gICAgZ2V0IGRlc2NyaXB0aW9uKCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHsgZGVzY3JpcHRpb24gfSA9IHRoaXMuZm9ybS52YWx1ZTtcblxuICAgICAgICByZXR1cm4gKGRlc2NyaXB0aW9uIHx8ICcnKS50cmltKCk7XG4gICAgfVxuXG4gICAgZ2V0IHZpc2liaWxpdHkoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmlzaWJpbGl0eU9wdGlvbiB8fCAnJztcbiAgICB9XG5cbiAgICBzdWJtaXQoKSB7XG4gICAgICAgIGNvbnN0IHsgZm9ybSwgZGlhbG9nIH0gPSB0aGlzO1xuXG4gICAgICAgIGlmICghZm9ybS52YWxpZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5kaXNhYmxlQ3JlYXRlQnV0dG9uID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5jcmVhdGUoKVxuICAgICAgICAgICAgLnBpcGUoZmluYWxpemUoKCkgPT4gKHRoaXMuZGlzYWJsZUNyZWF0ZUJ1dHRvbiA9IGZhbHNlKSkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKFxuICAgICAgICAgICAgICAgIChub2RlOiBTaXRlRW50cnkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdWNjZXNzLmVtaXQobm9kZSk7XG4gICAgICAgICAgICAgICAgICAgIGRpYWxvZy5jbG9zZShub2RlKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIChlcnJvcikgPT4gdGhpcy5oYW5kbGVFcnJvcihlcnJvcilcbiAgICAgICAgICAgICk7XG4gICAgfVxuXG4gICAgdmlzaWJpbGl0eUNoYW5nZUhhbmRsZXIoZXZlbnQpIHtcbiAgICAgICAgdGhpcy52aXNpYmlsaXR5T3B0aW9uID0gZXZlbnQudmFsdWU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjcmVhdGUoKTogT2JzZXJ2YWJsZTxTaXRlRW50cnk+IHtcbiAgICAgICAgY29uc3QgeyB0aXRsZSwgaWQsIGRlc2NyaXB0aW9uLCB2aXNpYmlsaXR5IH0gPSB0aGlzO1xuICAgICAgICBjb25zdCBzaXRlQm9keSA9IHtcbiAgICAgICAgICAgIGlkLFxuICAgICAgICAgICAgdGl0bGUsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbixcbiAgICAgICAgICAgIHZpc2liaWxpdHlcbiAgICAgICAgfSBhcyBTaXRlQm9keUNyZWF0ZTtcblxuICAgICAgICByZXR1cm4gdGhpcy5zaXRlc1NlcnZpY2UuY3JlYXRlU2l0ZShzaXRlQm9keSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzYW5pdGl6ZShpbnB1dDogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBpbnB1dC5yZXBsYWNlKC9bXFxzXFxzXSsvZywgJy0nKS5yZXBsYWNlKC9bXkEtWmEtejAtOS1dL2csICcnKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNhbkdlbmVyYXRlSWQodGl0bGUpIHtcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGl0bGUucmVwbGFjZSgvW15BLVphLXowLTktXS9nLCAnJykubGVuZ3RoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGhhbmRsZUVycm9yKGVycm9yOiBhbnkpOiBhbnkge1xuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSAnQ09SRS5NRVNTQUdFUy5FUlJPUlMuR0VORVJJQyc7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgICAgICBlcnJvcjogeyBzdGF0dXNDb2RlIH1cbiAgICAgICAgICAgIH0gPSBKU09OLnBhcnNlKGVycm9yLm1lc3NhZ2UpO1xuXG4gICAgICAgICAgICBpZiAoc3RhdHVzQ29kZSA9PT0gNDA5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5mb3JtLmNvbnRyb2xzWydpZCddLnNldEVycm9ycyh7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6ICdMSUJSQVJZLkVSUk9SUy5DT05GTElDVCdcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLnNob3dFcnJvcihlcnJvck1lc3NhZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5zaG93RXJyb3IoZXJyb3JNZXNzYWdlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlcnJvcjtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGNoZWNrTGlicmFyeU5hbWVFeGlzdHMobGlicmFyeVRpdGxlOiBzdHJpbmcpIHtcbiAgICAgICAgbGV0IGVudHJpZXMgPSBbXTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgZW50cmllcyA9IChhd2FpdCB0aGlzLmZpbmRMaWJyYXJ5QnlUaXRsZShsaWJyYXJ5VGl0bGUpKS5saXN0LmVudHJpZXM7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgZW50cmllcyA9IFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGVudHJpZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLmxpYnJhcnlUaXRsZUV4aXN0cyA9IGVudHJpZXNbMF0uZW50cnkudGl0bGUudG9Mb3dlckNhc2UoKSA9PT0gbGlicmFyeVRpdGxlLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmxpYnJhcnlUaXRsZUV4aXN0cyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBmaW5kTGlicmFyeUJ5VGl0bGUobGlicmFyeVRpdGxlOiBzdHJpbmcpOiBQcm9taXNlPFNpdGVQYWdpbmc+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucXVlcmllc0FwaS5maW5kU2l0ZXMobGlicmFyeVRpdGxlLCB7XG4gICAgICAgICAgICBtYXhJdGVtczogMSxcbiAgICAgICAgICAgIGZpZWxkczogWyd0aXRsZSddXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgZm9yYmlkU3BlY2lhbENoYXJhY3RlcnMoeyB2YWx1ZSB9OiBVbnR5cGVkRm9ybUNvbnRyb2wpIHtcbiAgICAgICAgaWYgKHZhbHVlID09PSBudWxsIHx8IHZhbHVlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB2YWxpZENoYXJhY3RlcnM6IFJlZ0V4cCA9IC9bXkEtWmEtejAtOS1dLztcbiAgICAgICAgY29uc3QgaXNWYWxpZDogYm9vbGVhbiA9ICF2YWxpZENoYXJhY3RlcnMudGVzdCh2YWx1ZSk7XG5cbiAgICAgICAgcmV0dXJuIGlzVmFsaWRcbiAgICAgICAgICAgID8gbnVsbFxuICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgICBtZXNzYWdlOiAnTElCUkFSWS5FUlJPUlMuSUxMRUdBTF9DSEFSQUNURVJTJ1xuICAgICAgICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgZm9yYmlkT25seVNwYWNlcyh7IHZhbHVlIH06IFVudHlwZWRGb3JtQ29udHJvbCkge1xuICAgICAgICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGlzVmFsaWQ6IGJvb2xlYW4gPSAhISh2YWx1ZSB8fCAnJykudHJpbSgpO1xuXG4gICAgICAgIHJldHVybiBpc1ZhbGlkXG4gICAgICAgICAgICA/IG51bGxcbiAgICAgICAgICAgIDoge1xuICAgICAgICAgICAgICAgICAgbWVzc2FnZTogJ0xJQlJBUlkuRVJST1JTLk9OTFlfU1BBQ0VTJ1xuICAgICAgICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgY3JlYXRlU2l0ZUlkVmFsaWRhdG9yKCkge1xuICAgICAgICBsZXQgdGltZXI7XG5cbiAgICAgICAgcmV0dXJuIChjb250cm9sOiBBYnN0cmFjdENvbnRyb2wpID0+IHtcbiAgICAgICAgICAgIGlmICh0aW1lcikge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHRpbWVyID0gc2V0VGltZW91dChcbiAgICAgICAgICAgICAgICAgICAgKCkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2l0ZXNTZXJ2aWNlLmdldFNpdGUoY29udHJvbC52YWx1ZSkuc3Vic2NyaWJlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICgpID0+IHJlc29sdmUoeyBtZXNzYWdlOiAnTElCUkFSWS5FUlJPUlMuRVhJU1RFTlRfU0lURScgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKCkgPT4gcmVzb2x2ZShudWxsKVxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgMzAwXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuICAgIH1cbn1cbiIsIjxoMiBtYXQtZGlhbG9nLXRpdGxlPnt7IGNyZWF0ZVRpdGxlIHwgdHJhbnNsYXRlIH19PC9oMj5cblxuPG1hdC1kaWFsb2ctY29udGVudCBjbGFzcz1cImFkZi1saWJyYXJ5LWRpYWxvZy1jb250ZW50XCI+XG4gIDxmb3JtIG5vdmFsaWRhdGUgW2Zvcm1Hcm91cF09XCJmb3JtXCIgKHN1Ym1pdCk9XCJzdWJtaXQoKVwiPlxuICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImFkZi1saWJyYXJ5LWRpYWxvZy1mb3JtLWZpZWxkXCI+XG4gICAgICA8bWF0LWxhYmVsPnt7ICdMSUJSQVJZLkRJQUxPRy5GT1JNLk5BTUUnIHwgdHJhbnNsYXRlIH19PC9tYXQtbGFiZWw+XG4gICAgICA8aW5wdXRcbiAgICAgICAgcmVxdWlyZWRcbiAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwidGl0bGVcIlxuICAgICAgICBhdXRvY29tcGxldGU9XCJvZmZcIlxuICAgICAgICBhZGYtYXV0by1mb2N1c1xuICAgICAgLz5cblxuICAgICAgPG1hdC1oaW50ICpuZ0lmPVwibGlicmFyeVRpdGxlRXhpc3RzXCI+e3tcbiAgICAgICAgJ0xJQlJBUlkuSElOVFMuU0lURV9USVRMRV9FWElTVFMnIHwgdHJhbnNsYXRlXG4gICAgICB9fTwvbWF0LWhpbnQ+XG4gICAgICA8bWF0LWVycm9yICpuZ0lmPVwiZm9ybS5jb250cm9sc1sndGl0bGUnXS5oYXNFcnJvcignbWF4bGVuZ3RoJylcIj5cbiAgICAgICAge3sgJ0xJQlJBUlkuRVJST1JTLlRJVExFX1RPT19MT05HJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9tYXQtZXJyb3I+XG5cbiAgICAgIDxtYXQtZXJyb3IgKm5nSWY9XCJmb3JtLmNvbnRyb2xzWyd0aXRsZSddLmhhc0Vycm9yKCdtaW5sZW5ndGgnKVwiPlxuICAgICAgICB7eyAnTElCUkFSWS5FUlJPUlMuVElUTEVfVE9PX1NIT1JUJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9tYXQtZXJyb3I+XG5cbiAgICAgIDxtYXQtZXJyb3IgKm5nSWY9XCJmb3JtLmNvbnRyb2xzWyd0aXRsZSddLmVycm9ycz8ubWVzc2FnZVwiPlxuICAgICAgICB7eyBmb3JtLmNvbnRyb2xzWyd0aXRsZSddLmVycm9ycz8ubWVzc2FnZSB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9tYXQtZXJyb3I+XG4gICAgPC9tYXQtZm9ybS1maWVsZD5cblxuICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImFkZi1saWJyYXJ5LWRpYWxvZy1mb3JtLWZpZWxkXCI+XG4gICAgICA8bWF0LWxhYmVsPnt7ICdMSUJSQVJZLkRJQUxPRy5GT1JNLlNJVEVfSUQnIHwgdHJhbnNsYXRlIH19PC9tYXQtbGFiZWw+XG4gICAgICA8aW5wdXRcbiAgICAgICAgcmVxdWlyZWRcbiAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiaWRcIlxuICAgICAgICBhdXRvY29tcGxldGU9XCJvZmZcIlxuICAgICAgLz5cblxuICAgICAgPG1hdC1lcnJvciAqbmdJZj1cImZvcm0uY29udHJvbHNbJ2lkJ10uZXJyb3JzPy5tZXNzYWdlXCI+XG4gICAgICAgIHt7IGZvcm0uY29udHJvbHNbJ2lkJ10uZXJyb3JzPy5tZXNzYWdlIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L21hdC1lcnJvcj5cblxuICAgICAgPG1hdC1lcnJvciAqbmdJZj1cImZvcm0uY29udHJvbHNbJ2lkJ10uaGFzRXJyb3IoJ21heGxlbmd0aCcpXCI+XG4gICAgICAgIHt7ICdMSUJSQVJZLkVSUk9SUy5JRF9UT09fTE9ORycgfCB0cmFuc2xhdGUgfX1cbiAgICAgIDwvbWF0LWVycm9yPlxuICAgIDwvbWF0LWZvcm0tZmllbGQ+XG5cbiAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJhZGYtbGlicmFyeS1kaWFsb2ctZm9ybS1maWVsZCBhZGYtbGlicmFyeS1kaWFsb2ctZm9ybS1maWVsZC1kZXNjcmlwdGlvblwiPlxuICAgICAgPG1hdC1sYWJlbD57eyAnTElCUkFSWS5ESUFMT0cuRk9STS5ERVNDUklQVElPTicgfCB0cmFuc2xhdGUgfX08L21hdC1sYWJlbD5cbiAgICAgIDx0ZXh0YXJlYVxuICAgICAgICBtYXRJbnB1dFxuICAgICAgICByb3dzPVwiM1wiXG4gICAgICAgIGZvcm1Db250cm9sTmFtZT1cImRlc2NyaXB0aW9uXCJcbiAgICAgID48L3RleHRhcmVhPlxuXG4gICAgICA8bWF0LWVycm9yICpuZ0lmPVwiZm9ybS5jb250cm9sc1snZGVzY3JpcHRpb24nXS5oYXNFcnJvcignbWF4bGVuZ3RoJylcIj5cbiAgICAgICAge3sgJ0xJQlJBUlkuRVJST1JTLkRFU0NSSVBUSU9OX1RPT19MT05HJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9tYXQtZXJyb3I+XG4gICAgPC9tYXQtZm9ybS1maWVsZD5cblxuICAgIDxtYXQtcmFkaW8tZ3JvdXBcbiAgICAgIGNsYXNzPVwiYWRmLWxpYnJhcnktZGlhbG9nLXJhZGlvLWdyb3VwXCJcbiAgICAgIFtuZ01vZGVsT3B0aW9uc109XCJ7IHN0YW5kYWxvbmU6IHRydWUgfVwiXG4gICAgICBbKG5nTW9kZWwpXT1cInZpc2liaWxpdHlPcHRpb25cIlxuICAgICAgKGNoYW5nZSk9XCJ2aXNpYmlsaXR5Q2hhbmdlSGFuZGxlcigkZXZlbnQpXCJcbiAgICA+XG4gICAgICA8bWF0LXJhZGlvLWJ1dHRvblxuICAgICAgICBjb2xvcj1cInByaW1hcnlcIlxuICAgICAgICBjbGFzcz1cImFkZi1saWJyYXJ5LWRpYWxvZy1yYWRpby1ncm91cC1idXR0b25cIlxuICAgICAgICBbZGlzYWJsZWRdPVwib3B0aW9uLmRpc2FibGVkXCJcbiAgICAgICAgKm5nRm9yPVwibGV0IG9wdGlvbiBvZiB2aXNpYmlsaXR5T3B0aW9uc1wiXG4gICAgICAgIFthdHRyLmRhdGEtYXV0b21hdGlvbi1pZF09XCJvcHRpb24udmFsdWVcIlxuICAgICAgICBbdmFsdWVdPVwib3B0aW9uLnZhbHVlXCJcbiAgICAgICAgW2NoZWNrZWRdPVwidmlzaWJpbGl0eU9wdGlvbi52YWx1ZSA9