@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
160 lines • 51.3 kB
JavaScript
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { ActionType } from './export-schedules.interface';
import { ReportsService } from './reports.service';
import { BsModalService } from 'ngx-bootstrap/modal';
import { ScheduleModalComponent } from './schedule-modal.component';
import { gettext, OptionsService, Permissions } from '@c8y/ngx-components';
import { cloneDeep } from 'lodash-es';
import { CronService } from './cron.service';
import { TranslateService } from '@ngx-translate/core';
import { UserService } from '@c8y/client';
import { isEmpty } from 'lodash-es';
import * as i0 from "@angular/core";
import * as i1 from "./reports.service";
import * as i2 from "ngx-bootstrap/modal";
import * as i3 from "./cron.service";
import * as i4 from "@ngx-translate/core";
import * as i5 from "@c8y/client";
import * as i6 from "@c8y/ngx-components";
import * as i7 from "@angular/common";
import * as i8 from "ngx-bootstrap/dropdown";
export class ExportSchedulesComponent {
set exportId(exportId) {
this._exportId = exportId;
}
constructor(reportsService, bsModalService, cronService, translateService, userService, optionsService) {
this.reportsService = reportsService;
this.bsModalService = bsModalService;
this.cronService = cronService;
this.translateService = translateService;
this.userService = userService;
this.optionsService = optionsService;
this.onSchedulesUpdate = new EventEmitter();
this.scheduleList = [];
this.initialSchedule = {
timestamp: null,
emailConfig: {
to: [],
cc: [],
bcc: [],
replyTo: '',
text: '',
subject: ''
},
cronConfig: {
minute: '0',
hour: '0',
day: '1',
month: '1',
weekday: '?'
}
};
this.listClass = 'interact-list';
this.sortReverse = false;
this.isOpen = {};
this.isEditMenuOpen = false;
this.currentUserEmail = '';
this.hasRequiredRole = false;
this.defaultExportEmailTemplate = this.translateService.instant(gettext('File with exported data can be downloaded from {tenant-domain}/apps/cockpit/index.html#?download={binaryId}.'));
this.loadingStatus = {
inProgress: false,
done: false,
error: false
};
}
async ngOnInit() {
this.hasRequiredRole = await this.checkRole();
this.getScheduleList(true);
const currentUserEmail = await this.getCurrentUserEmail();
this.initialSchedule.emailConfig.text = await this.optionsService.getTenantOption('configuration', 'export.data.mail.text');
if (isEmpty(this.initialSchedule.emailConfig.text)) {
this.initialSchedule.emailConfig.text = await this.optionsService.getInheritedTenantOption('configuration', 'export.data.mail.text', this.defaultExportEmailTemplate);
}
this.initialSchedule.emailConfig.to = currentUserEmail;
this.exp = await this.reportsService.getExport(this._exportId);
this.initialSchedule.emailConfig.subject = this.translateService.instant(gettext('Export of "{{expName}}"'), { expName: this.exp.name });
}
ngOnChanges() {
this.translateButtonTitles();
}
translateButtonTitles() {
this.buttonLabels = {
edit: this.translateService.instant(gettext('Edit schedule')),
editNoPermission: this.translateService.instant(gettext('Edit schedule - no permissions')),
duplicate: this.translateService.instant(gettext('Duplicate schedule')),
duplicateNoPermission: this.translateService.instant(gettext('Duplicate schedule - no permissions')),
delete: this.translateService.instant(gettext('Delete schedule')),
deleteNoPermission: this.translateService.instant(gettext('Delete schedule - no permissions'))
};
}
async getCurrentUserEmail() {
const { data } = await this.userService.current();
return data && data.email ? [data.email] : [];
}
async checkRole() {
const { data } = await this.userService.current();
const role = Permissions.ROLE_SCHEDULE_REPORT_ADMIN;
const hasRole = this.userService.hasRole(data, role);
return hasRole;
}
async getScheduleList(withProgress) {
if (withProgress) {
this.loadingStatus.inProgress = true;
}
this.scheduleList = await this.reportsService.getScheduleList(this._exportId);
if (withProgress) {
this.loadingStatus.inProgress = false;
}
}
addSchedule() {
this.openAddEditModal(this._exportId, this.initialSchedule, ActionType.CREATE);
}
editSchedule(schedule, index, event) {
if (this.hasRequiredRole) {
event.preventDefault();
this.openAddEditModal(this._exportId, schedule, ActionType.EDIT, index);
}
}
duplicateSchedule(schedule, event) {
event.preventDefault();
this.openAddEditModal(this._exportId, schedule, ActionType.DUPLICATE);
}
openAddEditModal(exportId, schedule, actionType, index) {
const payload = { actionType, exportId, schedule: cloneDeep(schedule) };
const modalOptions = {
class: 'modal-sm',
ariaDescribedby: 'modal-body',
ariaLabelledBy: 'modal-title',
initialState: payload
};
this.modalRef = this.bsModalService.show(ScheduleModalComponent, modalOptions);
this.modalRef.content.emitter.subscribe((load) => this.getMessageFromModal(load, index));
}
getMessageFromModal(payload, index) {
if (payload.success) {
if (index !== undefined) {
this.scheduleList[index] = payload.schedule;
}
else {
this.scheduleList.push(payload.schedule);
}
this.onSchedulesUpdate.emit(this.scheduleList);
}
}
removeSchedule(schedule, index, event) {
event.preventDefault();
this.scheduleList.splice(index, 1);
this.onSchedulesUpdate.emit(this.scheduleList);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ExportSchedulesComponent, deps: [{ token: i1.ReportsService }, { token: i2.BsModalService }, { token: i3.CronService }, { token: i4.TranslateService }, { token: i5.UserService }, { token: i6.OptionsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ExportSchedulesComponent, selector: "export-schedules", inputs: { exportId: "exportId" }, outputs: { onSchedulesUpdate: "onSchedulesUpdate" }, usesOnChanges: true, ngImport: i0, template: "<div>\n <div *ngIf=\"loadingStatus.inProgress\" class=\"d-flex a-i-center\">\n <c8y-loading></c8y-loading>\n </div>\n\n <div *ngIf=\"!loadingStatus.inProgress && loadingStatus.done && loadingStatus.error\">\n <div class=\"alert alert-warning max-width-100\" translate>Could not load schedules list.</div>\n </div>\n\n <div *ngIf=\"!loadingStatus.inProgress && !loadingStatus.done && !loadingStatus.error\">\n <c8y-ui-empty-state\n *ngIf=\"!scheduleList.length\"\n [icon]=\"'c8y-report'\"\n [title]=\"'No export schedules defined.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div class=\"c8y-list__group\" *ngIf=\"scheduleList.length\">\n <div class=\"c8y-list__item hidden-xs\">\n <div class=\"c8y-list__item__block\">\n <div class=\"c8y-list__item__icon\">\n <i class=\"p-l-24\"></i>\n </div>\n <div class=\"c8y-list__item__body\">\n <div class=\"d-flex\">\n <div class=\"col-sm-6\">\n <label class=\"m-0\">\n {{ 'Description' | translate }}\n </label>\n </div>\n <div class=\"col-sm-6 m-r-40\">\n <label class=\"m-0\">\n {{ 'Frequency' | translate }}\n </label>\n </div>\n </div>\n </div>\n <span></span>\n </div>\n </div>\n\n <div\n class=\"c8y-list__item pointer\"\n *ngFor=\"let schedule of scheduleList; index as i\"\n (click)=\"editSchedule(schedule, i, $event)\"\n >\n <div class=\"c8y-list__item__block\">\n <div class=\"c8y-list__item__icon\">\n <i c8yIcon=\"c8y-report\" class=\"c8y-icon-duocolor\"></i>\n </div>\n <div class=\"c8y-list__item__body d-flex\">\n <div class=\"col-sm-6 col-xs-6\">\n <div class=\"text-truncate\" title=\"{{ schedule.emailConfig.subject }}\">\n {{ schedule.emailConfig.subject }}\n </div>\n </div>\n <div class=\"col-sm-6 col-xs-6\">\n <div class=\"d-flex a-i-baseline\">\n <i c8yIcon=\"calendar\" class=\"text-muted m-r-4\"></i>\n <span class=\"smart-rule-information\">\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 2\"\n ngNonBindable\n translate\n [translateParams]=\"{ minutes: schedule.cronConfig.minute | number: '2.0-0' }\"\n >\n Hourly: {{ minutes }} minute(s) past the hour.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 3\"\n ngNonBindable\n translate\n [translateParams]=\"{\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Daily: at {{ hour }}:{{ minutes }}.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 4\"\n ngNonBindable\n translate\n [translateParams]=\"{\n weekDay: cronService.getWeekDayName(schedule.cronConfig),\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Weekly: {{ weekDay }}, at {{ hour }}:{{ minutes }}.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 5\"\n ngNonBindable\n translate\n [translateParams]=\"{\n monthDay: cronService.getMonthDayName(schedule.cronConfig),\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Monthly: {{ monthDay }} day of the month, at {{ hour }}:{{ minutes }}.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 6\"\n ngNonBindable\n translate\n [translateParams]=\"{\n month: cronService.getMonthName(schedule.cronConfig),\n monthDay: cronService.getMonthDayName(schedule.cronConfig),\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Yearly: {{ month }}, {{ monthDay }} day of the month, at {{ hour }}:{{\n minutes\n }}.\n </span>\n </span>\n </div>\n </div>\n </div>\n <div class=\"c8y-list__item__actions\" (click)=\"$event.stopPropagation()\">\n <div class=\"settings dropdown\" dropdown>\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Actions' | translate }}\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'ellipsis-v'\"></i>\n </button>\n <ul role=\"list\" class=\"dropdown-menu dropdown-menu-right\" *dropdownMenu>\n <li role=\"menuitem\">\n <button\n type=\"button\"\n [title]=\"hasRequiredRole ? buttonLabels.edit : buttonLabels.editNoPermission\"\n (click)=\"editSchedule(schedule, i, $event)\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'pencil'\"></i>\n {{ 'Edit' | translate }}\n </button>\n </li>\n <li role=\"menuitem\">\n <button\n type=\"button\"\n [title]=\"\n hasRequiredRole ? buttonLabels.duplicate : buttonLabels.duplicateNoPermission\n \"\n (click)=\"duplicateSchedule(schedule, $event)\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'copy'\"></i>\n {{ 'Duplicate' | translate }}\n </button>\n </li>\n <li role=\"menuitem\">\n <button\n type=\"button\"\n [title]=\"\n hasRequiredRole ? buttonLabels.delete : buttonLabels.deleteNoPermission\n \"\n (click)=\"removeSchedule(schedule, i, $event)\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'delete'\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"alert alert-warning max-width-100\" *ngIf=\"!hasRequiredRole\" role=\"alert\" translate>\n You don't have the permission required to schedule exports.\n </div>\n <button\n class=\"btn btn-default m-t-16\"\n type=\"button\"\n title=\"{{ 'Add schedule' | translate }}\"\n (click)=\"addSchedule()\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add schedule' | translate }}\n </button>\n</div>\n", dependencies: [{ kind: "component", type: i6.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i6.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i6.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i6.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: i8.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i8.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i8.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "pipe", type: i6.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i7.DecimalPipe, name: "number" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ExportSchedulesComponent, decorators: [{
type: Component,
args: [{ selector: 'export-schedules', template: "<div>\n <div *ngIf=\"loadingStatus.inProgress\" class=\"d-flex a-i-center\">\n <c8y-loading></c8y-loading>\n </div>\n\n <div *ngIf=\"!loadingStatus.inProgress && loadingStatus.done && loadingStatus.error\">\n <div class=\"alert alert-warning max-width-100\" translate>Could not load schedules list.</div>\n </div>\n\n <div *ngIf=\"!loadingStatus.inProgress && !loadingStatus.done && !loadingStatus.error\">\n <c8y-ui-empty-state\n *ngIf=\"!scheduleList.length\"\n [icon]=\"'c8y-report'\"\n [title]=\"'No export schedules defined.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div class=\"c8y-list__group\" *ngIf=\"scheduleList.length\">\n <div class=\"c8y-list__item hidden-xs\">\n <div class=\"c8y-list__item__block\">\n <div class=\"c8y-list__item__icon\">\n <i class=\"p-l-24\"></i>\n </div>\n <div class=\"c8y-list__item__body\">\n <div class=\"d-flex\">\n <div class=\"col-sm-6\">\n <label class=\"m-0\">\n {{ 'Description' | translate }}\n </label>\n </div>\n <div class=\"col-sm-6 m-r-40\">\n <label class=\"m-0\">\n {{ 'Frequency' | translate }}\n </label>\n </div>\n </div>\n </div>\n <span></span>\n </div>\n </div>\n\n <div\n class=\"c8y-list__item pointer\"\n *ngFor=\"let schedule of scheduleList; index as i\"\n (click)=\"editSchedule(schedule, i, $event)\"\n >\n <div class=\"c8y-list__item__block\">\n <div class=\"c8y-list__item__icon\">\n <i c8yIcon=\"c8y-report\" class=\"c8y-icon-duocolor\"></i>\n </div>\n <div class=\"c8y-list__item__body d-flex\">\n <div class=\"col-sm-6 col-xs-6\">\n <div class=\"text-truncate\" title=\"{{ schedule.emailConfig.subject }}\">\n {{ schedule.emailConfig.subject }}\n </div>\n </div>\n <div class=\"col-sm-6 col-xs-6\">\n <div class=\"d-flex a-i-baseline\">\n <i c8yIcon=\"calendar\" class=\"text-muted m-r-4\"></i>\n <span class=\"smart-rule-information\">\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 2\"\n ngNonBindable\n translate\n [translateParams]=\"{ minutes: schedule.cronConfig.minute | number: '2.0-0' }\"\n >\n Hourly: {{ minutes }} minute(s) past the hour.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 3\"\n ngNonBindable\n translate\n [translateParams]=\"{\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Daily: at {{ hour }}:{{ minutes }}.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 4\"\n ngNonBindable\n translate\n [translateParams]=\"{\n weekDay: cronService.getWeekDayName(schedule.cronConfig),\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Weekly: {{ weekDay }}, at {{ hour }}:{{ minutes }}.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 5\"\n ngNonBindable\n translate\n [translateParams]=\"{\n monthDay: cronService.getMonthDayName(schedule.cronConfig),\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Monthly: {{ monthDay }} day of the month, at {{ hour }}:{{ minutes }}.\n </span>\n <span\n *ngIf=\"cronService.getBase(schedule.cronConfig) === 6\"\n ngNonBindable\n translate\n [translateParams]=\"{\n month: cronService.getMonthName(schedule.cronConfig),\n monthDay: cronService.getMonthDayName(schedule.cronConfig),\n hour: schedule.cronConfig.hour | number: '2.0-0',\n minutes: schedule.cronConfig.minute | number: '2.0-0'\n }\"\n >\n Yearly: {{ month }}, {{ monthDay }} day of the month, at {{ hour }}:{{\n minutes\n }}.\n </span>\n </span>\n </div>\n </div>\n </div>\n <div class=\"c8y-list__item__actions\" (click)=\"$event.stopPropagation()\">\n <div class=\"settings dropdown\" dropdown>\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Actions' | translate }}\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'ellipsis-v'\"></i>\n </button>\n <ul role=\"list\" class=\"dropdown-menu dropdown-menu-right\" *dropdownMenu>\n <li role=\"menuitem\">\n <button\n type=\"button\"\n [title]=\"hasRequiredRole ? buttonLabels.edit : buttonLabels.editNoPermission\"\n (click)=\"editSchedule(schedule, i, $event)\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'pencil'\"></i>\n {{ 'Edit' | translate }}\n </button>\n </li>\n <li role=\"menuitem\">\n <button\n type=\"button\"\n [title]=\"\n hasRequiredRole ? buttonLabels.duplicate : buttonLabels.duplicateNoPermission\n \"\n (click)=\"duplicateSchedule(schedule, $event)\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'copy'\"></i>\n {{ 'Duplicate' | translate }}\n </button>\n </li>\n <li role=\"menuitem\">\n <button\n type=\"button\"\n [title]=\"\n hasRequiredRole ? buttonLabels.delete : buttonLabels.deleteNoPermission\n \"\n (click)=\"removeSchedule(schedule, i, $event)\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'delete'\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"alert alert-warning max-width-100\" *ngIf=\"!hasRequiredRole\" role=\"alert\" translate>\n You don't have the permission required to schedule exports.\n </div>\n <button\n class=\"btn btn-default m-t-16\"\n type=\"button\"\n title=\"{{ 'Add schedule' | translate }}\"\n (click)=\"addSchedule()\"\n [disabled]=\"!hasRequiredRole\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add schedule' | translate }}\n </button>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.ReportsService }, { type: i2.BsModalService }, { type: i3.CronService }, { type: i4.TranslateService }, { type: i5.UserService }, { type: i6.OptionsService }], propDecorators: { exportId: [{
type: Input
}], onSchedulesUpdate: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0LXNjaGVkdWxlcy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9yZXBvcnRzL2V4cG9ydC1zY2hlZHVsZXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vcmVwb3J0cy9leHBvcnQtc2NoZWR1bGVzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBcUIsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFGLE9BQU8sRUFBb0MsVUFBVSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDNUYsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxjQUFjLEVBQTRCLE1BQU0scUJBQXFCLENBQUM7QUFDL0UsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDcEUsT0FBTyxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDM0UsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN0QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFN0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMxQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFDOzs7Ozs7Ozs7O0FBS3BDLE1BQU0sT0FBTyx3QkFBd0I7SUFDbkMsSUFBYSxRQUFRLENBQUMsUUFBcUI7UUFDekMsSUFBSSxDQUFDLFNBQVMsR0FBRyxRQUFRLENBQUM7SUFDNUIsQ0FBQztJQTBDRCxZQUNVLGNBQThCLEVBQzlCLGNBQThCLEVBQy9CLFdBQXdCLEVBQ3ZCLGdCQUFrQyxFQUNsQyxXQUF3QixFQUN4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QUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDakQsQ0FBQzsrR0EzS1Usd0JBQXdCO21HQUF4Qix3QkFBd0Isb0tDaEJyQyxtd1BBK0xBOzs0RkQvS2Esd0JBQXdCO2tCQUpwQyxTQUFTOytCQUNFLGtCQUFrQjtnT0FJZixRQUFRO3NCQUFwQixLQUFLO2dCQUlJLGlCQUFpQjtzQkFBMUIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT25DaGFuZ2VzLCBPbkluaXQsIE91dHB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRXhwb3J0LCBTY2hlZHVsZSwgRW1pdHRlclBheWxvYWQsIEFjdGlvblR5cGUgfSBmcm9tICcuL2V4cG9ydC1zY2hlZHVsZXMuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydHNTZXJ2aWNlIH0gZnJvbSAnLi9yZXBvcnRzLnNlcnZpY2UnO1xuaW1wb3J0IHsgQnNNb2RhbFNlcnZpY2UsIEJzTW9kYWxSZWYsIE1vZGFsT3B0aW9ucyB9IGZyb20gJ25neC1ib290c3RyYXAvbW9kYWwnO1xuaW1wb3J0IHsgU2NoZWR1bGVNb2RhbENvbXBvbmVudCB9IGZyb20gJy4vc2NoZWR1bGUtbW9kYWwuY29tcG9uZW50JztcbmltcG9ydCB7IGdldHRleHQsIE9wdGlvbnNTZXJ2aWNlLCBQZXJtaXNzaW9ucyB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgY2xvbmVEZWVwIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IENyb25TZXJ2aWNlIH0gZnJvbSAnLi9jcm9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgSWRSZWZlcmVuY2UgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBVc2VyU2VydmljZSB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IGlzRW1wdHkgfSBmcm9tICdsb2Rhc2gtZXMnO1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZXhwb3J0LXNjaGVkdWxlcycsXG4gIHRlbXBsYXRlVXJsOiAnLi9leHBvcnQtc2NoZWR1bGVzLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBFeHBvcnRTY2hlZHVsZXNDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XG4gIEBJbnB1dCgpIHNldCBleHBvcnRJZChleHBvcnRJZDogSWRSZWZlcmVuY2UpIHtcbiAgICB0aGlzLl9leHBvcnRJZCA9IGV4cG9ydElkO1xuICB9XG5cbiAgQE91dHB1dCgpIG9uU2NoZWR1bGVzVXBkYXRlID0gbmV3IEV2ZW50RW1pdHRlcjxTY2hlZHVsZVtdPigpO1xuXG4gIGV4cDogRXhwb3J0O1xuICBzY2hlZHVsZUxpc3Q6IFNjaGVkdWxlW10gPSBbXTtcbiAgaW5pdGlhbFNjaGVkdWxlOiBTY2hlZHVsZSA9IHtcbiAgICB0aW1lc3RhbXA6IG51bGwsXG4gICAgZW1haWxDb25maWc6IHtcbiAgICAgIHRvOiBbXSxcbiAgICAgIGNjOiBbXSxcbiAgICAgIGJjYzogW10sXG4gICAgICByZXBseVRvOiAnJyxcbiAgICAgIHRleHQ6ICcnLFxuICAgICAgc3ViamVjdDogJydcbiAgICB9LFxuICAgIGNyb25Db25maWc6IHtcbiAgICAgIG1pbnV0ZTogJzAnLFxuICAgICAgaG91cjogJzAnLFxuICAgICAgZGF5OiAnMScsXG4gICAgICBtb250aDogJzEnLFxuICAgICAgd2Vla2RheTogJz8nXG4gICAgfVxuICB9O1xuICBidXR0b25MYWJlbHM6IGFueTtcbiAgbGlzdENsYXNzID0gJ2ludGVyYWN0LWxpc3QnO1xuICBsb2FkaW5nU3RhdHVzOiBhbnk7XG4gIHNvcnRUeXBlOiBzdHJpbmc7XG4gIHNvcnRSZXZlcnNlID0gZmFsc2U7XG4gIGlzT3BlbjogYW55ID0ge307XG4gIGlzRmxpcHBlZDogYm9vbGVhbjtcbiAgaXNFZGl0TWVudU9wZW4gPSBmYWxzZTtcbiAgbW9kYWxSZWY6IEJzTW9kYWxSZWY7XG4gIGN1cnJlbnRVc2VyRW1haWwgPSAnJztcbiAgaGFzUmVxdWlyZWRSb2xlID0gZmFsc2U7XG4gIHByaXZhdGUgX2V4cG9ydElkOiBJZFJlZmVyZW5jZTtcbiAgcHJpdmF0ZSBkZWZhdWx0RXhwb3J0RW1haWxUZW1wbGF0ZSA9IHRoaXMudHJhbnNsYXRlU2VydmljZS5pbnN0YW50KFxuICAgIGdldHRleHQoXG4gICAgICAnRmlsZSB3aXRoIGV4cG9ydGVkIGRhdGEgY2FuIGJlIGRvd25sb2FkZWQgZnJvbSB7dGVuYW50LWRvbWFpbn0vYXBwcy9jb2NrcGl0L2luZGV4Lmh0bWwjP2Rvd25sb2FkPXtiaW5hcnlJZH0uJ1xuICAgIClcbiAgKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlcG9ydHNTZXJ2aWNlOiBSZXBvcnRzU2VydmljZSxcbiAgICBwcml2YXRlIGJzTW9kYWxTZXJ2aWNlOiBCc01vZGFsU2VydmljZSxcbiAgICBwdWJsaWMgY3JvblNlcnZpY2U6IENyb25TZXJ2aWNlLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICBwcml2YXRlIHVzZXJTZXJ2aWNlOiBVc2VyU2VydmljZSxcbiAgICBwcml2YXRlIG9wdGlvbnNTZXJ2aWNlOiBPcHRpb25zU2VydmljZVxuICApIHtcbiAgICB0aGlzLmxvYWRpbmdTdGF0dXMgPSB7XG4gICAgICBpblByb2dyZXNzOiBmYWxzZSxcbiAgICAgIGRvbmU6IGZhbHNlLFxuICAgICAgZXJyb3I6IGZhbHNlXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIHRoaXMuaGFzUmVxdWlyZWRSb2xlID0gYXdhaXQgdGhpcy5jaGVja1JvbGUoKTtcbiAgICB0aGlzLmdldFNjaGVkdWxlTGlzdCh0cnVlKTtcbiAgICBjb25zdCBjdXJyZW50VXNlckVtYWlsID0gYXdhaXQgdGhpcy5nZXRDdXJyZW50VXNlckVtYWlsKCk7XG4gICAgdGhpcy5pbml0aWFsU2NoZWR1bGUuZW1haWxDb25maWcudGV4dCA9IGF3YWl0IHRoaXMub3B0aW9uc1NlcnZpY2UuZ2V0VGVuYW50T3B0aW9uKFxuICAgICAgJ2NvbmZpZ3VyYXRpb24nLFxuICAgICAgJ2V4cG9ydC5kYXRhLm1haWwudGV4dCdcbiAgICApO1xuICAgIGlmIChpc0VtcHR5KHRoaXMuaW5pdGlhbFNjaGVkdWxlLmVtYWlsQ29uZmlnLnRleHQpKSB7XG4gICAgICB0aGlzLmluaXRpYWxTY2hlZHVsZS5lbWFpbENvbmZpZy50ZXh0ID0gYXdhaXQgdGhpcy5vcHRpb25zU2VydmljZS5nZXRJbmhlcml0ZWRUZW5hbnRPcHRpb24oXG4gICAgICAgICdjb25maWd1cmF0aW9uJyxcbiAgICAgICAgJ2V4cG9ydC5kYXRhLm1haWwudGV4dCcsXG4gICAgICAgIHRoaXMuZGVmYXVsdEV4cG9ydEVtYWlsVGVtcGxhdGVcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMuaW5pdGlhbFNjaGVkdWxlLmVtYWlsQ29uZmlnLnRvID0gY3VycmVudFVzZXJFbWFpbDtcbiAgICB0aGlzLmV4cCA9IGF3YWl0IHRoaXMucmVwb3J0c1NlcnZpY2UuZ2V0RXhwb3J0KHRoaXMuX2V4cG9ydElkKTtcbiAgICB0aGlzLmluaXRpYWxTY2hlZHVsZS5lbWFpbENvbmZpZy5zdWJqZWN0ID0gdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoXG4gICAgICBnZXR0ZXh0KCdFeHBvcnQgb2YgXCJ7e2V4cE5hbWV9fVwiJyksXG4gICAgICB7IGV4cE5hbWU6IHRoaXMuZXhwLm5hbWUgfVxuICAgICk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcygpIHtcbiAgICB0aGlzLnRyYW5zbGF0ZUJ1dHRvblRpdGxlcygpO1xuICB9XG5cbiAgdHJhbnNsYXRlQnV0dG9uVGl0bGVzKCkge1xuICAgIHRoaXMuYnV0dG9uTGFiZWxzID0ge1xuICAgICAgZWRpdDogdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoZ2V0dGV4dCgnRWRpdCBzY2hlZHVsZScpKSxcbiAgICAgIGVkaXROb1Blcm1pc3Npb246IHRoaXMudHJhbnNsYXRlU2VydmljZS5pbnN0YW50KGdldHRleHQoJ0VkaXQgc2NoZWR1bGUgLSBubyBwZXJtaXNzaW9ucycpKSxcbiAgICAgIGR1cGxpY2F0ZTogdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoZ2V0dGV4dCgnRHVwbGljYXRlIHNjaGVkdWxlJykpLFxuICAgICAgZHVwbGljYXRlTm9QZXJtaXNzaW9uOiB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChcbiAgICAgICAgZ2V0dGV4dCgnRHVwbGljYXRlIHNjaGVkdWxlIC0gbm8gcGVybWlzc2lvbnMnKVxuICAgICAgKSxcbiAgICAgIGRlbGV0ZTogdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoZ2V0dGV4dCgnRGVsZXRlIHNjaGVkdWxlJykpLFxuICAgICAgZGVsZXRlTm9QZXJtaXNzaW9uOiB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChnZXR0ZXh0KCdEZWxldGUgc2NoZWR1bGUgLSBubyBwZXJtaXNzaW9ucycpKVxuICAgIH07XG4gIH1cblxuICBhc3luYyBnZXRDdXJyZW50VXNlckVtYWlsKCkge1xuICAgIGNvbnN0IHsgZGF0YSB9ID0gYXdhaXQgdGhpcy51c2VyU2VydmljZS5jdXJyZW50KCk7XG4gICAgcmV0dXJuIGRhdGEgJiYgZGF0YS5lbWFpbCA/IFtkYXRhLmVtYWlsXSA6IFtdO1xuICB9XG4gIGFzeW5jIGNoZWNrUm9sZSgpIHtcbiAgICBjb25zdCB7IGRhdGEgfSA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuY3VycmVudCgpO1xuICAgIGNvbnN0IHJvbGUgPSBQZXJtaXNzaW9ucy5ST0xFX1NDSEVEVUxFX1JFUE9SVF9BRE1JTjtcbiAgICBjb25zdCBoYXNSb2xlID0gdGhpcy51c2VyU2VydmljZS5oYXNSb2xlKGRhdGEsIHJvbGUpO1xuICAgIHJldHVybiBoYXNSb2xlO1xuICB9XG5cbiAgYXN5bmMgZ2V0U2NoZWR1bGVMaXN0KHdpdGhQcm9ncmVzczogYm9vbGVhbikge1xuICAgIGlmICh3aXRoUHJvZ3Jlc3MpIHtcbiAgICAgIHRoaXMubG9hZGluZ1N0YXR1cy5pblByb2dyZXNzID0gdHJ1ZTtcbiAgICB9XG4gICAgdGhpcy5zY2hlZHVsZUxpc3QgPSBhd2FpdCB0aGlzLnJlcG9ydHNTZXJ2aWNlLmdldFNjaGVkdWxlTGlzdCh0aGlzLl9leHBvcnRJZCk7XG4gICAgaWYgKHdpdGhQcm9ncmVzcykge1xuICAgICAgdGhpcy5sb2FkaW5nU3RhdHVzLmluUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBhZGRTY2hlZHVsZSgpIHtcbiAgICB0aGlzLm9wZW5BZGRFZGl0TW9kYWwodGhpcy5fZXhwb3J0SWQsIHRoaXMuaW5pdGlhbFNjaGVkdWxlLCBBY3Rpb25UeXBlLkNSRUFURSk7XG4gIH1cblxuICBlZGl0U2NoZWR1bGUoc2NoZWR1bGU6IFNjaGVkdWxlLCBpbmRleDogbnVtYmVyLCBldmVudDogYW55KSB7XG4gICAgaWYgKHRoaXMuaGFzUmVxdWlyZWRSb2xlKSB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgdGhpcy5vcGVuQWRkRWRpdE1vZGFsKHRoaXMuX2V4cG9ydElkLCBzY2hlZHVsZSwgQWN0aW9uVHlwZS5FRElULCBpbmRleCk7XG4gICAgfVxuICB9XG5cbiAgZHVwbGljYXRlU2NoZWR1bGUoc2NoZWR1bGU6IFNjaGVkdWxlLCBldmVudDogYW55KSB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB0aGlzLm9wZW5BZGRFZGl0TW9kYWwodGhpcy5fZXhwb3J0SWQsIHNjaGVkdWxlLCBBY3Rpb25UeXBlLkRVUExJQ0FURSk7XG4gIH1cblxuICBvcGVuQWRkRWRpdE1vZGFsKFxuICAgIGV4cG9ydElkOiBJZFJlZmVyZW5jZSxcbiAgICBzY2hlZHVsZTogU2NoZWR1bGUsXG4gICAgYWN0aW9uVHlwZTogQWN0aW9uVHlwZSxcbiAgICBpbmRleD86IG51bWJlclxuICApIHtcbiAgICBjb25zdCBwYXlsb2FkID0geyBhY3Rpb25UeXBlLCBleHBvcnRJZCwgc2NoZWR1bGU6IGNsb25lRGVlcChzY2hlZHVsZSkgfTtcbiAgICBjb25zdCBtb2RhbE9wdGlvbnMgPSB7XG4gICAgICBjbGFzczogJ21vZGFsLXNtJyxcbiAgICAgIGFyaWFEZXNjcmliZWRieTogJ21vZGFsLWJvZHknLFxuICAgICAgYXJpYUxhYmVsbGVkQnk6ICdtb2RhbC10aXRsZScsXG4gICAgICBpbml0aWFsU3RhdGU6IHBheWxvYWRcbiAgICB9IGFzIE1vZGFsT3B0aW9ucztcbiAgICB0aGlzLm1vZGFsUmVmID0gdGhpcy5ic01vZGFsU2VydmljZS5zaG93KFNjaGVkdWxlTW9kYWxDb21wb25lbnQsIG1vZGFsT3B0aW9ucyk7XG4gICAgdGhpcy5tb2RhbFJlZi5jb250ZW50LmVtaXR0ZXIuc3Vic2NyaWJlKChsb2FkOiBFbWl0dGVyUGF5bG9hZCkgPT5cbiAgICAgIHRoaXMuZ2V0TWVzc2FnZUZyb21Nb2RhbChsb2FkLCBpbmRleClcbiAgICApO1xuICB9XG5cbiAgZ2V0TWVzc2FnZUZyb21Nb2RhbChwYXlsb2FkOiBFbWl0dGVyUGF5bG9hZCwgaW5kZXg/OiBudW1iZXIpIHtcbiAgICBpZiAocGF5bG9hZC5zdWNjZXNzKSB7XG4gICAgICBpZiAoaW5kZXggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLnNjaGVkdWxlTGlzdFtpbmRleF0gPSBwYXlsb2FkLnNjaGVkdWxlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zY2hlZHVsZUxpc3QucHVzaChwYXlsb2FkLnNjaGVkdWxlKTtcbiAgICAgIH1cbiAgICAgIHRoaXMub25TY2hlZHVsZXNVcGRhdGUuZW1pdCh0aGlzLnNjaGVkdWxlTGlzdCk7XG4gICAgfVxuICB9XG5cbiAgcmVtb3ZlU2NoZWR1bGUoc2NoZWR1bGU6IFNjaGVkdWxlLCBpbmRleDogbnVtYmVyLCBldmVudDogYW55KSB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB0aGlzLnNjaGVkdWxlTGlzdC5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIHRoaXMub25TY2hlZHVsZXNVcGRhdGUuZW1pdCh0aGlzLnNjaGVkdWxlTGlzdCk7XG4gIH1cbn1cbiIsIjxkaXY+XG4gIDxkaXYgKm5nSWY9XCJsb2FkaW5nU3RhdHVzLmluUHJvZ3Jlc3NcIiBjbGFzcz1cImQtZmxleCBhLWktY2VudGVyXCI+XG4gICAgPGM4eS1sb2FkaW5nPjwvYzh5LWxvYWRpbmc+XG4gIDwvZGl2PlxuXG4gIDxkaXYgKm5nSWY9XCIhbG9hZGluZ1N0YXR1cy5pblByb2dyZXNzICYmIGxvYWRpbmdTdGF0dXMuZG9uZSAmJiBsb2FkaW5nU3RhdHVzLmVycm9yXCI+XG4gICAgPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LXdhcm5pbmcgbWF4LXdpZHRoLTEwMFwiIHRyYW5zbGF0ZT5Db3VsZCBub3QgbG9hZCBzY2hlZHVsZXMgbGlzdC48L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPGRpdiAqbmdJZj1cIiFsb2FkaW5nU3RhdHVzLmluUHJvZ3Jlc3MgJiYgIWxvYWRpbmdTdGF0dXMuZG9uZSAmJiAhbG9hZGluZ1N0YXR1cy5lcnJvclwiPlxuICAgIDxjOHktdWktZW1wdHktc3RhdGVcbiAgICAgICpuZ0lmPVwiIXNjaGVkdWxlTGlzdC5sZW5ndGhcIlxuICAgICAgW2ljb25dPVwiJ2M4eS1yZXBvcnQnXCJcbiAgICAgIFt0aXRsZV09XCInTm8gZXhwb3J0IHNjaGVkdWxlcyBkZWZpbmVkLicgfCB0cmFuc2xhdGVcIlxuICAgICAgW2hvcml6b250YWxdPVwidHJ1ZVwiXG4gICAgPjwvYzh5LXVpLWVtcHR5LXN0YXRlPlxuXG4gICAgPGRpdiBjbGFzcz1cImM4eS1saXN0X19ncm91cFwiICpuZ0lmPVwic2NoZWR1bGVMaXN0Lmxlbmd0aFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImM4eS1saXN0X19pdGVtIGhpZGRlbi14c1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYzh5LWxpc3RfX2l0ZW1fX2Jsb2NrXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImM4eS1saXN0X19pdGVtX19pY29uXCI+XG4gICAgICAgICAgICA8aSBjbGFzcz1cInAtbC0yNFwiPjwvaT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYzh5LWxpc3RfX2l0ZW1fX2JvZHlcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXhcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1zbS02XCI+XG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwibS0wXCI+XG4gICAgICAgICAgICAgICAgICB7eyAnRGVzY3JpcHRpb24nIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tNiBtLXItNDBcIj5cbiAgICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJtLTBcIj5cbiAgICAgICAgICAgICAgICAgIHt7ICdGcmVxdWVuY3knIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJjOHktbGlzdF9faXRlbSBwb2ludGVyXCJcbiAgICAgICAgKm5nRm9yPVwibGV0IHNjaGVkdWxlIG9mIHNjaGVkdWxlTGlzdDsgaW5kZXggYXMgaVwiXG4gICAgICAgIChjbGljayk9XCJlZGl0U2NoZWR1bGUoc2NoZWR1bGUsIGksICRldmVudClcIlxuICAgICAgPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYzh5LWxpc3RfX2l0ZW1fX2Jsb2NrXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImM4eS1saXN0X19pdGVtX19pY29uXCI+XG4gICAgICAgICAgICA8aSBjOHlJY29uPVwiYzh5LXJlcG9ydFwiIGNsYXNzPVwiYzh5LWljb24tZHVvY29sb3JcIj48L2k+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImM4eS1saXN0X19pdGVtX19ib2R5IGQtZmxleFwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1zbS02IGNvbC14cy02XCI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0ZXh0LXRydW5jYXRlXCIgdGl0bGU9XCJ7eyBzY2hlZHVsZS5lbWFpbENvbmZpZy5zdWJqZWN0IH19XCI+XG4gICAgICAgICAgICAgICAge3sgc2NoZWR1bGUuZW1haWxDb25maWcuc3ViamVjdCB9fVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1zbS02IGNvbC14cy02XCI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggYS1pLWJhc2VsaW5lXCI+XG4gICAgICAgICAgICAgICAgPGkgYzh5SWNvbj1cImNhbGVuZGFyXCIgY2xhc3M9XCJ0ZXh0LW11dGVkIG0tci00XCI+PC9pPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic21hcnQtcnVsZS1pbmZvcm1hdGlvblwiPlxuICAgICAgICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCJjcm9uU2VydmljZS5nZXRCYXNlKHNjaGVkdWxlLmNyb25Db25maWcpID09PSAyXCJcbiAgICAgICAgICAgICAgICAgICAgbmdOb25CaW5kYWJsZVxuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgICAgICAgW3RyYW5zbGF0ZVBhcmFtc109XCJ7IG1pbnV0ZXM6IHNjaGVkdWxlLmNyb25Db25maWcubWludXRlIHwgbnVtYmVyOiAnMi4wLTAnIH1cIlxuICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICBIb3VybHk6IHt7IG1pbnV0ZXMgfX0gbWludXRlKHMpIHBhc3QgdGhlIGhvdXIuXG4gICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgICAgICAgICAqbmdJZj1cImNyb25TZXJ2aWNlLmdldEJhc2Uoc2NoZWR1bGUuY3JvbkNvbmZpZykgPT09IDNcIlxuICAgICAgICAgICAgICAgICAgICBuZ05vbkJpbmRhYmxlXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgICAgICAgICBbdHJhbnNsYXRlUGFyYW1zXT1cIntcbiAgICAgICAgICAgICAgICAgICAgICBob3VyOiBzY2hlZHVsZS5jcm9uQ29uZmlnLmhvdXIgfCBudW1iZXI6ICcyLjAtMCcsXG4gICAgICAgICAgICAgICAgICAgICAgbWludXRlczogc2NoZWR1bGUuY3JvbkNvbmZpZy5taW51dGUgfCBudW1iZXI6ICcyLjAtMCdcbiAgICAgICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIERhaWx5OiBhdCB7eyBob3VyIH19Ont7IG1pbnV0ZXMgfX0uXG4gICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgICAgICAgICAqbmdJZj1cImNyb25TZXJ2aWNlLmdldEJhc2Uoc2NoZWR1bGUuY3JvbkNvbmZpZykgPT09IDRcIlxuICAgICAgICAgICAgICAgICAgICBuZ05vbkJpbmRhYmxlXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgICAgICAgICBbdHJhbnNsYXRlUGFyYW1zXT1cIntcbiAgICAgICAgICAgICAgICAgICAgICB3ZWVrRGF5OiBjcm9uU2VydmljZS5nZXRXZWVrRGF5TmFtZShzY2hlZHVsZS5jcm9uQ29uZmlnKSxcbiAgICAgICAgICAgICAgICAgICAgICBob3VyOiBzY2hlZHVsZS5jcm9uQ29uZmlnLmhvdXIgfCBudW1iZXI6ICcyLjAtMCcsXG4gICAgICAgICAgICAgICAgICAgICAgbWludXRlczogc2NoZWR1bGUuY3JvbkNvbmZpZy5taW51dGUgfCBudW1iZXI6ICcyLjAtMCdcbiAgICAgICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIFdlZWtseToge3sgd2Vla0RheSB9fSwgYXQge3sgaG91ciB9fTp7eyBtaW51dGVzIH19LlxuICAgICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCJjcm9uU2VydmljZS5nZXRCYXNlKHNjaGVkdWxlLmNyb25Db25maWcpID09PSA1XCJcbiAgICAgICAgICAgICAgICAgICAgbmdOb25CaW5kYWJsZVxuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgICAgICAgW3RyYW5zbGF0ZVBhcmFtc109XCJ7XG4gICAgICAgICAgICAgICAgICAgICAgbW9udGhEYXk6IGNyb25TZXJ2aWNlLmdldE1vbnRoRGF5TmFtZShzY2hlZHVsZS5jcm9uQ29uZmlnKSxcbiAgICAgICAgICAgICAgICAgICAgICBob3VyOiBzY2hlZHVsZS5jcm9uQ29uZmlnLmhvdXIgfCBudW1iZXI6ICcyLjAtMCcsXG4gICAgICAgICAgICAgICAgICAgICAgbWludXRlczogc2NoZWR1bGUuY3JvbkNvbmZpZy5taW51dGUgfCBudW1iZXI6ICcyLjAtMCdcbiAgICAgICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIE1vbnRobHk6IHt7IG1vbnRoRGF5IH19IGRheSBvZiB0aGUgbW9udGgsIGF0IHt7IGhvdXIgfX06e3sgbWludXRlcyB9fS5cbiAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICAgICAgICAgICpuZ0lmPVwiY3JvblNlcnZpY2UuZ2V0QmFzZShzY2hlZHVsZS5jcm9uQ29uZmlnKSA9PT0gNlwiXG4gICAgICAgICAgICAgICAgICAgIG5nTm9uQmluZGFibGVcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNsYXRlXG4gICAgICAgICAgICAgICAgICAgIFt0cmFuc2xhdGVQYXJhbXNdPVwie1xuICAgICAgICAgICAgICAgICAgICAgIG1vbnRoOiBjcm9uU2VydmljZS5nZXRNb250aE5hbWUoc2NoZWR1bGUuY3JvbkNvbmZpZyksXG4gICAgICAgICAgICAgICAgICAgICAgbW9udGhEYXk6IGNyb25TZXJ2aWNlLmdldE1vbnRoRGF5TmFtZShzY2hlZHVsZS5jcm9uQ29uZmlnKSxcbiAgICAgICAgICAgICAgICAgICAgICBob3VyOiBzY2hlZHVsZS5jcm9uQ29uZmlnLmhvdXIgfCBudW1iZXI6ICcyLjAtMCcsXG4gICAgICAgICAgICAgICAgICAgICAgbWludXRlczogc2NoZWR1bGUuY3JvbkNvbmZpZy5taW51dGUgfCBudW1iZXI6ICcyLjAtMCdcbiAgICAgICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIFllYXJseToge3sgbW9udGggfX0sIHt7IG1vbnRoRGF5IH19IGRheSBvZiB0aGUgbW9udGgsIGF0IHt7IGhvdXIgfX06e3tcbiAgICAgICAgICAgICAgICAgICAgICBtaW51dGVzXG4gICAgICAgICAgICAgICAgICAgIH19LlxuICAgICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYzh5LWxpc3RfX2l0ZW1fX2FjdGlvbnNcIiAoY2xpY2spPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2V0dGluZ3MgZHJvcGRvd25cIiBkcm9wZG93bj5cbiAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZHJvcGRvd24tdG9nZ2xlIGM4eS1kcm9wZG93blwiXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgdGl0bGU9XCJ7eyAnQWN0aW9ucycgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAgIGRyb3Bkb3duVG9nZ2xlXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8aSBbYzh5SWNvbl09XCInZWxsaXBzaXMtdidcIj48L2k+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICA8dWwgcm9sZT1cImxpc3RcIiBjbGFzcz1cImRyb3Bkb3duLW1lbnUgZHJvcGRvd24tbWVudS1yaWdodFwiICpkcm9wZG93bk1lbnU+XG4gICAgICAgICAgICAgICAgPGxpIHJvbGU9XCJtZW51aXRlbVwiPlxuICAgICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgICAgW3RpdGxlXT1cImhhc1JlcXVpcmVkUm9sZSA/IGJ1dHRvbkxhYmVscy5lZGl0IDogYnV0dG9uTGFiZWxzLmVkaXROb1Blcm1pc3Npb25cIlxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiZWRpdFNjaGVkdWxlKHNjaGVkdWxlLCBpLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFoYXNSZXF1aXJlZFJvbGVcIlxuICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICA8aSBbYzh5SWNvbl09XCIncGVuY2lsJ1wiPjwvaT5cbiAgICAgICAgICAgICAgICAgICAge3sgJ0VkaXQnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICA8L2xpPlxuICAgICAgICAgICAgICAgIDxsaSByb2xlPVwibWVudWl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgICAgIFt0aXRsZV09XCJcbiAgICAgICAgICAgICAgICAgICAgICBoYXNSZXF1aXJlZFJvbGUgPyBidXR0b25MYWJlbHMuZHVwbGljYXRlIDogYnV0dG9uTGFiZWxzLmR1cGxpY2F0ZU5vUGVybWlzc2lvblxuICAgICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiZHVwbGljYXRlU2NoZWR1bGUoc2NoZWR1bGUsICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWhhc1JlcXVpcmVkUm9sZVwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIDxpIFtjOHlJY29uXT1cIidjb3B5J1wiPjwvaT5cbiAgICAgICAgICAgICAgICAgICAge3sgJ0R1cGxpY2F0ZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgIDwvbGk+XG4gICAgICAgICAgICAgICAgPGxpIHJvbGU9XCJtZW51aXRlbVwiPlxuICAgICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgICAgW3RpdGxlXT1cIlxuICAgICAgICAgICAgICAgICAgICAgIGhhc1JlcXVpcmVkUm9sZSA/IGJ1dHRvbkxhYmVscy5k