@tolle_/tolle-ui 0.0.1-beta

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 (77) hide show
  1. package/README.md +35 -0
  2. package/esm2022/lib/accordion-item.component.mjs +78 -0
  3. package/esm2022/lib/accordion.component.mjs +60 -0
  4. package/esm2022/lib/badge.component.mjs +76 -0
  5. package/esm2022/lib/button-group.component.mjs +25 -0
  6. package/esm2022/lib/button.component.mjs +70 -0
  7. package/esm2022/lib/calendar.component.mjs +315 -0
  8. package/esm2022/lib/card.component.mjs +94 -0
  9. package/esm2022/lib/checkbox.component.mjs +100 -0
  10. package/esm2022/lib/data-table.component.mjs +332 -0
  11. package/esm2022/lib/date-picker.component.mjs +232 -0
  12. package/esm2022/lib/date-range-picker.component.mjs +208 -0
  13. package/esm2022/lib/input.component.mjs +134 -0
  14. package/esm2022/lib/masked-input.component.mjs +179 -0
  15. package/esm2022/lib/modal-ref.mjs +31 -0
  16. package/esm2022/lib/modal-stack.service.mjs +26 -0
  17. package/esm2022/lib/modal.component.mjs +98 -0
  18. package/esm2022/lib/modal.mjs +27 -0
  19. package/esm2022/lib/modal.service.mjs +65 -0
  20. package/esm2022/lib/multi-select.component.mjs +231 -0
  21. package/esm2022/lib/pagination.component.mjs +279 -0
  22. package/esm2022/lib/range-calendar.component.mjs +285 -0
  23. package/esm2022/lib/select-group.component.mjs +28 -0
  24. package/esm2022/lib/select-item.component.mjs +84 -0
  25. package/esm2022/lib/select-separator.component.mjs +24 -0
  26. package/esm2022/lib/select.component.mjs +261 -0
  27. package/esm2022/lib/select.service.mjs +21 -0
  28. package/esm2022/lib/skeleton.component.mjs +34 -0
  29. package/esm2022/lib/switch.component.mjs +133 -0
  30. package/esm2022/lib/toast.service.mjs +59 -0
  31. package/esm2022/lib/tolle-cell.directive.mjs +22 -0
  32. package/esm2022/lib/tolle-config.mjs +11 -0
  33. package/esm2022/lib/tooltip.directive.mjs +71 -0
  34. package/esm2022/lib/types/date-range.mjs +2 -0
  35. package/esm2022/lib/utils/cn.mjs +6 -0
  36. package/esm2022/public-api.mjs +36 -0
  37. package/esm2022/tolle_-tolle-ui.mjs +5 -0
  38. package/fesm2022/tolle_-tolle-ui.mjs +3553 -0
  39. package/fesm2022/tolle_-tolle-ui.mjs.map +1 -0
  40. package/index.d.ts +5 -0
  41. package/lib/accordion-item.component.d.ts +13 -0
  42. package/lib/accordion.component.d.ts +14 -0
  43. package/lib/badge.component.d.ts +14 -0
  44. package/lib/button-group.component.d.ts +8 -0
  45. package/lib/button.component.d.ts +16 -0
  46. package/lib/calendar.component.d.ts +35 -0
  47. package/lib/card.component.d.ts +32 -0
  48. package/lib/checkbox.component.d.ts +23 -0
  49. package/lib/data-table.component.d.ts +45 -0
  50. package/lib/date-picker.component.d.ts +35 -0
  51. package/lib/date-range-picker.component.d.ts +36 -0
  52. package/lib/input.component.d.ts +27 -0
  53. package/lib/masked-input.component.d.ts +36 -0
  54. package/lib/modal-ref.d.ts +16 -0
  55. package/lib/modal-stack.service.d.ts +12 -0
  56. package/lib/modal.component.d.ts +19 -0
  57. package/lib/modal.d.ts +29 -0
  58. package/lib/modal.service.d.ts +18 -0
  59. package/lib/multi-select.component.d.ts +47 -0
  60. package/lib/pagination.component.d.ts +36 -0
  61. package/lib/range-calendar.component.d.ts +37 -0
  62. package/lib/select-group.component.d.ts +8 -0
  63. package/lib/select-item.component.d.ts +18 -0
  64. package/lib/select-separator.component.d.ts +8 -0
  65. package/lib/select.component.d.ts +45 -0
  66. package/lib/select.service.d.ts +10 -0
  67. package/lib/skeleton.component.d.ts +10 -0
  68. package/lib/switch.component.d.ts +39 -0
  69. package/lib/toast.service.d.ts +24 -0
  70. package/lib/tolle-cell.directive.d.ts +9 -0
  71. package/lib/tolle-config.d.ts +9 -0
  72. package/lib/tooltip.directive.d.ts +15 -0
  73. package/lib/types/date-range.d.ts +4 -0
  74. package/lib/utils/cn.d.ts +2 -0
  75. package/package.json +32 -0
  76. package/public-api.d.ts +32 -0
  77. package/theme.css +211 -0
