UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

118 lines 20.4 kB
import { Component, Output, EventEmitter, Input } from '@angular/core'; import { UserService } from '@c8y/client'; import { LoginService } from '../login/login.service'; import { AlertService } from '../alert/alert.service'; import { gettext } from '../i18n/gettext'; import * as i0 from "@angular/core"; import * as i1 from "../login/login.service"; import * as i2 from "@c8y/client"; import * as i3 from "../alert/alert.service"; import * as i4 from "@angular/forms"; import * as i5 from "../forms/form-group.component"; import * as i6 from "../forms/required-input-placeholder.directive"; import * as i7 from "../i18n/c8y-translate.directive"; import * as i8 from "@angular/common"; import * as i9 from "../i18n/c8y-translate.pipe"; export class SmsChallengeComponent { constructor(loginService, users, alert) { this.loginService = loginService; this.users = users; this.alert = alert; this.onCancel = new EventEmitter(); this.model = { smsToken: '' }; this.isLoading = false; this.resendTfa = '0'; } async verifyTFACode() { this.isLoading = true; if (await this.usesOAuthInternal()) { await this.verifyCodeWithOauth(); } else { await this.verifyCodeWithBasicAuth(); } this.isLoading = false; } async resendTFASms() { try { this.isLoading = true; await this.users.verifyTFACode(this.resendTfa); } catch (e) { if (e.res.status === 403) { this.loginService.cleanMessages(); this.loginService.addSuccessMessage('resend_sms'); } else { this.alert.addServerFailure(e); } } finally { this.isLoading = false; } } async usesOAuthInternal() { return this.loginService.isPasswordGrantLogin(this.credentials); } async verifyCodeWithOauth() { try { const { credentials } = this; await this.loginService.switchLoginMode({ ...credentials, tfa: this.model.smsToken }); await this.loginService.verifyAppAccess(); await this.loginService.authFulfilled(); } catch (e) { const resStatus = e.res && e.res.status; if (resStatus === 401) { // it is assumed that the user and password are correct so it must be the tfa code this.alert.danger(gettext('Invalid code')); } else { this.alert.addServerFailure(e); } } } async verifyCodeWithBasicAuth() { try { const { res } = await this.users.verifyTFACode(this.model.smsToken); const tfaToken = res.headers.get('tfatoken'); this.credentials.tfa = tfaToken; await this.loginWithTFA(tfaToken); } catch (e) { const resStatus = e.res && e.res.status; // BE returns 403 in case of invalid tfa code if (resStatus === 403) { this.alert.danger(gettext('Invalid code')); } else { this.alert.addServerFailure(e); } } } async loginWithTFA(tfaToken) { try { await this.loginService.login(this.loginService.useBasicAuth({ tfa: tfaToken }), this.credentials); this.loginService.saveTFAToken(tfaToken, sessionStorage); if (this.loginService.rememberMe) { this.loginService.saveTFAToken(tfaToken, localStorage); } } catch (e) { this.alert.addServerFailure(e); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SmsChallengeComponent, deps: [{ token: i1.LoginService }, { token: i2.UserService }, { token: i3.AlertService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: SmsChallengeComponent, selector: "c8y-sms-challenge", inputs: { credentials: "credentials" }, outputs: { onCancel: "onCancel" }, ngImport: i0, template: "<form #twoFactorForm=\"ngForm\" class=\"loginForm\" (ngSubmit)=\"verifyTFACode()\" novalidate>\n <div class=\"legend form-block center\" translate>Two-factor authentication</div>\n\n <c8y-form-group>\n <label translate>Verification code</label>\n <input\n [(ngModel)]=\"model.smsToken\"\n #sms_token=\"ngModel\"\n type=\"text\"\n name=\"sms_token\"\n autofocus\n autocapitalize=\"off\"\n autocorrect=\"off\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} 624327\"\n required\n />\n <p *ngIf=\"!twoFactorForm.form.valid || isLoading\" class=\"help-block\" translate>\n Insert the code received via SMS.\n </p>\n </c8y-form-group>\n\n <button\n title=\"{{ 'Verify' | translate }}\"\n [disabled]=\"!twoFactorForm.form.valid || isLoading\"\n class=\"btn btn-primary btn-lg btn-block form-group\"\n >\n {{ 'Verify' | translate }}\n </button>\n\n <div class=\"d-flex m-t-8\">\n <button\n type=\"button\"\n title=\"{{ 'Send new code' | translate }}\"\n [ngClass]=\"{ disabled: isLoading }\"\n class=\"btn btn-link btn-sm\"\n (click)=\"resendTFASms()\"\n >\n {{ 'Send new code' | translate }}\n </button>\n <button\n type=\"button\"\n title=\"{{ 'Log in' | translate }}\"\n class=\"btn btn-link btn-sm\"\n (click)=\"onCancel.emit()\"\n >\n {{ 'Log in' | 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.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: "component", type: i5.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i6.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i7.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i9.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SmsChallengeComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-sms-challenge', template: "<form #twoFactorForm=\"ngForm\" class=\"loginForm\" (ngSubmit)=\"verifyTFACode()\" novalidate>\n <div class=\"legend form-block center\" translate>Two-factor authentication</div>\n\n <c8y-form-group>\n <label translate>Verification code</label>\n <input\n [(ngModel)]=\"model.smsToken\"\n #sms_token=\"ngModel\"\n type=\"text\"\n name=\"sms_token\"\n autofocus\n autocapitalize=\"off\"\n autocorrect=\"off\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} 624327\"\n required\n />\n <p *ngIf=\"!twoFactorForm.form.valid || isLoading\" class=\"help-block\" translate>\n Insert the code received via SMS.\n </p>\n </c8y-form-group>\n\n <button\n title=\"{{ 'Verify' | translate }}\"\n [disabled]=\"!twoFactorForm.form.valid || isLoading\"\n class=\"btn btn-primary btn-lg btn-block form-group\"\n >\n {{ 'Verify' | translate }}\n </button>\n\n <div class=\"d-flex m-t-8\">\n <button\n type=\"button\"\n title=\"{{ 'Send new code' | translate }}\"\n [ngClass]=\"{ disabled: isLoading }\"\n class=\"btn btn-link btn-sm\"\n (click)=\"resendTFASms()\"\n >\n {{ 'Send new code' | translate }}\n </button>\n <button\n type=\"button\"\n title=\"{{ 'Log in' | translate }}\"\n class=\"btn btn-link btn-sm\"\n (click)=\"onCancel.emit()\"\n >\n {{ 'Log in' | translate }}\n </button>\n </div>\n</form>\n" }] }], ctorParameters: () => [{ type: i1.LoginService }, { type: i2.UserService }, { type: i3.AlertService }], propDecorators: { credentials: [{ type: Input }], onCancel: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21zLWNoYWxsZW5nZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9jb3JlL2F1dGhlbnRpY2F0aW9uL3Ntcy1jaGFsbGVuZ2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vY29yZS9hdXRoZW50aWNhdGlvbi9zbXMtY2hhbGxlbmdlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdkUsT0FBTyxFQUFFLFdBQVcsRUFBZ0IsTUFBTSxhQUFhLENBQUM7QUFDeEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3RELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0saUJBQWlCLENBQUM7Ozs7Ozs7Ozs7O0FBTzFDLE1BQU0sT0FBTyxxQkFBcUI7SUFXaEMsWUFDUyxZQUEwQixFQUN6QixLQUFrQixFQUNsQixLQUFtQjtRQUZwQixpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUN6QixVQUFLLEdBQUwsS0FBSyxDQUFhO1FBQ2xCLFVBQUssR0FBTCxLQUFLLENBQWM7UUFabkIsYUFBUSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFFeEMsVUFBSyxHQUFHO1lBQ04sUUFBUSxFQUFFLEVBQUU7U0FDYixDQUFDO1FBQ0YsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUVWLGNBQVMsR0FBRyxHQUFHLENBQUM7SUFNckIsQ0FBQztJQUVKLEtBQUssQ0FBQyxhQUFhO1FBQ2pCLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDO1FBQ3RCLElBQUksTUFBTSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDO1lBQ25DLE1BQU0sSUFBSSxDQUFDLG1CQUFtQixFQUFFLENB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QUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDO1lBQzdDLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2pDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxZQUFZLENBQUMsUUFBUTtRQUNqQyxJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUMzQixJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUNqRCxJQUFJLENBQUMsV0FBVyxDQUNqQixDQUFDO1lBQ0YsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQ3pELElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDakMsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBQ3pELENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakMsQ0FBQztJQUNILENBQUM7K0dBOUZVLHFCQUFxQjttR0FBckIscUJBQXFCLG9JQ1hsQyxrOENBa0RBOzs0RkR2Q2EscUJBQXFCO2tCQUxqQyxTQUFTOytCQUNFLG1CQUFtQjtzSUFLcEIsV0FBVztzQkFBbkIsS0FBSztnQkFDSSxRQUFRO3NCQUFqQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgSW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFVzZXJTZXJ2aWNlLCBJQ3JlZGVudGlhbHMgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBMb2dpblNlcnZpY2UgfSBmcm9tICcuLi9sb2dpbi9sb2dpbi5zZXJ2aWNlJztcbmltcG9ydCB7IEFsZXJ0U2VydmljZSB9IGZyb20gJy4uL2FsZXJ0L2FsZXJ0LnNlcnZpY2UnO1xuaW1wb3J0IHsgZ2V0dGV4dCB9IGZyb20gJy4uL2kxOG4vZ2V0dGV4dCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1zbXMtY2hhbGxlbmdlJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3Ntcy1jaGFsbGVuZ2UuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZXM6IFtdXG59KVxuZXhwb3J0IGNsYXNzIFNtc0NoYWxsZW5nZUNvbXBvbmVudCB7XG4gIEBJbnB1dCgpIGNyZWRlbnRpYWxzOiBJQ3JlZGVudGlhbHM7XG4gIEBPdXRwdXQoKSBvbkNhbmNlbCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBtb2RlbCA9IHtcbiAgICBzbXNUb2tlbjogJydcbiAgfTtcbiAgaXNMb2FkaW5nID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZXNlbmRUZmEgPSAnMCc7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGxvZ2luU2VydmljZTogTG9naW5TZXJ2aWNlLFxuICAgIHByaXZhdGUgdXNlcnM6IFVzZXJTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnQ6IEFsZXJ0U2VydmljZVxuICApIHt9XG5cbiAgYXN5bmMgdmVyaWZ5VEZBQ29kZSgpIHtcbiAgICB0aGlzLmlzTG9hZGluZyA9IHRydWU7XG4gICAgaWYgKGF3YWl0IHRoaXMudXNlc09BdXRoSW50ZXJuYWwoKSkge1xuICAgICAgYXdhaXQgdGhpcy52ZXJpZnlDb2RlV2l0aE9hdXRoKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRoaXMudmVyaWZ5Q29kZVdpdGhCYXNpY0F1dGgoKTtcbiAgICB9XG4gICAgdGhpcy5pc0xvYWRpbmcgPSBmYWxzZTtcbiAgfVxuXG4gIGFzeW5jIHJlc2VuZFRGQVNtcygpIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5pc0xvYWRpbmcgPSB0cnVlO1xuICAgICAgYXdhaXQgdGhpcy51c2Vycy52ZXJpZnlURkFDb2RlKHRoaXMucmVzZW5kVGZhKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBpZiAoZS5yZXMuc3RhdHVzID09PSA0MDMpIHtcbiAgICAgICAgdGhpcy5sb2dpblNlcnZpY2UuY2xlYW5NZXNzYWdlcygpO1xuICAgICAgICB0aGlzLmxvZ2luU2VydmljZS5hZGRTdWNjZXNzTWVzc2FnZSgncmVzZW5kX3NtcycpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5hbGVydC5hZGRTZXJ2ZXJGYWlsdXJlKGUpO1xuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmlzTG9hZGluZyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgdXNlc09BdXRoSW50ZXJuYWwoKSB7XG4gICAgcmV0dXJuIHRoaXMubG9naW5TZXJ2aWNlLmlzUGFzc3dvcmRHcmFudExvZ2luKHRoaXMuY3JlZGVudGlhbHMpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlDb2RlV2l0aE9hdXRoKCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IGNyZWRlbnRpYWxzIH0gPSB0aGlzO1xuICAgICAgYXdhaXQgdGhpcy5sb2dpblNlcnZpY2Uuc3dpdGNoTG9naW5Nb2RlKHsgLi4uY3JlZGVudGlhbHMsIHRmYTogdGhpcy5tb2RlbC5zbXNUb2tlbiB9KTtcbiAgICAgIGF3YWl0IHRoaXMubG9naW5TZXJ2aWNlLnZlcmlmeUFwcEFjY2VzcygpO1xuICAgICAgYXdhaXQgdGhpcy5sb2dpblNlcnZpY2UuYXV0aEZ1bGZpbGxlZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnN0IHJlc1N0YXR1cyA9IGUucmVzICYmIGUucmVzLnN0YXR1cztcbiAgICAgIGlmIChyZXNTdGF0dXMgPT09IDQwMSkge1xuICAgICAgICAvLyBpdCBpcyBhc3N1bWVkIHRoYXQgdGhlIHVzZXIgYW5kIHBhc3N3b3JkIGFyZSBjb3JyZWN0IHNvIGl0IG11c3QgYmUgdGhlIHRmYSBjb2RlXG4gICAgICAgIHRoaXMuYWxlcnQuZGFuZ2VyKGdldHRleHQoJ0ludmFsaWQgY29kZScpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYWxlcnQuYWRkU2VydmVyRmFpbHVyZShlKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHZlcmlmeUNvZGVXaXRoQmFzaWNBdXRoKCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IHJlcyB9ID0gYXdhaXQgdGhpcy51c2Vycy52ZXJpZnlURkFDb2RlKHRoaXMubW9kZWwuc21zVG9rZW4pO1xuICAgICAgY29uc3QgdGZhVG9rZW4gPSByZXMuaGVhZGVycy5nZXQoJ3RmYXRva2VuJyk7XG4gICAgICB0aGlzLmNyZWRlbnRpYWxzLnRmYSA9IHRmYVRva2VuO1xuICAgICAgYXdhaXQgdGhpcy5sb2dpbldpdGhURkEodGZhVG9rZW4pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnN0IHJlc1N0YXR1cyA9IGUucmVzICYmIGUucmVzLnN0YXR1cztcbiAgICAgIC8vIEJFIHJldHVybnMgNDAzIGluIGNhc2Ugb2YgaW52YWxpZCB0ZmEgY29kZVxuICAgICAgaWYgKHJlc1N0YXR1cyA9PT0gNDAzKSB7XG4gICAgICAgIHRoaXMuYWxlcnQuZGFuZ2VyKGdldHRleHQoJ0ludmFsaWQgY29kZScpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYWxlcnQuYWRkU2VydmVyRmFpbHVyZShlKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvZ2luV2l0aFRGQSh0ZmFUb2tlbikge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmxvZ2luU2VydmljZS5sb2dpbihcbiAgICAgICAgdGhpcy5sb2dpblNlcnZpY2UudXNlQmFzaWNBdXRoKHsgdGZhOiB0ZmFUb2tlbiB9KSxcbiAgICAgICAgdGhpcy5jcmVkZW50aWFsc1xuICAgICAgKTtcbiAgICAgIHRoaXMubG9naW5TZXJ2aWNlLnNhdmVURkFUb2tlbih0ZmFUb2tlbiwgc2Vzc2lvblN0b3JhZ2UpO1xuICAgICAgaWYgKHRoaXMubG9naW5TZXJ2aWNlLnJlbWVtYmVyTWUpIHtcbiAgICAgICAgdGhpcy5sb2dpblNlcnZpY2Uuc2F2ZVRGQVRva2VuKHRmYVRva2VuLCBsb2NhbFN0b3JhZ2UpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRoaXMuYWxlcnQuYWRkU2VydmVyRmFpbHVyZShlKTtcbiAgICB9XG4gIH1cbn1cbiIsIjxmb3JtICN0d29GYWN0b3JGb3JtPVwibmdGb3JtXCIgY2xhc3M9XCJsb2dpbkZvcm1cIiAobmdTdWJtaXQpPVwidmVyaWZ5VEZBQ29kZSgpXCIgbm92YWxpZGF0ZT5cbiAgPGRpdiBjbGFzcz1cImxlZ2VuZCBmb3JtLWJsb2NrIGNlbnRlclwiIHRyYW5zbGF0ZT5Ud28tZmFjdG9yIGF1dGhlbnRpY2F0aW9uPC9kaXY+XG5cbiAgPGM4eS1mb3JtLWdyb3VwPlxuICAgIDxsYWJlbCB0cmFuc2xhdGU+VmVyaWZpY2F0aW9uIGNvZGU8L2xhYmVsPlxuICAgIDxpbnB1dFxuICAgICAgWyhuZ01vZGVsKV09XCJtb2RlbC5zbXNUb2tlblwiXG4gICAgICAjc21zX3Rva2VuPVwibmdNb2RlbFwiXG4gICAgICB0eXBlPVwidGV4dFwiXG4gICAgICBuYW1lPVwic21zX3Rva2VuXCJcbiAgICAgIGF1dG9mb2N1c1xuICAgICAgYXV0b2NhcGl0YWxpemU9XCJvZmZcIlxuICAgICAgYXV0b2NvcnJlY3Q9XCJvZmZcIlxuICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnZS5nLicgfCB0cmFuc2xhdGUgfX0gNjI0MzI3XCJcbiAgICAgIHJlcXVpcmVkXG4gICAgLz5cbiAgICA8cCAqbmdJZj1cIiF0d29GYWN0b3JGb3JtLmZvcm0udmFsaWQgfHwgaXNMb2FkaW5nXCIgY2xhc3M9XCJoZWxwLWJsb2NrXCIgdHJhbnNsYXRlPlxuICAgICAgSW5zZXJ0IHRoZSBjb2RlIHJlY2VpdmVkIHZpYSBTTVMuXG4gICAgPC9wPlxuICA8L2M4eS1mb3JtLWdyb3VwPlxuXG4gIDxidXR0b25cbiAgICB0aXRsZT1cInt7ICdWZXJpZnknIHwgdHJhbnNsYXRlIH19XCJcbiAgICBbZGlzYWJsZWRdPVwiIXR3b0ZhY3RvckZvcm0uZm9ybS52YWxpZCB8fCBpc0xvYWRpbmdcIlxuICAgIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi1sZyBidG4tYmxvY2sgZm9ybS1ncm91cFwiXG4gID5cbiAgICB7eyAnVmVyaWZ5JyB8IHRyYW5zbGF0ZSB9fVxuICA8L2J1dHRvbj5cblxuICA8ZGl2IGNsYXNzPVwiZC1mbGV4IG0tdC04XCI+XG4gICAgPGJ1dHRvblxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICB0aXRsZT1cInt7ICdTZW5kIG5ldyBjb2RlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICBbbmdDbGFzc109XCJ7IGRpc2FibGVkOiBpc0xvYWRpbmcgfVwiXG4gICAgICBjbGFzcz1cImJ0biBidG4tbGluayBidG4tc21cIlxuICAgICAgKGNsaWNrKT1cInJlc2VuZFRGQVNtcygpXCJcbiAgICA+XG4gICAgICB7eyAnU2VuZCBuZXcgY29kZScgfCB0cmFuc2xhdGUgfX1cbiAgICA8L2J1dHRvbj5cbiAgICA8YnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIHRpdGxlPVwie3sgJ0xvZyBpbicgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgY2xhc3M9XCJidG4gYnRuLWxpbmsgYnRuLXNtXCJcbiAgICAgIChjbGljayk9XCJvbkNhbmNlbC5lbWl0KClcIlxuICAgID5cbiAgICAgIHt7ICdMb2cgaW4nIHwgdHJhbnNsYXRlIH19XG4gICAgPC9idXR0b24+XG4gIDwvZGl2PlxuPC9mb3JtPlxuIl19