@bsachref/ng-form
Version:
A dynamic form component for Angular using PrimeNG or Angular Material
85 lines • 20.5 kB
JavaScript
/**
* @component DefaultFormsComponent
* @description
* The `DefaultFormsComponent` is an Angular standalone component that provides a dynamic form generation
* based on the provided configuration. It uses reactive forms to handle form controls and their validations.
* The component is designed to be highly configurable and supports various types of form validators.
*
* @selector default-forms
* @standalone true
* @imports
* - ReactiveFormsModule
* - CommonModule
* - FormsModule
* - ValidationMessagesComponent
* @templateUrl ./default-forms.component.html
* @styleUrl ./default-forms.component.css
* @changeDetection ChangeDetectionStrategy.OnPush
*
* @input
* - `formName: string` - The name of the form.
* - `controls: FormControlConfig[]` - An array of form control configurations.
*
* @output
* - `formSubmit: EventEmitter<Record<string, any>>` - Emits the form value when the form is submitted.
*
* @class DefaultFormsComponent
* @implements OnInit
*
* @property {string} formName - The name of the form.
* @property {FormControlConfig[]} controls - The configuration for the form controls.
* @property {EventEmitter<Record<string, any>>} formSubmit - Event emitter for form submission.
* @property {FormGroup} form - The reactive form group instance.
* @property {BehaviorSubject<boolean>} formChanges$ - A subject to track form changes.
*
* @constructor
* @param {FormBuilder} fb - Angular's FormBuilder service to create form controls.
* @param {ChangeDetectorRef} cdr - Angular's ChangeDetectorRef service to manually trigger change detection.
*
* @method ngOnInit
* @description Lifecycle hook that is called after the component's view has been initialized. It initializes the form.
*
* @method initializeForm
* @description Initializes the form by creating form controls based on the provided configuration and sets up value change subscriptions.
*
* @method getValidators
* @param {FormControlConfig} control - The configuration for a form control.
* @returns {ValidatorFn[]} An array of validators for the form control.
* @description Generates an array of validators based on the provided control configuration.
*
* @method updateValidators
* @param {AbstractControl} control - The form control to update validators for.
* @param {any} value - The current value of the form control.
* @description Updates the validators for a form control based on its current value.
*
* @method shouldRequireValidation
* @param {any} value - The value to check for validation requirement.
* @returns {boolean} Whether the value requires validation.
* @description Determines if a value should require validation.
*
* @method onSubmit
* @description Handles the form submission. Marks the form as touched and dirty, validates the form, emits the form value if valid, and resets the form.
*/
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { ValidationMessagesComponent } from '../validation-messages/validation-messages.component';
import { BaseFormsComponent } from '../base.component';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "@angular/common";
export class DefaultFormsComponent extends BaseFormsComponent {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultFormsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DefaultFormsComponent, isStandalone: true, selector: "default-forms", usesInheritance: true, ngImport: i0, template: "<form [formGroup]=\"form\" [attr.name]=\"formName()\" (ngSubmit)=\"onSubmit()\">\n @for (control of controls(); track $index) {\n @if (control.uiFramework === \"default\" || !control.uiFramework) {\n @if (form.get(control.name)) {\n <section [ngClass]=\"control.class\" [ngStyle]=\"control.style\">\n @if (control.label) {\n <label\n [attr.for]=\"control.name\"\n [ngClass]=\"control.labelClass\"\n [ngStyle]=\"control.labelStyle\"\n >\n {{ control.label }}\n </label>\n }\n\n @if (control.type === \"input\") {\n <input\n [formControlName]=\"control.name\"\n [id]=\"control.name\"\n type=\"text\"\n />\n }\n @if (control.type === \"select\") {\n <select [formControlName]=\"control.name\" [id]=\"control.name\">\n @for (option of control.options; track $index) {\n <option [value]=\"option\">{{ option }}</option>\n }\n </select>\n }\n @if (control.type === \"textarea\") {\n <textarea\n [formControlName]=\"control.name\"\n [id]=\"control.name\"\n ></textarea>\n }\n @if (control.type === \"checkbox\") {\n <input\n type=\"checkbox\"\n [formControlName]=\"control.name\"\n [id]=\"control.name\"\n />\n }\n @if (control.type === \"radio\") {\n @for (option of control.options ?? []; track $index) {\n <div>\n <input\n type=\"radio\"\n [formControlName]=\"control.name\"\n [id]=\"control.name + '-' + option\"\n [value]=\"option\"\n />\n <label [for]=\"control.name + '-' + option\">{{ option }}</label>\n </div>\n }\n }\n\n <validation-messages\n [control]=\"form.get(control.name)\"\n [controlName]=\"control.name\"\n [config]=\"control\"\n ></validation-messages>\n </section>\n }\n }\n }\n <button type=\"submit\" [disabled]=\"form.invalid\">Submit</button>\n</form>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.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: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: ValidationMessagesComponent, selector: "validation-messages", inputs: ["control", "controlName", "config"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultFormsComponent, decorators: [{
type: Component,
args: [{ selector: 'default-forms', standalone: true, imports: [
BaseFormsComponent,
ReactiveFormsModule,
CommonModule,
FormsModule,
ValidationMessagesComponent,
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form [formGroup]=\"form\" [attr.name]=\"formName()\" (ngSubmit)=\"onSubmit()\">\n @for (control of controls(); track $index) {\n @if (control.uiFramework === \"default\" || !control.uiFramework) {\n @if (form.get(control.name)) {\n <section [ngClass]=\"control.class\" [ngStyle]=\"control.style\">\n @if (control.label) {\n <label\n [attr.for]=\"control.name\"\n [ngClass]=\"control.labelClass\"\n [ngStyle]=\"control.labelStyle\"\n >\n {{ control.label }}\n </label>\n }\n\n @if (control.type === \"input\") {\n <input\n [formControlName]=\"control.name\"\n [id]=\"control.name\"\n type=\"text\"\n />\n }\n @if (control.type === \"select\") {\n <select [formControlName]=\"control.name\" [id]=\"control.name\">\n @for (option of control.options; track $index) {\n <option [value]=\"option\">{{ option }}</option>\n }\n </select>\n }\n @if (control.type === \"textarea\") {\n <textarea\n [formControlName]=\"control.name\"\n [id]=\"control.name\"\n ></textarea>\n }\n @if (control.type === \"checkbox\") {\n <input\n type=\"checkbox\"\n [formControlName]=\"control.name\"\n [id]=\"control.name\"\n />\n }\n @if (control.type === \"radio\") {\n @for (option of control.options ?? []; track $index) {\n <div>\n <input\n type=\"radio\"\n [formControlName]=\"control.name\"\n [id]=\"control.name + '-' + option\"\n [value]=\"option\"\n />\n <label [for]=\"control.name + '-' + option\">{{ option }}</label>\n </div>\n }\n }\n\n <validation-messages\n [control]=\"form.get(control.name)\"\n [controlName]=\"control.name\"\n [config]=\"control\"\n ></validation-messages>\n </section>\n }\n }\n }\n <button type=\"submit\" [disabled]=\"form.invalid\">Submit</button>\n</form>\n" }]
}] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC1mb3Jtcy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9uZ0Zvcm0vc3JjL2FwcC9kZWZhdWx0LWZvcm1zL2RlZmF1bHQtZm9ybXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vbmdGb3JtL3NyYy9hcHAvZGVmYXVsdC1mb3Jtcy9kZWZhdWx0LWZvcm1zLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNkRHO0FBQ0gsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLHNEQUFzRCxDQUFDO0FBQ25HLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDOzs7O0FBZXZELE1BQU0sT0FBTyxxQkFBc0IsU0FBUSxrQkFBa0I7d0dBQWhELHFCQUFxQjs0RkFBckIscUJBQXFCLGdHQ2pGbEMseXlFQW1FQSwyQ0RNSSxtQkFBbUIsMnVEQUNuQixZQUFZLGlOQUNaLFdBQVcsK0JBQ1gsMkJBQTJCOzs0RkFLbEIscUJBQXFCO2tCQWJqQyxTQUFTOytCQUNFLGVBQWUsY0FDYixJQUFJLFdBQ1A7d0JBQ1Asa0JBQWtCO3dCQUNsQixtQkFBbUI7d0JBQ25CLFlBQVk7d0JBQ1osV0FBVzt3QkFDWCwyQkFBMkI7cUJBQzVCLG1CQUVnQix1QkFBdUIsQ0FBQyxNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAY29tcG9uZW50IERlZmF1bHRGb3Jtc0NvbXBvbmVudFxuICogQGRlc2NyaXB0aW9uXG4gKiBUaGUgYERlZmF1bHRGb3Jtc0NvbXBvbmVudGAgaXMgYW4gQW5ndWxhciBzdGFuZGFsb25lIGNvbXBvbmVudCB0aGF0IHByb3ZpZGVzIGEgZHluYW1pYyBmb3JtIGdlbmVyYXRpb25cbiAqIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBJdCB1c2VzIHJlYWN0aXZlIGZvcm1zIHRvIGhhbmRsZSBmb3JtIGNvbnRyb2xzIGFuZCB0aGVpciB2YWxpZGF0aW9ucy5cbiAqIFRoZSBjb21wb25lbnQgaXMgZGVzaWduZWQgdG8gYmUgaGlnaGx5IGNvbmZpZ3VyYWJsZSBhbmQgc3VwcG9ydHMgdmFyaW91cyB0eXBlcyBvZiBmb3JtIHZhbGlkYXRvcnMuXG4gKlxuICogQHNlbGVjdG9yIGRlZmF1bHQtZm9ybXNcbiAqIEBzdGFuZGFsb25lIHRydWVcbiAqIEBpbXBvcnRzXG4gKiAtIFJlYWN0aXZlRm9ybXNNb2R1bGVcbiAqIC0gQ29tbW9uTW9kdWxlXG4gKiAtIEZvcm1zTW9kdWxlXG4gKiAtIFZhbGlkYXRpb25NZXNzYWdlc0NvbXBvbmVudFxuICogQHRlbXBsYXRlVXJsIC4vZGVmYXVsdC1mb3Jtcy5jb21wb25lbnQuaHRtbFxuICogQHN0eWxlVXJsIC4vZGVmYXVsdC1mb3Jtcy5jb21wb25lbnQuY3NzXG4gKiBAY2hhbmdlRGV0ZWN0aW9uIENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaFxuICpcbiAqIEBpbnB1dFxuICogLSBgZm9ybU5hbWU6IHN0cmluZ2AgLSBUaGUgbmFtZSBvZiB0aGUgZm9ybS5cbiAqIC0gYGNvbnRyb2xzOiBGb3JtQ29udHJvbENvbmZpZ1tdYCAtIEFuIGFycmF5IG9mIGZvcm0gY29udHJvbCBjb25maWd1cmF0aW9ucy5cbiAqXG4gKiBAb3V0cHV0XG4gKiAtIGBmb3JtU3VibWl0OiBFdmVudEVtaXR0ZXI8UmVjb3JkPHN0cmluZywgYW55Pj5gIC0gRW1pdHMgdGhlIGZvcm0gdmFsdWUgd2hlbiB0aGUgZm9ybSBpcyBzdWJtaXR0ZWQuXG4gKlxuICogQGNsYXNzIERlZmF1bHRGb3Jtc0NvbXBvbmVudFxuICogQGltcGxlbWVudHMgT25Jbml0XG4gKlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGZvcm1OYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGZvcm0uXG4gKiBAcHJvcGVydHkge0Zvcm1Db250cm9sQ29uZmlnW119IGNvbnRyb2xzIC0gVGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBmb3JtIGNvbnRyb2xzLlxuICogQHByb3BlcnR5IHtFdmVudEVtaXR0ZXI8UmVjb3JkPHN0cmluZywgYW55Pj59IGZvcm1TdWJtaXQgLSBFdmVudCBlbWl0dGVyIGZvciBmb3JtIHN1Ym1pc3Npb24uXG4gKiBAcHJvcGVydHkge0Zvcm1Hcm91cH0gZm9ybSAtIFRoZSByZWFjdGl2ZSBmb3JtIGdyb3VwIGluc3RhbmNlLlxuICogQHByb3BlcnR5IHtCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj59IGZvcm1DaGFuZ2VzJCAtIEEgc3ViamVjdCB0byB0cmFjayBmb3JtIGNoYW5nZXMuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge0Zvcm1CdWlsZGVyfSBmYiAtIEFuZ3VsYXIncyBGb3JtQnVpbGRlciBzZXJ2aWNlIHRvIGNyZWF0ZSBmb3JtIGNvbnRyb2xzLlxuICogQHBhcmFtIHtDaGFuZ2VEZXRlY3RvclJlZn0gY2RyIC0gQW5ndWxhcidzIENoYW5nZURldGVjdG9yUmVmIHNlcnZpY2UgdG8gbWFudWFsbHkgdHJpZ2dlciBjaGFuZ2UgZGV0ZWN0aW9uLlxuICpcbiAqIEBtZXRob2QgbmdPbkluaXRcbiAqIEBkZXNjcmlwdGlvbiBMaWZlY3ljbGUgaG9vayB0aGF0IGlzIGNhbGxlZCBhZnRlciB0aGUgY29tcG9uZW50J3MgdmlldyBoYXMgYmVlbiBpbml0aWFsaXplZC4gSXQgaW5pdGlhbGl6ZXMgdGhlIGZvcm0uXG4gKlxuICogQG1ldGhvZCBpbml0aWFsaXplRm9ybVxuICogQGRlc2NyaXB0aW9uIEluaXRpYWxpemVzIHRoZSBmb3JtIGJ5IGNyZWF0aW5nIGZvcm0gY29udHJvbHMgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIHNldHMgdXAgdmFsdWUgY2hhbmdlIHN1YnNjcmlwdGlvbnMuXG4gKlxuICogQG1ldGhvZCBnZXRWYWxpZGF0b3JzXG4gKiBAcGFyYW0ge0Zvcm1Db250cm9sQ29uZmlnfSBjb250cm9sIC0gVGhlIGNvbmZpZ3VyYXRpb24gZm9yIGEgZm9ybSBjb250cm9sLlxuICogQHJldHVybnMge1ZhbGlkYXRvckZuW119IEFuIGFycmF5IG9mIHZhbGlkYXRvcnMgZm9yIHRoZSBmb3JtIGNvbnRyb2wuXG4gKiBAZGVzY3JpcHRpb24gR2VuZXJhdGVzIGFuIGFycmF5IG9mIHZhbGlkYXRvcnMgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbnRyb2wgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAbWV0aG9kIHVwZGF0ZVZhbGlkYXRvcnNcbiAqIEBwYXJhbSB7QWJzdHJhY3RDb250cm9sfSBjb250cm9sIC0gVGhlIGZvcm0gY29udHJvbCB0byB1cGRhdGUgdmFsaWRhdG9ycyBmb3IuXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgY3VycmVudCB2YWx1ZSBvZiB0aGUgZm9ybSBjb250cm9sLlxuICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgdGhlIHZhbGlkYXRvcnMgZm9yIGEgZm9ybSBjb250cm9sIGJhc2VkIG9uIGl0cyBjdXJyZW50IHZhbHVlLlxuICpcbiAqIEBtZXRob2Qgc2hvdWxkUmVxdWlyZVZhbGlkYXRpb25cbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBjaGVjayBmb3IgdmFsaWRhdGlvbiByZXF1aXJlbWVudC5cbiAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSB2YWx1ZSByZXF1aXJlcyB2YWxpZGF0aW9uLlxuICogQGRlc2NyaXB0aW9uIERldGVybWluZXMgaWYgYSB2YWx1ZSBzaG91bGQgcmVxdWlyZSB2YWxpZGF0aW9uLlxuICpcbiAqIEBtZXRob2Qgb25TdWJtaXRcbiAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIHRoZSBmb3JtIHN1Ym1pc3Npb24uIE1hcmtzIHRoZSBmb3JtIGFzIHRvdWNoZWQgYW5kIGRpcnR5LCB2YWxpZGF0ZXMgdGhlIGZvcm0sIGVtaXRzIHRoZSBmb3JtIHZhbHVlIGlmIHZhbGlkLCBhbmQgcmVzZXRzIHRoZSBmb3JtLlxuICovXG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUmVhY3RpdmVGb3Jtc01vZHVsZSwgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBWYWxpZGF0aW9uTWVzc2FnZXNDb21wb25lbnQgfSBmcm9tICcuLi92YWxpZGF0aW9uLW1lc3NhZ2VzL3ZhbGlkYXRpb24tbWVzc2FnZXMuY29tcG9uZW50JztcbmltcG9ydCB7IEJhc2VGb3Jtc0NvbXBvbmVudCB9IGZyb20gJy4uL2Jhc2UuY29tcG9uZW50JztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZGVmYXVsdC1mb3JtcycsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBCYXNlRm9ybXNDb21wb25lbnQsXG4gICAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgVmFsaWRhdGlvbk1lc3NhZ2VzQ29tcG9uZW50LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vZGVmYXVsdC1mb3Jtcy5jb21wb25lbnQuaHRtbCcsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBEZWZhdWx0Rm9ybXNDb21wb25lbnQgZXh0ZW5kcyBCYXNlRm9ybXNDb21wb25lbnQge31cbiIsIjxmb3JtIFtmb3JtR3JvdXBdPVwiZm9ybVwiIFthdHRyLm5hbWVdPVwiZm9ybU5hbWUoKVwiIChuZ1N1Ym1pdCk9XCJvblN1Ym1pdCgpXCI+XG4gIEBmb3IgKGNvbnRyb2wgb2YgY29udHJvbHMoKTsgdHJhY2sgJGluZGV4KSB7XG4gICAgQGlmIChjb250cm9sLnVpRnJhbWV3b3JrID09PSBcImRlZmF1bHRcIiB8fCAhY29udHJvbC51aUZyYW1ld29yaykge1xuICAgICAgQGlmIChmb3JtLmdldChjb250cm9sLm5hbWUpKSB7XG4gICAgICAgIDxzZWN0aW9uIFtuZ0NsYXNzXT1cImNvbnRyb2wuY2xhc3NcIiBbbmdTdHlsZV09XCJjb250cm9sLnN0eWxlXCI+XG4gICAgICAgICAgQGlmIChjb250cm9sLmxhYmVsKSB7XG4gICAgICAgICAgICA8bGFiZWxcbiAgICAgICAgICAgICAgW2F0dHIuZm9yXT1cImNvbnRyb2wubmFtZVwiXG4gICAgICAgICAgICAgIFtuZ0NsYXNzXT1cImNvbnRyb2wubGFiZWxDbGFzc1wiXG4gICAgICAgICAgICAgIFtuZ1N0eWxlXT1cImNvbnRyb2wubGFiZWxTdHlsZVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7IGNvbnRyb2wubGFiZWwgfX1cbiAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgQGlmIChjb250cm9sLnR5cGUgPT09IFwiaW5wdXRcIikge1xuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIFtmb3JtQ29udHJvbE5hbWVdPVwiY29udHJvbC5uYW1lXCJcbiAgICAgICAgICAgICAgW2lkXT1cImNvbnRyb2wubmFtZVwiXG4gICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgfVxuICAgICAgICAgIEBpZiAoY29udHJvbC50eXBlID09PSBcInNlbGVjdFwiKSB7XG4gICAgICAgICAgICA8c2VsZWN0IFtmb3JtQ29udHJvbE5hbWVdPVwiY29udHJvbC5uYW1lXCIgW2lkXT1cImNvbnRyb2wubmFtZVwiPlxuICAgICAgICAgICAgICBAZm9yIChvcHRpb24gb2YgY29udHJvbC5vcHRpb25zOyB0cmFjayAkaW5kZXgpIHtcbiAgICAgICAgICAgICAgICA8b3B0aW9uIFt2YWx1ZV09XCJvcHRpb25cIj57eyBvcHRpb24gfX08L29wdGlvbj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgICAgfVxuICAgICAgICAgIEBpZiAoY29udHJvbC50eXBlID09PSBcInRleHRhcmVhXCIpIHtcbiAgICAgICAgICAgIDx0ZXh0YXJlYVxuICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xOYW1lXT1cImNvbnRyb2wubmFtZVwiXG4gICAgICAgICAgICAgIFtpZF09XCJjb250cm9sLm5hbWVcIlxuICAgICAgICAgICAgPjwvdGV4dGFyZWE+XG4gICAgICAgICAgfVxuICAgICAgICAgIEBpZiAoY29udHJvbC50eXBlID09PSBcImNoZWNrYm94XCIpIHtcbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xOYW1lXT1cImNvbnRyb2wubmFtZVwiXG4gICAgICAgICAgICAgIFtpZF09XCJjb250cm9sLm5hbWVcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICB9XG4gICAgICAgICAgQGlmIChjb250cm9sLnR5cGUgPT09IFwicmFkaW9cIikge1xuICAgICAgICAgICAgQGZvciAob3B0aW9uIG9mIGNvbnRyb2wub3B0aW9ucyA/PyBbXTsgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICB0eXBlPVwicmFkaW9cIlxuICAgICAgICAgICAgICAgICAgW2Zvcm1Db250cm9sTmFtZV09XCJjb250cm9sLm5hbWVcIlxuICAgICAgICAgICAgICAgICAgW2lkXT1cImNvbnRyb2wubmFtZSArICctJyArIG9wdGlvblwiXG4gICAgICAgICAgICAgICAgICBbdmFsdWVdPVwib3B0aW9uXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDxsYWJlbCBbZm9yXT1cImNvbnRyb2wubmFtZSArICctJyArIG9wdGlvblwiPnt7IG9wdGlvbiB9fTwvbGFiZWw+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIDx2YWxpZGF0aW9uLW1lc3NhZ2VzXG4gICAgICAgICAgICBbY29udHJvbF09XCJmb3JtLmdldChjb250cm9sLm5hbWUpXCJcbiAgICAgICAgICAgIFtjb250cm9sTmFtZV09XCJjb250cm9sLm5hbWVcIlxuICAgICAgICAgICAgW2NvbmZpZ109XCJjb250cm9sXCJcbiAgICAgICAgICA+PC92YWxpZGF0aW9uLW1lc3NhZ2VzPlxuICAgICAgICA8L3NlY3Rpb24+XG4gICAgICB9XG4gICAgfVxuICB9XG4gIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiIFtkaXNhYmxlZF09XCJmb3JtLmludmFsaWRcIj5TdWJtaXQ8L2J1dHRvbj5cbjwvZm9ybT5cbiJdfQ==