@@ -0,0 +1,332 @@
1
+ import { Component, Input, ContentChildren } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { cn } from './utils/cn';
5
+ import { PaginationComponent } from '@tolle/ui/pagination.component';
6
+ import { InputComponent } from '@tolle/ui/input.component';
7
+ import { TolleCellDirective } from '@tolle/ui/tolle-cell.directive';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/common";
10
+ import * as i2 from "@angular/forms";
11
+ export class DataTableComponent {
12
+ data = [];
13
+ columns = [];
14
+ searchable = true;
15
+ paginate = true;
16
+ pageSize = 10;
17
+ expandable = false;
18
+ size = 'default';
19
+ // Track which rows are open
20
+ expandedRows = new Set();
21
+ // Use ContentChildren to grab the tolleCell templates from the user's HTML
22
+ cellTemplates;
23
+ // Keep this as an Input for the main expansion slot
24
+ expandedTemplate;
25
+ filteredData = [];
26
+ pagedData = [];
27
+ searchTerm = '';
28
+ currentPage = 1;
29
+ sortKey = '';
30
+ sortDir = null;
31
+ // 2. Map Size to Padding for Cells
32
+ get cellPaddingClass() {
33
+ switch (this.size) {
34
+ case 'xs': return 'p-1 px-4'; // Ultra-compact
35
+ case 'sm': return 'p-2 px-4'; // Dense
36
+ case 'lg': return 'p-6 px-4'; // Spacious
37
+ default: return 'p-4'; // Standard (16px)
38
+ }
39
+ }
40
+ // 3. Map Size to Padding for Header (usually slightly shorter than cells)
41
+ get headerPaddingClass() {
42
+ switch (this.size) {
43
+ case 'xs': return 'h-7 px-4';
44
+ case 'sm': return 'h-9 px-4';
45
+ case 'lg': return 'h-14 px-4';
46
+ default: return 'h-12 px-4';
47
+ }
48
+ }
49
+ // 4. Map Size to Font Sizes
50
+ get fontSizeClass() {
51
+ switch (this.size) {
52
+ case 'xs': return 'text-[11px]';
53
+ case 'sm': return 'text-xs';
54
+ case 'lg': return 'text-base';
55
+ default: return 'text-sm';
56
+ }
57
+ }
58
+ cn = cn;
59
+ ngOnInit() { this.refreshTable(); }
60
+ ngOnChanges(changes) {
61
+ if (changes['data']) {
62
+ this.refreshTable();
63
+ }
64
+ }
65
+ // --- Search & Sort & Page Logic ---
66
+ // (Your existing implementation of applySearch, applySort, and updatePage goes here)
67
+ refreshTable() { this.applySearch(); this.applySort(); this.updatePage(); }
68
+ onSearch() { this.currentPage = 1; this.refreshTable(); }
69
+ applySearch() {
70
+ if (!this.searchTerm) {
71
+ this.filteredData = [...this.data];
72
+ return;
73
+ }
74
+ const q = this.searchTerm.toLowerCase();
75
+ this.filteredData = this.data.filter(row => Object.values(row).some(val => String(val).toLowerCase().includes(q)));
76
+ }
77
+ applySort() {
78
+ if (!this.sortKey || !this.sortDir)
79
+ return;
80
+ this.filteredData.sort((a, b) => {
81
+ const valA = a[this.sortKey];
82
+ const valB = b[this.sortKey];
83
+ if (valA < valB)
84
+ return this.sortDir === 'asc' ? -1 : 1;
85
+ if (valA > valB)
86
+ return this.sortDir === 'asc' ? 1 : -1;
87
+ return 0;
88
+ });
89
+ }
90
+ updatePage() {
91
+ if (!this.paginate) {
92
+ this.pagedData = this.filteredData;
93
+ return;
94
+ }
95
+ const start = (this.currentPage - 1) * this.pageSize;
96
+ const end = start + this.pageSize;
97
+ this.pagedData = this.filteredData.slice(start, end);
98
+ }
99
+ // --- Helpers ---
100
+ toggleSort(key) {
101
+ if (this.sortKey === key) {
102
+ this.sortDir = this.sortDir === 'asc' ? 'desc' : this.sortDir === 'desc' ? null : 'asc';
103
+ }
104
+ else {
105
+ this.sortKey = key;
106
+ this.sortDir = 'asc';
107
+ }
108
+ this.refreshTable();
109
+ }
110
+ getSortIcon(key) {
111
+ if (this.sortKey !== key || !this.sortDir)
112
+ return 'ri-arrow-up-down-line opacity-30';
113
+ return this.sortDir === 'asc' ? 'ri-arrow-up-line' : 'ri-arrow-down-line';
114
+ }
115
+ toggleRow(index) {
116
+ if (this.expandedRows.has(index))
117
+ this.expandedRows.delete(index);
118
+ else
119
+ this.expandedRows.add(index);
120
+ }
121
+ // Helper to find the right cell template
122
+ getTemplate(key) {
123
+ return this.cellTemplates?.find(t => t.name === key);
124
+ }
125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
126
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DataTableComponent, isStandalone: true, selector: "tolle-data-table", inputs: { data: "data", columns: "columns", searchable: "searchable", paginate: "paginate", pageSize: "pageSize", expandable: "expandable", size: "size", expandedTemplate: "expandedTemplate" }, queries: [{ propertyName: "cellTemplates", predicate: TolleCellDirective }], usesOnChanges: true, ngImport: i0, template: `
127
+ <div class="space-y-4">
128
+ <div *ngIf="searchable" class="flex items-center py-2">
129
+ <tolle-input
130
+ [size]="size === 'lg' ? 'default' : 'sm'"
131
+ class="max-w-sm"
132
+ placeholder="Filter records..."
133
+ [(ngModel)]="searchTerm"
134
+ (ngModelChange)="onSearch()">
135
+ <i prefix class="ri-search-line"></i>
136
+ </tolle-input>
137
+ </div>
138
+
139
+ <div class="rounded-md border border-border bg-background overflow-hidden shadow-sm">
140
+ <table class="w-full text-sm">
141
+ <thead class="border-b bg-muted/30">
142
+ <tr>
143
+ <th *ngIf="expandable" [class]="cn('px-4', size === 'xs' ? 'w-[32px]' : 'w-[48px]')"></th>
144
+ <th *ngFor="let col of columns"
145
+ [class]="cn(
146
+ 'font-medium text-muted-foreground transition-all',
147
+ headerPaddingClass,
148
+ fontSizeClass,
149
+ col.class
150
+ )">
151
+ <div *ngIf="col.sortable; else simpleHeader" (click)="toggleSort(col.key)" class="flex items-center gap-1 cursor-pointer hover:text-foreground">
152
+ {{ col.label }}
153
+ <i [class]="getSortIcon(col.key)"></i>
154
+ </div>
155
+ <ng-template #simpleHeader>{{ col.label }}</ng-template>
156
+ </th>
157
+ </tr>
158
+ </thead>
159
+ <tbody class="divide-y divide-border">
160
+ <ng-container *ngFor="let row of pagedData; let i = index">
161
+ <tr class="hover:bg-muted/50 transition-colors">
162
+ <td *ngIf="expandable" class="px-4">
163
+ <button (click)="toggleRow(i)"
164
+ [class]="cn(
165
+ 'flex items-center justify-center rounded-md hover:bg-accent text-muted-foreground hover:text-foreground',
166
+ size === 'xs' ? 'h-6 w-6' : 'h-8 w-8'
167
+ )">
168
+ <i [class]="expandedRows.has(i) ? 'ri-arrow-down-s-line' : 'ri-arrow-right-s-line'"></i>
169
+ </button>
170
+ </td>
171
+
172
+ <td *ngFor="let col of columns"
173
+ [class]="cn(
174
+ 'align-middle transition-all',
175
+ cellPaddingClass,
176
+ fontSizeClass,
177
+ col.class
178
+ )">
179
+ <ng-container *ngIf="getTemplate(col.key) as cell; else defaultValue">
180
+ <ng-container *ngTemplateOutlet="cell.template; context: { $implicit: row[col.key], row: row }"></ng-container>
181
+ </ng-container>
182
+ <ng-template #defaultValue>
183
+ <span class="text-foreground">{{ row[col.key] }}</span>
184
+ </ng-template>
185
+ </td>
186
+ </tr>
187
+
188
+ <tr *ngIf="expandedRows.has(i)" class="bg-muted/10">
189
+ <td [attr.colspan]="columns.length + (expandable ? 1 : 0)" class="p-0">
190
+ <div class="p-6 border-b border-dashed border-border">
191
+ <ng-container *ngIf="expandedTemplate; else defaultExpanded">
192
+ <ng-container *ngTemplateOutlet="expandedTemplate; context: { row: row }"></ng-container>
193
+ </ng-container>
194
+ <ng-template #defaultExpanded>
195
+ <div class="text-xs text-muted-foreground italic">No details available.</div>
196
+ </ng-template>
197
+ </div>
198
+ </td>
199
+ </tr>
200
+ </ng-container>
201
+ </tbody>
202
+ </table>
203
+ </div>
204
+
205
+ <tolle-pagination
206
+ *ngIf="paginate"
207
+ [totalRecords]="filteredData.length"
208
+ [currentPage]="currentPage"
209
+ [currentPageSize]="pageSize"
210
+ (onPageNumberChange)="updatePage()"
211
+ (onPageSizeChange)="updatePage()"
212
+ ></tolle-pagination>
213
+ </div>
214
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: PaginationComponent, selector: "tolle-pagination", inputs: ["class", "showPageLinks", "showPageOptions", "showCurrentPageInfo", "currentPageInfoTemplate", "totalRecords", "currentPageSize", "currentPage", "pageSizeOptions"], outputs: ["onPageNumberChange", "onPageSizeChange"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["type", "placeholder", "disabled", "error", "size", "containerClass", "class"] }] });
215
+ }
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, decorators: [{
217
+ type: Component,
218
+ args: [{
219
+ selector: 'tolle-data-table',
220
+ standalone: true,
221
+ imports: [CommonModule, FormsModule, PaginationComponent, InputComponent],
222
+ template: `
223
+ <div class="space-y-4">
224
+ <div *ngIf="searchable" class="flex items-center py-2">
225
+ <tolle-input
226
+ [size]="size === 'lg' ? 'default' : 'sm'"
227
+ class="max-w-sm"
228
+ placeholder="Filter records..."
229
+ [(ngModel)]="searchTerm"
230
+ (ngModelChange)="onSearch()">
231
+ <i prefix class="ri-search-line"></i>
232
+ </tolle-input>
233
+ </div>
234
+
235
+ <div class="rounded-md border border-border bg-background overflow-hidden shadow-sm">
236
+ <table class="w-full text-sm">
237
+ <thead class="border-b bg-muted/30">
238
+ <tr>
239
+ <th *ngIf="expandable" [class]="cn('px-4', size === 'xs' ? 'w-[32px]' : 'w-[48px]')"></th>
240
+ <th *ngFor="let col of columns"
241
+ [class]="cn(
242
+ 'font-medium text-muted-foreground transition-all',
243
+ headerPaddingClass,
244
+ fontSizeClass,
245
+ col.class
246
+ )">
247
+ <div *ngIf="col.sortable; else simpleHeader" (click)="toggleSort(col.key)" class="flex items-center gap-1 cursor-pointer hover:text-foreground">
248
+ {{ col.label }}
249
+ <i [class]="getSortIcon(col.key)"></i>
250
+ </div>
251
+ <ng-template #simpleHeader>{{ col.label }}</ng-template>
252
+ </th>
253
+ </tr>
254
+ </thead>
255
+ <tbody class="divide-y divide-border">
256
+ <ng-container *ngFor="let row of pagedData; let i = index">
257
+ <tr class="hover:bg-muted/50 transition-colors">
258
+ <td *ngIf="expandable" class="px-4">
259
+ <button (click)="toggleRow(i)"
260
+ [class]="cn(
261
+ 'flex items-center justify-center rounded-md hover:bg-accent text-muted-foreground hover:text-foreground',
262
+ size === 'xs' ? 'h-6 w-6' : 'h-8 w-8'
263
+ )">
264
+ <i [class]="expandedRows.has(i) ? 'ri-arrow-down-s-line' : 'ri-arrow-right-s-line'"></i>
265
+ </button>
266
+ </td>
267
+
268
+ <td *ngFor="let col of columns"
269
+ [class]="cn(
270
+ 'align-middle transition-all',
271
+ cellPaddingClass,
272
+ fontSizeClass,
273
+ col.class
274
+ )">
275
+ <ng-container *ngIf="getTemplate(col.key) as cell; else defaultValue">
276
+ <ng-container *ngTemplateOutlet="cell.template; context: { $implicit: row[col.key], row: row }"></ng-container>
277
+ </ng-container>
278
+ <ng-template #defaultValue>
279
+ <span class="text-foreground">{{ row[col.key] }}</span>
280
+ </ng-template>
281
+ </td>
282
+ </tr>
283
+
284
+ <tr *ngIf="expandedRows.has(i)" class="bg-muted/10">
285
+ <td [attr.colspan]="columns.length + (expandable ? 1 : 0)" class="p-0">
286
+ <div class="p-6 border-b border-dashed border-border">
287
+ <ng-container *ngIf="expandedTemplate; else defaultExpanded">
288
+ <ng-container *ngTemplateOutlet="expandedTemplate; context: { row: row }"></ng-container>
289
+ </ng-container>
290
+ <ng-template #defaultExpanded>
291
+ <div class="text-xs text-muted-foreground italic">No details available.</div>
292
+ </ng-template>
293
+ </div>
294
+ </td>
295
+ </tr>
296
+ </ng-container>
297
+ </tbody>
298
+ </table>
299
+ </div>
300
+
301
+ <tolle-pagination
302
+ *ngIf="paginate"
303
+ [totalRecords]="filteredData.length"
304
+ [currentPage]="currentPage"
305
+ [currentPageSize]="pageSize"
306
+ (onPageNumberChange)="updatePage()"
307
+ (onPageSizeChange)="updatePage()"
308
+ ></tolle-pagination>
309
+ </div>
310
+ `
311
+ }]
312
+ }], propDecorators: { data: [{
313
+ type: Input
314
+ }], columns: [{
315
+ type: Input
316
+ }], searchable: [{
317
+ type: Input
318
+ }], paginate: [{
319
+ type: Input
320
+ }], pageSize: [{
321
+ type: Input
322
+ }], expandable: [{
323
+ type: Input
324
+ }], size: [{
325
+ type: Input
326
+ }], cellTemplates: [{
327
+ type: ContentChildren,
328
+ args: [TolleCellDirective]
329
+ }], expandedTemplate: [{
330
+ type: Input
331
+ }] } });
332
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS10YWJsZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy90b2xsZS9zcmMvbGliL2RhdGEtdGFibGUuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQUUsS0FBSyxFQUNILGVBQWUsRUFDN0IsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ2hDLE9BQU8sRUFBQyxtQkFBbUIsRUFBQyxNQUFNLGdDQUFnQyxDQUFDO0FBQ25FLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUN6RCxPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxnQ0FBZ0MsQ0FBQzs7OztBQXVHbEUsTUFBTSxPQUFPLGtCQUFrQjtJQUNwQixJQUFJLEdBQVUsRUFBRSxDQUFDO0lBQ2pCLE9BQU8sR0FBa0IsRUFBRSxDQUFDO0lBQzVCLFVBQVUsR0FBRyxJQUFJLENBQUM7SUFDbEIsUUFBUSxHQUFHLElBQUksQ0FBQztJQUNoQixRQUFRLEdBQUcsRUFBRSxDQUFDO0lBQ2QsVUFBVSxHQUFHLEtBQUssQ0FBQztJQUNuQixJQUFJLEdBQW1DLFNBQVMsQ0FBQztJQUMxRCw0QkFBNEI7SUFDNUIsWUFBWSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFFakMsMkVBQTJFO0lBQ3RDLGFBQWEsQ0FBaUM7SUFFbkYsb0RBQW9EO0lBQzNDLGdCQUFnQixDQUFvQjtJQUU3QyxZQUFZLEdBQVUsRUFBRSxDQUFDO0lBQ3pCLFNBQVMsR0FBVSxFQUFFLENBQUM7SUFDdEIsVUFBVSxHQUFHLEVBQUUsQ0FBQztJQUNoQixXQUFXLEdBQUcsQ0FBQyxD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RSxtQkFBbUIsZ1NBQUUsY0FBYzs7NEZBMkY3RCxrQkFBa0I7a0JBOUY5QixTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxrQkFBa0I7b0JBQzVCLFVBQVUsRUFBRSxJQUFJO29CQUNoQixPQUFPLEVBQUUsQ0FBQyxZQUFZLEVBQUUsV0FBVyxFQUFFLG1CQUFtQixFQUFFLGNBQWMsQ0FBQztvQkFDekUsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0ZUO2lCQUNGOzhCQUVVLElBQUk7c0JBQVosS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxJQUFJO3NCQUFaLEtBQUs7Z0JBSytCLGFBQWE7c0JBQWpELGVBQWU7dUJBQUMsa0JBQWtCO2dCQUcxQixnQkFBZ0I7c0JBQXhCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsIElucHV0LCBPbkluaXQsIE9uQ2hhbmdlcywgU2ltcGxlQ2hhbmdlcyxcbiAgVGVtcGxhdGVSZWYsIENvbnRlbnRDaGlsZHJlbiwgUXVlcnlMaXN0XG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgY24gfSBmcm9tICcuL3V0aWxzL2NuJztcbmltcG9ydCB7UGFnaW5hdGlvbkNvbXBvbmVudH0gZnJvbSAnQHRvbGxlL3VpL3BhZ2luYXRpb24uY29tcG9uZW50JztcbmltcG9ydCB7SW5wdXRDb21wb25lbnR9IGZyb20gJ0B0b2xsZS91aS9pbnB1dC5jb21wb25lbnQnO1xuaW1wb3J0IHtUb2xsZUNlbGxEaXJlY3RpdmV9IGZyb20gJ0B0b2xsZS91aS90b2xsZS1jZWxsLmRpcmVjdGl2ZSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGFibGVDb2x1bW4ge1xuICBrZXk6IHN0cmluZztcbiAgbGFiZWw6IHN0cmluZztcbiAgc29ydGFibGU/OiBib29sZWFuO1xuICBjbGFzcz86IHN0cmluZztcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndG9sbGUtZGF0YS10YWJsZScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIEZvcm1zTW9kdWxlLCBQYWdpbmF0aW9uQ29tcG9uZW50LCBJbnB1dENvbXBvbmVudF0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cInNwYWNlLXktNFwiPlxuICAgICAgPGRpdiAqbmdJZj1cInNlYXJjaGFibGVcIiBjbGFzcz1cImZsZXggaXRlbXMtY2VudGVyIHB5LTJcIj5cbiAgICAgICAgPHRvbGxlLWlucHV0XG4gICAgICAgICAgW3NpemVdPVwic2l6ZSA9PT0gJ2xnJyA/ICdkZWZhdWx0JyA6ICdzbSdcIlxuICAgICAgICAgIGNsYXNzPVwibWF4LXctc21cIlxuICAgICAgICAgIHBsYWNlaG9sZGVyPVwiRmlsdGVyIHJlY29yZHMuLi5cIlxuICAgICAgICAgIFsobmdNb2RlbCldPVwic2VhcmNoVGVybVwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25TZWFyY2goKVwiPlxuICAgICAgICAgIDxpIHByZWZpeCBjbGFzcz1cInJpLXNlYXJjaC1saW5lXCI+PC9pPlxuICAgICAgICA8L3RvbGxlLWlucHV0PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJyb3VuZGVkLW1kIGJvcmRlciBib3JkZXItYm9yZGVyIGJnLWJhY2tncm91bmQgb3ZlcmZsb3ctaGlkZGVuIHNoYWRvdy1zbVwiPlxuICAgICAgICA8dGFibGUgY2xhc3M9XCJ3LWZ1bGwgdGV4dC1zbVwiPlxuICAgICAgICAgIDx0aGVhZCBjbGFzcz1cImJvcmRlci1iIGJnLW11dGVkLzMwXCI+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0aCAqbmdJZj1cImV4cGFuZGFibGVcIiBbY2xhc3NdPVwiY24oJ3B4LTQnLCBzaXplID09PSAneHMnID8gJ3ctWzMycHhdJyA6ICd3LVs0OHB4XScpXCI+PC90aD5cbiAgICAgICAgICAgICAgPHRoICpuZ0Zvcj1cImxldCBjb2wgb2YgY29sdW1uc1wiXG4gICAgICAgICAgICAgICAgICBbY2xhc3NdPVwiY24oXG4gICAgICAgICAgICAgICAgICAnZm9udC1tZWRpdW0gdGV4dC1tdXRlZC1mb3JlZ3JvdW5kIHRyYW5zaXRpb24tYWxsJyxcbiAgICAgICAgICAgICAgICAgIGhlYWRlclBhZGRpbmdDbGFzcyxcbiAgICAgICAgICAgICAgICAgIGZvbnRTaXplQ2xhc3MsXG4gICAgICAgICAgICAgICAgICBjb2wuY2xhc3NcbiAgICAgICAgICAgICAgICApXCI+XG4gICAgICAgICAgICAgICAgPGRpdiAqbmdJZj1cImNvbC5zb3J0YWJsZTsgZWxzZSBzaW1wbGVIZWFkZXJcIiAoY2xpY2spPVwidG9nZ2xlU29ydChjb2wua2V5KVwiIGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTEgY3Vyc29yLXBvaW50ZXIgaG92ZXI6dGV4dC1mb3JlZ3JvdW5kXCI+XG4gICAgICAgICAgICAgICAgICB7eyBjb2wubGFiZWwgfX1cbiAgICAgICAgICAgICAgICAgIDxpIFtjbGFzc109XCJnZXRTb3J0SWNvbihjb2wua2V5KVwiPjwvaT5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgI3NpbXBsZUhlYWRlcj57eyBjb2wubGFiZWwgfX08L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgICA8L3RoPlxuICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICA8L3RoZWFkPlxuICAgICAgICAgIDx0Ym9keSBjbGFzcz1cImRpdmlkZS15IGRpdmlkZS1ib3JkZXJcIj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IHJvdyBvZiBwYWdlZERhdGE7IGxldCBpID0gaW5kZXhcIj5cbiAgICAgICAgICAgICAgPHRyIGNsYXNzPVwiaG92ZXI6YmctbXV0ZWQvNTAgdHJhbnNpdGlvbi1jb2xvcnNcIj5cbiAgICAgICAgICAgICAgICA8dGQgKm5nSWY9XCJleHBhbmRhYmxlXCIgY2xhc3M9XCJweC00XCI+XG4gICAgICAgICAgICAgICAgICA8YnV0dG9uIChjbGljayk9XCJ0b2dnbGVSb3coaSlcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICBbY2xhc3NdPVwiY24oXG4gICAgICAgICAgICAgICAgICAgICAgJ2ZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHJvdW5kZWQtbWQgaG92ZXI6YmctYWNjZW50IHRleHQtbXV0ZWQtZm9yZWdyb3VuZCBob3Zlcjp0ZXh0LWZvcmVncm91bmQnLFxuICAgICAgICAgICAgICAgICAgICAgIHNpemUgPT09ICd4cycgPyAnaC02IHctNicgOiAnaC04IHctOCdcbiAgICAgICAgICAgICAgICAgICAgKVwiPlxuICAgICAgICAgICAgICAgICAgICA8aSBbY2xhc3NdPVwiZXhwYW5kZWRSb3dzLmhhcyhpKSA/ICdyaS1hcnJvdy1kb3duLXMtbGluZScgOiAncmktYXJyb3ctcmlnaHQtcy1saW5lJ1wiPjwvaT5cbiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgIDwvdGQ+XG5cbiAgICAgICAgICAgICAgICA8dGQgKm5nRm9yPVwibGV0IGNvbCBvZiBjb2x1bW5zXCJcbiAgICAgICAgICAgICAgICAgICAgW2NsYXNzXT1cImNuKFxuICAgICAgICAgICAgICAgICAgICAnYWxpZ24tbWlkZGxlIHRyYW5zaXRpb24tYWxsJyxcbiAgICAgICAgICAgICAgICAgICAgY2VsbFBhZGRpbmdDbGFzcyxcbiAgICAgICAgICAgICAgICAgICAgZm9udFNpemVDbGFzcyxcbiAgICAgICAgICAgICAgICAgICAgY29sLmNsYXNzXG4gICAgICAgICAgICAgICAgICApXCI+XG4gICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZ2V0VGVtcGxhdGUoY29sLmtleSkgYXMgY2VsbDsgZWxzZSBkZWZhdWx0VmFsdWVcIj5cbiAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImNlbGwudGVtcGxhdGU7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiByb3dbY29sLmtleV0sIHJvdzogcm93IH1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNkZWZhdWx0VmFsdWU+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1mb3JlZ3JvdW5kXCI+e3sgcm93W2NvbC5rZXldIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8L3RyPlxuXG4gICAgICAgICAgICAgIDx0ciAqbmdJZj1cImV4cGFuZGVkUm93cy5oYXMoaSlcIiBjbGFzcz1cImJnLW11dGVkLzEwXCI+XG4gICAgICAgICAgICAgICAgPHRkIFthdHRyLmNvbHNwYW5dPVwiY29sdW1ucy5sZW5ndGggKyAoZXhwYW5kYWJsZSA/IDEgOiAwKVwiIGNsYXNzPVwicC0wXCI+XG4gICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInAtNiBib3JkZXItYiBib3JkZXItZGFzaGVkIGJvcmRlci1ib3JkZXJcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZXhwYW5kZWRUZW1wbGF0ZTsgZWxzZSBkZWZhdWx0RXhwYW5kZWRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJleHBhbmRlZFRlbXBsYXRlOyBjb250ZXh0OiB7IHJvdzogcm93IH1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgI2RlZmF1bHRFeHBhbmRlZD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0ZXh0LXhzIHRleHQtbXV0ZWQtZm9yZWdyb3VuZCBpdGFsaWNcIj5ObyBkZXRhaWxzIGF2YWlsYWJsZS48L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8L3Rib2R5PlxuICAgICAgICA8L3RhYmxlPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDx0b2xsZS1wYWdpbmF0aW9uXG4gICAgICAgICpuZ0lmPVwicGFnaW5hdGVcIlxuICAgICAgICBbdG90YWxSZWNvcmRzXT1cImZpbHRlcmVkRGF0YS5sZW5ndGhcIlxuICAgICAgICBbY3VycmVudFBhZ2VdPVwiY3VycmVudFBhZ2VcIlxuICAgICAgICBbY3VycmVudFBhZ2VTaXplXT1cInBhZ2VTaXplXCJcbiAgICAgICAgKG9uUGFnZU51bWJlckNoYW5nZSk9XCJ1cGRhdGVQYWdlKClcIlxuICAgICAgICAob25QYWdlU2l6ZUNoYW5nZSk9XCJ1cGRhdGVQYWdlKClcIlxuICAgICAgPjwvdG9sbGUtcGFnaW5hdGlvbj5cbiAgICA8L2Rpdj5cbiAgYFxufSlcbmV4cG9ydCBjbGFzcyBEYXRhVGFibGVDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XG4gIEBJbnB1dCgpIGRhdGE6IGFueVtdID0gW107XG4gIEBJbnB1dCgpIGNvbHVtbnM6IFRhYmxlQ29sdW1uW10gPSBbXTtcbiAgQElucHV0KCkgc2VhcmNoYWJsZSA9IHRydWU7XG4gIEBJbnB1dCgpIHBhZ2luYXRlID0gdHJ1ZTtcbiAgQElucHV0KCkgcGFnZVNpemUgPSAxMDtcbiAgQElucHV0KCkgZXhwYW5kYWJsZSA9IGZhbHNlO1xuICBASW5wdXQoKSBzaXplOiAneHMnIHwgJ3NtJyB8ICdkZWZhdWx0JyB8ICdsZycgPSAnZGVmYXVsdCc7XG4gIC8vIFRyYWNrIHdoaWNoIHJvd3MgYXJlIG9wZW5cbiAgZXhwYW5kZWRSb3dzID0gbmV3IFNldDxudW1iZXI+KCk7XG5cbiAgLy8gVXNlIENvbnRlbnRDaGlsZHJlbiB0byBncmFiIHRoZSB0b2xsZUNlbGwgdGVtcGxhdGVzIGZyb20gdGhlIHVzZXIncyBIVE1MXG4gIEBDb250ZW50Q2hpbGRyZW4oVG9sbGVDZWxsRGlyZWN0aXZlKSBjZWxsVGVtcGxhdGVzITogUXVlcnlMaXN0PFRvbGxlQ2VsbERpcmVjdGl2ZT47XG5cbiAgLy8gS2VlcCB0aGlzIGFzIGFuIElucHV0IGZvciB0aGUgbWFpbiBleHBhbnNpb24gc2xvdFxuICBASW5wdXQoKSBleHBhbmRlZFRlbXBsYXRlPzogVGVtcGxhdGVSZWY8YW55PjtcblxuICBmaWx0ZXJlZERhdGE6IGFueVtdID0gW107XG4gIHBhZ2VkRGF0YTogYW55W10gPSBbXTtcbiAgc2VhcmNoVGVybSA9ICcnO1xuICBjdXJyZW50UGFnZSA9IDE7XG4gIHNvcnRLZXkgPSAnJztcbiAgc29ydERpcjogJ2FzYycgfCAnZGVzYycgfCBudWxsID0gbnVsbDtcblxuICAvLyAyLiBNYXAgU2l6ZSB0byBQYWRkaW5nIGZvciBDZWxsc1xuICBnZXQgY2VsbFBhZGRpbmdDbGFzcygpOiBzdHJpbmcge1xuICAgIHN3aXRjaCAodGhpcy5zaXplKSB7XG4gICAgICBjYXNlICd4cyc6IHJldHVybiAncC0xIHB4LTQnOyAgICAvLyBVbHRyYS1jb21wYWN0XG4gICAgICBjYXNlICdzbSc6IHJldHVybiAncC0yIHB4LTQnOyAgICAvLyBEZW5zZVxuICAgICAgY2FzZSAnbGcnOiByZXR1cm4gJ3AtNiBweC00JzsgICAgLy8gU3BhY2lvdXNcbiAgICAgIGRlZmF1bHQ6ICAgcmV0dXJuICdwLTQnOyAgICAgICAgIC8vIFN0YW5kYXJkICgxNnB4KVxuICAgIH1cbiAgfVxuXG4gIC8vIDMuIE1hcCBTaXplIHRvIFBhZGRpbmcgZm9yIEhlYWRlciAodXN1YWxseSBzbGlnaHRseSBzaG9ydGVyIHRoYW4gY2VsbHMpXG4gIGdldCBoZWFkZXJQYWRkaW5nQ2xhc3MoKTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKHRoaXMuc2l6ZSkge1xuICAgICAgY2FzZSAneHMnOiByZXR1cm4gJ2gtNyBweC00JztcbiAgICAgIGNhc2UgJ3NtJzogcmV0dXJuICdoLTkgcHgtNCc7XG4gICAgICBjYXNlICdsZyc6IHJldHVybiAnaC0xNCBweC00JztcbiAgICAgIGRlZmF1bHQ6ICAgcmV0dXJuICdoLTEyIHB4LTQnO1xuICAgIH1cbiAgfVxuXG4gIC8vIDQuIE1hcCBTaXplIHRvIEZvbnQgU2l6ZXNcbiAgZ2V0IGZvbnRTaXplQ2xhc3MoKTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKHRoaXMuc2l6ZSkge1xuICAgICAgY2FzZSAneHMnOiByZXR1cm4gJ3RleHQtWzExcHhdJztcbiAgICAgIGNhc2UgJ3NtJzogcmV0dXJuICd0ZXh0LXhzJztcbiAgICAgIGNhc2UgJ2xnJzogcmV0dXJuICd0ZXh0LWJhc2UnO1xuICAgICAgZGVmYXVsdDogICByZXR1cm4gJ3RleHQtc20nO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBjbiA9IGNuO1xuXG4gIG5nT25Jbml0KCkgeyB0aGlzLnJlZnJlc2hUYWJsZSgpOyB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcykge1xuICAgIGlmIChjaGFuZ2VzWydkYXRhJ10pIHsgdGhpcy5yZWZyZXNoVGFibGUoKTsgfVxuICB9XG5cbiAgLy8gLS0tIFNlYXJjaCAmIFNvcnQgJiBQYWdlIExvZ2ljIC0tLVxuICAvLyAoWW91ciBleGlzdGluZyBpbXBsZW1lbnRhdGlvbiBvZiBhcHBseVNlYXJjaCwgYXBwbHlTb3J0LCBhbmQgdXBkYXRlUGFnZSBnb2VzIGhlcmUpXG4gIHJlZnJlc2hUYWJsZSgpIHsgdGhpcy5hcHBseVNlYXJjaCgpOyB0aGlzLmFwcGx5U29ydCgpOyB0aGlzLnVwZGF0ZVBhZ2UoKTsgfVxuICBvblNlYXJjaCgpIHsgdGhpcy5jdXJyZW50UGFnZSA9IDE7IHRoaXMucmVmcmVzaFRhYmxlKCk7IH1cblxuICBwcml2YXRlIGFwcGx5U2VhcmNoKCkge1xuICAgIGlmICghdGhpcy5zZWFyY2hUZXJtKSB7IHRoaXMuZmlsdGVyZWREYXRhID0gWy4uLnRoaXMuZGF0YV07IHJldHVybjsgfVxuICAgIGNvbnN0IHEgPSB0aGlzLnNlYXJjaFRlcm0udG9Mb3dlckNhc2UoKTtcbiAgICB0aGlzLmZpbHRlcmVkRGF0YSA9IHRoaXMuZGF0YS5maWx0ZXIocm93ID0+XG4gICAgICBPYmplY3QudmFsdWVzKHJvdykuc29tZSh2YWwgPT4gU3RyaW5nKHZhbCkudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhxKSlcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBhcHBseVNvcnQoKSB7XG4gICAgaWYgKCF0aGlzLnNvcnRLZXkgfHwgIXRoaXMuc29ydERpcikgcmV0dXJuO1xuICAgIHRoaXMuZmlsdGVyZWREYXRhLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgIGNvbnN0IHZhbEEgPSBhW3RoaXMuc29ydEtleV07IGNvbnN0IHZhbEIgPSBiW3RoaXMuc29ydEtleV07XG4gICAgICBpZiAodmFsQSA8IHZhbEIpIHJldHVybiB0aGlzLnNvcnREaXIgPT09ICdhc2MnID8gLTEgOiAxO1xuICAgICAgaWYgKHZhbEEgPiB2YWxCKSByZXR1cm4gdGhpcy5zb3J0RGlyID09PSAnYXNjJyA/IDEgOiAtMTtcbiAgICAgIHJldHVybiAwO1xuICAgIH0pO1xuICB9XG5cbiAgdXBkYXRlUGFnZSgpIHtcbiAgICBpZiAoIXRoaXMucGFnaW5hdGUpIHsgdGhpcy5wYWdlZERhdGEgPSB0aGlzLmZpbHRlcmVkRGF0YTsgcmV0dXJuOyB9XG4gICAgY29uc3Qgc3RhcnQgPSAodGhpcy5jdXJyZW50UGFnZSAtIDEpICogdGhpcy5wYWdlU2l6ZTtcbiAgICBjb25zdCBlbmQgPSBzdGFydCArIHRoaXMucGFnZVNpemU7XG4gICAgdGhpcy5wYWdlZERhdGEgPSB0aGlzLmZpbHRlcmVkRGF0YS5zbGljZShzdGFydCwgZW5kKTtcbiAgfVxuXG4gIC8vIC0tLSBIZWxwZXJzIC0tLVxuICB0b2dnbGVTb3J0KGtleTogc3RyaW5nKSB7XG4gICAgaWYgKHRoaXMuc29ydEtleSA9PT0ga2V5KSB7XG4gICAgICB0aGlzLnNvcnREaXIgPSB0aGlzLnNvcnREaXIgPT09ICdhc2MnID8gJ2Rlc2MnIDogdGhpcy5zb3J0RGlyID09PSAnZGVzYycgPyBudWxsIDogJ2FzYyc7XG4gICAgfSBlbHNlIHsgdGhpcy5zb3J0S2V5ID0ga2V5OyB0aGlzLnNvcnREaXIgPSAnYXNjJzsgfVxuICAgIHRoaXMucmVmcmVzaFRhYmxlKCk7XG4gIH1cblxuICBnZXRTb3J0SWNvbihrZXk6IHN0cmluZykge1xuICAgIGlmICh0aGlzLnNvcnRLZXkgIT09IGtleSB8fCAhdGhpcy5zb3J0RGlyKSByZXR1cm4gJ3JpLWFycm93LXVwLWRvd24tbGluZSBvcGFjaXR5LTMwJztcbiAgICByZXR1cm4gdGhpcy5zb3J0RGlyID09PSAnYXNjJyA/ICdyaS1hcnJvdy11cC1saW5lJyA6ICdyaS1hcnJvdy1kb3duLWxpbmUnO1xuICB9XG5cbiAgdG9nZ2xlUm93KGluZGV4OiBudW1iZXIpIHtcbiAgICBpZiAodGhpcy5leHBhbmRlZFJvd3MuaGFzKGluZGV4KSkgdGhpcy5leHBhbmRlZFJvd3MuZGVsZXRlKGluZGV4KTtcbiAgICBlbHNlIHRoaXMuZXhwYW5kZWRSb3dzLmFkZChpbmRleCk7XG4gIH1cblxuICAvLyBIZWxwZXIgdG8gZmluZCB0aGUgcmlnaHQgY2VsbCB0ZW1wbGF0ZVxuICBnZXRUZW1wbGF0ZShrZXk6IHN0cmluZyk6IFRvbGxlQ2VsbERpcmVjdGl2ZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuY2VsbFRlbXBsYXRlcz8uZmluZCh0ID0+IHQubmFtZSA9PT0ga2V5KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,232 @@
1
+ import { Component, Input, forwardRef, ViewChild, HostListener } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
4
+ import { computePosition, flip, shift, offset, autoUpdate } from '@floating-ui/dom';
5
+ import { format, parse, isValid, startOfDay } from 'date-fns';
6
+ import { cn } from './utils/cn';
7
+ import { MaskedInputComponent } from './masked-input.component';
8
+ import { CalendarComponent } from './calendar.component';
9
+ import * as i0 from "@angular/core";
10
+ import * as i1 from "@angular/common";
11
+ import * as i2 from "@angular/forms";
12
+ export class DatePickerComponent {
13
+ cdr;
14
+ placeholder = 'MM/DD/YYYY';
15
+ disabled = false;
16
+ class = '';
17
+ disablePastDates = false;
18
+ triggerContainer;
19
+ popover;
20
+ value = null;
21
+ inputValue = '';
22
+ isOpen = false;
23
+ cleanupAutoUpdate;
24
+ constructor(cdr) {
25
+ this.cdr = cdr;
26
+ }
27
+ // --- Logic ---
28
+ onInputChange(str) {
29
+ if (str?.length === 10) {
30
+ const parsed = parse(str, 'MM/dd/yyyy', new Date());
31
+ if (isValid(parsed)) {
32
+ this.value = startOfDay(parsed);
33
+ this.onChange(this.value);
34
+ }
35
+ }
36
+ else if (!str) {
37
+ this.value = null;
38
+ this.onChange(null);
39
+ }
40
+ }
41
+ onCalendarChange(date) {
42
+ this.value = date;
43
+ this.inputValue = format(date, 'MM/dd/yyyy');
44
+ this.onChange(this.value);
45
+ this.close();
46
+ }
47
+ togglePopover(event) {
48
+ event.stopPropagation(); // Prevent bubbling to document
49
+ if (this.disabled)
50
+ return;
51
+ this.isOpen ? this.close() : this.open();
52
+ }
53
+ open() {
54
+ this.isOpen = true;
55
+ setTimeout(() => this.updatePosition());
56
+ }
57
+ close() {
58
+ this.isOpen = false;
59
+ if (this.cleanupAutoUpdate)
60
+ this.cleanupAutoUpdate();
61
+ }
62
+ clear(event) {
63
+ event.stopPropagation(); // CRITICAL: Stop the calendar from opening
64
+ this.value = null;
65
+ this.inputValue = '';
66
+ this.onChange(null);
67
+ this.cdr.markForCheck();
68
+ }
69
+ // --- Positioning ---
70
+ updatePosition() {
71
+ if (!this.triggerContainer || !this.popover)
72
+ return;
73
+ this.cleanupAutoUpdate = autoUpdate(this.triggerContainer.nativeElement, this.popover.nativeElement, () => {
74
+ computePosition(this.triggerContainer.nativeElement, this.popover.nativeElement, {
75
+ placement: 'bottom-end', // Aligned to the right where the icon is
76
+ middleware: [offset(4), flip(), shift({ padding: 8 })],
77
+ }).then(({ x, y }) => {
78
+ Object.assign(this.popover.nativeElement.style, {
79
+ left: `${x}px`,
80
+ top: `${y}px`,
81
+ visibility: 'visible',
82
+ });
83
+ });
84
+ });
85
+ }
86
+ onClickOutside(event) {
87
+ if (this.isOpen &&
88
+ !this.triggerContainer.nativeElement.contains(event.target) &&
89
+ !this.popover.nativeElement.contains(event.target)) {
90
+ this.close();
91
+ }
92
+ }
93
+ // --- CVA ---
94
+ onChange = () => { };
95
+ onTouched = () => { };
96
+ writeValue(val) {
97
+ if (val) {
98
+ const date = new Date(val);
99
+ if (isValid(date)) {
100
+ this.value = startOfDay(date);
101
+ this.inputValue = format(this.value, 'MM/dd/yyyy');
102
+ }
103
+ }
104
+ else {
105
+ this.value = null;
106
+ this.inputValue = '';
107
+ }
108
+ this.cdr.markForCheck();
109
+ }
110
+ registerOnChange(fn) { this.onChange = fn; }
111
+ registerOnTouched(fn) { this.onTouched = fn; }
112
+ setDisabledState(isDisabled) { this.disabled = isDisabled; }
113
+ cn = cn;
114
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatePickerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
115
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DatePickerComponent, isStandalone: true, selector: "tolle-date-picker", inputs: { placeholder: "placeholder", disabled: "disabled", class: "class", disablePastDates: "disablePastDates" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, providers: [
116
+ {
117
+ provide: NG_VALUE_ACCESSOR,
118
+ useExisting: forwardRef(() => DatePickerComponent),
119
+ multi: true
120
+ }
121
+ ], viewQueries: [{ propertyName: "triggerContainer", first: true, predicate: ["triggerContainer"], descendants: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: `
122
+ <div class="relative w-full" #triggerContainer>
123
+ <tolle-masked-input
124
+ #maskInput
125
+ [mask]="'00/00/0000'"
126
+ [placeholder]="placeholder"
127
+ [disabled]="disabled"
128
+ [(ngModel)]="inputValue"
129
+ (ngModelChange)="onInputChange($event)"
130
+ [class]="cn(class)"
131
+ >
132
+ <div suffix class="flex items-center gap-1.5 cursor-pointer">
133
+ <i
134
+ *ngIf="value && !disabled"
135
+ (click)="clear($event)"
136
+ class="ri-close-line cursor-pointer text-muted-foreground hover:text-foreground transition-colors"
137
+ ></i>
138
+
139
+ <i
140
+ (click)="togglePopover($event)"
141
+ class="ri-calendar-line cursor-pointer text-muted-foreground hover:text-primary transition-colors"
142
+ ></i>
143
+ </div>
144
+ </tolle-masked-input>
145
+
146
+ <div
147
+ #popover
148
+ *ngIf="isOpen"
149
+ class="absolute bg-popover z-50 max-w-max left-0 right-0 overflow-hidden rounded-md border border-border text-popover-foreground bg-background shadow-md"
150
+ style="visibility: hidden; top: 0; left: 0;"
151
+ >
152
+ <tolle-calendar
153
+ [(ngModel)]="value"
154
+ (ngModelChange)="onCalendarChange($event)"
155
+ [disablePastDates]="disablePastDates"
156
+ ></tolle-calendar>
157
+ </div>
158
+ </div>
159
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MaskedInputComponent, selector: "tolle-masked-input", inputs: ["mask", "placeholder", "type", "disabled", "class", "error", "size", "returnRaw"] }, { kind: "component", type: CalendarComponent, selector: "tolle-calendar", inputs: ["class", "disablePastDates"] }] });
160
+ }
161
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatePickerComponent, decorators: [{
162
+ type: Component,
163
+ args: [{
164
+ selector: 'tolle-date-picker',
165
+ standalone: true,
166
+ imports: [CommonModule, FormsModule, MaskedInputComponent, CalendarComponent],
167
+ providers: [
168
+ {
169
+ provide: NG_VALUE_ACCESSOR,
170
+ useExisting: forwardRef(() => DatePickerComponent),
171
+ multi: true
172
+ }
173
+ ],
174
+ template: `
175
+ <div class="relative w-full" #triggerContainer>
176
+ <tolle-masked-input
177
+ #maskInput
178
+ [mask]="'00/00/0000'"
179
+ [placeholder]="placeholder"
180
+ [disabled]="disabled"
181
+ [(ngModel)]="inputValue"
182
+ (ngModelChange)="onInputChange($event)"
183
+ [class]="cn(class)"
184
+ >
185
+ <div suffix class="flex items-center gap-1.5 cursor-pointer">
186
+ <i
187
+ *ngIf="value && !disabled"
188
+ (click)="clear($event)"
189
+ class="ri-close-line cursor-pointer text-muted-foreground hover:text-foreground transition-colors"
190
+ ></i>
191
+
192
+ <i
193
+ (click)="togglePopover($event)"
194
+ class="ri-calendar-line cursor-pointer text-muted-foreground hover:text-primary transition-colors"
195
+ ></i>
196
+ </div>
197
+ </tolle-masked-input>
198
+
199
+ <div
200
+ #popover
201
+ *ngIf="isOpen"
202
+ class="absolute bg-popover z-50 max-w-max left-0 right-0 overflow-hidden rounded-md border border-border text-popover-foreground bg-background shadow-md"
203
+ style="visibility: hidden; top: 0; left: 0;"
204
+ >
205
+ <tolle-calendar
206
+ [(ngModel)]="value"
207
+ (ngModelChange)="onCalendarChange($event)"
208
+ [disablePastDates]="disablePastDates"
209
+ ></tolle-calendar>
210
+ </div>
211
+ </div>
212
+ `
213
+ }]
214
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { placeholder: [{
215
+ type: Input
216
+ }], disabled: [{
217
+ type: Input
218
+ }], class: [{
219
+ type: Input
220
+ }], disablePastDates: [{
221
+ type: Input
222
+ }], triggerContainer: [{
223
+ type: ViewChild,
224
+ args: ['triggerContainer']
225
+ }], popover: [{
226
+ type: ViewChild,
227
+ args: ['popover']
228
+ }], onClickOutside: [{
229
+ type: HostListener,
230
+ args: ['document:mousedown', ['$event']]
231
+ }] } });
232
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvdG9sbGUvc3JjL2xpYi9kYXRlLXBpY2tlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFjLFNBQVMsRUFBRSxZQUFZLEVBQ2xFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQXdCLGlCQUFpQixFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3RGLE9BQU8sRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDcEYsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUM5RCxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ2hDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDOzs7O0FBcUR6RCxNQUFNLE9BQU8sbUJBQW1CO0lBY1Y7SUFiWCxXQUFXLEdBQUcsWUFBWSxDQUFDO0lBQzNCLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDakIsS0FBSyxHQUFHLEVBQUUsQ0FBQztJQUNYLGdCQUFnQixHQUFHLEtBQUssQ0FBQztJQUVILGdCQUFnQixDQUFjO0lBQ3ZDLE9BQU8sQ0FBYztJQUUzQyxLQUFLLEdBQWdCLElBQUksQ0FBQztJQUMxQixVQUFVLEdBQVcsRUFBRSxDQUFDO0lBQ3hCLE1BQU0sR0FBRyxLQUFLLENBQUM7SUFDZixpQkFBaUIsQ0FBYztJQUUvQixZQUFv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O29CQUNELFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzQ1Q7aUJBQ0Y7c0ZBRVUsV0FBVztzQkFBbkIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBRXlCLGdCQUFnQjtzQkFBOUMsU0FBUzt1QkFBQyxrQkFBa0I7Z0JBQ1AsT0FBTztzQkFBNUIsU0FBUzt1QkFBQyxTQUFTO2dCQStFcEIsY0FBYztzQkFEYixZQUFZO3VCQUFDLG9CQUFvQixFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LCBJbnB1dCwgZm9yd2FyZFJlZiwgRWxlbWVudFJlZiwgVmlld0NoaWxkLCBIb3N0TGlzdGVuZXIsIENoYW5nZURldGVjdG9yUmVmXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUiwgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBjb21wdXRlUG9zaXRpb24sIGZsaXAsIHNoaWZ0LCBvZmZzZXQsIGF1dG9VcGRhdGUgfSBmcm9tICdAZmxvYXRpbmctdWkvZG9tJztcbmltcG9ydCB7IGZvcm1hdCwgcGFyc2UsIGlzVmFsaWQsIHN0YXJ0T2ZEYXkgfSBmcm9tICdkYXRlLWZucyc7XG5pbXBvcnQgeyBjbiB9IGZyb20gJy4vdXRpbHMvY24nO1xuaW1wb3J0IHsgTWFza2VkSW5wdXRDb21wb25lbnQgfSBmcm9tICcuL21hc2tlZC1pbnB1dC5jb21wb25lbnQnO1xuaW1wb3J0IHsgQ2FsZW5kYXJDb21wb25lbnQgfSBmcm9tICcuL2NhbGVuZGFyLmNvbXBvbmVudCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3RvbGxlLWRhdGUtcGlja2VyJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgRm9ybXNNb2R1bGUsIE1hc2tlZElucHV0Q29tcG9uZW50LCBDYWxlbmRhckNvbXBvbmVudF0sXG4gIHByb3ZpZGVyczogW1xuICAgIHtcbiAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gRGF0ZVBpY2tlckNvbXBvbmVudCksXG4gICAgICBtdWx0aTogdHJ1ZVxuICAgIH1cbiAgXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwicmVsYXRpdmUgdy1mdWxsXCIgI3RyaWdnZXJDb250YWluZXI+XG4gICAgICA8dG9sbGUtbWFza2VkLWlucHV0XG4gICAgICAgICNtYXNrSW5wdXRcbiAgICAgICAgW21hc2tdPVwiJzAwLzAwLzAwMDAnXCJcbiAgICAgICAgW3BsYWNlaG9sZGVyXT1cInBsYWNlaG9sZGVyXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICAgICAgWyhuZ01vZGVsKV09XCJpbnB1dFZhbHVlXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25JbnB1dENoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgW2NsYXNzXT1cImNuKGNsYXNzKVwiXG4gICAgICA+XG4gICAgICAgIDxkaXYgc3VmZml4IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTEuNSBjdXJzb3ItcG9pbnRlclwiPlxuICAgICAgICAgIDxpXG4gICAgICAgICAgICAqbmdJZj1cInZhbHVlICYmICFkaXNhYmxlZFwiXG4gICAgICAgICAgICAoY2xpY2spPVwiY2xlYXIoJGV2ZW50KVwiXG4gICAgICAgICAgICBjbGFzcz1cInJpLWNsb3NlLWxpbmUgY3Vyc29yLXBvaW50ZXIgdGV4dC1tdXRlZC1mb3JlZ3JvdW5kIGhvdmVyOnRleHQtZm9yZWdyb3VuZCB0cmFuc2l0aW9uLWNvbG9yc1wiXG4gICAgICAgICAgPjwvaT5cblxuICAgICAgICAgIDxpXG4gICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlUG9wb3ZlcigkZXZlbnQpXCJcbiAgICAgICAgICAgIGNsYXNzPVwicmktY2FsZW5kYXItbGluZSBjdXJzb3ItcG9pbnRlciB0ZXh0LW11dGVkLWZvcmVncm91bmQgaG92ZXI6dGV4dC1wcmltYXJ5IHRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICA+PC9pPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvdG9sbGUtbWFza2VkLWlucHV0PlxuXG4gICAgICA8ZGl2XG4gICAgICAgICNwb3BvdmVyXG4gICAgICAgICpuZ0lmPVwiaXNPcGVuXCJcbiAgICAgICAgY2xhc3M9XCJhYnNvbHV0ZSBiZy1wb3BvdmVyIHotNTAgbWF4LXctbWF4IGxlZnQtMCByaWdodC0wIG92ZXJmbG93LWhpZGRlbiByb3VuZGVkLW1kIGJvcmRlciBib3JkZXItYm9yZGVyIHRleHQtcG9wb3Zlci1mb3JlZ3JvdW5kIGJnLWJhY2tncm91bmQgc2hhZG93LW1kXCJcbiAgICAgICAgc3R5bGU9XCJ2aXNpYmlsaXR5OiBoaWRkZW47IHRvcDogMDsgbGVmdDogMDtcIlxuICAgICAgPlxuICAgICAgICA8dG9sbGUtY2FsZW5kYXJcbiAgICAgICAgICBbKG5nTW9kZWwpXT1cInZhbHVlXCJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkNhbGVuZGFyQ2hhbmdlKCRldmVudClcIlxuICAgICAgICAgIFtkaXNhYmxlUGFzdERhdGVzXT1cImRpc2FibGVQYXN0RGF0ZXNcIlxuICAgICAgICA+PC90b2xsZS1jYWxlbmRhcj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICBgXG59KVxuZXhwb3J0IGNsYXNzIERhdGVQaWNrZXJDb21wb25lbnQgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciB7XG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyID0gJ01NL0REL1lZWVknO1xuICBASW5wdXQoKSBkaXNhYmxlZCA9IGZhbHNlO1xuICBASW5wdXQoKSBjbGFzcyA9ICcnO1xuICBASW5wdXQoKSBkaXNhYmxlUGFzdERhdGVzID0gZmFsc2U7XG5cbiAgQFZpZXdDaGlsZCgndHJpZ2dlckNvbnRhaW5lcicpIHRyaWdnZXJDb250YWluZXIhOiBFbGVtZW50UmVmO1xuICBAVmlld0NoaWxkKCdwb3BvdmVyJykgcG9wb3ZlciE6IEVsZW1lbnRSZWY7XG5cbiAgdmFsdWU6IERhdGUgfCBudWxsID0gbnVsbDtcbiAgaW5wdXRWYWx1ZTogc3RyaW5nID0gJyc7XG4gIGlzT3BlbiA9IGZhbHNlO1xuICBjbGVhbnVwQXV0b1VwZGF0ZT86ICgpID0+IHZvaWQ7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG4gIC8vIC0tLSBMb2dpYyAtLS1cblxuICBvbklucHV0Q2hhbmdlKHN0cjogc3RyaW5nKSB7XG4gICAgaWYgKHN0cj8ubGVuZ3RoID09PSAxMCkge1xuICAgICAgY29uc3QgcGFyc2VkID0gcGFyc2Uoc3RyLCAnTU0vZGQveXl5eScsIG5ldyBEYXRlKCkpO1xuICAgICAgaWYgKGlzVmFsaWQocGFyc2VkKSkge1xuICAgICAgICB0aGlzLnZhbHVlID0gc3RhcnRPZkRheShwYXJzZWQpO1xuICAgICAgICB0aGlzLm9uQ2hhbmdlKHRoaXMudmFsdWUpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoIXN0cikge1xuICAgICAgdGhpcy52YWx1ZSA9IG51bGw7XG4gICAgICB0aGlzLm9uQ2hhbmdlKG51bGwpO1xuICAgIH1cbiAgfVxuXG4gIG9uQ2FsZW5kYXJDaGFuZ2UoZGF0ZTogRGF0ZSkge1xuICAgIHRoaXMudmFsdWUgPSBkYXRlO1xuICAgIHRoaXMuaW5wdXRWYWx1ZSA9IGZvcm1hdChkYXRlLCAnTU0vZGQveXl5eScpO1xuICAgIHRoaXMub25DaGFuZ2UodGhpcy52YWx1ZSk7XG4gICAgdGhpcy5jbG9zZSgpO1xuICB9XG5cbiAgdG9nZ2xlUG9wb3ZlcihldmVudDogTW91c2VFdmVudCkge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpOyAvLyBQcmV2ZW50IGJ1YmJsaW5nIHRvIGRvY3VtZW50XG4gICAgaWYgKHRoaXMuZGlzYWJsZWQpIHJldHVybjtcbiAgICB0aGlzLmlzT3BlbiA/IHRoaXMuY2xvc2UoKSA6IHRoaXMub3BlbigpO1xuICB9XG5cbiAgb3BlbigpIHtcbiAgICB0aGlzLmlzT3BlbiA9IHRydWU7XG4gICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnVwZGF0ZVBvc2l0aW9uKCkpO1xuICB9XG5cbiAgY2xvc2UoKSB7XG4gICAgdGhpcy5pc09wZW4gPSBmYWxzZTtcbiAgICBpZiAodGhpcy5jbGVhbnVwQXV0b1VwZGF0ZSkgdGhpcy5jbGVhbnVwQXV0b1VwZGF0ZSgpO1xuICB9XG5cbiAgY2xlYXIoZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTsgLy8gQ1JJVElDQUw6IFN0b3AgdGhlIGNhbGVuZGFyIGZyb20gb3BlbmluZ1xuICAgIHRoaXMudmFsdWUgPSBudWxsO1xuICAgIHRoaXMuaW5wdXRWYWx1ZSA9ICcnO1xuICAgIHRoaXMub25DaGFuZ2UobnVsbCk7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICAvLyAtLS0gUG9zaXRpb25pbmcgLS0tXG5cbiAgcHJpdmF0ZSB1cGRhdGVQb3NpdGlvbigpIHtcbiAgICBpZiAoIXRoaXMudHJpZ2dlckNvbnRhaW5lciB8fCAhdGhpcy5wb3BvdmVyKSByZXR1cm47XG5cbiAgICB0aGlzLmNsZWFudXBBdXRvVXBkYXRlID0gYXV0b1VwZGF0ZShcbiAgICAgIHRoaXMudHJpZ2dlckNvbnRhaW5lci5uYXRpdmVFbGVtZW50LFxuICAgICAgdGhpcy5wb3BvdmVyLm5hdGl2ZUVsZW1lbnQsXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNvbXB1dGVQb3NpdGlvbih0aGlzLnRyaWdnZXJDb250YWluZXIubmF0aXZlRWxlbWVudCwgdGhpcy5wb3BvdmVyLm5hdGl2ZUVsZW1lbnQsIHtcbiAgICAgICAgICBwbGFjZW1lbnQ6ICdib3R0b20tZW5kJywgLy8gQWxpZ25lZCB0byB0aGUgcmlnaHQgd2hlcmUgdGhlIGljb24gaXNcbiAgICAgICAgICBtaWRkbGV3YXJlOiBbb2Zmc2V0KDQpLCBmbGlwKCksIHNoaWZ0KHsgcGFkZGluZzogOCB9KV0sXG4gICAgICAgIH0pLnRoZW4oKHsgeCwgeSB9KSA9PiB7XG4gICAgICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLnBvcG92ZXIubmF0aXZlRWxlbWVudC5zdHlsZSwge1xuICAgICAgICAgICAgbGVmdDogYCR7eH1weGAsXG4gICAgICAgICAgICB0b3A6IGAke3l9cHhgLFxuICAgICAgICAgICAgdmlzaWJpbGl0eTogJ3Zpc2libGUnLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6bW91c2Vkb3duJywgWyckZXZlbnQnXSlcbiAgb25DbGlja091dHNpZGUoZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAodGhpcy5pc09wZW4gJiZcbiAgICAgICF0aGlzLnRyaWdnZXJDb250YWluZXIubmF0aXZlRWxlbWVudC5jb250YWlucyhldmVudC50YXJnZXQpICYmXG4gICAgICAhdGhpcy5wb3BvdmVyLm5hdGl2ZUVsZW1lbnQuY29udGFpbnMoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgdGhpcy5jbG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIC8vIC0tLSBDVkEgLS0tXG4gIG9uQ2hhbmdlOiBhbnkgPSAoKSA9PiB7fTtcbiAgb25Ub3VjaGVkOiBhbnkgPSAoKSA9PiB7fTtcblxuICB3cml0ZVZhbHVlKHZhbDogYW55KTogdm9pZCB7XG4gICAgaWYgKHZhbCkge1xuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHZhbCk7XG4gICAgICBpZiAoaXNWYWxpZChkYXRlKSkge1xuICAgICAgICB0aGlzLnZhbHVlID0gc3RhcnRPZkRheShkYXRlKTtcbiAgICAgICAgdGhpcy5pbnB1dFZhbHVlID0gZm9ybWF0KHRoaXMudmFsdWUsICdNTS9kZC95eXl5Jyk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudmFsdWUgPSBudWxsO1xuICAgICAgdGhpcy5pbnB1dFZhbHVlID0gJyc7XG4gICAgfVxuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgcmVnaXN0ZXJPbkNoYW5nZShmbjogYW55KTogdm9pZCB7IHRoaXMub25DaGFuZ2UgPSBmbjsgfVxuICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7IHRoaXMub25Ub3VjaGVkID0gZm47IH1cbiAgc2V0RGlzYWJsZWRTdGF0ZShpc0Rpc2FibGVkOiBib29sZWFuKTogdm9pZCB7IHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkOyB9XG4gIHByb3RlY3RlZCBjbiA9IGNuO1xufVxuIl19