UNPKG

@nowzoo/ngx-firebase-auth

Version:

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

356 lines (351 loc) 30.7 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ import { Component, Input, Output, EventEmitter, NgZone, ViewChild, ElementRef } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { AngularFireAuth } from 'angularfire2/auth'; import { debounceTime } from 'rxjs/operators'; import { getOAuthProviderIcon, getOAuthProviderName } from '../../shared'; import { NgxFirebaseAuthFormHelper } from '../../form-helper'; import { NgxFirebaseAuthService } from '../../ngx-firebase-auth.service'; import { fadeInOutAnimation, screenAnimation } from '../../shared'; export class SignInMethodsFormComponent { /** * @param {?} _afAuth * @param {?} _authService * @param {?} _ngZone */ constructor(_afAuth, _authService, _ngZone) { this._afAuth = _afAuth; this._authService = _authService; this._ngZone = _ngZone; this.oAuthProviderIds = []; this.emailChange = new EventEmitter(); this.rememberChange = new EventEmitter(); this.success = new EventEmitter(); this.error = new EventEmitter(); this.formId = 'ngx-firebase-auth-sign-in-methods-form-'; this.submitting = false; this.getOAuthProviderIcon = getOAuthProviderIcon; this.getOAuthProviderName = getOAuthProviderName; this.methodsForEmail = { status: 'unfetched', methods: [], email: null }; } /** * @return {?} */ get auth() { return this._afAuth.auth; } /** * @return {?} */ get authService() { return this._authService; } /** * @return {?} */ get methods() { return this.methodsForEmail.methods; } /** * @return {?} */ get fetchStatus() { return this.methodsForEmail.status; } /** * @return {?} */ get methodsFetched() { return this.methodsForEmail.status === 'fetched'; } /** * @return {?} */ get accountIsNew() { return this.methodsFetched && this.methods.length === 0; } /** * @return {?} */ get accountExists() { return this.methodsFetched && this.methods.length > 0; } /** * @return {?} */ get accountHasPassword() { return this.accountExists && this.methods.indexOf('password') !== -1; } /** * @return {?} */ get accountOAuthMethods() { if (!this.accountExists) { return []; } return this.methods.filter(id => id !== 'password'); } /** * @return {?} */ ngOnInit() { this.emailFc = new FormControl(this.email, { validators: [Validators.required, Validators.email] }); this.rememberFc = new FormControl(this.remember); this.rememberFc.valueChanges.subscribe(() => this.rememberChange.emit(this.rememberFc.value)); this.fg = new FormGroup({ email: this.emailFc, remember: this.rememberFc }); this.emailFc.valueChanges.subscribe(() => this.emailChange.emit(this.emailFc.value.trim())); this.emailFc.valueChanges.pipe(debounceTime(500)).subscribe(() => this.fetch()); this.fetch(); } /** * @return {?} */ ngAfterViewInit() { this.emailInput.nativeElement.focus(); } /** * @return {?} */ fetch() { /** @type {?} */ const email = this.emailFc.value.trim(); if (email === this.methodsForEmail.email) { return; } if ('fetching' === this.methodsForEmail.status) { return; } this.methodsForEmail = { status: 'fetching', methods: [], email: email }; if (this.emailFc.invalid) { this.methodsForEmail = { status: 'unfetched', methods: [], email: email }; return; } this.auth.fetchSignInMethodsForEmail(email) .then(results => { this.methodsForEmail = { status: 'fetched', methods: results, email: email }; }) .catch((error) => { this.emailFc.markAsDirty(); this.emailFc.markAsTouched(); switch (error.code) { case 'auth/invalid-email': NgxFirebaseAuthFormHelper.setErrorUntilChanged(this.emailFc, error.code); break; } this.methodsForEmail = { email: this.email, status: 'unfetched', methods: [] }; }); } } SignInMethodsFormComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-firebase-auth-sign-in-methods-form', template: `<form [formGroup]="fg"> <div class="form-group"> <label [attr.for]="formId + 'email'">Email Address</label> <input #emailInput [attr.id]="formId + 'email'" [attr.aria-describedby]="formId + 'email'" type="email" autocomplete="email" placeholder="Email Address" formControlName="email" (blur)="fetch()" (keyup.enter)="emailInput.blur()" class="form-control" [class.is-invalid]="emailFc.touched && emailFc.invalid"> <div class="invalid-feedback" [@fadeInOut]="'in'" *ngIf="emailFc.touched && emailFc.hasError('required')"> Required. </div> <div class="invalid-feedback" [@fadeInOut]="'in'" *ngIf="emailFc.touched && emailFc.hasError('email')"> Invalid email. </div> <div class="invalid-feedback" [@fadeInOut]="'in'" *ngIf="emailFc.touched && emailFc.hasError('auth/invalid-email')"> Invalid email. </div> <small class="text-muted form-text" [attr.id]="formId + 'email'" [ngSwitch]="fetchStatus"> <span *ngSwitchCase="'unfetched'" [@fadeInOut]="'in'"> To get started, enter your email address. If you don’t yet have an account we’ll create one for you. </span> <span *ngSwitchCase="'fetching'" [@fadeInOut]="'in'"> <i class="fas fa-spin fa-spinner fa-fw" aria-hidden="true"></i> Looking up account... </span> <span *ngSwitchCase="'fetched'" [@fadeInOut]="'in'"> <i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> <span *ngIf="accountExists">Account found.</span> <span *ngIf="accountIsNew">We'll create an account.</span> </span> </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> </form> <div *ngIf="methodsFetched && accountExists" [@screen]="'in'"> <small class="text-muted mb-1 form-text"> <span *ngIf="accountHasPassword"> <span *ngIf="accountOAuthMethods.length === 0"> Please sign in with your password... </span> <span *ngIf="accountOAuthMethods.length === 1"> Please sign in with your password or your linked {{getOAuthProviderName(accountOAuthMethods[0])}} account... </span> <span *ngIf="accountOAuthMethods.length > 1"> Please sign in with your password or one of your linked accounts... </span> </span> <span *ngIf="!accountHasPassword"> <span *ngIf="accountOAuthMethods.length === 1"> Please sign in with your linked {{getOAuthProviderName(accountOAuthMethods[0])}} account... </span> <span *ngIf="accountOAuthMethods.length > 1"> Please sign in with one of your linked accounts... </span> </span> </small> <div class="list-group"> <a *ngIf="accountHasPassword" routerLink="." [queryParams]="{action: 'signInPassword'}" class="list-group-item list-group-item-action"> <i class="fas fa-lock fa-fw" aria-hidden="true"></i> <span class="ml-2"> Sign In with Your Password </span> </a> <a *ngFor="let id of accountOAuthMethods" routerLink="." [queryParams]="{action: 'signInOAuth', providerId: id}" class="list-group-item list-group-item-action"> <i [attr.class]="getOAuthProviderIcon(id)" aria-hidden="true"></i> <span class="ml-2"> Sign In with {{getOAuthProviderName(id)}} </span> </a> </div> </div> <div *ngIf="methodsFetched && accountIsNew" [@screen]="'in'"> <small class="text-muted mb-1 form-text"> <span *ngIf="oAuthProviderIds.length === 0"> Please create an account... </span> <span *ngIf="oAuthProviderIds.length === 1"> Please sign up with your {{getOAuthProviderName(oAuthProviderIds[0])}} account, or create a separate account with a password.... </span> <span *ngIf="oAuthProviderIds.length >1"> Please sign up with one of the services listed below, or create a separate account with a password.... </span> </small> <div class="list-group"> <a *ngFor="let id of oAuthProviderIds" routerLink="." [queryParams]="{action: 'signInOAuth', providerId: id}" class="list-group-item list-group-item-action"> <i [attr.class]="getOAuthProviderIcon(id)" aria-hidden="true"></i> <span class="ml-2"> Sign Up with {{getOAuthProviderName(id)}} </span> </a> <a routerLink="." [queryParams]="{action: 'signUpPassword'}" class="list-group-item list-group-item-action"> <i class="fas fa-lock fa-fw" aria-hidden="true"></i> <span class="ml-2"> Create <span *ngIf="oAuthProviderIds.length > 0"> a Separate </span> Account </span> </a> </div> </div> `, styles: [``], animations: [fadeInOutAnimation, screenAnimation] },] }, ]; /** @nocollapse */ SignInMethodsFormComponent.ctorParameters = () => [ { type: AngularFireAuth }, { type: NgxFirebaseAuthService }, { type: NgZone } ]; SignInMethodsFormComponent.propDecorators = { emailInput: [{ type: ViewChild, args: ['emailInput',] }], email: [{ type: Input }], remember: [{ type: Input }], oAuthProviderIds: [{ type: Input }], emailChange: [{ type: Output }], rememberChange: [{ type: Output }], success: [{ type: Output }], error: [{ type: Output }] }; if (false) { /** @type {?} */ SignInMethodsFormComponent.prototype.emailInput; /** @type {?} */ SignInMethodsFormComponent.prototype.email; /** @type {?} */ SignInMethodsFormComponent.prototype.remember; /** @type {?} */ SignInMethodsFormComponent.prototype.oAuthProviderIds; /** @type {?} */ SignInMethodsFormComponent.prototype.emailChange; /** @type {?} */ SignInMethodsFormComponent.prototype.rememberChange; /** @type {?} */ SignInMethodsFormComponent.prototype.success; /** @type {?} */ SignInMethodsFormComponent.prototype.error; /** @type {?} */ SignInMethodsFormComponent.prototype.formId; /** @type {?} */ SignInMethodsFormComponent.prototype.submitting; /** @type {?} */ SignInMethodsFormComponent.prototype.fg; /** @type {?} */ SignInMethodsFormComponent.prototype.emailFc; /** @type {?} */ SignInMethodsFormComponent.prototype.rememberFc; /** @type {?} */ SignInMethodsFormComponent.prototype.getOAuthProviderIcon; /** @type {?} */ SignInMethodsFormComponent.prototype.getOAuthProviderName; /** @type {?} */ SignInMethodsFormComponent.prototype.methodsForEmail; /** @type {?} */ SignInMethodsFormComponent.prototype._afAuth; /** @type {?} */ SignInMethodsFormComponent.prototype._authService; /** @type {?} */ SignInMethodsFormComponent.prototype._ngZone; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbi1pbi1tZXRob2RzLWZvcm0uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vQG5vd3pvby9uZ3gtZmlyZWJhc2UtYXV0aC8iLCJzb3VyY2VzIjpbImxpYi9zaWduLWluL3NpZ24taW4tbWV0aG9kcy1mb3JtL3NpZ24taW4tbWV0aG9kcy1mb3JtLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBeUIsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN0gsT0FBTyxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDcEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXBELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQWdDLG9CQUFvQixFQUFFLG9CQUFvQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3hHLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzlELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxlQUFlLEVBQUUsTUFBTSxjQUFjLENBQUM7QUE2Sm5FLE1BQU07Ozs7OztJQXNCSixZQUNVLFNBQ0EsY0FDQTtRQUZBLFlBQU8sR0FBUCxPQUFPO1FBQ1AsaUJBQVksR0FBWixZQUFZO1FBQ1osWUFBTyxHQUFQLE9BQU87Z0NBbkJxQixFQUFFOzJCQUNNLElBQUksWUFBWSxFQUFFOzhCQUNkLElBQUksWUFBWSxFQUFFO3VCQUNiLElBQUksWUFBWSxFQUFFO3FCQUM3QixJQUFJLFlBQVksRUFBRTtzQkFHckQseUNBQXlDOzBCQUNyQyxLQUFLO29DQUlLLG9CQUFvQjtvQ0FD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b0JBQW9CO29CQUN2Qix5QkFBeUIsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDekUsS0FBSyxDQUFDO2FBQ1Q7WUFDRCxJQUFJLENBQUMsZUFBZSxHQUFHLEVBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFDLENBQUM7U0FDOUUsQ0FBQyxDQUFDO0tBQ047OztZQS9RRixTQUFTLFNBQUM7Z0JBQ1QsUUFBUSxFQUFFLHdDQUF3QztnQkFDbEQsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQXFKWDtnQkFDQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQ1osVUFBVSxFQUFFLENBQUMsa0JBQWtCLEVBQUUsZUFBZSxDQUFDO2FBQ2xEOzs7O1lBbEtRLGVBQWU7WUFLZixzQkFBc0I7WUFQeUMsTUFBTTs7O3lCQXdLM0UsU0FBUyxTQUFDLFlBQVk7b0JBQ3RCLEtBQUs7dUJBQ0wsS0FBSzsrQkFDTCxLQUFLOzBCQUNMLE1BQU07NkJBQ04sTUFBTTtzQkFDTixNQUFNO29CQUNOLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBOZ1pvbmUsIFZpZXdDaGlsZCwgRWxlbWVudFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IEFuZ3VsYXJGaXJlQXV0aCB9IGZyb20gJ2FuZ3VsYXJmaXJlMi9hdXRoJztcbmltcG9ydCB7IGF1dGggfSBmcm9tICdmaXJlYmFzZS9hcHAnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgSVNpZ25Jbk1ldGhvZHNGb3JFbWFpbFJlc3VsdCwgZ2V0T0F1dGhQcm92aWRlckljb24sIGdldE9BdXRoUHJvdmlkZXJOYW1lIH0gZnJvbSAnLi4vLi4vc2hhcmVkJztcbmltcG9ydCB7IE5neEZpcmViYXNlQXV0aEZvcm1IZWxwZXIgfSBmcm9tICcuLi8uLi9mb3JtLWhlbHBlcic7XG5pbXBvcnQgeyBOZ3hGaXJlYmFzZUF1dGhTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vbmd4LWZpcmViYXNlLWF1dGguc2VydmljZSc7XG5pbXBvcnQgeyBmYWRlSW5PdXRBbmltYXRpb24sIHNjcmVlbkFuaW1hdGlvbiB9IGZyb20gJy4uLy4uL3NoYXJlZCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1maXJlYmFzZS1hdXRoLXNpZ24taW4tbWV0aG9kcy1mb3JtJyxcbiAgdGVtcGxhdGU6IGA8Zm9ybSBbZm9ybUdyb3VwXT1cImZnXCI+XG4gIDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwXCI+XG4gICAgPGxhYmVsIFthdHRyLmZvcl09XCJmb3JtSWQgKyAnZW1haWwnXCI+RW1haWwgQWRkcmVzczwvbGFiZWw+XG4gICAgPGlucHV0XG4gICAgICAjZW1haWxJbnB1dFxuICAgICAgW2F0dHIuaWRdPVwiZm9ybUlkICsgJ2VtYWlsJ1wiXG4gICAgICBbYXR0ci5hcmlhLWRlc2NyaWJlZGJ5XT1cImZvcm1JZCArICdlbWFpbCdcIlxuICAgICAgdHlwZT1cImVtYWlsXCJcbiAgICAgIGF1dG9jb21wbGV0ZT1cImVtYWlsXCJcbiAgICAgIHBsYWNlaG9sZGVyPVwiRW1haWwgQWRkcmVzc1wiXG4gICAgICBmb3JtQ29udHJvbE5hbWU9XCJlbWFpbFwiXG4gICAgICAoYmx1cik9XCJmZXRjaCgpXCJcbiAgICAgIChrZXl1cC5lbnRlcik9XCJlbWFpbElucHV0LmJsdXIoKVwiXG4gICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICBbY2xhc3MuaXMtaW52YWxpZF09XCJlbWFpbEZjLnRvdWNoZWQgJiYgZW1haWxGYy5pbnZhbGlkXCI+XG4gICAgPGRpdiBjbGFzcz1cImludmFsaWQtZmVlZGJhY2tcIiBbQGZhZGVJbk91dF09XCInaW4nXCJcbiAgICAgICpuZ0lmPVwiZW1haWxGYy50b3VjaGVkICYmIGVtYWlsRmMuaGFzRXJyb3IoJ3JlcXVpcmVkJylcIj5cbiAgICAgIFJlcXVpcmVkLlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJpbnZhbGlkLWZlZWRiYWNrXCIgW0BmYWRlSW5PdXRdPVwiJ2luJ1wiXG4gICAgICAqbmdJZj1cImVtYWlsRmMudG91Y2hlZCAmJiBlbWFpbEZjLmhhc0Vycm9yKCdlbWFpbCcpXCI+XG4gICAgICBJbnZhbGlkIGVtYWlsLlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJpbnZhbGlkLWZlZWRiYWNrXCIgW0BmYWRlSW5PdXRdPVwiJ2luJ1wiXG4gICAgICAqbmdJZj1cImVtYWlsRmMudG91Y2hlZCAmJiBlbWFpbEZjLmhhc0Vycm9yKCdhdXRoL2ludmFsaWQtZW1haWwnKVwiPlxuICAgICAgSW52YWxpZCBlbWFpbC5cbiAgICA8L2Rpdj5cbiAgICA8c21hbGwgY2xhc3M9XCJ0ZXh0LW11dGVkIGZvcm0tdGV4dFwiIFthdHRyLmlkXT1cImZvcm1JZCArICdlbWFpbCdcIiBbbmdTd2l0Y2hdPVwiZmV0Y2hTdGF0dXNcIj5cbiAgICAgIDxzcGFuICpuZ1N3aXRjaENhc2U9XCIndW5mZXRjaGVkJ1wiIFtAZmFkZUluT3V0XT1cIidpbidcIj5cbiAgICAgICAgVG8gZ2V0IHN0YXJ0ZWQsIGVudGVyIHlvdXIgZW1haWwgYWRkcmVzcy5cbiAgICAgICAgSWYgeW91IGRvbuKAmXQgeWV0IGhhdmUgYW4gYWNjb3VudCB3ZeKAmWxsIGNyZWF0ZSBvbmUgZm9yIHlvdS5cbiAgICAgIDwvc3Bhbj5cbiAgICAgIDxzcGFuICpuZ1N3aXRjaENhc2U9XCInZmV0Y2hpbmcnXCIgW0BmYWRlSW5PdXRdPVwiJ2luJ1wiPlxuICAgICAgICA8aSBjbGFzcz1cImZhcyBmYS1zcGluIGZhLXNwaW5uZXIgZmEtZndcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L2k+XG4gICAgICAgIExvb2tpbmcgdXAgYWNjb3VudC4uLlxuICAgICAgPC9zcGFuPlxuICAgICAgPHNwYW4gKm5nU3dpdGNoQ2FzZT1cIidmZXRjaGVkJ1wiIFtAZmFkZUluT3V0XT1cIidpbidcIj5cbiAgICAgICAgPGkgY2xhc3M9XCJmYXMgZmEtY2hlY2sgZmEtZncgdGV4dC1zdWNjZXNzXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9pPlxuICAgICAgICA8c3BhbiAqbmdJZj1cImFjY291bnRFeGlzdHNcIj5BY2NvdW50IGZvdW5kLjwvc3Bhbj5cbiAgICAgICAgPHNwYW4gKm5nSWY9XCJhY2NvdW50SXNOZXdcIj5XZSdsbCBjcmVhdGUgYW4gYWNjb3VudC48L3NwYW4+XG4gICAgICA8L3NwYW4+XG4gICAgPC9zbWFsbD5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwXCI+XG4gICAgPGRpdiBjbGFzcz1cImZvcm0tY2hlY2tcIj5cbiAgICAgIDxpbnB1dFxuICAgICAgICBjbGFzcz1cImZvcm0tY2hlY2staW5wdXRcIlxuICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICBbdmFsdWVdPVwidHJ1ZVwiXG4gICAgICAgIGZvcm1Db250cm9sTmFtZT1cInJlbWVtYmVyXCJcbiAgICAgICAgW2F0dHIuaWRdPVwiZm9ybUlkICsgJ3JlbWVtYmVyJ1wiPlxuICAgICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1jaGVjay1sYWJlbFwiIFthdHRyLmZvcl09XCJmb3JtSWQgKyAncmVtZW1iZXInXCI+XG4gICAgICAgIFJlbWVtYmVyIG1lIG9uIHRoaXMgZGV2aWNlLlxuICAgICAgPC9sYWJlbD5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Zvcm0+XG48ZGl2ICpuZ0lmPVwibWV0aG9kc0ZldGNoZWQgJiYgYWNjb3VudEV4aXN0c1wiIFtAc2NyZWVuXT1cIidpbidcIj5cbiAgPHNtYWxsIGNsYXNzPVwidGV4dC1tdXRlZCBtYi0xIGZvcm0tdGV4dFwiPlxuICAgIDxzcGFuICpuZ0lmPVwiYWNjb3VudEhhc1Bhc3N3b3JkXCI+XG4gICAgICA8c3BhbiAqbmdJZj1cImFjY291bnRPQXV0aE1ldGhvZHMubGVuZ3RoID09PSAwXCI+XG4gICAgICAgIFBsZWFzZSBzaWduIGluIHdpdGggeW91ciBwYXNzd29yZC4uLlxuICAgICAgPC9zcGFuPlxuICAgICAgPHNwYW4gKm5nSWY9XCJhY2NvdW50T0F1dGhNZXRob2RzLmxlbmd0aCA9PT0gMVwiPlxuICAgICAgICBQbGVhc2Ugc2lnbiBpbiB3aXRoIHlvdXIgcGFzc3dvcmQgb3IgeW91clxuICAgICAgICBsaW5rZWQge3tnZXRPQXV0aFByb3ZpZGVyTmFtZShhY2NvdW50T0F1dGhNZXRob2RzWzBdKX19IGFjY291bnQuLi5cbiAgICAgIDwvc3Bhbj5cbiAgICAgIDxzcGFuICpuZ0lmPVwiYWNjb3VudE9BdXRoTWV0aG9kcy5sZW5ndGggPiAxXCI+XG4gICAgICAgIFBsZWFzZSBzaWduIGluIHdpdGggeW91ciBwYXNzd29yZCBvciBvbmUgb2YgeW91ciBsaW5rZWQgYWNjb3VudHMuLi5cbiAgICAgIDwvc3Bhbj5cbiAgICA8L3NwYW4+XG4gICAgPHNwYW4gKm5nSWY9XCIhYWNjb3VudEhhc1Bhc3N3b3JkXCI+XG4gICAgICA8c3BhbiAqbmdJZj1cImFjY291bnRPQXV0aE1ldGhvZHMubGVuZ3RoID09PSAxXCI+XG4gICAgICAgIFBsZWFzZSBzaWduIGluIHdpdGggeW91clxuICAgICAgICBsaW5rZWQge3tnZXRPQXV0aFByb3ZpZGVyTmFtZShhY2NvdW50T0F1dGhNZXRob2RzWzBdKX19IGFjY291bnQuLi5cbiAgICAgIDwvc3Bhbj5cbiAgICAgIDxzcGFuICpuZ0lmPVwiYWNjb3VudE9BdXRoTWV0aG9kcy5sZW5ndGggPiAxXCI+XG4gICAgICAgIFBsZWFzZSBzaWduIGluIHdpdGggb25lIG9mIHlvdXIgbGlua2VkIGFjY291bnRzLi4uXG4gICAgICA8L3NwYW4+XG4gICAgPC9zcGFuPlxuXG4gIDwvc21hbGw+XG5cbiAgPGRpdiBjbGFzcz1cImxpc3QtZ3JvdXBcIj5cbiAgICA8YVxuICAgICAgKm5nSWY9XCJhY2NvdW50SGFzUGFzc3dvcmRcIlxuICAgICAgcm91dGVyTGluaz1cIi5cIlxuICAgICAgW3F1ZXJ5UGFyYW1zXT1cInthY3Rpb246ICdzaWduSW5QYXNzd29yZCd9XCJcbiAgICAgIGNsYXNzPVwibGlzdC1ncm91cC1pdGVtIGxpc3QtZ3JvdXAtaXRlbS1hY3Rpb25cIj5cbiAgICAgIDxpIGNsYXNzPVwiZmFzIGZhLWxvY2sgZmEtZndcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L2k+XG4gICAgICA8c3BhbiBjbGFzcz1cIm1sLTJcIj5cbiAgICAgICAgU2lnbiBJbiB3aXRoIFlvdXIgUGFzc3dvcmRcbiAgICAgIDwvc3Bhbj5cbiAgICA8L2E+XG4gICAgPGFcbiAgICAgICpuZ0Zvcj1cImxldCBpZCBvZiBhY2NvdW50T0F1dGhNZXRob2RzXCJcbiAgICAgIHJvdXRlckxpbms9XCIuXCJcbiAgICAgIFtxdWVyeVBhcmFtc109XCJ7YWN0aW9uOiAnc2lnbkluT0F1dGgnLCBwcm92aWRlcklkOiBpZH1cIlxuICAgICAgY2xhc3M9XCJsaXN0LWdyb3VwLWl0ZW0gbGlzdC1ncm91cC1pdGVtLWFjdGlvblwiPlxuICAgICAgPGkgW2F0dHIuY2xhc3NdPVwiZ2V0T0F1dGhQcm92aWRlckljb24oaWQpXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9pPlxuICAgICAgPHNwYW4gY2xhc3M9XCJtbC0yXCI+XG4gICAgICAgIFNpZ24gSW4gd2l0aCB7e2dldE9BdXRoUHJvdmlkZXJOYW1lKGlkKX19XG4gICAgICA8L3NwYW4+XG4gICAgPC9hPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48ZGl2ICpuZ0lmPVwibWV0aG9kc0ZldGNoZWQgJiYgYWNjb3VudElzTmV3XCIgW0BzY3JlZW5dPVwiJ2luJ1wiPlxuICA8c21hbGwgY2xhc3M9XCJ0ZXh0LW11dGVkIG1iLTEgZm9ybS10ZXh0XCI+XG4gICAgPHNwYW4gKm5nSWY9XCJvQXV0aFByb3ZpZGVySWRzLmxlbmd0aCA9PT0gMFwiPlxuICAgICAgUGxlYXNlIGNyZWF0ZSBhbiBhY2NvdW50Li4uXG4gICAgPC9zcGFuPlxuICAgIDxzcGFuICpuZ0lmPVwib0F1dGhQcm92aWRlcklkcy5sZW5ndGggPT09IDFcIj5cbiAgICAgIFBsZWFzZSBzaWduIHVwIHdpdGggeW91clxuICAgICAge3tnZXRPQXV0aFByb3ZpZGVyTmFtZShvQXV0aFByb3ZpZGVySWRzWzBdKX19IGFjY291bnQsXG4gICAgICBvciBjcmVhdGUgYSBzZXBhcmF0ZSBhY2NvdW50IHdpdGggYSBwYXNzd29yZC4uLi5cbiAgICA8L3NwYW4+XG4gICAgPHNwYW4gKm5nSWY9XCJvQXV0aFByb3ZpZGVySWRzLmxlbmd0aCA+MVwiPlxuICAgICAgUGxlYXNlIHNpZ24gdXAgd2l0aCBvbmUgb2YgdGhlIHNlcnZpY2VzIGxpc3RlZCBiZWxvdyxcbiAgICAgIG9yIGNyZWF0ZSBhIHNlcGFyYXRlIGFjY291bnQgd2l0aCBhIHBhc3N3b3JkLi4uLlxuICAgIDwvc3Bhbj5cbiAgPC9zbWFsbD5cbiAgPGRpdiBjbGFzcz1cImxpc3QtZ3JvdXBcIj5cblxuICAgIDxhXG4gICAgICAqbmdGb3I9XCJsZXQgaWQgb2Ygb0F1dGhQcm92aWRlcklkc1wiXG4gICAgICByb3V0ZXJMaW5rPVwiLlwiXG4gICAgICBbcXVlcnlQYXJhbXNdPVwie2FjdGlvbjogJ3NpZ25Jbk9BdXRoJywgcHJvdmlkZXJJZDogaWR9XCJcbiAgICAgIGNsYXNzPVwibGlzdC1ncm91cC1pdGVtIGxpc3QtZ3JvdXAtaXRlbS1hY3Rpb25cIj5cbiAgICAgIDxpIFthdHRyLmNsYXNzXT1cImdldE9BdXRoUHJvdmlkZXJJY29uKGlkKVwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPjwvaT5cbiAgICAgIDxzcGFuIGNsYXNzPVwibWwtMlwiPlxuICAgICAgICBTaWduIFVwIHdpdGgge3tnZXRPQXV0aFByb3ZpZGVyTmFtZShpZCl9fVxuICAgICAgPC9zcGFuPlxuICAgIDwvYT5cbiAgICA8YVxuICAgICAgcm91dGVyTGluaz1cIi5cIlxuICAgICAgW3F1ZXJ5UGFyYW1zXT1cInthY3Rpb246ICdzaWduVXBQYXNzd29yZCd9XCJcbiAgICAgIGNsYXNzPVwibGlzdC1ncm91cC1pdGVtIGxpc3QtZ3JvdXAtaXRlbS1hY3Rpb25cIj5cbiAgICAgIDxpIGNsYXNzPVwiZmFzIGZhLWxvY2sgZmEtZndcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L2k+XG4gICAgICA8c3BhbiBjbGFzcz1cIm1sLTJcIj5cbiAgICAgICAgQ3JlYXRlXG4gICAgICAgIDxzcGFuICpuZ0lmPVwib0F1dGhQcm92aWRlcklkcy5sZW5ndGggPiAwXCI+XG4gICAgICAgICAgYSBTZXBhcmF0ZVxuICAgICAgICA8L3NwYW4+XG4gICAgICAgIEFjY291bnRcbiAgICAgIDwvc3Bhbj5cbiAgICA8L2E+XG4gIDwvZGl2PlxuPC9kaXY+XG5gLFxuICBzdHlsZXM6IFtgYF0sXG4gIGFuaW1hdGlvbnM6IFtmYWRlSW5PdXRBbmltYXRpb24sIHNjcmVlbkFuaW1hdGlvbl1cbn0pXG5leHBvcnQgY2xhc3MgU2lnbkluTWV0aG9kc0Zvcm1Db21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQge1xuXG5cbiAgQFZpZXdDaGlsZCgnZW1haWxJbnB1dCcpIGVtYWlsSW5wdXQ6IEVsZW1lbnRSZWY7XG4gIEBJbnB1dCgpIGVtYWlsOiBzdHJpbmc7XG4gIEBJbnB1dCgpIHJlbWVtYmVyOiBib29sZWFuO1xuICBASW5wdXQoKSBvQXV0aFByb3ZpZGVySWRzOiBzdHJpbmdbXSA9IFtdO1xuICBAT3V0cHV0KCkgZW1haWxDaGFuZ2U6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcmVtZW1iZXJDaGFuZ2U6IEV2ZW50RW1pdHRlcjxib29sZWFuPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgpIHN1Y2Nlc3M6IEV2ZW50RW1pdHRlcjxhdXRoLlVzZXJDcmVkZW50aWFsPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgpIGVycm9yOiBFdmVudEVtaXR0ZXI8YXV0aC5FcnJvcj4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cblxuICBmb3JtSWQgPSAnbmd4LWZpcmViYXNlLWF1dGgtc2lnbi1pbi1tZXRob2RzLWZvcm0tJztcbiAgc3VibWl0dGluZyA9IGZhbHNlO1xuICBmZzogRm9ybUdyb3VwO1xuICBlbWFpbEZjOiBGb3JtQ29udHJvbDtcbiAgcmVtZW1iZXJGYzogRm9ybUNvbnRyb2w7XG4gIGdldE9BdXRoUHJvdmlkZXJJY29uID0gZ2V0T0F1dGhQcm92aWRlckljb247XG4gIGdldE9BdXRoUHJvdmlkZXJOYW1lID0gZ2V0T0F1dGhQcm92aWRlck5hbWU7XG4gIG1ldGhvZHNGb3JFbWFpbDogSVNpZ25Jbk1ldGhvZHNGb3JFbWFpbFJlc3VsdCA9IHtzdGF0dXM6ICd1bmZldGNoZWQnLCBtZXRob2RzOiBbXSwgZW1haWw6IG51bGx9O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgX2FmQXV0aDogQW5ndWxhckZpcmVBdXRoLFxuICAgIHByaXZhdGUgX2F1dGhTZXJ2aWNlOiBOZ3hGaXJlYmFzZUF1dGhTZXJ2aWNlLFxuICAgIHByaXZhdGUgX25nWm9uZTogTmdab25lXG4gICkgeyB9XG5cbiAgZ2V0IGF1dGgoKTogYXV0aC5BdXRoIHtcbiAgICByZXR1cm4gdGhpcy5fYWZBdXRoLmF1dGg7XG4gIH1cbiAgZ2V0IGF1dGhTZXJ2aWNlKCk6IE5neEZpcmViYXNlQXV0aFNlcnZpY2Uge1xuICAgIHJldHVybiB0aGlzLl9hdXRoU2VydmljZTtcbiAgfVxuXG5cbiAgZ2V0IG1ldGhvZHMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLm1ldGhvZHNGb3JFbWFpbC5tZXRob2RzO1xuICB9XG5cbiAgZ2V0IGZldGNoU3RhdHVzKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubWV0aG9kc0ZvckVtYWlsLnN0YXR1cztcbiAgfVxuXG4gIGdldCBtZXRob2RzRmV0Y2hlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5tZXRob2RzRm9yRW1haWwuc3RhdHVzID09PSAnZmV0Y2hlZCc7XG4gIH1cblxuICBnZXQgYWNjb3VudElzTmV3KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLm1ldGhvZHNGZXRjaGVkICYmIHRoaXMubWV0aG9kcy5sZW5ndGggPT09IDA7XG4gIH1cblxuICBnZXQgYWNjb3VudEV4aXN0cygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5tZXRob2RzRmV0Y2hlZCAmJiB0aGlzLm1ldGhvZHMubGVuZ3RoID4gMDtcbiAgfVxuXG4gIGdldCBhY2NvdW50SGFzUGFzc3dvcmQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuYWNjb3VudEV4aXN0cyAmJiB0aGlzLm1ldGhvZHMuaW5kZXhPZigncGFzc3dvcmQnKSAhPT0gLTE7XG4gIH1cblxuICBnZXQgYWNjb3VudE9BdXRoTWV0aG9kcygpOiBzdHJpbmdbXSB7XG4gICAgaWYgKCEgdGhpcy5hY2NvdW50RXhpc3RzKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1ldGhvZHMuZmlsdGVyKGlkID0+IGlkICE9PSAncGFzc3dvcmQnKTtcbiAgfVxuXG5cblxuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMuZW1haWxGYyA9IG5ldyBGb3JtQ29udHJvbChcbiAgICAgIHRoaXMuZW1haWwsXG4gICAgICB7dmFsaWRhdG9yczogW1ZhbGlkYXRvcnMucmVxdWlyZWQsIFZhbGlkYXRvcnMuZW1haWxdfVxuICAgICk7XG4gICAgdGhpcy5yZW1lbWJlckZjID0gbmV3IEZvcm1Db250cm9sKHRoaXMucmVtZW1iZXIpO1xuICAgIHRoaXMucmVtZW1iZXJGYy52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKCgpID0+IHRoaXMucmVtZW1iZXJDaGFuZ2UuZW1pdCh0aGlzLnJlbWVtYmVyRmMudmFsdWUpKTtcbiAgICB0aGlzLmZnID0gbmV3IEZvcm1Hcm91cCh7ZW1haWw6IHRoaXMuZW1haWxGYywgcmVtZW1iZXI6IHRoaXMucmVtZW1iZXJGY30pO1xuICAgIHRoaXMuZW1haWxGYy52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKCgpID0+IHRoaXMuZW1haWxDaGFuZ2UuZW1pdCh0aGlzLmVtYWlsRmMudmFsdWUudHJpbSgpKSk7XG4gICAgdGhpcy5lbWFpbEZjLnZhbHVlQ2hhbmdlcy5waXBlKGRlYm91bmNlVGltZSg1MDApKS5zdWJzY3JpYmUoKCkgPT4gdGhpcy5mZXRjaCgpKTtcbiAgICB0aGlzLmZldGNoKCk7XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgdGhpcy5lbWFpbElucHV0Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcblxuICB9XG5cblxuICBmZXRjaCgpIHtcbiAgICBjb25zdCBlbWFpbCA9IHRoaXMuZW1haWxGYy52YWx1ZS50cmltKCk7XG4gICAgaWYgKGVtYWlsID09PSB0aGlzLm1ldGhvZHNGb3JFbWFpbC5lbWFpbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoJ2ZldGNoaW5nJyA9PT0gdGhpcy5tZXRob2RzRm9yRW1haWwuc3RhdHVzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMubWV0aG9kc0ZvckVtYWlsID0ge3N0YXR1czogJ2ZldGNoaW5nJywgbWV0aG9kczogW10sIGVtYWlsOiBlbWFpbH07XG4gICAgaWYgKHRoaXMuZW1haWxGYy5pbnZhbGlkKSB7XG4gICAgICB0aGlzLm1ldGhvZHNGb3JFbWFpbCA9IHtzdGF0dXM6ICd1bmZldGNoZWQnLCBtZXRob2RzOiBbXSwgZW1haWw6IGVtYWlsfTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5hdXRoLmZldGNoU2lnbkluTWV0aG9kc0ZvckVtYWlsKGVtYWlsKVxuICAgICAgLnRoZW4ocmVzdWx0cyA9PiB7XG4gICAgICAgIHRoaXMubWV0aG9kc0ZvckVtYWlsID0ge3N0YXR1czogJ2ZldGNoZWQnLCBtZXRob2RzOiByZXN1bHRzLCBlbWFpbDogZW1haWx9O1xuICAgICAgfSlcbiAgICAgIC5jYXRjaCgoZXJyb3I6IGF1dGguRXJyb3IpID0+IHtcbiAgICAgICAgdGhpcy5lbWFpbEZjLm1hcmtBc0RpcnR5KCk7XG4gICAgICAgIHRoaXMuZW1haWxGYy5tYXJrQXNUb3VjaGVkKCk7XG4gICAgICAgIHN3aXRjaCAoZXJyb3IuY29kZSkge1xuICAgICAgICAgIGNhc2UgJ2F1dGgvaW52YWxpZC1lbWFpbCc6XG4gICAgICAgICAgICBOZ3hGaXJlYmFzZUF1dGhGb3JtSGVscGVyLnNldEVycm9yVW50aWxDaGFuZ2VkKHRoaXMuZW1haWxGYywgZXJyb3IuY29kZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1ldGhvZHNGb3JFbWFpbCA9IHtlbWFpbDogdGhpcy5lbWFpbCwgc3RhdHVzOiAndW5mZXRjaGVkJywgbWV0aG9kczogW119O1xuICAgICAgfSk7XG4gIH1cblxufVxuIl19