@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
278 lines • 43.6 kB
JavaScript
import { Component, EventEmitter, forwardRef } from '@angular/core';
import { QueriesUtil } from '@c8y/client';
import { gettext, ModalSelectionMode, PRODUCT_EXPERIENCE_EVENT_SOURCE } from '@c8y/ngx-components';
import { TranslateService } from '@ngx-translate/core';
import { get, has, isEmpty, isEqual, omitBy } from 'lodash-es';
import { BehaviorSubject, merge, of, Subject } from 'rxjs';
import { map, mergeMap, switchMap, tap } from 'rxjs/operators';
import { PRODUCT_EXPERIENCE_REPOSITORY_SHARED } from '../repository.model';
import { RepositoryService } from '../repository.service';
import * as i0 from "@angular/core";
import * as i1 from "../repository.service";
import * as i2 from "@ngx-translate/core";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@angular/common";
// MODAL STRUCTURE
// - selectModalObject (repository entry (repositoryCategory) -> type c8y_Firmware/c8y_Software)
// -- ISelectModalOption (repository binary entry (repositoryBinary) => type c8y_FirmwareBinary/c8y_SoftwareBinary)
// -- ISelectModalOption...
// - selectModalObject...
/**
* RepositorySelectModalComponent displays repository entries options and allows to select them.
*
* ```typescript
* import { take } from 'rxjs/operators';
* import { RepositorySelectModalComponent, ModalSelectionMode, RepositoryType } from '@c8y/ngx-components/repository/shared';
*
* const initialState = {
* repositoryType: RepositoryType.FIRMWARE,
* title: gettext('Install firmware'),
* subTitle: gettext('Available firmwares matching the device type'),
* icon: 'c8y-firmware',
* mode: ModalSelectionMode.SINGLE,
* labels: { ok: gettext('Install') },
* disableSelected: false
* };
*
* const modal = this.bsModal.show(RepositorySelectModalComponent, {
* ignoreBackdropClick: true,
* initialState
* });
*
* modal.content.load.next();
* modal.content.resultEmitter.pipe(take(1)).subscribe((firmware) => {
* })
* ```
*/
export class RepositorySelectModalComponent {
constructor(repositoryService, translateService) {
this.repositoryService = repositoryService;
this.translateService = translateService;
this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
/**
* Optional
* Allows to provide custom data.
* ```typescript
* import { from } from 'rxjs';
*
* const repositoryEntry = { name: 'ExampleEntry', type: 'c8y_Firmware' };
* const versions = [{ c8y_Firmware: { version: '1.0.0', url: 'http://example.com' } }];
*
* const initialState = {repositoryEntriesWithVersions$: from({ ...repositoryEntry, versions })};
* ```
*/
this.repositoryEntriesWithVersions$ = undefined;
/**
* Optional
* Allows to use custom badges templates.
* ```typescript
* import { gettext } from '@c8y/ngx-components';
*
* const badgeTemplates = { '=1': gettext('{{count}} version'), other: gettext('{{count}} versions') };
* const initialState = { badgeTemplates };
* ```
*/
this.badgeTemplates = { '=1': gettext('{{count}} version'), other: gettext('{{count}} versions') };
/**
* Optional
* Allows to provide custom modal title.
*/
this.title = gettext('Select repository entry');
/**
* Loads the content of the modal.
* Must be invoked by the modal's caller.
*/
this.load = new Subject();
/**
* Triggers an update of the item list emitted.
*/
this.updateInstallableList$ = new Subject();
/**
* Optional
* Emits a filter criteria object currently entered in the filter input.
* Use it to filter the items if you use custom repositoryEntriesWithVersions$.
*/
this.searchTerm = new BehaviorSubject({});
/**
* Optional
* Allows to provide device type query to restrict search criteria.
* Only takes effect when repositoryEntriesWithVersions$ is not provided,
* otherwise modal's caller have to provide already filtered data in the repositoryEntriesWithVersions$.
*/
this.deviceTypeQuery = {};
/**
* Optional
* Allows to provide query to restrict search criteria.
* Only takes effect when repositoryEntriesWithVersions$ is not provided,
* otherwise modal's caller have to provide already filtered data in the repositoryEntriesWithVersions$.
*/
this.searchQuery = {};
/**
* Optional
* Allows to provide custom labels for the buttons responsible for confirm/dismiss modal actions.
*/
this.labels = { ok: gettext('Save') };
/**
* Optional
* Allows to hide the name filter input field.
* By default, the filter input field is displayed.
*/
this.showFilter = true;
/**
* Optional
* Allows to show a warning that the search criteria should be narrowed down.
* By default, this warning is hidden.
*/
this.areMoreEntries = false;
/**
* Emits whenever a new repository binary have been selected in the modal.
*/
this.onChoiceUpdated = new EventEmitter();
/**
* Emits the list of selected options.
*/
this.resultEmitter = new EventEmitter();
/**
* Optional
* Allows to change selection mode.
* Supported options:
* * single: only single option can be selected.
* * multiple: multiple options can be selected.
*/
this.mode = ModalSelectionMode.SINGLE;
/**
* Allows to block selection of the other versions from the same repository entry.
*/
this.disableSelected = true;
this.filterCriteria = {};
this.repositoryEntries$ = this.load.pipe(switchMap(() => this.repositoryEntriesWithVersions$), mergeMap(mos => this.aggregate(mos)), tap(items => {
this.areMoreEntries = items.length >= this.PAGE_SIZE ? true : false;
}), tap(items => (this.repositoryEntries = items)));
this.modalEntries = merge(this.repositoryEntries$, this.updateInstallableList$.pipe(map((updateItemEvent) => {
const itemToUpdate = (this.repositoryEntries || []).find(item => item.groupId === updateItemEvent.object.groupId);
if (itemToUpdate) {
const optionToUpdate = (itemToUpdate.options || []).find(option => option.obj.id === updateItemEvent.object.selectedId);
if (optionToUpdate) {
optionToUpdate.template = updateItemEvent.template;
if (updateItemEvent.mapper) {
optionToUpdate.obj = updateItemEvent.mapper(optionToUpdate.obj);
}
}
}
return this.repositoryEntries;
})));
this.PAGE_SIZE = 100;
this.queriesUtil = new QueriesUtil();
}
ngOnInit() {
if (!this.repositoryType) {
throw new Error('Repository type must be defined');
}
if (!this.repositoryEntriesWithVersions$) {
this.repositoryEntriesWithVersions$ = of(1).pipe(mergeMap(() => this.repositoryService.listRepositoryEntries(this.repositoryType, {
query: this.queriesUtil.addAndFilter(this.deviceTypeQuery, has(this.searchQuery, 'name')
? { ...this.searchQuery, name: `*${this.searchQuery.name}*` }
: this.searchQuery),
params: { pageSize: this.PAGE_SIZE }
})), map(({ data }) => data), map(mos => this.getAndAssignRepositoryBinaries(mos)));
}
}
getAndAssignRepositoryBinaries(mos) {
mos.forEach(mo => {
mo.versions = this.repositoryService.listAllVersions(mo);
});
return mos;
}
search(filterCriteria) {
this.filterCriteria = omitBy({
...this.filterCriteria,
...filterCriteria
}, isEmpty);
if (!isEqual(this.filterCriteria, this.searchQuery)) {
this.searchTerm.next(this.filterCriteria);
this.searchQuery = this.filterCriteria;
this.load.next();
}
}
result(selectedItems) {
this.resultEmitter.emit(selectedItems);
}
async aggregate(mos) {
const repositoryType = this.repositoryType;
const selectedItems = this.selected;
return Promise.all(mos.map(async (repositoryEntry) => {
const options = this.getSelectModalOptions(await this.repositoryService.fetchAllItemsFromList(repositoryEntry.versions), selectedItems, repositoryEntry, repositoryType);
const selectModalObject = this.getSelectModalObject(repositoryEntry, options);
return selectModalObject;
}));
}
getSelectModalOptions(versions, selectedItems, repositoryEntry, repositoryType) {
const selectModalOptions = [];
versions.forEach(repositoryBinary => {
const isSelected = this.isBinaryRepositorySelected(selectedItems, repositoryEntry, repositoryBinary, repositoryType);
const { version } = repositoryBinary[`${repositoryType}`];
const bodyValue = version || `(${this.translateService.instant(gettext('not specified`version`'))})`;
const bodyClass = version ? '' : 'text-muted';
selectModalOptions.push({
body: [
{
value: bodyValue,
class: bodyClass
}
],
obj: {
id: repositoryBinary.id,
name: repositoryEntry.name,
version,
...(get(repositoryBinary, 'c8y_Patch.dependency') && {
dependency: get(repositoryBinary, 'c8y_Patch.dependency')
}),
...(get(repositoryBinary, 'c8y_Patch') && { isPatch: true }),
url: repositoryBinary[`${repositoryType}`].url,
softwareType: repositoryEntry.softwareType
},
selected: isSelected
});
});
return selectModalOptions;
}
isBinaryRepositorySelected(selectedItems, repositoryEntry, repositoryBinary, repositoryType) {
const isSelected = selectedItems
? selectedItems.filter(repositoryFragment => repositoryFragment.name === repositoryEntry.name &&
repositoryFragment.version === repositoryBinary[`${repositoryType}`].version).length > 0
: false;
return isSelected;
}
getSelectModalObject(repositoryEntry, options) {
const label = options.length === 1
? this.translateService.instant(this.badgeTemplates['=1'], { count: options.length })
: this.translateService.instant(this.badgeTemplates.other, { count: options.length });
const selectModalObject = {
groupId: repositoryEntry.id,
body: [
{ value: repositoryEntry.name, class: 'text-truncate' },
{ value: repositoryEntry.description, class: 'text-truncate text-muted' }
],
additionalInformation: { value: label, class: 'label label-info' },
options
};
return selectModalObject;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RepositorySelectModalComponent, deps: [{ token: i1.RepositoryService }, { token: i2.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: RepositorySelectModalComponent, selector: "c8y-repository-select-modal", providers: [
{
provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
useExisting: forwardRef(() => RepositorySelectModalComponent)
}
], ngImport: i0, template: "<c8y-select-modal\n [icon]=\"icon\"\n [title]=\"title\"\n [subTitle]=\"subTitle\"\n [items]=\"modalEntries | async\"\n [mode]=\"mode\"\n [disableSelected]=\"disableSelected\"\n [labels]=\"labels\"\n [showFilter]=\"showFilter\"\n [additionalFilterTemplate]=\"additionalFilterTemplate\"\n [areMoreEntries]=\"areMoreEntries\"\n [noItemsMessage]=\"noItemsMessage\"\n [hideEmptyItems]=\"hideEmptyItems\"\n (search)=\"search({ name: $event })\"\n (onChoiceUpdated)=\"onChoiceUpdated.emit($event)\"\n (result)=\"result($event)\"\n c8yProductExperience\n inherit\n suppressDataOverriding\n [actionData]=\"{ component: PRODUCT_EXPERIENCE.SHARED.COMPONENTS.REPOSITORY_SELECT_MODAL }\"\n></c8y-select-modal>\n", dependencies: [{ kind: "component", type: i3.SelectModalComponent, selector: "c8y-select-modal", inputs: ["icon", "title", "subTitle", "items", "mode", "disableSelected", "showFilter", "additionalFilterTemplate", "areMoreEntries", "labels", "noItemsMessage", "hideEmptyItems"], outputs: ["result", "search", "onChoiceUpdated"] }, { kind: "directive", type: i3.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RepositorySelectModalComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-repository-select-modal', providers: [
{
provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
useExisting: forwardRef(() => RepositorySelectModalComponent)
}
], template: "<c8y-select-modal\n [icon]=\"icon\"\n [title]=\"title\"\n [subTitle]=\"subTitle\"\n [items]=\"modalEntries | async\"\n [mode]=\"mode\"\n [disableSelected]=\"disableSelected\"\n [labels]=\"labels\"\n [showFilter]=\"showFilter\"\n [additionalFilterTemplate]=\"additionalFilterTemplate\"\n [areMoreEntries]=\"areMoreEntries\"\n [noItemsMessage]=\"noItemsMessage\"\n [hideEmptyItems]=\"hideEmptyItems\"\n (search)=\"search({ name: $event })\"\n (onChoiceUpdated)=\"onChoiceUpdated.emit($event)\"\n (result)=\"result($event)\"\n c8yProductExperience\n inherit\n suppressDataOverriding\n [actionData]=\"{ component: PRODUCT_EXPERIENCE.SHARED.COMPONENTS.REPOSITORY_SELECT_MODAL }\"\n></c8y-select-modal>\n" }]
}], ctorParameters: () => [{ type: i1.RepositoryService }, { type: i2.TranslateService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3NpdG9yeS1zZWxlY3QtbW9kYWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcmVwb3NpdG9yeS9zaGFyZWQvc2VsZWN0LW1vZGFsL3JlcG9zaXRvcnktc2VsZWN0LW1vZGFsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3JlcG9zaXRvcnkvc2hhcmVkL3NlbGVjdC1tb2RhbC9yZXBvc2l0b3J5LXNlbGVjdC1tb2RhbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQWUsTUFBTSxlQUFlLENBQUM7QUFDakYsT0FBTyxFQUFrQixXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDMUQsT0FBTyxFQUNMLE9BQU8sRUFLUCxrQkFBa0IsRUFHbEIsK0JBQStCLEVBQ2hDLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkQsT0FBTyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQWMsRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN2RSxPQUFPLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDL0QsT0FBTyxFQUVMLG9DQUFvQyxFQUtyQyxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDOzs7Ozs7QUFFMUQsa0JBQWtCO0FBQ2xCLGdHQUFnRztBQUNoRyxxSEFBcUg7QUFDckgsNkJBQTZCO0FBQzdCLHlCQUF5QjtBQUV6Qjs7Ozs7Ozs7Ozs7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a0JBVjFDLFNBQVM7K0JBQ0UsNkJBQTZCLGFBRTVCO3dCQUNUOzRCQUNFLE9BQU8sRUFBRSwrQkFBK0I7NEJBQ3hDLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLCtCQUErQixDQUFDO3lCQUM5RDtxQkFDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBmb3J3YXJkUmVmLCBUZW1wbGF0ZVJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSU1hbmFnZWRPYmplY3QsIFF1ZXJpZXNVdGlsIH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHtcbiAgZ2V0dGV4dCxcbiAgSVNlbGVjdE1vZGFsT2JqZWN0LFxuICBJU2VsZWN0TW9kYWxPcHRpb24sXG4gIElVcGRhdGVJdGVtRXZlbnQsXG4gIE1vZGFsTGFiZWxzLFxuICBNb2RhbFNlbGVjdGlvbk1vZGUsXG4gIFByb2R1Y3RFeHBlcmllbmNlRXZlbnQsXG4gIFByb2R1Y3RFeHBlcmllbmNlRXZlbnRTb3VyY2UsXG4gIFBST0RVQ1RfRVhQRVJJRU5DRV9FVkVOVF9TT1VSQ0Vcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBnZXQsIGhhcywgaXNFbXB0eSwgaXNFcXVhbCwgb21pdEJ5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgbWVyZ2UsIE9ic2VydmFibGUsIG9mLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBtYXAsIG1lcmdlTWFwLCBzd2l0Y2hNYXAsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7XG4gIEZpbHRlckNyaXRlcmlhLFxuICBQUk9EVUNUX0VYUEVSSUVOQ0VfUkVQT1NJVE9SWV9TSEFSRUQsXG4gIFJlcG9zaXRvcnlCaW5hcnksXG4gIFJlcG9zaXRvcnlDYXRlZ29yeSxcbiAgUmVwb3NpdG9yeVR5cGUsXG4gIFNlbGVjdGVkUmVwb3NpdG9yeUJpbmFyeVxufSBmcm9tICcuLi9yZXBvc2l0b3J5Lm1vZGVsJztcbmltcG9ydCB7IFJlcG9zaXRvcnlTZXJ2aWNlIH0gZnJvbSAnLi4vcmVwb3NpdG9yeS5zZXJ2aWNlJztcblxuLy8gTU9EQUwgU1RSVUNUVVJFXG4vLyAtIHNlbGVjdE1vZGFsT2JqZWN0IChyZXBvc2l0b3J5IGVudHJ5IChyZXBvc2l0b3J5Q2F0ZWdvcnkpIC0+IHR5cGUgYzh5X0Zpcm13YXJlL2M4eV9Tb2Z0d2FyZSlcbi8vICAgLS0gSVNlbGVjdE1vZGFsT3B0aW9uIChyZXBvc2l0b3J5IGJpbmFyeSBlbnRyeSAocmVwb3NpdG9yeUJpbmFyeSkgPT4gdHlwZSBjOHlfRmlybXdhcmVCaW5hcnkvYzh5X1NvZnR3YXJlQmluYXJ5KVxuLy8gICAtLSBJU2VsZWN0TW9kYWxPcHRpb24uLi5cbi8vIC0gc2VsZWN0TW9kYWxPYmplY3QuLi5cblxuLyoqXG4gKiBSZXBvc2l0b3J5U2VsZWN0TW9kYWxDb21wb25lbnQgZGlzcGxheXMgcmVwb3NpdG9yeSBlbnRyaWVzIG9wdGlvbnMgYW5kIGFsbG93cyB0byBzZWxlY3QgdGhlbS5cbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuICogaW1wb3J0IHsgUmVwb3NpdG9yeVNlbGVjdE1vZGFsQ29tcG9uZW50LCBNb2RhbFNlbGVjdGlvbk1vZGUsIFJlcG9zaXRvcnlUeXBlIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9yZXBvc2l0b3J5L3NoYXJlZCc7XG4gKlxuICogY29uc3QgaW5pdGlhbFN0YXRlID0ge1xuICogICByZXBvc2l0b3J5VHlwZTogUmVwb3NpdG9yeVR5cGUuRklSTVdBUkUsXG4gKiAgIHRpdGxlOiBnZXR0ZXh0KCdJbnN0YWxsIGZpcm13YXJlJyksXG4gKiAgIHN1YlRpdGxlOiBnZXR0ZXh0KCdBdmFpbGFibGUgZmlybXdhcmVzIG1hdGNoaW5nIHRoZSBkZXZpY2UgdHlwZScpLFxuICogICBpY29uOiAnYzh5LWZpcm13YXJlJyxcbiAqICAgbW9kZTogTW9kYWxTZWxlY3Rpb25Nb2RlLlNJTkdMRSxcbiAqICAgbGFiZWxzOiB7IG9rOiBnZXR0ZXh0KCdJbnN0YWxsJykgfSxcbiAqICAgZGlzYWJsZVNlbGVjdGVkOiBmYWxzZVxuICogfTtcbiAqXG4gKiBjb25zdCBtb2RhbCA9IHRoaXMuYnNNb2RhbC5zaG93KFJlcG9zaXRvcnlTZWxlY3RNb2RhbENvbXBvbmVudCwge1xuICogICBpZ25vcmVCYWNrZHJvcENsaWNrOiB0cnVlLFxuICogICBpbml0aWFsU3RhdGVcbiAqIH0pO1xuICpcbiAqIG1vZGFsLmNvbnRlbnQubG9hZC5uZXh0KCk7XG4gKiBtb2RhbC5jb250ZW50LnJlc3VsdEVtaXR0ZXIucGlwZSh0YWtlKDEpKS5zdWJzY3JpYmUoKGZpcm13YXJlKSA9PiB7XG4gKiB9KVxuICogYGBgXG4gKi9cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LXJlcG9zaXRvcnktc2VsZWN0LW1vZGFsJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3JlcG9zaXRvcnktc2VsZWN0LW1vZGFsLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogUFJPRFVDVF9FWFBFUklFTkNFX0VWRU5UX1NPVVJDRSxcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IFJlcG9zaXRvcnlTZWxlY3RNb2RhbENvbXBvbmVudClcbiAgICB9XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgUmVwb3NpdG9yeVNlbGVjdE1vZGFsQ29tcG9uZW50IGltcGxlbWVudHMgUHJvZHVjdEV4cGVyaWVuY2VFdmVudFNvdXJjZSB7XG4gIFBST0RVQ1RfRVhQRVJJRU5DRSA9IFBST0RVQ1RfRVhQRVJJRU5DRV9SRVBPU0lUT1JZX1NIQVJFRDtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEFsbG93cyB0byBwcm92aWRlIGN1c3RvbSBkYXRhLlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGltcG9ydCB7IGZyb20gfSBmcm9tICdyeGpzJztcbiAgICpcbiAgICogY29uc3QgcmVwb3NpdG9yeUVudHJ5ID0geyBuYW1lOiAnRXhhbXBsZUVudHJ5JywgdHlwZTogJ2M4eV9GaXJtd2FyZScgfTtcbiAgICogY29uc3QgdmVyc2lvbnMgPSBbeyBjOHlfRmlybXdhcmU6IHsgdmVyc2lvbjogJzEuMC4wJywgdXJsOiAnaHR0cDovL2V4YW1wbGUuY29tJyB9IH1dO1xuICAgKlxuICAgKiBjb25zdCBpbml0aWFsU3RhdGUgPSB7cmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnMkOiBmcm9tKHsgLi4ucmVwb3NpdG9yeUVudHJ5LCB2ZXJzaW9ucyB9KX07XG4gICAqIGBgYFxuICAgKi9cbiAgcmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnMkOiBPYnNlcnZhYmxlPElNYW5hZ2VkT2JqZWN0W10+ID0gdW5kZWZpbmVkO1xuICAvKipcbiAgICogUmVwb3NpdG9yeSBlbnRyeSB0eXBlLlxuICAgKi9cbiAgcmVwb3NpdG9yeVR5cGU6IFJlcG9zaXRvcnlUeXBlLkZJUk1XQVJFIHwgUmVwb3NpdG9yeVR5cGUuU09GVFdBUkU7XG4gIC8qKlxuICAgKiBPcHRpb25hbFxuICAgKiBBbGxvd3MgdG8gdXNlIGN1c3RvbSBiYWRnZXMgdGVtcGxhdGVzLlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGltcG9ydCB7IGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbiAgICpcbiAgICogY29uc3QgYmFkZ2VUZW1wbGF0ZXMgPSB7ICc9MSc6IGdldHRleHQoJ3t7Y291bnR9fSB2ZXJzaW9uJyksIG90aGVyOiBnZXR0ZXh0KCd7e2NvdW50fX0gdmVyc2lvbnMnKSB9O1xuICAgKiBjb25zdCBpbml0aWFsU3RhdGUgPSB7IGJhZGdlVGVtcGxhdGVzIH07XG4gICAqIGBgYFxuICAgKi9cbiAgYmFkZ2VUZW1wbGF0ZXMgPSB7ICc9MSc6IGdldHRleHQoJ3t7Y291bnR9fSB2ZXJzaW9uJyksIG90aGVyOiBnZXR0ZXh0KCd7e2NvdW50fX0gdmVyc2lvbnMnKSB9O1xuICAvKipcbiAgICogT3B0aW9uYWxcbiAgICogQWxsb3dzIHRvIHByb3ZpZGUgY3VzdG9tIG1vZGFsIHRpdGxlLlxuICAgKi9cbiAgdGl0bGU6IHN0cmluZyA9IGdldHRleHQoJ1NlbGVjdCByZXBvc2l0b3J5IGVudHJ5Jyk7XG4gIC8qKlxuICAgKiBPcHRpb25hbFxuICAgKiBBbGxvd3MgdG8gcHJvdmlkZSBjdXN0b20gbW9kYWwgc3VidGl0bGUuXG4gICAqL1xuICBzdWJUaXRsZTogc3RyaW5nO1xuICAvKipcbiAgICogTG9hZHMgdGhlIGNvbnRlbnQgb2YgdGhlIG1vZGFsLlxuICAgKiBNdXN0IGJlIGludm9rZWQgYnkgdGhlIG1vZGFsJ3MgY2FsbGVyLlxuICAgKi9cbiAgbG9hZDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0KCk7XG4gIC8qKlxuICAgKiBUcmlnZ2VycyBhbiB1cGRhdGUgb2YgdGhlIGl0ZW0gbGlzdCBlbWl0dGVkLlxuICAgKi9cbiAgdXBkYXRlSW5zdGFsbGFibGVMaXN0JDogU3ViamVjdDxJVXBkYXRlSXRlbUV2ZW50PGFueT4+ID0gbmV3IFN1YmplY3QoKTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEVtaXRzIGEgZmlsdGVyIGNyaXRlcmlhIG9iamVjdCBjdXJyZW50bHkgZW50ZXJlZCBpbiB0aGUgZmlsdGVyIGlucHV0LlxuICAgKiBVc2UgaXQgdG8gZmlsdGVyIHRoZSBpdGVtcyBpZiB5b3UgdXNlIGN1c3RvbSByZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9ucyQuXG4gICAqL1xuICBzZWFyY2hUZXJtOiBCZWhhdmlvclN1YmplY3Q8RmlsdGVyQ3JpdGVyaWE+ID0gbmV3IEJlaGF2aW9yU3ViamVjdCh7fSk7XG4gIC8qKlxuICAgKiBPcHRpb25hbFxuICAgKiBBbGxvd3MgdG8gcHJvdmlkZSBkZXZpY2UgdHlwZSBxdWVyeSB0byByZXN0cmljdCBzZWFyY2ggY3JpdGVyaWEuXG4gICAqIE9ubHkgdGFrZXMgZWZmZWN0IHdoZW4gcmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnMkIGlzIG5vdCBwcm92aWRlZCxcbiAgICogb3RoZXJ3aXNlIG1vZGFsJ3MgY2FsbGVyIGhhdmUgdG8gcHJvdmlkZSBhbHJlYWR5IGZpbHRlcmVkIGRhdGEgaW4gdGhlIHJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zJC5cbiAgICovXG4gIGRldmljZVR5cGVRdWVyeTogYW55ID0ge307XG4gIC8qKlxuICAgKiBPcHRpb25hbFxuICAgKiBBbGxvd3MgdG8gcHJvdmlkZSBxdWVyeSB0byByZXN0cmljdCBzZWFyY2ggY3JpdGVyaWEuXG4gICAqIE9ubHkgdGFrZXMgZWZmZWN0IHdoZW4gcmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnMkIGlzIG5vdCBwcm92aWRlZCxcbiAgICogb3RoZXJ3aXNlIG1vZGFsJ3MgY2FsbGVyIGhhdmUgdG8gcHJvdmlkZSBhbHJlYWR5IGZpbHRlcmVkIGRhdGEgaW4gdGhlIHJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zJC5cbiAgICovXG4gIHNlYXJjaFF1ZXJ5OiBhbnkgPSB7fTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEFsbG93cyB0byBwcm92aWRlIGN1c3RvbSBsYWJlbHMgZm9yIHRoZSBidXR0b25zIHJlc3BvbnNpYmxlIGZvciBjb25maXJtL2Rpc21pc3MgbW9kYWwgYWN0aW9ucy5cbiAgICovXG4gIGxhYmVsczogTW9kYWxMYWJlbHMgPSB7IG9rOiBnZXR0ZXh0KCdTYXZlJykgfTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEFsbG93cyB0byBoaWRlIHRoZSBuYW1lIGZpbHRlciBpbnB1dCBmaWVsZC5cbiAgICogQnkgZGVmYXVsdCwgdGhlIGZpbHRlciBpbnB1dCBmaWVsZCBpcyBkaXNwbGF5ZWQuXG4gICAqL1xuICBzaG93RmlsdGVyID0gdHJ1ZTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEFsbG93cyB0byBzaG93IGEgd2FybmluZyB0aGF0IHRoZSBzZWFyY2ggY3JpdGVyaWEgc2hvdWxkIGJlIG5hcnJvd2VkIGRvd24uXG4gICAqIEJ5IGRlZmF1bHQsIHRoaXMgd2FybmluZyBpcyBoaWRkZW4uXG4gICAqL1xuICBhcmVNb3JlRW50cmllcyA9IGZhbHNlO1xuICAvKipcbiAgICogT3B0aW9uYWxcbiAgICogQWxsb3dzIHRvIGRpc3BsYXkgYSBtb3JlIHNwZWNpZmljIHRoYW4gdGhlIGRlZmF1bHQgbWVzc2FnZSBpbiBjYXNlIHRoZXJlIGFyZSBubyBpdGVtcyB0byBkaXNwbGF5LlxuICAgKi9cbiAgbm9JdGVtc01lc3NhZ2U6IHN0cmluZztcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEFsbG93cyB0byBwYXNzIHRoZSBhcnJheSBvZiBpdGVtcy4gRWFjaCBpdGVtIGZyb20gdGhpcyBhcnJheSB3aWxsIGJlIG1hcmtlZCBhcyBzZWxlY3RlZCBpbiB0aGUgbW9kYWwuXG4gICAqL1xuICBzZWxlY3RlZDogU2VsZWN0ZWRSZXBvc2l0b3J5QmluYXJ5W107XG4gIC8qKlxuICAgKiBFbWl0cyB3aGVuZXZlciBhIG5ldyByZXBvc2l0b3J5IGJpbmFyeSBoYXZlIGJlZW4gc2VsZWN0ZWQgaW4gdGhlIG1vZGFsLlxuICAgKi9cbiAgb25DaG9pY2VVcGRhdGVkOiBFdmVudEVtaXR0ZXI8SVNlbGVjdE1vZGFsT2JqZWN0PiA9IG5ldyBFdmVudEVtaXR0ZXI8SVNlbGVjdE1vZGFsT2JqZWN0PigpO1xuICAvKipcbiAgICogRW1pdHMgdGhlIGxpc3Qgb2Ygc2VsZWN0ZWQgb3B0aW9ucy5cbiAgICovXG4gIHJlc3VsdEVtaXR0ZXI6IEV2ZW50RW1pdHRlcjxTZWxlY3RlZFJlcG9zaXRvcnlCaW5hcnlbXT4gPSBuZXcgRXZlbnRFbWl0dGVyPFxuICAgIFNlbGVjdGVkUmVwb3NpdG9yeUJpbmFyeVtdXG4gID4oKTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEFsbG93cyB0byBjaGFuZ2Ugc2VsZWN0aW9uIG1vZGUuXG4gICAqIFN1cHBvcnRlZCBvcHRpb25zOlxuICAgKiAgICogc2luZ2xlOiBvbmx5IHNpbmdsZSBvcHRpb24gY2FuIGJlIHNlbGVjdGVkLlxuICAgKiAgICogbXVsdGlwbGU6IG11bHRpcGxlIG9wdGlvbnMgY2FuIGJlIHNlbGVjdGVkLlxuICAgKi9cbiAgbW9kZTogTW9kYWxTZWxlY3Rpb25Nb2RlID0gTW9kYWxTZWxlY3Rpb25Nb2RlLlNJTkdMRTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIEFsbG93cyB0byB1c2UgY3VzdG9tIGljb24gaW4gdGhlIG1vZGFsIGhlYWRlci5cbiAgICovXG4gIGljb246IHN0cmluZztcbiAgLyoqXG4gICAqIEFsbG93cyB0byBibG9jayBzZWxlY3Rpb24gb2YgdGhlIG90aGVyIHZlcnNpb25zIGZyb20gdGhlIHNhbWUgcmVwb3NpdG9yeSBlbnRyeS5cbiAgICovXG4gIGRpc2FibGVTZWxlY3RlZCA9IHRydWU7XG4gIC8qKlxuICAgKiBBbGxvd3MgdG8gaGlkZSBpdGVtcyB0aGF0IGhhdmUgbm8gb3B0aW9ucyBhdmFpbGFibGUuXG4gICAqL1xuICBoaWRlRW1wdHlJdGVtczogYm9vbGVhbjtcblxuICBmaWx0ZXJDcml0ZXJpYTogRmlsdGVyQ3JpdGVyaWEgPSB7fTtcblxuICByZXBvc2l0b3J5RW50cmllcyQ6IE9ic2VydmFibGU8SVNlbGVjdE1vZGFsT2JqZWN0W10+ID0gdGhpcy5sb2FkLnBpcGUoXG4gICAgc3dpdGNoTWFwKCgpID0+IHRoaXMucmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnMkKSxcbiAgICBtZXJnZU1hcChtb3MgPT4gdGhpcy5hZ2dyZWdhdGUobW9zKSksXG4gICAgdGFwKGl0ZW1zID0+IHtcbiAgICAgIHRoaXMuYXJlTW9yZUVudHJpZXMgPSBpdGVtcy5sZW5ndGggPj0gdGhpcy5QQUdFX1NJWkUgPyB0cnVlIDogZmFsc2U7XG4gICAgfSksXG4gICAgdGFwKGl0ZW1zID0+ICh0aGlzLnJlcG9zaXRvcnlFbnRyaWVzID0gaXRlbXMpKVxuICApO1xuXG4gIG1vZGFsRW50cmllczogT2JzZXJ2YWJsZTxJU2VsZWN0TW9kYWxPYmplY3RbXT4gPSBtZXJnZShcbiAgICB0aGlzLnJlcG9zaXRvcnlFbnRyaWVzJCxcbiAgICB0aGlzLnVwZGF0ZUluc3RhbGxhYmxlTGlzdCQucGlwZShcbiAgICAgIG1hcCgodXBkYXRlSXRlbUV2ZW50OiBJVXBkYXRlSXRlbUV2ZW50PGFueT4pID0+IHtcbiAgICAgICAgY29uc3QgaXRlbVRvVXBkYXRlOiBJU2VsZWN0TW9kYWxPYmplY3QgPSAodGhpcy5yZXBvc2l0b3J5RW50cmllcyB8fCBbXSkuZmluZChcbiAgICAgICAgICBpdGVtID0+IGl0ZW0uZ3JvdXBJZCA9PT0gdXBkYXRlSXRlbUV2ZW50Lm9iamVjdC5ncm91cElkXG4gICAgICAgICk7XG4gICAgICAgIGlmIChpdGVtVG9VcGRhdGUpIHtcbiAgICAgICAgICBjb25zdCBvcHRpb25Ub1VwZGF0ZTogSVNlbGVjdE1vZGFsT3B0aW9uID0gKGl0ZW1Ub1VwZGF0ZS5vcHRpb25zIHx8IFtdKS5maW5kKFxuICAgICAgICAgICAgb3B0aW9uID0+IG9wdGlvbi5vYmouaWQgPT09ICh1cGRhdGVJdGVtRXZlbnQub2JqZWN0IGFzIGFueSkuc2VsZWN0ZWRJZFxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKG9wdGlvblRvVXBkYXRlKSB7XG4gICAgICAgICAgICBvcHRpb25Ub1VwZGF0ZS50ZW1wbGF0ZSA9IHVwZGF0ZUl0ZW1FdmVudC50ZW1wbGF0ZTtcbiAgICAgICAgICAgIGlmICh1cGRhdGVJdGVtRXZlbnQubWFwcGVyKSB7XG4gICAgICAgICAgICAgIG9wdGlvblRvVXBkYXRlLm9iaiA9IHVwZGF0ZUl0ZW1FdmVudC5tYXBwZXIob3B0aW9uVG9VcGRhdGUub2JqKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMucmVwb3NpdG9yeUVudHJpZXM7XG4gICAgICB9KVxuICAgIClcbiAgKTtcblxuICAvKipcbiAgICogT3B0aW9uYWxcbiAgICogQWxsb3dzIHRvIHByb3ZpZGUgYWRkaXRpb25hbCB0ZW1wbGF0ZSB0aGF0IHdpbGwgYmUgcmVuZGVyZWQgaW4gdGhlXG4gICAqIGZpbHRlcnMgYmxvY2sgb24gdG9wIG9mIHRoZSByZXN1bHRzIGxpc3QgaW4gdGhlIHNlbGVjdCBtb2RhbC5cbiAgICovXG4gIGFkZGl0aW9uYWxGaWx0ZXJUZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PjtcblxuICBwcm9kdWN0RXhwZXJpZW5jZUV2ZW50OiBQcm9kdWN0RXhwZXJpZW5jZUV2ZW50O1xuXG4gIHByaXZhdGUgUEFHRV9TSVpFID0gMTAwO1xuICBwcml2YXRlIHF1ZXJpZXNVdGlsOiBRdWVyaWVzVXRpbDtcbiAgcHJpdmF0ZSByZXBvc2l0b3J5RW50cmllczogSVNlbGVjdE1vZGFsT2JqZWN0W107XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZXBvc2l0b3J5U2VydmljZTogUmVwb3NpdG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0cmFuc2xhdGVTZXJ2aWNlOiBUcmFuc2xhdGVTZXJ2aWNlXG4gICkge1xuICAgIHRoaXMucXVlcmllc1V0aWwgPSBuZXcgUXVlcmllc1V0aWwoKTtcbiAgfVxuXG4gIG5nT25Jbml0KCkge1xuICAgIGlmICghdGhpcy5yZXBvc2l0b3J5VHlwZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZXBvc2l0b3J5IHR5cGUgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zJCkge1xuICAgICAgdGhpcy5yZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9ucyQgPSBvZigxKS5waXBlKFxuICAgICAgICBtZXJnZU1hcCgoKSA9PlxuICAgICAgICAgIHRoaXMucmVwb3NpdG9yeVNlcnZpY2UubGlzdFJlcG9zaXRvcnlFbnRyaWVzKHRoaXMucmVwb3NpdG9yeVR5cGUsIHtcbiAgICAgICAgICAgIHF1ZXJ5OiB0aGlzLnF1ZXJpZXNVdGlsLmFkZEFuZEZpbHRlcihcbiAgICAgICAgICAgICAgdGhpcy5kZXZpY2VUeXBlUXVlcnksXG4gICAgICAgICAgICAgIGhhcyh0aGlzLnNlYXJjaFF1ZXJ5LCAnbmFtZScpXG4gICAgICAgICAgICAgICAgPyB7IC4uLnRoaXMuc2VhcmNoUXVlcnksIG5hbWU6IGAqJHt0aGlzLnNlYXJjaFF1ZXJ5Lm5hbWV9KmAgfVxuICAgICAgICAgICAgICAgIDogdGhpcy5zZWFyY2hRdWVyeVxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIHBhcmFtczogeyBwYWdlU2l6ZTogdGhpcy5QQUdFX1NJWkUgfVxuICAgICAgICAgIH0pXG4gICAgICAgICksXG4gICAgICAgIG1hcCgoeyBkYXRhIH0pID0+IGRhdGEpLFxuICAgICAgICBtYXAobW9zID0+IHRoaXMuZ2V0QW5kQXNzaWduUmVwb3NpdG9yeUJpbmFyaWVzKG1vcykpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIGdldEFuZEFzc2lnblJlcG9zaXRvcnlCaW5hcmllcyhtb3M6IElNYW5hZ2VkT2JqZWN0W10pIHtcbiAgICBtb3MuZm9yRWFjaChtbyA9PiB7XG4gICAgICBtby52ZXJzaW9ucyA9IHRoaXMucmVwb3NpdG9yeVNlcnZpY2UubGlzdEFsbFZlcnNpb25zKG1vKTtcbiAgICB9KTtcbiAgICByZXR1cm4gbW9zO1xuICB9XG5cbiAgc2VhcmNoKGZpbHRlckNyaXRlcmlhOiBGaWx0ZXJDcml0ZXJpYSkge1xuICAgIHRoaXMuZmlsdGVyQ3JpdGVyaWEgPSBvbWl0QnkoXG4gICAgICB7XG4gICAgICAgIC4uLnRoaXMuZmlsdGVyQ3JpdGVyaWEsXG4gICAgICAgIC4uLmZpbHRlckNyaXRlcmlhXG4gICAgICB9LFxuICAgICAgaXNFbXB0eVxuICAgICk7XG5cbiAgICBpZiAoIWlzRXF1YWwodGhpcy5maWx0ZXJDcml0ZXJpYSwgdGhpcy5zZWFyY2hRdWVyeSkpIHtcbiAgICAgIHRoaXMuc2VhcmNoVGVybS5uZXh0KHRoaXMuZmlsdGVyQ3JpdGVyaWEpO1xuICAgICAgdGhpcy5zZWFyY2hRdWVyeSA9IHRoaXMuZmlsdGVyQ3JpdGVyaWE7XG4gICAgICB0aGlzLmxvYWQubmV4dCgpO1xuICAgIH1cbiAgfVxuXG4gIHJlc3VsdChzZWxlY3RlZEl0ZW1zOiBTZWxlY3RlZFJlcG9zaXRvcnlCaW5hcnlbXSkge1xuICAgIHRoaXMucmVzdWx0RW1pdHRlci5lbWl0KHNlbGVjdGVkSXRlbXMpO1xuICB9XG5cbiAgYXN5bmMgYWdncmVnYXRlKG1vczogSU1hbmFnZWRPYmplY3RbXSk6IFByb21pc2U8SVNlbGVjdE1vZGFsT2JqZWN0W10+IHtcbiAgICBjb25zdCByZXBvc2l0b3J5VHlwZSA9IHRoaXMucmVwb3NpdG9yeVR5cGU7XG4gICAgY29uc3Qgc2VsZWN0ZWRJdGVtczogU2VsZWN0ZWRSZXBvc2l0b3J5QmluYXJ5W10gPSB0aGlzLnNlbGVjdGVkO1xuXG4gICAgcmV0dXJuIFByb21pc2UuYWxsKFxuICAgICAgbW9zLm1hcChhc3luYyByZXBvc2l0b3J5RW50cnkgPT4ge1xuICAgICAgICBjb25zdCBvcHRpb25zOiBJU2VsZWN0TW9kYWxPcHRpb25bXSA9IHRoaXMuZ2V0U2VsZWN0TW9kYWxPcHRpb25zKFxuICAgICAgICAgIGF3YWl0IHRoaXMucmVwb3NpdG9yeVNlcnZpY2UuZmV0Y2hBbGxJdGVtc0Zyb21MaXN0KHJlcG9zaXRvcnlFbnRyeS52ZXJzaW9ucyksXG4gICAgICAgICAgc2VsZWN0ZWRJdGVtcyxcbiAgICAgICAgICByZXBvc2l0b3J5RW50cnkgYXMgUmVwb3NpdG9yeUNhdGVnb3J5LFxuICAgICAgICAgIHJlcG9zaXRvcnlUeXBlXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHNlbGVjdE1vZGFsT2JqZWN0ID0gdGhpcy5nZXRTZWxlY3RNb2RhbE9iamVjdChcbiAgICAgICAgICByZXBvc2l0b3J5RW50cnkgYXMgUmVwb3NpdG9yeUNhdGVnb3J5LFxuICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgKTtcblxuICAgICAgICByZXR1cm4gc2VsZWN0TW9kYWxPYmplY3Q7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBnZXRTZWxlY3RNb2RhbE9wdGlvbnMoXG4gICAgdmVyc2lvbnM6IFJlcG9zaXRvcnlCaW5hcnlbXSxcbiAgICBzZWxlY3RlZEl0ZW1zOiBTZWxlY3RlZFJlcG9zaXRvcnlCaW5hcnlbXSxcbiAgICByZXBvc2l0b3J5RW50cnk6IFJlcG9zaXRvcnlDYXRlZ29yeSxcbiAgICByZXBvc2l0b3J5VHlwZTogUmVwb3NpdG9yeVR5cGVcbiAgKTogSVNlbGVjdE1vZGFsT3B0aW9uW10ge1xuICAgIGNvbnN0IHNlbGVjdE1vZGFsT3B0aW9uczogSVNlbGVjdE1vZGFsT3B0aW9uW10gPSBbXTtcbiAgICB2ZXJzaW9ucy5mb3JFYWNoKHJlcG9zaXRvcnlCaW5hcnkgPT4ge1xuICAgICAgY29uc3QgaXNTZWxlY3RlZDogYm9vbGVhbiA9IHRoaXMuaXNCaW5hcnlSZXBvc2l0b3J5U2VsZWN0ZWQoXG4gICAgICAgIHNlbGVjdGVkSXRlbXMsXG4gICAgICAgIHJlcG9zaXRvcnlFbnRyeSxcbiAgICAgICAgcmVwb3NpdG9yeUJpbmFyeSxcbiAgICAgICAgcmVwb3NpdG9yeVR5cGVcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHsgdmVyc2lvbiB9ID0gcmVwb3NpdG9yeUJpbmFyeVtgJHtyZXBvc2l0b3J5VHlwZX1gXTtcbiAgICAgIGNvbnN0IGJvZHlWYWx1ZSA9XG4gICAgICAgIHZlcnNpb24gfHwgYCgke3RoaXMudHJhbnNsYXRlU2VydmljZS5pbnN0YW50KGdldHRleHQoJ25vdCBzcGVjaWZpZWRgdmVyc2lvbmAnKSl9KWA7XG4gICAgICBjb25zdCBib2R5Q2xhc3MgPSB2ZXJzaW9uID8gJycgOiAndGV4dC1tdXRlZCc7XG4gICAgICBzZWxlY3RNb2RhbE9wdGlvbnMucHVzaCh7XG4gICAgICAgIGJvZHk6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICB2YWx1ZTogYm9keVZhbHVlLFxuICAgICAgICAgICAgY2xhc3M6IGJvZHlDbGFzc1xuICAgICAgICAgIH1cbiAgICAgICAgXSxcbiAgICAgICAgb2JqOiB7XG4gICAgICAgICAgaWQ6IHJlcG9zaXRvcnlCaW5hcnkuaWQsXG4gICAgICAgICAgbmFtZTogcmVwb3NpdG9yeUVudHJ5Lm5hbWUsXG4gICAgICAgICAgdmVyc2lvbixcbiAgICAgICAgICAuLi4oZ2V0KHJlcG9zaXRvcnlCaW5hcnksICdjOHlfUGF0Y2guZGVwZW5kZW5jeScpICYmIHtcbiAgICAgICAgICAgIGRlcGVuZGVuY3k6IGdldChyZXBvc2l0b3J5QmluYXJ5LCAnYzh5X1BhdGNoLmRlcGVuZGVuY3knKVxuICAgICAgICAgIH0pLFxuICAgICAgICAgIC4uLihnZXQocmVwb3NpdG9yeUJpbmFyeSwgJ2M4eV9QYXRjaCcpICYmIHsgaXNQYXRjaDogdHJ1ZSB9KSxcbiAgICAgICAgICB1cmw6IHJlcG9zaXRvcnlCaW5hcnlbYCR7cmVwb3NpdG9yeVR5cGV9YF0udXJsLFxuICAgICAgICAgIHNvZnR3YXJlVHlwZTogcmVwb3NpdG9yeUVudHJ5LnNvZnR3YXJlVHlwZVxuICAgICAgICB9LFxuICAgICAgICBzZWxlY3RlZDogaXNTZWxlY3RlZFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHNlbGVjdE1vZGFsT3B0aW9ucztcbiAgfVxuXG4gIGlzQmluYXJ5UmVwb3NpdG9yeVNlbGVjdGVkKFxuICAgIHNlbGVjdGVkSXRlbXM6IFNlbGVjdGVkUmVwb3NpdG9yeUJpbmFyeVtdLFxuICAgIHJlcG9zaXRvcnlFbnRyeTogUmVwb3NpdG9yeUNhdGVnb3J5LFxuICAgIHJlcG9zaXRvcnlCaW5hcnk6IFJlcG9zaXRvcnlCaW5hcnksXG4gICAgcmVwb3NpdG9yeVR5cGU6IFJlcG9zaXRvcnlUeXBlXG4gICk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGlzU2VsZWN0ZWQgPSBzZWxlY3RlZEl0ZW1zXG4gICAgICA/IHNlbGVjdGVkSXRlbXMuZmlsdGVyKFxuICAgICAgICAgIHJlcG9zaXRvcnlGcmFnbWVudCA9PlxuICAgICAgICAgICAgcmVwb3NpdG9yeUZyYWdtZW50Lm5hbWUgPT09IHJlcG9zaXRvcnlFbnRyeS5uYW1lICYmXG4gICAgICAgICAgICByZXBvc2l0b3J5RnJhZ21lbnQudmVyc2lvbiA9PT0gcmVwb3NpdG9yeUJpbmFyeVtgJHtyZXBvc2l0b3J5VHlwZX1gXS52ZXJzaW9uXG4gICAgICAgICkubGVuZ3RoID4gMFxuICAgICAgOiBmYWxzZTtcblxuICAgIHJldHVybiBpc1NlbGVjdGVkO1xuICB9XG5cbiAgZ2V0U2VsZWN0TW9kYWxPYmplY3QoXG4gICAgcmVwb3NpdG9yeUVudHJ5OiBSZXBvc2l0b3J5Q2F0ZWdvcnksXG4gICAgb3B0aW9uczogSVNlbGVjdE1vZGFsT3B0aW9uW11cbiAgKTogSVNlbGVjdE1vZGFsT2JqZWN0IHtcbiAgICBjb25zdCBsYWJlbCA9XG4gICAgICBvcHRpb25zLmxlbmd0aCA9PT0gMVxuICAgICAgICA/IHRoaXMudHJhbnNsYXRlU2VydmljZS5pbnN0YW50KHRoaXMuYmFkZ2VUZW1wbGF0ZXNbJz0xJ10sIHsgY291bnQ6IG9wdGlvbnMubGVuZ3RoIH0pXG4gICAgICAgIDogdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQodGhpcy5iYWRnZVRlbXBsYXRlcy5vdGhlciwgeyBjb3VudDogb3B0aW9ucy5sZW5ndGggfSk7XG5cbiAgICBjb25zdCBzZWxlY3RNb2RhbE9iamVjdDogSVNlbGVjdE1vZGFsT2JqZWN0ID0ge1xuICAgICAgZ3JvdXBJZDogcmVwb3NpdG9yeUVudHJ5LmlkLFxuICAgICAgYm9keTogW1xuICAgICAgICB7IHZhbHVlOiByZXBvc2l0b3J5RW50cnkubmFtZSwgY2xhc3M6ICd0ZXh0LXRydW5jYXRlJyB9LFxuICAgICAgICB7IHZhbHVlOiByZXBvc2l0b3J5RW50cnkuZGVzY3JpcHRpb24sIGNsYXNzOiAndGV4dC10cnVuY2F0ZSB0ZXh0LW11dGVkJyB9XG4gICAgICBdLFxuICAgICAgYWRkaXRpb25hbEluZm9ybWF0aW9uOiB7IHZhbHVlOiBsYWJlbCwgY2xhc3M6ICdsYWJlbCBsYWJlbC1pbmZvJyB9LFxuICAgICAgb3B0aW9uc1xuICAgIH07XG5cbiAgICByZXR1cm4gc2VsZWN0TW9kYWxPYmplY3Q7XG4gIH1cbn1cbiIsIjxjOHktc2VsZWN0LW1vZGFsXG4gIFtpY29uXT1cImljb25cIlxuICBbdGl0bGVdPVwidGl0bGVcIlxuICBbc3ViVGl0bGVdPVwic3ViVGl0bGVcIlxuICBbaXRlbXNdPVwibW9kYWxFbnRyaWVzIHwgYXN5bmNcIlxuICBbbW9kZV09XCJtb2RlXCJcbiAgW2Rpc2FibGVTZWxlY3RlZF09XCJkaXNhYmxlU2VsZWN0ZWRcIlxuICBbbGFiZWxzXT1cImxhYmVsc1wiXG4gIFtzaG93RmlsdGVyXT1cInNob3dGaWx0ZXJcIlxuICBbYWRkaXRpb25hbEZpbHRlclRlbXBsYXRlXT1cImFkZGl0aW9uYWxGaWx0ZXJUZW1wbGF0ZVwiXG4gIFthcmVNb3JlRW50cmllc109XCJhcmVNb3JlRW50cmllc1wiXG4gIFtub0l0ZW1zTWVzc2FnZV09XCJub0l0ZW1zTWVzc2FnZVwiXG4gIFtoaWRlRW1wdHlJdGVtc109XCJoaWRlRW1wdHlJdGVtc1wiXG4gIChzZWFyY2gpPVwic2VhcmNoKHsgbmFtZTogJGV2ZW50IH0pXCJcbiAgKG9uQ2hvaWNlVXBkYXRlZCk9XCJvbkNob2ljZVVwZGF0ZWQuZW1pdCgkZXZlbnQpXCJcbiAgKHJlc3VsdCk9XCJyZXN1bHQoJGV2ZW50KVwiXG4gIGM4eVByb2R1Y3RFeHBlcmllbmNlXG4gIGluaGVyaXRcbiAgc3VwcHJlc3NEYXRhT3ZlcnJpZGluZ1xuICBbYWN0aW9uRGF0YV09XCJ7IGNvbXBvbmVudDogUFJPRFVDVF9FWFBFUklFTkNFLlNIQVJFRC5DT01QT05FTlRTLlJFUE9TSVRPUllfU0VMRUNUX01PREFMIH1cIlxuPjwvYzh5LXNlbGVjdC1tb2RhbD5cbiJdfQ==