UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

124 lines 31.3 kB
import { Component, Output, Input, EventEmitter } from '@angular/core'; import { LoginService } from './login.service'; import { AlertService } from '../alert/alert.service'; import { gettext } from '../i18n/gettext'; import { LoginViews } from './login.model'; import { CredentialsFromQueryParamsService } from './credentials-from-query-params.service'; import * as i0 from "@angular/core"; import * as i1 from "./login.service"; import * as i2 from "../alert/alert.service"; import * as i3 from "./credentials-from-query-params.service"; import * as i4 from "@angular/forms"; import * as i5 from "../common/icon.directive"; import * as i6 from "../i18n/c8y-translate.directive"; import * as i7 from "@angular/common"; import * as i8 from "../authentication/password-input.component"; import * as i9 from "../forms/form-group.component"; import * as i10 from "../forms/required-input-placeholder.directive"; import * as i11 from "../i18n/c8y-translate.pipe"; export class CredentialsComponent { constructor(loginService, alert, credentialsFromQueryParamsService) { this.loginService = loginService; this.alert = alert; this.credentialsFromQueryParamsService = credentialsFromQueryParamsService; this.onChangeView = new EventEmitter(); this.loginViewParams = { disableTenant: false, showTenant: false }; this.LOGIN_VIEWS = LoginViews; this.model = {}; this.isLoading = false; this.showLoginForm = false; this.showBasicAuth = false; this.oauthOptions = {}; this.showTenant = false; this.PASSWORD_RESET_HEADER_NAME = 'passwordresettoken'; this.NO_PHONE_HEADER_NAME = 'NoPhoneHeader'; } ngOnInit() { const { oauthOptions, loginMode } = this.loginService; this.model.tenant = this.loginService.getTenant(); this.showLoginForm = typeof loginMode.visibleOnLoginPage === 'undefined' || loginMode.visibleOnLoginPage; this.showBasicAuth = loginMode.type === 'BASIC'; this.oauthOptions = oauthOptions; const credentialsFromQueryParams = this.credentialsFromQueryParamsService.getCredentialsFromQueryParams(); Object.assign(this.model, credentialsFromQueryParams); this.showTenant = this.loginViewParams.showTenant || this.loginService.showTenant(); } redirectToOauth() { this.loginService.redirectToOauth(); } /** * Allows to login into the application using basic auth. * If successful logged in the client is set in shared/cumulocity.service.ts */ async login() { try { this.isLoading = true; const basicAuth = this.loginService.useBasicAuth(this.model); await this.loginService.login(basicAuth, this.model); } catch (e) { if (e.res && e.res.headers && e.res.headers.get(this.PASSWORD_RESET_HEADER_NAME)) { this.handlePasswordReset(e.res); } else if (e.res && e.res.status === 401 && /pin.*generated/i.test(e.data.message)) { this.handleSmsChallenge(e.data.message); } else if (e.res && e.res.status === 401 && /TOTP/i.test(e.data.message)) { this.handleTotpChallenge(e.data.message); } else if (e.res && e.res.headers && e.res.headers.get(this.NO_PHONE_HEADER_NAME) && !this.loginService.isSupportUser(this.model)) { this.handleNoPhoneNumberProvided(); } else { this.loginService.generateOauthToken(this.model); this.loginService.reset(); this.alert.addServerFailure(e); } } finally { this.isLoading = false; } } handlePasswordReset(e) { this.alert.removeLastDanger(); this.model.token = e.headers.get(this.PASSWORD_RESET_HEADER_NAME); this.onChangeView.emit({ view: LoginViews.ChangePassword, credentials: this.model }); } handleTotpChallenge(message) { if (/TOTP setup required/i.test(message)) { this.onChangeView.emit({ view: LoginViews.TotpSetup, credentials: this.model }); } else { this.onChangeView.emit({ view: LoginViews.TotpChallenge, credentials: this.model }); } } handleSmsChallenge(message) { if (/pin has already been generated/i.test(message)) { this.alert.warning(gettext('The verification code was already sent. For a new verification code, please click on the link above.')); } this.alert.removeLastDanger(); this.onChangeView.emit({ view: LoginViews.SmsChallenge, credentials: this.model }); } handleNoPhoneNumberProvided() { this.onChangeView.emit({ view: LoginViews.ProvidePhoneNumber, credentials: this.model }); this.alert.warning(gettext('Two-factor authentication has been turned on for this account. Provide your phone number above to save it in your user profile and start receiving verification codes via SMS.')); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CredentialsComponent, deps: [{ token: i1.LoginService }, { token: i2.AlertService }, { token: i3.CredentialsFromQueryParamsService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: CredentialsComponent, selector: "c8y-credentials", inputs: { loginViewParams: "loginViewParams" }, outputs: { onChangeView: "onChangeView" }, ngImport: i0, template: "<div\n id=\"oauth\"\n *ngIf=\"oauthOptions.initRequest && oauthOptions.visibleOnLoginPage\"\n>\n <button\n class=\"btn btn-default btn-block btn-lg form-group m-t-8\"\n title=\"{{ oauthOptions.buttonName | translate }}\"\n type=\"button\"\n (click)=\"redirectToOauth()\"\n >\n <i\n class=\"pull-left\"\n [c8yIcon]=\"'sign-in'\"\n ></i>\n {{ oauthOptions.buttonName | translate }}\n </button>\n</div>\n\n<form\n class=\"loginForm\"\n (ngSubmit)=\"login()\"\n #loginForm=\"ngForm\"\n *ngIf=\"showLoginForm\"\n novalidate\n>\n <span\n class=\"legend form-block center\"\n *ngIf=\"!(oauthOptions.initRequest && oauthOptions.visibleOnLoginPage); else orLegend\"\n translate\n >\n Login\n </span>\n\n <ng-template #orLegend>\n <div\n class=\"legend form-block center\"\n translate\n >\n or\n </div>\n </ng-template>\n\n <c8y-form-group\n class=\"tenantField\"\n id=\"tenantField\"\n *ngIf=\"showTenant\"\n >\n <label\n for=\"tenant\"\n translate\n >\n Tenant ID\n </label>\n <input\n class=\"form-control\"\n id=\"tenant\"\n placeholder=\"{{ 'e.g.' | translate }} t12345\"\n name=\"tenant\"\n type=\"text\"\n required\n [(ngModel)]=\"model.tenant\"\n #tenant=\"ngModel\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n placeholder-no-required-hint\n [readonly]=\"loginViewParams.disableTenant\"\n />\n </c8y-form-group>\n <c8y-form-group>\n <label\n for=\"user\"\n translate\n >\n Username\n </label>\n <input\n class=\"form-control\"\n id=\"user\"\n placeholder=\"{{ 'e.g. joe or joe.doe@example.com`LOCALIZE`' | translate }}\"\n name=\"user\"\n type=\"text\"\n required\n [(ngModel)]=\"model.user\"\n #user=\"ngModel\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n placeholder-no-required-hint\n />\n </c8y-form-group>\n <c8y-form-group>\n <label\n for=\"password\"\n translate\n >\n Password\n </label>\n <c8y-password-input\n name=\"password\"\n required\n [id]=\"'password'\"\n [(ngModel)]=\"model.password\"\n [autocomplete]=\"'off'\"\n ></c8y-password-input>\n </c8y-form-group>\n <div\n class=\"form-group\"\n *ngIf=\"showBasicAuth\"\n >\n <label\n class=\"c8y-checkbox\"\n title=\"{{ 'Remember me' | translate }}\"\n >\n <input\n name=\"remember\"\n type=\"checkbox\"\n [(ngModel)]=\"loginService.rememberMe\"\n />\n <span></span>\n <span>{{ 'Remember me' | translate }}</span>\n </label>\n </div>\n <button\n class=\"btn btn-primary btn-lg btn-block form-group\"\n title=\"{{ 'Log in' | translate }}\"\n type=\"submit\"\n [disabled]=\"!loginForm.form.valid || isLoading\"\n >\n {{ 'Log in' | translate }}\n </button>\n <div class=\"text-center m-t-8\">\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Forgot password?' | translate }}\"\n type=\"button\"\n (click)=\"onChangeView.emit({ view: LOGIN_VIEWS.RecoverPassword })\"\n >\n {{ 'Forgot password?' | translate }}\n </button>\n </div>\n</form>\n", dependencies: [{ kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.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: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i5.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i6.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i8.PasswordInputComponent, selector: "c8y-password-input", inputs: ["id", "autocomplete"] }, { kind: "component", type: i9.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i10.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "pipe", type: i11.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CredentialsComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-credentials', template: "<div\n id=\"oauth\"\n *ngIf=\"oauthOptions.initRequest && oauthOptions.visibleOnLoginPage\"\n>\n <button\n class=\"btn btn-default btn-block btn-lg form-group m-t-8\"\n title=\"{{ oauthOptions.buttonName | translate }}\"\n type=\"button\"\n (click)=\"redirectToOauth()\"\n >\n <i\n class=\"pull-left\"\n [c8yIcon]=\"'sign-in'\"\n ></i>\n {{ oauthOptions.buttonName | translate }}\n </button>\n</div>\n\n<form\n class=\"loginForm\"\n (ngSubmit)=\"login()\"\n #loginForm=\"ngForm\"\n *ngIf=\"showLoginForm\"\n novalidate\n>\n <span\n class=\"legend form-block center\"\n *ngIf=\"!(oauthOptions.initRequest && oauthOptions.visibleOnLoginPage); else orLegend\"\n translate\n >\n Login\n </span>\n\n <ng-template #orLegend>\n <div\n class=\"legend form-block center\"\n translate\n >\n or\n </div>\n </ng-template>\n\n <c8y-form-group\n class=\"tenantField\"\n id=\"tenantField\"\n *ngIf=\"showTenant\"\n >\n <label\n for=\"tenant\"\n translate\n >\n Tenant ID\n </label>\n <input\n class=\"form-control\"\n id=\"tenant\"\n placeholder=\"{{ 'e.g.' | translate }} t12345\"\n name=\"tenant\"\n type=\"text\"\n required\n [(ngModel)]=\"model.tenant\"\n #tenant=\"ngModel\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n placeholder-no-required-hint\n [readonly]=\"loginViewParams.disableTenant\"\n />\n </c8y-form-group>\n <c8y-form-group>\n <label\n for=\"user\"\n translate\n >\n Username\n </label>\n <input\n class=\"form-control\"\n id=\"user\"\n placeholder=\"{{ 'e.g. joe or joe.doe@example.com`LOCALIZE`' | translate }}\"\n name=\"user\"\n type=\"text\"\n required\n [(ngModel)]=\"model.user\"\n #user=\"ngModel\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n placeholder-no-required-hint\n />\n </c8y-form-group>\n <c8y-form-group>\n <label\n for=\"password\"\n translate\n >\n Password\n </label>\n <c8y-password-input\n name=\"password\"\n required\n [id]=\"'password'\"\n [(ngModel)]=\"model.password\"\n [autocomplete]=\"'off'\"\n ></c8y-password-input>\n </c8y-form-group>\n <div\n class=\"form-group\"\n *ngIf=\"showBasicAuth\"\n >\n <label\n class=\"c8y-checkbox\"\n title=\"{{ 'Remember me' | translate }}\"\n >\n <input\n name=\"remember\"\n type=\"checkbox\"\n [(ngModel)]=\"loginService.rememberMe\"\n />\n <span></span>\n <span>{{ 'Remember me' | translate }}</span>\n </label>\n </div>\n <button\n class=\"btn btn-primary btn-lg btn-block form-group\"\n title=\"{{ 'Log in' | translate }}\"\n type=\"submit\"\n [disabled]=\"!loginForm.form.valid || isLoading\"\n >\n {{ 'Log in' | translate }}\n </button>\n <div class=\"text-center m-t-8\">\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Forgot password?' | translate }}\"\n type=\"button\"\n (click)=\"onChangeView.emit({ view: LOGIN_VIEWS.RecoverPassword })\"\n >\n {{ 'Forgot password?' | translate }}\n </button>\n </div>\n</form>\n" }] }], ctorParameters: () => [{ type: i1.LoginService }, { type: i2.AlertService }, { type: i3.CredentialsFromQueryParamsService }], propDecorators: { onChangeView: [{ type: Output }], loginViewParams: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlZGVudGlhbHMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vY29yZS9sb2dpbi9jcmVkZW50aWFscy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL2xvZ2luL2NyZWRlbnRpYWxzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVUsTUFBTSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0UsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRS9DLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDMUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsaUNBQWlDLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQzs7Ozs7Ozs7Ozs7OztBQVE1RixNQUFNLE9BQU8sb0JBQW9CO0lBbUIvQixZQUNTLFlBQTBCLEVBQzFCLEtBQW1CLEVBQ2xCLGlDQUFvRTtRQUZyRSxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixVQUFLLEdBQUwsS0FBSyxDQUFjO1FBQ2xCLHNDQUFpQyxHQUFqQyxpQ0FBaUMsQ0FBbUM7UUFyQnBFLGlCQUFZLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUVuQyxvQkFBZSxHQUErQjtZQUNyRCxhQUFhLEVBQUUsS0FBSztZQUNwQixVQUFVLEVBQUUsS0FBSztTQUNsQixDQUFDO1FBRUYsZ0JBQVcsR0FBRyxVQUFVLENBQUM7UUFDekIsVUFBSyxHQUFpQixFQUFFLENBQUM7UUFDekIsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixrQkFBYSxHQUFHLEtBQUssQ0FBQztRQUN0QixrQkFBYSxHQUFHLEtBQUssQ0FBQztRQUN0QixpQkFB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dEYsQ0FBQztJQUNILENBQUM7SUFFTyxrQkFBa0IsQ0FBQyxPQUFlO1FBQ3hDLElBQUksaUNBQWlDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDcEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ2hCLE9BQU8sQ0FDTCxzR0FBc0csQ0FDdkcsQ0FDRixDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsWUFBWSxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBRU8sMkJBQTJCO1FBQ2pDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLFVBQVUsQ0FBQyxrQkFBa0IsRUFBRSxXQUFXLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDekYsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ2hCLE9BQU8sQ0FDTCxnTEFBZ0wsQ0FDakwsQ0FDRixDQUFDO0lBQ0osQ0FBQzsrR0E1R1Usb0JBQW9CO21HQUFwQixvQkFBb0Isa0pDZGpDLG9zR0E0SUE7OzRGRDlIYSxvQkFBb0I7a0JBTGhDLFNBQVM7K0JBQ0UsaUJBQWlCOzRKQUtqQixZQUFZO3NCQUFyQixNQUFNO2dCQUVFLGVBQWU7c0JBQXZCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgT3V0cHV0LCBJbnB1dCwgRXZlbnRFbWl0dGVyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBMb2dpblNlcnZpY2UgfSBmcm9tICcuL2xvZ2luLnNlcnZpY2UnO1xuaW1wb3J0IHsgSUNyZWRlbnRpYWxzIH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgQWxlcnRTZXJ2aWNlIH0gZnJvbSAnLi4vYWxlcnQvYWxlcnQuc2VydmljZSc7XG5pbXBvcnQgeyBnZXR0ZXh0IH0gZnJvbSAnLi4vaTE4bi9nZXR0ZXh0JztcbmltcG9ydCB7IExvZ2luVmlld3MgfSBmcm9tICcuL2xvZ2luLm1vZGVsJztcbmltcG9ydCB7IENyZWRlbnRpYWxzRnJvbVF1ZXJ5UGFyYW1zU2VydmljZSB9IGZyb20gJy4vY3JlZGVudGlhbHMtZnJvbS1xdWVyeS1wYXJhbXMuc2VydmljZSc7XG5pbXBvcnQgeyBDcmVkZW50aWFsc0NvbXBvbmVudFBhcmFtcyB9IGZyb20gJy4vY3JlZGVudGlhbHMtY29tcG9uZW50LXBhcmFtcyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1jcmVkZW50aWFscycsXG4gIHRlbXBsYXRlVXJsOiAnLi9jcmVkZW50aWFscy5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlczogW11cbn0pXG5leHBvcnQgY2xhc3MgQ3JlZGVudGlhbHNDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBAT3V0cHV0KCkgb25DaGFuZ2VWaWV3ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBJbnB1dCgpIGxvZ2luVmlld1BhcmFtczogQ3JlZGVudGlhbHNDb21wb25lbnRQYXJhbXMgPSB7XG4gICAgZGlzYWJsZVRlbmFudDogZmFsc2UsXG4gICAgc2hvd1RlbmFudDogZmFsc2VcbiAgfTtcblxuICBMT0dJTl9WSUVXUyA9IExvZ2luVmlld3M7XG4gIG1vZGVsOiBJQ3JlZGVudGlhbHMgPSB7fTtcbiAgaXNMb2FkaW5nID0gZmFsc2U7XG4gIHNob3dMb2dpbkZvcm0gPSBmYWxzZTtcbiAgc2hvd0Jhc2ljQXV0aCA9IGZhbHNlO1xuICBvYXV0aE9wdGlvbnM6IGFueSA9IHt9O1xuICBzaG93VGVuYW50ID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBQQVNTV09SRF9SRVNFVF9IRUFERVJfTkFNRSA9ICdwYXNzd29yZHJlc2V0dG9rZW4nO1xuICBwcml2YXRlIHJlYWRvbmx5IE5PX1BIT05FX0hFQURFUl9OQU1FID0gJ05vUGhvbmVIZWFkZXInO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyBsb2dpblNlcnZpY2U6IExvZ2luU2VydmljZSxcbiAgICBwdWJsaWMgYWxlcnQ6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIGNyZWRlbnRpYWxzRnJvbVF1ZXJ5UGFyYW1zU2VydmljZTogQ3JlZGVudGlhbHNGcm9tUXVlcnlQYXJhbXNTZXJ2aWNlXG4gICkge31cblxuICBuZ09uSW5pdCgpIHtcbiAgICBjb25zdCB7IG9hdXRoT3B0aW9ucywgbG9naW5Nb2RlIH0gPSB0aGlzLmxvZ2luU2VydmljZTtcbiAgICB0aGlzLm1vZGVsLnRlbmFudCA9IHRoaXMubG9naW5TZXJ2aWNlLmdldFRlbmFudCgpO1xuICAgIHRoaXMuc2hvd0xvZ2luRm9ybSA9XG4gICAgICB0eXBlb2YgbG9naW5Nb2RlLnZpc2libGVPbkxvZ2luUGFnZSA9PT0gJ3VuZGVmaW5lZCcgfHwgbG9naW5Nb2RlLnZpc2libGVPbkxvZ2luUGFnZTtcbiAgICB0aGlzLnNob3dCYXNpY0F1dGggPSBsb2dpbk1vZGUudHlwZSA9PT0gJ0JBU0lDJztcbiAgICB0aGlzLm9hdXRoT3B0aW9ucyA9IG9hdXRoT3B0aW9ucztcbiAgICBjb25zdCBjcmVkZW50aWFsc0Zyb21RdWVyeVBhcmFtcyA9XG4gICAgICB0aGlzLmNyZWRlbnRpYWxzRnJvbVF1ZXJ5UGFyYW1zU2VydmljZS5nZXRDcmVkZW50aWFsc0Zyb21RdWVyeVBhcmFtcygpO1xuICAgIE9iamVjdC5hc3NpZ24odGhpcy5tb2RlbCwgY3JlZGVudGlhbHNGcm9tUXVlcnlQYXJhbXMpO1xuICAgIHRoaXMuc2hvd1RlbmFudCA9IHRoaXMubG9naW5WaWV3UGFyYW1zLnNob3dUZW5hbnQgfHwgdGhpcy5sb2dpblNlcnZpY2Uuc2hvd1RlbmFudCgpO1xuICB9XG5cbiAgcmVkaXJlY3RUb09hdXRoKCkge1xuICAgIHRoaXMubG9naW5TZXJ2aWNlLnJlZGlyZWN0VG9PYXV0aCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsbG93cyB0byBsb2dpbiBpbnRvIHRoZSBhcHBsaWNhdGlvbiB1c2luZyBiYXNpYyBhdXRoLlxuICAgKiBJZiBzdWNjZXNzZnVsIGxvZ2dlZCBpbiB0aGUgY2xpZW50IGlzIHNldCBpbiBzaGFyZWQvY3VtdWxvY2l0eS5zZXJ2aWNlLnRzXG4gICAqL1xuICBhc3luYyBsb2dpbigpIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5pc0xvYWRpbmcgPSB0cnVlO1xuICAgICAgY29uc3QgYmFzaWNBdXRoID0gdGhpcy5sb2dpblNlcnZpY2UudXNlQmFzaWNBdXRoKHRoaXMubW9kZWwpO1xuICAgICAgYXdhaXQgdGhpcy5sb2dpblNlcnZpY2UubG9naW4oYmFzaWNBdXRoLCB0aGlzLm1vZGVsKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBpZiAoZS5yZXMgJiYgZS5yZXMuaGVhZGVycyAmJiBlLnJlcy5oZWFkZXJzLmdldCh0aGlzLlBBU1NXT1JEX1JFU0VUX0hFQURFUl9OQU1FKSkge1xuICAgICAgICB0aGlzLmhhbmRsZVBhc3N3b3JkUmVzZXQoZS5yZXMpO1xuICAgICAgfSBlbHNlIGlmIChlLnJlcyAmJiBlLnJlcy5zdGF0dXMgPT09IDQwMSAmJiAvcGluLipnZW5lcmF0ZWQvaS50ZXN0KGUuZGF0YS5tZXNzYWdlKSkge1xuICAgICAgICB0aGlzLmhhbmRsZVNtc0NoYWxsZW5nZShlLmRhdGEubWVzc2FnZSk7XG4gICAgICB9IGVsc2UgaWYgKGUucmVzICYmIGUucmVzLnN0YXR1cyA9PT0gNDAxICYmIC9UT1RQL2kudGVzdChlLmRhdGEubWVzc2FnZSkpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVUb3RwQ2hhbGxlbmdlKGUuZGF0YS5tZXNzYWdlKTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIGUucmVzICYmXG4gICAgICAgIGUucmVzLmhlYWRlcnMgJiZcbiAgICAgICAgZS5yZXMuaGVhZGVycy5nZXQodGhpcy5OT19QSE9ORV9IRUFERVJfTkFNRSkgJiZcbiAgICAgICAgIXRoaXMubG9naW5TZXJ2aWNlLmlzU3VwcG9ydFVzZXIodGhpcy5tb2RlbClcbiAgICAgICkge1xuICAgICAgICB0aGlzLmhhbmRsZU5vUGhvbmVOdW1iZXJQcm92aWRlZCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sb2dpblNlcnZpY2UuZ2VuZXJhdGVPYXV0aFRva2VuKHRoaXMubW9kZWwpO1xuICAgICAgICB0aGlzLmxvZ2luU2VydmljZS5yZXNldCgpO1xuICAgICAgICB0aGlzLmFsZXJ0LmFkZFNlcnZlckZhaWx1cmUoZSk7XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVQYXNzd29yZFJlc2V0KGU6IGFueSkge1xuICAgIHRoaXMuYWxlcnQucmVtb3ZlTGFzdERhbmdlcigpO1xuICAgIHRoaXMubW9kZWwudG9rZW4gPSBlLmhlYWRlcnMuZ2V0KHRoaXMuUEFTU1dPUkRfUkVTRVRfSEVBREVSX05BTUUpO1xuICAgIHRoaXMub25DaGFuZ2VWaWV3LmVtaXQoeyB2aWV3OiBMb2dpblZpZXdzLkNoYW5nZVBhc3N3b3JkLCBjcmVkZW50aWFsczogdGhpcy5tb2RlbCB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlVG90cENoYWxsZW5nZShtZXNzYWdlKSB7XG4gICAgaWYgKC9UT1RQIHNldHVwIHJlcXVpcmVkL2kudGVzdChtZXNzYWdlKSkge1xuICAgICAgdGhpcy5vbkNoYW5nZVZpZXcuZW1pdCh7IHZpZXc6IExvZ2luVmlld3MuVG90cFNldHVwLCBjcmVkZW50aWFsczogdGhpcy5tb2RlbCB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5vbkNoYW5nZVZpZXcuZW1pdCh7IHZpZXc6IExvZ2luVmlld3MuVG90cENoYWxsZW5nZSwgY3JlZGVudGlhbHM6IHRoaXMubW9kZWwgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVTbXNDaGFsbGVuZ2UobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgaWYgKC9waW4gaGFzIGFscmVhZHkgYmVlbiBnZW5lcmF0ZWQvaS50ZXN0KG1lc3NhZ2UpKSB7XG4gICAgICB0aGlzLmFsZXJ0Lndhcm5pbmcoXG4gICAgICAgIGdldHRleHQoXG4gICAgICAgICAgJ1RoZSB2ZXJpZmljYXRpb24gY29kZSB3YXMgYWxyZWFkeSBzZW50LiBGb3IgYSBuZXcgdmVyaWZpY2F0aW9uIGNvZGUsIHBsZWFzZSBjbGljayBvbiB0aGUgbGluayBhYm92ZS4nXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMuYWxlcnQucmVtb3ZlTGFzdERhbmdlcigpO1xuICAgIHRoaXMub25DaGFuZ2VWaWV3LmVtaXQoeyB2aWV3OiBMb2dpblZpZXdzLlNtc0NoYWxsZW5nZSwgY3JlZGVudGlhbHM6IHRoaXMubW9kZWwgfSk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZU5vUGhvbmVOdW1iZXJQcm92aWRlZCgpIHtcbiAgICB0aGlzLm9uQ2hhbmdlVmlldy5lbWl0KHsgdmlldzogTG9naW5WaWV3cy5Qcm92aWRlUGhvbmVOdW1iZXIsIGNyZWRlbnRpYWxzOiB0aGlzLm1vZGVsIH0pO1xuICAgIHRoaXMuYWxlcnQud2FybmluZyhcbiAgICAgIGdldHRleHQoXG4gICAgICAgICdUd28tZmFjdG9yIGF1dGhlbnRpY2F0aW9uIGhhcyBiZWVuIHR1cm5lZCBvbiBmb3IgdGhpcyBhY2NvdW50LiBQcm92aWRlIHlvdXIgcGhvbmUgbnVtYmVyIGFib3ZlIHRvIHNhdmUgaXQgaW4geW91ciB1c2VyIHByb2ZpbGUgYW5kIHN0YXJ0IHJlY2VpdmluZyB2ZXJpZmljYXRpb24gY29kZXMgdmlhIFNNUy4nXG4gICAgICApXG4gICAgKTtcbiAgfVxufVxuIiwiPGRpdlxuICBpZD1cIm9hdXRoXCJcbiAgKm5nSWY9XCJvYXV0aE9wdGlvbnMuaW5pdFJlcXVlc3QgJiYgb2F1dGhPcHRpb25zLnZpc2libGVPbkxvZ2luUGFnZVwiXG4+XG4gIDxidXR0b25cbiAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdCBidG4tYmxvY2sgYnRuLWxnIGZvcm0tZ3JvdXAgbS10LThcIlxuICAgIHRpdGxlPVwie3sgb2F1dGhPcHRpb25zLmJ1dHRvbk5hbWUgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIChjbGljayk9XCJyZWRpcmVjdFRvT2F1dGgoKVwiXG4gID5cbiAgICA8aVxuICAgICAgY2xhc3M9XCJwdWxsLWxlZnRcIlxuICAgICAgW2M4eUljb25dPVwiJ3NpZ24taW4nXCJcbiAgICA+PC9pPlxuICAgIHt7IG9hdXRoT3B0aW9ucy5idXR0b25OYW1lIHwgdHJhbnNsYXRlIH19XG4gIDwvYnV0dG9uPlxuPC9kaXY+XG5cbjxmb3JtXG4gIGNsYXNzPVwibG9naW5Gb3JtXCJcbiAgKG5nU3VibWl0KT1cImxvZ2luKClcIlxuICAjbG9naW5Gb3JtPVwibmdGb3JtXCJcbiAgKm5nSWY9XCJzaG93TG9naW5Gb3JtXCJcbiAgbm92YWxpZGF0ZVxuPlxuICA8c3BhblxuICAgIGNsYXNzPVwibGVnZW5kIGZvcm0tYmxvY2sgY2VudGVyXCJcbiAgICAqbmdJZj1cIiEob2F1dGhPcHRpb25zLmluaXRSZXF1ZXN0ICYmIG9hdXRoT3B0aW9ucy52aXNpYmxlT25Mb2dpblBhZ2UpOyBlbHNlIG9yTGVnZW5kXCJcbiAgICB0cmFuc2xhdGVcbiAgPlxuICAgIExvZ2luXG4gIDwvc3Bhbj5cblxuICA8bmctdGVtcGxhdGUgI29yTGVnZW5kPlxuICAgIDxkaXZcbiAgICAgIGNsYXNzPVwibGVnZW5kIGZvcm0tYmxvY2sgY2VudGVyXCJcbiAgICAgIHRyYW5zbGF0ZVxuICAgID5cbiAgICAgIG9yXG4gICAgPC9kaXY+XG4gIDwvbmctdGVtcGxhdGU+XG5cbiAgPGM4eS1mb3JtLWdyb3VwXG4gICAgY2xhc3M9XCJ0ZW5hbnRGaWVsZFwiXG4gICAgaWQ9XCJ0ZW5hbnRGaWVsZFwiXG4gICAgKm5nSWY9XCJzaG93VGVuYW50XCJcbiAgPlxuICAgIDxsYWJlbFxuICAgICAgZm9yPVwidGVuYW50XCJcbiAgICAgIHRyYW5zbGF0ZVxuICAgID5cbiAgICAgIFRlbmFudCBJRFxuICAgIDwvbGFiZWw+XG4gICAgPGlucHV0XG4gICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICBpZD1cInRlbmFudFwiXG4gICAgICBwbGFjZWhvbGRlcj1cInt7ICdlLmcuJyB8IHRyYW5zbGF0ZSB9fSB0MTIzNDVcIlxuICAgICAgbmFtZT1cInRlbmFudFwiXG4gICAgICB0eXBlPVwidGV4dFwiXG4gICAgICByZXF1aXJlZFxuICAgICAgWyhuZ01vZGVsKV09XCJtb2RlbC50ZW5hbnRcIlxuICAgICAgI3RlbmFudD1cIm5nTW9kZWxcIlxuICAgICAgYXV0b2NhcGl0YWxpemU9XCJvZmZcIlxuICAgICAgYXV0b2NvcnJlY3Q9XCJvZmZcIlxuICAgICAgcGxhY2Vob2xkZXItbm8tcmVxdWlyZWQtaGludFxuICAgICAgW3JlYWRvbmx5XT1cImxvZ2luVmlld1BhcmFtcy5kaXNhYmxlVGVuYW50XCJcbiAgICAvPlxuICA8L2M4eS1mb3JtLWdyb3VwPlxuICA8Yzh5LWZvcm0tZ3JvdXA+XG4gICAgPGxhYmVsXG4gICAgICBmb3I9XCJ1c2VyXCJcbiAgICAgIHRyYW5zbGF0ZVxuICAgID5cbiAgICAgIFVzZXJuYW1lXG4gICAgPC9sYWJlbD5cbiAgICA8aW5wdXRcbiAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgIGlkPVwidXNlclwiXG4gICAgICBwbGFjZWhvbGRlcj1cInt7ICdlLmcuIGpvZSBvciBqb2UuZG9lQGV4YW1wbGUuY29tYExPQ0FMSVpFYCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgbmFtZT1cInVzZXJcIlxuICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgcmVxdWlyZWRcbiAgICAgIFsobmdNb2RlbCldPVwibW9kZWwudXNlclwiXG4gICAgICAjdXNlcj1cIm5nTW9kZWxcIlxuICAgICAgYXV0b2NhcGl0YWxpemU9XCJvZmZcIlxuICAgICAgYXV0b2NvcnJlY3Q9XCJvZmZcIlxuICAgICAgcGxhY2Vob2xkZXItbm8tcmVxdWlyZWQtaGludFxuICAgIC8+XG4gIDwvYzh5LWZvcm0tZ3JvdXA+XG4gIDxjOHktZm9ybS1ncm91cD5cbiAgICA8bGFiZWxcbiAgICAgIGZvcj1cInBhc3N3b3JkXCJcbiAgICAgIHRyYW5zbGF0ZVxuICAgID5cbiAgICAgIFBhc3N3b3JkXG4gICAgPC9sYWJlbD5cbiAgICA8Yzh5LXBhc3N3b3JkLWlucHV0XG4gICAgICBuYW1lPVwicGFzc3dvcmRcIlxuICAgICAgcmVxdWlyZWRcbiAgICAgIFtpZF09XCIncGFzc3dvcmQnXCJcbiAgICAgIFsobmdNb2RlbCldPVwibW9kZWwucGFzc3dvcmRcIlxuICAgICAgW2F1dG9jb21wbGV0ZV09XCInb2ZmJ1wiXG4gICAgPjwvYzh5LXBhc3N3b3JkLWlucHV0PlxuICA8L2M4eS1mb3JtLWdyb3VwPlxuICA8ZGl2XG4gICAgY2xhc3M9XCJmb3JtLWdyb3VwXCJcbiAgICAqbmdJZj1cInNob3dCYXNpY0F1dGhcIlxuICA+XG4gICAgPGxhYmVsXG4gICAgICBjbGFzcz1cImM4eS1jaGVja2JveFwiXG4gICAgICB0aXRsZT1cInt7ICdSZW1lbWJlciBtZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgID5cbiAgICAgIDxpbnB1dFxuICAgICAgICBuYW1lPVwicmVtZW1iZXJcIlxuICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICBbKG5nTW9kZWwpXT1cImxvZ2luU2VydmljZS5yZW1lbWJlck1lXCJcbiAgICAgIC8+XG4gICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICA8c3Bhbj57eyAnUmVtZW1iZXIgbWUnIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgIDwvbGFiZWw+XG4gIDwvZGl2PlxuICA8YnV0dG9uXG4gICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnkgYnRuLWxnIGJ0bi1ibG9jayBmb3JtLWdyb3VwXCJcbiAgICB0aXRsZT1cInt7ICdMb2cgaW4nIHwgdHJhbnNsYXRlIH19XCJcbiAgICB0eXBlPVwic3VibWl0XCJcbiAgICBbZGlzYWJsZWRdPVwiIWxvZ2luRm9ybS5mb3JtLnZhbGlkIHx8IGlzTG9hZGluZ1wiXG4gID5cbiAgICB7eyAnTG9nIGluJyB8IHRyYW5zbGF0ZSB9fVxuICA8L2J1dHRvbj5cbiAgPGRpdiBjbGFzcz1cInRleHQtY2VudGVyIG0tdC04XCI+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJidG4gYnRuLWxpbmsgYnRuLXNtXCJcbiAgICAgIHRpdGxlPVwie3sgJ0ZvcmdvdCBwYXNzd29yZD8nIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgKGNsaWNrKT1cIm9uQ2hhbmdlVmlldy5lbWl0KHsgdmlldzogTE9HSU5fVklFV1MuUmVjb3ZlclBhc3N3b3JkIH0pXCJcbiAgICA+XG4gICAgICB7eyAnRm9yZ290IHBhc3N3b3JkPycgfCB0cmFuc2xhdGUgfX1cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG48L2Zvcm0+XG4iXX0=