@decaf-ts/for-angular 0.0.25 → 0.0.26

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 (78) hide show
  1. package/fesm2022/decaf-ts-for-angular.mjs +1465 -1488
  2. package/fesm2022/decaf-ts-for-angular.mjs.map +1 -1
  3. package/index.d.ts +7470 -3
  4. package/package.json +14 -17
  5. package/components/component-renderer/component-renderer.component.d.ts +0 -278
  6. package/components/crud-field/crud-field.component.d.ts +0 -611
  7. package/components/crud-form/constants.d.ts +0 -5
  8. package/components/crud-form/crud-form.component.d.ts +0 -288
  9. package/components/crud-form/types.d.ts +0 -17
  10. package/components/empty-state/empty-state.component.d.ts +0 -300
  11. package/components/fieldset/fieldset.component.d.ts +0 -555
  12. package/components/filter/filter.component.d.ts +0 -514
  13. package/components/for-angular-components.module.d.ts +0 -20
  14. package/components/index.d.ts +0 -16
  15. package/components/layout/layout.component.d.ts +0 -110
  16. package/components/list/list.component.d.ts +0 -848
  17. package/components/list-item/list-item.component.d.ts +0 -390
  18. package/components/model-renderer/model-renderer.component.d.ts +0 -97
  19. package/components/pagination/constants.d.ts +0 -7
  20. package/components/pagination/pagination.component.d.ts +0 -264
  21. package/components/searchbar/searchbar.component.d.ts +0 -407
  22. package/components/stepped-form/stepped-form.component.d.ts +0 -255
  23. package/directives/collapsable.directive.d.ts +0 -9
  24. package/directives/index.d.ts +0 -1
  25. package/engine/DynamicModule.d.ts +0 -17
  26. package/engine/NgxBaseComponent.d.ts +0 -541
  27. package/engine/NgxCrudFormField.d.ts +0 -123
  28. package/engine/NgxFormService.d.ts +0 -601
  29. package/engine/NgxRenderingEngine.d.ts +0 -282
  30. package/engine/ValidatorFactory.d.ts +0 -15
  31. package/engine/constants.d.ts +0 -168
  32. package/engine/decorators.d.ts +0 -25
  33. package/engine/index.d.ts +0 -18
  34. package/engine/interfaces.d.ts +0 -271
  35. package/engine/types.d.ts +0 -200
  36. package/esm2022/components/component-renderer/component-renderer.component.mjs +0 -321
  37. package/esm2022/components/crud-field/crud-field.component.mjs +0 -518
  38. package/esm2022/components/crud-form/constants.mjs +0 -14
  39. package/esm2022/components/crud-form/crud-form.component.mjs +0 -259
  40. package/esm2022/components/crud-form/types.mjs +0 -2
  41. package/esm2022/components/empty-state/empty-state.component.mjs +0 -345
  42. package/esm2022/components/fieldset/fieldset.component.mjs +0 -677
  43. package/esm2022/components/filter/filter.component.mjs +0 -700
  44. package/esm2022/components/for-angular-components.module.mjs +0 -84
  45. package/esm2022/components/index.mjs +0 -20
  46. package/esm2022/components/layout/layout.component.mjs +0 -150
  47. package/esm2022/components/list/list.component.mjs +0 -1238
  48. package/esm2022/components/list-item/list-item.component.mjs +0 -405
  49. package/esm2022/components/model-renderer/model-renderer.component.mjs +0 -144
  50. package/esm2022/components/pagination/constants.mjs +0 -2
  51. package/esm2022/components/pagination/pagination.component.mjs +0 -321
  52. package/esm2022/components/searchbar/searchbar.component.mjs +0 -491
  53. package/esm2022/components/stepped-form/stepped-form.component.mjs +0 -306
  54. package/esm2022/decaf-ts-for-angular.mjs +0 -5
  55. package/esm2022/directives/collapsable.directive.mjs +0 -29
  56. package/esm2022/directives/index.mjs +0 -2
  57. package/esm2022/engine/DynamicModule.mjs +0 -18
  58. package/esm2022/engine/NgxBaseComponent.mjs +0 -541
  59. package/esm2022/engine/NgxCrudFormField.mjs +0 -137
  60. package/esm2022/engine/NgxFormService.mjs +0 -917
  61. package/esm2022/engine/NgxRenderingEngine.mjs +0 -376
  62. package/esm2022/engine/ValidatorFactory.mjs +0 -106
  63. package/esm2022/engine/constants.mjs +0 -170
  64. package/esm2022/engine/decorators.mjs +0 -38
  65. package/esm2022/engine/index.mjs +0 -19
  66. package/esm2022/engine/interfaces.mjs +0 -4
  67. package/esm2022/engine/types.mjs +0 -2
  68. package/esm2022/for-angular-common.module.mjs +0 -84
  69. package/esm2022/helpers/index.mjs +0 -13
  70. package/esm2022/helpers/utils.mjs +0 -436
  71. package/esm2022/i18n/Loader.mjs +0 -86
  72. package/esm2022/i18n/data/en.json +0 -85
  73. package/esm2022/public-apis.mjs +0 -15
  74. package/for-angular-common.module.d.ts +0 -50
  75. package/helpers/index.d.ts +0 -12
  76. package/helpers/utils.d.ts +0 -279
  77. package/i18n/Loader.d.ts +0 -43
  78. package/public-apis.d.ts +0 -14
