@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
205 lines • 56.7 kB
JavaScript
import { Component, EventEmitter, Input, Output, TemplateRef, ViewChild } from '@angular/core';
import { QueriesUtil } from '@c8y/client';
import { ModalSelectionMode, gettext } from '@c8y/ngx-components';
import { PRODUCT_EXPERIENCE_REPOSITORY_SHARED, RepositorySelectModalComponent, RepositoryService, RepositoryType } from '@c8y/ngx-components/repository/shared';
import { get } from 'lodash-es';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BehaviorSubject, Subject, combineLatest, from, of, pipe } from 'rxjs';
import { distinctUntilChanged, filter, map, mergeMap, shareReplay, switchMap, takeUntil, tap } from 'rxjs/operators';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/ngx-components/repository/shared";
import * as i2 from "ngx-bootstrap/modal";
import * as i3 from "@angular/common";
import * as i4 from "@c8y/ngx-components";
import * as i5 from "@angular/forms";
import * as i6 from "ngx-bootstrap/tooltip";
import * as i7 from "./device-software-list.component";
export class InstalledSoftwareComponent {
constructor(repository, bsModal) {
this.repository = repository;
this.bsModal = bsModal;
this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
this.changes = new EventEmitter();
this.showSoftwareChanges = new EventEmitter();
this.alreadyInstalledMessage = gettext('{{ name }} (v. {{ version }}) is already installed on this device');
this.showFilter = false;
this.supportsSoftwareOperations = false;
this.textFilter$ = new BehaviorSubject('');
this.softwareTypeFilter$ = new BehaviorSubject('');
this.operationTypes = ['c8y_SoftwareUpdate', 'c8y_SoftwareList', 'c8y_Software'];
this.destroyed$ = new Subject();
this.filterCriteria$ = combineLatest([this.textFilter$, this.softwareTypeFilter$]).pipe(map(([textFilter, softwareTypeFilter]) => ({
name: textFilter,
softwareType: softwareTypeFilter
})), map(filterCriteria => !filterCriteria.name && !filterCriteria.softwareType ? null : filterCriteria));
this.queriesUtil = new QueriesUtil();
}
ngOnInit() {
const supportedOperations = get(this.device, 'c8y_SupportedOperations', []);
this.supportsSoftwareOperations = this.operationTypes.some(operationType => supportedOperations.indexOf(operationType) > -1);
}
installSoftware() {
const { resultEmitter, choiceEmitter, updateInstallableList$ } = this.displaySoftwareSelectModal({
title: gettext('Install software'),
subTitle: gettext('Available softwares matching the device type'),
labels: { ok: gettext('Install') },
noItemsMessage: gettext('No matching software available.'),
showAdditionalFilter: true,
additionalFilterTemplate: this.softwareTypeTemplate,
repositoryEntriesWithVersions$: of([]),
repositoryEntriesWithVersionsFn$: modal => this.getInstallableSoftwareListWithVersions$(modal.content.searchTerm)
});
resultEmitter.pipe(takeUntil(this.destroyed$)).subscribe(softwareToInstall => {
this.emitSoftwareInstall(softwareToInstall);
this.showSoftwareChanges.emit();
});
choiceEmitter
.pipe(this.isSoftwareInstalledOnDevicePipe(updateInstallableList$), takeUntil(this.destroyed$))
.subscribe(({ item }) => updateInstallableList$.next({
object: item,
template: this.alreadyInstalledWarningTemplate,
mapper: object => {
object.installed = true;
return object;
}
}));
}
updateSoftware(softwareToUpdate) {
const { resultEmitter, choiceEmitter, updateInstallableList$ } = this.displaySoftwareSelectModal({
title: gettext('Update software'),
subTitle: gettext('Select one of the available software versions'),
labels: { ok: gettext('Update') },
noItemsMessage: gettext('No other software versions available.'),
showFilter: false,
repositoryEntriesWithVersions$: this.getSingleSoftwareWithVersions$(softwareToUpdate)
});
resultEmitter.pipe(takeUntil(this.destroyed$)).subscribe(softwareToInstall => {
this.emitSoftwareInstall(softwareToInstall);
this.showSoftwareChanges.emit();
});
choiceEmitter
.pipe(this.isSoftwareInstalledOnDevicePipe(updateInstallableList$), takeUntil(this.destroyed$))
.subscribe(({ item }) => updateInstallableList$.next({
object: item,
template: this.alreadyInstalledWarningTemplate,
mapper: object => {
object.installed = true;
return object;
}
}));
}
removeSoftware(softwareToRemove) {
this.emitSoftwareRemoval([softwareToRemove]);
}
getInstallableSoftwareListWithVersions$(searchTerm$) {
const installedSoftwareNames = (this.softwareList || []).map(s => s.name);
return searchTerm$.pipe(distinctUntilChanged(), switchMap(searchTerm => this.repository.listRepositoryEntries(RepositoryType.SOFTWARE, {
query: searchTerm.softwareType
? this.queriesUtil.addAndFilter(this.typesQuery, {
softwareType: searchTerm.softwareType
})
: this.typesQuery,
partialName: searchTerm?.name,
params: { pageSize: 100 }
})), map(({ data }) => data), map(softwareList => {
return softwareList.filter(software => {
return !installedSoftwareNames.includes(software.name);
});
}), map(softwareList => this.attachVersions(softwareList)), shareReplay(1));
}
getSingleSoftwareWithVersions$(software) {
return from(this.repository.listRepositoryEntries(RepositoryType.SOFTWARE, {
query: { name: software.name }
})).pipe(map(({ data }) => data), map(softwareList => this.attachVersions(softwareList)), shareReplay(1));
}
attachVersions(softwareList) {
softwareList.forEach(software => {
software.versions = this.repository.listBaseVersions(software);
});
return softwareList;
}
displaySoftwareSelectModal(initialStateOverrides) {
const initialState = {
repositoryType: RepositoryType.SOFTWARE,
mode: ModalSelectionMode.MULTI,
icon: 'c8y-tools',
disableSelected: false,
selected: this.softwareList,
hideEmptyItems: true,
...initialStateOverrides
};
const modal = this.bsModal.show(RepositorySelectModalComponent, {
ignoreBackdropClick: true,
class: 'modal-sm',
ariaDescribedby: 'modal-body',
ariaLabelledBy: 'modal-title',
initialState
});
if (initialStateOverrides.repositoryEntriesWithVersionsFn$) {
modal.content.repositoryEntriesWithVersions$ =
initialStateOverrides.repositoryEntriesWithVersionsFn$(modal);
}
this.modalSearch = modal.content.search.bind(modal.content);
modal.content.load.next();
return {
resultEmitter: modal.content.resultEmitter,
choiceEmitter: modal.content.onChoiceUpdated,
updateInstallableList$: modal.content.updateInstallableList$
};
}
search(filterCriteria) {
if (this.modalSearch) {
this.modalSearch(filterCriteria);
}
}
emitSoftwareInstall(items) {
this.changes.emit(items.map(item => {
return { ...item, action: 'install' };
}));
}
emitSoftwareRemoval(items) {
this.changes.emit(items.map(item => {
return { ...item, action: 'delete' };
}));
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
}
isSoftwareInstalledOnDevicePipe(updateInstallableList$) {
return pipe(tap((item) => updateInstallableList$.next({ object: item, template: this.loadingTemplate })), map(item => ({
item,
software: ((item.options || []).find(option => option.obj.id === item.selectedId) || {}).obj
})), mergeMap(({ item, software }) => from(this.repository.isSoftwareInstalledOnDevice(this.device.id, software)).pipe(map(installed => ({ item, installed })))), tap(({ item }) => updateInstallableList$.next({ object: item })), filter(({ installed }) => !!installed));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InstalledSoftwareComponent, deps: [{ token: i1.RepositoryService }, { token: i2.BsModalService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: InstalledSoftwareComponent, selector: "c8y-installed-software", inputs: { device: "device", softwareList: "softwareList", deviceSoftwareChanges: "deviceSoftwareChanges", deviceSoftwareChangesInProgress: "deviceSoftwareChangesInProgress", typesQuery: "typesQuery" }, outputs: { changes: "changes", showSoftwareChanges: "showSoftwareChanges" }, viewQueries: [{ propertyName: "alreadyInstalledWarningTemplate", first: true, predicate: ["alreadyInstalledWarning"], descendants: true, static: true }, { propertyName: "loadingTemplate", first: true, predicate: ["loading"], descendants: true, static: true }, { propertyName: "softwareTypeTemplate", first: true, predicate: ["softwareType"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"d-flex d-col flex-grow\">\n <div class=\"card-header large-padding separator sticky-top\">\n <div\n class=\"card-title\"\n translate\n >\n Installed software\n </div>\n </div>\n <div class=\"flex-grow\">\n <fieldset\n class=\"card-block large-padding overflow-visible separator-bottom\"\n *ngIf=\"showFilter\"\n >\n <div class=\"row\">\n <div class=\"col-xs-6\">\n <div class=\"input-group input-group-search\">\n <label\n class=\"sr-only\"\n for=\"filter\"\n >\n {{ 'Filter\u2026' | translate }}\n </label>\n <input\n class=\"form-control\"\n title=\"{{ 'Filter\u2026' | translate }}\"\n id=\"filter\"\n placeholder=\"{{ 'Filter\u2026' | translate }}\"\n type=\"search\"\n [ngModel]=\"textFilter$ | async\"\n (ngModelChange)=\"textFilter$.next($event)\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"(textFilter$ | async).length === 0\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"(textFilter$ | async).length > 0\"\n (click)=\"textFilter$.next('')\"\n ></i>\n </span>\n <span\n class=\"sr-only\"\n for=\"search\"\n translate\n >\n Filter\u2026\n </span>\n </div>\n </div>\n <div class=\"col-xs-6\">\n <c8y-software-type\n [required]=\"false\"\n [emitResultsOnly]=\"true\"\n [showBtnInNotFoundMessage]=\"false\"\n [allowFreeEntries]=\"false\"\n [placeholder]=\"'Filter by software type\u2026' | translate\"\n [showClearSelectionOption]=\"true\"\n [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n (onSelectSoftware)=\"softwareTypeFilter$.next($event?.softwareType)\"\n ></c8y-software-type>\n </div>\n </div>\n </fieldset>\n\n <fieldset\n class=\"flex-grow inner-scroll\"\n id=\"software-list\"\n [disabled]=\"deviceSoftwareChangesInProgress\"\n >\n <!-- NOT EMPTY STATE -->\n <c8y-device-software-list\n class=\"d-block p-l-16 p-r-16\"\n container=\"body\"\n [device]=\"device\"\n [filterCriteria$]=\"filterCriteria$\"\n [softwareList]=\"softwareList\"\n [deviceSoftwareChanges]=\"deviceSoftwareChanges\"\n (update)=\"updateSoftware($event)\"\n (remove)=\"removeSoftware($event)\"\n (onListEmpty)=\"showFilter = !$event\"\n >\n <!-- EMPTY STATE -->\n <div class=\"c8y-empty-state text-center\">\n <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n <p>\n <strong translate>No software installed.</strong>\n <br />\n <small translate>Click below to install software into this device.</small>\n </p>\n </div>\n <!-- NO SEARCH RESULTS STATE -->\n <div class=\"c8y-empty-state c8y-no-results-state text-center\">\n <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n <p>\n <strong translate>No software matches your filter criteria.</strong>\n <br />\n <small translate>Try changing your search criteria.</small>\n </p>\n </div>\n </c8y-device-software-list>\n </fieldset>\n </div>\n <!-- INSTALL SOFTWARE-->\n <div\n class=\"card-footer large-padding separator sticky-bottom d-flex j-c-between bg-level-0\"\n [ngClass]=\"{ 'visible-sm visible-xs': !supportsSoftwareOperations }\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Install software' | translate }}\"\n *ngIf=\"supportsSoftwareOperations\"\n (click)=\"installSoftware()\"\n [disabled]=\"deviceSoftwareChangesInProgress\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.OPEN_INSTALL_SOFTWARE\n }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install software' | translate }}\n </button>\n <button\n class=\"btn btn-clean text-primary visible-sm visible-xs\"\n [title]=\"'Show "Software changes"' | translate\"\n (click)=\"showSoftwareChanges.emit()\"\n >\n <span translate>Show \"Software changes\"</span>\n <i c8yIcon=\"chevron-right\"></i>\n </button>\n </div>\n</div>\n\n<ng-template\n #alreadyInstalledWarning\n let-item\n let-option=\"option\"\n>\n <i\n class=\"text-warning a-s-center\"\n c8yIcon=\"warning\"\n [tooltip]=\"\n alreadyInstalledMessage\n | translate: { name: item.body[0].value, version: option.body[0].value }\n \"\n ></i>\n</ng-template>\n\n<ng-template #loading>\n <div class=\"p-relative d-flex m-l-auto\">\n <i\n class=\"icon-spin\"\n c8yIcon=\"circle-o-notch\"\n ></i>\n </div>\n</ng-template>\n\n<ng-template #softwareType>\n <c8y-software-type\n additionalFilter\n [required]=\"false\"\n [placeholder]=\"'Filter by software type\u2026' | translate\"\n (onSelectSoftware)=\"search({ softwareType: $event?.softwareType })\"\n [emitResultsOnly]=\"true\"\n [showBtnInNotFoundMessage]=\"false\"\n [allowFreeEntries]=\"false\"\n [showClearSelectionOption]=\"true\"\n [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n ></c8y-software-type>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i1.SoftwareTypeComponent, selector: "c8y-software-type", inputs: ["softwareTypeMO", "disabled", "style", "required", "placeholder", "emitResultsOnly", "showBtnInNotFoundMessage", "allowFreeEntries", "showClearSelectionOption", "clearSelectionOptionLabel", "presetSoftwareTypes"], outputs: ["onSelectSoftware"] }, { kind: "directive", type: i6.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "component", type: i7.DeviceSoftwareListComponent, selector: "c8y-device-software-list", inputs: ["softwareList", "device", "deviceSoftwareChanges", "filterCriteria$"], outputs: ["update", "remove", "onListEmpty"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InstalledSoftwareComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-installed-software', template: "<div class=\"d-flex d-col flex-grow\">\n <div class=\"card-header large-padding separator sticky-top\">\n <div\n class=\"card-title\"\n translate\n >\n Installed software\n </div>\n </div>\n <div class=\"flex-grow\">\n <fieldset\n class=\"card-block large-padding overflow-visible separator-bottom\"\n *ngIf=\"showFilter\"\n >\n <div class=\"row\">\n <div class=\"col-xs-6\">\n <div class=\"input-group input-group-search\">\n <label\n class=\"sr-only\"\n for=\"filter\"\n >\n {{ 'Filter\u2026' | translate }}\n </label>\n <input\n class=\"form-control\"\n title=\"{{ 'Filter\u2026' | translate }}\"\n id=\"filter\"\n placeholder=\"{{ 'Filter\u2026' | translate }}\"\n type=\"search\"\n [ngModel]=\"textFilter$ | async\"\n (ngModelChange)=\"textFilter$.next($event)\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"(textFilter$ | async).length === 0\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"(textFilter$ | async).length > 0\"\n (click)=\"textFilter$.next('')\"\n ></i>\n </span>\n <span\n class=\"sr-only\"\n for=\"search\"\n translate\n >\n Filter\u2026\n </span>\n </div>\n </div>\n <div class=\"col-xs-6\">\n <c8y-software-type\n [required]=\"false\"\n [emitResultsOnly]=\"true\"\n [showBtnInNotFoundMessage]=\"false\"\n [allowFreeEntries]=\"false\"\n [placeholder]=\"'Filter by software type\u2026' | translate\"\n [showClearSelectionOption]=\"true\"\n [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n (onSelectSoftware)=\"softwareTypeFilter$.next($event?.softwareType)\"\n ></c8y-software-type>\n </div>\n </div>\n </fieldset>\n\n <fieldset\n class=\"flex-grow inner-scroll\"\n id=\"software-list\"\n [disabled]=\"deviceSoftwareChangesInProgress\"\n >\n <!-- NOT EMPTY STATE -->\n <c8y-device-software-list\n class=\"d-block p-l-16 p-r-16\"\n container=\"body\"\n [device]=\"device\"\n [filterCriteria$]=\"filterCriteria$\"\n [softwareList]=\"softwareList\"\n [deviceSoftwareChanges]=\"deviceSoftwareChanges\"\n (update)=\"updateSoftware($event)\"\n (remove)=\"removeSoftware($event)\"\n (onListEmpty)=\"showFilter = !$event\"\n >\n <!-- EMPTY STATE -->\n <div class=\"c8y-empty-state text-center\">\n <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n <p>\n <strong translate>No software installed.</strong>\n <br />\n <small translate>Click below to install software into this device.</small>\n </p>\n </div>\n <!-- NO SEARCH RESULTS STATE -->\n <div class=\"c8y-empty-state c8y-no-results-state text-center\">\n <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n <p>\n <strong translate>No software matches your filter criteria.</strong>\n <br />\n <small translate>Try changing your search criteria.</small>\n </p>\n </div>\n </c8y-device-software-list>\n </fieldset>\n </div>\n <!-- INSTALL SOFTWARE-->\n <div\n class=\"card-footer large-padding separator sticky-bottom d-flex j-c-between bg-level-0\"\n [ngClass]=\"{ 'visible-sm visible-xs': !supportsSoftwareOperations }\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Install software' | translate }}\"\n *ngIf=\"supportsSoftwareOperations\"\n (click)=\"installSoftware()\"\n [disabled]=\"deviceSoftwareChangesInProgress\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.OPEN_INSTALL_SOFTWARE\n }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install software' | translate }}\n </button>\n <button\n class=\"btn btn-clean text-primary visible-sm visible-xs\"\n [title]=\"'Show "Software changes"' | translate\"\n (click)=\"showSoftwareChanges.emit()\"\n >\n <span translate>Show \"Software changes\"</span>\n <i c8yIcon=\"chevron-right\"></i>\n </button>\n </div>\n</div>\n\n<ng-template\n #alreadyInstalledWarning\n let-item\n let-option=\"option\"\n>\n <i\n class=\"text-warning a-s-center\"\n c8yIcon=\"warning\"\n [tooltip]=\"\n alreadyInstalledMessage\n | translate: { name: item.body[0].value, version: option.body[0].value }\n \"\n ></i>\n</ng-template>\n\n<ng-template #loading>\n <div class=\"p-relative d-flex m-l-auto\">\n <i\n class=\"icon-spin\"\n c8yIcon=\"circle-o-notch\"\n ></i>\n </div>\n</ng-template>\n\n<ng-template #softwareType>\n <c8y-software-type\n additionalFilter\n [required]=\"false\"\n [placeholder]=\"'Filter by software type\u2026' | translate\"\n (onSelectSoftware)=\"search({ softwareType: $event?.softwareType })\"\n [emitResultsOnly]=\"true\"\n [showBtnInNotFoundMessage]=\"false\"\n [allowFreeEntries]=\"false\"\n [showClearSelectionOption]=\"true\"\n [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n ></c8y-software-type>\n</ng-template>\n" }]
}], ctorParameters: () => [{ type: i1.RepositoryService }, { type: i2.BsModalService }], propDecorators: { device: [{
type: Input
}], softwareList: [{
type: Input
}], deviceSoftwareChanges: [{
type: Input
}], deviceSoftwareChangesInProgress: [{
type: Input
}], typesQuery: [{
type: Input
}], changes: [{
type: Output
}], showSoftwareChanges: [{
type: Output
}], alreadyInstalledWarningTemplate: [{
type: ViewChild,
args: ['alreadyInstalledWarning', { static: true }]
}], loadingTemplate: [{
type: ViewChild,
args: ['loading', { static: true }]
}], softwareTypeTemplate: [{
type: ViewChild,
args: ['softwareType', { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbGVkLXNvZnR3YXJlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3JlcG9zaXRvcnkvc29mdHdhcmUvZGV2aWNlLXRhYi9pbnN0YWxsZWQtc29mdHdhcmUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcmVwb3NpdG9yeS9zb2Z0d2FyZS9kZXZpY2UtdGFiL2luc3RhbGxlZC1zb2Z0d2FyZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxFQUNOLFdBQVcsRUFDWCxTQUFTLEVBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFrQixXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDMUQsT0FBTyxFQUdMLGtCQUFrQixFQUNsQixPQUFPLEVBQ1IsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBSUwsb0NBQW9DLEVBQ3BDLDhCQUE4QixFQUM5QixpQkFBaUIsRUFDakIsY0FBYyxFQUNmLE1BQU0sdUNBQXVDLENBQUM7QUFDL0MsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNoQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDckQsT0FBTyxFQUFFLGVBQWUsRUFBYyxPQUFPLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzNGLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsTUFBTSxFQUNOLEdBQUcsRUFDSCxRQUFRLEVBQ1IsV0FBVyxFQUNYLFNBQVMsRUFDVCxTQUFTLEVBQ1QsR0FBRyxFQUNKLE1BQU0sZ0JBQWdCLENBQUM7Ozs7Ozs7OztBQU14QixNQUFNLE9BQU8sMEJBQTBCO0lBaUNyQyxZQUNVLFVBQTZCLEVBQzdCLE9BQXVCO1FBRHZCLGVBQVUs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QUl0QyxvQkFBb0I7c0JBRG5CLFNBQVM7dUJBQUMsY0FBYyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgVGVtcGxhdGVSZWYsXG4gIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElNYW5hZ2VkT2JqZWN0LCBRdWVyaWVzVXRpbCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7XG4gIElTZWxlY3RNb2RhbE9iamVjdCxcbiAgSVVwZGF0ZUl0ZW1FdmVudCxcbiAgTW9kYWxTZWxlY3Rpb25Nb2RlLFxuICBnZXR0ZXh0XG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHtcbiAgRGV2aWNlU29mdHdhcmUsXG4gIERldmljZVNvZnR3YXJlQ2hhbmdlLFxuICBGaWx0ZXJDcml0ZXJpYSxcbiAgUFJPRFVDVF9FWFBFUklFTkNFX1JFUE9TSVRPUllfU0hBUkVELFxuICBSZXBvc2l0b3J5U2VsZWN0TW9kYWxDb21wb25lbnQsXG4gIFJlcG9zaXRvcnlTZXJ2aWNlLFxuICBSZXBvc2l0b3J5VHlwZVxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL3JlcG9zaXRvcnkvc2hhcmVkJztcbmltcG9ydCB7IGdldCB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBCc01vZGFsU2VydmljZSB9IGZyb20gJ25neC1ib290c3RyYXAvbW9kYWwnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBmcm9tLCBvZiwgcGlwZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtcbiAgZGlzdGluY3RVbnRpbENoYW5nZWQsXG4gIGZpbHRlcixcbiAgbWFwLFxuICBtZXJnZU1hcCxcbiAgc2hhcmVSZXBsYXksXG4gIHN3aXRjaE1hcCxcbiAgdGFrZVVudGlsLFxuICB0YXBcbn0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktaW5zdGFsbGVkLXNvZnR3YXJlJyxcbiAgdGVtcGxhdGVVcmw6ICdpbnN0YWxsZWQtc29mdHdhcmUuY29tcG9uZW50Lmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIEluc3RhbGxlZFNvZnR3YXJlQ29tcG9uZW50IGltcGxlbWVudHMgT25EZXN0cm95LCBPbkluaXQge1xuICBQUk9EVUNUX0VYUEVSSUVOQ0UgPSBQUk9EVUNUX0VYUEVSSUVOQ0VfUkVQT1NJVE9SWV9TSEFSRUQ7XG4gIEBJbnB1dCgpIGRldmljZTogSU1hbmFnZWRPYmplY3Q7XG4gIEBJbnB1dCgpIHNvZnR3YXJlTGlzdDogRGV2aWNlU29mdHdhcmVbXTtcbiAgQElucHV0KCkgZGV2aWNlU29mdHdhcmVDaGFuZ2VzOiBEZXZpY2VTb2Z0d2FyZUNoYW5nZVtdO1xuICBASW5wdXQoKSBkZXZpY2VTb2Z0d2FyZUNoYW5nZXNJblByb2dyZXNzOiBib29sZWFuO1xuICBASW5wdXQoKSB0eXBlc1F1ZXJ5OiBvYmplY3Q7XG4gIEBPdXRwdXQoKSBjaGFuZ2VzID0gbmV3IEV2ZW50RW1pdHRlcjxEZXZpY2VTb2Z0d2FyZUNoYW5nZVtdPigpO1xuICBAT3V0cHV0KCkgc2hvd1NvZnR3YXJlQ2hhbmdlcyA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBAVmlld0NoaWxkKCdhbHJlYWR5SW5zdGFsbGVkV2FybmluZycsIHsgc3RhdGljOiB0cnVlIH0pXG4gIGFscmVhZHlJbnN0YWxsZWRXYXJuaW5nVGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XG4gIGFscmVhZHlJbnN0YWxsZWRNZXNzYWdlID0gZ2V0dGV4dChcbiAgICAne3sgbmFtZSB9fSAodi4ge3sgdmVyc2lvbiB9fSkgaXMgYWxyZWFkeSBpbnN0YWxsZWQgb24gdGhpcyBkZXZpY2UnXG4gICk7XG4gIEBWaWV3Q2hpbGQoJ2xvYWRpbmcnLCB7IHN0YXRpYzogdHJ1ZSB9KVxuICBsb2FkaW5nVGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XG5cbiAgQFZpZXdDaGlsZCgnc29mdHdhcmVUeXBlJywgeyBzdGF0aWM6IHRydWUgfSlcbiAgc29mdHdhcmVUeXBlVGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XG5cbiAgc2hvd0ZpbHRlciA9IGZhbHNlO1xuICBzdXBwb3J0c1NvZnR3YXJlT3BlcmF0aW9ucyA9IGZhbHNlO1xuICB0ZXh0RmlsdGVyJDogQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KCcnKTtcbiAgc29mdHdhcmVUeXBlRmlsdGVyJDogQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KCcnKTtcbiAgZmlsdGVyQ3JpdGVyaWEkOiBPYnNlcnZhYmxlPEZpbHRlckNyaXRlcmlhPjtcblxuICBwcml2YXRlIHJlYWRvbmx5IG9wZXJhdGlvblR5cGVzID0gWydjOHlfU29mdHdhcmVVcGRhdGUnLCAnYzh5X1NvZnR3YXJlTGlzdCcsICdjOHlfU29mdHdhcmUnXTtcblxuICBwcml2YXRlIHF1ZXJpZXNVdGlsOiBRdWVyaWVzVXRpbDtcbiAgcHJpdmF0ZSBtb2RhbFNlYXJjaDogKGZpbHRlckNyaXRlcmlhOiBGaWx0ZXJDcml0ZXJpYSkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBkZXN0cm95ZWQkOiBTdWJqZWN0PHZvaWQ+ID0gbmV3IFN1YmplY3QoKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlcG9zaXRvcnk6IFJlcG9zaXRvcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgYnNNb2RhbDogQnNNb2RhbFNlcnZpY2VcbiAgKSB7XG4gICAgdGhpcy5maWx0ZXJDcml0ZXJpYSQgPSBjb21iaW5lTGF0ZXN0KFt0aGlzLnRleHRGaWx0ZXIkLCB0aGlzLnNvZnR3YXJlVHlwZUZpbHRlciRdKS5waXBlKFxuICAgICAgbWFwKChbdGV4dEZpbHRlciwgc29mdHdhcmVUeXBlRmlsdGVyXSkgPT4gKHtcbiAgICAgICAgbmFtZTogdGV4dEZpbHRlcixcbiAgICAgICAgc29mdHdhcmVUeXBlOiBzb2Z0d2FyZVR5cGVGaWx0ZXJcbiAgICAgIH0pKSxcbiAgICAgIG1hcChmaWx0ZXJDcml0ZXJpYSA9PlxuICAgICAgICAhZmlsdGVyQ3JpdGVyaWEubmFtZSAmJiAhZmlsdGVyQ3JpdGVyaWEuc29mdHdhcmVUeXBlID8gbnVsbCA6IGZpbHRlckNyaXRlcmlhXG4gICAgICApXG4gICAgKTtcbiAgICB0aGlzLnF1ZXJpZXNVdGlsID0gbmV3IFF1ZXJpZXNVdGlsKCk7XG4gIH1cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICBjb25zdCBzdXBwb3J0ZWRPcGVyYXRpb25zID0gZ2V0KHRoaXMuZGV2aWNlLCAnYzh5X1N1cHBvcnRlZE9wZXJhdGlvbnMnLCBbXSk7XG4gICAgdGhpcy5zdXBwb3J0c1NvZnR3YXJlT3BlcmF0aW9ucyA9IHRoaXMub3BlcmF0aW9uVHlwZXMuc29tZShcbiAgICAgIG9wZXJhdGlvblR5cGUgPT4gc3VwcG9ydGVkT3BlcmF0aW9ucy5pbmRleE9mKG9wZXJhdGlvblR5cGUpID4gLTFcbiAgICApO1xuICB9XG5cbiAgaW5zdGFsbFNvZnR3YXJlKCkge1xuICAgIGNvbnN0IHsgcmVzdWx0RW1pdHRlciwgY2hvaWNlRW1pdHRlciwgdXBkYXRlSW5zdGFsbGFibGVMaXN0JCB9ID1cbiAgICAgIHRoaXMuZGlzcGxheVNvZnR3YXJlU2VsZWN0TW9kYWwoe1xuICAgICAgICB0aXRsZTogZ2V0dGV4dCgnSW5zdGFsbCBzb2Z0d2FyZScpLFxuICAgICAgICBzdWJUaXRsZTogZ2V0dGV4dCgnQXZhaWxhYmxlIHNvZnR3YXJlcyBtYXRjaGluZyB0aGUgZGV2aWNlIHR5cGUnKSxcbiAgICAgICAgbGFiZWxzOiB7IG9rOiBnZXR0ZXh0KCdJbnN0YWxsJykgfSxcbiAgICAgICAgbm9JdGVtc01lc3NhZ2U6IGdldHRleHQoJ05vIG1hdGNoaW5nIHNvZnR3YXJlIGF2YWlsYWJsZS4nKSxcbiAgICAgICAgc2hvd0FkZGl0aW9uYWxGaWx0ZXI6IHRydWUsXG4gICAgICAgIGFkZGl0aW9uYWxGaWx0ZXJUZW1wbGF0ZTogdGhpcy5zb2Z0d2FyZVR5cGVUZW1wbGF0ZSxcbiAgICAgICAgcmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnMkOiBvZihbXSksXG4gICAgICAgIHJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zRm4kOiBtb2RhbCA9PlxuICAgICAgICAgIHRoaXMuZ2V0SW5zdGFsbGFibGVTb2Z0d2FyZUxpc3RXaXRoVmVyc2lvbnMkKG1vZGFsLmNvbnRlbnQuc2VhcmNoVGVybSlcbiAgICAgIH0pO1xuXG4gICAgcmVzdWx0RW1pdHRlci5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3llZCQpKS5zdWJzY3JpYmUoc29mdHdhcmVUb0luc3RhbGwgPT4ge1xuICAgICAgdGhpcy5lbWl0U29mdHdhcmVJbnN0YWxsKHNvZnR3YXJlVG9JbnN0YWxsKTtcbiAgICAgIHRoaXMuc2hvd1NvZnR3YXJlQ2hhbmdlcy5lbWl0KCk7XG4gICAgfSk7XG5cbiAgICBjaG9pY2VFbWl0dGVyXG4gICAgICAucGlwZShcbiAgICAgICAgdGhpcy5pc1NvZnR3YXJlSW5zdGFsbGVkT25EZXZpY2VQaXBlKHVwZGF0ZUluc3RhbGxhYmxlTGlzdCQpLFxuICAgICAgICB0YWtlVW50aWwodGhpcy5kZXN0cm95ZWQkKVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoeyBpdGVtIH0pID0+XG4gICAgICAgIHVwZGF0ZUluc3RhbGxhYmxlTGlzdCQubmV4dCh7XG4gICAgICAgICAgb2JqZWN0OiBpdGVtLFxuICAgICAgICAgIHRlbXBsYXRlOiB0aGlzLmFscmVhZHlJbnN0YWxsZWRXYXJuaW5nVGVtcGxhdGUsXG4gICAgICAgICAgbWFwcGVyOiBvYmplY3QgPT4ge1xuICAgICAgICAgICAgb2JqZWN0Lmluc3RhbGxlZCA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gb2JqZWN0O1xuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgICk7XG4gIH1cblxuICB1cGRhdGVTb2Z0d2FyZShzb2Z0d2FyZVRvVXBkYXRlKSB7XG4gICAgY29uc3QgeyByZXN1bHRFbWl0dGVyLCBjaG9pY2VFbWl0dGVyLCB1cGRhdGVJbnN0YWxsYWJsZUxpc3QkIH0gPVxuICAgICAgdGhpcy5kaXNwbGF5U29mdHdhcmVTZWxlY3RNb2RhbCh7XG4gICAgICAgIHRpdGxlOiBnZXR0ZXh0KCdVcGRhdGUgc29mdHdhcmUnKSxcbiAgICAgICAgc3ViVGl0bGU6IGdldHRleHQoJ1NlbGVjdCBvbmUgb2YgdGhlIGF2YWlsYWJsZSBzb2Z0d2FyZSB2ZXJzaW9ucycpLFxuICAgICAgICBsYWJlbHM6IHsgb2s6IGdldHRleHQoJ1VwZGF0ZScpIH0sXG4gICAgICAgIG5vSXRlbXNNZXNzYWdlOiBnZXR0ZXh0KCdObyBvdGhlciBzb2Z0d2FyZSB2ZXJzaW9ucyBhdmFpbGFibGUuJyksXG4gICAgICAgIHNob3dGaWx0ZXI6IGZhbHNlLFxuICAgICAgICByZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9ucyQ6IHRoaXMuZ2V0U2luZ2xlU29mdHdhcmVXaXRoVmVyc2lvbnMkKHNvZnR3YXJlVG9VcGRhdGUpXG4gICAgICB9KTtcblxuICAgIHJlc3VsdEVtaXR0ZXIucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95ZWQkKSkuc3Vic2NyaWJlKHNvZnR3YXJlVG9JbnN0YWxsID0+IHtcbiAgICAgIHRoaXMuZW1pdFNvZnR3YXJlSW5zdGFsbChzb2Z0d2FyZVRvSW5zdGFsbCk7XG4gICAgICB0aGlzLnNob3dTb2Z0d2FyZUNoYW5nZXMuZW1pdCgpO1xuICAgIH0pO1xuXG4gICAgY2hvaWNlRW1pdHRlclxuICAgICAgLnBpcGUoXG4gICAgICAgIHRoaXMuaXNTb2Z0d2FyZUluc3RhbGxlZE9uRGV2aWNlUGlwZSh1cGRhdGVJbnN0YWxsYWJsZUxpc3QkKSxcbiAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveWVkJClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKHsgaXRlbSB9KSA9PlxuICAgICAgICB1cGRhdGVJbnN0YWxsYWJsZUxpc3QkLm5leHQoe1xuICAgICAgICAgIG9iamVjdDogaXRlbSxcbiAgICAgICAgICB0ZW1wbGF0ZTogdGhpcy5hbHJlYWR5SW5zdGFsbGVkV2FybmluZ1RlbXBsYXRlLFxuICAgICAgICAgIG1hcHBlcjogb2JqZWN0ID0+IHtcbiAgICAgICAgICAgIG9iamVjdC5pbnN0YWxsZWQgPSB0cnVlO1xuICAgICAgICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICApO1xuICB9XG5cbiAgcmVtb3ZlU29mdHdhcmUoc29mdHdhcmVUb1JlbW92ZSkge1xuICAgIHRoaXMuZW1pdFNvZnR3YXJlUmVtb3ZhbChbc29mdHdhcmVUb1JlbW92ZV0pO1xuICB9XG5cbiAgZ2V0SW5zdGFsbGFibGVTb2Z0d2FyZUxpc3RXaXRoVmVyc2lvbnMkKHNlYXJjaFRlcm0kOiBCZWhhdmlvclN1YmplY3Q8RmlsdGVyQ3JpdGVyaWE+KSB7XG4gICAgY29uc3QgaW5zdGFsbGVkU29mdHdhcmVOYW1lcyA9ICh0aGlzLnNvZnR3YXJlTGlzdCB8fCBbXSkubWFwKHMgPT4gcy5uYW1lKTtcbiAgICByZXR1cm4gc2VhcmNoVGVybSQucGlwZShcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCksXG4gICAgICBzd2l0Y2hNYXAoc2VhcmNoVGVybSA9PlxuICAgICAgICB0aGlzLnJlcG9zaXRvcnkubGlzdFJlcG9zaXRvcnlFbnRyaWVzKFJlcG9zaXRvcnlUeXBlLlNPRlRXQVJFLCB7XG4gICAgICAgICAgcXVlcnk6IHNlYXJjaFRlcm0uc29mdHdhcmVUeXBlXG4gICAgICAgICAgICA/IHRoaXMucXVlcmllc1V0aWwuYWRkQW5kRmlsdGVyKHRoaXMudHlwZXNRdWVyeSwge1xuICAgICAgICAgICAgICAgIHNvZnR3YXJlVHlwZTogc2VhcmNoVGVybS5zb2Z0d2FyZVR5cGVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIDogdGhpcy50eXBlc1F1ZXJ5LFxuICAgICAgICAgIHBhcnRpYWxOYW1lOiBzZWFyY2hUZXJtPy5uYW1lLFxuICAgICAgICAgIHBhcmFtczogeyBwYWdlU2l6ZTogMTAwIH1cbiAgICAgICAgfSlcbiAgICAgICksXG4gICAgICBtYXAoKHsgZGF0YSB9KSA9PiBkYXRhKSxcbiAgICAgIG1hcChzb2Z0d2FyZUxpc3QgPT4ge1xuICAgICAgICByZXR1cm4gc29mdHdhcmVMaXN0LmZpbHRlcihzb2Z0d2FyZSA9PiB7XG4gICAgICAgICAgcmV0dXJuICFpbnN0YWxsZWRTb2Z0d2FyZU5hbWVzLmluY2x1ZGVzKHNvZnR3YXJlLm5hbWUpO1xuICAgICAgICB9KTtcbiAgICAgIH0pLFxuICAgICAgbWFwKHNvZnR3YXJlTGlzdCA9PiB0aGlzLmF0dGFjaFZlcnNpb25zKHNvZnR3YXJlTGlzdCkpLFxuICAgICAgc2hhcmVSZXBsYXkoMSlcbiAgICApO1xuICB9XG5cbiAgZ2V0U2luZ2xlU29mdHdhcmVXaXRoVmVyc2lvbnMkKHNvZnR3YXJlOiBEZXZpY2VTb2Z0d2FyZSkge1xuICAgIHJldHVybiBmcm9tKFxuICAgICAgdGhpcy5yZXBvc2l0b3J5Lmxpc3RSZXBvc2l0b3J5RW50cmllcyhSZXBvc2l0b3J5VHlwZS5TT0ZUV0FSRSwge1xuICAgICAgICBxdWVyeTogeyBuYW1lOiBzb2Z0d2FyZS5uYW1lIH1cbiAgICAgIH0pXG4gICAgKS5waXBlKFxuICAgICAgbWFwKCh7IGRhdGEgfSkgPT4gZGF0YSksXG4gICAgICBtYXAoc29mdHdhcmVMaXN0ID0+IHRoaXMuYXR0YWNoVmVyc2lvbnMoc29mdHdhcmVMaXN0KSksXG4gICAgICBzaGFyZVJlcGxheSgxKVxuICAgICk7XG4gIH1cblxuICBhdHRhY2hWZXJzaW9ucyhzb2Z0d2FyZUxpc3Q6IElNYW5hZ2VkT2JqZWN0W10pIHtcbiAgICBzb2Z0d2FyZUxpc3QuZm9yRWFjaChzb2Z0d2FyZSA9PiB7XG4gICAgICBzb2Z0d2FyZS52ZXJzaW9ucyA9IHRoaXMucmVwb3NpdG9yeS5saXN0QmFzZVZlcnNpb25zKHNvZnR3YXJlKTtcbiAgICB9KTtcbiAgICByZXR1cm4gc29mdHdhcmVMaXN0O1xuICB9XG5cbiAgZGlzcGxheVNvZnR3YXJlU2VsZWN0TW9kYWwoaW5pdGlhbFN0YXRlT3ZlcnJpZGVzKSB7XG4gICAgY29uc3QgaW5pdGlhbFN0YXRlID0ge1xuICAgICAgcmVwb3NpdG9yeVR5cGU6IFJlcG9zaXRvcnlUeXBlLlNPRlRXQVJFLFxuICAgICAgbW9kZTogTW9kYWxTZWxlY3Rpb25Nb2RlLk1VTFRJLFxuICAgICAgaWNvbjogJ2M4eS10b29scycsXG4gICAgICBkaXNhYmxlU2VsZWN0ZWQ6IGZhbHNlLFxuICAgICAgc2VsZWN0ZWQ6IHRoaXMuc29mdHdhcmVMaXN0LFxuICAgICAgaGlkZUVtcHR5SXRlbXM6IHRydWUsXG4gICAgICAuLi5pbml0aWFsU3RhdGVPdmVycmlkZXNcbiAgICB9O1xuICAgIGNvbnN0IG1vZGFsID0gdGhpcy5ic01vZGFsLnNob3coUmVwb3NpdG9yeVNlbGVjdE1vZGFsQ29tcG9uZW50LCB7XG4gICAgICBpZ25vcmVCYWNrZHJvcENsaWNrOiB0cnVlLFxuICAgICAgY2xhc3M6ICdtb2RhbC1zbScsXG4gICAgICBhcmlhRGVzY3JpYmVkYnk6ICdtb2RhbC1ib2R5JyxcbiAgICAgIGFyaWFMYWJlbGxlZEJ5OiAnbW9kYWwtdGl0bGUnLFxuICAgICAgaW5pdGlhbFN0YXRlXG4gICAgfSk7XG5cbiAgICBpZiAoaW5pdGlhbFN0YXRlT3ZlcnJpZGVzLnJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zRm4kKSB7XG4gICAgICBtb2RhbC5jb250ZW50LnJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zJCA9XG4gICAgICAgIGluaXRpYWxTdGF0ZU92ZXJyaWRlcy5yZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9uc0ZuJChtb2RhbCk7XG4gICAgfVxuXG4gICAgdGhpcy5tb2RhbFNlYXJjaCA9IG1vZGFsLmNvbnRlbnQuc2VhcmNoLmJpbmQobW9kYWwuY29udGVudCk7XG5cbiAgICBtb2RhbC5jb250ZW50LmxvYWQubmV4dCgpO1xuICAgIHJldHVybiB7XG4gICAgICByZXN1bHRFbWl0dGVyOiBtb2RhbC5jb250ZW50LnJlc3VsdEVtaXR0ZXIsXG4gICAgICBjaG9pY2VFbWl0dGVyOiBtb2RhbC5jb250ZW50Lm9uQ2hvaWNlVXBkYXRlZCxcbiAgICAgIHVwZGF0ZUluc3RhbGxhYmxlTGlzdCQ6IG1vZGFsLmNvbnRlbnQudXBkYXRlSW5zdGFsbGFibGVMaXN0JFxuICAgIH07XG4gIH1cblxuICBzZWFyY2goZmlsdGVyQ3JpdGVyaWE6IEZpbHRlckNyaXRlcmlhKSB7XG4gICAgaWYgKHRoaXMubW9kYWxTZWFyY2gpIHtcbiAgICAgIHRoaXMubW9kYWxTZWFyY2goZmlsdGVyQ3JpdGVyaWEpO1xuICAgIH1cbiAgfVxuXG4gIGVtaXRTb2Z0d2FyZUluc3RhbGwoaXRlbXM6IERldmljZVNvZnR3YXJlW10pIHtcbiAgICB0aGlzLmNoYW5nZXMuZW1pdChcbiAgICAgIGl0ZW1zLm1hcChpdGVtID0+IHtcbiAgICAgICAgcmV0dXJuIHsgLi4uaXRlbSwgYWN0aW9uOiAnaW5zdGFsbCcgfTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIGVtaXRTb2Z0d2FyZVJlbW92YWwoaXRlbXM6IERldmljZVNvZnR3YXJlW10pIHtcbiAgICB0aGlzLmNoYW5nZXMuZW1pdChcbiAgICAgIGl0ZW1zLm1hcChpdGVtID0+IHtcbiAgICAgICAgcmV0dXJuIHsgLi4uaXRlbSwgYWN0aW9uOiAnZGVsZXRlJyB9O1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5kZXN0cm95ZWQkLm5leHQoKTtcbiAgICB0aGlzLmRlc3Ryb3llZCQuY29tcGxldGUoKTtcbiAgfVxuXG4gIHByaXZhdGUgaXNTb2Z0d2FyZUluc3RhbGxlZE9uRGV2aWNlUGlwZSh1cGRhdGVJbnN0YWxsYWJsZUxpc3QkOiBTdWJqZWN0PElVcGRhdGVJdGVtRXZlbnQ8YW55Pj4pIHtcbiAgICByZXR1cm4gcGlwZShcbiAgICAgIHRhcCgoaXRlbTogSVNlbGVjdE1vZGFsT2JqZWN0KSA9PlxuICAgICAgICB1cGRhdGVJbnN0YWxsYWJsZUxpc3QkLm5leHQoeyBvYmplY3Q6IGl0ZW0sIHRlbXBsYXRlOiB0aGlzLmxvYWRpbmdUZW1wbGF0ZSB9KVxuICAgICAgKSxcbiAgICAgIG1hcChpdGVtID0+ICh7XG4gICAgICAgIGl0ZW0sXG4gICAgICAgIHNvZnR3YXJlOiAoXG4gICAgICAgICAgKGl0ZW0ub3B0aW9ucyB8fCBbXSkuZmluZChvcHRpb24gPT4gb3B0aW9uLm9iai5pZCA9PT0gKGl0ZW0gYXMgYW55KS5zZWxlY3RlZElkKSB8fCB7fVxuICAgICAgICApLm9ialxuICAgICAgfSkpLFxuICAgICAgbWVyZ2VNYXAoKHsgaXRlbSwgc29mdHdhcmUgfSkgPT5cbiAgICAgICAgZnJvbShcbiAgICAgICAgICB0aGlzLnJlcG9zaXRvcnkuaXNTb2Z0d2FyZUluc3RhbGxlZE9uRGV2aWNlKHRoaXMuZGV2aWNlLmlkLCBzb2Z0d2FyZSBhcyBEZXZpY2VTb2Z0d2FyZSlcbiAgICAgICAgKS5waXBlKG1hcChpbnN0YWxsZWQgPT4gKHsgaXRlbSwgaW5zdGFsbGVkIH0pKSlcbiAgICAgICksXG4gICAgICB0YXAoKHsgaXRlbSB9KSA9PiB1cGRhdGVJbnN0YWxsYWJsZUxpc3QkLm5leHQoeyBvYmplY3Q6IGl0ZW0gfSkpLFxuICAgICAgZmlsdGVyKCh7IGluc3RhbGxlZCB9KSA9PiAhIWluc3RhbGxlZClcbiAgICApO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiZC1mbGV4IGQtY29sIGZsZXgtZ3Jvd1wiPlxuICA8ZGl2IGNsYXNzPVwiY2FyZC1oZWFkZXIgbGFyZ2UtcGFkZGluZyBzZXBhcmF0b3Igc3RpY2t5LXRvcFwiPlxuICAgIDxkaXZcbiAgICAgIGNsYXNzPVwiY2FyZC10aXRsZVwiXG4gICAgICB0cmFuc2xhdGVcbiAgICA+XG4gICAgICBJbnN0YWxsZWQgc29mdHdhcmVcbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJmbGV4LWdyb3dcIj5cbiAgICA8ZmllbGRzZXRcbiAgICAgIGNsYXNzPVwiY2FyZC1ibG9jayBsYXJnZS1wYWRkaW5nIG92ZXJmbG93LXZpc2libGUgc2VwYXJhdG9yLWJvdHRvbVwiXG4gICAgICAqbmdJZj1cInNob3dGaWx0ZXJcIlxuICAgID5cbiAgICAgIDxkaXYgY2xhc3M9XCJyb3dcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImNvbC14cy02XCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImlucHV0LWdyb3VwIGlucHV0LWdyb3VwLXNlYXJjaFwiPlxuICAgICAgICAgICAgPGxhYmVsXG4gICAgICAgICAgICAgIGNsYXNzPVwic3Itb25seVwiXG4gICAgICAgICAgICAgIGZvcj1cImZpbHRlclwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7ICdGaWx0ZXLigKYnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgICAgICAgICAgdGl0bGU9XCJ7eyAnRmlsdGVy4oCmJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgIGlkPVwiZmlsdGVyXCJcbiAgICAgICAgI