UNPKG

ngx-vest-forms

Version:

Opinionated template-driven forms library for Angular

175 lines 28.8 kB
import { Directive, inject, input, Output } from '@angular/core'; import { NgForm, PristineChangeEvent, StatusChangeEvent, ValueChangeEvent, } from '@angular/forms'; import { debounceTime, distinctUntilChanged, filter, map, Observable, of, ReplaySubject, startWith, Subject, switchMap, take, takeUntil, tap, zip, } from 'rxjs'; import { toObservable } from '@angular/core/rxjs-interop'; import { cloneDeep, getAllFormErrors, mergeValuesAndRawValues, set, } from '../utils/form-utils'; import { validateShape } from '../utils/shape-validation'; import * as i0 from "@angular/core"; export class FormDirective { constructor() { this.ngForm = inject(NgForm, { self: true, optional: false }); /** * The value of the form, this is needed for the validation part */ this.formValue = input(null); /** * Static vest suite that will be used to feed our angular validators */ this.suite = input(null); /** * The shape of our form model. This is a deep required version of the form model * The goal is to add default values to the shape so when the template-driven form * contains values that shouldn't be there (typo's) that the developer gets run-time * errors in dev mode */ this.formShape = input(null); /** * Updates the validation config which is a dynamic object that will be used to * trigger validations on the dependant fields * Eg: ```typescript * validationConfig = { * 'passwords.password': ['passwords.confirmPassword'] * } * ``` * * This will trigger the updateValueAndValidity on passwords.confirmPassword every time the passwords.password gets a new value * * @param v */ this.validationConfig = input(null); this.pending$ = this.ngForm.form.events.pipe(filter((v) => v instanceof StatusChangeEvent), map((v) => v.status), filter((v) => v === 'PENDING'), distinctUntilChanged()); /** * Emits every time the form status changes in a state * that is not PENDING * We need this to assure that the form is in 'idle' state */ this.idle$ = this.ngForm.form.events.pipe(filter((v) => v instanceof StatusChangeEvent), map((v) => v.status), filter((v) => v !== 'PENDING'), distinctUntilChanged()); /** * Triggered as soon as the form value changes * Also every time Angular creates a new control or group * It also contains the disabled values (raw values) */ this.formValueChange = this.ngForm.form.events.pipe(filter((v) => v instanceof ValueChangeEvent), map((v) => v.value), map(() => mergeValuesAndRawValues(this.ngForm.form))); /** * Emits an object with all the errors of the form * every time a form control or form groups changes its status to valid or invalid */ this.errorsChange = this.ngForm.form.events.pipe(filter((v) => v instanceof StatusChangeEvent), map((v) => v.status), filter((v) => v !== 'PENDING'), map(() => getAllFormErrors(this.ngForm.form))); /** * Triggered as soon as the form becomes dirty */ this.dirtyChange = this.ngForm.form.events.pipe(filter((v) => v instanceof PristineChangeEvent), map((v) => !v.pristine), startWith(this.ngForm.form.dirty), distinctUntilChanged()); this.destroy$$ = new Subject(); /** * Fired when the status of the root form changes. */ this.statusChanges$ = this.ngForm.form.statusChanges.pipe(startWith(this.ngForm.form.status), distinctUntilChanged()); /** * Triggered When the form becomes valid but waits until the form is idle */ this.validChange = this.statusChanges$.pipe(filter((e) => e === 'VALID' || e === 'INVALID'), map((v) => v === 'VALID'), distinctUntilChanged()); /** * Used to debounce formValues to make sure vest isn't triggered all the time */ this.formValueCache = {}; // When the validation config changes // Listen to changes of the left-side of the config and trigger the updateValueAndValidity // function on the dependant controls or groups at the right-side of the config toObservable(this.validationConfig) .pipe(filter((conf) => !!conf), switchMap((conf) => { if (!conf) { return of(null); } const streams = Object.keys(conf).map((key) => { return this.ngForm?.form.get(key)?.valueChanges.pipe( // Wait until something is pending switchMap(() => this.pending$), // Wait until the form is not pending anymore switchMap(() => this.idle$), map(() => this.ngForm?.form.get(key)?.value), takeUntil(this.destroy$$), tap((v) => { conf[key]?.forEach((path) => { this.ngForm?.form.get(path)?.updateValueAndValidity({ onlySelf: true, emitEvent: true, }); }); })); }); return zip(streams); })) .subscribe(); /** * Trigger shape validations if the form gets updated * This is how we can throw run-time errors */ this.formValueChange.pipe(takeUntil(this.destroy$$)).subscribe((v) => { if (this.formShape()) { validateShape(v, this.formShape()); } }); /** * Mark all the fields as touched when the form is submitted */ this.ngForm.ngSubmit.subscribe(() => { this.ngForm.form.markAllAsTouched(); }); } /** * This will feed the formValueCache, debounce it till the next tick * and create an asynchronous validator that runs a vest suite * @param field * @param validationOptions * @returns an asynchronous validator function */ createAsyncValidator(field, validationOptions) { if (!this.suite()) { return () => of(null); } return (value) => { if (!this.formValue()) { return of(null); } const mod = cloneDeep(this.formValue()); set(mod, field, value); // Update the property with path if (!this.formValueCache[field]) { this.formValueCache[field] = { sub$$: new ReplaySubject(1), // Keep track of the last model }; this.formValueCache[field].debounced = this.formValueCache[field].sub$$.pipe(debounceTime(validationOptions.debounceTime)); } // Next the latest model in the cache for a certain field this.formValueCache[field].sub$$.next(mod); return this.formValueCache[field].debounced.pipe( // When debounced, take the latest value and perform the asynchronous vest validation take(1), switchMap(() => { return new Observable((observer) => { this.suite()(mod, field).done((result) => { const errors = result.getErrors()[field]; observer.next(errors ? { error: errors[0], errors } : null); observer.complete(); }); }); }), takeUntil(this.destroy$$)); }; } ngOnDestroy() { this.destroy$$.next(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FormDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.0.1", type: FormDirective, isStandalone: true, selector: "form[scVestForm]", inputs: { formValue: { classPropertyName: "formValue", publicName: "formValue", isSignal: true, isRequired: false, transformFunction: null }, suite: { classPropertyName: "suite", publicName: "suite", isSignal: true, isRequired: false, transformFunction: null }, formShape: { classPropertyName: "formShape", publicName: "formShape", isSignal: true, isRequired: false, transformFunction: null }, validationConfig: { classPropertyName: "validationConfig", publicName: "validationConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formValueChange: "formValueChange", errorsChange: "errorsChange", dirtyChange: "dirtyChange", validChange: "validChange" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FormDirective, decorators: [{ type: Directive, args: [{ selector: 'form[scVestForm]', standalone: true, }] }], ctorParameters: () => [], propDecorators: { formValueChange: [{ type: Output }], errorsChange: [{ type: Output }], dirtyChange: [{ type: Output }], validChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdmVzdC1mb3Jtcy9zcmMvbGliL2RpcmVjdGl2ZXMvZm9ybS5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFhLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM1RSxPQUFPLEVBRUwsTUFBTSxFQUNOLG1CQUFtQixFQUNuQixpQkFBaUIsRUFFakIsZ0JBQWdCLEdBQ2pCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUNMLFlBQVksRUFDWixvQkFBb0IsRUFDcEIsTUFBTSxFQUNOLEdBQUcsRUFDSCxVQUFVLEVBQ1YsRUFBRSxFQUNGLGFBQWEsRUFDYixTQUFTLEVBQ1QsT0FBTyxFQUNQLFNBQVMsRUFDVCxJQUFJLEVBQ0osU0FBUyxFQUNULEdBQUcsRUFDSCxHQUFHLEdBQ0osTUFBTSxNQUFNLENBQUM7QUFFZCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFMUQsT0FBTyxFQUNMLFNBQVMsRUFDVCxnQkFBZ0IsRUFDaEIsdUJBQXVCLEVBQ3ZCLEdBQUcsR0FDSixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQzs7QUFPMUQsTUFBTSxPQUFPLGFBQWE7SUF5SHhCO1FBeEhnQixXQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFFekU7O1dBRUc7UUFDYSxjQUFTLEdBQUcsS0FBSyxDQUFXLElBQUksQ0FBQyxDQUFDO1FBRWxEOztXQUVHO1FBQ2EsVUFBSyxHQUFHLEtBQUssQ0FJbkIsSUFBSSxDQUFDLENBQUM7UUFFaEI7Ozs7O1dBS0c7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b0JBQ2pDLElBQUksQ0FBQyxLQUFLLEVBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7d0JBQ3hDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQzt3QkFDekMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7d0JBQzVELFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztvQkFDdEIsQ0FBQyxDQUFDLENBQUM7Z0JBQ0wsQ0FBQyxDQUF3QyxDQUFDO1lBQzVDLENBQUMsQ0FBQyxFQUNGLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQzFCLENBQUM7UUFDSixDQUFDLENBQUM7SUFDSixDQUFDO0lBRU0sV0FBVztRQUNoQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3hCLENBQUM7OEdBNU5VLGFBQWE7a0dBQWIsYUFBYTs7MkZBQWIsYUFBYTtrQkFKekIsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsa0JBQWtCO29CQUM1QixVQUFVLEVBQUUsSUFBSTtpQkFDakI7d0RBbUUyQixlQUFlO3NCQUF4QyxNQUFNO2dCQVVtQixZQUFZO3NCQUFyQyxNQUFNO2dCQVVtQixXQUFXO3NCQUFwQyxNQUFNO2dCQW1CbUIsV0FBVztzQkFBcEMsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERpcmVjdGl2ZSwgaW5qZWN0LCBpbnB1dCwgT25EZXN0cm95LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIEFzeW5jVmFsaWRhdG9yRm4sXG4gIE5nRm9ybSxcbiAgUHJpc3RpbmVDaGFuZ2VFdmVudCxcbiAgU3RhdHVzQ2hhbmdlRXZlbnQsXG4gIFZhbGlkYXRpb25FcnJvcnMsXG4gIFZhbHVlQ2hhbmdlRXZlbnQsXG59IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7XG4gIGRlYm91bmNlVGltZSxcbiAgZGlzdGluY3RVbnRpbENoYW5nZWQsXG4gIGZpbHRlcixcbiAgbWFwLFxuICBPYnNlcnZhYmxlLFxuICBvZixcbiAgUmVwbGF5U3ViamVjdCxcbiAgc3RhcnRXaXRoLFxuICBTdWJqZWN0LFxuICBzd2l0Y2hNYXAsXG4gIHRha2UsXG4gIHRha2VVbnRpbCxcbiAgdGFwLFxuICB6aXAsXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgU3RhdGljU3VpdGUgfSBmcm9tICd2ZXN0JztcbmltcG9ydCB7IHRvT2JzZXJ2YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcbmltcG9ydCB7IERlZXBSZXF1aXJlZCB9IGZyb20gJy4uL3V0aWxzL2RlZXAtcmVxdWlyZWQnO1xuaW1wb3J0IHtcbiAgY2xvbmVEZWVwLFxuICBnZXRBbGxGb3JtRXJyb3JzLFxuICBtZXJnZVZhbHVlc0FuZFJhd1ZhbHVlcyxcbiAgc2V0LFxufSBmcm9tICcuLi91dGlscy9mb3JtLXV0aWxzJztcbmltcG9ydCB7IHZhbGlkYXRlU2hhcGUgfSBmcm9tICcuLi91dGlscy9zaGFwZS12YWxpZGF0aW9uJztcbmltcG9ydCB7IFZhbGlkYXRpb25PcHRpb25zIH0gZnJvbSAnLi92YWxpZGF0aW9uLW9wdGlvbnMnO1xuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdmb3JtW3NjVmVzdEZvcm1dJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbn0pXG5leHBvcnQgY2xhc3MgRm9ybURpcmVjdGl2ZTxUIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55Pj4gaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xuICBwdWJsaWMgcmVhZG9ubHkgbmdGb3JtID0gaW5qZWN0KE5nRm9ybSwgeyBzZWxmOiB0cnVlLCBvcHRpb25hbDogZmFsc2UgfSk7XG5cbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBvZiB0aGUgZm9ybSwgdGhpcyBpcyBuZWVkZWQgZm9yIHRoZSB2YWxpZGF0aW9uIHBhcnRcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBmb3JtVmFsdWUgPSBpbnB1dDxUIHwgbnVsbD4obnVsbCk7XG5cbiAgLyoqXG4gICAqIFN0YXRpYyB2ZXN0IHN1aXRlIHRoYXQgd2lsbCBiZSB1c2VkIHRvIGZlZWQgb3VyIGFuZ3VsYXIgdmFsaWRhdG9yc1xuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHN1aXRlID0gaW5wdXQ8U3RhdGljU3VpdGU8XG4gICAgc3RyaW5nLFxuICAgIHN0cmluZyxcbiAgICAobW9kZWw6IFQsIGZpZWxkOiBzdHJpbmcpID0+IHZvaWRcbiAgPiB8IG51bGw+KG51bGwpO1xuXG4gIC8qKlxuICAgKiBUaGUgc2hhcGUgb2Ygb3VyIGZvcm0gbW9kZWwuIFRoaXMgaXMgYSBkZWVwIHJlcXVpcmVkIHZlcnNpb24gb2YgdGhlIGZvcm0gbW9kZWxcbiAgICogVGhlIGdvYWwgaXMgdG8gYWRkIGRlZmF1bHQgdmFsdWVzIHRvIHRoZSBzaGFwZSBzbyB3aGVuIHRoZSB0ZW1wbGF0ZS1kcml2ZW4gZm9ybVxuICAgKiBjb250YWlucyB2YWx1ZXMgdGhhdCBzaG91bGRuJ3QgYmUgdGhlcmUgKHR5cG8ncykgdGhhdCB0aGUgZGV2ZWxvcGVyIGdldHMgcnVuLXRpbWVcbiAgICogZXJyb3JzIGluIGRldiBtb2RlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZm9ybVNoYXBlID0gaW5wdXQ8RGVlcFJlcXVpcmVkPFQ+IHwgbnVsbD4obnVsbCk7XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgdGhlIHZhbGlkYXRpb24gY29uZmlnIHdoaWNoIGlzIGEgZHluYW1pYyBvYmplY3QgdGhhdCB3aWxsIGJlIHVzZWQgdG9cbiAgICogdHJpZ2dlciB2YWxpZGF0aW9ucyBvbiB0aGUgZGVwZW5kYW50IGZpZWxkc1xuICAgKiBFZzogYGBgdHlwZXNjcmlwdFxuICAgKiB2YWxpZGF0aW9uQ29uZmlnID0ge1xuICAgKiAgICAgJ3Bhc3N3b3Jkcy5wYXNzd29yZCc6IFsncGFzc3dvcmRzLmNvbmZpcm1QYXNzd29yZCddXG4gICAqIH1cbiAgICogYGBgXG4gICAqXG4gICAqIFRoaXMgd2lsbCB0cmlnZ2VyIHRoZSB1cGRhdGVWYWx1ZUFuZFZhbGlkaXR5IG9uIHBhc3N3b3Jkcy5jb25maXJtUGFzc3dvcmQgZXZlcnkgdGltZSB0aGUgcGFzc3dvcmRzLnBhc3N3b3JkIGdldHMgYSBuZXcgdmFsdWVcbiAgICpcbiAgICogQHBhcmFtIHZcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB2YWxpZGF0aW9uQ29uZmlnID0gaW5wdXQ8eyBba2V5OiBzdHJpbmddOiBzdHJpbmdbXSB9IHwgbnVsbD4oXG4gICAgbnVsbFxuICApO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcGVuZGluZyQgPSB0aGlzLm5nRm9ybS5mb3JtLmV2ZW50cy5waXBlKFxuICAgIGZpbHRlcigodikgPT4gdiBpbnN0YW5jZW9mIFN0YXR1c0NoYW5nZUV2ZW50KSxcbiAgICBtYXAoKHYpID0+ICh2IGFzIFN0YXR1c0NoYW5nZUV2ZW50KS5zdGF0dXMpLFxuICAgIGZpbHRlcigodikgPT4gdiA9PT0gJ1BFTkRJTkcnKSxcbiAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpXG4gICk7XG5cbiAgLyoqXG4gICAqIEVtaXRzIGV2ZXJ5IHRpbWUgdGhlIGZvcm0gc3RhdHVzIGNoYW5nZXMgaW4gYSBzdGF0ZVxuICAgKiB0aGF0IGlzIG5vdCBQRU5ESU5HXG4gICAqIFdlIG5lZWQgdGhpcyB0byBhc3N1cmUgdGhhdCB0aGUgZm9ybSBpcyBpbiAnaWRsZScgc3RhdGVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBpZGxlJCA9IHRoaXMubmdGb3JtLmZvcm0uZXZlbnRzLnBpcGUoXG4gICAgZmlsdGVyKCh2KSA9PiB2IGluc3RhbmNlb2YgU3RhdHVzQ2hhbmdlRXZlbnQpLFxuICAgIG1hcCgodikgPT4gKHYgYXMgU3RhdHVzQ2hhbmdlRXZlbnQpLnN0YXR1cyksXG4gICAgZmlsdGVyKCh2KSA9PiB2ICE9PSAnUEVORElORycpLFxuICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgKTtcblxuICAvKipcbiAgICogVHJpZ2dlcmVkIGFzIHNvb24gYXMgdGhlIGZvcm0gdmFsdWUgY2hhbmdlc1xuICAgKiBBbHNvIGV2ZXJ5IHRpbWUgQW5ndWxhciBjcmVhdGVzIGEgbmV3IGNvbnRyb2wgb3IgZ3JvdXBcbiAgICogSXQgYWxzbyBjb250YWlucyB0aGUgZGlzYWJsZWQgdmFsdWVzIChyYXcgdmFsdWVzKVxuICAgKi9cbiAgQE91dHB1dCgpIHB1YmxpYyByZWFkb25seSBmb3JtVmFsdWVDaGFuZ2UgPSB0aGlzLm5nRm9ybS5mb3JtLmV2ZW50cy5waXBlKFxuICAgIGZpbHRlcigodikgPT4gdiBpbnN0YW5jZW9mIFZhbHVlQ2hhbmdlRXZlbnQpLFxuICAgIG1hcCgodikgPT4gKHYgYXMgVmFsdWVDaGFuZ2VFdmVudDxhbnk+KS52YWx1ZSksXG4gICAgbWFwKCgpID0+IG1lcmdlVmFsdWVzQW5kUmF3VmFsdWVzPFQ+KHRoaXMubmdGb3JtLmZvcm0pKVxuICApO1xuXG4gIC8qKlxuICAgKiBFbWl0cyBhbiBvYmplY3Qgd2l0aCBhbGwgdGhlIGVycm9ycyBvZiB0aGUgZm9ybVxuICAgKiBldmVyeSB0aW1lIGEgZm9ybSBjb250cm9sIG9yIGZvcm0gZ3JvdXBzIGNoYW5nZXMgaXRzIHN0YXR1cyB0byB2YWxpZCBvciBpbnZhbGlkXG4gICAqL1xuICBAT3V0cHV0KCkgcHVibGljIHJlYWRvbmx5IGVycm9yc0NoYW5nZSA9IHRoaXMubmdGb3JtLmZvcm0uZXZlbnRzLnBpcGUoXG4gICAgZmlsdGVyKCh2KSA9PiB2IGluc3RhbmNlb2YgU3RhdHVzQ2hhbmdlRXZlbnQpLFxuICAgIG1hcCgodikgPT4gKHYgYXMgU3RhdHVzQ2hhbmdlRXZlbnQpLnN0YXR1cyksXG4gICAgZmlsdGVyKCh2KSA9PiB2ICE9PSAnUEVORElORycpLFxuICAgIG1hcCgoKSA9PiBnZXRBbGxGb3JtRXJyb3JzKHRoaXMubmdGb3JtLmZvcm0pKVxuICApO1xuXG4gIC8qKlxuICAgKiBUcmlnZ2VyZWQgYXMgc29vbiBhcyB0aGUgZm9ybSBiZWNvbWVzIGRpcnR5XG4gICAqL1xuICBAT3V0cHV0KCkgcHVibGljIHJlYWRvbmx5IGRpcnR5Q2hhbmdlID0gdGhpcy5uZ0Zvcm0uZm9ybS5ldmVudHMucGlwZShcbiAgICBmaWx0ZXIoKHYpID0+IHYgaW5zdGFuY2VvZiBQcmlzdGluZUNoYW5nZUV2ZW50KSxcbiAgICBtYXAoKHYpID0+ICEodiBhcyBQcmlzdGluZUNoYW5nZUV2ZW50KS5wcmlzdGluZSksXG4gICAgc3RhcnRXaXRoKHRoaXMubmdGb3JtLmZvcm0uZGlydHkpLFxuICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgKTtcbiAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95JCQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIC8qKlxuICAgKiBGaXJlZCB3aGVuIHRoZSBzdGF0dXMgb2YgdGhlIHJvb3QgZm9ybSBjaGFuZ2VzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBzdGF0dXNDaGFuZ2VzJCA9IHRoaXMubmdGb3JtLmZvcm0uc3RhdHVzQ2hhbmdlcy5waXBlKFxuICAgIHN0YXJ0V2l0aCh0aGlzLm5nRm9ybS5mb3JtLnN0YXR1cyksXG4gICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKVxuICApO1xuXG4gIC8qKlxuICAgKiBUcmlnZ2VyZWQgV2hlbiB0aGUgZm9ybSBiZWNvbWVzIHZhbGlkIGJ1dCB3YWl0cyB1bnRpbCB0aGUgZm9ybSBpcyBpZGxlXG4gICAqL1xuICBAT3V0cHV0KCkgcHVibGljIHJlYWRvbmx5IHZhbGlkQ2hhbmdlID0gdGhpcy5zdGF0dXNDaGFuZ2VzJC5waXBlKFxuICAgIGZpbHRlcigoZSkgPT4gZSA9PT0gJ1ZBTElEJyB8fCBlID09PSAnSU5WQUxJRCcpLFxuICAgIG1hcCgodikgPT4gdiA9PT0gJ1ZBTElEJyksXG4gICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKVxuICApO1xuXG4gIC8qKlxuICAgKiBVc2VkIHRvIGRlYm91bmNlIGZvcm1WYWx1ZXMgdG8gbWFrZSBzdXJlIHZlc3QgaXNuJ3QgdHJpZ2dlcmVkIGFsbCB0aGUgdGltZVxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBmb3JtVmFsdWVDYWNoZToge1xuICAgIFtmaWVsZDogc3RyaW5nXTogUGFydGlhbDx7XG4gICAgICBzdWIkJDogUmVwbGF5U3ViamVjdDx1bmtub3duPjtcbiAgICAgIGRlYm91bmNlZDogT2JzZXJ2YWJsZTxhbnk+O1xuICAgIH0+O1xuICB9ID0ge307XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKCkge1xuICAgIC8vIFdoZW4gdGhlIHZhbGlkYXRpb24gY29uZmlnIGNoYW5nZXNcbiAgICAvLyBMaXN0ZW4gdG8gY2hhbmdlcyBvZiB0aGUgbGVmdC1zaWRlIG9mIHRoZSBjb25maWcgYW5kIHRyaWdnZXIgdGhlIHVwZGF0ZVZhbHVlQW5kVmFsaWRpdHlcbiAgICAvLyBmdW5jdGlvbiBvbiB0aGUgZGVwZW5kYW50IGNvbnRyb2xzIG9yIGdyb3VwcyBhdCB0aGUgcmlnaHQtc2lkZSBvZiB0aGUgY29uZmlnXG4gICAgdG9PYnNlcnZhYmxlKHRoaXMudmFsaWRhdGlvbkNvbmZpZylcbiAgICAgIC5waXBlKFxuICAgICAgICBmaWx0ZXIoKGNvbmYpID0+ICEhY29uZiksXG4gICAgICAgIHN3aXRjaE1hcCgoY29uZikgPT4ge1xuICAgICAgICAgIGlmICghY29uZikge1xuICAgICAgICAgICAgcmV0dXJuIG9mKG51bGwpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBzdHJlYW1zID0gT2JqZWN0LmtleXMoY29uZikubWFwKChrZXkpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm5nRm9ybT8uZm9ybS5nZXQoa2V5KT8udmFsdWVDaGFuZ2VzLnBpcGUoXG4gICAgICAgICAgICAgIC8vIFdhaXQgdW50aWwgc29tZXRoaW5nIGlzIHBlbmRpbmdcbiAgICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMucGVuZGluZyQpLFxuICAgICAgICAgICAgICAvLyBXYWl0IHVudGlsIHRoZSBmb3JtIGlzIG5vdCBwZW5kaW5nIGFueW1vcmVcbiAgICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuaWRsZSQpLFxuICAgICAgICAgICAgICBtYXAoKCkgPT4gdGhpcy5uZ0Zvcm0/LmZvcm0uZ2V0KGtleSk/LnZhbHVlKSxcbiAgICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQkKSxcbiAgICAgICAgICAgICAgdGFwKCh2KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uZltrZXldPy5mb3JFYWNoKChwYXRoOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgICAgIHRoaXMubmdGb3JtPy5mb3JtLmdldChwYXRoKT8udXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7XG4gICAgICAgICAgICAgICAgICAgIG9ubHlTZWxmOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBlbWl0RXZlbnQ6IHRydWUsXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuIHppcChzdHJlYW1zKTtcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKTtcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgc2hhcGUgdmFsaWRhdGlvbnMgaWYgdGhlIGZvcm0gZ2V0cyB1cGRhdGVkXG4gICAgICogVGhpcyBpcyBob3cgd2UgY2FuIHRocm93IHJ1bi10aW1lIGVycm9yc1xuICAgICAqL1xuICAgIHRoaXMuZm9ybVZhbHVlQ2hhbmdlLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQkKSkuc3Vic2NyaWJlKCh2KSA9PiB7XG4gICAgICBpZiAodGhpcy5mb3JtU2hhcGUoKSkge1xuICAgICAgICB2YWxpZGF0ZVNoYXBlKHYsIHRoaXMuZm9ybVNoYXBlKCkgYXMgRGVlcFJlcXVpcmVkPFQ+KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIE1hcmsgYWxsIHRoZSBmaWVsZHMgYXMgdG91Y2hlZCB3aGVuIHRoZSBmb3JtIGlzIHN1Ym1pdHRlZFxuICAgICAqL1xuICAgIHRoaXMubmdGb3JtLm5nU3VibWl0LnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLm5nRm9ybS5mb3JtLm1hcmtBbGxBc1RvdWNoZWQoKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIHdpbGwgZmVlZCB0aGUgZm9ybVZhbHVlQ2FjaGUsIGRlYm91bmNlIGl0IHRpbGwgdGhlIG5leHQgdGlja1xuICAgKiBhbmQgY3JlYXRlIGFuIGFzeW5jaHJvbm91cyB2YWxpZGF0b3IgdGhhdCBydW5zIGEgdmVzdCBzdWl0ZVxuICAgKiBAcGFyYW0gZmllbGRcbiAgICogQHBhcmFtIHZhbGlkYXRpb25PcHRpb25zXG4gICAqIEByZXR1cm5zIGFuIGFzeW5jaHJvbm91cyB2YWxpZGF0b3IgZnVuY3Rpb25cbiAgICovXG4gIHB1YmxpYyBjcmVhdGVBc3luY1ZhbGlkYXRvcihmaWVsZDogc3RyaW5nLCB2YWxpZGF0aW9uT3B0aW9uczogVmFsaWRhdGlvbk9wdGlvbnMpOiBBc3luY1ZhbGlkYXRvckZuIHtcbiAgICBpZiAoIXRoaXMuc3VpdGUoKSkge1xuICAgICAgcmV0dXJuICgpID0+IG9mKG51bGwpO1xuICAgIH1cbiAgICByZXR1cm4gKHZhbHVlOiBhbnkpID0+IHtcbiAgICAgIGlmICghdGhpcy5mb3JtVmFsdWUoKSkge1xuICAgICAgICByZXR1cm4gb2YobnVsbCk7XG4gICAgICB9XG4gICAgICBjb25zdCBtb2QgPSBjbG9uZURlZXAodGhpcy5mb3JtVmFsdWUoKSBhcyBUKTtcbiAgICAgIHNldChtb2QgYXMgb2JqZWN0LCBmaWVsZCwgdmFsdWUpOyAvLyBVcGRhdGUgdGhlIHByb3BlcnR5IHdpdGggcGF0aFxuICAgICAgaWYgKCF0aGlzLmZvcm1WYWx1ZUNhY2hlW2ZpZWxkXSkge1xuICAgICAgICB0aGlzLmZvcm1WYWx1ZUNhY2hlW2ZpZWxkXSA9IHtcbiAgICAgICAgICBzdWIkJDogbmV3IFJlcGxheVN1YmplY3QoMSksIC8vIEtlZXAgdHJhY2sgb2YgdGhlIGxhc3QgbW9kZWxcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5mb3JtVmFsdWVDYWNoZVtmaWVsZF0uZGVib3VuY2VkID0gdGhpcy5mb3JtVmFsdWVDYWNoZVtcbiAgICAgICAgICBmaWVsZFxuICAgICAgICAgIF0uc3ViJCQhLnBpcGUoZGVib3VuY2VUaW1lKHZhbGlkYXRpb25PcHRpb25zLmRlYm91bmNlVGltZSkpO1xuICAgICAgfVxuICAgICAgLy8gTmV4dCB0aGUgbGF0ZXN0IG1vZGVsIGluIHRoZSBjYWNoZSBmb3IgYSBjZXJ0YWluIGZpZWxkXG4gICAgICB0aGlzLmZvcm1WYWx1ZUNhY2hlW2ZpZWxkXS5zdWIkJCEubmV4dChtb2QpO1xuXG4gICAgICByZXR1cm4gdGhpcy5mb3JtVmFsdWVDYWNoZVtmaWVsZF0uZGVib3VuY2VkIS5waXBlKFxuICAgICAgICAvLyBXaGVuIGRlYm91bmNlZCwgdGFrZSB0aGUgbGF0ZXN0IHZhbHVlIGFuZCBwZXJmb3JtIHRoZSBhc3luY2hyb25vdXMgdmVzdCB2YWxpZGF0aW9uXG4gICAgICAgIHRha2UoMSksXG4gICAgICAgIHN3aXRjaE1hcCgoKSA9PiB7XG4gICAgICAgICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlKChvYnNlcnZlcikgPT4ge1xuICAgICAgICAgICAgdGhpcy5zdWl0ZSgpIShtb2QsIGZpZWxkKS5kb25lKChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgZXJyb3JzID0gcmVzdWx0LmdldEVycm9ycygpW2ZpZWxkXTtcbiAgICAgICAgICAgICAgb2JzZXJ2ZXIubmV4dChlcnJvcnMgPyB7IGVycm9yOiBlcnJvcnNbMF0sIGVycm9ycyB9IDogbnVsbCk7XG4gICAgICAgICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KSBhcyBPYnNlcnZhYmxlPFZhbGlkYXRpb25FcnJvcnMgfCBudWxsPjtcbiAgICAgICAgfSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkJClcbiAgICAgICk7XG4gICAgfTtcbiAgfVxuXG4gIHB1YmxpYyBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3kkJC5uZXh0KCk7XG4gIH1cbn1cbiJdfQ==