@@ -1,700 +0,0 @@
1
- import { __decorate, __metadata } from "tslib";
2
- import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
3
- import { NgxBaseComponent } from '../../engine/NgxBaseComponent';
4
- import { IonButton, IonChip, IonIcon, IonItem, IonLabel, IonSelect, IonSelectOption } from '@ionic/angular/standalone';
5
- import { Dynamic } from '../../engine';
6
- import { getWindowWidth, isDarkMode } from '../../helpers/utils';
7
- import { debounceTime, fromEvent } from 'rxjs';
8
- import { OrderDirection, Repository } from '@decaf-ts/core';
9
- import { SearchbarComponent } from '../searchbar/searchbar.component';
10
- import { addIcons } from 'ionicons';
11
- import { chevronDownOutline, chevronUpOutline } from 'ionicons/icons';
12
- import { TranslatePipe } from '@ngx-translate/core';
13
- import { FormsModule } from '@angular/forms';
14
- import * as i0 from "@angular/core";
15
- import * as i1 from "@angular/forms";
16
- /**
17
- * @description Advanced filter component for creating dynamic search filters with step-by-step construction.
18
- * @summary This component provides a comprehensive filtering interface that allows users to build
19
- * complex search criteria using a three-step approach: select index → select condition → enter value.
20
- * It supports filtering by multiple field indexes, comparison conditions, and values, displaying
21
- * selected filters as removable chips. The component is responsive and includes auto-suggestions
22
- * with keyboard navigation support.
23
- *
24
- * @example
25
- * ```html
26
- * <ngx-decaf-filter
27
- * [indexes]="['name', 'email', 'department', 'status']"
28
- * [conditions]="['Equal', 'Contains', 'Greater Than', 'Less Than']"
29
- * [sort]="['createdAt', 'updatedAt']"
30
- * [disableSort]="false"
31
- * (filterEvent)="onFiltersChanged($event)">
32
- * </ngx-decaf-filter>
33
- * ```
34
- *
35
- * @mermaid
36
- * sequenceDiagram
37
- * participant U as User
38
- * participant F as FilterComponent
39
- * participant P as Parent Component
40
- *
41
- * U->>F: Focus input field
42
- * F->>F: handleFocus() - Show available indexes
43
- * U->>F: Select index (e.g., "name")
44
- * F->>F: addFilter() - Step 1 completed
45
- * F->>F: Show available conditions
46
- * U->>F: Select condition (e.g., "Contains")
47
- * F->>F: addFilter() - Step 2 completed
48
- * F->>F: Show value input prompt
49
- * U->>F: Enter value and press Enter
50
- * F->>F: addFilter() - Step 3 completed
51
- * F->>F: Create complete filter object
52
- * F->>P: Emit filterEvent with new filter array
53
- * F->>F: Reset to step 1 for next filter
54
- *
55
- * @memberOf ForAngularCommonModule
56
- */
57
- let FilterComponent = class FilterComponent extends NgxBaseComponent {
58
- /**
59
- * @description Constructor for FilterComponent.
60
- * @summary Initializes a new instance of the FilterComponent.
61
- * Calls the parent constructor with the component name to establish base locale string generation
62
- * and internationalization support.
63
- *
64
- * @memberOf FilterComponent
65
- */
66
- constructor() {
67
- super("FilterComponent");
68
- /**
69
- * @description Available field indexes for filtering operations.
70
- * @summary Defines the list of field names that users can filter by. These represent
71
- * the data properties available for filtering operations. Each index corresponds to
72
- * a field in the data model that supports comparison operations.
73
- *
74
- * @type {string[]}
75
- * @default []
76
- * @memberOf FilterComponent
77
- */
78
- this.indexes = [];
79
- /**
80
- * @description Available comparison conditions for filters.
81
- * @summary Defines the list of comparison operators that can be used when creating filters.
82
- * These conditions determine how the filter value is compared against the field value.
83
- * Common conditions include equality, containment, and numerical comparison operations.
84
- *
85
- * @type {string[]}
86
- * @default []
87
- * @memberOf FilterComponent
88
- */
89
- this.conditions = ['Equal', 'Contains', 'Not Contains', 'Greater Than', 'Less Than', 'Not Equal'];
90
- /**
91
- * @description Available sorting options for the filtered data.
92
- * @summary Defines the list of field names that can be used for sorting the filtered results.
93
- * When disableSort is false, this array is automatically merged with the indexes array
94
- * to provide comprehensive sorting capabilities.
95
- *
96
- * @type {string[]}
97
- * @default []
98
- * @memberOf FilterComponent
99
- */
100
- this.sortBy = [];
101
- /**
102
- * @description Controls whether sorting functionality is disabled.
103
- * @summary When set to true, prevents the automatic merging of sort and indexes arrays,
104
- * effectively disabling sorting capabilities. This is useful when you want to provide
105
- * filtering without sorting options.
106
- *
107
- * @type {boolean}
108
- * @default false
109
- * @memberOf FilterComponent
110
- */
111
- this.disableSort = false;
112
- /**
113
- * @description Available options for the current filter step.
114
- * @summary Contains the list of options available for selection in the current step.
115
- * This array changes dynamically based on the current step: indexes → conditions → empty for value input.
116
- *
117
- * @type {string[]}
118
- * @default []
119
- * @memberOf FilterComponent
120
- */
121
- this.options = [];
122
- /**
123
- * @description Filtered options based on user input.
124
- * @summary Contains the subset of options that match the current user input for real-time
125
- * filtering. This array is updated as the user types to show only relevant suggestions
126
- * in the dropdown menu.
127
- *
128
- * @type {string[]}
129
- * @default []
130
- * @memberOf FilterComponent
131
- */
132
- this.filteredOptions = [];
133
- /**
134
- * @description Complete filter objects created by the user.
135
- * @summary Array of complete filter objects, each containing index, condition, and value properties.
136
- * These represent the active filters that can be applied to data operations.
137
- *
138
- * @type {KeyValue[]}
139
- * @default []
140
- * @memberOf FilterComponent
141
- */
142
- this.filterValue = [];
143
- /**
144
- * @description Current filter being constructed.
145
- * @summary Temporary object that accumulates filter properties (index, condition, value)
146
- * during the three-step filter creation process. Gets added to filterValue when complete.
147
- *
148
- * @type {KeyValue}
149
- * @default {}
150
- * @memberOf FilterComponent
151
- */
152
- this.lastFilter = {};
153
- /**
154
- * @description Current step in the filter creation process.
155
- * @summary Tracks the current step of filter creation: 1 = index selection, 2 = condition selection,
156
- * 3 = value input. Automatically resets to 1 after completing a filter.
157
- *
158
- * @type {number}
159
- * @default 1
160
- * @memberOf FilterComponent
161
- */
162
- this.step = 1;
163
- /**
164
- * @description Controls dropdown visibility state.
165
- * @summary Boolean flag that determines whether the options dropdown is currently visible.
166
- * Used to manage the dropdown's open/close state and coordinate with focus/blur events.
167
- *
168
- * @type {boolean}
169
- * @default false
170
- * @memberOf FilterComponent
171
- */
172
- this.dropdownOpen = false;
173
- /**
174
- * @description Current input field value.
175
- * @summary Stores the current text input value that the user is typing. This value is
176
- * bound to the input field and is cleared after each successful filter step completion.
177
- *
178
- * @type {string}
179
- * @default ''
180
- * @memberOf FilterComponent
181
- */
182
- this.value = '';
183
- /**
184
- * @description Current sorting field value.
185
- * @summary Stores the field name currently selected for sorting operations.
186
- * This value determines which field is used to order the filtered results.
187
- * Defaults to 'id' and can be changed through the sort dropdown selection.
188
- *
189
- * @type {string}
190
- * @default 'id'
191
- * @memberOf FilterComponent
192
- */
193
- this.sortValue = 'id';
194
- /**
195
- * @description Current sorting direction.
196
- * @summary Defines the direction of the sort operation - ascending or descending.
197
- * This value works in conjunction with sortValue to determine the complete
198
- * sorting configuration for filtered results.
199
- *
200
- * @type {OrderDirection}
201
- * @default OrderDirection.DSC
202
- * @memberOf FilterComponent
203
- */
204
- this.sortDirection = OrderDirection.DSC;
205
- /**
206
- * @description Browsing mode (dark or light).
207
- * @summary Indicates whether the dark mode theme is currently enabled.
208
- * Defaults to `false`.
209
- *
210
- * @type {boolean}
211
- * @memberOf FilterComponent
212
- */
213
- this.isDarkMode = false;
214
- /**
215
- * @description Event emitter for filter changes.
216
- * @summary Emits filter events when the user creates, modifies, or clears filters.
217
- * The emitted value contains an array of complete filter objects or undefined when
218
- * filters are cleared. Parent components listen to this event to update their data display.
219
- *
220
- * @type {EventEmitter<KeyValue[] | undefined>}
221
- * @memberOf FilterComponent
222
- */
223
- this.filterEvent = new EventEmitter();
224
- /**
225
- * @description Event emitter for search events.
226
- * @summary Emits search events when the user interacts with the searchbar.
227
- * @type {EventEmitter<string>}
228
- * @memberOf FilterComponent
229
- */
230
- this.searchEvent = new EventEmitter();
231
- addIcons({ chevronDownOutline, chevronUpOutline });
232
- }
233
- /**
234
- * @description Initializes the component after Angular first displays the data-bound properties.
235
- * @summary Sets up the component by initializing window width tracking, setting up resize event
236
- * subscriptions with debouncing, configuring sorting options, and calling the base initialization.
237
- * This method prepares the component for user interaction and responsive behavior.
238
- *
239
- * @mermaid
240
- * sequenceDiagram
241
- * participant A as Angular Lifecycle
242
- * participant F as FilterComponent
243
- * participant W as Window
244
- * participant R as RxJS
245
- *
246
- * A->>F: ngOnInit()
247
- * F->>W: getWindowWidth()
248
- * W-->>F: Return current width
249
- * F->>R: Setup resize subscription with debounce
250
- * R-->>F: Subscription created
251
- * alt disableSort is false
252
- * F->>F: Merge sort and indexes arrays
253
- * end
254
- * F->>F: Call initialize()
255
- *
256
- * @returns {Promise<void>}
257
- * @memberOf FilterComponent
258
- */
259
- async ngOnInit() {
260
- this.isDarkMode = await isDarkMode();
261
- this.windowWidth = getWindowWidth();
262
- this.windowResizeSubscription = fromEvent(window, 'resize')
263
- .pipe(debounceTime(300))
264
- .subscribe(() => {
265
- this.windowWidth = getWindowWidth();
266
- });
267
- this.getIndexes();
268
- this.initialize();
269
- }
270
- /**
271
- * @description Retrieves and configures available indexes for filtering and sorting.
272
- * @summary Extracts field indexes from the model if available and merges them with
273
- * sorting options when sorting is enabled. This method sets up the available field
274
- * options for both filtering and sorting operations based on the model structure.
275
- *
276
- * @returns {void}
277
- * @memberOf FilterComponent
278
- */
279
- getIndexes() {
280
- if (this.model)
281
- this.indexes = Object.keys(Repository.indexes(this.model) || {});
282
- if (!this.disableSort)
283
- this.sortBy = [...this.sortBy, ...this.indexes];
284
- }
285
- /**
286
- * @description Cleanup method called when the component is destroyed.
287
- * @summary Unsubscribes from window resize events to prevent memory leaks.
288
- * This is essential for proper cleanup of RxJS subscriptions when the component
289
- * is removed from the DOM.
290
- *
291
- * @returns {void}
292
- * @memberOf FilterComponent
293
- */
294
- ngOnDestroy() {
295
- this.windowResizeSubscription.unsubscribe();
296
- this.clear();
297
- }
298
- /**
299
- * @description Handles input events from the text field.
300
- * @summary Processes user input and filters the available options based on the typed value.
301
- * This method provides real-time filtering of suggestions as the user types in the input field.
302
- *
303
- * @param {InputEvent} event - The input event containing the new value
304
- * @returns {void}
305
- * @memberOf FilterComponent
306
- */
307
- handleInput(event) {
308
- const { value } = event.target;
309
- this.filteredOptions = this.filterOptions(value);
310
- }
311
- /**
312
- * @description Handles focus events on the input field.
313
- * @summary Sets up the available options when the input field receives focus and opens the dropdown.
314
- * If no options are provided, automatically determines the appropriate options based on current step.
315
- * This method initializes the dropdown with contextually relevant suggestions.
316
- *
317
- * @param {string[]} options - Optional array of options to display
318
- * @returns {void}
319
- * @memberOf FilterComponent
320
- */
321
- handleFocus(options = []) {
322
- if (!options.length)
323
- options = this.getOptions();
324
- this.filteredOptions = this.options = options;
325
- this.dropdownOpen = true;
326
- }
327
- /**
328
- * @description Handles blur events on the input field with delayed closing.
329
- * @summary Manages the dropdown closing behavior with a delay to allow for option selection.
330
- * Uses a two-phase approach to prevent premature closing when users click on dropdown options.
331
- *
332
- * @param {boolean} close - Internal flag to control the closing phase
333
- * @returns {void}
334
- * @memberOf FilterComponent
335
- */
336
- handleBlur(close = false) {
337
- if (!close) {
338
- this.dropdownOpen = false;
339
- setTimeout(() => {
340
- this.handleBlur(true);
341
- }, 100);
342
- }
343
- else {
344
- if (!this.dropdownOpen && this.options.length) {
345
- setTimeout(() => {
346
- this.options = [];
347
- this.dropdownOpen = false;
348
- }, 50);
349
- }
350
- }
351
- }
352
- /**
353
- * @description Determines the appropriate options based on the current filter step.
354
- * @summary Returns the contextually relevant options for the current step in the filter creation process.
355
- * Step 1 shows indexes, Step 2 shows conditions, Step 3 shows no options (value input).
356
- *
357
- * @returns {string[]} Array of options appropriate for the current step
358
- * @memberOf FilterComponent
359
- */
360
- getOptions() {
361
- switch (this.step) {
362
- case 1:
363
- this.options = this.indexes;
364
- break;
365
- case 2:
366
- this.options = this.conditions;
367
- break;
368
- case 3:
369
- this.options = [];
370
- break;
371
- }
372
- return this.options;
373
- }
374
- /**
375
- * @description Adds a filter step or completes filter creation through a three-step process.
376
- * @summary Core method for building filters step by step: Step 1 (Index) → Step 2 (Condition) → Step 3 (Value).
377
- * When all steps are complete, creates a complete filter object and adds it to the filter collection.
378
- * Handles both keyboard events (Enter to submit) and programmatic calls.
379
- *
380
- * @param {string} value - The value to add for the current step
381
- * @param {CustomEvent} event - Optional event (KeyboardEvent triggers submission when value is empty)
382
- * @returns {void}
383
- *
384
- * @mermaid
385
- * sequenceDiagram
386
- * participant U as User
387
- * participant F as FilterComponent
388
- *
389
- * U->>F: addFilter(value, event)
390
- * F->>F: Trim and validate value
391
- * alt KeyboardEvent && empty value
392
- * F->>F: submit() - Send current filters
393
- * else Valid value or step 3
394
- * alt Step 1 (Index)
395
- * F->>F: lastFilter.index = value
396
- * F->>F: options = conditions
397
- * else Step 2 (Condition)
398
- * F->>F: lastFilter.condition = value
399
- * F->>F: options = []
400
- * else Step 3 (Value)
401
- * F->>F: lastFilter.value = value
402
- * F->>F: Add complete filter to filterValue
403
- * F->>F: Reset step to 1
404
- * end
405
- * F->>F: Increment step
406
- * F->>F: Clear input & focus
407
- * F->>F: Show next options
408
- * end
409
- *
410
- * @memberOf FilterComponent
411
- */
412
- addFilter(value, event) {
413
- value = value.trim();
414
- if (event instanceof KeyboardEvent && !value) {
415
- this.submit();
416
- }
417
- else {
418
- if ((value && (!(event instanceof KeyboardEvent)) || this.step === 3)) {
419
- const filter = this.lastFilter;
420
- switch (this.step) {
421
- case 1:
422
- filter['index'] = value;
423
- this.options = this.conditions;
424
- break;
425
- case 2:
426
- filter['condition'] = value;
427
- this.options = [];
428
- break;
429
- case 3:
430
- filter['value'] = value;
431
- this.options = this.indexes;
432
- break;
433
- }
434
- if (!this.filterValue.length) {
435
- this.filterValue.push(filter);
436
- }
437
- else {
438
- if (this.step === 1)
439
- this.filterValue.push(filter);
440
- }
441
- if (this.step === 3) {
442
- this.step = 0;
443
- this.filterValue[this.filterValue.length - 1] = filter;
444
- this.lastFilter = {};
445
- }
446
- this.step++;
447
- this.value = '';
448
- if (this.options.length)
449
- this.handleFocus(this.options);
450
- this.component.nativeElement.focus();
451
- }
452
- }
453
- }
454
- /**
455
- * @description Selects an option from the dropdown suggestions.
456
- * @summary Handles option selection when a user clicks on a suggestion in the dropdown.
457
- * This method acts as a bridge between dropdown clicks and the main addFilter logic.
458
- *
459
- * @param {CustomEvent} event - The click event from the dropdown option
460
- * @param {string} value - The selected option value
461
- * @returns {void}
462
- * @memberOf FilterComponent
463
- */
464
- selectOption(value) {
465
- this.addFilter(value);
466
- }
467
- /**
468
- * @description Determines if a filter option can be individually removed.
469
- * @summary Checks whether a filter component should display a close icon for removal.
470
- * Only value options can be removed individually; index and condition options are part
471
- * of the complete filter structure and cannot be removed separately.
472
- *
473
- * @param {string} option - The filter option text to check
474
- * @returns {boolean} True if the option can be cleared individually, false otherwise
475
- * @memberOf FilterComponent
476
- */
477
- allowClear(option) {
478
- return this.indexes.indexOf(option) === -1 && this.conditions.indexOf(option) === -1;
479
- }
480
- /**
481
- * @description Removes a complete filter from the collection based on filter value.
482
- * @summary Removes a complete filter by matching the provided value against filter values
483
- * in the collection. Uses string normalization to handle accents and case differences.
484
- * After removal, resets the interface to show available indexes for new filter creation.
485
- *
486
- * @param {string} filter - The filter value to remove (matches against filter.value property)
487
- * @returns {void}
488
- *
489
- * @mermaid
490
- * sequenceDiagram
491
- * participant U as User
492
- * participant F as FilterComponent
493
- *
494
- * U->>F: removeFilter(filterValue)
495
- * F->>F: cleanString(filterValue)
496
- * F->>F: Filter out matching filter objects
497
- * F->>F: Clear input value
498
- * F->>F: handleFocus(indexes) - Reset to index selection
499
- * Note over F: Filter removed and UI reset
500
- *
501
- * @memberOf FilterComponent
502
- */
503
- removeFilter(filter) {
504
- function cleanString(filter) {
505
- return filter
506
- .toLowerCase() // convert all characters to lowercase
507
- .normalize("NFD") // separate accent marks from characters
508
- .replace(/[\u0300-\u036f]/g, "") // remove accent marks
509
- .replace(/\s+/g, ""); // remove all whitespace
510
- }
511
- this.value = "";
512
- this.filterValue = this.filterValue.filter((item) => item?.['value'] && cleanString(item?.['value']) !== cleanString(filter));
513
- if (this.filterValue.length === 0) {
514
- this.step = 1;
515
- this.lastFilter = {};
516
- }
517
- this.handleFocus(this.indexes);
518
- }
519
- /**
520
- * @description Resets the component to its initial state.
521
- * @summary Clears all filter data, options, and resets the step counter to 1.
522
- * This method provides a clean slate for new filter creation without emitting events.
523
- *
524
- * @returns {void}
525
- * @memberOf FilterComponent
526
- */
527
- reset() {
528
- this.options = this.filteredOptions = this.filterValue = [];
529
- this.step = 1;
530
- this.lastFilter = {};
531
- this.value = '';
532
- setTimeout(() => {
533
- this.submit();
534
- }, 100);
535
- }
536
- /**
537
- * @description Clears all filters and notifies parent components.
538
- * @summary Resets the component state and emits undefined to notify parent components
539
- * that all filters have been cleared. This triggers any connected data refresh logic.
540
- *
541
- * @param {string} value - Optional parameter (currently unused)
542
- * @returns {void}
543
- * @memberOf FilterComponent
544
- */
545
- clear(value) {
546
- if (!value)
547
- this.reset();
548
- }
549
- /**
550
- * @description Submits the current filter collection to parent components.
551
- * @summary Emits the current filter array to parent components when filters are ready
552
- * to be applied. Only emits if there are active filters. Clears options after submission.
553
- *
554
- * @returns {void}
555
- * @memberOf FilterComponent
556
- */
557
- submit() {
558
- this.filterEvent.emit({
559
- query: this.filterValue.length > 0 ? this.filterValue : undefined,
560
- sort: {
561
- value: this.sortValue,
562
- direction: this.sortDirection
563
- }
564
- });
565
- if (this.filterValue.length === 0)
566
- this.options = [];
567
- }
568
- /**
569
- * @description Toggles the sort direction between ascending and descending.
570
- * @summary Handles sort direction changes by toggling between ASC and DSC values.
571
- * When the direction changes, automatically triggers a submit to apply the new
572
- * sorting configuration to the filtered results.
573
- *
574
- * @returns {void}
575
- * @memberOf FilterComponent
576
- */
577
- handleSortDirectionChange() {
578
- const direction = this.sortDirection === OrderDirection.ASC ? OrderDirection.DSC : OrderDirection.ASC;
579
- if (direction !== this.sortDirection) {
580
- this.sortDirection = direction;
581
- this.submit();
582
- }
583
- }
584
- /**
585
- * @description Handles sort field selection changes from the dropdown.
586
- * @summary Processes sort field changes when users select a different field
587
- * from the sort dropdown. Updates the sortValue property and triggers
588
- * a submit to apply the new sorting configuration if the value has changed.
589
- *
590
- * @param {CustomEvent} event - The select change event containing the new sort field value
591
- * @returns {void}
592
- * @memberOf FilterComponent
593
- */
594
- handleSortChange(event) {
595
- const target = event.target;
596
- const value = target.value;
597
- if (value !== this.sortValue) {
598
- this.sortValue = value;
599
- this.submit();
600
- }
601
- }
602
- /**
603
- * @description Filters available options based on user input with visual highlighting.
604
- * @summary Performs real-time filtering of available options based on user input.
605
- * Also handles visual highlighting of matching options in the dropdown. Returns all
606
- * options if input is less than 2 characters for performance optimization.
607
- *
608
- * @param {string | null | undefined} value - The search value to filter by
609
- * @returns {string[]} Array of filtered options that match the input
610
- *
611
- * @mermaid
612
- * sequenceDiagram
613
- * participant U as User
614
- * participant F as FilterComponent
615
- * participant D as DOM
616
- *
617
- * U->>F: filterOptions(inputValue)
618
- * alt inputValue < 2 characters
619
- * F->>D: Remove existing highlights
620
- * F-->>U: Return all options
621
- * else inputValue >= 2 characters
622
- * F->>D: Query all option elements
623
- * F->>D: Add highlight to first matching option
624
- * F->>F: Filter options by substring match
625
- * F-->>U: Return filtered options
626
- * end
627
- *
628
- * @memberOf FilterComponent
629
- */
630
- filterOptions(value) {
631
- const optionsElement = this.optionsFilterElement.nativeElement;
632
- if (!value?.length || !value || value.length < 2) {
633
- const filteredOption = optionsElement.querySelector('.dcf-filtering-item');
634
- if (filteredOption)
635
- filteredOption.classList.remove('dcf-filtering-item');
636
- return this.options;
637
- }
638
- const options = optionsElement.querySelectorAll('.dcf-item');
639
- for (const option of options) {
640
- const isActive = option.textContent?.toLowerCase().includes(value.toLowerCase());
641
- if (isActive) {
642
- option.classList.add('dcf-filtering-item');
643
- break;
644
- }
645
- }
646
- return this.options.filter((option) => option.toLowerCase().includes(value.toLowerCase()));
647
- }
648
- /**
649
- * @description Handles search events from the integrated searchbar component.
650
- * @summary Processes search input from the searchbar and emits search events
651
- * to parent components. This method acts as a bridge between the internal
652
- * searchbar component and external search event listeners.
653
- *
654
- * @param {string | undefined} value - The search value entered by the user
655
- * @returns {void}
656
- * @memberOf FilterComponent
657
- */
658
- handleSearch(value) {
659
- this.searchEvent.emit(value);
660
- }
661
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
662
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FilterComponent, isStandalone: true, selector: "ngx-decaf-filter", inputs: { indexes: "indexes", conditions: "conditions", sortBy: "sortBy", disableSort: "disableSort" }, outputs: { filterEvent: "filterEvent", searchEvent: "searchEvent" }, viewQueries: [{ propertyName: "optionsFilterElement", first: true, predicate: ["optionsFilterElement"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "\n@if(!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-grid\" [class.dcf-hidden]=\"!indexes.length\">\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if(filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if(filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if(filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon name=\"close\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\n />\n @if(windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if(filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if(windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if(!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'medium'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}@media (prefers-color-scheme: light){.dcf-filter ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}}@media (prefers-color-scheme: dark){.dcf-filter ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}@media (prefers-color-scheme: light){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-1)}}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}@media (prefers-color-scheme: light){.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}}@media (prefers-color-scheme: dark){.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}@media (prefers-color-scheme: light){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonChip, selector: "ion-chip", inputs: ["color", "disabled", "mode", "outline"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }] }); }
663
- };
664
- FilterComponent = __decorate([
665
- Dynamic(),
666
- __metadata("design:paramtypes", [])
667
- ], FilterComponent);
668
- export { FilterComponent };
669
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FilterComponent, decorators: [{
670
- type: Component,
671
- args: [{ selector: 'ngx-decaf-filter', imports: [
672
- FormsModule,
673
- TranslatePipe,
674
- IonLabel,
675
- IonItem,
676
- IonChip,
677
- IonIcon,
678
- IonButton,
679
- IonSelect,
680
- IonSelectOption,
681
- IonIcon,
682
- SearchbarComponent
683
- ], standalone: true, template: "\n@if(!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-grid\" [class.dcf-hidden]=\"!indexes.length\">\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if(filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if(filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if(filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon name=\"close\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\n />\n @if(windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if(filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if(windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if(!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'medium'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}@media (prefers-color-scheme: light){.dcf-filter ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}}@media (prefers-color-scheme: dark){.dcf-filter ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}@media (prefers-color-scheme: light){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-1)}}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}@media (prefers-color-scheme: light){.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}}@media (prefers-color-scheme: dark){.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}@media (prefers-color-scheme: light){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}\n"] }]
684
- }], ctorParameters: () => [], propDecorators: { optionsFilterElement: [{
685
- type: ViewChild,
686
- args: ['optionsFilterElement', { read: ElementRef, static: false }]
687
- }], indexes: [{
688
- type: Input
689
- }], conditions: [{
690
- type: Input
691
- }], sortBy: [{
692
- type: Input
693
- }], disableSort: [{
694
- type: Input
695
- }], filterEvent: [{
696
- type: Output
697
- }], searchEvent: [{
698
- type: Output
699
- }] } });
700
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9maWx0ZXIvZmlsdGVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9maWx0ZXIvZmlsdGVyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFxQixNQUFNLEVBQUUsU0FBUyxFQUFHLE1BQU0sZUFBZSxDQUFDO0FBQ2xILE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUN0SCxPQUFPLEVBQUUsT0FBTyxFQUFrQyxNQUFNLGNBQWMsQ0FBQztBQUN2RSxPQUFPLEVBQUUsY0FBYyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUM3RCxPQUFPLEVBQUUsY0FBYyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTVELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDcEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7O0FBRTdDOzs7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QkFjTixNQUFNO3NCQURMLEtBQUs7Z0JBY04sV0FBVztzQkFEVixLQUFLO2dCQW1KTixXQUFXO3NCQURWLE1BQU07Z0JBVVAsV0FBVztzQkFEVixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkRlc3Ryb3ksIE9uSW5pdCwgT3V0cHV0LCBWaWV3Q2hpbGQgIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOZ3hCYXNlQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vZW5naW5lL05neEJhc2VDb21wb25lbnQnO1xuaW1wb3J0IHsgSW9uQnV0dG9uLCBJb25DaGlwLCBJb25JY29uLCBJb25JdGVtLCBJb25MYWJlbCwgSW9uU2VsZWN0LCBJb25TZWxlY3RPcHRpb259IGZyb20gJ0Bpb25pYy9hbmd1bGFyL3N0YW5kYWxvbmUnO1xuaW1wb3J0IHsgRHluYW1pYywgSUZpbHRlclF1ZXJ5LCBJRmlsdGVyUXVlcnlJdGVtIH0gZnJvbSAnLi4vLi4vZW5naW5lJztcbmltcG9ydCB7IGdldFdpbmRvd1dpZHRoLCBpc0RhcmtNb2RlIH0gZnJvbSAnLi4vLi4vaGVscGVycy91dGlscyc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIGZyb21FdmVudCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBPcmRlckRpcmVjdGlvbiwgUmVwb3NpdG9yeSB9IGZyb20gJ0BkZWNhZi10cy9jb3JlJztcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSAnQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uJztcbmltcG9ydCB7IFNlYXJjaGJhckNvbXBvbmVudCB9IGZyb20gJy4uL3NlYXJjaGJhci9zZWFyY2hiYXIuY29tcG9uZW50JztcbmltcG9ydCB7IGFkZEljb25zIH0gZnJvbSAnaW9uaWNvbnMnO1xuaW1wb3J0IHsgY2hldnJvbkRvd25PdXRsaW5lLCBjaGV2cm9uVXBPdXRsaW5lIH0gZnJvbSAnaW9uaWNvbnMvaWNvbnMnO1xuaW1wb3J0IHsgVHJhbnNsYXRlUGlwZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEFkdmFuY2VkIGZpbHRlciBjb21wb25lbnQgZm9yIGNyZWF0aW5nIGR5bmFtaWMgc2VhcmNoIGZpbHRlcnMgd2l0aCBzdGVwLWJ5LXN0ZXAgY29uc3RydWN0aW9uLlxuICogQHN1bW1hcnkgVGhpcyBjb21wb25lbnQgcHJvdmlkZXMgYSBjb21wcmVoZW5zaXZlIGZpbHRlcmluZyBpbnRlcmZhY2UgdGhhdCBhbGxvd3MgdXNlcnMgdG8gYnVpbGRcbiAqIGNvbXBsZXggc2VhcmNoIGNyaXRlcmlhIHVzaW5nIGEgdGhyZWUtc3RlcCBhcHByb2FjaDogc2VsZWN0IGluZGV4IOKGkiBzZWxlY3QgY29uZGl0aW9uIOKGkiBlbnRlciB2YWx1ZS5cbiAqIEl0IHN1cHBvcnRzIGZpbHRlcmluZyBieSBtdWx0aXBsZSBmaWVsZCBpbmRleGVzLCBjb21wYXJpc29uIGNvbmRpdGlvbnMsIGFuZCB2YWx1ZXMsIGRpc3BsYXlpbmdcbiAqIHNlbGVjdGVkIGZpbHRlcnMgYXMgcmVtb3ZhYmxlIGNoaXBzLiBUaGUgY29tcG9uZW50IGlzIHJlc3BvbnNpdmUgYW5kIGluY2x1ZGVzIGF1dG8tc3VnZ2VzdGlvbnNcbiAqIHdpdGgga2V5Ym9hcmQgbmF2aWdhdGlvbiBzdXBwb3J0LlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGBodG1sXG4gKiA8bmd4LWRlY2FmLWZpbHRlclxuICogICBbaW5kZXhlc109XCJbJ25hbWUnLCAnZW1haWwnLCAnZGVwYXJ0bWVudCcsICdzdGF0dXMnXVwiXG4gKiAgIFtjb25kaXRpb25zXT1cIlsnRXF1YWwnLCAnQ29udGFpbnMnLCAnR3JlYXRlciBUaGFuJywgJ0xlc3MgVGhhbiddXCJcbiAqICAgW3NvcnRdPVwiWydjcmVhdGVkQXQnLCAndXBkYXRlZEF0J11cIlxuICogICBbZGlzYWJsZVNvcnRdPVwiZmFsc2VcIlxuICogICAoZmlsdGVyRXZlbnQpPVwib25GaWx0ZXJzQ2hhbmdlZCgkZXZlbnQpXCI+XG4gKiA8L25neC1kZWNhZi1maWx0ZXI+XG4gKiBgYGBcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IFUgYXMgVXNlclxuICogICBwYXJ0aWNpcGFudCBGIGFzIEZpbHRlckNvbXBvbmVudFxuICogICBwYXJ0aWNpcGFudCBQIGFzIFBhcmVudCBDb21wb25lbnRcbiAqXG4gKiAgIFUtPj5GOiBGb2N1cyBpbnB1dCBmaWVsZFxuICogICBGLT4+RjogaGFuZGxlRm9jdXMoKSAtIFNob3cgYXZhaWxhYmxlIGluZGV4ZXNcbiAqICAgVS0+PkY6IFNlbGVjdCBpbmRleCAoZS5nLiwgXCJuYW1lXCIpXG4gKiAgIEYtPj5GOiBhZGRGaWx0ZXIoKSAtIFN0ZXAgMSBjb21wbGV0ZWRcbiAqICAgRi0+PkY6IFNob3cgYXZhaWxhYmxlIGNvbmRpdGlvbnNcbiAqICAgVS0+PkY6IFNlbGVjdCBjb25kaXRpb24gKGUuZy4sIFwiQ29udGFpbnNcIilcbiAqICAgRi0+PkY6IGFkZEZpbHRlcigpIC0gU3RlcCAyIGNvbXBsZXRlZFxuICogICBGLT4+RjogU2hvdyB2YWx1ZSBpbnB1dCBwcm9tcHRcbiAqICAgVS0+PkY6IEVudGVyIHZhbHVlIGFuZCBwcmVzcyBFbnRlclxuICogICBGLT4+RjogYWRkRmlsdGVyKCkgLSBTdGVwIDMgY29tcGxldGVkXG4gKiAgIEYtPj5GOiBDcmVhdGUgY29tcGxldGUgZmlsdGVyIG9iamVjdFxuICogICBGLT4+UDogRW1pdCBmaWx0ZXJFdmVudCB3aXRoIG5ldyBmaWx0ZXIgYXJyYXlcbiAqICAgRi0+PkY6IFJlc2V0IHRvIHN0ZXAgMSBmb3IgbmV4dCBmaWx0ZXJcbiAqXG4gKiBAbWVtYmVyT2YgRm9yQW5ndWxhckNvbW1vbk1vZHVsZVxuICovXG5ARHluYW1pYygpXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtZGVjYWYtZmlsdGVyJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2ZpbHRlci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2ZpbHRlci5jb21wb25lbnQuc2NzcyddLFxuICBpbXBvcnRzOiBbXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgVHJhbnNsYXRlUGlwZSxcbiAgICBJb25MYWJlbCxcbiAgICBJb25JdGVtLFxuICAgIElvbkNoaXAsXG4gICAgSW9uSWNvbixcbiAgICBJb25CdXR0b24sXG4gICAgSW9uU2VsZWN0LFxuICAgIElvblNlbGVjdE9wdGlvbixcbiAgICBJb25JY29uLFxuICAgIFNlYXJjaGJhckNvbXBvbmVudFxuICBdLFxuICBzdGFuZGFsb25lOiB0cnVlLFxufSlcbmV4cG9ydCBjbGFzcyBGaWx0ZXJDb21wb25lbnQgZXh0ZW5kcyBOZ3hCYXNlQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVmZXJlbmNlIHRvIHRoZSBkcm9wZG93biBvcHRpb25zIGNvbnRhaW5lciBlbGVtZW50LlxuICAgKiBAc3VtbWFyeSBWaWV3Q2hpbGQgcmVmZXJlbmNlIHVzZWQgdG8gYWNjZXNzIGFuZCBtYW5pcHVsYXRlIHRoZSBkcm9wZG93biBvcHRpb25zIGVsZW1lbnRcbiAgICogZm9yIGhpZ2hsaWdodGluZyBmaWx0ZXJlZCBpdGVtcyBhbmQgbWFuYWdpbmcgdmlzdWFsIGZlZWRiYWNrIGR1cmluZyBvcHRpb24gc2VsZWN0aW9uLlxuICAgKiBUaGlzIGVsZW1lbnQgY29udGFpbnMgdGhlIGZpbHRlcmFibGUgc3VnZ2VzdGlvbnMgdGhhdCB1c2VycyBjYW4gaW50ZXJhY3Qgd2l0aC5cbiAgICpcbiAgICogQHR5cGUge0VsZW1lbnRSZWZ9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIEBWaWV3Q2hpbGQoJ29wdGlvbnNGaWx0ZXJFbGVtZW50JywgeyByZWFkOiBFbGVtZW50UmVmLCBzdGF0aWM6IGZhbHNlIH0pXG4gIG9wdGlvbnNGaWx0ZXJFbGVtZW50ITogRWxlbWVudFJlZjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEF2YWlsYWJsZSBmaWVsZCBpbmRleGVzIGZvciBmaWx0ZXJpbmcgb3BlcmF0aW9ucy5cbiAgICogQHN1bW1hcnkgRGVmaW5lcyB0aGUgbGlzdCBvZiBmaWVsZCBuYW1lcyB0aGF0IHVzZXJzIGNhbiBmaWx0ZXIgYnkuIFRoZXNlIHJlcHJlc2VudFxuICAgKiB0aGUgZGF0YSBwcm9wZXJ0aWVzIGF2YWlsYWJsZSBmb3IgZmlsdGVyaW5nIG9wZXJhdGlvbnMuIEVhY2ggaW5kZXggY29ycmVzcG9uZHMgdG9cbiAgICogYSBmaWVsZCBpbiB0aGUgZGF0YSBtb2RlbCB0aGF0IHN1cHBvcnRzIGNvbXBhcmlzb24gb3BlcmF0aW9ucy5cbiAgICpcbiAgICogQHR5cGUge3N0cmluZ1tdfVxuICAgKiBAZGVmYXVsdCBbXVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBASW5wdXQoKVxuICBpbmRleGVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQXZhaWxhYmxlIGNvbXBhcmlzb24gY29uZGl0aW9ucyBmb3IgZmlsdGVycy5cbiAgICogQHN1bW1hcnkgRGVmaW5lcyB0aGUgbGlzdCBvZiBjb21wYXJpc29uIG9wZXJhdG9ycyB0aGF0IGNhbiBiZSB1c2VkIHdoZW4gY3JlYXRpbmcgZmlsdGVycy5cbiAgICogVGhlc2UgY29uZGl0aW9ucyBkZXRlcm1pbmUgaG93IHRoZSBmaWx0ZXIgdmFsdWUgaXMgY29tcGFyZWQgYWdhaW5zdCB0aGUgZmllbGQgdmFsdWUuXG4gICAqIENvbW1vbiBjb25kaXRpb25zIGluY2x1ZGUgZXF1YWxpdHksIGNvbnRhaW5tZW50LCBhbmQgbnVtZXJpY2FsIGNvbXBhcmlzb24gb3BlcmF0aW9ucy5cbiAgICpcbiAgICogQHR5cGUge3N0cmluZ1tdfVxuICAgKiBAZGVmYXVsdCBbXVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBASW5wdXQoKVxuICBjb25kaXRpb25zOiBzdHJpbmdbXSA9IFsnRXF1YWwnLCAnQ29udGFpbnMnLCAnTm90IENvbnRhaW5zJywgJ0dyZWF0ZXIgVGhhbicsICdMZXNzIFRoYW4nLCAnTm90IEVxdWFsJ107XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBdmFpbGFibGUgc29ydGluZyBvcHRpb25zIGZvciB0aGUgZmlsdGVyZWQgZGF0YS5cbiAgICogQHN1bW1hcnkgRGVmaW5lcyB0aGUgbGlzdCBvZiBmaWVsZCBuYW1lcyB0aGF0IGNhbiBiZSB1c2VkIGZvciBzb3J0aW5nIHRoZSBmaWx0ZXJlZCByZXN1bHRzLlxuICAgKiBXaGVuIGRpc2FibGVTb3J0IGlzIGZhbHNlLCB0aGlzIGFycmF5IGlzIGF1dG9tYXRpY2FsbHkgbWVyZ2VkIHdpdGggdGhlIGluZGV4ZXMgYXJyYXlcbiAgICogdG8gcHJvdmlkZSBjb21wcmVoZW5zaXZlIHNvcnRpbmcgY2FwYWJpbGl0aWVzLlxuICAgKlxuICAgKiBAdHlwZSB7c3RyaW5nW119XG4gICAqIEBkZWZhdWx0IFtdXG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIEBJbnB1dCgpXG4gIHNvcnRCeTogc3RyaW5nW10gPSBbXTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENvbnRyb2xzIHdoZXRoZXIgc29ydGluZyBmdW5jdGlvbmFsaXR5IGlzIGRpc2FibGVkLlxuICAgKiBAc3VtbWFyeSBXaGVuIHNldCB0byB0cnVlLCBwcmV2ZW50cyB0aGUgYXV0b21hdGljIG1lcmdpbmcgb2Ygc29ydCBhbmQgaW5kZXhlcyBhcnJheXMsXG4gICAqIGVmZmVjdGl2ZWx5IGRpc2FibGluZyBzb3J0aW5nIGNhcGFiaWxpdGllcy4gVGhpcyBpcyB1c2VmdWwgd2hlbiB5b3Ugd2FudCB0byBwcm92aWRlXG4gICAqIGZpbHRlcmluZyB3aXRob3V0IHNvcnRpbmcgb3B0aW9ucy5cbiAgICpcbiAgICogQHR5cGUge2Jvb2xlYW59XG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIEBJbnB1dCgpXG4gIGRpc2FibGVTb3J0OiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDdXJyZW50IHdpbmRvdyB3aWR0aCBmb3IgcmVzcG9uc2l2ZSBiZWhhdmlvci5cbiAgICogQHN1bW1hcnkgU3RvcmVzIHRoZSBjdXJyZW50IGJyb3dzZXIgd2luZG93IHdpZHRoIGluIHBpeGVscy4gVGhpcyB2YWx1ZSBpcyB1cGRhdGVkXG4gICAqIG9uIHdpbmRvdyByZXNpemUgZXZlbnRzIHRvIGVuYWJsZSByZXNwb25zaXZlIGZpbHRlcmluZyBiZWhhdmlvciBhbmQgbGF5b3V0IGFkanVzdG1lbnRzXG4gICAqIGJhc2VkIG9uIGF2YWlsYWJsZSBzY3JlZW4gc3BhY2UuXG4gICAqXG4gICAqIEB0eXBlIHtudW1iZXJ9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIHdpbmRvd1dpZHRoITogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQXZhaWxhYmxlIG9wdGlvbnMgZm9yIHRoZSBjdXJyZW50IGZpbHRlciBzdGVwLlxuICAgKiBAc3VtbWFyeSBDb250YWlucyB0aGUgbGlzdCBvZiBvcHRpb25zIGF2YWlsYWJsZSBmb3Igc2VsZWN0aW9uIGluIHRoZSBjdXJyZW50IHN0ZXAuXG4gICAqIFRoaXMgYXJyYXkgY2hhbmdlcyBkeW5hbWljYWxseSBiYXNlZCBvbiB0aGUgY3VycmVudCBzdGVwOiBpbmRleGVzIOKGkiBjb25kaXRpb25zIOKGkiBlbXB0eSBmb3IgdmFsdWUgaW5wdXQuXG4gICAqXG4gICAqIEB0eXBlIHtzdHJpbmdbXX1cbiAgICogQGRlZmF1bHQgW11cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgb3B0aW9uczogc3RyaW5nW10gPSBbXTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEZpbHRlcmVkIG9wdGlvbnMgYmFzZWQgb24gdXNlciBpbnB1dC5cbiAgICogQHN1bW1hcnkgQ29udGFpbnMgdGhlIHN1YnNldCBvZiBvcHRpb25zIHRoYXQgbWF0Y2ggdGhlIGN1cnJlbnQgdXNlciBpbnB1dCBmb3IgcmVhbC10aW1lXG4gICAqIGZpbHRlcmluZy4gVGhpcyBhcnJheSBpcyB1cGRhdGVkIGFzIHRoZSB1c2VyIHR5cGVzIHRvIHNob3cgb25seSByZWxldmFudCBzdWdnZXN0aW9uc1xuICAgKiBpbiB0aGUgZHJvcGRvd24gbWVudS5cbiAgICpcbiAgICogQHR5cGUge3N0cmluZ1tdfVxuICAgKiBAZGVmYXVsdCBbXVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBmaWx0ZXJlZE9wdGlvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDb21wbGV0ZSBmaWx0ZXIgb2JqZWN0cyBjcmVhdGVkIGJ5IHRoZSB1c2VyLlxuICAgKiBAc3VtbWFyeSBBcnJheSBvZiBjb21wbGV0ZSBmaWx0ZXIgb2JqZWN0cywgZWFjaCBjb250YWluaW5nIGluZGV4LCBjb25kaXRpb24sIGFuZCB2YWx1ZSBwcm9wZXJ0aWVzLlxuICAgKiBUaGVzZSByZXByZXNlbnQgdGhlIGFjdGl2ZSBmaWx0ZXJzIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gZGF0YSBvcGVyYXRpb25zLlxuICAgKlxuICAgKiBAdHlwZSB7S2V5VmFsdWVbXX1cbiAgICogQGRlZmF1bHQgW11cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgZmlsdGVyVmFsdWU6IElGaWx0ZXJRdWVyeUl0ZW1bXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3VycmVudCBmaWx0ZXIgYmVpbmcgY29uc3RydWN0ZWQuXG4gICAqIEBzdW1tYXJ5IFRlbXBvcmFyeSBvYmplY3QgdGhhdCBhY2N1bXVsYXRlcyBmaWx0ZXIgcHJvcGVydGllcyAoaW5kZXgsIGNvbmRpdGlvbiwgdmFsdWUpXG4gICAqIGR1cmluZyB0aGUgdGhyZWUtc3RlcCBmaWx0ZXIgY3JlYXRpb24gcHJvY2Vzcy4gR2V0cyBhZGRlZCB0byBmaWx0ZXJWYWx1ZSB3aGVuIGNvbXBsZXRlLlxuICAgKlxuICAgKiBAdHlwZSB7S2V5VmFsdWV9XG4gICAqIEBkZWZhdWx0IHt9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIGxhc3RGaWx0ZXI6IElGaWx0ZXJRdWVyeUl0ZW0gPSB7fTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEN1cnJlbnQgc3RlcCBpbiB0aGUgZmlsdGVyIGNyZWF0aW9uIHByb2Nlc3MuXG4gICAqIEBzdW1tYXJ5IFRyYWNrcyB0aGUgY3VycmVudCBzdGVwIG9mIGZpbHRlciBjcmVhdGlvbjogMSA9IGluZGV4IHNlbGVjdGlvbiwgMiA9IGNvbmRpdGlvbiBzZWxlY3Rpb24sXG4gICAqIDMgPSB2YWx1ZSBpbnB1dC4gQXV0b21hdGljYWxseSByZXNldHMgdG8gMSBhZnRlciBjb21wbGV0aW5nIGEgZmlsdGVyLlxuICAgKlxuICAgKiBAdHlwZSB7bnVtYmVyfVxuICAgKiBAZGVmYXVsdCAxXG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIHN0ZXA6IG51bWJlciA9IDE7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDb250cm9scyBkcm9wZG93biB2aXNpYmlsaXR5IHN0YXRlLlxuICAgKiBAc3VtbWFyeSBCb29sZWFuIGZsYWcgdGhhdCBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIG9wdGlvbnMgZHJvcGRvd24gaXMgY3VycmVudGx5IHZpc2libGUuXG4gICAqIFVzZWQgdG8gbWFuYWdlIHRoZSBkcm9wZG93bidzIG9wZW4vY2xvc2Ugc3RhdGUgYW5kIGNvb3JkaW5hdGUgd2l0aCBmb2N1cy9ibHVyIGV2ZW50cy5cbiAgICpcbiAgICogQHR5cGUge2Jvb2xlYW59XG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIGRyb3Bkb3duT3BlbjogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3VycmVudCBpbnB1dCBmaWVsZCB2YWx1ZS5cbiAgICogQHN1bW1hcnkgU3RvcmVzIHRoZSBjdXJyZW50IHRleHQgaW5wdXQgdmFsdWUgdGhhdCB0aGUgdXNlciBpcyB0eXBpbmcuIFRoaXMgdmFsdWUgaXNcbiAgICogYm91bmQgdG8gdGhlIGlucHV0IGZpZWxkIGFuZCBpcyBjbGVhcmVkIGFmdGVyIGVhY2ggc3VjY2Vzc2Z1bCBmaWx0ZXIgc3RlcCBjb21wbGV0aW9uLlxuICAgKlxuICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgKiBAZGVmYXVsdCAnJ1xuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICB2YWx1ZTogc3RyaW5nID0gJyc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDdXJyZW50IHNvcnRpbmcgZmllbGQgdmFsdWUuXG4gICAqIEBzdW1tYXJ5IFN0b3JlcyB0aGUgZmllbGQgbmFtZSBjdXJyZW50bHkgc2VsZWN0ZWQgZm9yIHNvcnRpbmcgb3BlcmF0aW9ucy5cbiAgICogVGhpcyB2YWx1ZSBkZXRlcm1pbmVzIHdoaWNoIGZpZWxkIGlzIHVzZWQgdG8gb3JkZXIgdGhlIGZpbHRlcmVkIHJlc3VsdHMuXG4gICAqIERlZmF1bHRzIHRvICdpZCcgYW5kIGNhbiBiZSBjaGFuZ2VkIHRocm91Z2ggdGhlIHNvcnQgZHJvcGRvd24gc2VsZWN0aW9uLlxuICAgKlxuICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgKiBAZGVmYXVsdCAnaWQnXG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIHNvcnRWYWx1ZTogc3RyaW5nID0gJ2lkJztcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEN1cnJlbnQgc29ydGluZyBkaXJlY3Rpb24uXG4gICAqIEBzdW1tYXJ5IERlZmluZXMgdGhlIGRpcmVjdGlvbiBvZiB0aGUgc29ydCBvcGVyYXRpb24gLSBhc2NlbmRpbmcgb3IgZGVzY2VuZGluZy5cbiAgICogVGhpcyB2YWx1ZSB3b3JrcyBpbiBjb25qdW5jdGlvbiB3aXRoIHNvcnRWYWx1ZSB0byBkZXRlcm1pbmUgdGhlIGNvbXBsZXRlXG4gICAqIHNvcnRpbmcgY29uZmlndXJhdGlvbiBmb3IgZmlsdGVyZWQgcmVzdWx0cy5cbiAgICpcbiAgICogQHR5cGUge09yZGVyRGlyZWN0aW9ufVxuICAgKiBAZGVmYXVsdCBPcmRlckRpcmVjdGlvbi5EU0NcbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgc29ydERpcmVjdGlvbjogT3JkZXJEaXJlY3Rpb24gPSBPcmRlckRpcmVjdGlvbi5EU0M7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTdWJzY3JpcHRpb24gZm9yIHdpbmRvdyByZXNpemUgZXZlbnRzLlxuICAgKiBAc3VtbWFyeSBSeEpTIHN1YnNjcmlwdGlvbiB0aGF0IGxpc3RlbnMgZm9yIHdpbmRvdyByZXNpemUgZXZlbnRzIHdpdGggZGVib3VuY2luZ1xuICAgKiB0byB1cGRhdGUgdGhlIHdpbmRvd1dpZHRoIHByb3BlcnR5LiBUaGlzIGVuYWJsZXMgcmVzcG9uc2l2ZSBiZWhhdmlvciBhbmQgcHJldmVudHNcbiAgICogZXhjZXNzaXZlIHVwZGF0ZXMgZHVyaW5nIHJlc2l6ZSBvcGVyYXRpb25zLlxuICAgKlxuICAgKiBAdHlwZSB7U3Vic2NyaXB0aW9ufVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICB3aW5kb3dSZXNpemVTdWJzY3JpcHRpb24hOiBTdWJzY3JpcHRpb247XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBCcm93c2luZyBtb2RlIChkYXJrIG9yIGxpZ2h0KS5cbiAgICogQHN1bW1hcnkgSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGRhcmsgbW9kZSB0aGVtZSBpcyBjdXJyZW50bHkgZW5hYmxlZC5cbiAgICogRGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICpcbiAgICogQHR5cGUge2Jvb2xlYW59XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIGlzRGFya01vZGU6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV2ZW50IGVtaXR0ZXIgZm9yIGZpbHRlciBjaGFuZ2VzLlxuICAgKiBAc3VtbWFyeSBFbWl0cyBmaWx0ZXIgZXZlbnRzIHdoZW4gdGhlIHVzZXIgY3JlYXRlcywgbW9kaWZpZXMsIG9yIGNsZWFycyBmaWx0ZXJzLlxuICAgKiBUaGUgZW1pdHRlZCB2YWx1ZSBjb250YWlucyBhbiBhcnJheSBvZiBjb21wbGV0ZSBmaWx0ZXIgb2JqZWN0cyBvciB1bmRlZmluZWQgd2hlblxuICAgKiBmaWx0ZXJzIGFyZSBjbGVhcmVkLiBQYXJlbnQgY29tcG9uZW50cyBsaXN0ZW4gdG8gdGhpcyBldmVudCB0byB1cGRhdGUgdGhlaXIgZGF0YSBkaXNwbGF5LlxuICAgKlxuICAgKiBAdHlwZSB7RXZlbnRFbWl0dGVyPEtleVZhbHVlW10gfCB1bmRlZmluZWQ+fVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBAT3V0cHV0KClcbiAgZmlsdGVyRXZlbnQ6IEV2ZW50RW1pdHRlcjxJRmlsdGVyUXVlcnkgfCB1bmRlZmluZWQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxJRmlsdGVyUXVlcnkgfCB1bmRlZmluZWQ+KCk7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFdmVudCBlbWl0dGVyIGZvciBzZWFyY2ggZXZlbnRzLlxuICAgKiBAc3VtbWFyeSBFbWl0cyBzZWFyY2ggZXZlbnRzIHdoZW4gdGhlIHVzZXIgaW50ZXJhY3RzIHdpdGggdGhlIHNlYXJjaGJhci5cbiAgICogQHR5cGUge0V2ZW50RW1pdHRlcjxzdHJpbmc+fVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBAT3V0cHV0KClcbiAgc2VhcmNoRXZlbnQ6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENvbnN0cnVjdG9yIGZvciBGaWx0ZXJDb21wb25lbnQuXG4gICAqIEBzdW1tYXJ5IEluaXRpYWxpemVzIGEgbmV3IGluc3RhbmNlIG9mIHRoZSBGaWx0ZXJDb21wb25lbnQuXG4gICAqIENhbGxzIHRoZSBwYXJlbnQgY29uc3RydWN0b3Igd2l0aCB0aGUgY29tcG9uZW50IG5hbWUgdG8gZXN0YWJsaXNoIGJhc2UgbG9jYWxlIHN0cmluZyBnZW5lcmF0aW9uXG4gICAqIGFuZCBpbnRlcm5hdGlvbmFsaXphdGlvbiBzdXBwb3J0LlxuICAgKlxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcihcIkZpbHRlckNvbXBvbmVudFwiKTtcbiAgICBhZGRJY29ucyh7Y2hldnJvbkRvd25PdXRsaW5lLCBjaGV2cm9uVXBPdXRsaW5lfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEluaXRpYWxpemVzIHRoZSBjb21wb25lbnQgYWZ0ZXIgQW5ndWxhciBmaXJzdCBkaXNwbGF5cyB0aGUgZGF0YS1ib3VuZCBwcm9wZXJ0aWVzLlxuICAgKiBAc3VtbWFyeSBTZXRzIHVwIHRoZSBjb21wb25lbnQgYnkgaW5pdGlhbGl6aW5nIHdpbmRvdyB3aWR0aCB0cmFja2luZywgc2V0dGluZyB1cCByZXNpemUgZXZlbnRcbiAgICogc3Vic2NyaXB0aW9ucyB3aXRoIGRlYm91bmNpbmcsIGNvbmZpZ3VyaW5nIHNvcnRpbmcgb3B0aW9ucywgYW5kIGNhbGxpbmcgdGhlIGJhc2UgaW5pdGlhbGl6YXRpb24uXG4gICAqIFRoaXMgbWV0aG9kIHByZXBhcmVzIHRoZSBjb21wb25lbnQgZm9yIHVzZXIgaW50ZXJhY3Rpb24gYW5kIHJlc3BvbnNpdmUgYmVoYXZpb3IuXG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEEgYXMgQW5ndWxhciBMaWZlY3ljbGVcbiAgICogICBwYXJ0aWNpcGFudCBGIGFzIEZpbHRlckNvbXBvbmVudFxuICAgKiAgIHBhcnRpY2lwYW50IFcgYXMgV2luZG93XG4gICAqICAgcGFydGljaXBhbnQgUiBhcyBSeEpTXG4gICAqXG4gICAqICAgQS0+PkY6IG5nT25Jbml0KClcbiAgICogICBGLT4+VzogZ2V0V2luZG93V2lkdGgoKVxuICAgKiAgIFctLT4+RjogUmV0dXJuIGN1cnJlbnQgd2lkdGhcbiAgICogICBGLT4+UjogU2V0dXAgcmVzaXplIHN1YnNjcmlwdGlvbiB3aXRoIGRlYm91bmNlXG4gICAqICAgUi0tPj5GOiBTdWJzY3JpcHRpb24gY3JlYXRlZFxuICAgKiAgIGFsdCBkaXNhYmxlU29ydCBpcyBmYWxzZVxuICAgKiAgICAgRi0+PkY6IE1lcmdlIHNvcnQgYW5kIGluZGV4ZXMgYXJyYXlzXG4gICAqICAgZW5kXG4gICAqICAgRi0+PkY6IENhbGwgaW5pdGlhbGl6ZSgpXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBhc3luYyBuZ09uSW5pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmlzRGFya01vZGUgPSBhd2FpdCBpc0RhcmtNb2RlKCk7XG4gICAgdGhpcy53aW5kb3dXaWR0aCA9IGdldFdpbmRvd1dpZHRoKCkgYXMgbnVtYmVyO1xuICAgIHRoaXMud2luZG93UmVzaXplU3Vic2NyaXB0aW9uID0gZnJvbUV2ZW50KHdpbmRvdywgJ3Jlc2l6ZScpXG4gICAgLnBpcGUoZGVib3VuY2VUaW1lKDMwMCkpXG4gICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgIHRoaXMud2luZG93V2lkdGggPSBnZXRXaW5kb3dXaWR0aCgpIGFzIG51bWJlcjtcbiAgICB9KTtcblxuICAgIHRoaXMuZ2V0SW5kZXhlcygpO1xuICAgIHRoaXMuaW5pdGlhbGl6ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgYW5kIGNvbmZpZ3VyZXMgYXZhaWxhYmxlIGluZGV4ZXMgZm9yIGZpbHRlcmluZyBhbmQgc29ydGluZy5cbiAgICogQHN1bW1hcnkgRXh0cmFjdHMgZmllbGQgaW5kZXhlcyBmcm9tIHRoZSBtb2RlbCBpZiBhdmFpbGFibGUgYW5kIG1lcmdlcyB0aGVtIHdpdGhcbiAgICogc29ydGluZyBvcHRpb25zIHdoZW4gc29ydGluZyBpcyBlbmFibGVkLiBUaGlzIG1ldGhvZCBzZXRzIHVwIHRoZSBhdmFpbGFibGUgZmllbGRcbiAgICogb3B0aW9ucyBmb3IgYm90aCBmaWx0ZXJpbmcgYW5kIHNvcnRpbmcgb3BlcmF0aW9ucyBiYXNlZCBvbiB0aGUgbW9kZWwgc3RydWN0dXJlLlxuICAgKlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgZ2V0SW5kZXhlcygpOiB2b2lkIHtcbiAgICBpZih0aGlzLm1vZGVsKVxuICAgICAgdGhpcy5pbmRleGVzID0gT2JqZWN0LmtleXMoUmVwb3NpdG9yeS5pbmRleGVzKHRoaXMubW9kZWwgYXMgTW9kZWwpIHx8IHt9KTtcbiAgICBpZighdGhpcy5kaXNhYmxlU29ydClcbiAgICAgIHRoaXMuc29ydEJ5ID0gWy4uLiB0aGlzLnNvcnRCeSwgLi4udGhpcy5pbmRleGVzXTtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDbGVhbnVwIG1ldGhvZCBjYWxsZWQgd2hlbiB0aGUgY29tcG9uZW50IGlzIGRlc3Ryb3llZC5cbiAgICogQHN1bW1hcnkgVW5zdWJzY3JpYmVzIGZyb20gd2luZG93IHJlc2l6ZSBldmVudHMgdG8gcHJldmVudCBtZW1vcnkgbGVha3MuXG4gICAqIFRoaXMgaXMgZXNzZW50aWFsIGZvciBwcm9wZXIgY2xlYW51cCBvZiBSeEpTIHN1YnNjcmlwdGlvbnMgd2hlbiB0aGUgY29tcG9uZW50XG4gICAqIGlzIHJlbW92ZWQgZnJvbSB0aGUgRE9NLlxuICAgKlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy53aW5kb3dSZXNpemVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLmNsZWFyKCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgaW5wdXQgZXZlbnRzIGZyb20gdGhlIHRleHQgZmllbGQuXG4gICAqIEBzdW1tYXJ5IFByb2Nlc3NlcyB1c2VyIGlucHV0IGFuZCBmaWx0ZXJzIHRoZSBhdmFpbGFibGUgb3B0aW9ucyBiYXNlZCBvbiB0aGUgdHlwZWQgdmFsdWUuXG4gICAqIFRoaXMgbWV0aG9kIHByb3ZpZGVzIHJlYWwtdGltZSBmaWx0ZXJpbmcgb2Ygc3VnZ2VzdGlvbnMgYXMgdGhlIHVzZXIgdHlwZXMgaW4gdGhlIGlucHV0IGZpZWxkLlxuICAgKlxuICAgKiBAcGFyYW0ge0lucHV0RXZlbnR9IGV2ZW50IC0gVGhlIGlucHV0IGV2ZW50IGNvbnRhaW5pbmcgdGhlIG5ldyB2YWx1ZVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgaGFuZGxlSW5wdXQoZXZlbnQ6IElucHV0RXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCB7dmFsdWV9ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG4gICAgICB0aGlzLmZpbHRlcmVkT3B0aW9ucyA9IHRoaXMuZmlsdGVyT3B0aW9ucyh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgZm9jdXMgZXZlbnRzIG9uIHRoZSBpbnB1dCBmaWVsZC5cbiAgICogQHN1bW1hcnkgU2V0cyB1cCB0aGUgYXZhaWxhYmxlIG9wdGlvbnMgd2hlbiB0aGUgaW5wdXQgZmllbGQgcmVjZWl2ZXMgZm9jdXMgYW5kIG9wZW5zIHRoZSBkcm9wZG93bi5cbiAgICogSWYgbm8gb3B0aW9ucyBhcmUgcHJvdmlkZWQsIGF1dG9tYXRpY2FsbHkgZGV0ZXJtaW5lcyB0aGUgYXBwcm9wcmlhdGUgb3B0aW9ucyBiYXNlZCBvbiBjdXJyZW50IHN0ZXAuXG4gICAqIFRoaXMgbWV0aG9kIGluaXRpYWxpemVzIHRoZSBkcm9wZG93biB3aXRoIGNvbnRleHR1YWxseSByZWxldmFudCBzdWdnZXN0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gb3B0aW9ucyAtIE9wdGlvbmFsIGFycmF5IG9mIG9wdGlvbnMgdG8gZGlzcGxheVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgaGFuZGxlRm9jdXMob3B0aW9uczogc3RyaW5nW10gID0gW10pOiB2b2lkIHtcbiAgICBpZighb3B0aW9ucy5sZW5ndGgpXG4gICAgIG9wdGlvbnMgPSB0aGlzLmdldE9wdGlvbnMoKTtcbiAgICB0aGlzLmZpbHRlcmVkT3B0aW9ucyA9IHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5kcm9wZG93bk9wZW4gPSB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIGJsdXIgZXZlbnRzIG9uIHRoZSBpbnB1dCBmaWVsZCB3aXRoIGRlbGF5ZWQgY2xvc2luZy5cbiAgICogQHN1bW1hcnkgTWFuYWdlcyB0aGUgZHJvcGRvd24gY2xvc2luZyBiZWhhdmlvciB3aXRoIGEgZGVsYXkgdG8gYWxsb3cgZm9yIG9wdGlvbiBzZWxlY3Rpb24uXG4gICAqIFVzZXMgYSB0d28tcGhhc2UgYXBwcm9hY2ggdG8gcHJldmVudCBwcmVtYXR1cmUgY2xvc2luZyB3aGVuIHVzZXJzIGNsaWNrIG9uIGRyb3Bkb3duIG9wdGlvbnMuXG4gICAqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gY2xvc2UgLSBJbnRlcm5hbCBmbGFnIHRvIGNvbnRyb2wgdGhlIGNsb3NpbmcgcGhhc2VcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIGhhbmRsZUJsdXIoY2xvc2U6IGJvb2xlYW4gPSBmYWxzZSk6IHZvaWQge1xuICAgIGlmKCFjbG9zZSkge1xuICAgICAgdGhpcy5kcm9wZG93bk9wZW4gPSBmYWxzZTtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLmhhbmRsZUJsdXIodHJ1ZSk7XG4gICAgICB9LCAxMDApO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZighdGhpcy5kcm9wZG93bk9wZW4gJiYgdGhpcy5vcHRpb25zLmxlbmd0aCkge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICB0aGlzLm9wdGlvbnMgPSBbXTtcbiAgICAgICAgICB0aGlzLmRyb3Bkb3duT3BlbiA9IGZhbHNlO1xuICAgICAgICB9LCA1MCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZXRlcm1pbmVzIHRoZSBhcHByb3ByaWF0ZSBvcHRpb25zIGJhc2VkIG9uIHRoZSBjdXJyZW50IGZpbHRlciBzdGVwLlxuICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBjb250ZXh0dWFsbHkgcmVsZXZhbnQgb3B0aW9ucyBmb3IgdGhlIGN1cnJlbnQgc3RlcCBpbiB0aGUgZmlsdGVyIGNyZWF0aW9uIHByb2Nlc3MuXG4gICAqIFN0ZXAgMSBzaG93cyBpbmRleGVzLCBTdGVwIDIgc2hvd3MgY29uZGl0aW9ucywgU3RlcCAzIHNob3dzIG5vIG9wdGlvbnMgKHZhbHVlIGlucHV0KS5cbiAgICpcbiAgICogQHJldHVybnMge3N0cmluZ1tdfSBBcnJheSBvZiBvcHRpb25zIGFwcHJvcHJpYXRlIGZvciB0aGUgY3VycmVudCBzdGVwXG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIGdldE9wdGlvbnMoKTogc3RyaW5nW10ge1xuICAgc3dpdGNoICh0aGlzLnN0ZXApIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgdGhpcy5vcHRpb25zID0gdGhpcy5pbmRleGVzO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgdGhpcy5vcHRpb25zID0gdGhpcy5jb25kaXRpb25zO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgdGhpcy5vcHRpb25zID0gW107XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5vcHRpb25zXG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFkZHMgYSBmaWx0ZXIgc3RlcCBvciBjb21wbGV0ZXMgZmlsdGVyIGNyZWF0aW9uIHRocm91Z2ggYSB0aHJlZS1zdGVwIHByb2Nlc3MuXG4gICAqIEBzdW1tYXJ5IENvcmUgbWV0aG9kIGZvciBidWlsZGluZyBmaWx0ZXJzIHN0ZXAgYnkgc3RlcDogU3RlcCAxIChJbmRleCkg4oaSIFN0ZXAgMiAoQ29uZGl0aW9uKSDihpIgU3RlcCAzIChWYWx1ZSkuXG4gICAqIFdoZW4gYWxsIHN0ZXBzIGFyZSBjb21wbGV0ZSwgY3JlYXRlcyBhIGNvbXBsZXRlIGZpbHRlciBvYmplY3QgYW5kIGFkZHMgaXQgdG8gdGhlIGZpbHRlciBjb2xsZWN0aW9uLlxuICAgKiBIYW5kbGVzIGJvdGgga2V5Ym9hcmQgZXZlbnRzIChFbnRlciB0byBzdWJtaXQpIGFuZCBwcm9ncmFtbWF0aWMgY2FsbHMuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBhZGQgZm9yIHRoZSBjdXJyZW50IHN0ZXBcbiAgICogQHBhcmFtIHtDdXN0b21FdmVudH0gZXZlbnQgLSBPcHRpb25hbCBldmVudCAoS2V5Ym9hcmRFdmVudCB0cmlnZ2VycyBzdWJtaXNzaW9uIHdoZW4gdmFsdWUgaXMgZW1wdHkpXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBVIGFzIFVzZXJcbiAgICogICBwYXJ0aWNpcGFudCBGIGFzIEZpbHRlckNvbXBvbmVudFxuICAgKlxuICAgKiAgIFUtPj5GOiBhZGRGaWx0ZXIodmFsdWUsIGV2ZW50KVxuICAgKiAgIEYtPj5GOiBUcmltIGFuZCB2YWxpZGF0ZSB2YWx1ZVxuICAgKiAgIGFsdCBLZXlib2FyZEV2ZW50ICYmIGVtcHR5IHZhbHVlXG4gICAqICAgICBGLT4+Rjogc3VibWl0KCkgLSBTZW5kIGN1cnJlbnQgZmlsdGVyc1xuICAgKiAgIGVsc2UgVmFsaWQgdmFsdWUgb3Igc3RlcCAzXG4gICAqICAgICBhbHQgU3RlcCAxIChJbmRleClcbiAgICogICAgICAgRi0+PkY6IGxhc3RGaWx0ZXIuaW5kZXggPSB2YWx1ZVxuICAgKiAgICAgICBGLT4+Rjogb3B0aW9ucyA9IGNvbmRpdGlvbnNcbiAgICogICAgIGVsc2UgU3RlcCAyIChDb25kaXRpb24pXG4gICAqICAgICAgIEYtPj5GOiBsYXN0RmlsdGVyLmNvbmRpdGlvbiA9IHZhbHVlXG4gICAqICAgICAgIEYtPj5GOiBvcHRpb25zID0gW11cbiAgICogICAgIGVsc2UgU3RlcCAzIChWYWx1ZSlcbiAgICogICAgICAgRi0+PkY6IGxhc3RGaWx0ZXIudmFsdWUgPSB2YWx1ZVxuICAgKiAgICAgICBGLT4+RjogQWRkIGNvbXBsZXRlIGZpbHRlciB0byBmaWx0ZXJWYWx1ZVxuICAgKiAgICAgICBGLT4+RjogUmVzZXQgc3RlcCB0byAxXG4gICAqICAgICBlbmRcbiAgICogICAgIEYtPj5GOiBJbmNyZW1lbnQgc3RlcFxuICAgKiAgICAgRi0+PkY6IENsZWFyIGlucHV0ICYgZm9jdXNcbiAgICogICAgIEYtPj5GOiBTaG93IG5leHQgb3B0aW9uc1xuICAgKiAgIGVuZFxuICAgKlxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBhZGRGaWx0ZXIodmFsdWU6IHN0cmluZywgZXZlbnQ/OiBDdXN0b21FdmVudCk6IHZvaWQge1xuICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xuICAgIGlmKGV2ZW50IGluc3RhbmNlb2YgS2V5Ym9hcmRFdmVudCAmJiAhdmFsdWUpIHtcbiAgICAgIHRoaXMuc3VibWl0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICBpZigodmFsdWUgJiYgKCEoZXZlbnQgaW5zdGFuY2VvZiBLZXlib2FyZEV2ZW50KSkgfHwgdGhpcy5zdGVwID09PSAzKSkge1xuICAgICAgICBjb25zdCBmaWx0ZXIgPSB0aGlzLmxhc3RGaWx0ZXI7XG4gICAgICAgIHN3aXRjaCAodGhpcy5zdGVwKSB7XG4gICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgZmlsdGVyWydpbmRleCddID0gdmFsdWU7XG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMgPSB0aGlzLmNvbmRpdGlvbnM7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICBmaWx0ZXJbJ2NvbmRpdGlvbiddID0gdmFsdWU7XG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMgPSBbXTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgIGZpbHRlclsndmFsdWUnXSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zID0gdGhpcy5pbmRleGVzO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYoIXRoaXMuZmlsdGVyVmFsdWUubGVuZ3RoKSB7XG4gICAgICAgICAgdGhpcy5maWx0ZXJWYWx1ZS5wdXNoKGZpbHRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYodGhpcy5zdGVwID09PSAxKVxuICAgICAgICAgICAgdGhpcy5maWx0ZXJWYWx1ZS5wdXNoKGZpbHRlcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYodGhpcy5zdGVwID09PSAzKSB7XG4gICAgICAgICAgdGhpcy5zdGVwID0gMDtcbiAgICAgICAgICB0aGlzLmZpbHRlclZhbHVlW3RoaXMuZmlsdGVyVmFsdWUubGVuZ3RoIC0gMV0gPSBmaWx0ZXI7XG4gICAgICAgICAgdGhpcy5sYXN0RmlsdGVyID0ge307XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdGVwKys7XG4gICAgICAgIHRoaXMudmFsdWUgPSAnJztcbiAgICAgICAgaWYodGhpcy5vcHRpb25zLmxlbmd0aClcbiAgICAgICAgICB0aGlzLmhhbmRsZUZvY3VzKHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHRoaXMuY29tcG9uZW50Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNlbGVjdHMgYW4gb3B0aW9uIGZyb20gdGhlIGRyb3Bkb3duIHN1Z2dlc3Rpb25zLlxuICAgKiBAc3VtbWFyeSBIYW5kbGVzIG9wdGlvbiBzZWxlY3Rpb24gd2hlbiBhIHVzZXIgY2xpY2tzIG9uIGEgc3VnZ2VzdGlvbiBpbiB0aGUgZHJvcGRvd24uXG4gICAqIFRoaXMgbWV0aG9kIGFjdHMgYXMgYSBicmlkZ2UgYmV0d2VlbiBkcm9wZG93biBjbGlja3MgYW5kIHRoZSBtYWluIGFkZEZpbHRlciBsb2dpYy5cbiAgICpcbiAgICogQHBhcmFtIHtDdXN0b21FdmVudH0gZXZlbnQgLSBUaGUgY2xpY2sgZXZlbnQgZnJvbSB0aGUgZHJvcGRvd24gb3B0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSBzZWxlY3RlZCBvcHRpb24gdmFsdWVcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIHNlbGVjdE9wdGlvbih2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5hZGRGaWx0ZXIodmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZXRlcm1pbmVzIGlmIGEgZmlsdGVyIG9wdGlvbiBjYW4gYmUgaW5kaXZpZHVhbGx5IHJlbW92ZWQuXG4gICAqIEBzdW1tYXJ5IENoZWNrcyB3aGV0aGVyIGEgZmlsdGVyIGNvbXBvbmVudCBzaG91bGQgZGlzcGxheSBhIGNsb3NlIGljb24gZm9yIHJlbW92YWwuXG4gICAqIE9ubHkgdmFsdWUgb3B0aW9ucyBjYW4gYmUgcmVtb3ZlZCBpbmRpdmlkdWFsbHk7IGluZGV4IGFuZCBjb25kaXRpb24gb3B0aW9ucyBhcmUgcGFydFxuICAgKiBvZiB0aGUgY29tcGxldGUgZmlsdGVyIHN0cnVjdHVyZSBhbmQgY2Fubm90IGJlIHJlbW92ZWQgc2VwYXJhdGVseS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbiAtIFRoZSBmaWx0ZXIgb3B0aW9uIHRleHQgdG8gY2hlY2tcbiAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIG9wdGlvbiBjYW4gYmUgY2xlYXJlZCBpbmRpdmlkdWFsbHksIGZhbHNlIG90aGVyd2lzZVxuICAgKiBAbWVtYmVyT2YgRmlsdGVyQ29tcG9uZW50XG4gICAqL1xuICBhbGxvd0NsZWFyKG9wdGlvbjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaW5kZXhlcy5pbmRleE9mKG9wdGlvbikgPT09IC0xICYmIHRoaXMuY29uZGl0aW9ucy5pbmRleE9mKG9wdGlvbikgPT09IC0xO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZW1vdmVzIGEgY29tcGxldGUgZmlsdGVyIGZyb20gdGhlIGNvbGxlY3Rpb24gYmFzZWQgb24gZmlsdGVyIHZhbHVlLlxuICAgKiBAc3VtbWFyeSBSZW1vdmVzIGEgY29tcGxldGUgZmlsdGVyIGJ5IG1hdGNoaW5nIHRoZSBwcm92aWRlZCB2YWx1ZSBhZ2FpbnN0IGZpbHRlciB2YWx1ZXNcbiAgICogaW4gdGhlIGNvbGxlY3Rpb24uIFVzZXMgc3RyaW5nIG5vcm1hbGl6YXRpb24gdG8gaGFuZGxlIGFjY2VudHMgYW5kIGNhc2UgZGlmZmVyZW5jZXMuXG4gICAqIEFmdGVyIHJlbW92YWwsIHJlc2V0cyB0aGUgaW50ZXJmYWNlIHRvIHNob3cgYXZhaWxhYmxlIGluZGV4ZXMgZm9yIG5ldyBmaWx0ZXIgY3JlYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBmaWx0ZXIgLSBUaGUgZmlsdGVyIHZhbHVlIHRvIHJlbW92ZSAobWF0Y2hlcyBhZ2FpbnN0IGZpbHRlci52YWx1ZSBwcm9wZXJ0eSlcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IFUgYXMgVXNlclxuICAgKiAgIHBhcnRpY2lwYW50IEYgYXMgRmlsdGVyQ29tcG9uZW50XG4gICAqXG4gICAqICAgVS0+PkY6IHJlbW92ZUZpbHRlcihmaWx0ZXJWYWx1ZSlcbiAgICogICBGLT4+RjogY2xlYW5TdHJpbmcoZmlsdGVyVmFsdWUpXG4gICAqICAgRi0+PkY6IEZpbHRlciBvdXQgbWF0Y2hpbmcgZmlsdGVyIG9iamVjdHNcbiAgICogICBGLT4+RjogQ2xlYXIgaW5wdXQgdmFsdWVcbiAgICogICBGLT4+RjogaGFuZGxlRm9jdXMoaW5kZXhlcykgLSBSZXNldCB0byBpbmRleCBzZWxlY3Rpb25cbiAgICogICBOb3RlIG92ZXIgRjogRmlsdGVyIHJlbW92ZWQgYW5kIFVJIHJlc2V0XG4gICAqXG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIHJlbW92ZUZpbHRlcihmaWx0ZXI6IHN0cmluZyk6IHZvaWQge1xuICAgIGZ1bmN0aW9uIGNsZWFuU3RyaW5nKGZpbHRlcjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgIHJldHVybiBmaWx0ZXJcbiAgICAgICAgLnRvTG93ZXJDYXNlKCkgICAgICAgICAgICAgICAgIC8vIGNvbnZlcnQgYWxsIGNoYXJhY3RlcnMgdG8gbG93ZXJjYXNlXG4gICAgICAgIC5ub3JtYWxpemUoXCJORkRcIikgICAgICAgICAgICAgIC8vIHNlcGFyYXRlIGFjY2VudCBtYXJrcyBmcm9tIGNoYXJhY3RlcnNcbiAgICAgICAgLnJlcGxhY2UoL1tcXHUwMzAwLVxcdTAzNmZdL2csIFwiXCIpIC8vIHJlbW92ZSBhY2NlbnQgbWFya3NcbiAgICAgICAgLnJlcGxhY2UoL1xccysvZywgXCJcIik7ICAgICAgICAgIC8vIHJlbW92ZSBhbGwgd2hpdGVzcGFjZVxuICAgIH1cbiAgICB0aGlzLnZhbHVlID0gXCJcIjtcbiAgICB0aGlzLmZpbHRlclZhbHVlID0gdGhpcy5maWx0ZXJWYWx1ZS5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0/LlsndmFsdWUnXSAmJiBjbGVhblN0cmluZyhpdGVtPy5bJ3ZhbHVlJ10pICE9PSBjbGVhblN0cmluZyhmaWx0ZXIpKTtcbiAgICBpZih0aGlzLmZpbHRlclZhbHVlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5zdGVwID0gMTtcbiAgICAgIHRoaXMubGFzdEZpbHRlciA9IHt9O1xuICAgIH1cbiAgICB0aGlzLmhhbmRsZUZvY3VzKHRoaXMuaW5kZXhlcyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlc2V0cyB0aGUgY29tcG9uZW50IHRvIGl0cyBpbml0aWFsIHN0YXRlLlxuICAgKiBAc3VtbWFyeSBDbGVhcnMgYWxsIGZpbHRlciBkYXRhLCBvcHRpb25zLCBhbmQgcmVzZXRzIHRoZSBzdGVwIGNvdW50ZXIgdG8gMS5cbiAgICogVGhpcyBtZXRob2QgcHJvdmlkZXMgYSBjbGVhbiBzbGF0ZSBmb3IgbmV3IGZpbHRlciBjcmVhdGlvbiB3aXRob3V0IGVtaXR0aW5nIGV2ZW50cy5cbiAgICpcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMub3B0aW9ucyA9IHRoaXMuZmlsdGVyZWRPcHRpb25zID0gdGhpcy5maWx0ZXJWYWx1ZSA9IFtdO1xuICAgIHRoaXMuc3RlcCA9IDE7XG4gICAgdGhpcy5sYXN0RmlsdGVyID0ge307XG4gICAgdGhpcy52YWx1ZSA9ICcnO1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgIHRoaXMuc3VibWl0KCk7XG4gICAgfSwgMTAwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ2xlYXJzIGFsbCBmaWx0ZXJzIGFuZCBub3RpZmllcyBwYXJlbnQgY29tcG9uZW50cy5cbiAgICogQHN1bW1hcnkgUmVzZXRzIHRoZSBjb21wb25lbnQgc3RhdGUgYW5kIGVtaXRzIHVuZGVmaW5lZCB0byBub3RpZnkgcGFyZW50IGNvbXBvbmVudHNcbiAgICogdGhhdCBhbGwgZmlsdGVycyBoYXZlIGJlZW4gY2xlYXJlZC4gVGhpcyB0cmlnZ2VycyBhbnkgY29ubmVjdGVkIGRhdGEgcmVmcmVzaCBsb2dpYy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIC0gT3B0aW9uYWwgcGFyYW1ldGVyIChjdXJyZW50bHkgdW51c2VkKVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgY2xlYXIodmFsdWU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZighdmFsdWUpXG4gICAgICB0aGlzLnJlc2V0KCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFN1Ym1pdHMgdGhlIGN1cnJlbnQgZmlsdGVyIGNvbGxlY3Rpb24gdG8gcGFyZW50IGNvbXBvbmVudHMuXG4gICAqIEBzdW1tYXJ5IEVtaXRzIHRoZSBjdXJyZW50IGZpbHRlciBhcnJheSB0byBwYXJlbnQgY29tcG9uZW50cyB3aGVuIGZpbHRlcnMgYXJlIHJlYWR5XG4gICAqIHRvIGJlIGFwcGxpZWQuIE9ubHkgZW1pdHMgaWYgdGhlcmUgYXJlIGFjdGl2ZSBmaWx0ZXJzLiBDbGVhcnMgb3B0aW9ucyBhZnRlciBzdWJtaXNzaW9uLlxuICAgKlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgc3VibWl0KCk6IHZvaWQge1xuICAgIHRoaXMuZmlsdGVyRXZlbnQuZW1pdCh7XG4gICAgICBxdWVyeTogdGhpcy5maWx0ZXJWYWx1ZS5sZW5ndGggPiAwID8gdGhpcy5maWx0ZXJWYWx1ZSA6IHVuZGVmaW5lZCxcbiAgICAgIHNvcnQ6IHtcbiAgICAgICAgdmFsdWU6IHRoaXMuc29ydFZhbHVlLFxuICAgICAgICBkaXJlY3Rpb246IHRoaXMuc29ydERpcmVjdGlvblxuICAgICAgfVxuICAgIH0gYXMgSUZpbHRlclF1ZXJ5KTtcbiAgICBpZih0aGlzLmZpbHRlclZhbHVlLmxlbmd0aCA9PT0gMClcbiAgICAgIHRoaXMub3B0aW9ucyA9IFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUb2dnbGVzIHRoZSBzb3J0IGRpcmVjdGlvbiBiZXR3ZWVuIGFzY2VuZGluZyBhbmQgZGVzY2VuZGluZy5cbiAgICogQHN1bW1hcnkgSGFuZGxlcyBzb3J0IGRpcmVjdGlvbiBjaGFuZ2VzIGJ5IHRvZ2dsaW5nIGJldHdlZW4gQVNDIGFuZCBEU0MgdmFsdWVzLlxuICAgKiBXaGVuIHRoZSBkaXJlY3Rpb24gY2hhbmdlcywgYXV0b21hdGljYWxseSB0cmlnZ2VycyBhIHN1Ym1pdCB0byBhcHBseSB0aGUgbmV3XG4gICAqIHNvcnRpbmcgY29uZmlndXJhdGlvbiB0byB0aGUgZmlsdGVyZWQgcmVzdWx0cy5cbiAgICpcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gICBoYW5kbGVTb3J0RGlyZWN0aW9uQ2hhbmdlKCk6IHZvaWQge1xuICAgIGNvbnN0IGRpcmVjdGlvbiA9IHRoaXMuc29ydERpcmVjdGlvbiA9PT0gIE9yZGVyRGlyZWN0aW9uLkFTQyA/IE9yZGVyRGlyZWN0aW9uLkRTQyA6IE9yZGVyRGlyZWN0aW9uLkFTQztcbiAgICBpZihkaXJlY3Rpb24gIT09IHRoaXMuc29ydERpcmVjdGlvbikge1xuICAgICAgdGhpcy5zb3J0RGlyZWN0aW9uID0gZGlyZWN0aW9uO1xuICAgICAgdGhpcy5zdWJtaXQoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgc29ydCBmaWVsZCBzZWxlY3Rpb24gY2hhbmdlcyBmcm9tIHRoZSBkcm9wZG93bi5cbiAgICogQHN1bW1hcnkgUHJvY2Vzc2VzIHNvcnQgZmllbGQgY2hhbmdlcyB3aGVuIHVzZXJzIHNlbGVjdCBhIGRpZmZlcmVudCBmaWVsZFxuICAgKiBmcm9tIHRoZSBzb3J0IGRyb3Bkb3duLiBVcGRhdGVzIHRoZSBzb3J0VmFsdWUgcHJvcGVydHkgYW5kIHRyaWdnZXJzXG4gICAqIGEgc3VibWl0IHRvIGFwcGx5IHRoZSBuZXcgc29ydGluZyBjb25maWd1cmF0aW9uIGlmIHRoZSB2YWx1ZSBoYXMgY2hhbmdlZC5cbiAgICpcbiAgICogQHBhcmFtIHtDdXN0b21FdmVudH0gZXZlbnQgLSBUaGUgc2VsZWN0IGNoYW5nZSBldmVudCBjb250YWluaW5nIHRoZSBuZXcgc29ydCBmaWVsZCB2YWx1ZVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgaGFuZGxlU29ydENoYW5nZShldmVudDogQ3VzdG9tRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQgYXMgSFRNTElvblNlbGVjdEVsZW1lbnQ7XG4gICAgY29uc3QgdmFsdWUgPSB0YXJnZXQudmFsdWU7XG4gICAgaWYodmFsdWUgIT09IHRoaXMuc29ydFZhbHVlKSB7XG4gICAgICB0aGlzLnNvcnRWYWx1ZSA9IHZhbHVlIGFzIHN0cmluZztcbiAgICAgIHRoaXMuc3VibWl0KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBGaWx0ZXJzIGF2YWlsYWJsZSBvcHRpb25zIGJhc2VkIG9uIHVzZXIgaW5wdXQgd2l0aCB2aXN1YWwgaGlnaGxpZ2h0aW5nLlxuICAgKiBAc3VtbWFyeSBQZXJmb3JtcyByZWFsLXRpbWUgZmlsdGVyaW5nIG9mIGF2YWlsYWJsZSBvcHRpb25zIGJhc2VkIG9uIHVzZXIgaW5wdXQuXG4gICAqIEFsc28gaGFuZGxlcyB2aXN1YWwgaGlnaGxpZ2h0aW5nIG9mIG1hdGNoaW5nIG9wdGlvbnMgaW4gdGhlIGRyb3Bkb3duLiBSZXR1cm5zIGFsbFxuICAgKiBvcHRpb25zIGlmIGlucHV0IGlzIGxlc3MgdGhhbiAyIGNoYXJhY3RlcnMgZm9yIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkfSB2YWx1ZSAtIFRoZSBzZWFyY2ggdmFsdWUgdG8gZmlsdGVyIGJ5XG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gQXJyYXkgb2YgZmlsdGVyZWQgb3B0aW9ucyB0aGF0IG1hdGNoIHRoZSBpbnB1dFxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBVIGFzIFVzZXJcbiAgICogICBwYXJ0aWNpcGFudCBGIGFzIEZpbHRlckNvbXBvbmVudFxuICAgKiAgIHBhcnRpY2lwYW50IEQgYXMgRE9NXG4gICAqXG4gICAqICAgVS0+PkY6IGZpbHRlck9wdGlvbnMoaW5wdXRWYWx1ZSlcbiAgICogICBhbHQgaW5wdXRWYWx1ZSA8IDIgY2hhcmFjdGVyc1xuICAgKiAgICAgRi0+PkQ6IFJlbW92ZSBleGlzdGluZyBoaWdobGlnaHRzXG4gICAqICAgICBGLS0+PlU6IFJldHVybiBhbGwgb3B0aW9uc1xuICAgKiAgIGVsc2UgaW5wdXRWYWx1ZSA+PSAyIGNoYXJhY3RlcnNcbiAgICogICAgIEYtPj5EOiBRdWVyeSBhbGwgb3B0aW9uIGVsZW1lbnRzXG4gICAqICAgICBGLT4+RDogQWRkIGhpZ2hsaWdodCB0byBmaXJzdCBtYXRjaGluZyBvcHRpb25cbiAgICogICAgIEYtPj5GOiBGaWx0ZXIgb3B0aW9ucyBieSBzdWJzdHJpbmcgbWF0Y2hcbiAgICogICAgIEYtLT4+VTogUmV0dXJuIGZpbHRlcmVkIG9wdGlvbnNcbiAgICogICBlbmRcbiAgICpcbiAgICogQG1lbWJlck9mIEZpbHRlckNvbXBvbmVudFxuICAgKi9cbiAgZmlsdGVyT3B0aW9ucyh2YWx1ZTogc3RyaW5nIHwgbnVsbCB8ICB1bmRlZmluZWQpOiBzdHJpbmdbXSB7XG4gICAgY29uc3Qgb3B0aW9uc0VsZW1lbnQgPSB0aGlzLm9wdGlvbnNGaWx0ZXJFbGVtZW50Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYoIXZhbHVlPy5sZW5ndGggfHwgIXZhbHVlIHx8IHZhbHVlLmxlbmd0aCA8IDIpIHtcbiAgICAgIGNvbnN0IGZpbHRlcmVkT3B0aW9uID0gb3B0aW9uc0VsZW1lbnQucXVlcnlTZWxlY3RvcignLmRjZi1maWx0ZXJpbmctaXRlbScpO1xuICAgICAgaWYoZmlsdGVyZWRPcHRpb24pXG4gICAgICAgIGZpbHRlcmVkT3B0aW9uLmNsYXNzTGlzdC5yZW1vdmUoJ2RjZi1maWx0ZXJpbmctaXRlbScpO1xuICAgICAgcmV0dXJuIHRoaXMub3B0aW9ucztcbiAgICB9XG4gICAgY29uc3Qgb3B0aW9ucyA9IG9wdGlvbnNFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5kY2YtaXRlbScpO1xuICAgIGZvciAoY29uc3Qgb3B0aW9uIG9mIG9wdGlvbnMpIHtcbiAgICAgIGNvbnN0IGlzQWN0aXZlID0gb3B0aW9uLnRleHRDb250ZW50Py50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHZhbHVlLnRvTG93ZXJDYXNlKCkpO1xuICAgICAgaWYoaXNBY3RpdmUpIHtcbiAgICAgICAgb3B0aW9uLmNsYXNzTGlzdC5hZGQoJ2RjZi1maWx0ZXJpbmctaXRlbScpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRoaXMub3B0aW9ucy5maWx0ZXIoKG9wdGlvbjogc3RyaW5nKSA9PiBvcHRpb24udG9Mb3dlckNhc2UoKS5pbmNsdWRlcyh2YWx1ZS50b0xvd2VyQ2FzZSgpIGFzIHN0cmluZykpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIHNlYXJjaCBldmVudHMgZnJvbSB0aGUgaW50ZWdyYXRlZCBzZWFyY2hiYXIgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBQcm9jZXNzZXMgc2VhcmNoIGlucHV0IGZyb20gdGhlIHNlYXJjaGJhciBhbmQgZW1pdHMgc2VhcmNoIGV2ZW50c1xuICAgKiB0byBwYXJlbnQgY29tcG9uZW50cy4gVGhpcyBtZXRob2QgYWN0cyBhcyBhIGJyaWRnZSBiZXR3ZWVuIHRoZSBpbnRlcm5hbFxuICAgKiBzZWFyY2hiYXIgY29tcG9uZW50IGFuZCBleHRlcm5hbCBzZWFyY2ggZXZlbnQgbGlzdGVuZXJzLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IHVuZGVmaW5lZH0gdmFsdWUgLSBUaGUgc2VhcmNoIHZhbHVlIGVudGVyZWQgYnkgdGhlIHVzZXJcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBGaWx0ZXJDb21wb25lbnRcbiAgICovXG4gIGhhbmRsZVNlYXJjaCh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgdGhpcy5zZWFyY2hFdmVudC5lbWl0KHZhbHVlKTtcbiAgfVxuXG59XG4iLCJcbkBpZighaW5kZXhlcy5sZW5ndGgpIHtcbiAgPG5neC1kZWNhZi1zZWFyY2hiYXIgW2VtaXRFdmVudFRvV2luZG93XT1cImZhbHNlXCIgW2RlYm91bmNlXT1cIjUwMFwiIChzZWFyY2hFdmVudCk9XCJoYW5kbGVTZWFyY2goJGV2ZW50KVwiIC8+XG59XG5cbjxkaXYgW2lkXT1cInVpZFwiIGNsYXNzPVwiZGNmLWdyaWQgZGNmLWdyaWQtc21hbGwgZGNmLWdyaWQtbWF0Y2ggZGNmLWZpbHRlci1ncmlkXCIgW2NsYXNzLmRjZi1oaWRkZW5dPVwiIWluZGV4ZXMubGVuZ3RoXCI+XG4gIDxkaXYgY2xhc3M9XCJkY2Ytd2lkdGgtZXhwYW5kXCI+XG4gICAgPGRpdiBjbGFzcz1cImRjZi1maWx0ZXJcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJkY2YtaW5wdXRcIj5cbiAgICAgICAgQGZvcihmaWx0ZXIgb2YgZmlsdGVyVmFsdWU7IHRyYWNrIHRyYWNrSXRlbUZuKCRpbmRleCwgZmlsdGVyPy5bJ2luZGV4J10pKSB7XG4gICAgICAgICAgQGlmKGZpbHRlcj8uWydpbmRleCddKSB7XG4gICAgICAgICAgICA8aW9uLWNoaXAgW291dGxpbmVdPVwidHJ1ZVwiPnt7IGZpbHRlcj8uWydpbmRleCddIH19PC9pb24tY2hpcD5cbiAgICAgICAgICB9XG4gICAgICAgICAgQGlmKGZpbHRlcj8uWydjb25kaXRpb24nXSkge1xuICAgICAgICAgICAgPGlvbi1jaGlwIFtvdXRsaW5lXT1cInRydWVcIj57eyBmaWx0ZXI/LlsnY29uZGl0aW9uJ10gfX08L2lvbi1jaGlwPlxuICAgICAgICAgIH1cbiAgICAgICAgICBAaWYoZmlsdGVyPy5bJ3ZhbHVlJ10pIHtcbiAgICAgICAgICAgIDxpb24tY2hpcCBbb3V0bGluZV09XCJ0cnVlXCIgY2xhc3M9XCJkY2YtZmlsdGVyLXZhbHVlXCI+XG4gICAgICAgICAgICAgIHt7IGZpbHRlcj8uWyd2YWx1ZSddIH19XG4gICAgICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwiY2xvc2VcIiAoY2xpY2spPVwicmVtb3ZlRmlsdGVyKGZpbHRlcj8uWyd2YWx1ZSddKVwiIHNpemU9XCJzbWFsbFwiPjwvaW9uLWljb24+XG4gICAgICAgICAgICA8L2lvbi1jaGlwPlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICA8ZGl2IGNsYXNzPVwiZGNmLXdpZHRoLTEtMVwiPlxuICAgICAgICAgICAgIDwhLS0gW3JlYWRvbmx5XT1cInN0ZXAgIT09IDNcIiAtLT5cbiAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIGZpbGw9XCJub25lXCJcbiAgICAgICAgICAgIFsobmdNb2RlbCldPVwidmFsdWVcIlxuICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwiYWRkRmlsdGVyKHZhbHVlLCAkZXZlbnQpXCJcbiAgICAgICAgICAgIChrZXlkb3duLmJhY2tzcGFjZSk9XCJjbGVhcih2YWx1ZSlcIlxuICAgICAgICAgICAgKGlucHV0KT1cImhhbmRsZUlucHV0KCRldmVudClcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImhhbmRsZUZvY3VzKClcIlxuICAgICAgICAgICAgKGJsdXIpPVwiaGFuZGxlQmx1cigpXCJcbiAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcblxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyBsb2NhbGUgKyAoc3RlcCA9PT0gMyA/ICcudHlwZScgOiAnLnNlbGVjdCcpIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICNjb21wb25lbnRcbiAgICAgICAgICAvPlxuICAgICAgICAgIEBpZih3aW5kb3dXaWR0aCA+PSA3NjgpIHtcbiAgICAgICAgICAgIDxkaXYgW2NsYXNzXT1cIidkY2YtZHJvcGRvd24gJyArIChvcHRpb25zLmxlbmd0aCA+IDAgPyAnIGRjZi1hY3RpdmUnIDogJycpXCIgI29wdGlvbnNGaWx0ZXJFbGVtZW50PlxuICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgIEBpZihmaWx0ZXJlZE9wdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgQGZvcihrZXkgb2YgZmlsdGVyZWRPcHRpb25zOyB0cmFjayBrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiZGNmLWl0ZW1cIlxuICAgICAgICAgICAgICAgICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgICAgICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwic2VsZWN0T3B0aW9uKGtleSlcIlxuICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJzZWxlY3RPcHRpb24oa2V5KVwiPlxuICAgICAgICAgICAgICAgICAgICAgIHt7IGtleSB9fVxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkY2YtZW1wdHlcIlxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiZmlsdGVyZWRPcHRpb25zID0gb3B0aW9uczsgdmFsdWUgPSAnJ1wiXG4gICAgICAgICAgICAgICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgICAgICAgICAgICAgIChrZXlkb3duLmVudGVyKT1cImZpbHRlcmVkT3B0aW9ucyA9IG9wdGlvbnM7IHZhbHVlID0gJydcIlxuICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICB7eyBsb2NhbGUgKyAnLm5vX3N1Z2dlc3Rpb25zJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICAgIEBpZihmaWx0ZXJWYWx1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkY2YtaWNvbi1jbGVhclwiPlxuICAgICAgICAgIDxpb24tYnV0dG9uIGZpbGw9XCJjbGVhclwiIHNpemU9XCJzbWFsbFwiIChjbGljayk9XCJjbGVhcigpXCI+XG4gICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cInRyYXNoLW91dGxpbmVcIiBbY29sb3JdPVwiIWlzRGFya01vZGUgPyAnZGFyaycgOiAnbWVkaXVtJ1wiIHNsb3Q9XCJpY29uLW9ubHlcIj48L2lvbi1pY29uPlxuICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICB9XG4gICAgICA8ZGl2IGNsYXNzPVwiZGNmLWljb24tc2VhcmNoXCI+XG4gICAgICAgIDxpb24tYnV0dG9uIGZpbGw9XCJjbGVhclwiIHNpemU9XCJzbWFsbFwiIChjbGljayk9XCJzdWJtaXQoKVwiPlxuICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwic2VhcmNoLW91dGxpbmVcIiBbY29sb3JdPVwiIWlzRGFya01vZGUgPyAnZGFyaycgOiAnbWVkaXVtJ1wiIHNsb3Q9XCJpY29uLW9ubHlcIj48L2lvbi1pY29uPlxuICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICBAaWYod2luZG93V2lkdGggPCA3NjgpIHtcbiAgICAgIDxkaXYgW2NsYXNzXT1cIidkY2YtZHJvcGRvd24gJyArIChvcHRpb25zLmxlbmd0aCA+IDAgPyAnIGRjZi1hY3RpdmUnIDogJycpXCIgI29wdGlvbnNGaWx0ZXJFbGVtZW50PlxuICAgICAgICA8ZGl2PlxuICAgICAgICAgIEBpZihmaWx0ZXJlZE9wdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgQGZvcihrZXkgb2YgZmlsdGVyZWRPcHRpb25zOyB0cmFjayBrZXkpIHtcbiAgICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZGNmLWl0ZW1cIlxuICAgICAgICAgICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwic2VsZWN0T3B0aW9uKGtleSlcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJzZWxlY3RPcHRpb24oa2V5KVwiPlxuICAgICAgICAgICAgICAgIHt7IGtleSB9fVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkY2YtZW1wdHlcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImZpbHRlcmVkT3B0aW9ucyA9IG9wdGlvbnM7IHZhbHVlID0gJydcIlxuICAgICAgICAgICAgdGFiaW5kZXg9XCIwXCJcbiAgICAgICAgICAgIChrZXlkb3duLmVudGVyKT1cImZpbHRlcmVkT3B0aW9ucyA9IG9wdGlvbnM7IHZhbHVlID0gJydcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICB7eyBsb2NhbGUgKyAnLm5vX3N1Z2dlc3Rpb25zJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIH1cbiAgPC9kaXY+XG4gIEBpZighZGlzYWJsZVNvcnQpIHtcbiAgICA8ZGl2IGNsYXNzPVwiZGNmLXdpZHRoLTEtNUBtIGRjZi13aWR0aC0xLTEgZGNmLXNvcnQtY29udGFpbmVyXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZGNmLWdyaWQgZGNmLWdyaWQtY29sbGFwc2UgZGNmLWZsZXggZGNmLWZsZXgtbWlkZGxlIGRjZi1ncmlkLW1hdGNoXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkY2Ytd2lkdGgtZXhwYW5kXCI+XG4gICAgICAgICAgPGlvbi1zZWxlY3RcbiAgICAgICAgICAgICAgdG9nZ2xlSWNvbj1cImNoZXZyb24tZG93bi1vdXRsaW5lXCJcbiAgICAgICAgICAgICAgZXhwYW5kZWRJY29uPVwiY2hldnJvbi11cC1vdXRsaW5lXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJkY2Ytc29ydC1zZWxlY3RcIlxuICAgICAgICAgICAgICAoaW9uQ2hhbmdlKT1cImhhbmRsZVNvcnRDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIGludGVyZmFjZT1cInBvcG92ZXJcIlxuICAgICAgICAgICAgICBbdmFsdWVdPVwic29ydFZhbHVlXCJcbiAgICAgICAgICAgICAgbGFiZWwtcGxhY2VtZW50PVwiZmxvYXRpbmdcIlxuICAgICAgICAgICAgICBmaWxsPVwib3V0bGluZVwiXG4gICAgICAgICAgICAgIFtsYWJlbF09XCJsb2NhbGUgKyAnLnNvcnQnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgIEBmb3Ioc29ydCBvZiBzb3J0Qnk7IHRyYWNrIHNvcnQpIHtcblxuICAgICAgICAgICAgICA8aW9uLXNlbGVjdC1vcHRpb24gW3ZhbHVlXT1cInNvcnRcIj57eyBzb3J0IHwgdHJhbnNsYXRlIH19PC9pb24tc2VsZWN0LW9wdGlvbj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2lvbi1zZWxlY3Q+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZGNmLXdpZHRoLWF1dG9cIj5cbiAgICAgICAgICA8aW9uLWJ1dHRvbiAoY2xpY2spPVwiaGFuZGxlU29ydERpcmVjdGlvbkNoYW5nZSgpXCIgZmlsbD1cImNsZWFyXCI+XG4gICAgICAgICAgICA8aW9uLWljb24gc2xvdD1cImljb24tb25seVwiIFtjb2xvcl09XCIhaXNEYXJrTW9kZSA/ICdwcmltYXJ5JyA6ICdtZWRpdW0nXCIgW25hbWVdPVwic29ydERpcmVjdGlvbiA9PT0gJ2Rlc2MnID8gJ2Fycm93LWRvd24tb3V0bGluZScgOiAnYXJyb3ctdXAtb3V0bGluZSdcIj48L2lvbi1pY29uPlxuICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgfVxuPC9kaXY+XG5cblxuIl19