@edugouvfr/ngx-dsfr
Version:
NgxDsfr est un portage Angular des éléments d'interface du Système de Design de l'État Français (DSFR).
147 lines • 30.6 kB
JavaScript
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, forwardRef, Input, Output, ViewEncapsulation, } from '@angular/core';
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { DefaultControlComponent, DsfrI18nPipe, DsfrSeverityConst, isStringEmptyOrNull, } from '../../shared';
import { EduMessageSeverityDirective } from '../../shared/directives/message-severity.directive';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@angular/forms";
export class DsfrFormSelectComponent extends DefaultControlComponent {
constructor() {
super(...arguments);
/**
* Indique que le champ est obligatoire, nécessaire du point de vue de l'accessibilité.
*/
this.required = false;
/**
* Message d'information lié au composant
*/
this.message = undefined;
/**
* Cache le label visuellement en le laissant disponible aux lecteurs d'écran.
*/
this.labelSrOnly = false;
/**
* Output équivalent de (ngModelChange) si celui n'est pas disponible.
*/
this.selectChange = new EventEmitter();
/**
* @internal
* https://github.com/angular/angular/issues/50233 : issue performance with ng-container/ng-template inside select for Firefox
* Dans le cas ou il n'y a pas de groupe, supprimer le 'if' côté template
* FIXME ticket toujours non résolu (v1.13)
*/
this.noGroup = true;
/** @internal fonction de comparaison */
this.compareFn = Object.is;
// Afin de pouvoir utiliser le type dans l'HTML
/** @internal */
this.DsfrSeverity = DsfrSeverityConst;
this.trackByIndex = (index) => {
return index;
};
}
/**
* @deprecated since 1.2, utiliser `placeholder` à la place (sans H majuscule).
*/
get placeHolder() {
return this.placeholder;
}
get options() {
return this._options;
}
/**
* @deprecated since 1.2, utiliser `placeholder` à la place (sans H majuscule).
*/
set placeHolder(value) {
this.placeholder = value;
}
/**
* Le modèle de présentation permettant de transmettre la liste des options.
*/
set options(value) {
this._options = value;
if (this._options && this._options.length && this._options.find((o) => o.options)) {
this.noGroup = false;
}
}
/** Personnalisation de la comparaison. CompareWith est une fonction qui a deux arguments: valeur option1 et valeur option2.
Si compareWith est fournie, sélection de l'option en fonction du retour de la fonction. */
set compareWith(fn) {
if (typeof fn !== 'function') {
throw Error('`compareWith` must be a function.');
}
this.compareFn = fn;
}
/** @internal */
ngOnInit() {
super.ngOnInit();
this.messagesGroupId = `${this.inputId}-messages`;
}
ngOnChanges({ value }) {
if (value && this.value && this.options.length) {
if (!this.findOption(this.value, this.options)) {
this.value = undefined;
}
}
}
/** @internal */
onChange() {
// Comme on a le double binding, la valeur est déjà à jour
this.selectChange.emit(this.value);
}
/** @internal */
hasMessage(severity) {
return !isStringEmptyOrNull(this.message) && severity === this.messageSeverity;
}
findOption(value, options) {
return options?.find((option) => this.compareFn(value, option.value) ||
option.value === value ||
(option.options && this.findOption(value, option.options)));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DsfrFormSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DsfrFormSelectComponent, isStandalone: true, selector: "dsfr-form-select", inputs: { placeholder: "placeholder", required: "required", ariaLabel: "ariaLabel", ariaInvalid: "ariaInvalid", error: "error", valid: "valid", message: "message", messageSeverity: "messageSeverity", labelSrOnly: "labelSrOnly", placeHolder: "placeHolder", options: "options", compareWith: "compareWith" }, outputs: { selectChange: "selectChange" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DsfrFormSelectComponent),
multi: true,
},
], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div\n [ngClass]=\"{\n 'fr-select-group': true,\n 'fr-select-group--disabled': disabled,\n 'fr-select-group--valid':\n valid || (message && (messageSeverity === DsfrSeverity.SUCCESS || messageSeverity === DsfrSeverity.VALID)),\n 'fr-select-group--error': error || (message && messageSeverity === DsfrSeverity.ERROR),\n 'fr-input-group--info': message && messageSeverity === DsfrSeverity.INFO,\n 'fr-input-group--warning': message && messageSeverity === DsfrSeverity.WARNING,\n }\">\n <label class=\"fr-label\" [ngClass]=\"{ 'fr-sr-only': labelSrOnly }\" [for]=\"inputId\">\n @if (label) {\n {{ label }}\n } @else {\n <ng-content select=\"[label]\"></ng-content>\n }\n @if (hint) {\n <span class=\"fr-hint-text\">{{ hint }}</span>\n }\n </label>\n\n <!-- Select sans groupes. Duplication du select pour pb perf. affichage d'options sur firefox si utilisation d'un if -->\n @if (noGroup) {\n <select\n class=\"fr-select\"\n [id]=\"inputId\"\n [attr.name]=\"name || null\"\n [(ngModel)]=\"value\"\n [attr.aria-describedby]=\"message ? messagesGroupId : null\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-invalid]=\"ariaInvalid || null\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [compareWith]=\"compareFn\"\n (change)=\"onChange()\">\n @if (!value) {\n <option style=\"display: none\" aria-hidden=\"true\" [value]=\"value\" selected disabled>\n {{ placeholder ?? ('select.placeholder' | dsfrI18n) }}\n </option>\n }\n @for (option of options; track trackByIndex($index)) {\n <option [ngValue]=\"option.value\" [disabled]=\"option.disabled || null\">\n {{ option.label }}\n </option>\n }\n </select>\n } @else {\n <!-- Select avec groupes. Ne sera pas optimis\u00E9 pour FF -->\n <select\n class=\"fr-select\"\n [id]=\"inputId\"\n [attr.name]=\"name || null\"\n [(ngModel)]=\"value\"\n [attr.aria-describedby]=\"message ? messagesGroupId : null\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-invalid]=\"ariaInvalid || null\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [compareWith]=\"compareFn\"\n (change)=\"onChange()\">\n @if (!value) {\n <option style=\"display: none\" aria-hidden=\"true\" [value]=\"value\" selected disabled>\n {{ placeholder ?? ('select.placeholder' | dsfrI18n) }}\n </option>\n }\n @for (option of options; track trackByIndex($index)) {\n @if (option.options) {\n <optgroup [label]=\"option.label\">\n @for (option of option.options; track trackByIndex($index)) {\n <option [ngValue]=\"option.value\" [disabled]=\"option.disabled || null\">\n {{ option.label }}\n </option>\n }\n </optgroup>\n } @else {\n <option [ngValue]=\"option.value\" [disabled]=\"option.disabled || null\">\n {{ option.label }}\n </option>\n }\n }\n </select>\n }\n\n <div [id]=\"messagesGroupId\" class=\"fr-messages-group\" aria-live=\"polite\">\n @if (message) {\n <p class=\"fr-message\" [eduMessageSeverity]=\"messageSeverity\">\n {{ message }}\n </p>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: DsfrI18nPipe, name: "dsfrI18n" }, { kind: "directive", type: EduMessageSeverityDirective, selector: "[eduMessageSeverity]", inputs: ["eduMessageSeverity"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DsfrFormSelectComponent, decorators: [{
type: Component,
args: [{ selector: 'dsfr-form-select', encapsulation: ViewEncapsulation.None, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DsfrFormSelectComponent),
multi: true,
},
], standalone: true, imports: [CommonModule, FormsModule, DsfrI18nPipe, EduMessageSeverityDirective], template: "<div\n [ngClass]=\"{\n 'fr-select-group': true,\n 'fr-select-group--disabled': disabled,\n 'fr-select-group--valid':\n valid || (message && (messageSeverity === DsfrSeverity.SUCCESS || messageSeverity === DsfrSeverity.VALID)),\n 'fr-select-group--error': error || (message && messageSeverity === DsfrSeverity.ERROR),\n 'fr-input-group--info': message && messageSeverity === DsfrSeverity.INFO,\n 'fr-input-group--warning': message && messageSeverity === DsfrSeverity.WARNING,\n }\">\n <label class=\"fr-label\" [ngClass]=\"{ 'fr-sr-only': labelSrOnly }\" [for]=\"inputId\">\n @if (label) {\n {{ label }}\n } @else {\n <ng-content select=\"[label]\"></ng-content>\n }\n @if (hint) {\n <span class=\"fr-hint-text\">{{ hint }}</span>\n }\n </label>\n\n <!-- Select sans groupes. Duplication du select pour pb perf. affichage d'options sur firefox si utilisation d'un if -->\n @if (noGroup) {\n <select\n class=\"fr-select\"\n [id]=\"inputId\"\n [attr.name]=\"name || null\"\n [(ngModel)]=\"value\"\n [attr.aria-describedby]=\"message ? messagesGroupId : null\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-invalid]=\"ariaInvalid || null\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [compareWith]=\"compareFn\"\n (change)=\"onChange()\">\n @if (!value) {\n <option style=\"display: none\" aria-hidden=\"true\" [value]=\"value\" selected disabled>\n {{ placeholder ?? ('select.placeholder' | dsfrI18n) }}\n </option>\n }\n @for (option of options; track trackByIndex($index)) {\n <option [ngValue]=\"option.value\" [disabled]=\"option.disabled || null\">\n {{ option.label }}\n </option>\n }\n </select>\n } @else {\n <!-- Select avec groupes. Ne sera pas optimis\u00E9 pour FF -->\n <select\n class=\"fr-select\"\n [id]=\"inputId\"\n [attr.name]=\"name || null\"\n [(ngModel)]=\"value\"\n [attr.aria-describedby]=\"message ? messagesGroupId : null\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-invalid]=\"ariaInvalid || null\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [compareWith]=\"compareFn\"\n (change)=\"onChange()\">\n @if (!value) {\n <option style=\"display: none\" aria-hidden=\"true\" [value]=\"value\" selected disabled>\n {{ placeholder ?? ('select.placeholder' | dsfrI18n) }}\n </option>\n }\n @for (option of options; track trackByIndex($index)) {\n @if (option.options) {\n <optgroup [label]=\"option.label\">\n @for (option of option.options; track trackByIndex($index)) {\n <option [ngValue]=\"option.value\" [disabled]=\"option.disabled || null\">\n {{ option.label }}\n </option>\n }\n </optgroup>\n } @else {\n <option [ngValue]=\"option.value\" [disabled]=\"option.disabled || null\">\n {{ option.label }}\n </option>\n }\n }\n </select>\n }\n\n <div [id]=\"messagesGroupId\" class=\"fr-messages-group\" aria-live=\"polite\">\n @if (message) {\n <p class=\"fr-message\" [eduMessageSeverity]=\"messageSeverity\">\n {{ message }}\n </p>\n }\n </div>\n</div>\n" }]
}], propDecorators: { placeholder: [{
type: Input
}], required: [{
type: Input
}], ariaLabel: [{
type: Input
}], ariaInvalid: [{
type: Input
}], error: [{
type: Input
}], valid: [{
type: Input
}], message: [{
type: Input
}], messageSeverity: [{
type: Input
}], labelSrOnly: [{
type: Input
}], selectChange: [{
type: Output
}], placeHolder: [{
type: Input
}], options: [{
type: Input
}], compareWith: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS1zZWxlY3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWRzZnItY29tcG9uZW50cy9zcmMvbGliL2Zvcm1zL2Zvcm0tc2VsZWN0L2Zvcm0tc2VsZWN0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1kc2ZyLWNvbXBvbmVudHMvc3JjL2xpYi9mb3Jtcy9mb3JtLXNlbGVjdC9mb3JtLXNlbGVjdC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUNMLFNBQVMsRUFDVCxZQUFZLEVBQ1osVUFBVSxFQUNWLEtBQUssRUFHTCxNQUFNLEVBRU4saUJBQWlCLEdBQ2xCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxXQUFXLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFlBQVksRUFHWixpQkFBaUIsRUFDakIsbUJBQW1CLEdBQ3BCLE1BQU0sY0FBYyxDQUFDO0FBQ3RCLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLG9EQUFvRCxDQUFDOzs7O0FBZ0JqRyxNQUFNLE9BQU8sdUJBQXdCLFNBQVEsdUJBQTRCO0lBZHpFOztRQXFCRTs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUEwQjFCOztXQUVHO1FBQ00sWUFBTyxHQUF1QixTQUFTLENBQUM7UUFPakQ7O1dBRUc7UUFDTSxnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUU3Qjs7V0FFRztRQUNPLGlCQUFZLEdBQUcsSUFBSSxZQUFZLEVBQU8sQ0FBQztRQUlqRDs7Ozs7V0FLRztRQUNILFlBQU8sR0FBWSxJQUFJLENBQUM7UUFFeEIsd0NBQXdDO1FBQ3hDLGNBQVMsR0FBa0MsTUFBTSxD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Qyx1QkFBdUIsQ0FBQztnQkFDdEQsS0FBSyxFQUFFLElBQUk7YUFDWjtTQUNGLHNFQ2pDSCwyeEdBMkZBLDJDRHhEWSxZQUFZLDRIQUFFLFdBQVcsazlCQUFFLFlBQVksaURBQUUsMkJBQTJCOzs0RkFFbkUsdUJBQXVCO2tCQWRuQyxTQUFTOytCQUNFLGtCQUFrQixpQkFFYixpQkFBaUIsQ0FBQyxJQUFJLGFBQzFCO3dCQUNUOzRCQUNFLE9BQU8sRUFBRSxpQkFBaUI7NEJBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLHdCQUF3QixDQUFDOzRCQUN0RCxLQUFLLEVBQUUsSUFBSTt5QkFDWjtxQkFDRixjQUNXLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLDJCQUEyQixDQUFDOzhCQU90RSxXQUFXO3NCQUFuQixLQUFLO2dCQUtHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBS0csU0FBUztzQkFBakIsS0FBSztnQkFLRyxXQUFXO3NCQUFuQixLQUFLO2dCQU9HLEtBQUs7c0JBQWIsS0FBSztnQkFPRyxLQUFLO3NCQUFiLEtBQUs7Z0JBS0csT0FBTztzQkFBZixLQUFLO2dCQUtHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBS0csV0FBVztzQkFBbkIsS0FBSztnQkFLSSxZQUFZO3NCQUFyQixNQUFNO2dCQW9DTSxXQUFXO3NCQUF2QixLQUFLO2dCQU9PLE9BQU87c0JBQW5CLEtBQUs7Z0JBVUYsV0FBVztzQkFEZCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBmb3J3YXJkUmVmLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVmlld0VuY2Fwc3VsYXRpb24sXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHtcbiAgRGVmYXVsdENvbnRyb2xDb21wb25lbnQsXG4gIERzZnJJMThuUGlwZSxcbiAgRHNmclNlbGVjdE9wdGlvbixcbiAgRHNmclNldmVyaXR5LFxuICBEc2ZyU2V2ZXJpdHlDb25zdCxcbiAgaXNTdHJpbmdFbXB0eU9yTnVsbCxcbn0gZnJvbSAnLi4vLi4vc2hhcmVkJztcbmltcG9ydCB7IEVkdU1lc3NhZ2VTZXZlcml0eURpcmVjdGl2ZSB9IGZyb20gJy4uLy4uL3NoYXJlZC9kaXJlY3RpdmVzL21lc3NhZ2Utc2V2ZXJpdHkuZGlyZWN0aXZlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZHNmci1mb3JtLXNlbGVjdCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9mb3JtLXNlbGVjdC5jb21wb25lbnQuaHRtbCcsXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIHByb3ZpZGVyczogW1xuICAgIHtcbiAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gRHNmckZvcm1TZWxlY3RDb21wb25lbnQpLFxuICAgICAgbXVsdGk6IHRydWUsXG4gICAgfSxcbiAgXSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgRm9ybXNNb2R1bGUsIERzZnJJMThuUGlwZSwgRWR1TWVzc2FnZVNldmVyaXR5RGlyZWN0aXZlXSxcbn0pXG5leHBvcnQgY2xhc3MgRHNmckZvcm1TZWxlY3RDb21wb25lbnQgZXh0ZW5kcyBEZWZhdWx0Q29udHJvbENvbXBvbmVudDxhbnk+IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMge1xuICAvKipcbiAgICogUGVybWV0IGRlIHBlcnNvbm5hbGlzZXIgbGEgcHJlbWnDqHJlIG9wdGlvbiAobm9uIHPDqWxlY3Rpb25uYWJsZSkuIENldHRlIHByb3ByacOpdMOpIGVzdCBwb3NpdGlvbm7DqWUgw6AgdW5lIHZhbGV1ciBwYXJcbiAgICogZMOpZmF1dCAoZXggOiBTw6lsZWN0aW9ubmV6IHVuZSBvcHRpb24pIGludGVybmF0aW9uYWxpc8OpZS5cbiAgICovXG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEluZGlxdWUgcXVlIGxlIGNoYW1wIGVzdCBvYmxpZ2F0b2lyZSwgbsOpY2Vzc2FpcmUgZHUgcG9pbnQgZGUgdnVlIGRlIGwnYWNjZXNzaWJpbGl0w6kuXG4gICAqL1xuICBASW5wdXQoKSByZXF1aXJlZCA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBQZXJtZXQgZCdham91dGVyIHVuIGF0dHJpYnV0ICdhcmlhLWxhYmVsJyBzdXIgbGUgY2hhbXAgZGUgZm9ybXVsYWlyZSBlbiBjYXMgZGUgYmVzb2luLlxuICAgKi9cbiAgQElucHV0KCkgYXJpYUxhYmVsOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFqb3V0ZXIgbCdhdHRyaWJ1dCAnYXJpYS1pbnZhbGlkJyBzdXIgbGUgY2hhbXAgZGUgZm9ybXVsYWlyZS5cbiAgICovXG4gIEBJbnB1dCgpIGFyaWFJbnZhbGlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE1lc3NhZ2UgZCdlcnJldXIsIHF1YW5kIGlsIGVzdCBwcsOpc2VudCBsZXMgY291bGV1cnMgZHUgY29udHLDtGxlIGNoYW5nZW50LlxuICAgKlxuICAgKiAgQGRlcHJlY2F0ZWQgKEBzaW5jZSAxLjEzLjApXG4gICAqL1xuICBASW5wdXQoKSBlcnJvcjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNZXNzYWdlIGRlIHZhbGlkYXRpb24sIHF1YW5kIGlsIGVzdCBwcsOpc2VudCBsZXMgY291bGV1cnMgZHUgY29udHLDtGxlIGNoYW5nZW50LlxuICAgKlxuICAgKiAgQGRlcHJlY2F0ZWQgKEBzaW5jZSAxLjEzLjApXG4gICAqL1xuICBASW5wdXQoKSB2YWxpZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNZXNzYWdlIGQnaW5mb3JtYXRpb24gbGnDqSBhdSBjb21wb3NhbnRcbiAgICovXG4gIEBJbnB1dCgpIG1lc3NhZ2U6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogUmVwcsOpc2VudGUgbGEgc8OpdsOpcml0w6kgZHUgbWVzc2FnZS5cbiAgICovXG4gIEBJbnB1dCgpIG1lc3NhZ2VTZXZlcml0eTogRHNmclNldmVyaXR5O1xuXG4gIC8qKlxuICAgKiBDYWNoZSBsZSBsYWJlbCB2aXN1ZWxsZW1lbnQgZW4gbGUgbGFpc3NhbnQgZGlzcG9uaWJsZSBhdXggbGVjdGV1cnMgZCfDqWNyYW4uXG4gICAqL1xuICBASW5wdXQoKSBsYWJlbFNyT25seSA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBPdXRwdXQgw6lxdWl2YWxlbnQgZGUgKG5nTW9kZWxDaGFuZ2UpIHNpIGNlbHVpIG4nZXN0IHBhcyBkaXNwb25pYmxlLlxuICAgKi9cbiAgQE91dHB1dCgpIHNlbGVjdENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIC8qKiBAaW50ZXJuYWwgKi8gbWVzc2FnZXNHcm91cElkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKiBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2lzc3Vlcy81MDIzMyA6IGlzc3VlIHBlcmZvcm1hbmNlIHdpdGggbmctY29udGFpbmVyL25nLXRlbXBsYXRlIGluc2lkZSBzZWxlY3QgZm9yIEZpcmVmb3hcbiAgICogRGFucyBsZSBjYXMgb3UgaWwgbid5IGEgcGFzIGRlIGdyb3VwZSwgc3VwcHJpbWVyIGxlICdpZicgY8O0dMOpIHRlbXBsYXRlXG4gICAqIEZJWE1FIHRpY2tldCB0b3Vqb3VycyBub24gcsOpc29sdSAodjEuMTMpXG4gICAqL1xuICBub0dyb3VwOiBib29sZWFuID0gdHJ1ZTtcblxuICAvKiogQGludGVybmFsIGZvbmN0aW9uIGRlIGNvbXBhcmFpc29uICovXG4gIGNvbXBhcmVGbjogKG8xOiBhbnksIG8yOiBhbnkpID0+IGJvb2xlYW4gPSBPYmplY3QuaXM7XG5cbiAgLy8gQWZpbiBkZSBwb3V2b2lyIHV0aWxpc2VyIGxlIHR5cGUgZGFucyBsJ0hUTUxcbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgRHNmclNldmVyaXR5ID0gRHNmclNldmVyaXR5Q29uc3Q7XG5cbiAgLyogZml4bWUgOiByZW1wbGFjZXIgcGFyIHVuIHNpZ25hbCBpbnB1dCBzaSBodHRwczovL2dpdGh1Yi5jb20vY29tcG9kb2MvY29tcG9kb2MvcHVsbC8xNDkxICovXG4gIHByaXZhdGUgX29wdGlvbnM6IERzZnJTZWxlY3RPcHRpb25bXTtcblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQgc2luY2UgMS4yLCB1dGlsaXNlciBgcGxhY2Vob2xkZXJgIMOgIGxhIHBsYWNlIChzYW5zIEggbWFqdXNjdWxlKS5cbiAgICovXG4gIGdldCBwbGFjZUhvbGRlcigpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnBsYWNlaG9sZGVyO1xuICB9XG5cbiAgZ2V0IG9wdGlvbnMoKTogRHNmclNlbGVjdE9wdGlvbltdIHtcbiAgICByZXR1cm4gdGhpcy5fb3B0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCBzaW5jZSAxLjIsIHV0aWxpc2VyIGBwbGFjZWhvbGRlcmAgw6AgbGEgcGxhY2UgKHNhbnMgSCBtYWp1c2N1bGUpLlxuICAgKi9cbiAgQElucHV0KCkgc2V0IHBsYWNlSG9sZGVyKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgICB0aGlzLnBsYWNlaG9sZGVyID0gdmFsdWU7XG4gIH1cblxuICAvKipcbiAgICogTGUgbW9kw6hsZSBkZSBwcsOpc2VudGF0aW9uIHBlcm1ldHRhbnQgZGUgdHJhbnNtZXR0cmUgbGEgbGlzdGUgZGVzIG9wdGlvbnMuXG4gICAqL1xuICBASW5wdXQoKSBzZXQgb3B0aW9ucyh2YWx1ZTogRHNmclNlbGVjdE9wdGlvbltdKSB7XG4gICAgdGhpcy5fb3B0aW9ucyA9IHZhbHVlO1xuICAgIGlmICh0aGlzLl9vcHRpb25zICYmIHRoaXMuX29wdGlvbnMubGVuZ3RoICYmIHRoaXMuX29wdGlvbnMuZmluZCgobykgPT4gby5vcHRpb25zKSkge1xuICAgICAgdGhpcy5ub0dyb3VwID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqIFBlcnNvbm5hbGlzYXRpb24gZGUgbGEgY29tcGFyYWlzb24uIENvbXBhcmVXaXRoIGVzdCB1bmUgZm9uY3Rpb24gcXVpIGEgZGV1eCBhcmd1bWVudHM6IHZhbGV1ciBvcHRpb24xIGV0IHZhbGV1ciBvcHRpb24yLlxuICBTaSBjb21wYXJlV2l0aCBlc3QgZm91cm5pZSwgc8OpbGVjdGlvbiBkZSBsJ29wdGlvbiBlbiBmb25jdGlvbiBkdSByZXRvdXIgZGUgbGEgZm9uY3Rpb24uICovXG4gIEBJbnB1dCgpXG4gIHNldCBjb21wYXJlV2l0aChmbjogKG8xOiBhbnksIG8yOiBhbnkpID0+IGJvb2xlYW4pIHtcbiAgICBpZiAodHlwZW9mIGZuICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aHJvdyBFcnJvcignYGNvbXBhcmVXaXRoYCBtdXN0IGJlIGEgZnVuY3Rpb24uJyk7XG4gICAgfVxuXG4gICAgdGhpcy5jb21wYXJlRm4gPSBmbjtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgbmdPbkluaXQoKSB7XG4gICAgc3VwZXIubmdPbkluaXQoKTtcbiAgICB0aGlzLm1lc3NhZ2VzR3JvdXBJZCA9IGAke3RoaXMuaW5wdXRJZH0tbWVzc2FnZXNgO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoeyB2YWx1ZSB9OiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlICYmIHRoaXMudmFsdWUgJiYgdGhpcy5vcHRpb25zLmxlbmd0aCkge1xuICAgICAgaWYgKCF0aGlzLmZpbmRPcHRpb24odGhpcy52YWx1ZSwgdGhpcy5vcHRpb25zKSkge1xuICAgICAgICB0aGlzLnZhbHVlID0gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgb25DaGFuZ2UoKSB7XG4gICAgLy8gQ29tbWUgb24gYSBsZSBkb3VibGUgYmluZGluZywgbGEgdmFsZXVyIGVzdCBkw6lqw6Agw6Agam91clxuICAgIHRoaXMuc2VsZWN0Q2hhbmdlLmVtaXQodGhpcy52YWx1ZSk7XG4gIH1cblxuICB0cmFja0J5SW5kZXggPSAoaW5kZXg6IG51bWJlcik6IG51bWJlciA9PiB7XG4gICAgcmV0dXJuIGluZGV4O1xuICB9O1xuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgcHJvdGVjdGVkIGhhc01lc3NhZ2Uoc2V2ZXJpdHk6IERzZnJTZXZlcml0eSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhaXNTdHJpbmdFbXB0eU9yTnVsbCh0aGlzLm1lc3NhZ2UpICYmIHNldmVyaXR5ID09PSB0aGlzLm1lc3NhZ2VTZXZlcml0eTtcbiAgfVxuXG4gIHByaXZhdGUgZmluZE9wdGlvbih2YWx1ZTogYW55LCBvcHRpb25zOiBEc2ZyU2VsZWN0T3B0aW9uW10pOiBhbnkge1xuICAgIHJldHVybiBvcHRpb25zPy5maW5kKFxuICAgICAgKG9wdGlvbikgPT5cbiAgICAgICAgdGhpcy5jb21wYXJlRm4odmFsdWUsIG9wdGlvbi52YWx1ZSkgfHxcbiAgICAgICAgb3B0aW9uLnZhbHVlID09PSB2YWx1ZSB8fFxuICAgICAgICAob3B0aW9uLm9wdGlvbnMgJiYgdGhpcy5maW5kT3B0aW9uKHZhbHVlLCBvcHRpb24ub3B0aW9ucykpLFxuICAgICk7XG4gIH1cbn1cbiIsIjxkaXZcbiAgW25nQ2xhc3NdPVwie1xuICAgICdmci1zZWxlY3QtZ3JvdXAnOiB0cnVlLFxuICAgICdmci1zZWxlY3QtZ3JvdXAtLWRpc2FibGVkJzogZGlzYWJsZWQsXG4gICAgJ2ZyLXNlbGVjdC1ncm91cC0tdmFsaWQnOlxuICAgICAgdmFsaWQgfHwgKG1lc3NhZ2UgJiYgKG1lc3NhZ2VTZXZlcml0eSA9PT0gRHNmclNldmVyaXR5LlNVQ0NFU1MgfHwgbWVzc2FnZVNldmVyaXR5ID09PSBEc2ZyU2V2ZXJpdHkuVkFMSUQpKSxcbiAgICAnZnItc2VsZWN0LWdyb3VwLS1lcnJvcic6IGVycm9yIHx8IChtZXNzYWdlICYmIG1lc3NhZ2VTZXZlcml0eSA9PT0gRHNmclNldmVyaXR5LkVSUk9SKSxcbiAgICAnZnItaW5wdXQtZ3JvdXAtLWluZm8nOiBtZXNzYWdlICYmIG1lc3NhZ2VTZXZlcml0eSA9PT0gRHNmclNldmVyaXR5LklORk8sXG4gICAgJ2ZyLWlucHV0LWdyb3VwLS13YXJuaW5nJzogbWVzc2FnZSAmJiBtZXNzYWdlU2V2ZXJpdHkgPT09IERzZnJTZXZlcml0eS5XQVJOSU5HLFxuICB9XCI+XG4gIDxsYWJlbCBjbGFzcz1cImZyLWxhYmVsXCIgW25nQ2xhc3NdPVwieyAnZnItc3Itb25seSc6IGxhYmVsU3JPbmx5IH1cIiBbZm9yXT1cImlucHV0SWRcIj5cbiAgICBAaWYgKGxhYmVsKSB7XG4gICAgICB7eyBsYWJlbCB9fVxuICAgIH0gQGVsc2Uge1xuICAgICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW2xhYmVsXVwiPjwvbmctY29udGVudD5cbiAgICB9XG4gICAgQGlmIChoaW50KSB7XG4gICAgICA8c3BhbiBjbGFzcz1cImZyLWhpbnQtdGV4dFwiPnt7IGhpbnQgfX08L3NwYW4+XG4gICAgfVxuICA8L2xhYmVsPlxuXG4gIDwhLS0gU2VsZWN0IHNhbnMgZ3JvdXBlcy4gRHVwbGljYXRpb24gZHUgc2VsZWN0IHBvdXIgcGIgcGVyZi4gYWZmaWNoYWdlIGQnb3B0aW9ucyBzdXIgZmlyZWZveCBzaSB1dGlsaXNhdGlvbiBkJ3VuIGlmIC0tPlxuICBAaWYgKG5vR3JvdXApIHtcbiAgICA8c2VsZWN0XG4gICAgICBjbGFzcz1cImZyLXNlbGVjdFwiXG4gICAgICBbaWRdPVwiaW5wdXRJZFwiXG4gICAgICBbYXR0ci5uYW1lXT1cIm5hbWUgfHwgbnVsbFwiXG4gICAgICBbKG5nTW9kZWwpXT1cInZhbHVlXCJcbiAgICAgIFthdHRyLmFyaWEtZGVzY3JpYmVkYnldPVwibWVzc2FnZSA/IG1lc3NhZ2VzR3JvdXBJZCA6IG51bGxcIlxuICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJhcmlhTGFiZWxcIlxuICAgICAgW2F0dHIuYXJpYS1pbnZhbGlkXT1cImFyaWFJbnZhbGlkIHx8IG51bGxcIlxuICAgICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICAgIFtyZXF1aXJlZF09XCJyZXF1aXJlZFwiXG4gICAgICBbY29tcGFyZVdpdGhdPVwiY29tcGFyZUZuXCJcbiAgICAgIChjaGFuZ2UpPVwib25DaGFuZ2UoKVwiPlxuICAgICAgQGlmICghdmFsdWUpIHtcbiAgICAgICAgPG9wdGlvbiBzdHlsZT1cImRpc3BsYXk6IG5vbmVcIiBhcmlhLWhpZGRlbj1cInRydWVcIiBbdmFsdWVdPVwidmFsdWVcIiBzZWxlY3RlZCBkaXNhYmxlZD5cbiAgICAgICAgICB7eyBwbGFjZWhvbGRlciA/PyAoJ3NlbGVjdC5wbGFjZWhvbGRlcicgfCBkc2ZySTE4bikgfX1cbiAgICAgICAgPC9vcHRpb24+XG4gICAgICB9XG4gICAgICBAZm9yIChvcHRpb24gb2Ygb3B0aW9uczsgdHJhY2sgdHJhY2tCeUluZGV4KCRpbmRleCkpIHtcbiAgICAgICAgPG9wdGlvbiBbbmdWYWx1ZV09XCJvcHRpb24udmFsdWVcIiBbZGlzYWJsZWRdPVwib3B0aW9uLmRpc2FibGVkIHx8IG51bGxcIj5cbiAgICAgICAgICB7eyBvcHRpb24ubGFiZWwgfX1cbiAgICAgICAgPC9vcHRpb24+XG4gICAgICB9XG4gICAgPC9zZWxlY3Q+XG4gIH0gQGVsc2Uge1xuICAgIDwhLS0gU2VsZWN0IGF2ZWMgZ3JvdXBlcy4gTmUgc2VyYSBwYXMgb3B0aW1pc8OpIHBvdXIgRkYgLS0+XG4gICAgPHNlbGVjdFxuICAgICAgY2xhc3M9XCJmci1zZWxlY3RcIlxuICAgICAgW2lkXT1cImlucHV0SWRcIlxuICAgICAgW2F0dHIubmFtZV09XCJuYW1lIHx8IG51bGxcIlxuICAgICAgWyhuZ01vZGVsKV09XCJ2YWx1ZVwiXG4gICAgICBbYXR0ci5hcmlhLWRlc2NyaWJlZGJ5XT1cIm1lc3NhZ2UgPyBtZXNzYWdlc0dyb3VwSWQgOiBudWxsXCJcbiAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsXCJcbiAgICAgIFthdHRyLmFyaWEtaW52YWxpZF09XCJhcmlhSW52YWxpZCB8fCBudWxsXCJcbiAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICBbcmVxdWlyZWRdPVwicmVxdWlyZWRcIlxuICAgICAgW2NvbXBhcmVXaXRoXT1cImNvbXBhcmVGblwiXG4gICAgICAoY2hhbmdlKT1cIm9uQ2hhbmdlKClcIj5cbiAgICAgIEBpZiAoIXZhbHVlKSB7XG4gICAgICAgIDxvcHRpb24gc3R5bGU9XCJkaXNwbGF5OiBub25lXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgW3ZhbHVlXT1cInZhbHVlXCIgc2VsZWN0ZWQgZGlzYWJsZWQ+XG4gICAgICAgICAge3sgcGxhY2Vob2xkZXIgPz8gKCdzZWxlY3QucGxhY2Vob2xkZXInIHwgZHNmckkxOG4pIH19XG4gICAgICAgIDwvb3B0aW9uPlxuICAgICAgfVxuICAgICAgQGZvciAob3B0aW9uIG9mIG9wdGlvbnM7IHRyYWNrIHRyYWNrQnlJbmRleCgkaW5kZXgpKSB7XG4gICAgICAgIEBpZiAob3B0aW9uLm9wdGlvbnMpIHtcbiAgICAgICAgICA8b3B0Z3JvdXAgW2xhYmVsXT1cIm9wdGlvbi5sYWJlbFwiPlxuICAgICAgICAgICAgQGZvciAob3B0aW9uIG9mIG9wdGlvbi5vcHRpb25zOyB0cmFjayB0cmFja0J5SW5kZXgoJGluZGV4KSkge1xuICAgICAgICAgICAgICA8b3B0aW9uIFtuZ1ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiIFtkaXNhYmxlZF09XCJvcHRpb24uZGlzYWJsZWQgfHwgbnVsbFwiPlxuICAgICAgICAgICAgICAgIHt7IG9wdGlvbi5sYWJlbCB9fVxuICAgICAgICAgICAgICA8L29wdGlvbj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L29wdGdyb3VwPlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8b3B0aW9uIFtuZ1ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiIFtkaXNhYmxlZF09XCJvcHRpb24uZGlzYWJsZWQgfHwgbnVsbFwiPlxuICAgICAgICAgICAge3sgb3B0aW9uLmxhYmVsIH19XG4gICAgICAgICAgPC9vcHRpb24+XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICA8L3NlbGVjdD5cbiAgfVxuXG4gIDxkaXYgW2lkXT1cIm1lc3NhZ2VzR3JvdXBJZFwiIGNsYXNzPVwiZnItbWVzc2FnZXMtZ3JvdXBcIiBhcmlhLWxpdmU9XCJwb2xpdGVcIj5cbiAgICBAaWYgKG1lc3NhZ2UpIHtcbiAgICAgIDxwIGNsYXNzPVwiZnItbWVzc2FnZVwiIFtlZHVNZXNzYWdlU2V2ZXJpdHldPVwibWVzc2FnZVNldmVyaXR5XCI+XG4gICAgICAgIHt7IG1lc3NhZ2UgfX1cbiAgICAgIDwvcD5cbiAgICB9XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=