UNPKG

@nowzoo/ngx-firebase-auth

Version:

Angular components for Firebase email-first sign in and out-of-band (oob) actions (reset password, etc).

265 lines (258 loc) 23.5 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ import { Component, Input, Output, EventEmitter } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AngularFireAuth } from 'angularfire2/auth'; import { NgxFirebaseAuthFormHelper } from '../../form-helper'; import { NgxFirebaseAuthService } from '../../ngx-firebase-auth.service'; import { screenAnimation } from '../../shared'; export class OobResetPasswordComponent { /** * @param {?} _afAuth * @param {?} _authService */ constructor(_afAuth, _authService) { this._afAuth = _afAuth; this._authService = _authService; this.success = new EventEmitter(); this.screen = 'wait'; this.submitting = false; this.formId = 'ngx-firebase-auth-oob-reset-password-'; this.unhandledError = null; this.cred = null; } /** * @return {?} */ get auth() { return this._afAuth.auth; } /** * @return {?} */ get authService() { return this._authService; } /** * @return {?} */ ngOnInit() { /** @type {?} */ const remembered = this.authService.getRemembered(); this.emailFc = new FormControl(''); this.passwordFc = new FormControl('', { validators: [Validators.required] }); this.rememberFc = new FormControl(remembered.remember); this.fg = new FormGroup({ email: this.emailFc, password: this.passwordFc, remember: this.rememberFc }); this.auth.checkActionCode(this.oobCode) .then((result) => { this.info = result; this.emailFc.setValue(result.data.email); this.screen = 'form'; }) .catch((error) => { this.unhandledError = error; this.screen = 'error'; }); } /** * @return {?} */ submit() { this.submitting = true; this.auth.confirmPasswordReset(this.oobCode, this.passwordFc.value) .then(() => { return this.auth.signInWithEmailAndPassword(this.info.data.email, this.passwordFc.value); }) .then((cred) => { this.cred = cred; return this.authService.setRemembered(this.rememberFc.value === true, this.info.data.email); }) .then(() => { this.screen = 'success'; this.success.emit({ mode: 'resetPassword', info: this.info, cred: this.cred, user: this.cred.user }); }) .catch((error) => { this.submitting = false; this.passwordFc.markAsDirty(); this.passwordFc.markAsTouched(); switch (error.code) { case 'auth/weak-password': NgxFirebaseAuthFormHelper.setErrorUntilChanged(this.passwordFc, error.code); break; default: this.unhandledError = error; this.screen = 'error'; break; } }); } } OobResetPasswordComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-firebase-auth-oob-reset-password', template: `<div *ngIf="'wait' === screen" [@screen]="'in'"> <div class="alert alert-secondary"> <i class="fas fa-spin fa-spinner fa-fw" aria-hidden="true"></i> Please wait... </div> </div> <div *ngIf="'success' === screen" [@screen]="'in'"> <div class="alert alert-success"> <i class="fas fa-check fa-fw" aria-hidden="true"></i> Welcome, {{cred.user.displayName}}! Your new password has been saved and you are signed in. </div> </div> <div *ngIf="screen === 'error'" [@screen]="'in'"> <div class="alert alert-danger"> <p> <i class="fas fa-exclamation-triangle fa-fw" aria-hidden="true"></i> Woops! An error occurred. </p> <div [ngSwitch]="unhandledError.code"> <p class="mb-0" *ngSwitchCase="'auth/expired-action-code'"> The reset password link you used has expired. </p> <p class="mb-0" *ngSwitchCase="'auth/invalid-action-code'"> The reset password link you used is not valid. This may be because it has already been used. </p> <p class="mb-0" *ngSwitchCase="'auth/user-disabled'"> The account associated with the reset password link you used has been disabled. </p> <p class="mb-0" *ngSwitchCase="'auth/user-not-found'"> The account associated with the reset password link you used has been removed. </p> <div *ngSwitchDefault> <p>Code: {{unhandledError.code}}</p> <p class="mb-0"> Message: {{unhandledError.message}} </p> </div> </div> </div> </div> <div *ngIf="'form' === screen" [@screen]="'in'"> <form [formGroup]="fg" (ngSubmit)="submit()"> <div class="form-group"> <label [attr.for]="formId + 'email'">Email Address</label> <input readonly #emailInput [attr.id]="formId + 'email'" [attr.aria-describedby]="formId + 'email'" type="email" autocomplete="email" placeholder="Email Address" formControlName="email" class="form-control"> <small class="text-muted form-text" [attr.id]="formId + 'email'" > You are resetting the password for {{emailFc.value}}. </small> </div> <div class="form-group"> <div class="d-flex justify-content-between align-items-end"> <label [attr.for]="formId + 'password'">Password</label> <small> <a (click)="$event.preventDefault(); passwordInput.type = 'password' === passwordInput.type ? 'text' : 'password'" href="#" tabindex="-1" class="d-inline-block"> <span *ngIf="'password' === passwordInput.type">Show</span> <span *ngIf="'text' === passwordInput.type">Hide</span> </a> </small> </div> <input #passwordInput [attr.id]="formId + 'password'" [attr.aria-describedby]="formId + 'password-help'" type="password" formControlName="password" placeholder="Password" autocomplete="password" class="form-control" [class.is-invalid]="passwordFc.touched && passwordFc.invalid"> <div class="invalid-feedback" *ngIf="passwordFc.touched && passwordFc.hasError('required')"> Required. </div> <div class="invalid-feedback" *ngIf="passwordFc.touched && passwordFc.hasError('auth/weak-password')"> That password is too weak. </div> <small [attr.id]="formId + 'password-help'" class="form-text text-muted"> Please choose a strong password. </small> </div> <div class="form-group"> <div class="form-check"> <input class="form-check-input" type="checkbox" [value]="true" formControlName="remember" [attr.id]="formId + 'remember'"> <label class="form-check-label" [attr.for]="formId + 'remember'"> Remember me on this device. </label> </div> </div> <div class="form-group"> <button type="submit" class="btn btn-success btn-block" [disabled]="fg.invalid || submitting"> <i class="fas fa-save fa-fw" aria-hidden="true"></i> Save Password and Sign In </button> </div> </form> </div> `, styles: [``], animations: [screenAnimation] },] }, ]; /** @nocollapse */ OobResetPasswordComponent.ctorParameters = () => [ { type: AngularFireAuth }, { type: NgxFirebaseAuthService } ]; OobResetPasswordComponent.propDecorators = { oobCode: [{ type: Input }], success: [{ type: Output }] }; if (false) { /** @type {?} */ OobResetPasswordComponent.prototype.oobCode; /** @type {?} */ OobResetPasswordComponent.prototype.success; /** @type {?} */ OobResetPasswordComponent.prototype.screen; /** @type {?} */ OobResetPasswordComponent.prototype.info; /** @type {?} */ OobResetPasswordComponent.prototype.submitting; /** @type {?} */ OobResetPasswordComponent.prototype.formId; /** @type {?} */ OobResetPasswordComponent.prototype.fg; /** @type {?} */ OobResetPasswordComponent.prototype.emailFc; /** @type {?} */ OobResetPasswordComponent.prototype.passwordFc; /** @type {?} */ OobResetPasswordComponent.prototype.rememberFc; /** @type {?} */ OobResetPasswordComponent.prototype.unhandledError; /** @type {?} */ OobResetPasswordComponent.prototype.cred; /** @type {?} */ OobResetPasswordComponent.prototype._afAuth; /** @type {?} */ OobResetPasswordComponent.prototype._authService; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib29iLXJlc2V0LXBhc3N3b3JkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0Bub3d6b28vbmd4LWZpcmViYXNlLWF1dGgvIiwic291cmNlcyI6WyJsaWIvb29iL29vYi1yZXNldC1wYXNzd29yZC9vb2ItcmVzZXQtcGFzc3dvcmQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9FLE9BQU8sRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUdwRCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBZ0kvQyxNQUFNOzs7OztJQWVKLFlBQ1UsU0FDRTtRQURGLFlBQU8sR0FBUCxPQUFPO1FBQ0wsaUJBQVksR0FBWixZQUFZO3VCQWRzQyxJQUFJLFlBQVksRUFBRTtzQkFFaEMsTUFBTTswQkFFekMsS0FBSztzQkFDVCx1Q0FBdUM7OEJBS25CLElBQUk7b0JBQ0wsSUFBSTtLQUkzQjs7OztJQUVMLElBQUksSUFBSTtRQUNOLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztLQUMxQjs7OztJQUNELElBQUksV0FBVztRQUNiLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDO0tBQzFCOzs7O0lBRUQsUUFBUTs7UUFDTixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3BELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxXQUFX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LElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO29CQUM1QixJQUFJLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQztvQkFDdEIsS0FBSyxDQUFDO2FBQ1Q7U0FDRixDQUFDLENBQUM7S0FDTjs7O1lBNU1GLFNBQVMsU0FBQztnQkFDVCxRQUFRLEVBQUUsc0NBQXNDO2dCQUNoRCxRQUFRLEVBQUU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQXdIWDtnQkFDQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQ1osVUFBVSxFQUFFLENBQUMsZUFBZSxDQUFDO2FBQzlCOzs7O1lBcElRLGVBQWU7WUFJZixzQkFBc0I7OztzQkFtSTVCLEtBQUs7c0JBQ0wsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1Hcm91cCwgRm9ybUNvbnRyb2wsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBBbmd1bGFyRmlyZUF1dGggfSBmcm9tICdhbmd1bGFyZmlyZTIvYXV0aCc7XG5pbXBvcnQgeyBhdXRoLCBVc2VyIH0gZnJvbSAnZmlyZWJhc2UvYXBwJztcbmltcG9ydCB7IElOZ3hGaXJlYmFzZUF1dGhPb2JTdWNjZXNzIH0gZnJvbSAnLi4vLi4vc2hhcmVkJztcbmltcG9ydCB7IE5neEZpcmViYXNlQXV0aEZvcm1IZWxwZXIgfSBmcm9tICcuLi8uLi9mb3JtLWhlbHBlcic7XG5pbXBvcnQgeyBOZ3hGaXJlYmFzZUF1dGhTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vbmd4LWZpcmViYXNlLWF1dGguc2VydmljZSc7XG5pbXBvcnQgeyBzY3JlZW5BbmltYXRpb24gfSBmcm9tICcuLi8uLi9zaGFyZWQnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtZmlyZWJhc2UtYXV0aC1vb2ItcmVzZXQtcGFzc3dvcmQnLFxuICB0ZW1wbGF0ZTogYDxkaXYgKm5nSWY9XCInd2FpdCcgPT09IHNjcmVlblwiIFtAc2NyZWVuXT1cIidpbidcIj5cbiAgPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LXNlY29uZGFyeVwiPlxuICAgIDxpIGNsYXNzPVwiZmFzIGZhLXNwaW4gZmEtc3Bpbm5lciBmYS1md1wiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPjwvaT5cbiAgICBQbGVhc2Ugd2FpdC4uLlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48ZGl2ICpuZ0lmPVwiJ3N1Y2Nlc3MnID09PSBzY3JlZW5cIiBbQHNjcmVlbl09XCInaW4nXCI+XG4gIDxkaXYgY2xhc3M9XCJhbGVydCBhbGVydC1zdWNjZXNzXCI+XG4gICAgPGkgY2xhc3M9XCJmYXMgZmEtY2hlY2sgZmEtZndcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L2k+XG4gICAgV2VsY29tZSwge3tjcmVkLnVzZXIuZGlzcGxheU5hbWV9fSFcbiAgICBZb3VyIG5ldyBwYXNzd29yZCBoYXMgYmVlbiBzYXZlZCBhbmQgeW91IGFyZSBzaWduZWQgaW4uXG4gIDwvZGl2PlxuPC9kaXY+XG5cbjxkaXYgKm5nSWY9XCJzY3JlZW4gPT09ICdlcnJvcidcIiBbQHNjcmVlbl09XCInaW4nXCI+XG4gIDxkaXYgY2xhc3M9XCJhbGVydCBhbGVydC1kYW5nZXJcIj5cbiAgICA8cD5cbiAgICAgIDxpIGNsYXNzPVwiZmFzIGZhLWV4Y2xhbWF0aW9uLXRyaWFuZ2xlIGZhLWZ3XCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9pPlxuICAgICAgV29vcHMhIEFuIGVycm9yIG9jY3VycmVkLlxuICAgIDwvcD5cbiAgICA8ZGl2IFtuZ1N3aXRjaF09XCJ1bmhhbmRsZWRFcnJvci5jb2RlXCI+XG4gICAgICA8cCBjbGFzcz1cIm1iLTBcIiAqbmdTd2l0Y2hDYXNlPVwiJ2F1dGgvZXhwaXJlZC1hY3Rpb24tY29kZSdcIj5cbiAgICAgICAgVGhlIHJlc2V0IHBhc3N3b3JkIGxpbmsgeW91IHVzZWQgaGFzIGV4cGlyZWQuXG4gICAgICA8L3A+XG4gICAgICA8cCBjbGFzcz1cIm1iLTBcIiAqbmdTd2l0Y2hDYXNlPVwiJ2F1dGgvaW52YWxpZC1hY3Rpb24tY29kZSdcIj5cbiAgICAgICAgVGhlIHJlc2V0IHBhc3N3b3JkIGxpbmsgeW91IHVzZWQgaXMgbm90IHZhbGlkLiBUaGlzIG1heSBiZSBiZWNhdXNlIGl0XG4gICAgICAgIGhhcyBhbHJlYWR5IGJlZW4gdXNlZC5cbiAgICAgIDwvcD5cbiAgICAgIDxwIGNsYXNzPVwibWItMFwiICpuZ1N3aXRjaENhc2U9XCInYXV0aC91c2VyLWRpc2FibGVkJ1wiPlxuICAgICAgICBUaGUgYWNjb3VudCBhc3NvY2lhdGVkIHdpdGggdGhlIHJlc2V0IHBhc3N3b3JkIGxpbmsgeW91IHVzZWQgaGFzIGJlZW4gZGlzYWJsZWQuXG4gICAgICA8L3A+XG4gICAgICA8cCBjbGFzcz1cIm1iLTBcIiAqbmdTd2l0Y2hDYXNlPVwiJ2F1dGgvdXNlci1ub3QtZm91bmQnXCI+XG4gICAgICAgIFRoZSBhY2NvdW50IGFzc29jaWF0ZWQgd2l0aCB0aGUgcmVzZXQgcGFzc3dvcmQgbGluayB5b3UgdXNlZCBoYXMgYmVlbiByZW1vdmVkLlxuICAgICAgPC9wPlxuICAgICAgPGRpdiAqbmdTd2l0Y2hEZWZhdWx0PlxuICAgICAgICA8cD5Db2RlOiB7e3VuaGFuZGxlZEVycm9yLmNvZGV9fTwvcD5cbiAgICAgICAgPHAgY2xhc3M9XCJtYi0wXCI+XG4gICAgICAgICAgTWVzc2FnZToge3t1bmhhbmRsZWRFcnJvci5tZXNzYWdlfX1cbiAgICAgICAgPC9wPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuPC9kaXY+XG5cblxuPGRpdiAqbmdJZj1cIidmb3JtJyA9PT0gc2NyZWVuXCIgW0BzY3JlZW5dPVwiJ2luJ1wiPlxuICA8Zm9ybSBbZm9ybUdyb3VwXT1cImZnXCIgKG5nU3VibWl0KT1cInN1Ym1pdCgpXCI+XG4gICAgPGRpdiBjbGFzcz1cImZvcm0tZ3JvdXBcIj5cbiAgICAgIDxsYWJlbCBbYXR0ci5mb3JdPVwiZm9ybUlkICsgJ2VtYWlsJ1wiPkVtYWlsIEFkZHJlc3M8L2xhYmVsPlxuXG4gICAgICA8aW5wdXRcbiAgICAgICAgcmVhZG9ubHlcbiAgICAgICAgI2VtYWlsSW5wdXRcbiAgICAgICAgW2F0dHIuaWRdPVwiZm9ybUlkICsgJ2VtYWlsJ1wiXG4gICAgICAgIFthdHRyLmFyaWEtZGVzY3JpYmVkYnldPVwiZm9ybUlkICsgJ2VtYWlsJ1wiXG4gICAgICAgIHR5cGU9XCJlbWFpbFwiXG4gICAgICAgIGF1dG9jb21wbGV0ZT1cImVtYWlsXCJcbiAgICAgICAgcGxhY2Vob2xkZXI9XCJFbWFpbCBBZGRyZXNzXCJcbiAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiZW1haWxcIlxuICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiPlxuICAgICAgPHNtYWxsIGNsYXNzPVwidGV4dC1tdXRlZCBmb3JtLXRleHRcIiBbYXR0ci5pZF09XCJmb3JtSWQgKyAnZW1haWwnXCIgPlxuICAgICAgICBZb3UgYXJlIHJlc2V0dGluZyB0aGUgcGFzc3dvcmQgZm9yIHt7ZW1haWxGYy52YWx1ZX19LlxuICAgICAgPC9zbWFsbD5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGp1c3RpZnktY29udGVudC1iZXR3ZWVuIGFsaWduLWl0ZW1zLWVuZFwiPlxuICAgICAgICA8bGFiZWwgW2F0dHIuZm9yXT1cImZvcm1JZCArICdwYXNzd29yZCdcIj5QYXNzd29yZDwvbGFiZWw+XG4gICAgICAgIDxzbWFsbD5cbiAgICAgICAgICA8YSAoY2xpY2spPVwiJGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IHBhc3N3b3JkSW5wdXQudHlwZSA9ICdwYXNzd29yZCcgPT09IHBhc3N3b3JkSW5wdXQudHlwZSAgPyAndGV4dCcgOiAncGFzc3dvcmQnXCJcbiAgICAgICAgICAgIGhyZWY9XCIjXCIgdGFiaW5kZXg9XCItMVwiIGNsYXNzPVwiZC1pbmxpbmUtYmxvY2tcIj5cbiAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwiJ3Bhc3N3b3JkJyA9PT0gcGFzc3dvcmRJbnB1dC50eXBlXCI+U2hvdzwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwiJ3RleHQnID09PSBwYXNzd29yZElucHV0LnR5cGVcIj5IaWRlPC9zcGFuPlxuICAgICAgICAgIDwvYT5cbiAgICAgICAgPC9zbWFsbD5cbiAgICAgIDwvZGl2PlxuICAgICAgPGlucHV0XG4gICAgICAgICNwYXNzd29yZElucHV0XG4gICAgICAgIFthdHRyLmlkXT1cImZvcm1JZCArICdwYXNzd29yZCdcIlxuICAgICAgICBbYXR0ci5hcmlhLWRlc2NyaWJlZGJ5XT1cImZvcm1JZCArICdwYXNzd29yZC1oZWxwJ1wiXG4gICAgICAgIHR5cGU9XCJwYXNzd29yZFwiXG4gICAgICAgIGZvcm1Db250cm9sTmFtZT1cInBhc3N3b3JkXCJcbiAgICAgICAgcGxhY2Vob2xkZXI9XCJQYXNzd29yZFwiXG4gICAgICAgIGF1dG9jb21wbGV0ZT1cInBhc3N3b3JkXCJcbiAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICBbY2xhc3MuaXMtaW52YWxpZF09XCJwYXNzd29yZEZjLnRvdWNoZWQgJiYgcGFzc3dvcmRGYy5pbnZhbGlkXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiaW52YWxpZC1mZWVkYmFja1wiICpuZ0lmPVwicGFzc3dvcmRGYy50b3VjaGVkICYmIHBhc3N3b3JkRmMuaGFzRXJyb3IoJ3JlcXVpcmVkJylcIj5cbiAgICAgICAgUmVxdWlyZWQuXG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJpbnZhbGlkLWZlZWRiYWNrXCIgKm5nSWY9XCJwYXNzd29yZEZjLnRvdWNoZWQgJiYgcGFzc3dvcmRGYy5oYXNFcnJvcignYXV0aC93ZWFrLXBhc3N3b3JkJylcIj5cbiAgICAgICAgVGhhdCBwYXNzd29yZCBpcyB0b28gd2Vhay5cbiAgICAgIDwvZGl2PlxuICAgICAgPHNtYWxsIFthdHRyLmlkXT1cImZvcm1JZCArICdwYXNzd29yZC1oZWxwJ1wiIGNsYXNzPVwiZm9ybS10ZXh0IHRleHQtbXV0ZWRcIj5cbiAgICAgICAgUGxlYXNlIGNob29zZSBhIHN0cm9uZyBwYXNzd29yZC5cbiAgICAgIDwvc21hbGw+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImZvcm0tZ3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLWNoZWNrXCI+XG4gICAgICAgIDxpbnB1dFxuICAgICAgICAgIGNsYXNzPVwiZm9ybS1jaGVjay1pbnB1dFwiXG4gICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICBbdmFsdWVdPVwidHJ1ZVwiXG4gICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwicmVtZW1iZXJcIlxuICAgICAgICAgIFthdHRyLmlkXT1cImZvcm1JZCArICdyZW1lbWJlcidcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1jaGVjay1sYWJlbFwiIFthdHRyLmZvcl09XCJmb3JtSWQgKyAncmVtZW1iZXInXCI+XG4gICAgICAgICAgUmVtZW1iZXIgbWUgb24gdGhpcyBkZXZpY2UuXG4gICAgICAgIDwvbGFiZWw+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwiZm9ybS1ncm91cFwiPlxuICAgICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCJcbiAgICAgICAgY2xhc3M9XCJidG4gYnRuLXN1Y2Nlc3MgYnRuLWJsb2NrXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cImZnLmludmFsaWQgfHwgc3VibWl0dGluZ1wiPlxuICAgICAgICA8aSBjbGFzcz1cImZhcyBmYS1zYXZlIGZhLWZ3XCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9pPlxuICAgICAgICBTYXZlIFBhc3N3b3JkIGFuZCBTaWduIEluXG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9mb3JtPlxuPC9kaXY+XG5gLFxuICBzdHlsZXM6IFtgYF0sXG4gIGFuaW1hdGlvbnM6IFtzY3JlZW5BbmltYXRpb25dXG59KVxuZXhwb3J0IGNsYXNzIE9vYlJlc2V0UGFzc3dvcmRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuXG4gIEBJbnB1dCgpIG9vYkNvZGU6IHN0cmluZztcbiAgQE91dHB1dCgpIHN1Y2Nlc3M6IEV2ZW50RW1pdHRlcjxJTmd4RmlyZWJhc2VBdXRoT29iU3VjY2Vzcz4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgc2NyZWVuOiAnd2FpdCcgfCAnZm9ybScgfCAnZXJyb3InIHwgJ3N1Y2Nlc3MnID0gJ3dhaXQnO1xuICBpbmZvOiBhdXRoLkFjdGlvbkNvZGVJbmZvO1xuICBzdWJtaXR0aW5nID0gZmFsc2U7XG4gIGZvcm1JZCA9ICduZ3gtZmlyZWJhc2UtYXV0aC1vb2ItcmVzZXQtcGFzc3dvcmQtJztcbiAgZmc6IEZvcm1Hcm91cDtcbiAgZW1haWxGYzogRm9ybUNvbnRyb2w7XG4gIHBhc3N3b3JkRmM6IEZvcm1Db250cm9sO1xuICByZW1lbWJlckZjOiBGb3JtQ29udHJvbDtcbiAgdW5oYW5kbGVkRXJyb3I6IGF1dGguRXJyb3IgPSBudWxsO1xuICBjcmVkOiBhdXRoLlVzZXJDcmVkZW50aWFsID0gbnVsbDtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBfYWZBdXRoOiBBbmd1bGFyRmlyZUF1dGgsXG4gICAgICBwcml2YXRlIF9hdXRoU2VydmljZTogTmd4RmlyZWJhc2VBdXRoU2VydmljZSxcbiAgKSB7IH1cblxuICBnZXQgYXV0aCgpOiBhdXRoLkF1dGgge1xuICAgIHJldHVybiB0aGlzLl9hZkF1dGguYXV0aDtcbiAgfVxuICBnZXQgYXV0aFNlcnZpY2UoKTogTmd4RmlyZWJhc2VBdXRoU2VydmljZSB7XG4gICAgcmV0dXJuIHRoaXMuX2F1dGhTZXJ2aWNlO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgY29uc3QgcmVtZW1iZXJlZCA9IHRoaXMuYXV0aFNlcnZpY2UuZ2V0UmVtZW1iZXJlZCgpO1xuICAgIHRoaXMuZW1haWxGYyA9IG5ldyBGb3JtQ29udHJvbCgnJyk7XG4gICAgdGhpcy5wYXNzd29yZEZjID0gbmV3IEZvcm1Db250cm9sKCcnLCB7dmFsaWRhdG9yczogW1ZhbGlkYXRvcnMucmVxdWlyZWRdfSk7XG4gICAgdGhpcy5yZW1lbWJlckZjID0gbmV3IEZvcm1Db250cm9sKHJlbWVtYmVyZWQucmVtZW1iZXIpO1xuICAgIHRoaXMuZmcgPSBuZXcgRm9ybUdyb3VwKHtlbWFpbDogdGhpcy5lbWFpbEZjLCBwYXNzd29yZDogdGhpcy5wYXNzd29yZEZjLCByZW1lbWJlcjogdGhpcy5yZW1lbWJlckZjfSk7XG4gICAgdGhpcy5hdXRoLmNoZWNrQWN0aW9uQ29kZSh0aGlzLm9vYkNvZGUpXG4gICAgICAudGhlbigocmVzdWx0OiBhdXRoLkFjdGlvbkNvZGVJbmZvKSA9PiB7XG4gICAgICAgIHRoaXMuaW5mbyA9IHJlc3VsdDtcbiAgICAgICAgdGhpcy5lbWFpbEZjLnNldFZhbHVlKHJlc3VsdC5kYXRhLmVtYWlsKTtcbiAgICAgICAgdGhpcy5zY3JlZW4gPSAnZm9ybSc7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlcnJvcjogYXV0aC5FcnJvcikgPT4ge1xuICAgICAgICB0aGlzLnVuaGFuZGxlZEVycm9yID0gZXJyb3I7XG4gICAgICAgIHRoaXMuc2NyZWVuID0gJ2Vycm9yJztcbiAgICAgIH0pO1xuICB9XG5cbiAgc3VibWl0KCkge1xuICAgIHRoaXMuc3VibWl0dGluZyA9IHRydWU7XG4gICAgdGhpcy5hdXRoLmNvbmZpcm1QYXNzd29yZFJlc2V0KHRoaXMub29iQ29kZSwgdGhpcy5wYXNzd29yZEZjLnZhbHVlKVxuICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5hdXRoLnNpZ25JbldpdGhFbWFpbEFuZFBhc3N3b3JkKHRoaXMuaW5mby5kYXRhLmVtYWlsLCB0aGlzLnBhc3N3b3JkRmMudmFsdWUpO1xuICAgICAgfSlcbiAgICAgIC50aGVuKChjcmVkOiBhdXRoLlVzZXJDcmVkZW50aWFsKSA9PiB7XG4gICAgICAgIHRoaXMuY3JlZCA9IGNyZWQ7XG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhTZXJ2aWNlLnNldFJlbWVtYmVyZWQodGhpcy5yZW1lbWJlckZjLnZhbHVlID09PSB0cnVlLCB0aGlzLmluZm8uZGF0YS5lbWFpbCk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICB0aGlzLnNjcmVlbiA9ICdzdWNjZXNzJztcbiAgICAgICAgdGhpcy5zdWNjZXNzLmVtaXQoe1xuICAgICAgICAgIG1vZGU6ICdyZXNldFBhc3N3b3JkJyxcbiAgICAgICAgICBpbmZvOiB0aGlzLmluZm8sXG4gICAgICAgICAgY3JlZDogdGhpcy5jcmVkLFxuICAgICAgICAgIHVzZXI6IHRoaXMuY3JlZC51c2VyXG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaCgoZXJyb3I6IGF1dGguRXJyb3IpID0+IHtcbiAgICAgICAgdGhpcy5zdWJtaXR0aW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMucGFzc3dvcmRGYy5tYXJrQXNEaXJ0eSgpO1xuICAgICAgICB0aGlzLnBhc3N3b3JkRmMubWFya0FzVG91Y2hlZCgpO1xuICAgICAgICBzd2l0Y2ggKGVycm9yLmNvZGUpIHtcbiAgICAgICAgICBjYXNlICdhdXRoL3dlYWstcGFzc3dvcmQnOlxuICAgICAgICAgICAgTmd4RmlyZWJhc2VBdXRoRm9ybUhlbHBlci5zZXRFcnJvclVudGlsQ2hhbmdlZCh0aGlzLnBhc3N3b3JkRmMsIGVycm9yLmNvZGUpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHRoaXMudW5oYW5kbGVkRXJyb3IgPSBlcnJvcjtcbiAgICAgICAgICAgIHRoaXMuc2NyZWVuID0gJ2Vycm9yJztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgfVxuXG59XG4iXX0=