@harbor/ui
Version:
Harbor shared UI components based on Clarity and Angular6
299 lines (298 loc) • 29.7 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
import { Component, Input, Output, EventEmitter, ViewChild, Inject } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Configuration, StringValueItem } from '../config';
import { SERVICE_CONFIG } from '../../service.config';
import { clone, isEmpty, getChanges, toPromise } from '../../utils';
import { ErrorHandler } from '../../error-handler/index';
import { ConfirmationMessage } from '../../confirmation-dialog/confirmation-message';
import { ConfirmationDialogComponent } from '../../confirmation-dialog/confirmation-dialog.component';
import { ConfigurationService } from '../../service/index';
import { from } from 'rxjs';
/** @type {?} */
const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
export class SystemSettingsComponent {
/**
* @param {?} configInfo
* @param {?} configService
* @param {?} errorHandler
*/
constructor(configInfo, configService, errorHandler) {
this.configInfo = configInfo;
this.configService = configService;
this.errorHandler = errorHandler;
this.config = new Configuration();
this.onGoing = false;
this.configChange = new EventEmitter();
this.readOnlyChange = new EventEmitter();
this.reloadSystemConfig = new EventEmitter();
this.showSubTitle = false;
this.hasAdminRole = false;
this.hasCAFile = false;
this.withAdmiral = false;
if (this.configInfo && this.configInfo.systemInfoEndpoint) {
this.downloadLink = this.configInfo.systemInfoEndpoint + "/getcert";
}
}
/**
* @return {?}
*/
get systemSettings() {
return this.config;
}
/**
* @param {?} cfg
* @return {?}
*/
set systemSettings(cfg) {
this.config = cfg;
this.configChange.emit(this.config);
}
/**
* @return {?}
*/
get editable() {
return this.systemSettings &&
this.systemSettings.token_expiration &&
this.systemSettings.token_expiration.editable;
}
/**
* @return {?}
*/
isValid() {
return this.systemSettingsForm && this.systemSettingsForm.valid;
}
/**
* @return {?}
*/
hasChanges() {
return !isEmpty(this.getChanges());
}
/**
* @return {?}
*/
getChanges() {
/** @type {?} */
let allChanges = getChanges(this.originalConfig, this.config);
if (allChanges) {
return this.getSystemChanges(allChanges);
}
return null;
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (changes && changes["systemSettings"]) {
this.originalConfig = clone(this.config);
}
}
/**
* @param {?} allChanges
* @return {?}
*/
getSystemChanges(allChanges) {
/** @type {?} */
let changes = {};
for (let prop in allChanges) {
if (prop === 'token_expiration' || prop === 'read_only' || prop === 'project_creation_restriction') {
changes[prop] = allChanges[prop];
}
}
return changes;
}
/**
* @param {?} $event
* @return {?}
*/
setRepoReadOnlyValue($event) {
this.systemSettings.read_only.value = $event;
}
/**
* @param {?} prop
* @return {?}
*/
disabled(prop) {
return !(prop && prop.editable);
}
/**
* @return {?}
*/
get canDownloadCert() {
return this.hasAdminRole && this.hasCAFile;
}
/**
*
* Save the changed values
*
* \@memberOf ConfigurationComponent
* @return {?}
*/
save() {
/** @type {?} */
let changes = this.getChanges();
if (!isEmpty(changes)) {
this.onGoing = true;
this.configService.saveConfigurations(changes)
.then(response => {
this.onGoing = false;
// API should return the updated configurations here
// Unfortunately API does not do that
// To refresh the view, we can clone the original data copy
// or force refresh by calling service.
// HERE we choose force way
this.retrieveConfig();
if ('read_only' in changes) {
this.readOnlyChange.emit(changes['read_only']);
}
this.reloadSystemConfig.emit();
this.errorHandler.info('CONFIG.SAVE_SUCCESS');
})
.catch(error => {
this.onGoing = false;
this.errorHandler.error(error);
});
}
else {
// Inprop situation, should not come here
console.error('Save abort because nothing changed');
}
}
/**
* @return {?}
*/
retrieveConfig() {
this.onGoing = true;
from(toPromise(this.configService.getConfigurations()))
.subscribe((configurations) => {
this.onGoing = false;
// Add two password fields
configurations.email_password = new StringValueItem(fakePass, true);
this.config = configurations;
// Keep the original copy of the data
this.originalConfig = clone(configurations);
}, error => {
this.onGoing = false;
this.errorHandler.error(error);
});
}
/**
* @param {?} changes
* @return {?}
*/
reset(changes) {
if (!isEmpty(changes)) {
for (let prop in changes) {
if (this.originalConfig[prop]) {
this.config[prop] = clone(this.originalConfig[prop]);
}
}
}
else {
// force reset
this.retrieveConfig();
}
}
/**
* @param {?} ack
* @return {?}
*/
confirmCancel(ack) {
if (ack && ack.source === 9 /* CONFIG */ &&
ack.state === 1 /* CONFIRMED */) {
/** @type {?} */
let changes = this.getChanges();
this.reset(changes);
}
}
/**
* @return {?}
*/
get inProgress() {
return this.onGoing;
}
/**
*
* Discard current changes if have and reset
*
* \@memberOf ConfigurationComponent
* @return {?}
*/
cancel() {
/** @type {?} */
let changes = this.getChanges();
if (!isEmpty(changes)) {
/** @type {?} */
let msg = new ConfirmationMessage('CONFIG.CONFIRM_TITLE', 'CONFIG.CONFIRM_SUMMARY', '', {}, 9 /* CONFIG */);
this.confirmationDlg.open(msg);
}
else {
// Invalid situation, should not come here
console.error('Nothing changed');
}
}
}
SystemSettingsComponent.decorators = [
{ type: Component, args: [{
selector: 'system-settings',
template: "<form #systemConfigFrom=\"ngForm\" class=\"compact\">\n <section class=\"form-block\" style=\"margin-top:0px;margin-bottom:0px;\">\n <label style=\"font-size:14px;font-weight:600;\" *ngIf=\"showSubTitle\">{{'CONFIG.SYSTEM' | translate}}</label>\n <div class=\"form-group\">\n <label for=\"proCreation\">{{'CONFIG.PRO_CREATION_RESTRICTION' | translate}}</label>\n <div class=\"select\">\n <select id=\"proCreation\" name=\"proCreation\" [(ngModel)]=\"systemSettings.project_creation_restriction.value\" [disabled]=\"disabled(systemSettings.project_creation_restriction)\">\n <option value=\"everyone\">{{'CONFIG.PRO_CREATION_EVERYONE' | translate }}</option>\n <option value=\"adminonly\">{{'CONFIG.PRO_CREATION_ADMIN' | translate }}</option>\n </select>\n </div>\n <a href=\"javascript:void(0)\" role=\"tooltip\" aria-haspopup=\"true\" class=\"tooltip tooltip-lg tooltip-top-right\" style=\"top: -1px;\">\n <clr-icon shape=\"info-circle\" class=\"info-tips-icon\" size=\"24\"></clr-icon>\n <span class=\"tooltip-content\">{{'CONFIG.TOOLTIP.PRO_CREATION_RESTRICTION' | translate}}</span>\n </a>\n </div>\n <div class=\"form-group\">\n <label for=\"tokenExpiration\" class=\"required\">{{'CONFIG.TOKEN_EXPIRATION' | translate}}</label>\n <label for=\"tokenExpiration\" aria-haspopup=\"true\" role=\"tooltip\" class=\"tooltip tooltip-validation tooltip-md tooltip-top-right\"\n [class.invalid]=\"tokenExpirationInput.invalid && (tokenExpirationInput.dirty || tokenExpirationInput.touched)\">\n <input name=\"tokenExpiration\" type=\"text\" #tokenExpirationInput=\"ngModel\" [(ngModel)]=\"systemSettings.token_expiration.value\"\n required pattern=\"^[1-9]{1}[0-9]*$\" id=\"tokenExpiration\" size=\"20\" [disabled]=\"!editable\">\n <span class=\"tooltip-content\">\n {{'TOOLTIP.NUMBER_REQUIRED' | translate}}\n </span>\n </label>\n <a href=\"javascript:void(0)\" role=\"tooltip\" aria-haspopup=\"true\" class=\"tooltip tooltip-top-right\">\n <clr-icon shape=\"info-circle\" class=\"info-tips-icon\" size=\"24\"></clr-icon>\n <span class=\"tooltip-content\">{{'CONFIG.TOOLTIP.TOKEN_EXPIRATION' | translate}}</span>\n </a>\n </div>\n <div class=\"form-group\" *ngIf=\"canDownloadCert\">\n <label for=\"certDownloadLink\" class=\"required\">{{'CONFIG.ROOT_CERT' | translate}}</label>\n <a #certDownloadLink [href]=\"downloadLink\" target=\"_blank\">{{'CONFIG.ROOT_CERT_LINK' | translate}}</a>\n <a href=\"javascript:void(0)\" role=\"tooltip\" aria-haspopup=\"true\" class=\"tooltip tooltip-top-right\">\n <clr-icon shape=\"info-circle\" class=\"info-tips-icon\" size=\"24\"></clr-icon>\n <span class=\"tooltip-content\">{{'CONFIG.TOOLTIP.ROOT_CERT_DOWNLOAD' | translate}}</span>\n </a>\n </div>\n <div *ngIf=\"!withAdmiral\" class=\"form-group\">\n <label for=\"repoReadOnly\">{{'CONFIG.REPO_READ_ONLY' | translate}}</label>\n <clr-checkbox name=\"repoReadOnly\" id=\"repoReadOnly\" [clrChecked]=\"systemSettings.read_only.value\" (clrCheckedChange)=\"setRepoReadOnlyValue($event)\">\n <a href=\"javascript:void(0)\" role=\"tooltip\" aria-haspopup=\"true\" class=\"tooltip tooltip-top-right\" style=\"top:-7px;\">\n <clr-icon shape=\"info-circle\" class=\"info-tips-icon\" size=\"24\"></clr-icon>\n <span class=\"tooltip-content\">{{'CONFIG.TOOLTIP.REPO_TOOLTIP' | translate}}</span>\n </a>\n </clr-checkbox>\n </div>\n </section>\n</form>\n<div>\n <button type=\"button\" id=\"config_system_save\" class=\"btn btn-primary\" (click)=\"save()\" [disabled]=\"!isValid() || !hasChanges()\">{{'BUTTON.SAVE' | translate}}</button>\n <button type=\"button\" class=\"btn btn-outline\" (click)=\"cancel()\" [disabled]=\"!isValid() || !hasChanges()\">{{'BUTTON.CANCEL' | translate}}</button>\n</div>\n<confirmation-dialog #cfgConfirmationDialog (confirmAction)=\"confirmCancel($event)\"></confirmation-dialog>",
styles: ["", ".info-tips-icon{color:grey}.info-tips-icon:hover{color:#007cbb}"]
}] }
];
/** @nocollapse */
SystemSettingsComponent.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [SERVICE_CONFIG,] }] },
{ type: ConfigurationService },
{ type: ErrorHandler }
];
SystemSettingsComponent.propDecorators = {
configChange: [{ type: Output }],
readOnlyChange: [{ type: Output }],
reloadSystemConfig: [{ type: Output }],
systemSettings: [{ type: Input }],
showSubTitle: [{ type: Input }],
hasAdminRole: [{ type: Input }],
hasCAFile: [{ type: Input }],
withAdmiral: [{ type: Input }],
systemSettingsForm: [{ type: ViewChild, args: ["systemConfigFrom",] }],
confirmationDlg: [{ type: ViewChild, args: ["cfgConfirmationDialog",] }]
};
if (false) {
/** @type {?} */
SystemSettingsComponent.prototype.config;
/** @type {?} */
SystemSettingsComponent.prototype.onGoing;
/** @type {?} */
SystemSettingsComponent.prototype.originalConfig;
/** @type {?} */
SystemSettingsComponent.prototype.downloadLink;
/** @type {?} */
SystemSettingsComponent.prototype.configChange;
/** @type {?} */
SystemSettingsComponent.prototype.readOnlyChange;
/** @type {?} */
SystemSettingsComponent.prototype.reloadSystemConfig;
/** @type {?} */
SystemSettingsComponent.prototype.showSubTitle;
/** @type {?} */
SystemSettingsComponent.prototype.hasAdminRole;
/** @type {?} */
SystemSettingsComponent.prototype.hasCAFile;
/** @type {?} */
SystemSettingsComponent.prototype.withAdmiral;
/** @type {?} */
SystemSettingsComponent.prototype.systemSettingsForm;
/** @type {?} */
SystemSettingsComponent.prototype.confirmationDlg;
/** @type {?} */
SystemSettingsComponent.prototype.configInfo;
/** @type {?} */
SystemSettingsComponent.prototype.configService;
/** @type {?} */
SystemSettingsComponent.prototype.errorHandler;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3lzdGVtLXNldHRpbmdzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BoYXJib3IvdWkvIiwic291cmNlcyI6WyJzcmMvY29uZmlnL3N5c3RlbS9zeXN0ZW0tc2V0dGluZ3MuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQTRCLE1BQU0sZUFBZSxDQUFDO0FBQ3BILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QyxPQUFPLEVBQUUsYUFBYSxFQUFFLGVBQWUsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUMzRCxPQUFPLEVBQUUsY0FBYyxFQUFrQixNQUFNLHNCQUFzQixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDcEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdEQUFnRCxDQUFDO0FBQ3JGLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLHlEQUF5RCxDQUFDO0FBR3RHLE9BQU8sRUFDSCxvQkFBb0IsRUFDdkIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDOztBQUM1QixNQUFNLFFBQVEsR0FBRyxzQkFBc0IsQ0FBQztBQU94QyxNQUFNOzs7Ozs7SUFpTEYsWUFBNEMsVUFBMEIsRUFDMUQsZUFDQTtRQUZnQyxlQUFVLEdBQVYsVUFBVSxDQUFnQjtRQUMxRCxrQkFBYSxHQUFiLGFBQWE7UUFDYixpQkFBWSxHQUFaLFlBQVk7c0JBbExBLElBQUksYUFBYSxFQUFFO3VCQUNqQyxLQUFLOzRCQUd1QyxJQUFJLFlBQVksRUFBaUI7OEJB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LGlCQUFpQjtnQkFDM0Isd3lJQUErQzs7YUFFbEQ7Ozs7NENBa0xnQixNQUFNLFNBQUMsY0FBYztZQTNMbEMsb0JBQW9CO1lBTmYsWUFBWTs7OzJCQXFCaEIsTUFBTTs2QkFDTixNQUFNO2lDQUNOLE1BQU07NkJBRU4sS0FBSzsyQkFTTCxLQUFLOzJCQUNMLEtBQUs7d0JBQ0wsS0FBSzswQkFDTCxLQUFLO2lDQUVMLFNBQVMsU0FBQyxrQkFBa0I7OEJBQzVCLFNBQVMsU0FBQyx1QkFBdUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgVmlld0NoaWxkLCBJbmplY3QsIE9uQ2hhbmdlcywgU2ltcGxlQ2hhbmdlcyB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTmdGb3JtIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQ29uZmlndXJhdGlvbiwgU3RyaW5nVmFsdWVJdGVtIH0gZnJvbSAnLi4vY29uZmlnJztcbmltcG9ydCB7IFNFUlZJQ0VfQ09ORklHLCBJU2VydmljZUNvbmZpZyB9IGZyb20gJy4uLy4uL3NlcnZpY2UuY29uZmlnJztcbmltcG9ydCB7IGNsb25lLCBpc0VtcHR5LCBnZXRDaGFuZ2VzLCB0b1Byb21pc2UgfSBmcm9tICcuLi8uLi91dGlscyc7XG5pbXBvcnQgeyBFcnJvckhhbmRsZXIgfSBmcm9tICcuLi8uLi9lcnJvci1oYW5kbGVyL2luZGV4JztcbmltcG9ydCB7IENvbmZpcm1hdGlvbk1lc3NhZ2UgfSBmcm9tICcuLi8uLi9jb25maXJtYXRpb24tZGlhbG9nL2NvbmZpcm1hdGlvbi1tZXNzYWdlJztcbmltcG9ydCB7IENvbmZpcm1hdGlvbkRpYWxvZ0NvbXBvbmVudCB9IGZyb20gJy4uLy4uL2NvbmZpcm1hdGlvbi1kaWFsb2cvY29uZmlybWF0aW9uLWRpYWxvZy5jb21wb25lbnQnO1xuaW1wb3J0IHsgQ29uZmlybWF0aW9uU3RhdGUsIENvbmZpcm1hdGlvblRhcmdldHMgfSBmcm9tICcuLi8uLi9zaGFyZWQvc2hhcmVkLmNvbnN0JztcbmltcG9ydCB7IENvbmZpcm1hdGlvbkFja25vd2xlZGdlbWVudCB9IGZyb20gJy4uLy4uL2NvbmZpcm1hdGlvbi1kaWFsb2cvY29uZmlybWF0aW9uLXN0YXRlLW1lc3NhZ2UnO1xuaW1wb3J0IHtcbiAgICBDb25maWd1cmF0aW9uU2VydmljZVxufSBmcm9tICcuLi8uLi9zZXJ2aWNlL2luZGV4JztcbmltcG9ydCB7IGZyb20gfSBmcm9tICdyeGpzJztcbmNvbnN0IGZha2VQYXNzID0gJ2FXcExPU1lrSXpKVFRVNHdNRGt4JztcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdzeXN0ZW0tc2V0dGluZ3MnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9zeXN0ZW0tc2V0dGluZ3MuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3N5c3RlbS1zZXR0aW5ncy5jb21wb25lbnQuc2NzcycsICcuLi9yZWdpc3RyeS1jb25maWcuY29tcG9uZW50LnNjc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBTeXN0ZW1TZXR0aW5nc0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gICAgY29uZmlnOiBDb25maWd1cmF0aW9uID0gbmV3IENvbmZpZ3VyYXRpb24oKTtcbiAgICBvbkdvaW5nID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBvcmlnaW5hbENvbmZpZzogQ29uZmlndXJhdGlvbjtcbiAgICBkb3dubG9hZExpbms6IHN0cmluZztcbiAgICBAT3V0cHV0KCkgY29uZmlnQ2hhbmdlOiBFdmVudEVtaXR0ZXI8Q29uZmlndXJhdGlvbj4gPSBuZXcgRXZlbnRFbWl0dGVyPENvbmZpZ3VyYXRpb24+KCk7XG4gICAgQE91dHB1dCgpIHJlYWRPbmx5Q2hhbmdlOiBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4gPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG4gICAgQE91dHB1dCgpIHJlbG9hZFN5c3RlbUNvbmZpZzogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuICAgIEBJbnB1dCgpXG4gICAgZ2V0IHN5c3RlbVNldHRpbmdzKCk6IENvbmZpZ3VyYXRpb24ge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maWc7XG4gICAgfVxuICAgIHNldCBzeXN0ZW1TZXR0aW5ncyhjZmc6IENvbmZpZ3VyYXRpb24pIHtcbiAgICAgICAgdGhpcy5jb25maWcgPSBjZmc7XG4gICAgICAgIHRoaXMuY29uZmlnQ2hhbmdlLmVtaXQodGhpcy5jb25maWcpO1xuICAgIH1cblxuICAgIEBJbnB1dCgpIHNob3dTdWJUaXRsZTogYm9vbGVhbiA9IGZhbHNlO1xuICAgIEBJbnB1dCgpIGhhc0FkbWluUm9sZTogYm9vbGVhbiA9IGZhbHNlO1xuICAgIEBJbnB1dCgpIGhhc0NBRmlsZTogYm9vbGVhbiA9IGZhbHNlO1xuICAgIEBJbnB1dCgpIHdpdGhBZG1pcmFsID0gZmFsc2U7XG5cbiAgICBAVmlld0NoaWxkKFwic3lzdGVtQ29uZmlnRnJvbVwiKSBzeXN0ZW1TZXR0aW5nc0Zvcm06IE5nRm9ybTtcbiAgICBAVmlld0NoaWxkKFwiY2ZnQ29uZmlybWF0aW9uRGlhbG9nXCIpIGNvbmZpcm1hdGlvbkRsZzogQ29uZmlybWF0aW9uRGlhbG9nQ29tcG9uZW50O1xuXG4gICAgZ2V0IGVkaXRhYmxlKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5zeXN0ZW1TZXR0aW5ncyAmJlxuICAgICAgICAgICAgdGhpcy5zeXN0ZW1TZXR0aW5ncy50b2tlbl9leHBpcmF0aW9uICYmXG4gICAgICAgICAgICB0aGlzLnN5c3RlbVNldHRpbmdzLnRva2VuX2V4cGlyYXRpb24uZWRpdGFibGU7XG4gICAgfVxuXG4gICAgcHVibGljIGlzVmFsaWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnN5c3RlbVNldHRpbmdzRm9ybSAmJiB0aGlzLnN5c3RlbVNldHRpbmdzRm9ybS52YWxpZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFzQ2hhbmdlcygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICFpc0VtcHR5KHRoaXMuZ2V0Q2hhbmdlcygpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0Q2hhbmdlcygpIHtcbiAgICAgICAgbGV0IGFsbENoYW5nZXMgPSBnZXRDaGFuZ2VzKHRoaXMub3JpZ2luYWxDb25maWcsIHRoaXMuY29uZmlnKTtcbiAgICAgICAgaWYgKGFsbENoYW5nZXMpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldFN5c3RlbUNoYW5nZXMoYWxsQ2hhbmdlcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICBpZiAoY2hhbmdlcyAmJiBjaGFuZ2VzW1wic3lzdGVtU2V0dGluZ3NcIl0pIHtcbiAgICAgICAgICAgIHRoaXMub3JpZ2luYWxDb25maWcgPSBjbG9uZSh0aGlzLmNvbmZpZyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0U3lzdGVtQ2hhbmdlcyhhbGxDaGFuZ2VzOiBhbnkpIHtcbiAgICAgICAgbGV0IGNoYW5nZXMgPSB7fTtcbiAgICAgICAgZm9yIChsZXQgcHJvcCBpbiBhbGxDaGFuZ2VzKSB7XG4gICAgICAgICAgICBpZiAocHJvcCA9PT0gJ3Rva2VuX2V4cGlyYXRpb24nIHx8IHByb3AgPT09ICdyZWFkX29ubHknIHx8IHByb3AgPT09ICdwcm9qZWN0X2NyZWF0aW9uX3Jlc3RyaWN0aW9uJykge1xuICAgICAgICAgICAgICAgIGNoYW5nZXNbcHJvcF0gPSBhbGxDaGFuZ2VzW3Byb3BdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjaGFuZ2VzO1xuICAgIH1cblxuICAgIHNldFJlcG9SZWFkT25seVZhbHVlKCRldmVudDogYW55KSB7XG4gICAgICAgIHRoaXMuc3lzdGVtU2V0dGluZ3MucmVhZF9vbmx5LnZhbHVlID0gJGV2ZW50O1xuICAgIH1cblxuICAgIGRpc2FibGVkKHByb3A6IGFueSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gIShwcm9wICYmIHByb3AuZWRpdGFibGUpO1xuICAgIH1cblxuICAgIGdldCBjYW5Eb3dubG9hZENlcnQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmhhc0FkbWluUm9sZSAmJiB0aGlzLmhhc0NBRmlsZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIFNhdmUgdGhlIGNoYW5nZWQgdmFsdWVzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyT2YgQ29uZmlndXJhdGlvbkNvbXBvbmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBzYXZlKCk6IHZvaWQge1xuICAgICAgICBsZXQgY2hhbmdlcyA9IHRoaXMuZ2V0Q2hhbmdlcygpO1xuICAgICAgICBpZiAoIWlzRW1wdHkoY2hhbmdlcykpIHtcbiAgICAgICAgICAgIHRoaXMub25Hb2luZyA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZ1NlcnZpY2Uuc2F2ZUNvbmZpZ3VyYXRpb25zKGNoYW5nZXMpXG4gICAgICAgICAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm9uR29pbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgLy8gQVBJIHNob3VsZCByZXR1cm4gdGhlIHVwZGF0ZWQgY29uZmlndXJhdGlvbnMgaGVyZVxuICAgICAgICAgICAgICAgICAgICAvLyBVbmZvcnR1bmF0ZWx5IEFQSSBkb2VzIG5vdCBkbyB0aGF0XG4gICAgICAgICAgICAgICAgICAgIC8vIFRvIHJlZnJlc2ggdGhlIHZpZXcsIHdlIGNhbiBjbG9uZSB0aGUgb3JpZ2luYWwgZGF0YSBjb3B5XG4gICAgICAgICAgICAgICAgICAgIC8vIG9yIGZvcmNlIHJlZnJlc2ggYnkgY2FsbGluZyBzZXJ2aWNlLlxuICAgICAgICAgICAgICAgICAgICAvLyBIRVJFIHdlIGNob29zZSBmb3JjZSB3YXlcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXRyaWV2ZUNvbmZpZygpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoJ3JlYWRfb25seScgaW4gY2hhbmdlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWFkT25seUNoYW5nZS5lbWl0KGNoYW5nZXNbJ3JlYWRfb25seSddKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVsb2FkU3lzdGVtQ29uZmlnLmVtaXQoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuaW5mbygnQ09ORklHLlNBVkVfU1VDQ0VTUycpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vbkdvaW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIElucHJvcCBzaXR1YXRpb24sIHNob3VsZCBub3QgY29tZSBoZXJlXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdTYXZlIGFib3J0IGJlY2F1c2Ugbm90aGluZyBjaGFuZ2VkJyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXRyaWV2ZUNvbmZpZygpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5vbkdvaW5nID0gdHJ1ZTtcbiAgICAgICAgZnJvbSh0b1Byb21pc2UodGhpcy5jb25maWdTZXJ2aWNlLmdldENvbmZpZ3VyYXRpb25zKCkpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoY29uZmlndXJhdGlvbnM6IENvbmZpZ3VyYXRpb24pID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uR29pbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAvLyBBZGQgdHdvIHBhc3N3b3JkIGZpZWxkc1xuICAgICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb25zLmVtYWlsX3Bhc3N3b3JkID0gbmV3IFN0cmluZ1ZhbHVlSXRlbShmYWtlUGFzcywgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWcgPSBjb25maWd1cmF0aW9ucztcbiAgICAgICAgICAgICAgICAvLyBLZWVwIHRoZSBvcmlnaW5hbCBjb3B5IG9mIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgdGhpcy5vcmlnaW5hbENvbmZpZyA9IGNsb25lKGNvbmZpZ3VyYXRpb25zKTtcbiAgICAgICAgICAgIH0sIGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uR29pbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZXNldChjaGFuZ2VzOiBhbnkpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFpc0VtcHR5KGNoYW5nZXMpKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBwcm9wIGluIGNoYW5nZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5vcmlnaW5hbENvbmZpZ1twcm9wXSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZ1twcm9wXSA9IGNsb25lKHRoaXMub3JpZ2luYWxDb25maWdbcHJvcF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGZvcmNlIHJlc2V0XG4gICAgICAgICAgICB0aGlzLnJldHJpZXZlQ29uZmlnKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjb25maXJtQ2FuY2VsKGFjazogQ29uZmlybWF0aW9uQWNrbm93bGVkZ2VtZW50KTogdm9pZCB7XG4gICAgICAgIGlmIChhY2sgJiYgYWNrLnNvdXJjZSA9PT0gQ29uZmlybWF0aW9uVGFyZ2V0cy5DT05GSUcgJiZcbiAgICAgICAgICAgIGFjay5zdGF0ZSA9PT0gQ29uZmlybWF0aW9uU3RhdGUuQ09ORklSTUVEKSB7XG4gICAgICAgICAgICBsZXQgY2hhbmdlcyA9IHRoaXMuZ2V0Q2hhbmdlcygpO1xuICAgICAgICAgICAgdGhpcy5yZXNldChjaGFuZ2VzKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcHVibGljIGdldCBpblByb2dyZXNzKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5vbkdvaW5nO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICogRGlzY2FyZCBjdXJyZW50IGNoYW5nZXMgaWYgaGF2ZSBhbmQgcmVzZXRcbiAgICAgKlxuICAgICAqIEBtZW1iZXJPZiBDb25maWd1cmF0aW9uQ29tcG9uZW50XG4gICAgICovXG4gICAgcHVibGljIGNhbmNlbCgpOiB2b2lkIHtcbiAgICAgICAgbGV0IGNoYW5nZXMgPSB0aGlzLmdldENoYW5nZXMoKTtcbiAgICAgICAgaWYgKCFpc0VtcHR5KGNoYW5nZXMpKSB7XG4gICAgICAgICAgICBsZXQgbXNnID0gbmV3IENvbmZpcm1hdGlvbk1lc3NhZ2UoXG4gICAgICAgICAgICAgICAgJ0NPTkZJRy5DT05GSVJNX1RJVExFJyxcbiAgICAgICAgICAgICAgICAnQ09ORklHLkNPTkZJUk1fU1VNTUFSWScsXG4gICAgICAgICAgICAgICAgJycsXG4gICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgQ29uZmlybWF0aW9uVGFyZ2V0cy5DT05GSUdcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICB0aGlzLmNvbmZpcm1hdGlvbkRsZy5vcGVuKG1zZyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBJbnZhbGlkIHNpdHVhdGlvbiwgc2hvdWxkIG5vdCBjb21lIGhlcmVcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ05vdGhpbmcgY2hhbmdlZCcpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgY29uc3RydWN0b3IoQEluamVjdChTRVJWSUNFX0NPTkZJRykgcHJpdmF0ZSBjb25maWdJbmZvOiBJU2VydmljZUNvbmZpZyxcbiAgICAgICAgcHJpdmF0ZSBjb25maWdTZXJ2aWNlOiBDb25maWd1cmF0aW9uU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBlcnJvckhhbmRsZXI6IEVycm9ySGFuZGxlcikge1xuICAgICAgICBpZiAodGhpcy5jb25maWdJbmZvICYmIHRoaXMuY29uZmlnSW5mby5zeXN0ZW1JbmZvRW5kcG9pbnQpIHtcbiAgICAgICAgICAgIHRoaXMuZG93bmxvYWRMaW5rID0gdGhpcy5jb25maWdJbmZvLnN5c3RlbUluZm9FbmRwb2ludCArIFwiL2dldGNlcnRcIjtcbiAgICAgICAgfVxuICAgIH1cblxuXG5cbn1cbiJdfQ==