@seniorsistemas/angular-components 19.7.4 → 19.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/alert/lib/alert/alert.component.d.ts +8 -1
  2. package/chips/README.md +3 -2
  3. package/chips/lib/chips/chip-item/chip-item.component.d.ts +2 -0
  4. package/chips/lib/chips/chips/chips.component.d.ts +2 -1
  5. package/datepicker/README.md +15 -2
  6. package/datepicker/lib/datepicker/date-segment-input.d.ts +82 -0
  7. package/datepicker/lib/datepicker/date.utils.d.ts +3 -7
  8. package/datepicker/lib/datepicker/datepicker.component.d.ts +101 -8
  9. package/dynamic-form/dynamic-form/components/lookup/models/lookup-api.model.d.ts +7 -1
  10. package/dynamic-form/dynamic-form/form-field/configurations/fields/lookup-field.d.ts +1 -1
  11. package/dynamic-form/public-api.d.ts +1 -1
  12. package/esm2022/alert/lib/alert/alert.component.mjs +12 -6
  13. package/esm2022/chips/lib/chips/chip-item/chip-item.component.mjs +15 -4
  14. package/esm2022/chips/lib/chips/chips/chips.component.mjs +26 -14
  15. package/esm2022/datepicker/lib/datepicker/date-segment-input.mjs +418 -0
  16. package/esm2022/datepicker/lib/datepicker/date.utils.mjs +7 -79
  17. package/esm2022/datepicker/lib/datepicker/datepicker.component.mjs +451 -41
  18. package/esm2022/dynamic-form/dynamic-form/components/lookup/lookup.component.mjs +2 -2
  19. package/esm2022/dynamic-form/dynamic-form/components/lookup/models/lookup-api.model.mjs +1 -1
  20. package/esm2022/dynamic-form/dynamic-form/form-field/configurations/fields/lookup-field.mjs +1 -1
  21. package/esm2022/dynamic-form/public-api.mjs +1 -1
  22. package/esm2022/panel/lib/panel/panel.component.mjs +3 -3
  23. package/esm2022/sidebar/lib/sidebar/sidebar.component.mjs +8 -6
  24. package/esm2022/thumbnail/lib/thumbnail/thumbnail.component.mjs +3 -3
  25. package/fesm2022/seniorsistemas-angular-components-alert.mjs +12 -6
  26. package/fesm2022/seniorsistemas-angular-components-alert.mjs.map +1 -1
  27. package/fesm2022/seniorsistemas-angular-components-chips.mjs +39 -16
  28. package/fesm2022/seniorsistemas-angular-components-chips.mjs.map +1 -1
  29. package/fesm2022/seniorsistemas-angular-components-datepicker.mjs +873 -118
  30. package/fesm2022/seniorsistemas-angular-components-datepicker.mjs.map +1 -1
  31. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +1 -1
  32. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
  33. package/fesm2022/seniorsistemas-angular-components-panel.mjs +2 -2
  34. package/fesm2022/seniorsistemas-angular-components-panel.mjs.map +1 -1
  35. package/fesm2022/seniorsistemas-angular-components-sidebar.mjs +7 -5
  36. package/fesm2022/seniorsistemas-angular-components-sidebar.mjs.map +1 -1
  37. package/fesm2022/seniorsistemas-angular-components-thumbnail.mjs +2 -2
  38. package/fesm2022/seniorsistemas-angular-components-thumbnail.mjs.map +1 -1
  39. package/package.json +13 -13
  40. package/schematics/migrations/migrate-steps-to-stepper/index.d.ts +2 -0
  41. package/schematics/migrations/migrate-steps-to-stepper/index.js +104 -0
  42. package/schematics/migrations/migrate-steps-to-stepper/index.js.map +1 -0
  43. package/schematics/migrations.json +5 -0
  44. package/schematics/utils/ast-utils.d.ts +13 -0
  45. package/schematics/utils/ast-utils.js +76 -0
  46. package/schematics/utils/ast-utils.js.map +1 -1
  47. package/sidebar/lib/sidebar/sidebar.component.d.ts +3 -1
  48. package/schematics/migrations/migrate-dynamic-form-v19/index.test.d.ts +0 -1
  49. package/schematics/migrations/migrate-dynamic-form-v19/index.test.js +0 -888
  50. package/schematics/migrations/migrate-dynamic-form-v19/index.test.js.map +0 -1
  51. package/schematics/migrations/migrate-p-datepicker/index.test.d.ts +0 -1
  52. package/schematics/migrations/migrate-p-datepicker/index.test.js +0 -392
  53. package/schematics/migrations/migrate-p-datepicker/index.test.js.map +0 -1
  54. package/schematics/migrations/migrate-p-editor/index.test.d.ts +0 -1
  55. package/schematics/migrations/migrate-p-editor/index.test.js +0 -393
  56. package/schematics/migrations/migrate-p-editor/index.test.js.map +0 -1
  57. package/schematics/migrations/migrate-s-chips-outputs/index.test.d.ts +0 -1
  58. package/schematics/migrations/migrate-s-chips-outputs/index.test.js +0 -125
  59. package/schematics/migrations/migrate-s-chips-outputs/index.test.js.map +0 -1
  60. package/schematics/utils/ast-utils.test.d.ts +0 -1
  61. package/schematics/utils/ast-utils.test.js +0 -138
  62. package/schematics/utils/ast-utils.test.js.map +0 -1
  63. package/schematics/utils/workspace-utils.test.d.ts +0 -1
  64. package/schematics/utils/workspace-utils.test.js +0 -152
  65. package/schematics/utils/workspace-utils.test.js.map +0 -1
@@ -42,6 +42,13 @@ export declare class AlertComponent {
42
42
  * @default true
43
43
  */
44
44
  closable: boolean;
45
+ /**
46
+ * @description Quando `true`, o conteúdo do alerta é escapado para evitar a execução de HTML ou scripts.
47
+ * Quando `false`, o conteúdo do alerta é renderizado como HTML, permitindo a inclusão de links, negrito, etc.
48
+ *
49
+ * @default true
50
+ */
51
+ escape: import("@angular/core").InputSignal<boolean>;
45
52
  /**
46
53
  * @description Emitido quando o usuário fecha o alerta clicando no botão de fechar.
47
54
  */
@@ -52,5 +59,5 @@ export declare class AlertComponent {
52
59
  onClose(): void;
53
60
  private _isOpen;
54
61
  static ɵfac: i0.ɵɵFactoryDeclaration<AlertComponent, never>;
55
- static ɵcmp: i0.ɵɵComponentDeclaration<AlertComponent, "s-alert", never, { "severity": { "alias": "severity"; "required": false; }; "summary": { "alias": "summary"; "required": true; }; "detail": { "alias": "detail"; "required": true; }; "closable": { "alias": "closable"; "required": false; }; }, { "closed": "closed"; }, never, never, true, never>;
62
+ static ɵcmp: i0.ɵɵComponentDeclaration<AlertComponent, "s-alert", never, { "severity": { "alias": "severity"; "required": false; }; "summary": { "alias": "summary"; "required": true; }; "detail": { "alias": "detail"; "required": false; }; "closable": { "alias": "closable"; "required": false; }; "escape": { "alias": "escape"; "required": false; "isSignal": true; }; }, { "closed": "closed"; }, never, ["*"], true, never>;
56
63
  }
package/chips/README.md CHANGED
@@ -142,8 +142,9 @@ paises = [
142
142
  ## Acessibilidade
143
143
 
144
144
  - O campo de entrada é um `<input>` acessível via teclado
145
- - **Enter** confirma adição do chip; **Tab** também pode confirmar (configurável)
146
- - Os botões de remoção de cada chip são acessíveis via teclado
145
+ - **Enter** confirma a adição do chip; **Tab** sempre navega normalmente para o próximo elemento da tela, independente de `addOnTab`
146
+ - `addOnTab` controla apenas se o valor digitado é adicionado como chip antes do foco sair do campo — nunca bloqueia a navegação
147
+ - Cada chip já adicionado é focável via **Tab** (na ordem: chips existentes → campo de entrada), removível com **Backspace**/**Delete** e ativável com **Enter**/**Espaço** (mesmo comportamento de um clique)
147
148
  - Use `aria-label` ou `<label for="...">` apontando para `inputId` para associar um rótulo ao campo
148
149
 
149
150
  ## Componentes relacionados
@@ -31,8 +31,10 @@ export declare class ChipItemComponent {
31
31
  event: Event;
32
32
  data: string | Object;
33
33
  }>;
34
+ private readonly chipElement?;
34
35
  clickedRemove($event: Event): void;
35
36
  onChipClicked($event: Event): void;
37
+ focus(): void;
36
38
  get _text(): string;
37
39
  get _rawText(): any;
38
40
  static ɵfac: i0.ɵɵFactoryDeclaration<ChipItemComponent, never>;
@@ -73,7 +73,7 @@ export declare class ChipsComponent implements AfterViewInit, ControlValueAccess
73
73
  valueChange: EventEmitter<any[] | string[]>;
74
74
  private readonly templates;
75
75
  private readonly input;
76
- isFocused: boolean;
76
+ private readonly chipItems;
77
77
  onChange: (value: string[] | any[]) => void;
78
78
  onTouched: (value: string[] | any[]) => void;
79
79
  private isTabEventActive;
@@ -100,6 +100,7 @@ export declare class ChipsComponent implements AfterViewInit, ControlValueAccess
100
100
  private getMappedValues;
101
101
  private getValueToAdd;
102
102
  private hasDuplicatedItem;
103
+ private restoreFocusAfterRemove;
103
104
  private storeValue;
104
105
  static ɵfac: i0.ɵɵFactoryDeclaration<ChipsComponent, never>;
105
106
  static ɵcmp: i0.ɵɵComponentDeclaration<ChipsComponent, "s-chips", never, { "disabled": { "alias": "disabled"; "required": false; }; "field": { "alias": "field"; "required": false; }; "value": { "alias": "value"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "max": { "alias": "max"; "required": false; }; "maxLength": { "alias": "maxLength"; "required": false; }; "inputId": { "alias": "inputId"; "required": false; }; "allowDuplicated": { "alias": "allowDuplicated"; "required": false; }; "caseSensitiveDuplication": { "alias": "caseSensitiveDuplication"; "required": false; }; "addOnTab": { "alias": "addOnTab"; "required": false; }; "addOnBlur": { "alias": "addOnBlur"; "required": false; }; "separator": { "alias": "separator"; "required": false; }; "autofocus": { "alias": "autofocus"; "required": false; }; "infoLabel": { "alias": "infoLabel"; "required": false; }; "keyFilter": { "alias": "keyFilter"; "required": false; }; "showTooltip": { "alias": "showTooltip"; "required": false; }; "maxLengthRenderWithoutTooltip": { "alias": "maxLengthRenderWithoutTooltip"; "required": false; }; }, { "added": "added"; "removed": "removed"; "focused": "focused"; "focusLost": "focusLost"; "chipClicked": "chipClicked"; "valueChange": "valueChange"; }, ["templates"], never, true, never>;
@@ -51,8 +51,8 @@ export class MeuComponent {}
51
51
  | `min` | `Date \| null` | `null` | Não | Data mínima selecionável. Dias anteriores ficam desabilitados. |
52
52
  | `max` | `Date \| null` | `null` | Não | Data máxima selecionável. Dias posteriores ficam desabilitados. |
53
53
  | `defaultDate` | `Date \| null` | `null` | Não | Data exibida ao abrir o painel quando nenhuma data está selecionada. |
54
- | `dateFormat` | `string` | `'dd/MM/yyyy'` | Não | Formato de exibição da data no campo. |
55
- | `hourFormat` | `'12' \| '24'` | `'24'` | Não | Formato de exibição das horas. |
54
+ | `dateFormat` | `string` | resolvido do locale, fallback `'dd/MM/yyyy'` | Não | Formato de exibição da data (tokens `dd`, `MM`, `yyyy`). Quando omitido, é resolvido a partir do locale ativo (chave de tradução `platform.angular_components.date_format`). Vale para todos os modos exceto `year`. |
55
+ | `hourFormat` | `'12' \| '24'` | resolvido do locale, fallback `'24'` | Não | Formato de exibição das horas. Quando omitido, é resolvido a partir do locale ativo (chave de tradução `platform.angular_components.hour_format`). |
56
56
  | `minuteStep` | `number` | `5` | Não | Incremento em minutos ao usar as setas do time picker. |
57
57
  | `showSeconds` | `boolean` | `false` | Não | Exibe o campo de segundos no time picker. |
58
58
  | `rangeSeparator` | `string` | `' — '` | Não | Separador exibido entre as datas no modo `range`. |
@@ -191,6 +191,19 @@ const config: CalendarFieldConfig = {
191
191
  <s-dynamic-form [config]="config" />
192
192
  ```
193
193
 
194
+ ## Digitação por segmento
195
+
196
+ Nos modos `date`, `month`, `time` e `datetime`, o campo não usa `<input type="date">` nativo — o formato exibido segue o `dateFormat`/`hourFormat` (explícito ou resolvido do locale via ngx-translate), não o locale do browser/SO. A digitação replica o comportamento nativo:
197
+
198
+ - Clicar em um segmento (dia, mês, ano, hora, minuto, segundo) seleciona o segmento inteiro
199
+ - `Tab`/`Shift+Tab` e `←`/`→` navegam entre os segmentos sem sair do campo; nas bordas (último/primeiro segmento), o `Tab` volta a se comportar normalmente e move o foco para fora do campo, enquanto `←`/`→` simplesmente não fazem nada (como num `<input type="date">` nativo)
200
+ - `↑`/`↓` incrementam/decrementam o valor do segmento ativo, dando a volta (wrap) dentro do range válido
201
+ - Digitar um número preenche o segmento e avança automaticamente ao completar (ex.: digitar `1`, `5` no dia avança para o mês)
202
+ - Ao sair de um segmento incompleto (Tab, clique fora ou avanço automático), o valor é completado com zero à esquerda e ajustado aos limites (ex.: `2` no mês vira `02`; um dia maior que o total de dias do mês é reduzido para o último dia válido, considerando ano bissexto)
203
+ - Alterar o mês ou o ano com o dia já preenchido reajusta o dia automaticamente se ele deixar de ser válido (ex.: dia 31 + mês fevereiro → dia 28/29)
204
+
205
+ Em dispositivos touch (`(pointer: coarse)`), o campo cai automaticamente para o mesmo comportamento de `mode="range"`/`mode="year"` — somente leitura, com seleção exclusiva pelo painel do calendário — evitando abrir o teclado do aparelho no lugar do seletor nativo.
206
+
194
207
  ## Acessibilidade
195
208
 
196
209
  - O trigger usa `role="combobox"` com `aria-haspopup="grid"`, `aria-expanded` e `aria-controls` apontando para o painel
@@ -0,0 +1,82 @@
1
+ export type SegmentKind = 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second' | 'ampm';
2
+ export interface EditableSegmentState {
3
+ kind: SegmentKind;
4
+ length: number;
5
+ text: string;
6
+ }
7
+ export interface LiteralSegmentState {
8
+ kind: 'literal';
9
+ text: string;
10
+ }
11
+ export type SegmentState = EditableSegmentState | LiteralSegmentState;
12
+ export interface SegmentEngineConfig {
13
+ mode: 'date' | 'month' | 'time' | 'datetime';
14
+ dateFormat: string;
15
+ hourFormat: '12' | '24';
16
+ showSeconds: boolean;
17
+ }
18
+ interface FormatToken {
19
+ kind: 'day' | 'month' | 'year' | 'literal';
20
+ raw: string;
21
+ }
22
+ /** Tokeniza um `dateFormat` (ex.: `dd/MM/yyyy`, `MM/dd/yy`) em tokens de dia/mês/ano + literais. */
23
+ export declare function tokenizeDateFormat(format: string): FormatToken[];
24
+ /** Dias no mês (1-12), já resolvendo fevereiro/ano bissexto via rollover nativo do `Date`. */
25
+ export declare function daysInMonth(month: number, year: number): number;
26
+ /**
27
+ * Engine de segmentos (dia/mês/ano/hora/minuto/segundo/ampm) para o trigger do datepicker.
28
+ * Sem dependências de Angular — DOM/CVA ficam por conta do componente que a consome.
29
+ */
30
+ export declare class DateSegmentEngine {
31
+ private segments;
32
+ private config;
33
+ private activeIndex;
34
+ private freshEntry;
35
+ configure(config: SegmentEngineConfig): void;
36
+ getDisplayString(): string;
37
+ private renderSegment;
38
+ private segmentRenderLength;
39
+ getSegmentRange(index: number): [number, number];
40
+ getFirstEditableIndex(): number;
41
+ getLastEditableIndex(): number;
42
+ getActiveIndex(): number | null;
43
+ activeKind(): SegmentKind | null;
44
+ selectSegmentAt(charIndex: number): number;
45
+ private nearestEditableFrom;
46
+ selectSegment(index: number): void;
47
+ selectFirstSegment(): void;
48
+ /** Commita (pad/clamp) o segmento ativo e move para o próximo/anterior editável. */
49
+ moveToAdjacentSegment(direction: 1 | -1): 'moved' | 'boundary';
50
+ typeDigit(digit: string): void;
51
+ private autoAdvance;
52
+ setAmPm(value: 0 | 1): void;
53
+ clearActiveSegment(kind: 'backspace' | 'delete'): void;
54
+ /** Limpa todos os segmentos editáveis (usado quando o campo inteiro está selecionado, ex.: Ctrl+A). */
55
+ clearAll(): void;
56
+ /** Incrementa/decrementa o segmento ativo, dando a volta (wrap) dentro do range válido. */
57
+ incrementActiveSegment(delta: 1 | -1): void;
58
+ /** Pad/clamp do segmento ativo (ex.: "2" -> "02", "45" no dia -> clamp para daysInMonth). */
59
+ commitActiveSegment(): void;
60
+ /** Commita o segmento ativo e sai do modo de edição (usado no blur do campo). */
61
+ deactivate(): void;
62
+ private clampAndPad;
63
+ private boundsFor;
64
+ /**
65
+ * Bound do dia dependendo do que já é conhecido de mês/ano. Nunca "adivinha" com o mês/ano
66
+ * atuais do sistema — isso estreitaria o range antes da hora (ex.: dia=29 digitado antes do
67
+ * ano, mês=fevereiro conhecido mas ano ainda não -> se assumisse o ano atual do sistema e ele
68
+ * não fosse bissexto, o dia seria clampado para 28 e nunca mais reexpandido para 29 mesmo que
69
+ * o ano realmente digitado depois seja bissexto). Em vez disso, fica sempre no lado permissivo
70
+ * até que a informação realmente exista.
71
+ */
72
+ private daysInMonthNow;
73
+ private reconcileDayIfNeeded;
74
+ private findEditable;
75
+ isEmpty(): boolean;
76
+ isComplete(): boolean;
77
+ loadFromDate(date: Date | null): void;
78
+ private renderValueFor;
79
+ /** Constrói o `Date` a partir dos segmentos; `null` enquanto incompleto. Usa `referenceDate` para preencher partes ausentes (ex.: hora ao editar só a data). */
80
+ toDate(referenceDate?: Date | null): Date | null;
81
+ }
82
+ export {};
@@ -3,19 +3,15 @@ export type { DateRange };
3
3
  export declare function formatNativeDate(date: Date): string;
4
4
  /**
5
5
  * Formata uma data segundo um padrão simples contendo os tokens `dd`, `MM` e `yyyy`.
6
- * Usado apenas para exibição em campos `type="text"` (modo `range`), onde o browser
7
- * não controla o formato. Para `type="date"` nativo o formato é definido pelo browser.
6
+ * Usado para exibição em campos `type="text"` (modos `range` e seleção múltipla).
8
7
  */
9
8
  export declare function formatWithPattern(date: Date, pattern: string): string;
10
- export declare function formatTime(h: number, m: number, s?: number): string;
11
9
  /** Parses yyyy-MM-dd. Returns null when invalid. */
12
10
  export declare function parseDate(raw: string): Date | null;
13
11
  export declare function isSameDay(a: Date, b: Date): boolean;
14
12
  export declare function stripTime(date: Date): number;
15
13
  export declare function parseRangeInput(raw: string, separator?: string): DateRange | null;
16
- export declare function parseTimeInput(raw: string, base: Date | null, maxHours: number, maxMinutes: number): Date | null;
17
14
  export declare function parseYearInput(raw: string): Date | null;
18
- export declare function parseMonthInput(raw: string): Date | null;
19
- export declare function parseDateTimeInput(raw: string): Date | null;
20
- export declare function parseInput(mode: string, raw: string, base: Date | null, maxHours: number, maxMinutes: number, rangeSeparator?: string): Date | DateRange | null;
15
+ export declare function parseInput(mode: string, raw: string, rangeSeparator?: string): Date | DateRange | null;
16
+ /** Formata range/seleção múltipla (dateFormat) e o ano em `mode='year'`. Demais modos são resolvidos pela engine de segmentos. */
21
17
  export declare function formatValueForInput(mode: string, value: Date | DateRange | Date[] | null, rangeSeparator?: string, dateFormat?: string, multipleSeparator?: string): string;
@@ -16,6 +16,7 @@ export declare class DatepickerComponent implements ControlValueAccessor, Valida
16
16
  private static readonly MAX_HOURS;
17
17
  private static readonly MAX_MINUTES;
18
18
  private static readonly HOURS_PER_MERIDIEM;
19
+ private static readonly DOUBLE_CLICK_THRESHOLD_MS;
19
20
  private static nextId;
20
21
  /** HTML `id` aplicado ao elemento `<input>`. Auto-gerado quando omitido. */
21
22
  readonly inputId: import("@angular/core").InputSignal<string>;
@@ -53,10 +54,16 @@ export declare class DatepickerComponent implements ControlValueAccessor, Valida
53
54
  readonly max: import("@angular/core").InputSignal<Date | null>;
54
55
  /** Data exibida ao abrir o calendário quando nenhuma data está selecionada. */
55
56
  readonly defaultDate: import("@angular/core").InputSignal<Date | null>;
56
- /** Formato de exibição da data no campo (usado apenas para display). */
57
- readonly dateFormat: import("@angular/core").InputSignal<string>;
58
- /** Formato de exibição das horas: `'12'` ou `'24'`. */
59
- readonly hourFormat: import("@angular/core").InputSignal<"12" | "24">;
57
+ /**
58
+ * Formato de exibição da data no campo. Quando omitido, é resolvido a partir do
59
+ * locale ativo (chave `platform.angular_components.date_format`), com fallback para `dd/MM/yyyy`.
60
+ */
61
+ readonly dateFormat: import("@angular/core").InputSignal<string | undefined>;
62
+ /**
63
+ * Formato de exibição das horas: `'12'` ou `'24'`. Quando omitido, é resolvido a partir
64
+ * do locale ativo (chave `platform.angular_components.hour_format`), com fallback para `'24'`.
65
+ */
66
+ readonly hourFormat: import("@angular/core").InputSignal<"12" | "24" | undefined>;
60
67
  /** Incremento em minutos ao usar as setas do time picker. */
61
68
  readonly minuteStep: import("@angular/core").InputSignal<number>;
62
69
  /** Quando `true`, exibe o campo de segundos no time picker. */
@@ -137,22 +144,43 @@ export declare class DatepickerComponent implements ControlValueAccessor, Valida
137
144
  protected readonly pendingRangeStart: import("@angular/core").WritableSignal<Date | null>;
138
145
  protected readonly hoverDate: import("@angular/core").WritableSignal<Date | null>;
139
146
  private _hasFormatError;
140
- private _isBadInput;
141
147
  private onValidatorChange;
142
148
  private _onChange;
143
149
  private _onTouched;
144
150
  private readonly popupPanel;
145
151
  private readonly increaseHourButton;
146
152
  private readonly iconButton;
153
+ private readonly triggerInput;
147
154
  private readonly injector;
148
155
  private readonly hostElement;
156
+ private readonly translateService;
157
+ private readonly destroyRef;
158
+ private readonly currentLang;
159
+ /** Reflete `(pointer: coarse)` — dispositivos touch preferem o popup do calendário ao teclado. */
160
+ protected readonly isTouchDevice: import("@angular/core").WritableSignal<boolean>;
161
+ private readonly segmentEngine;
162
+ private lastSegmentConfig;
163
+ private measureCanvas?;
164
+ /** Incrementado a cada mutação do usuário — invalida callbacks de clique/foco adiados que ficaram obsoletos. */
165
+ private interactionGeneration;
166
+ /** `timeStamp` do último mousedown no input segmentado — usado pra detectar duplo clique na mão. */
167
+ private lastMouseDownAt;
168
+ constructor();
149
169
  protected readonly resolvedIcon: import("@angular/core").Signal<string>;
170
+ /** `dateFormat` explícito ou resolvido a partir do locale ativo (fallback `dd/MM/yyyy`). */
171
+ protected readonly resolvedDateFormat: import("@angular/core").Signal<string>;
172
+ /** `hourFormat` explícito ou resolvido a partir do locale ativo (fallback `'24'`). */
173
+ protected readonly resolvedHourFormat: import("@angular/core").Signal<"12" | "24">;
174
+ /** Modos cujo formato de exibição é resolvido pela engine de segmentos (independente de touch/readonly). */
175
+ protected readonly isSegmentModeCandidate: import("@angular/core").Signal<boolean>;
176
+ /** Interatividade de digitação por segmento — desligada em touch ou quando `readonlyInput` é usado. */
177
+ protected readonly isSegmentedMode: import("@angular/core").Signal<boolean>;
150
178
  /** Indica se o time picker deve usar o formato de 12 horas com seletor AM/PM. */
151
179
  protected readonly is12HourFormat: import("@angular/core").Signal<boolean>;
152
180
  /** Hora exibida no time picker: 1–12 no formato 12h, 0–23 no formato 24h. */
153
181
  protected readonly displayHours: import("@angular/core").Signal<number>;
154
182
  /** Meridiano atual derivado da hora interna (0–23). */
155
- protected readonly amPm: import("@angular/core").Signal<"AM" | "PM">;
183
+ protected readonly amPm: import("@angular/core").Signal<"PM" | "AM">;
156
184
  protected readonly positions: ConnectedPosition[];
157
185
  protected readonly popupId: import("@angular/core").Signal<string>;
158
186
  protected readonly currentMonthIndex: import("@angular/core").Signal<number>;
@@ -163,7 +191,6 @@ export declare class DatepickerComponent implements ControlValueAccessor, Valida
163
191
  /** Seleção múltipla ativa: apenas no modo `date` com `selectionMode = 'multiple'`. */
164
192
  protected readonly isMultipleMode: import("@angular/core").Signal<boolean>;
165
193
  protected readonly orderedWeekDayKeys: import("@angular/core").Signal<string[]>;
166
- protected readonly inputType: import("@angular/core").Signal<"date" | "month" | "time" | "text" | "datetime-local">;
167
194
  protected readonly dialogAriaLabelKey: import("@angular/core").Signal<"platform.angular_components.datepicker_select_range" | "platform.angular_components.datepicker_select_date">;
168
195
  protected readonly placeholderKey: import("@angular/core").Signal<string>;
169
196
  protected readonly effectiveRange: import("@angular/core").Signal<{
@@ -198,14 +225,66 @@ export declare class DatepickerComponent implements ControlValueAccessor, Valida
198
225
  private prepareOpenView;
199
226
  private focusBestCalendarTarget;
200
227
  protected closePanel(): void;
228
+ /**
229
+ * O backdrop do CDK Overlay cobre a tela inteira, incluindo o próprio trigger — clicar no
230
+ * input ou nos botões do trigger enquanto o painel já está aberto também dispara
231
+ * `backdropClick` (o próprio `<input>` nunca recebe o `click` nesse caso, então
232
+ * `handleInputClick` nunca dispara). Sem este filtro, clicar no input para trocar de
233
+ * segmento fecharia o painel e roubaria o foco para o botão do ícone (via `closePanel`).
234
+ * Quando o clique caiu especificamente sobre o `<input>`, reaplicamos a mesma lógica de
235
+ * reposicionamento de segmento que `handleInputClick` faria, em vez de só ignorar o clique.
236
+ */
237
+ protected handleBackdropClick(event: MouseEvent): void;
201
238
  protected toggle(): void;
202
239
  protected handleOverlayKeydown(event: KeyboardEvent): void;
203
- protected handleInputClick(): void;
240
+ protected handleInputClick(event: MouseEvent): void;
241
+ /**
242
+ * Ponto de entrada único pro clique no input segmentado — chamado tanto por
243
+ * `handleInputClick` (mousedown direto no `<input>`, o primeiro clique, antes do backdrop
244
+ * existir) quanto por `handleBackdropClick` (cliques seguintes, já com o painel aberto e o
245
+ * backdrop cobrindo o input). Precisa ser único porque os dois cliques de um duplo clique
246
+ * real costumam chegar por caminhos DIFERENTES — o primeiro via mousedown no input, o
247
+ * segundo via backdropClick — então rastrear o timestamp do "último clique" separadamente
248
+ * em cada handler nunca detectaria um duplo clique de verdade. Nem `dblclick` nem
249
+ * `event.detail` são confiáveis aqui (dependem da contagem/targeting interna de cliques do
250
+ * browser, que nossas manipulações de foco/seleção parecem atrapalhar — observado
251
+ * empiricamente: `event.detail` fica sempre 1), daí a detecção manual por timestamp.
252
+ */
253
+ private handleSegmentPointerDown;
254
+ /**
255
+ * Seleciona o segmento sob a coordenada `clientX` de um clique no input segmentado.
256
+ * Compartilhado por `handleInputClick` (mousedown real no `<input>` — usamos `mousedown`
257
+ * em vez de `click` porque o `focus`/`openOnFocus` disparado no meio do gesto pode montar
258
+ * o backdrop do CDK Overlay embaixo do cursor antes do `mouseup`, fazendo o browser resolver
259
+ * o `click` pro ancestral comum entre o alvo do mousedown e o do mouseup — na prática,
260
+ * `<body>` — em vez do `<input>` ou do backdrop) e `handleBackdropClick` (clique no trigger
261
+ * com o painel já aberto em regime estável, interceptado pelo backdrop do CDK Overlay).
262
+ */
263
+ private applySegmentClick;
264
+ /** Duplo clique seleciona o input inteiro (todos os segmentos), como num `<input>` de texto comum. */
265
+ protected handleInputDblClick(event: MouseEvent): void;
266
+ /**
267
+ * Seleciona todos os segmentos do input (usado tanto pelo duplo clique detectado na mão em
268
+ * `handleSegmentPointerDown` quanto por `handleInputDblClick`, mantido como caminho direto
269
+ * pra quem dispara um `dblclick` de verdade, ex.: acessibilidade/testes).
270
+ */
271
+ private selectWholeField;
204
272
  protected handleInputFocus(event: Event): void;
273
+ /** Mapeia a coordenada X (viewport) de um clique para o índice de caractere mais próximo no valor exibido. */
274
+ private clickClientXToCharIndex;
205
275
  protected handleNativeInput(event: Event): void;
206
276
  protected handleInputBlur(event: Event): void;
207
277
  protected handleInputChange(raw: string): void;
208
278
  protected handleTriggerKeydown(event: KeyboardEvent): void;
279
+ /** Teclas que devem passar direto para o browser sem inserir/alterar nada no campo. */
280
+ private static readonly SEGMENTED_PASSTHROUGH_KEYS;
281
+ /** Digitação por segmento (dia/mês/ano/hora/minuto/segundo/ampm) no input do trigger. */
282
+ private handleSegmentedKeydown;
283
+ /** Sincroniza o DOM com o estado atual da engine (valor + seleção do segmento ativo) após uma mutação. */
284
+ private syncSegmentedInput;
285
+ private selectActiveSegmentRange;
286
+ /** Propaga o valor da engine para o modelo (CVA) assim que todos os segmentos estiverem completos. */
287
+ private commitSegmentedValueIfComplete;
209
288
  protected navigatePrev(): void;
210
289
  protected navigateNext(): void;
211
290
  protected handleCalendarGridKeydown(event: KeyboardEvent): void;
@@ -245,6 +324,20 @@ export declare class DatepickerComponent implements ControlValueAccessor, Valida
245
324
  protected formatDayAriaLabel(date: Date): string;
246
325
  /** Formata o valor para exibição no input, aplicando rangeSeparator, dateFormat e multipleSeparator. */
247
326
  private formatForDisplay;
327
+ /**
328
+ * Atualiza `inputDate` a partir de um valor único, roteando pela engine de segmentos
329
+ * (date/month/time/datetime) ou pelo formatador legado (range/year/multiple).
330
+ */
331
+ private setDisplayFor;
332
+ /**
333
+ * (Re)configura a engine de segmentos quando `mode`/`dateFormat`/`hourFormat`/`showSeconds`
334
+ * mudaram desde a última chamada, recarregando o valor atual. Chamado de forma síncrona a
335
+ * partir de todo ponto de entrada que usa a engine — não depende de um `effect()` (que só
336
+ * roda em um ciclo de change detection, tarde demais para leituras/escritas imediatas).
337
+ */
338
+ private ensureSegmentEngineConfigured;
339
+ /** Retorna a tradução de `key`, ou `fallback` quando a chave não está traduzida (ngx-translate retorna a própria chave). */
340
+ private resolveTranslatedOrDefault;
248
341
  private syncTimeToValue;
249
342
  private buildCalendarDay;
250
343
  private computeValidationErrors;
@@ -1,5 +1,11 @@
1
- export type LookupSearchRequest = {
1
+ import { TableLazyLoadEvent } from 'primeng/table';
2
+ export type SortMeta = {
3
+ field: string;
4
+ order: number;
5
+ };
6
+ export type LookupSearchRequest = TableLazyLoadEvent & {
2
7
  filterData: Record<string, any>;
3
8
  first: number;
4
9
  rows: number;
10
+ multiSortMeta?: SortMeta[] | undefined | null;
5
11
  };
@@ -133,7 +133,7 @@ export interface LookupFieldConfig extends FieldConfig {
133
133
  * Callback chamado quando o usuário realiza uma pesquisa no diálogo avançado.
134
134
  * Deve atualizar o `searchObservable` com os resultados paginados.
135
135
  *
136
- * Estrutura de `LookupSearchRequest`: `{ filterData: Record<string, any>; first: number; rows: number; }`
136
+ * Estrutura de `LookupSearchRequest`: `{ filterData: Record<string, any>; first: number; rows: number; multiSortMeta?: SortMeta[] | undefined | null; }`
137
137
  * @typeImport import { LookupSearchRequest } from '@seniorsistemas/angular-components/dynamic-form';
138
138
  */
139
139
  onSearchRequest: (event: LookupSearchRequest) => void;
@@ -4,7 +4,7 @@ export type { SectionConfig } from './dynamic-form/configurations/structure/sect
4
4
  export { FieldLabelComponent } from './dynamic-form/components/field-label/field-label.component';
5
5
  export { LookupComponent } from './dynamic-form/components/lookup/lookup.component';
6
6
  export type { LookupAlertConfig } from './dynamic-form/components/lookup/models/lookup-alert-config';
7
- export type { LookupSearchRequest } from './dynamic-form/components/lookup/models/lookup-api.model';
7
+ export type { LookupSearchRequest, SortMeta } from './dynamic-form/components/lookup/models/lookup-api.model';
8
8
  export type { BaseFieldComponentConfig } from './dynamic-form/form-field/fields/base-field-component';
9
9
  export { type ExpandedDynamicType } from './dynamic-form/configurations/structure/row';
10
10
  export { DynamicFormComponent, dynamicTypeToDynamicStructure } from './dynamic-form/dynamic-form.component';
@@ -1,5 +1,5 @@
1
- import { Component, EventEmitter, Input, Output } from '@angular/core';
2
1
  import { NgClass } from '@angular/common';
2
+ import { Component, EventEmitter, input, Input, Output } from '@angular/core';
3
3
  import * as i0 from "@angular/core";
4
4
  /**
5
5
  * @description Componente de alerta que exibe mensagens informativas, de sucesso, aviso ou erro.
@@ -44,6 +44,13 @@ export class AlertComponent {
44
44
  * @default true
45
45
  */
46
46
  closable = true;
47
+ /**
48
+ * @description Quando `true`, o conteúdo do alerta é escapado para evitar a execução de HTML ou scripts.
49
+ * Quando `false`, o conteúdo do alerta é renderizado como HTML, permitindo a inclusão de links, negrito, etc.
50
+ *
51
+ * @default true
52
+ */
53
+ escape = input(true);
47
54
  /**
48
55
  * @description Emitido quando o usuário fecha o alerta clicando no botão de fechar.
49
56
  */
@@ -63,22 +70,21 @@ export class AlertComponent {
63
70
  }
64
71
  _isOpen = true;
65
72
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
66
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AlertComponent, isStandalone: true, selector: "s-alert", inputs: { severity: "severity", summary: "summary", detail: "detail", closable: "closable" }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (isOpen) {\n<div\n class=\"alert flex items-center justify-between gap-4 rounded-medium border-l-4 m-2 py-3 px-4 shadow-[1px_1px_2px_rgba(0,0,0,0.2)]\"\n [ngClass]=\"{\n 'alert--info': severity === 'info',\n 'alert--success': severity === 'success',\n 'alert--warning': severity === 'warning',\n 'alert--error': severity === 'error',\n 'bg-hippie-blue-50 border-primary': severity === 'info',\n 'bg-teal-50 border-criticality-green': severity === 'success',\n 'bg-buttercup-50 border-criticality-yellow': severity === 'warning',\n 'bg-sunset-orange-50 border-criticality-red': severity === 'error',\n }\"\n>\n <div class=\"content flex items-center gap-4\">\n <div\n class=\"icon-container inline-flex flex-shrink-0 items-center justify-center h-10 w-10 rounded-[50%]\"\n [ngClass]=\"{\n 'bg-primary': severity === 'info',\n 'bg-criticality-green': severity === 'success',\n 'bg-criticality-yellow': severity === 'warning',\n 'bg-criticality-red': severity === 'error',\n }\"\n >\n <i\n class=\"fas\"\n [ngClass]=\"{\n 'fa-info': severity === 'info',\n 'fa-check': severity === 'success',\n 'fa-exclamation-triangle': severity === 'warning',\n 'fa-times': severity === 'error',\n 'text-grayscale-0': severity !== 'warning',\n 'text-grayscale-90': severity === 'warning',\n }\"\n ></i>\n </div>\n <div class=\"text-container flex flex-col gap-4\">\n <div class=\"text flex flex-col justify-start\">\n @if (summary) {\n <span class=\"summary font-open-sans text-sm font-bold text-grayscale-90\">{{ summary }}</span>\n }\n\n @if (detail) {\n <span class=\"detail font-open-sans text-sm text-grayscale-90\">{{ detail }}</span>\n }\n </div>\n </div>\n </div>\n @if (closable) {\n <button\n class=\"close-option bg-transparent border-0 text-grayscale-90 cursor-pointer text-base p-1\"\n (click)=\"onClose()\"\n >\n <i class=\"fas fa-times\"></i>\n </button>\n }\n</div>\n}\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
73
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AlertComponent, isStandalone: true, selector: "s-alert", inputs: { severity: { classPropertyName: "severity", publicName: "severity", isSignal: false, isRequired: false, transformFunction: null }, summary: { classPropertyName: "summary", publicName: "summary", isSignal: false, isRequired: true, transformFunction: null }, detail: { classPropertyName: "detail", publicName: "detail", isSignal: false, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: false, isRequired: false, transformFunction: null }, escape: { classPropertyName: "escape", publicName: "escape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (isOpen) {\n <div\n class=\"alert m-2 flex items-center justify-between gap-4 rounded-medium border-l-4 px-4 py-3 shadow-[1px_1px_2px_rgba(0,0,0,0.2)]\"\n [ngClass]=\"{\n 'alert--info': severity === 'info',\n 'alert--success': severity === 'success',\n 'alert--warning': severity === 'warning',\n 'alert--error': severity === 'error',\n 'border-primary bg-hippie-blue-50': severity === 'info',\n 'border-criticality-green bg-teal-50': severity === 'success',\n 'border-criticality-yellow bg-buttercup-50': severity === 'warning',\n 'border-criticality-red bg-sunset-orange-50': severity === 'error',\n }\"\n >\n <div class=\"content flex items-center gap-4\">\n <div\n class=\"icon-container inline-flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-[50%]\"\n [ngClass]=\"{\n 'bg-primary': severity === 'info',\n 'bg-criticality-green': severity === 'success',\n 'bg-criticality-yellow': severity === 'warning',\n 'bg-criticality-red': severity === 'error',\n }\"\n >\n <i\n class=\"fas\"\n [ngClass]=\"{\n 'fa-info': severity === 'info',\n 'fa-check': severity === 'success',\n 'fa-exclamation-triangle': severity === 'warning',\n 'fa-times': severity === 'error',\n 'text-grayscale-0': severity !== 'warning',\n 'text-grayscale-90': severity === 'warning',\n }\"\n ></i>\n </div>\n <div class=\"text-container flex flex-col gap-4\">\n <div class=\"text flex flex-col justify-start\">\n @if (summary) {\n <span class=\"summary font-open-sans text-sm font-bold text-grayscale-90\">{{ summary }}</span>\n }\n\n @if (detail) {\n @if (escape()) {\n <span class=\"detail font-open-sans text-sm text-grayscale-90\">\n {{ detail }}\n </span>\n } @else {\n <span\n class=\"detail font-open-sans text-sm text-grayscale-90\"\n [innerHTML]=\"detail\"\n ></span>\n }\n } @else {\n <span class=\"detail font-open-sans text-sm text-grayscale-90\">\n <ng-content />\n </span>\n }\n </div>\n </div>\n </div>\n @if (closable) {\n <button\n class=\"close-option cursor-pointer border-0 bg-transparent p-1 text-base text-grayscale-90\"\n (click)=\"onClose()\"\n >\n <i class=\"fas fa-times\"></i>\n </button>\n }\n </div>\n}\n\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
67
74
  }
68
75
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, decorators: [{
69
76
  type: Component,
70
- args: [{ selector: 's-alert', standalone: true, imports: [NgClass], template: "@if (isOpen) {\n<div\n class=\"alert flex items-center justify-between gap-4 rounded-medium border-l-4 m-2 py-3 px-4 shadow-[1px_1px_2px_rgba(0,0,0,0.2)]\"\n [ngClass]=\"{\n 'alert--info': severity === 'info',\n 'alert--success': severity === 'success',\n 'alert--warning': severity === 'warning',\n 'alert--error': severity === 'error',\n 'bg-hippie-blue-50 border-primary': severity === 'info',\n 'bg-teal-50 border-criticality-green': severity === 'success',\n 'bg-buttercup-50 border-criticality-yellow': severity === 'warning',\n 'bg-sunset-orange-50 border-criticality-red': severity === 'error',\n }\"\n>\n <div class=\"content flex items-center gap-4\">\n <div\n class=\"icon-container inline-flex flex-shrink-0 items-center justify-center h-10 w-10 rounded-[50%]\"\n [ngClass]=\"{\n 'bg-primary': severity === 'info',\n 'bg-criticality-green': severity === 'success',\n 'bg-criticality-yellow': severity === 'warning',\n 'bg-criticality-red': severity === 'error',\n }\"\n >\n <i\n class=\"fas\"\n [ngClass]=\"{\n 'fa-info': severity === 'info',\n 'fa-check': severity === 'success',\n 'fa-exclamation-triangle': severity === 'warning',\n 'fa-times': severity === 'error',\n 'text-grayscale-0': severity !== 'warning',\n 'text-grayscale-90': severity === 'warning',\n }\"\n ></i>\n </div>\n <div class=\"text-container flex flex-col gap-4\">\n <div class=\"text flex flex-col justify-start\">\n @if (summary) {\n <span class=\"summary font-open-sans text-sm font-bold text-grayscale-90\">{{ summary }}</span>\n }\n\n @if (detail) {\n <span class=\"detail font-open-sans text-sm text-grayscale-90\">{{ detail }}</span>\n }\n </div>\n </div>\n </div>\n @if (closable) {\n <button\n class=\"close-option bg-transparent border-0 text-grayscale-90 cursor-pointer text-base p-1\"\n (click)=\"onClose()\"\n >\n <i class=\"fas fa-times\"></i>\n </button>\n }\n</div>\n}\n" }]
77
+ args: [{ selector: 's-alert', standalone: true, imports: [NgClass], template: "@if (isOpen) {\n <div\n class=\"alert m-2 flex items-center justify-between gap-4 rounded-medium border-l-4 px-4 py-3 shadow-[1px_1px_2px_rgba(0,0,0,0.2)]\"\n [ngClass]=\"{\n 'alert--info': severity === 'info',\n 'alert--success': severity === 'success',\n 'alert--warning': severity === 'warning',\n 'alert--error': severity === 'error',\n 'border-primary bg-hippie-blue-50': severity === 'info',\n 'border-criticality-green bg-teal-50': severity === 'success',\n 'border-criticality-yellow bg-buttercup-50': severity === 'warning',\n 'border-criticality-red bg-sunset-orange-50': severity === 'error',\n }\"\n >\n <div class=\"content flex items-center gap-4\">\n <div\n class=\"icon-container inline-flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-[50%]\"\n [ngClass]=\"{\n 'bg-primary': severity === 'info',\n 'bg-criticality-green': severity === 'success',\n 'bg-criticality-yellow': severity === 'warning',\n 'bg-criticality-red': severity === 'error',\n }\"\n >\n <i\n class=\"fas\"\n [ngClass]=\"{\n 'fa-info': severity === 'info',\n 'fa-check': severity === 'success',\n 'fa-exclamation-triangle': severity === 'warning',\n 'fa-times': severity === 'error',\n 'text-grayscale-0': severity !== 'warning',\n 'text-grayscale-90': severity === 'warning',\n }\"\n ></i>\n </div>\n <div class=\"text-container flex flex-col gap-4\">\n <div class=\"text flex flex-col justify-start\">\n @if (summary) {\n <span class=\"summary font-open-sans text-sm font-bold text-grayscale-90\">{{ summary }}</span>\n }\n\n @if (detail) {\n @if (escape()) {\n <span class=\"detail font-open-sans text-sm text-grayscale-90\">\n {{ detail }}\n </span>\n } @else {\n <span\n class=\"detail font-open-sans text-sm text-grayscale-90\"\n [innerHTML]=\"detail\"\n ></span>\n }\n } @else {\n <span class=\"detail font-open-sans text-sm text-grayscale-90\">\n <ng-content />\n </span>\n }\n </div>\n </div>\n </div>\n @if (closable) {\n <button\n class=\"close-option cursor-pointer border-0 bg-transparent p-1 text-base text-grayscale-90\"\n (click)=\"onClose()\"\n >\n <i class=\"fas fa-times\"></i>\n </button>\n }\n </div>\n}\n\n" }]
71
78
  }], propDecorators: { severity: [{
72
79
  type: Input
73
80
  }], summary: [{
74
81
  type: Input,
75
82
  args: [{ required: true }]
76
83
  }], detail: [{
77
- type: Input,
78
- args: [{ required: true }]
84
+ type: Input
79
85
  }], closable: [{
80
86
  type: Input
81
87
  }], closed: [{
82
88
  type: Output
83
89
  }] } });
84
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxlcnQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jb21wb25lbnRzL2FsZXJ0L3NyYy9saWIvYWxlcnQvYWxlcnQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jb21wb25lbnRzL2FsZXJ0L3NyYy9saWIvYWxlcnQvYWxlcnQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN2RSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0saUJBQWlCLENBQUM7O0FBRTFDOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQU9ILE1BQU0sT0FBTyxjQUFjO0lBQ3ZCOzs7Ozs7OztPQVFHO0lBQ0gsc0VBQXNFO0lBRS9ELFFBQVEsR0FBNkMsTUFBTSxDQUFDO0lBRW5FOztPQUVHO0lBRUksT0FBTyxDQUFVO0lBRXhCOztPQUVHO0lBRUksTUFBTSxDQUFVO0lBRXZCOzs7OztPQUtHO0lBRUksUUFBUSxHQUFHLElBQUksQ0FBQztJQUV2Qjs7T0FFRztJQUVJLE1BQU0sR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO0lBRXpDLElBQVcsTUFBTTtRQUNiLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQztJQUN4QixDQUFDO0lBRU0sVUFBVTtRQUNiLElBQUksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDO0lBQ3pCLENBQUM7SUFFTSxTQUFTO1FBQ1osSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7SUFDeEIsQ0FBQztJQUVNLE9BQU87UUFDVixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRU8sT0FBTyxHQUFHLElBQUksQ0FBQzt3R0ExRGQsY0FBYzs0RkFBZCxjQUFjLGdNQ3pCM0IsazRFQTBEQSw0Q0RuQ2MsT0FBTzs7NEZBRVIsY0FBYztrQkFOMUIsU0FBUzsrQkFDSSxTQUFTLGNBRVAsSUFBSSxXQUNQLENBQUMsT0FBTyxDQUFDOzhCQWNYLFFBQVE7c0JBRGQsS0FBSztnQkFPQyxPQUFPO3NCQURiLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQU9sQixNQUFNO3NCQURaLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQVVsQixRQUFRO3NCQURkLEtBQUs7Z0JBT0MsTUFBTTtzQkFEWixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgTmdDbGFzcyB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcblxyXG4vKipcclxuICogQGRlc2NyaXB0aW9uIENvbXBvbmVudGUgZGUgYWxlcnRhIHF1ZSBleGliZSBtZW5zYWdlbnMgaW5mb3JtYXRpdmFzLCBkZSBzdWNlc3NvLCBhdmlzbyBvdSBlcnJvLlxyXG4gKiBTdXBvcnRhIGZlY2hhbWVudG8gbWFudWFsIHBlbG8gdXN1w6FyaW8gZSBlbWl0ZSB1bSBldmVudG8gYW8gc2VyIGZlY2hhZG8uXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGBgYGh0bWxcclxuICogPHMtYWxlcnRcclxuICogICBzZXZlcml0eT1cIndhcm5pbmdcIlxyXG4gKiAgIHN1bW1hcnk9XCJBdGVuw6fDo29cIlxyXG4gKiAgIGRldGFpbD1cIlZlcmlmaXF1ZSBvcyBkYWRvcyBhbnRlcyBkZSBjb250aW51YXIuXCJcclxuICogICAoY2xvc2VkKT1cIm9uQWxlcnRDbG9zZWQoKVwiXHJcbiAqIC8+XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBAY2F0ZWdvcnkgRmVlZGJhY2tcclxuICovXHJcbkBDb21wb25lbnQoe1xyXG4gICAgc2VsZWN0b3I6ICdzLWFsZXJ0JyxcclxuICAgIHRlbXBsYXRlVXJsOiAnLi9hbGVydC5jb21wb25lbnQuaHRtbCcsXHJcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gICAgaW1wb3J0czogW05nQ2xhc3NdLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQWxlcnRDb21wb25lbnQge1xyXG4gICAgLyoqXHJcbiAgICAgKiBAZGVzY3JpcHRpb24gTsOtdmVsIGRlIHNldmVyaWRhZGUgZG8gYWxlcnRhLCBxdWUgZGVmaW5lIGEgY29yIGUgbyDDrWNvbmUgZXhpYmlkb3MuXHJcbiAgICAgKiAtIGAnaW5mbydgOiBhbGVydGEgaW5mb3JtYXRpdm8gKHBhZHLDo28pLlxyXG4gICAgICogLSBgJ3N1Y2Nlc3MnYDogYWxlcnRhIGRlIHN1Y2Vzc28uXHJcbiAgICAgKiAtIGAnd2FybmluZydgOiBhbGVydGEgZGUgYXZpc28uXHJcbiAgICAgKiAtIGAnZXJyb3InYDogYWxlcnRhIGRlIGVycm8uXHJcbiAgICAgKlxyXG4gICAgICogQGRlZmF1bHQgJ2luZm8nXHJcbiAgICAgKi9cclxuICAgIC8vIHNvbmFyLWlnbm9yZTogUmVmYWN0b3IgdGhpcyB1bmlvbiB0eXBlIHRvIGhhdmUgbGVzcyB0aGFuIDMgZWxlbWVudHNcclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgc2V2ZXJpdHk6ICdpbmZvJyB8ICdzdWNjZXNzJyB8ICd3YXJuaW5nJyB8ICdlcnJvcicgPSAnaW5mbyc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAZGVzY3JpcHRpb24gVMOtdHVsbyBwcmluY2lwYWwgZG8gYWxlcnRhIGV4aWJpZG8gZW0gZGVzdGFxdWUuIENhbXBvIG9icmlnYXTDs3Jpby5cclxuICAgICAqL1xyXG4gICAgQElucHV0KHsgcmVxdWlyZWQ6IHRydWUgfSlcclxuICAgIHB1YmxpYyBzdW1tYXJ5ITogc3RyaW5nO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQGRlc2NyaXB0aW9uIE1lbnNhZ2VtIGRldGFsaGFkYSBleGliaWRhIGFiYWl4byBkbyB0w610dWxvIGRvIGFsZXJ0YS4gQ2FtcG8gb2JyaWdhdMOzcmlvLlxyXG4gICAgICovXHJcbiAgICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KVxyXG4gICAgcHVibGljIGRldGFpbCE6IHN0cmluZztcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBkZXNjcmlwdGlvbiBRdWFuZG8gYHRydWVgLCBleGliZSBvIGJvdMOjbyBkZSBmZWNoYXIgbyBhbGVydGEuXHJcbiAgICAgKiBRdWFuZG8gYGZhbHNlYCwgbyBhbGVydGEgbsOjbyBwb2RlIHNlciBkaXNwZW5zYWRvIHBlbG8gdXN1w6FyaW8uXHJcbiAgICAgKlxyXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIGNsb3NhYmxlID0gdHJ1ZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBkZXNjcmlwdGlvbiBFbWl0aWRvIHF1YW5kbyBvIHVzdcOhcmlvIGZlY2hhIG8gYWxlcnRhIGNsaWNhbmRvIG5vIGJvdMOjbyBkZSBmZWNoYXIuXHJcbiAgICAgKi9cclxuICAgIEBPdXRwdXQoKVxyXG4gICAgcHVibGljIGNsb3NlZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgICBwdWJsaWMgZ2V0IGlzT3BlbigpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5faXNPcGVuO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBjbG9zZUFsZXJ0KCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuX2lzT3BlbiA9IGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBzaG93QWxlcnQoKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5faXNPcGVuID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25DbG9zZSgpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLmNsb3NlZC5lbWl0KCk7XHJcbiAgICAgICAgdGhpcy5jbG9zZUFsZXJ0KCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBfaXNPcGVuID0gdHJ1ZTtcclxufVxyXG4iLCJAaWYgKGlzT3Blbikge1xuPGRpdlxuICAgIGNsYXNzPVwiYWxlcnQgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIGdhcC00IHJvdW5kZWQtbWVkaXVtIGJvcmRlci1sLTQgbS0yIHB5LTMgcHgtNCBzaGFkb3ctWzFweF8xcHhfMnB4X3JnYmEoMCwwLDAsMC4yKV1cIlxuICAgIFtuZ0NsYXNzXT1cIntcbiAgICAgICAgJ2FsZXJ0LS1pbmZvJzogc2V2ZXJpdHkgPT09ICdpbmZvJyxcbiAgICAgICAgJ2FsZXJ0LS1zdWNjZXNzJzogc2V2ZXJpdHkgPT09ICdzdWNjZXNzJyxcbiAgICAgICAgJ2FsZXJ0LS13YXJuaW5nJzogc2V2ZXJpdHkgPT09ICd3YXJuaW5nJyxcbiAgICAgICAgJ2FsZXJ0LS1lcnJvcic6IHNldmVyaXR5ID09PSAnZXJyb3InLFxuICAgICAgICAnYmctaGlwcGllLWJsdWUtNTAgYm9yZGVyLXByaW1hcnknOiBzZXZlcml0eSA9PT0gJ2luZm8nLFxuICAgICAgICAnYmctdGVhbC01MCBib3JkZXItY3JpdGljYWxpdHktZ3JlZW4nOiBzZXZlcml0eSA9PT0gJ3N1Y2Nlc3MnLFxuICAgICAgICAnYmctYnV0dGVyY3VwLTUwIGJvcmRlci1jcml0aWNhbGl0eS15ZWxsb3cnOiBzZXZlcml0eSA9PT0gJ3dhcm5pbmcnLFxuICAgICAgICAnYmctc3Vuc2V0LW9yYW5nZS01MCBib3JkZXItY3JpdGljYWxpdHktcmVkJzogc2V2ZXJpdHkgPT09ICdlcnJvcicsXG4gICAgfVwiXG4+XG4gICAgPGRpdiBjbGFzcz1cImNvbnRlbnQgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTRcIj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3M9XCJpY29uLWNvbnRhaW5lciBpbmxpbmUtZmxleCBmbGV4LXNocmluay0wIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBoLTEwIHctMTAgcm91bmRlZC1bNTAlXVwiXG4gICAgICAgICAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgICAgICAgICAgJ2JnLXByaW1hcnknOiBzZXZlcml0eSA9PT0gJ2luZm8nLFxuICAgICAgICAgICAgICAgICdiZy1jcml0aWNhbGl0eS1ncmVlbic6IHNldmVyaXR5ID09PSAnc3VjY2VzcycsXG4gICAgICAgICAgICAgICAgJ2JnLWNyaXRpY2FsaXR5LXllbGxvdyc6IHNldmVyaXR5ID09PSAnd2FybmluZycsXG4gICAgICAgICAgICAgICAgJ2JnLWNyaXRpY2FsaXR5LXJlZCc6IHNldmVyaXR5ID09PSAnZXJyb3InLFxuICAgICAgICAgICAgfVwiXG4gICAgICAgID5cbiAgICAgICAgICAgIDxpXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmYXNcIlxuICAgICAgICAgICAgICAgIFtuZ0NsYXNzXT1cIntcbiAgICAgICAgICAgICAgICAgICAgJ2ZhLWluZm8nOiBzZXZlcml0eSA9PT0gJ2luZm8nLFxuICAgICAgICAgICAgICAgICAgICAnZmEtY2hlY2snOiBzZXZlcml0eSA9PT0gJ3N1Y2Nlc3MnLFxuICAgICAgICAgICAgICAgICAgICAnZmEtZXhjbGFtYXRpb24tdHJpYW5nbGUnOiBzZXZlcml0eSA9PT0gJ3dhcm5pbmcnLFxuICAgICAgICAgICAgICAgICAgICAnZmEtdGltZXMnOiBzZXZlcml0eSA9PT0gJ2Vycm9yJyxcbiAgICAgICAgICAgICAgICAgICAgJ3RleHQtZ3JheXNjYWxlLTAnOiBzZXZlcml0eSAhPT0gJ3dhcm5pbmcnLFxuICAgICAgICAgICAgICAgICAgICAndGV4dC1ncmF5c2NhbGUtOTAnOiBzZXZlcml0eSA9PT0gJ3dhcm5pbmcnLFxuICAgICAgICAgICAgICAgIH1cIlxuICAgICAgICAgICAgPjwvaT5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0ZXh0LWNvbnRhaW5lciBmbGV4IGZsZXgtY29sIGdhcC00XCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwidGV4dCBmbGV4IGZsZXgtY29sIGp1c3RpZnktc3RhcnRcIj5cbiAgICAgICAgICAgICAgICBAaWYgKHN1bW1hcnkpIHtcbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzdW1tYXJ5IGZvbnQtb3Blbi1zYW5zIHRleHQtc20gZm9udC1ib2xkIHRleHQtZ3JheXNjYWxlLTkwXCI+e3sgc3VtbWFyeSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBAaWYgKGRldGFpbCkge1xuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImRldGFpbCBmb250LW9wZW4tc2FucyB0ZXh0LXNtIHRleHQtZ3JheXNjYWxlLTkwXCI+e3sgZGV0YWlsIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICBAaWYgKGNsb3NhYmxlKSB7XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIGNsYXNzPVwiY2xvc2Utb3B0aW9uIGJnLXRyYW5zcGFyZW50IGJvcmRlci0wIHRleHQtZ3JheXNjYWxlLTkwIGN1cnNvci1wb2ludGVyIHRleHQtYmFzZSBwLTFcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm9uQ2xvc2UoKVwiXG4gICAgICAgID5cbiAgICAgICAgICAgIDxpIGNsYXNzPVwiZmFzIGZhLXRpbWVzXCI+PC9pPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICB9XG48L2Rpdj5cbn1cbiJdfQ==
90
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxlcnQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jb21wb25lbnRzL2FsZXJ0L3NyYy9saWIvYWxlcnQvYWxlcnQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jb21wb25lbnRzL2FsZXJ0L3NyYy9saWIvYWxlcnQvYWxlcnQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQUU5RTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFPSCxNQUFNLE9BQU8sY0FBYztJQUN2Qjs7Ozs7Ozs7T0FRRztJQUNILHNFQUFzRTtJQUUvRCxRQUFRLEdBQTZDLE1BQU0sQ0FBQztJQUVuRTs7T0FFRztJQUVJLE9BQU8sQ0FBVTtJQUV4Qjs7T0FFRztJQUVJLE1BQU0sQ0FBVTtJQUV2Qjs7Ozs7T0FLRztJQUVJLFFBQVEsR0FBRyxJQUFJLENBQUM7SUFFdkI7Ozs7O09BS0c7SUFDSCxNQUFNLEdBQUcsS0FBSyxDQUFVLElBQUksQ0FBQyxDQUFDO0lBRTlCOztPQUVHO0lBRUksTUFBTSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7SUFFekMsSUFBVyxNQUFNO1FBQ2IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3hCLENBQUM7SUFFTSxVQUFVO1FBQ2IsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDekIsQ0FBQztJQUVNLFNBQVM7UUFDWixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztJQUN4QixDQUFDO0lBRU0sT0FBTztRQUNWLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbkIsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFTyxPQUFPLEdBQUcsSUFBSSxDQUFDO3dHQWxFZCxjQUFjOzRGQUFkLGNBQWMsdXVCQ3pCM0IsOHFHQXdFQSw0Q0RqRGMsT0FBTzs7NEZBRVIsY0FBYztrQkFOMUIsU0FBUzsrQkFDSSxTQUFTLGNBRVAsSUFBSSxXQUNQLENBQUMsT0FBTyxDQUFDOzhCQWNYLFFBQVE7c0JBRGQsS0FBSztnQkFPQyxPQUFPO3NCQURiLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQU9sQixNQUFNO3NCQURaLEtBQUs7Z0JBVUMsUUFBUTtzQkFEZCxLQUFLO2dCQWVDLE1BQU07c0JBRFosTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nQ2xhc3MgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgaW5wdXQsIElucHV0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbi8qKlxyXG4gKiBAZGVzY3JpcHRpb24gQ29tcG9uZW50ZSBkZSBhbGVydGEgcXVlIGV4aWJlIG1lbnNhZ2VucyBpbmZvcm1hdGl2YXMsIGRlIHN1Y2Vzc28sIGF2aXNvIG91IGVycm8uXHJcbiAqIFN1cG9ydGEgZmVjaGFtZW50byBtYW51YWwgcGVsbyB1c3XDoXJpbyBlIGVtaXRlIHVtIGV2ZW50byBhbyBzZXIgZmVjaGFkby5cclxuICpcclxuICogQGV4YW1wbGVcclxuICogYGBgaHRtbFxyXG4gKiA8cy1hbGVydFxyXG4gKiAgIHNldmVyaXR5PVwid2FybmluZ1wiXHJcbiAqICAgc3VtbWFyeT1cIkF0ZW7Dp8Ojb1wiXHJcbiAqICAgZGV0YWlsPVwiVmVyaWZpcXVlIG9zIGRhZG9zIGFudGVzIGRlIGNvbnRpbnVhci5cIlxyXG4gKiAgIChjbG9zZWQpPVwib25BbGVydENsb3NlZCgpXCJcclxuICogLz5cclxuICogYGBgXHJcbiAqXHJcbiAqIEBjYXRlZ29yeSBGZWVkYmFja1xyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgICBzZWxlY3RvcjogJ3MtYWxlcnQnLFxyXG4gICAgdGVtcGxhdGVVcmw6ICcuL2FsZXJ0LmNvbXBvbmVudC5odG1sJyxcclxuICAgIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgICBpbXBvcnRzOiBbTmdDbGFzc10sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBBbGVydENvbXBvbmVudCB7XHJcbiAgICAvKipcclxuICAgICAqIEBkZXNjcmlwdGlvbiBOw612ZWwgZGUgc2V2ZXJpZGFkZSBkbyBhbGVydGEsIHF1ZSBkZWZpbmUgYSBjb3IgZSBvIMOtY29uZSBleGliaWRvcy5cclxuICAgICAqIC0gYCdpbmZvJ2A6IGFsZXJ0YSBpbmZvcm1hdGl2byAocGFkcsOjbykuXHJcbiAgICAgKiAtIGAnc3VjY2VzcydgOiBhbGVydGEgZGUgc3VjZXNzby5cclxuICAgICAqIC0gYCd3YXJuaW5nJ2A6IGFsZXJ0YSBkZSBhdmlzby5cclxuICAgICAqIC0gYCdlcnJvcidgOiBhbGVydGEgZGUgZXJyby5cclxuICAgICAqXHJcbiAgICAgKiBAZGVmYXVsdCAnaW5mbydcclxuICAgICAqL1xyXG4gICAgLy8gc29uYXItaWdub3JlOiBSZWZhY3RvciB0aGlzIHVuaW9uIHR5cGUgdG8gaGF2ZSBsZXNzIHRoYW4gMyBlbGVtZW50c1xyXG4gICAgQElucHV0KClcclxuICAgIHB1YmxpYyBzZXZlcml0eTogJ2luZm8nIHwgJ3N1Y2Nlc3MnIHwgJ3dhcm5pbmcnIHwgJ2Vycm9yJyA9ICdpbmZvJztcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBkZXNjcmlwdGlvbiBUw610dWxvIHByaW5jaXBhbCBkbyBhbGVydGEgZXhpYmlkbyBlbSBkZXN0YXF1ZS4gQ2FtcG8gb2JyaWdhdMOzcmlvLlxyXG4gICAgICovXHJcbiAgICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KVxyXG4gICAgcHVibGljIHN1bW1hcnkhOiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAZGVzY3JpcHRpb24gTWVuc2FnZW0gZGV0YWxoYWRhIGV4aWJpZGEgYWJhaXhvIGRvIHTDrXR1bG8gZG8gYWxlcnRhLiBDYW1wbyBvYnJpZ2F0w7NyaW8uXHJcbiAgICAgKi9cclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgZGV0YWlsITogc3RyaW5nO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQGRlc2NyaXB0aW9uIFF1YW5kbyBgdHJ1ZWAsIGV4aWJlIG8gYm90w6NvIGRlIGZlY2hhciBvIGFsZXJ0YS5cclxuICAgICAqIFF1YW5kbyBgZmFsc2VgLCBvIGFsZXJ0YSBuw6NvIHBvZGUgc2VyIGRpc3BlbnNhZG8gcGVsbyB1c3XDoXJpby5cclxuICAgICAqXHJcbiAgICAgKiBAZGVmYXVsdCB0cnVlXHJcbiAgICAgKi9cclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgY2xvc2FibGUgPSB0cnVlO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQGRlc2NyaXB0aW9uIFF1YW5kbyBgdHJ1ZWAsIG8gY29udGXDumRvIGRvIGFsZXJ0YSDDqSBlc2NhcGFkbyBwYXJhIGV2aXRhciBhIGV4ZWN1w6fDo28gZGUgSFRNTCBvdSBzY3JpcHRzLlxyXG4gICAgICogUXVhbmRvIGBmYWxzZWAsIG8gY29udGXDumRvIGRvIGFsZXJ0YSDDqSByZW5kZXJpemFkbyBjb21vIEhUTUwsIHBlcm1pdGluZG8gYSBpbmNsdXPDo28gZGUgbGlua3MsIG5lZ3JpdG8sIGV0Yy5cclxuICAgICAqXHJcbiAgICAgKiBAZGVmYXVsdCB0cnVlXHJcbiAgICAgKi9cclxuICAgIGVzY2FwZSA9IGlucHV0PGJvb2xlYW4+KHRydWUpO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQGRlc2NyaXB0aW9uIEVtaXRpZG8gcXVhbmRvIG8gdXN1w6FyaW8gZmVjaGEgbyBhbGVydGEgY2xpY2FuZG8gbm8gYm90w6NvIGRlIGZlY2hhci5cclxuICAgICAqL1xyXG4gICAgQE91dHB1dCgpXHJcbiAgICBwdWJsaWMgY2xvc2VkID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICAgIHB1YmxpYyBnZXQgaXNPcGVuKCk6IGJvb2xlYW4ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLl9pc09wZW47XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGNsb3NlQWxlcnQoKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5faXNPcGVuID0gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHNob3dBbGVydCgpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLl9pc09wZW4gPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbkNsb3NlKCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuY2xvc2VkLmVtaXQoKTtcclxuICAgICAgICB0aGlzLmNsb3NlQWxlcnQoKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIF9pc09wZW4gPSB0cnVlO1xyXG59XHJcbiIsIkBpZiAoaXNPcGVuKSB7XG4gICAgPGRpdlxuICAgICAgICBjbGFzcz1cImFsZXJ0IG0tMiBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gZ2FwLTQgcm91bmRlZC1tZWRpdW0gYm9yZGVyLWwtNCBweC00IHB5LTMgc2hhZG93LVsxcHhfMXB4XzJweF9yZ2JhKDAsMCwwLDAuMildXCJcbiAgICAgICAgW25nQ2xhc3NdPVwie1xuICAgICAgICAgICAgJ2FsZXJ0LS1pbmZvJzogc2V2ZXJpdHkgPT09ICdpbmZvJyxcbiAgICAgICAgICAgICdhbGVydC0tc3VjY2Vzcyc6IHNldmVyaXR5ID09PSAnc3VjY2VzcycsXG4gICAgICAgICAgICAnYWxlcnQtLXdhcm5pbmcnOiBzZXZlcml0eSA9PT0gJ3dhcm5pbmcnLFxuICAgICAgICAgICAgJ2FsZXJ0LS1lcnJvcic6IHNldmVyaXR5ID09PSAnZXJyb3InLFxuICAgICAgICAgICAgJ2JvcmRlci1wcmltYXJ5IGJnLWhpcHBpZS1ibHVlLTUwJzogc2V2ZXJpdHkgPT09ICdpbmZvJyxcbiAgICAgICAgICAgICdib3JkZXItY3JpdGljYWxpdHktZ3JlZW4gYmctdGVhbC01MCc6IHNldmVyaXR5ID09PSAnc3VjY2VzcycsXG4gICAgICAgICAgICAnYm9yZGVyLWNyaXRpY2FsaXR5LXllbGxvdyBiZy1idXR0ZXJjdXAtNTAnOiBzZXZlcml0eSA9PT0gJ3dhcm5pbmcnLFxuICAgICAgICAgICAgJ2JvcmRlci1jcml0aWNhbGl0eS1yZWQgYmctc3Vuc2V0LW9yYW5nZS01MCc6IHNldmVyaXR5ID09PSAnZXJyb3InLFxuICAgICAgICB9XCJcbiAgICA+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjb250ZW50IGZsZXggaXRlbXMtY2VudGVyIGdhcC00XCI+XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgY2xhc3M9XCJpY29uLWNvbnRhaW5lciBpbmxpbmUtZmxleCBoLTEwIHctMTAgZmxleC1zaHJpbmstMCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgcm91bmRlZC1bNTAlXVwiXG4gICAgICAgICAgICAgICAgW25nQ2xhc3NdPVwie1xuICAgICAgICAgICAgICAgICAgICAnYmctcHJpbWFyeSc6IHNldmVyaXR5ID09PSAnaW5mbycsXG4gICAgICAgICAgICAgICAgICAgICdiZy1jcml0aWNhbGl0eS1ncmVlbic6IHNldmVyaXR5ID09PSAnc3VjY2VzcycsXG4gICAgICAgICAgICAgICAgICAgICdiZy1jcml0aWNhbGl0eS15ZWxsb3cnOiBzZXZlcml0eSA9PT0gJ3dhcm5pbmcnLFxuICAgICAgICAgICAgICAgICAgICAnYmctY3JpdGljYWxpdHktcmVkJzogc2V2ZXJpdHkgPT09ICdlcnJvcicsXG4gICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGlcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJmYXNcIlxuICAgICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgICAgICAgICAgICAgICAgICAnZmEtaW5mbyc6IHNldmVyaXR5ID09PSAnaW5mbycsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZmEtY2hlY2snOiBzZXZlcml0eSA9PT0gJ3N1Y2Nlc3MnLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2ZhLWV4Y2xhbWF0aW9uLXRyaWFuZ2xlJzogc2V2ZXJpdHkgPT09ICd3YXJuaW5nJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICdmYS10aW1lcyc6IHNldmVyaXR5ID09PSAnZXJyb3InLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ3RleHQtZ3JheXNjYWxlLTAnOiBzZXZlcml0eSAhPT0gJ3dhcm5pbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ3RleHQtZ3JheXNjYWxlLTkwJzogc2V2ZXJpdHkgPT09ICd3YXJuaW5nJyxcbiAgICAgICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgICAgPjwvaT5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInRleHQtY29udGFpbmVyIGZsZXggZmxleC1jb2wgZ2FwLTRcIj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwidGV4dCBmbGV4IGZsZXgtY29sIGp1c3RpZnktc3RhcnRcIj5cbiAgICAgICAgICAgICAgICAgICAgQGlmIChzdW1tYXJ5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInN1bW1hcnkgZm9udC1vcGVuLXNhbnMgdGV4dC1zbSBmb250LWJvbGQgdGV4dC1ncmF5c2NhbGUtOTBcIj57eyBzdW1tYXJ5IH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgQGlmIChkZXRhaWwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIEBpZiAoZXNjYXBlKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImRldGFpbCBmb250LW9wZW4tc2FucyB0ZXh0LXNtIHRleHQtZ3JheXNjYWxlLTkwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7IGRldGFpbCB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiZGV0YWlsIGZvbnQtb3Blbi1zYW5zIHRleHQtc20gdGV4dC1ncmF5c2NhbGUtOTBcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbaW5uZXJIVE1MXT1cImRldGFpbFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPjwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImRldGFpbCBmb250LW9wZW4tc2FucyB0ZXh0LXNtIHRleHQtZ3JheXNjYWxlLTkwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRlbnQgLz5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICBAaWYgKGNsb3NhYmxlKSB7XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJjbG9zZS1vcHRpb24gY3Vyc29yLXBvaW50ZXIgYm9yZGVyLTAgYmctdHJhbnNwYXJlbnQgcC0xIHRleHQtYmFzZSB0ZXh0LWdyYXlzY2FsZS05MFwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uQ2xvc2UoKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJmYXMgZmEtdGltZXNcIj48L2k+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuICAgIDwvZGl2PlxufVxuXG4iXX0=