@firestitch/report 18.0.19 → 18.0.21

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 (23) hide show
  1. package/app/reports/data/report.data.d.ts +8 -2
  2. package/app/reports/dialogs/report-settings/report-settings.component.d.ts +4 -2
  3. package/app/reports/interfaces/report.interface.d.ts +26 -2
  4. package/app/reports/layout.d.ts +2 -0
  5. package/app/reports/services/report-filter-state.service.d.ts +4 -1
  6. package/app/reports/views/report/fs-ai-report.component.d.ts +2 -0
  7. package/app/reports/views/report/report.component.d.ts +2 -0
  8. package/app/reports/views/reports/fs-ai-reports.component.d.ts +28 -8
  9. package/esm2022/app/reports/data/report.data.mjs +53 -4
  10. package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +16 -11
  11. package/esm2022/app/reports/interfaces/report.interface.mjs +12 -1
  12. package/esm2022/app/reports/layout.mjs +6 -1
  13. package/esm2022/app/reports/services/report-filter-state.service.mjs +55 -4
  14. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +27 -5
  15. package/esm2022/app/reports/views/report/report.component.mjs +27 -5
  16. package/esm2022/app/reports/views/reports/fs-ai-reports.component.mjs +342 -74
  17. package/fesm2022/{firestitch-report-echarts-CfwgLaOA.mjs → firestitch-report-echarts-BYmAhi-N.mjs} +2 -2
  18. package/fesm2022/{firestitch-report-echarts-CfwgLaOA.mjs.map → firestitch-report-echarts-BYmAhi-N.mjs.map} +1 -1
  19. package/fesm2022/{firestitch-report-firestitch-report-_MCMM4XH.mjs → firestitch-report-firestitch-report-acZuB8V2.mjs} +529 -99
  20. package/fesm2022/firestitch-report-firestitch-report-acZuB8V2.mjs.map +1 -0
  21. package/fesm2022/firestitch-report.mjs +1 -1
  22. package/package.json +1 -1
  23. package/fesm2022/firestitch-report-firestitch-report-_MCMM4XH.mjs.map +0 -1
@@ -1,29 +1,46 @@
1
- import { ChangeDetectionStrategy, Component, DestroyRef, ViewChild, effect, inject, input } from '@angular/core';
1
+ import { ChangeDetectionStrategy, Component, DestroyRef, effect, inject, input, signal, viewChild, } from '@angular/core';
2
2
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
3
  import { ActivatedRoute, Router, RouterLink } from '@angular/router';
4
4
  import { MatDialog } from '@angular/material/dialog';
5
- import { FsDateModule } from '@firestitch/date';
6
- import { FsListComponent, FsListModule } from '@firestitch/list';
5
+ import { MatIconModule } from '@angular/material/icon';
6
+ import { FsFilterModule, ItemType } from '@firestitch/filter';
7
+ import { FsMessage } from '@firestitch/message';
7
8
  import { FsPrompt } from '@firestitch/prompt';
8
- import { map, switchMap } from 'rxjs/operators';
9
+ import { FsSkeletonModule } from '@firestitch/skeleton';
10
+ import { FsTreeComponent, FsTreeModule, TreeActionType, TreeDragMode, } from '@firestitch/tree';
11
+ import { switchMap } from 'rxjs';
9
12
  import { ReportData } from '../../data/report.data';
10
13
  import { GlobalSettingsComponent } from '../../dialogs/global-settings/global-settings.component';
11
- import { ReportState } from '../../interfaces/report.interface';
14
+ import { ReportNodeType, ReportState, ReportStates, } from '../../interfaces/report.interface';
12
15
  import * as i0 from "@angular/core";
13
- import * as i1 from "@firestitch/date";
14
- import * as i2 from "@firestitch/list";
15
- // The reports listing — an fs-list of reports. Rows are links built from a URL
16
- // pattern (a ':id' token → the report id; a leading '/' makes it absolute,
17
- // otherwise it's relative to this component's route). Create prompts for a
18
- // title, creates the report, then routes to it. The header gear opens the
19
- // global Report Settings dialog (AI knowledge document + semantic-database
20
- // build), which lives in this package. No routing is hard-coded here.
16
+ import * as i1 from "@firestitch/filter";
17
+ import * as i2 from "@firestitch/skeleton";
18
+ import * as i3 from "@firestitch/tree";
19
+ import * as i4 from "@angular/material/icon";
20
+ // The reports listing an fs-tree of folders and the reports filed into them.
21
+ // Rows link out through a URL pattern (a ':id' token the report id; a leading
22
+ // '/' makes it absolute, otherwise it's relative to this component's route).
23
+ // Create prompts for a title, creates the report, then routes to it. The gear
24
+ // opens the global Report Settings dialog (AI knowledge document +
25
+ // semantic-database build), which lives in this package. No routing is
26
+ // hard-coded here.
27
+ //
28
+ // Folders nest; reports are always leaves — canDrop enforces it here, and the
29
+ // backend enforces it structurally by keeping the tree in its own table. A
30
+ // report in no folder is a root node, which is where every report sat before
31
+ // folders existed, so nothing had to be migrated or bucketed as "uncategorized".
21
32
  //
22
33
  // Reports are soft-deletable: the row kebab deletes, "Show Deleted" flips the
23
- // list into deleted mode (the backend hides deleted reports otherwise), and in
24
- // that mode fs-list swaps Delete for Restore, which calls the undelete action
25
- // endpoint.
34
+ // listing into deleted mode (the backend hides deleted reports otherwise), and
35
+ // in that mode the kebab offers Restore instead. Folders do NOT take part in
36
+ // that — a folder is only deletable once it is empty, so it hard deletes and has
37
+ // nothing to restore. The upshot is that deleted mode keeps the folder structure
38
+ // on screen with the deleted reports sitting where they belong, so restoring one
39
+ // puts it back rather than dropping it at the root.
26
40
  export class FsAiReportsComponent {
41
+ // How deep the tree opens on load. Folders are audience buckets, not a
42
+ // filesystem, so there is nothing worth hiding behind a closed chevron.
43
+ static EXPAND_LEVEL = 10;
27
44
  // API base for the reports endpoints; override to mount elsewhere.
28
45
  basePath = input('reports');
29
46
  // Where a row links to; ':id' is replaced with the report id. Default takes
@@ -31,27 +48,44 @@ export class FsAiReportsComponent {
31
48
  openPattern = input(':id');
32
49
  // Where a freshly-created report routes to; same ':id' pattern rules.
33
50
  createPattern = input(':id');
34
- list = null;
35
- listConfig;
36
- // Template-side handle on the enum, so the name cell can tell a deleted row
37
- // (shown in Show Deleted mode) from a live one.
38
- deletedState = ReportState.Deleted;
51
+ // Null until the first load resolves — that is what gates *fsSkeleton.
52
+ nodes = signal(null);
53
+ treeConfig;
54
+ filterConfig;
55
+ // Template-side handle on the enum, so a row can tell a folder from a report.
56
+ nodeType = ReportNodeType;
57
+ _tree = viewChild(FsTreeComponent);
39
58
  _reportData = inject(ReportData);
40
59
  _router = inject(Router);
41
60
  _route = inject(ActivatedRoute);
42
61
  _prompt = inject(FsPrompt);
62
+ _message = inject(FsMessage);
43
63
  _dialog = inject(MatDialog);
44
64
  _destroyRef = inject(DestroyRef);
65
+ // The filter bar's current query — carries `state` when Show Deleted is on.
66
+ _query = {};
45
67
  constructor() {
46
68
  effect(() => {
47
69
  this._reportData.basePath = this.basePath();
48
70
  });
49
- this._initListConfig();
71
+ }
72
+ ngOnInit() {
73
+ // Set before the first fetch rather than waiting on the effect above, which
74
+ // does not run until after the initial change detection pass.
75
+ this._reportData.basePath = this.basePath();
76
+ this._initFilterConfig();
77
+ this._initTreeConfig();
78
+ this._load();
50
79
  }
51
80
  // routerLink commands for a report row (built from openPattern).
52
81
  openLink(report) {
53
82
  return this._patternCommands(this.openPattern(), report.id);
54
83
  }
84
+ // A deleted report can't be opened — the backend only assembles active ones —
85
+ // so in Show Deleted mode its name renders as plain text rather than a link.
86
+ isDeleted(report) {
87
+ return report?.state === ReportState.Deleted;
88
+ }
55
89
  // Prompt for a title, create the report, then route to it (createPattern).
56
90
  createReport() {
57
91
  this._prompt.input({
@@ -66,21 +100,6 @@ export class FsAiReportsComponent {
66
100
  this._router.navigate(this._patternCommands(pattern, report.id), pattern.startsWith('/') ? {} : { relativeTo: this._route });
67
101
  });
68
102
  }
69
- // Turn a ':id' pattern into router commands. Relative unless it starts
70
- // with '/', in which case the first segment carries the leading slash.
71
- _patternCommands(pattern, id) {
72
- const absolute = pattern.startsWith('/');
73
- const segments = pattern.split('/')
74
- .filter((segment) => segment.length > 0)
75
- .map((segment) => (segment === ':id' ? id : segment));
76
- if (!segments.length) {
77
- return [id];
78
- }
79
- if (absolute) {
80
- segments[0] = `/${segments[0]}`;
81
- }
82
- return segments;
83
- }
84
103
  // The global Report Settings dialog: the AI knowledge document and the
85
104
  // semantic-database build. A running build streams into the FsProcess dock,
86
105
  // which survives the dialog closing.
@@ -92,64 +111,313 @@ export class FsAiReportsComponent {
92
111
  autoFocus: false,
93
112
  });
94
113
  }
95
- _initListConfig() {
96
- this.listConfig = {
97
- // The backend list is not paged yet; show the full set until it is.
98
- paging: false,
114
+ _initFilterConfig() {
115
+ this.filterConfig = {
116
+ items: [
117
+ {
118
+ name: 'keyword',
119
+ type: ItemType.Keyword,
120
+ label: 'Search',
121
+ },
122
+ {
123
+ name: 'state',
124
+ type: ItemType.Select,
125
+ label: 'Status',
126
+ multiple: true,
127
+ values: () => ReportStates,
128
+ isolate: { label: 'Show Deleted', value: ReportState.Deleted },
129
+ },
130
+ ],
99
131
  actions: [
100
132
  {
101
- // Icon-only: the global Report Settings dialog.
133
+ icon: 'unfold_more',
134
+ tooltip: 'Expand all',
135
+ primary: false,
136
+ click: () => this._tree()?.expandAll(),
137
+ },
138
+ {
139
+ icon: 'unfold_less',
140
+ tooltip: 'Collapse all',
141
+ primary: false,
142
+ click: () => this._tree()?.collapseAll(),
143
+ },
144
+ {
102
145
  icon: 'settings',
103
146
  tooltip: 'Report settings',
104
147
  primary: false,
105
148
  click: () => this.openSettings(),
106
149
  },
150
+ {
151
+ label: 'New Folder',
152
+ primary: false,
153
+ click: () => this._createFolder(null),
154
+ },
107
155
  {
108
156
  label: 'Create',
109
157
  primary: true,
110
158
  click: () => this.createReport(),
111
159
  },
112
160
  ],
113
- rowActions: [
161
+ // The two items are answered in different places and both have to run.
162
+ // The keyword drives the tree's own search, which is the whole point of
163
+ // searching a tree — it reveals a match nested inside collapsed folders
164
+ // rather than only filtering what is already on screen. `state` is the
165
+ // Show Deleted toggle, and only the server can answer that.
166
+ change: (query) => {
167
+ const stateChanged = String(query?.state ?? '') !== String(this._query.state ?? '');
168
+ this._query = { ...query };
169
+ this._search(query?.keyword);
170
+ if (stateChanged) {
171
+ this._load();
172
+ }
173
+ },
174
+ };
175
+ }
176
+ _initTreeConfig() {
177
+ this.treeConfig = {
178
+ data: [],
179
+ childrenName: 'children',
180
+ expandLevel: FsAiReportsComponent.EXPAND_LEVEL,
181
+ draggable: true,
182
+ // The whole row is the grip and the handle stays hidden; a press only
183
+ // becomes a drag once the pointer moves, so the kebab, the chevron and the
184
+ // report link all stay clickable.
185
+ dragMode: TreeDragMode.Node,
186
+ // canDrop is asked about the node being DRAGGED, so only `toParent`
187
+ // describes the destination — reading node.level/node.parent here would
188
+ // describe where it came from. A report can never be a parent because its
189
+ // type says so, and that single test is the whole "folders nest, reports
190
+ // are leaves" rule on this side.
191
+ canDrop: (node, fromParent, toParent) => {
192
+ return !toParent || toParent.data?.type === ReportNodeType.Folder;
193
+ },
194
+ changeReorder: (event) => this._move(event),
195
+ nodeClass: (node) => node.data?.type,
196
+ // Match on the name only. The library's default matcher stringifies the
197
+ // whole node, so it would hit ids, the literal type word, and everything
198
+ // else riding on the row.
199
+ filterItem: (node, query) => {
200
+ return String(node.data?.name ?? '')
201
+ .toLowerCase()
202
+ .includes(String(query ?? '').toLowerCase());
203
+ },
204
+ actions: [
114
205
  {
115
- click: (report) => this._reportData.delete(report.id),
116
- remove: {
117
- title: 'Confirm',
118
- template: 'Are you sure you would like to delete this report?',
119
- },
120
- menu: true,
121
- label: 'Delete',
206
+ type: TreeActionType.Menu,
207
+ icon: 'more_vert',
208
+ items: [
209
+ {
210
+ label: 'Rename',
211
+ show: (node) => !this._isDeletedNode(node),
212
+ click: (node) => this._rename(node),
213
+ },
214
+ {
215
+ label: 'New Folder Inside',
216
+ show: (node) => this._isFolderNode(node),
217
+ click: (node) => this._createFolder(node.data?.id),
218
+ },
219
+ {
220
+ label: 'Delete',
221
+ show: (node) => !this._isDeletedNode(node),
222
+ click: (node) => this._delete(node),
223
+ },
224
+ // Folders never reach this: they hard delete, so a deleted folder
225
+ // does not exist to be restored.
226
+ {
227
+ label: 'Restore',
228
+ show: (node) => this._isDeletedNode(node),
229
+ click: (node) => this._restore(node),
230
+ },
231
+ ],
122
232
  },
123
233
  ],
124
- // `filter: true` makes fs-list render the Show Deleted toggle and send
125
- // `query` with the fetch; in that mode it also swaps the row's Delete
126
- // action for Restore.
127
- restore: {
128
- query: { state: ReportState.Deleted },
129
- filter: true,
130
- filterLabel: 'Show Deleted',
131
- menuLabel: 'Restore',
132
- reload: true,
133
- click: (report) => this._reportData.undelete(report.id),
134
- },
135
- fetch: (query) => {
136
- return this._reportData.reports(query)
137
- .pipe(map((reports) => ({ data: reports ?? [] })));
138
- },
139
234
  };
140
235
  }
236
+ _isFolderNode(node) {
237
+ return node?.data?.type === ReportNodeType.Folder;
238
+ }
239
+ _isDeletedNode(node) {
240
+ return this.isDeleted(node?.data?.report);
241
+ }
242
+ // Drive the tree's built-in search: it collapses everything, hides every node,
243
+ // then unhides each match and walks its ancestors open, so a report several
244
+ // folders deep surfaces with its path expanded. Clearing does NOT undo that
245
+ // initial collapse, so the tree is re-opened here — otherwise the listing is
246
+ // left fully collapsed the moment somebody empties the search box.
247
+ _search(keyword) {
248
+ const tree = this._tree();
249
+ if (!tree) {
250
+ return;
251
+ }
252
+ if (keyword) {
253
+ tree.search(keyword);
254
+ return;
255
+ }
256
+ tree.clearSearch();
257
+ tree.expandAll();
258
+ }
259
+ _load() {
260
+ this._reportData.tree(this._query)
261
+ .pipe(takeUntilDestroyed(this._destroyRef))
262
+ .subscribe((tree) => {
263
+ const nodes = this._buildNodes(tree);
264
+ this.nodes.set(nodes);
265
+ // The tree reads `config` once, in its own ngOnInit. The first load
266
+ // lands before it exists, so the data has to arrive through the config;
267
+ // every later one has to go through the instance or nothing changes.
268
+ this.treeConfig = { ...this.treeConfig, data: nodes };
269
+ this._tree()?.setData(nodes);
270
+ });
271
+ }
272
+ // Flat API rows → the nested shape fs-tree renders. Folders come before
273
+ // reports at every level, each already name-ordered by the backend.
274
+ _buildNodes(tree) {
275
+ const folders = tree?.folders ?? [];
276
+ const reports = tree?.reports ?? [];
277
+ const build = (parentId) => {
278
+ const folderNodes = folders
279
+ .filter((folder) => (folder.parentReportFolderId ?? null) === parentId)
280
+ .map((folder) => ({
281
+ key: `f:${folder.id}`,
282
+ id: folder.id,
283
+ name: folder.name,
284
+ type: ReportNodeType.Folder,
285
+ children: build(folder.id),
286
+ }));
287
+ const reportNodes = reports
288
+ .filter((report) => (report.reportFolderId ?? null) === parentId)
289
+ .map((report) => ({
290
+ key: `r:${report.id}`,
291
+ id: report.id,
292
+ name: report.name,
293
+ type: ReportNodeType.Report,
294
+ children: [],
295
+ report,
296
+ }));
297
+ return [...folderNodes, ...reportNodes];
298
+ };
299
+ return build(null);
300
+ }
301
+ // A drop moved a node under a new parent, or out to the root. The tree has
302
+ // already moved it on screen, so both outcomes reload: a success to pick up
303
+ // the server's ordering, a failure to put the row back where it really is.
304
+ _move(event) {
305
+ const node = event.node?.data;
306
+ if (!node) {
307
+ return;
308
+ }
309
+ const parentReportFolderId = event.toParent?.data?.id ?? null;
310
+ if (event.toParent && !event.toParent.isExpanded()) {
311
+ event.toParent.expand();
312
+ }
313
+ const save$ = node.type === ReportNodeType.Folder
314
+ ? this._reportData.updateFolder(node.id, { parentReportFolderId })
315
+ : this._reportData.moveReport(node.id, parentReportFolderId);
316
+ save$
317
+ .pipe(takeUntilDestroyed(this._destroyRef))
318
+ .subscribe({
319
+ next: () => {
320
+ this._message.success('Saved changes');
321
+ this._load();
322
+ },
323
+ error: () => this._load(),
324
+ });
325
+ }
326
+ _createFolder(parentReportFolderId) {
327
+ this._prompt.input({
328
+ title: 'New Folder',
329
+ label: 'Name',
330
+ commitLabel: 'Create',
331
+ required: true,
332
+ })
333
+ .pipe(switchMap((name) => this._reportData.createFolder(name, parentReportFolderId)), takeUntilDestroyed(this._destroyRef))
334
+ .subscribe(() => {
335
+ this._message.success('Created folder');
336
+ this._load();
337
+ });
338
+ }
339
+ _rename(node) {
340
+ const data = node?.data;
341
+ if (!data) {
342
+ return;
343
+ }
344
+ const folder = data.type === ReportNodeType.Folder;
345
+ this._prompt.input({
346
+ title: folder ? 'Rename Folder' : 'Rename Report',
347
+ label: 'Name',
348
+ default: data.name,
349
+ commitLabel: 'Save',
350
+ required: true,
351
+ })
352
+ .pipe(switchMap((name) => (folder
353
+ ? this._reportData.updateFolder(data.id, { name })
354
+ : this._reportData.rename(data.id, name))), takeUntilDestroyed(this._destroyRef))
355
+ .subscribe(() => {
356
+ this._message.success('Saved changes');
357
+ this._load();
358
+ });
359
+ }
360
+ // Deleting a folder is refused server-side while it still holds a sub-folder
361
+ // or an active report, and the message says which — so the confirm here warns
362
+ // that a folder delete is permanent rather than trying to restate the rule.
363
+ _delete(node) {
364
+ const data = node?.data;
365
+ if (!data) {
366
+ return;
367
+ }
368
+ const folder = data.type === ReportNodeType.Folder;
369
+ this._prompt.confirm({
370
+ title: 'Confirm',
371
+ template: folder
372
+ ? `Are you sure you would like to delete the folder "${data.name}"? This cannot be undone.`
373
+ : 'Are you sure you would like to delete this report?',
374
+ })
375
+ .pipe(switchMap(() => (folder
376
+ ? this._reportData.deleteFolder(data.id)
377
+ : this._reportData.delete(data.id))), takeUntilDestroyed(this._destroyRef))
378
+ .subscribe(() => {
379
+ this._message.success(folder ? 'Deleted folder' : 'Deleted report');
380
+ this._load();
381
+ });
382
+ }
383
+ _restore(node) {
384
+ const data = node?.data;
385
+ if (!data) {
386
+ return;
387
+ }
388
+ this._reportData.undelete(data.id)
389
+ .pipe(takeUntilDestroyed(this._destroyRef))
390
+ .subscribe(() => {
391
+ this._message.success('Restored report');
392
+ this._load();
393
+ });
394
+ }
395
+ // Turn a ':id' pattern into router commands. Relative unless it starts
396
+ // with '/', in which case the first segment carries the leading slash.
397
+ _patternCommands(pattern, id) {
398
+ const absolute = pattern.startsWith('/');
399
+ const segments = pattern.split('/')
400
+ .filter((segment) => segment.length > 0)
401
+ .map((segment) => (segment === ':id' ? id : segment));
402
+ if (!segments.length) {
403
+ return [id];
404
+ }
405
+ if (absolute) {
406
+ segments[0] = `/${segments[0]}`;
407
+ }
408
+ return segments;
409
+ }
141
410
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FsAiReportsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
142
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FsAiReportsComponent, isStandalone: true, selector: "fs-ai-reports", inputs: { basePath: { classPropertyName: "basePath", publicName: "basePath", isSignal: true, isRequired: false, transformFunction: null }, openPattern: { classPropertyName: "openPattern", publicName: "openPattern", isSignal: true, isRequired: false, transformFunction: null }, createPattern: { classPropertyName: "createPattern", publicName: "createPattern", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "list", first: true, predicate: FsListComponent, descendants: true }], ngImport: i0, template: "<fs-list\n [config]=\"listConfig\"\n #list>\n\n <fs-list-column title=\"Name\">\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <!-- A deleted report can't be opened (the backend only assembles active\n ones), so in Show Deleted mode the name is plain text \u2014 restore it\n from the row menu first. -->\n @if (row.state === deletedState) {\n {{ row.name }}\n } @else {\n <a [routerLink]=\"openLink(row)\">{{ row.name }}</a>\n }\n </ng-template>\n </fs-list-column>\n\n <fs-list-column title=\"Modified\">\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <fs-date [date]=\"row.modifyDate\"></fs-date>\n </ng-template>\n </fs-list-column>\n\n</fs-list>\n", styles: ["a{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: FsDateModule }, { kind: "component", type: i1.FsDateComponent, selector: "fs-date", inputs: ["date", "format", "timezone"] }, { kind: "ngmodule", type: FsListModule }, { kind: "component", type: i2.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines", "cellRowType"], outputs: ["filtersReady"] }, { kind: "directive", type: i2.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i2.FsListCellDirective, selector: "[fs-list-cell],[fsListCell]", inputs: ["colspan", "align", "class", "fsListCell", "configTyping"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
411
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FsAiReportsComponent, isStandalone: true, selector: "fs-ai-reports", inputs: { basePath: { classPropertyName: "basePath", publicName: "basePath", isSignal: true, isRequired: false, transformFunction: null }, openPattern: { classPropertyName: "openPattern", publicName: "openPattern", isSignal: true, isRequired: false, transformFunction: null }, createPattern: { classPropertyName: "createPattern", publicName: "createPattern", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "_tree", first: true, predicate: FsTreeComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<fs-filter [config]=\"filterConfig\"></fs-filter>\n\n<ng-container *fsSkeleton=\"nodes()\">\n <fs-tree [config]=\"treeConfig\">\n <ng-template\n fsTreeNode\n let-data=\"data\">\n <div class=\"fs-row.gap-sm.align-center node-row\">\n <mat-icon class=\"node-icon\">\n {{ data.type === nodeType.Folder ? 'folder' : 'insert_chart_outlined' }}\n </mat-icon>\n\n @if (data.type === nodeType.Folder) {\n <span class=\"node-name\">{{ data.name }}</span>\n } @else if (isDeleted(data.report)) {\n <!-- A deleted report can't be opened (the backend only assembles\n active ones), so in Show Deleted mode the name is plain text \u2014\n restore it from the row menu first. -->\n <span class=\"node-name\">{{ data.name }}</span>\n } @else {\n <a\n class=\"node-name\"\n [routerLink]=\"openLink(data.report)\">\n {{ data.name }}\n </a>\n }\n </div>\n </ng-template>\n </fs-tree>\n\n @if (!nodes().length) {\n <p class=\"small tree-empty\">\n No reports yet. Create one, or add a folder to group them.\n </p>\n }\n</ng-container>\n", styles: ["a{cursor:pointer}fs-tree .node>.container{flex:1;min-width:0}fs-tree .node>.container>.content{min-width:0}fs-tree .node>.container>button{margin-top:-5px}.node-row{min-width:0}.node-icon{font-size:18px;width:18px;height:18px;flex:none}.node-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-empty{margin-top:10px}\n"], dependencies: [{ kind: "ngmodule", type: FsFilterModule }, { kind: "component", type: i1.FilterComponent, selector: "fs-filter", inputs: ["config"], outputs: ["closed", "opened", "ready"] }, { kind: "ngmodule", type: FsSkeletonModule }, { kind: "directive", type: i2.FsSkeletonContentDirective, selector: "[fsSkeleton]", inputs: ["fsSkeleton", "fsSkeletonPattern"] }, { kind: "ngmodule", type: FsTreeModule }, { kind: "component", type: i3.FsTreeComponent, selector: "fs-tree", inputs: ["config"] }, { kind: "directive", type: i3.FsTreeNodeDirective, selector: "[fsTreeNode]", inputs: ["class"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
143
412
  }
144
413
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FsAiReportsComponent, decorators: [{
145
414
  type: Component,
146
415
  args: [{ selector: 'fs-ai-reports', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
147
- FsDateModule,
148
- FsListModule,
416
+ FsFilterModule,
417
+ FsSkeletonModule,
418
+ FsTreeModule,
419
+ MatIconModule,
149
420
  RouterLink,
150
- ], template: "<fs-list\n [config]=\"listConfig\"\n #list>\n\n <fs-list-column title=\"Name\">\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <!-- A deleted report can't be opened (the backend only assembles active\n ones), so in Show Deleted mode the name is plain text \u2014 restore it\n from the row menu first. -->\n @if (row.state === deletedState) {\n {{ row.name }}\n } @else {\n <a [routerLink]=\"openLink(row)\">{{ row.name }}</a>\n }\n </ng-template>\n </fs-list-column>\n\n <fs-list-column title=\"Modified\">\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <fs-date [date]=\"row.modifyDate\"></fs-date>\n </ng-template>\n </fs-list-column>\n\n</fs-list>\n", styles: ["a{cursor:pointer}\n"] }]
151
- }], ctorParameters: () => [], propDecorators: { list: [{
152
- type: ViewChild,
153
- args: [FsListComponent]
154
- }] } });
155
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMtYWktcmVwb3J0cy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL3JlcG9ydHMvdmlld3MvcmVwb3J0cy9mcy1haS1yZXBvcnRzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy92aWV3cy9yZXBvcnRzL2ZzLWFpLXJlcG9ydHMuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pILE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXJFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUVyRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGVBQWUsRUFBZ0IsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDL0UsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTlDLE9BQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFaEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3BELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHlEQUF5RCxDQUFDO0FBQ2xHLE9BQU8sRUFBa0IsV0FBVyxFQUFFLE1BQU0sbUNBQW1DLENBQUM7Ozs7QUFHaEYsK0VBQStFO0FBQy9FLDJFQUEyRTtBQUMzRSwyRUFBMkU7QUFDM0UsMEVBQTBFO0FBQzFFLDJFQUEy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QURWLFNBQVM7dUJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIERlc3Ryb3lSZWYsIFZpZXdDaGlsZCwgZWZmZWN0LCBpbmplY3QsIGlucHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSwgUm91dGVyLCBSb3V0ZXJMaW5rIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcblxuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcblxuaW1wb3J0IHsgRnNEYXRlTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvZGF0ZSc7XG5pbXBvcnQgeyBGc0xpc3RDb21wb25lbnQsIEZzTGlzdENvbmZpZywgRnNMaXN0TW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbGlzdCc7XG5pbXBvcnQgeyBGc1Byb21wdCB9IGZyb20gJ0BmaXJlc3RpdGNoL3Byb21wdCc7XG5cbmltcG9ydCB7IG1hcCwgc3dpdGNoTWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQgeyBHbG9iYWxTZXR0aW5nc0NvbXBvbmVudCB9IGZyb20gJy4uLy4uL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2dsb2JhbC1zZXR0aW5ncy5jb21wb25lbnQnO1xuaW1wb3J0IHsgUmVwb3J0TGlzdEl0ZW0sIFJlcG9ydFN0YXRlIH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9yZXBvcnQuaW50ZXJmYWNlJztcblxuXG4vLyBUaGUgcmVwb3J0cyBsaXN0aW5nIOKAlCBhbiBmcy1saXN0IG9mIHJlcG9ydHMuIFJvd3MgYXJlIGxpbmtzIGJ1aWx0IGZyb20gYSBVUkxcbi8vIHBhdHRlcm4gKGEgJzppZCcgdG9rZW4g4oaSIHRoZSByZXBvcnQgaWQ7IGEgbGVhZGluZyAnLycgbWFrZXMgaXQgYWJzb2x1dGUsXG4vLyBvdGhlcndpc2UgaXQncyByZWxhdGl2ZSB0byB0aGlzIGNvbXBvbmVudCdzIHJvdXRlKS4gQ3JlYXRlIHByb21wdHMgZm9yIGFcbi8vIHRpdGxlLCBjcmVhdGVzIHRoZSByZXBvcnQsIHRoZW4gcm91dGVzIHRvIGl0LiBUaGUgaGVhZGVyIGdlYXIgb3BlbnMgdGhlXG4vLyBnbG9iYWwgUmVwb3J0IFNldHRpbmdzIGRpYWxvZyAoQUkga25vd2xlZGdlIGRvY3VtZW50ICsgc2VtYW50aWMtZGF0YWJhc2Vcbi8vIGJ1aWxkKSwgd2hpY2ggbGl2ZXMgaW4gdGhpcyBwYWNrYWdlLiBObyByb3V0aW5nIGlzIGhhcmQtY29kZWQgaGVyZS5cbi8vXG4vLyBSZXBvcnRzIGFyZSBzb2Z0LWRlbGV0YWJsZTogdGhlIHJvdyBrZWJhYiBkZWxldGVzLCBcIlNob3cgRGVsZXRlZFwiIGZsaXBzIHRoZVxuLy8gbGlzdCBpbnRvIGRlbGV0ZWQgbW9kZSAodGhlIGJhY2tlbmQgaGlkZXMgZGVsZXRlZCByZXBvcnRzIG90aGVyd2lzZSksIGFuZCBpblxuLy8gdGhhdCBtb2RlIGZzLWxpc3Qgc3dhcHMgRGVsZXRlIGZvciBSZXN0b3JlLCB3aGljaCBjYWxscyB0aGUgdW5kZWxldGUgYWN0aW9uXG4vLyBlbmRwb2ludC5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2ZzLWFpLXJlcG9ydHMnLFxuICB0ZW1wbGF0ZVVybDogJy4vZnMtYWktcmVwb3J0cy5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2ZzLWFpLXJlcG9ydHMuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBGc0RhdGVNb2R1bGUsXG4gICAgRnNMaXN0TW9kdWxlLFxuICAgIFJvdXRlckxpbmssXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIEZzQWlSZXBvcnRzQ29tcG9uZW50IHtcblxuICAvLyBBUEkgYmFzZSBmb3IgdGhlIHJlcG9ydHMgZW5kcG9pbnRzOyBvdmVycmlkZSB0byBtb3VudCBlbHNld2hlcmUuXG4gIHB1YmxpYyByZWFkb25seSBiYXNlUGF0aCA9IGlucHV0PHN0cmluZz4oJ3JlcG9ydHMnKTtcblxuICAvLyBXaGVyZSBhIHJvdyBsaW5rcyB0bzsgJzppZCcgaXMgcmVwbGFjZWQgd2l0aCB0aGUgcmVwb3J0IGlkLiBEZWZhdWx0IHRha2VzXG4gIC8vIHlvdSB0byA8Y3VycmVudCByb3V0ZT4vOmlkLiBBYnNvbHV0ZSB3aGVuIGl0IHN0YXJ0cyB3aXRoICcvJy5cbiAgcHVibGljIHJlYWRvbmx5IG9wZW5QYXR0ZXJuID0gaW5wdXQ8c3RyaW5nPignOmlkJyk7XG5cbiAgLy8gV2hlcmUgYSBmcmVzaGx5LWNyZWF0ZWQgcmVwb3J0IHJvdXRlcyB0bzsgc2FtZSAnOmlkJyBwYXR0ZXJuIHJ1bGVzLlxuICBwdWJsaWMgcmVhZG9ubHkgY3JlYXRlUGF0dGVybiA9IGlucHV0PHN0cmluZz4oJzppZCcpO1xuXG4gIEBWaWV3Q2hpbGQoRnNMaXN0Q29tcG9uZW50KVxuICBwdWJsaWMgbGlzdDogRnNMaXN0Q29tcG9uZW50ID0gbnVsbDtcblxuICBwdWJsaWMgbGlzdENvbmZpZzogRnNMaXN0Q29uZmlnPFJlcG9ydExpc3RJdGVtPjtcblxuICAvLyBUZW1wbGF0ZS1zaWRlIGhhbmRsZSBvbiB0aGUgZW51bSwgc28gdGhlIG5hbWUgY2VsbCBjYW4gdGVsbCBhIGRlbGV0ZWQgcm93XG4gIC8vIChzaG93biBpbiBTaG93IERlbGV0ZWQgbW9kZSkgZnJvbSBhIGxpdmUgb25lLlxuICBwdWJsaWMgcmVhZG9ubHkgZGVsZXRlZFN0YXRlID0gUmVwb3J0U3RhdGUuRGVsZXRlZDtcblxuICBwcml2YXRlIF9yZXBvcnREYXRhID0gaW5qZWN0KFJlcG9ydERhdGEpO1xuICBwcml2YXRlIF9yb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcbiAgcHJpdmF0ZSBfcm91dGUgPSBpbmplY3QoQWN0aXZhdGVkUm91dGUpO1xuICBwcml2YXRlIF9wcm9tcHQgPSBpbmplY3QoRnNQcm9tcHQpO1xuICBwcml2YXRlIF9kaWFsb2cgPSBpbmplY3QoTWF0RGlhbG9nKTtcbiAgcHJpdmF0ZSBfZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBlZmZlY3QoKCkgPT4ge1xuICAgICAgdGhpcy5fcmVwb3J0RGF0YS5iYXNlUGF0aCA9IHRoaXMuYmFzZVBhdGgoKTtcbiAgICB9KTtcblxuICAgIHRoaXMuX2luaXRMaXN0Q29uZmlnKCk7XG4gIH1cblxuICAvLyByb3V0ZXJMaW5rIGNvbW1hbmRzIGZvciBhIHJlcG9ydCByb3cgKGJ1aWx0IGZyb20gb3BlblBhdHRlcm4pLlxuICBwdWJsaWMgb3BlbkxpbmsocmVwb3J0OiBSZXBvcnRMaXN0SXRlbSk6IHVua25vd25bXSB7XG4gICAgcmV0dXJuIHRoaXMuX3BhdHRlcm5Db21tYW5kcyh0aGlzLm9wZW5QYXR0ZXJuKCksIHJlcG9ydC5pZCk7XG4gIH1cblxuICAvLyBQcm9tcHQgZm9yIGEgdGl0bGUsIGNyZWF0ZSB0aGUgcmVwb3J0LCB0aGVuIHJvdXRlIHRvIGl0IChjcmVhdGVQYXR0ZXJuKS5cbiAgcHVibGljIGNyZWF0ZVJlcG9ydCgpOiB2b2lkIHtcbiAgICB0aGlzLl9wcm9tcHQuaW5wdXQoe1xuICAgICAgdGl0bGU6ICdDcmVhdGUgUmVwb3J0JyxcbiAgICAgIGxhYmVsOiAnVGl0bGUnLFxuICAgICAgY29tbWl0TGFiZWw6ICdDcmVhdGUnLFxuICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgfSlcbiAgICAgIC5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoKG5hbWU6IHN0cmluZykgPT4gdGhpcy5fcmVwb3J0RGF0YS5jcmVhdGUobmFtZSkpLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKChyZXBvcnQ6IFJlcG9ydExpc3RJdGVtKSA9PiB7XG4gICAgICAgIGNvbnN0IHBhdHRlcm4gPSB0aGlzLmNyZWF0ZVBhdHRlcm4oKTtcbiAgICAgICAgdGhpcy5fcm91dGVyLm5hdmlnYXRlKFxuICAgICAgICAgIHRoaXMuX3BhdHRlcm5Db21tYW5kcyhwYXR0ZXJuLCByZXBvcnQuaWQpLFxuICAgICAgICAgIHBhdHRlcm4uc3RhcnRzV2l0aCgnLycpID8ge30gOiB7IHJlbGF0aXZlVG86IHRoaXMuX3JvdXRlIH0sXG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIFR1cm4gYSAnOmlkJyBwYXR0ZXJuIGludG8gcm91dGVyIGNvbW1hbmRzLiBSZWxhdGl2ZSB1bmxlc3MgaXQgc3RhcnRzXG4gIC8vIHdpdGggJy8nLCBpbiB3aGljaCBjYXNlIHRoZSBmaXJzdCBzZWdtZW50IGNhcnJpZXMgdGhlIGxlYWRpbmcgc2xhc2guXG4gIHByaXZhdGUgX3BhdHRlcm5Db21tYW5kcyhwYXR0ZXJuOiBzdHJpbmcsIGlkOiBudW1iZXIpOiB1bmtub3duW10ge1xuICAgIGNvbnN0IGFic29sdXRlID0gcGF0dGVybi5zdGFydHNXaXRoKCcvJyk7XG4gICAgY29uc3Qgc2VnbWVudHM6IHVua25vd25bXSA9IHBhdHRlcm4uc3BsaXQoJy8nKVxuICAgICAgLmZpbHRlcigoc2VnbWVudCkgPT4gc2VnbWVudC5sZW5ndGggPiAwKVxuICAgICAgLm1hcCgoc2VnbWVudCkgPT4gKHNlZ21lbnQgPT09ICc6aWQnID8gaWQgOiBzZWdtZW50KSk7XG5cbiAgICBpZiAoIXNlZ21lbnRzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIFtpZF07XG4gICAgfVxuXG4gICAgaWYgKGFic29sdXRlKSB7XG4gICAgICBzZWdtZW50c1swXSA9IGAvJHtzZWdtZW50c1swXX1gO1xuICAgIH1cblxuICAgIHJldHVybiBzZWdtZW50cztcbiAgfVxuXG4gIC8vIFRoZSBnbG9iYWwgUmVwb3J0IFNldHRpbmdzIGRpYWxvZzogdGhlIEFJIGtub3dsZWRnZSBkb2N1bWVudCBhbmQgdGhlXG4gIC8vIHNlbWFudGljLWRhdGFiYXNlIGJ1aWxkLiBBIHJ1bm5pbmcgYnVpbGQgc3RyZWFtcyBpbnRvIHRoZSBGc1Byb2Nlc3MgZG9jayxcbiAgLy8gd2hpY2ggc3Vydml2ZXMgdGhlIGRpYWxvZyBjbG9zaW5nLlxuICBwdWJsaWMgb3BlblNldHRpbmdzKCk6IHZvaWQge1xuICAgIHRoaXMuX2RpYWxvZy5vcGVuKEdsb2JhbFNldHRpbmdzQ29tcG9uZW50LCB7XG4gICAgICB3aWR0aDogJzkwMHB4JyxcbiAgICAgIG1heFdpZHRoOiAnOTV2dycsXG4gICAgICBtYXhIZWlnaHQ6ICc5MHZoJyxcbiAgICAgIGF1dG9Gb2N1czogZmFsc2UsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9pbml0TGlzdENvbmZpZygpOiB2b2lkIHtcbiAgICB0aGlzLmxpc3RDb25maWcgPSB7XG4gICAgICAvLyBUaGUgYmFja2VuZCBsaXN0IGlzIG5vdCBwYWdlZCB5ZXQ7IHNob3cgdGhlIGZ1bGwgc2V0IHVudGlsIGl0IGlzLlxuICAgICAgcGFnaW5nOiBmYWxzZSxcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIC8vIEljb24tb25seTogdGhlIGdsb2JhbCBSZXBvcnQgU2V0dGluZ3MgZGlhbG9nLlxuICAgICAgICAgIGljb246ICdzZXR0aW5ncycsXG4gICAgICAgICAgdG9vbHRpcDogJ1JlcG9ydCBzZXR0aW5ncycsXG4gICAgICAgICAgcHJpbWFyeTogZmFsc2UsXG4gICAgICAgICAgY2xpY2s6ICgpID0+IHRoaXMub3BlblNldHRpbmdzKCksXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBsYWJlbDogJ0NyZWF0ZScsXG4gICAgICAgICAgcHJpbWFyeTogdHJ1ZSxcbiAgICAgICAgICBjbGljazogKCkgPT4gdGhpcy5jcmVhdGVSZXBvcnQoKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICByb3dBY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBjbGljazogKHJlcG9ydCkgPT4gdGhpcy5fcmVwb3J0RGF0YS5kZWxldGUocmVwb3J0LmlkKSxcbiAgICAgICAgICByZW1vdmU6IHtcbiAgICAgICAgICAgIHRpdGxlOiAnQ29uZmlybScsXG4gICAgICAgICAgICB0ZW1wbGF0ZTogJ0FyZSB5b3Ugc3VyZSB5b3Ugd291bGQgbGlrZSB0byBkZWxldGUgdGhpcyByZXBvcnQ/JyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIG1lbnU6IHRydWUsXG4gICAgICAgICAgbGFiZWw6ICdEZWxldGUnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIC8vIGBmaWx0ZXI6IHRydWVgIG1ha2VzIGZzLWxpc3QgcmVuZGVyIHRoZSBTaG93IERlbGV0ZWQgdG9nZ2xlIGFuZCBzZW5kXG4gICAgICAvLyBgcXVlcnlgIHdpdGggdGhlIGZldGNoOyBpbiB0aGF0IG1vZGUgaXQgYWxzbyBzd2FwcyB0aGUgcm93J3MgRGVsZXRlXG4gICAgICAvLyBhY3Rpb24gZm9yIFJlc3RvcmUuXG4gICAgICByZXN0b3JlOiB7XG4gICAgICAgIHF1ZXJ5OiB7IHN0YXRlOiBSZXBvcnRTdGF0ZS5EZWxldGVkIH0sXG4gICAgICAgIGZpbHRlcjogdHJ1ZSxcbiAgICAgICAgZmlsdGVyTGFiZWw6ICdTaG93IERlbGV0ZWQnLFxuICAgICAgICBtZW51TGFiZWw6ICdSZXN0b3JlJyxcbiAgICAgICAgcmVsb2FkOiB0cnVlLFxuICAgICAgICBjbGljazogKHJlcG9ydCkgPT4gdGhpcy5fcmVwb3J0RGF0YS51bmRlbGV0ZShyZXBvcnQuaWQpLFxuICAgICAgfSxcbiAgICAgIGZldGNoOiAocXVlcnkpID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3JlcG9ydERhdGEucmVwb3J0cyhxdWVyeSlcbiAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgIG1hcCgocmVwb3J0czogUmVwb3J0TGlzdEl0ZW1bXSkgPT4gKHsgZGF0YTogcmVwb3J0cyA/PyBbXSB9KSksXG4gICAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxufVxuIiwiPGZzLWxpc3RcbiAgICBbY29uZmlnXT1cImxpc3RDb25maWdcIlxuICAgICNsaXN0PlxuXG4gIDxmcy1saXN0LWNvbHVtbiB0aXRsZT1cIk5hbWVcIj5cbiAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgZnMtbGlzdC1jZWxsXG4gICAgICAgIGxldC1yb3c9XCJyb3dcIj5cbiAgICAgIDwhLS0gQSBkZWxldGVkIHJlcG9ydCBjYW4ndCBiZSBvcGVuZWQgKHRoZSBiYWNrZW5kIG9ubHkgYXNzZW1ibGVzIGFjdGl2ZVxuICAgICAgICAgICBvbmVzKSwgc28gaW4gU2hvdyBEZWxldGVkIG1vZGUgdGhlIG5hbWUgaXMgcGxhaW4gdGV4dCDigJQgcmVzdG9yZSBpdFxuICAgICAgICAgICBmcm9tIHRoZSByb3cgbWVudSBmaXJzdC4gLS0+XG4gICAgICBAaWYgKHJvdy5zdGF0ZSA9PT0gZGVsZXRlZFN0YXRlKSB7XG4gICAgICAgIHt7IHJvdy5uYW1lIH19XG4gICAgICB9IEBlbHNlIHtcbiAgICAgICAgPGEgW3JvdXRlckxpbmtdPVwib3Blbkxpbmsocm93KVwiPnt7IHJvdy5uYW1lIH19PC9hPlxuICAgICAgfVxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvZnMtbGlzdC1jb2x1bW4+XG5cbiAgPGZzLWxpc3QtY29sdW1uIHRpdGxlPVwiTW9kaWZpZWRcIj5cbiAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgZnMtbGlzdC1jZWxsXG4gICAgICAgIGxldC1yb3c9XCJyb3dcIj5cbiAgICAgIDxmcy1kYXRlIFtkYXRlXT1cInJvdy5tb2RpZnlEYXRlXCI+PC9mcy1kYXRlPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvZnMtbGlzdC1jb2x1bW4+XG5cbjwvZnMtbGlzdD5cbiJdfQ==
421
+ ], template: "<fs-filter [config]=\"filterConfig\"></fs-filter>\n\n<ng-container *fsSkeleton=\"nodes()\">\n <fs-tree [config]=\"treeConfig\">\n <ng-template\n fsTreeNode\n let-data=\"data\">\n <div class=\"fs-row.gap-sm.align-center node-row\">\n <mat-icon class=\"node-icon\">\n {{ data.type === nodeType.Folder ? 'folder' : 'insert_chart_outlined' }}\n </mat-icon>\n\n @if (data.type === nodeType.Folder) {\n <span class=\"node-name\">{{ data.name }}</span>\n } @else if (isDeleted(data.report)) {\n <!-- A deleted report can't be opened (the backend only assembles\n active ones), so in Show Deleted mode the name is plain text \u2014\n restore it from the row menu first. -->\n <span class=\"node-name\">{{ data.name }}</span>\n } @else {\n <a\n class=\"node-name\"\n [routerLink]=\"openLink(data.report)\">\n {{ data.name }}\n </a>\n }\n </div>\n </ng-template>\n </fs-tree>\n\n @if (!nodes().length) {\n <p class=\"small tree-empty\">\n No reports yet. Create one, or add a folder to group them.\n </p>\n }\n</ng-container>\n", styles: ["a{cursor:pointer}fs-tree .node>.container{flex:1;min-width:0}fs-tree .node>.container>.content{min-width:0}fs-tree .node>.container>button{margin-top:-5px}.node-row{min-width:0}.node-icon{font-size:18px;width:18px;height:18px;flex:none}.node-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-empty{margin-top:10px}\n"] }]
422
+ }], ctorParameters: () => [] });
423
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMtYWktcmVwb3J0cy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL3JlcG9ydHMvdmlld3MvcmVwb3J0cy9mcy1haS1yZXBvcnRzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy92aWV3cy9yZXBvcnRzL2ZzLWFpLXJlcG9ydHMuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixTQUFTLEVBQ1QsVUFBVSxFQUVWLE1BQU0sRUFDTixNQUFNLEVBQ04sS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDaEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFckUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUV2RCxPQUFPLEVBQWdCLGNBQWMsRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1RSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3hELE9BQU8sRUFFTCxlQUFlLEVBQ2YsWUFBWSxFQUdaLGNBQWMsRUFDZCxZQUFZLEdBQ2IsTUFBTSxrQkFBa0IsQ0FBQztBQUUxQixPQUFPLEVBQWMsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRTdDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSx3QkFBd0Is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QWdCO3dCQUNoQixZQUFZO3dCQUNaLGFBQWE7d0JBQ2IsVUFBVTtxQkFDWCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDb21wb25lbnQsXG4gIERlc3Ryb3lSZWYsXG4gIE9uSW5pdCxcbiAgZWZmZWN0LFxuICBpbmplY3QsXG4gIGlucHV0LFxuICBzaWduYWwsXG4gIHZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSwgUm91dGVyLCBSb3V0ZXJMaW5rIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcblxuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcblxuaW1wb3J0IHsgRmlsdGVyQ29uZmlnLCBGc0ZpbHRlck1vZHVsZSwgSXRlbVR5cGUgfSBmcm9tICdAZmlyZXN0aXRjaC9maWx0ZXInO1xuaW1wb3J0IHsgRnNNZXNzYWdlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbWVzc2FnZSc7XG5pbXBvcnQgeyBGc1Byb21wdCB9IGZyb20gJ0BmaXJlc3RpdGNoL3Byb21wdCc7XG5pbXBvcnQgeyBGc1NrZWxldG9uTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvc2tlbGV0b24nO1xuaW1wb3J0IHtcbiAgRmxhdEl0ZW1Ob2RlLFxuICBGc1RyZWVDb21wb25lbnQsXG4gIEZzVHJlZU1vZHVsZSxcbiAgSVRyZWVDaGFuZ2VSZW9yZGVyLFxuICBJVHJlZUNvbmZpZyxcbiAgVHJlZUFjdGlvblR5cGUsXG4gIFRyZWVEcmFnTW9kZSxcbn0gZnJvbSAnQGZpcmVzdGl0Y2gvdHJlZSc7XG5cbmltcG9ydCB7IE9ic2VydmFibGUsIHN3aXRjaE1hcCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQgeyBHbG9iYWxTZXR0aW5nc0NvbXBvbmVudCB9IGZyb20gJy4uLy4uL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2dsb2JhbC1zZXR0aW5ncy5jb21wb25lbnQnO1xuaW1wb3J0IHtcbiAgUmVwb3J0Rm9sZGVyLFxuICBSZXBvcnRMaXN0SXRlbSxcbiAgUmVwb3J0Tm9kZSxcbiAgUmVwb3J0Tm9kZVR5cGUsXG4gIFJlcG9ydFN0YXRlLFxuICBSZXBvcnRTdGF0ZXMsXG4gIFJlcG9ydFRyZWUsXG59IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5cblxuLy8gVGhlIHJlcG9ydHMgbGlzdGluZyDigJQgYW4gZnMtdHJlZSBvZiBmb2xkZXJzIGFuZCB0aGUgcmVwb3J0cyBmaWxlZCBpbnRvIHRoZW0uXG4vLyBSb3dzIGxpbmsgb3V0IHRocm91Z2ggYSBVUkwgcGF0dGVybiAoYSAnOmlkJyB0b2tlbiDihpIgdGhlIHJlcG9ydCBpZDsgYSBsZWFkaW5nXG4vLyAnLycgbWFrZXMgaXQgYWJzb2x1dGUsIG90aGVyd2lzZSBpdCdzIHJlbGF0aXZlIHRvIHRoaXMgY29tcG9uZW50J3Mgcm91dGUpLlxuLy8gQ3JlYXRlIHByb21wdHMgZm9yIGEgdGl0bGUsIGNyZWF0ZXMgdGhlIHJlcG9ydCwgdGhlbiByb3V0ZXMgdG8gaXQuIFRoZSBnZWFyXG4vLyBvcGVucyB0aGUgZ2xvYmFsIFJlcG9ydCBTZXR0aW5ncyBkaWFsb2cgKEFJIGtub3dsZWRnZSBkb2N1bWVudCArXG4vLyBzZW1hbnRpYy1kYXRhYmFzZSBidWlsZCksIHdoaWNoIGxpdmVzIGluIHRoaXMgcGFja2FnZS4gTm8gcm91dGluZyBpc1xuLy8gaGFyZC1jb2RlZCBoZXJlLlxuLy9cbi8vIEZvbGRlcnMgbmVzdDsgcmVwb3J0cyBhcmUgYWx3YXlzIGxlYXZlcyDigJQgY2FuRHJvcCBlbmZvcmNlcyBpdCBoZXJlLCBhbmQgdGhlXG4vLyBiYWNrZW5kIGVuZm9yY2VzIGl0IHN0cnVjdHVyYWxseSBieSBrZWVwaW5nIHRoZSB0cmVlIGluIGl0cyBvd24gdGFibGUuIEFcbi8vIHJlcG9ydCBpbiBubyBmb2xkZXIgaXMgYSByb290IG5vZGUsIHdoaWNoIGlzIHdoZXJlIGV2ZXJ5IHJlcG9ydCBzYXQgYmVmb3JlXG4vLyBmb2xkZXJzIGV4aXN0ZWQsIHNvIG5vdGhpbmcgaGFkIHRvIGJlIG1pZ3JhdGVkIG9yIGJ1Y2tldGVkIGFzIFwidW5jYXRlZ29yaXplZFwiLlxuLy9cbi8vIFJlcG9ydHMgYXJlIHNvZnQtZGVsZXRhYmxlOiB0aGUgcm93IGtlYmFiIGRlbGV0ZXMsIFwiU2hvdyBEZWxldGVkXCIgZmxpcHMgdGhlXG4vLyBsaXN0aW5nIGludG8gZGVsZXRlZCBtb2RlICh0aGUgYmFja2VuZCBoaWRlcyBkZWxldGVkIHJlcG9ydHMgb3RoZXJ3aXNlKSwgYW5kXG4vLyBpbiB0aGF0IG1vZGUgdGhlIGtlYmFiIG9mZmVycyBSZXN0b3JlIGluc3RlYWQuIEZvbGRlcnMgZG8gTk9UIHRha2UgcGFydCBpblxuLy8gdGhhdCDigJQgYSBmb2xkZXIgaXMgb25seSBkZWxldGFibGUgb25jZSBpdCBpcyBlbXB0eSwgc28gaXQgaGFyZCBkZWxldGVzIGFuZCBoYXNcbi8vIG5vdGhpbmcgdG8gcmVzdG9yZS4gVGhlIHVwc2hvdCBpcyB0aGF0IGRlbGV0ZWQgbW9kZSBrZWVwcyB0aGUgZm9sZGVyIHN0cnVjdHVyZVxuLy8gb24gc2NyZWVuIHdpdGggdGhlIGRlbGV0ZWQgcmVwb3J0cyBzaXR0aW5nIHdoZXJlIHRoZXkgYmVsb25nLCBzbyByZXN0b3Jpbmcgb25lXG4vLyBwdXRzIGl0IGJhY2sgcmF0aGVyIHRoYW4gZHJvcHBpbmcgaXQgYXQgdGhlIHJvb3QuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdmcy1haS1yZXBvcnRzJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2ZzLWFpLXJlcG9ydHMuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9mcy1haS1yZXBvcnRzLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgRnNGaWx0ZXJNb2R1bGUsXG4gICAgRnNTa2VsZXRvbk1vZHVsZSxcbiAgICBGc1RyZWVNb2R1bGUsXG4gICAgTWF0SWNvbk1vZHVsZSxcbiAgICBSb3V0ZXJMaW5rLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBGc0FpUmVwb3J0c0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cbiAgLy8gSG93IGRlZXAgdGhlIHRyZWUgb3BlbnMgb24gbG9hZC4gRm9sZGVycyBhcmUgYXVkaWVuY2UgYnVja2V0cywgbm90IGFcbiAgLy8gZmlsZXN5c3RlbSwgc28gdGhlcmUgaXMgbm90aGluZyB3b3J0aCBoaWRpbmcgYmVoaW5kIGEgY2xvc2VkIGNoZXZyb24uXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgRVhQQU5EX0xFVkVMID0gMTA7XG5cbiAgLy8gQVBJIGJhc2UgZm9yIHRoZSByZXBvcnRzIGVuZHBvaW50czsgb3ZlcnJpZGUgdG8gbW91bnQgZWxzZXdoZXJlLlxuICBwdWJsaWMgcmVhZG9ubHkgYmFzZVBhdGggPSBpbnB1dDxzdHJpbmc+KCdyZXBvcnRzJyk7XG5cbiAgLy8gV2hlcmUgYSByb3cgbGlua3MgdG87ICc6aWQnIGlzIHJlcGxhY2VkIHdpdGggdGhlIHJlcG9ydCBpZC4gRGVmYXVsdCB0YWtlc1xuICAvLyB5b3UgdG8gPGN1cnJlbnQgcm91dGU+LzppZC4gQWJzb2x1dGUgd2hlbiBpdCBzdGFydHMgd2l0aCAnLycuXG4gIHB1YmxpYyByZWFkb25seSBvcGVuUGF0dGVybiA9IGlucHV0PHN0cmluZz4oJzppZCcpO1xuXG4gIC8vIFdoZXJlIGEgZnJlc2hseS1jcmVhdGVkIHJlcG9ydCByb3V0ZXMgdG87IHNhbWUgJzppZCcgcGF0dGVybiBydWxlcy5cbiAgcHVibGljIHJlYWRvbmx5IGNyZWF0ZVBhdHRlcm4gPSBpbnB1dDxzdHJpbmc+KCc6aWQnKTtcblxuICAvLyBOdWxsIHVudGlsIHRoZSBmaXJzdCBsb2FkIHJlc29sdmVzIOKAlCB0aGF0IGlzIHdoYXQgZ2F0ZXMgKmZzU2tlbGV0b24uXG4gIHB1YmxpYyByZWFkb25seSBub2RlcyA9IHNpZ25hbDxSZXBvcnROb2RlW10+KG51bGwpO1xuXG4gIHB1YmxpYyB0cmVlQ29uZmlnOiBJVHJlZUNvbmZpZzxSZXBvcnROb2RlW10+O1xuICBwdWJsaWMgZmlsdGVyQ29uZmlnOiBGaWx0ZXJDb25maWc7XG5cbiAgLy8gVGVtcGxhdGUtc2lkZSBoYW5kbGUgb24gdGhlIGVudW0sIHNvIGEgcm93IGNhbiB0ZWxsIGEgZm9sZGVyIGZyb20gYSByZXBvcnQuXG4gIHB1YmxpYyByZWFkb25seSBub2RlVHlwZSA9IFJlcG9ydE5vZGVUeXBlO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3RyZWUgPSB2aWV3Q2hpbGQoRnNUcmVlQ29tcG9uZW50KTtcblxuICBwcml2YXRlIF9yZXBvcnREYXRhID0gaW5qZWN0KFJlcG9ydERhdGEpO1xuICBwcml2YXRlIF9yb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcbiAgcHJpdmF0ZSBfcm91dGUgPSBpbmplY3QoQWN0aXZhdGVkUm91dGUpO1xuICBwcml2YXRlIF9wcm9tcHQgPSBpbmplY3QoRnNQcm9tcHQpO1xuICBwcml2YXRlIF9tZXNzYWdlID0gaW5qZWN0KEZzTWVzc2FnZSk7XG4gIHByaXZhdGUgX2RpYWxvZyA9IGluamVjdChNYXREaWFsb2cpO1xuICBwcml2YXRlIF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIC8vIFRoZSBmaWx0ZXIgYmFyJ3MgY3VycmVudCBxdWVyeSDigJQgY2FycmllcyBgc3RhdGVgIHdoZW4gU2hvdyBEZWxldGVkIGlzIG9uLlxuICBwcml2YXRlIF9xdWVyeTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBlZmZlY3QoKCkgPT4ge1xuICAgICAgdGhpcy5fcmVwb3J0RGF0YS5iYXNlUGF0aCA9IHRoaXMuYmFzZVBhdGgoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAvLyBTZXQgYmVmb3JlIHRoZSBmaXJzdCBmZXRjaCByYXRoZXIgdGhhbiB3YWl0aW5nIG9uIHRoZSBlZmZlY3QgYWJvdmUsIHdoaWNoXG4gICAgLy8gZG9lcyBub3QgcnVuIHVudGlsIGFmdGVyIHRoZSBpbml0aWFsIGNoYW5nZSBkZXRlY3Rpb24gcGFzcy5cbiAgICB0aGlzLl9yZXBvcnREYXRhLmJhc2VQYXRoID0gdGhpcy5iYXNlUGF0aCgpO1xuXG4gICAgdGhpcy5faW5pdEZpbHRlckNvbmZpZygpO1xuICAgIHRoaXMuX2luaXRUcmVlQ29uZmlnKCk7XG4gICAgdGhpcy5fbG9hZCgpO1xuICB9XG5cbiAgLy8gcm91dGVyTGluayBjb21tYW5kcyBmb3IgYSByZXBvcnQgcm93IChidWlsdCBmcm9tIG9wZW5QYXR0ZXJuKS5cbiAgcHVibGljIG9wZW5MaW5rKHJlcG9ydDogUmVwb3J0TGlzdEl0ZW0pOiB1bmtub3duW10ge1xuICAgIHJldHVybiB0aGlzLl9wYXR0ZXJuQ29tbWFuZHModGhpcy5vcGVuUGF0dGVybigpLCByZXBvcnQuaWQpO1xuICB9XG5cbiAgLy8gQSBkZWxldGVkIHJlcG9ydCBjYW4ndCBiZSBvcGVuZWQg4oCUIHRoZSBiYWNrZW5kIG9ubHkgYXNzZW1ibGVzIGFjdGl2ZSBvbmVzIOKAlFxuICAvLyBzbyBpbiBTaG93IERlbGV0ZWQgbW9kZSBpdHMgbmFtZSByZW5kZXJzIGFzIHBsYWluIHRleHQgcmF0aGVyIHRoYW4gYSBsaW5rLlxuICBwdWJsaWMgaXNEZWxldGVkKHJlcG9ydDogUmVwb3J0TGlzdEl0ZW0pOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVwb3J0Py5zdGF0ZSA9PT0gUmVwb3J0U3RhdGUuRGVsZXRlZDtcbiAgfVxuXG4gIC8vIFByb21wdCBmb3IgYSB0aXRsZSwgY3JlYXRlIHRoZSByZXBvcnQsIHRoZW4gcm91dGUgdG8gaXQgKGNyZWF0ZVBhdHRlcm4pLlxuICBwdWJsaWMgY3JlYXRlUmVwb3J0KCk6IHZvaWQge1xuICAgIHRoaXMuX3Byb21wdC5pbnB1dCh7XG4gICAgICB0aXRsZTogJ0NyZWF0ZSBSZXBvcnQnLFxuICAgICAgbGFiZWw6ICdUaXRsZScsXG4gICAgICBjb21taXRMYWJlbDogJ0NyZWF0ZScsXG4gICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICB9KVxuICAgICAgLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgobmFtZTogc3RyaW5nKSA9PiB0aGlzLl9yZXBvcnREYXRhLmNyZWF0ZShuYW1lKSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKHJlcG9ydDogUmVwb3J0TGlzdEl0ZW0pID0+IHtcbiAgICAgICAgY29uc3QgcGF0dGVybiA9IHRoaXMuY3JlYXRlUGF0dGVybigpO1xuICAgICAgICB0aGlzLl9yb3V0ZXIubmF2aWdhdGUoXG4gICAgICAgICAgdGhpcy5fcGF0dGVybkNvbW1hbmRzKHBhdHRlcm4sIHJlcG9ydC5pZCksXG4gICAgICAgICAgcGF0dGVybi5zdGFydHNXaXRoKCcvJykgPyB7fSA6IHsgcmVsYXRpdmVUbzogdGhpcy5fcm91dGUgfSxcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gVGhlIGdsb2JhbCBSZXBvcnQgU2V0dGluZ3MgZGlhbG9nOiB0aGUgQUkga25vd2xlZGdlIGRvY3VtZW50IGFuZCB0aGVcbiAgLy8gc2VtYW50aWMtZGF0YWJhc2UgYnVpbGQuIEEgcnVubmluZyBidWlsZCBzdHJlYW1zIGludG8gdGhlIEZzUHJvY2VzcyBkb2NrLFxuICAvLyB3aGljaCBzdXJ2aXZlcyB0aGUgZGlhbG9nIGNsb3NpbmcuXG4gIHB1YmxpYyBvcGVuU2V0dGluZ3MoKTogdm9pZCB7XG4gICAgdGhpcy5fZGlhbG9nLm9wZW4oR2xvYmFsU2V0dGluZ3NDb21wb25lbnQsIHtcbiAgICAgIHdpZHRoOiAnOTAwcHgnLFxuICAgICAgbWF4V2lkdGg6ICc5NXZ3JyxcbiAgICAgIG1heEhlaWdodDogJzkwdmgnLFxuICAgICAgYXV0b0ZvY3VzOiBmYWxzZSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2luaXRGaWx0ZXJDb25maWcoKTogdm9pZCB7XG4gICAgdGhpcy5maWx0ZXJDb25maWcgPSB7XG4gICAgICBpdGVtczogW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogJ2tleXdvcmQnLFxuICAgICAgICAgIHR5cGU6IEl0ZW1UeXBlLktleXdvcmQsXG4gICAgICAgICAgbGFiZWw6ICdTZWFyY2gnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogJ3N0YXRlJyxcbiAgICAgICAgICB0eXBlOiBJdGVtVHlwZS5TZWxlY3QsXG4gICAgICAgICAgbGFiZWw6ICdTdGF0dXMnLFxuICAgICAgICAgIG11bHRpcGxlOiB0cnVlLFxuICAgICAgICAgIHZhbHVlczogKCkgPT4gUmVwb3J0U3RhdGVzLFxuICAgICAgICAgIGlzb2xhdGU6IHsgbGFiZWw6ICdTaG93IERlbGV0ZWQnLCB2YWx1ZTogUmVwb3J0U3RhdGUuRGVsZXRlZCB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGljb246ICd1bmZvbGRfbW9yZScsXG4gICAgICAgICAgdG9vbHRpcDogJ0V4cGFuZCBhbGwnLFxuICAgICAgICAgIHByaW1hcnk6IGZhbHNlLFxuICAgICAgICAgIGNsaWNrOiAoKSA9PiB0aGlzLl90cmVlKCk/LmV4cGFuZEFsbCgpLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgaWNvbjogJ3VuZm9sZF9sZXNzJyxcbiAgICAgICAgICB0b29sdGlwOiAnQ29sbGFwc2UgYWxsJyxcbiAgICAgICAgICBwcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICBjbGljazogKCkgPT4gdGhpcy5fdHJlZSgpPy5jb2xsYXBzZUFsbCgpLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgaWNvbjogJ3NldHRpbmdzJyxcbiAgICAgICAgICB0b29sdGlwOiAnUmVwb3J0IHNldHRpbmdzJyxcbiAgICAgICAgICBwcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICBjbGljazogKCkgPT4gdGhpcy5vcGVuU2V0dGluZ3MoKSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIGxhYmVsOiAnTmV3IEZvbGRlcicsXG4gICAgICAgICAgcHJpbWFyeTogZmFsc2UsXG4gICAgICAgICAgY2xpY2s6ICgpID0+IHRoaXMuX2NyZWF0ZUZvbGRlcihudWxsKSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIGxhYmVsOiAnQ3JlYXRlJyxcbiAgICAgICAgICBwcmltYXJ5OiB0cnVlLFxuICAgICAgICAgIGNsaWNrOiAoKSA9PiB0aGlzLmNyZWF0ZVJlcG9ydCgpLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIC8vIFRoZSB0d28gaXRlbXMgYXJlIGFuc3dlcmVkIGluIGRpZmZlcmVudCBwbGFjZXMgYW5kIGJvdGggaGF2ZSB0byBydW4uXG4gICAgICAvLyBUaGUga2V5d29yZCBkcml2ZXMgdGhlIHRyZWUncyBvd24gc2VhcmNoLCB3aGljaCBpcyB0aGUgd2hvbGUgcG9pbnQgb2ZcbiAgICAgIC8vIHNlYXJjaGluZyBhIHRyZWUg4oCUIGl0IHJldmVhbHMgYSBtYXRjaCBuZXN0ZWQgaW5zaWRlIGNvbGxhcHNlZCBmb2xkZXJzXG4gICAgICAvLyByYXRoZXIgdGhhbiBvbmx5IGZpbHRlcmluZyB3aGF0IGlzIGFscmVhZHkgb24gc2NyZWVuLiBgc3RhdGVgIGlzIHRoZVxuICAgICAgLy8gU2hvdyBEZWxldGVkIHRvZ2dsZSwgYW5kIG9ubHkgdGhlIHNlcnZlciBjYW4gYW5zd2VyIHRoYXQuXG4gICAgICBjaGFuZ2U6IChxdWVyeSkgPT4ge1xuICAgICAgICBjb25zdCBzdGF0ZUNoYW5nZWQgPSBTdHJpbmcocXVlcnk/LnN0YXRlID8/ICcnKSAhPT0gU3RyaW5nKHRoaXMuX3F1ZXJ5LnN0YXRlID8/ICcnKTtcbiAgICAgICAgdGhpcy5fcXVlcnkgPSB7IC4uLnF1ZXJ5IH07XG5cbiAgICAgICAgdGhpcy5fc2VhcmNoKHF1ZXJ5Py5rZXl3b3JkKTtcblxuICAgICAgICBpZiAoc3RhdGVDaGFuZ2VkKSB7XG4gICAgICAgICAgdGhpcy5fbG9hZCgpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIF9pbml0VHJlZUNvbmZpZygpOiB2b2lkIHtcbiAgICB0aGlzLnRyZWVDb25maWcgPSB7XG4gICAgICBkYXRhOiBbXSxcbiAgICAgIGNoaWxkcmVuTmFtZTogJ2NoaWxkcmVuJyxcbiAgICAgIGV4cGFuZExldmVsOiBGc0FpUmVwb3J0c0NvbXBvbmVudC5FWFBBTkRfTEVWRUwsXG4gICAgICBkcmFnZ2FibGU6IHRydWUsXG4gICAgICAvLyBUaGUgd2hvbGUgcm93IGlzIHRoZSBncmlwIGFuZCB0aGUgaGFuZGxlIHN0YXlzIGhpZGRlbjsgYSBwcmVzcyBvbmx5XG4gICAgICAvLyBiZWNvbWVzIGEgZHJhZyBvbmNlIHRoZSBwb2ludGVyIG1vdmVzLCBzbyB0aGUga2ViYWIsIHRoZSBjaGV2cm9uIGFuZCB0aGVcbiAgICAgIC8vIHJlcG9ydCBsaW5rIGFsbCBzdGF5IGNsaWNrYWJsZS5cbiAgICAgIGRyYWdNb2RlOiBUcmVlRHJhZ01vZGUuTm9kZSxcbiAgICAgIC8vIGNhbkRyb3AgaXMgYXNrZWQgYWJvdXQgdGhlIG5vZGUgYmVpbmcgRFJBR0dFRCwgc28gb25seSBgdG9QYXJlbnRgXG4gICAgICAvLyBkZXNjcmliZXMgdGhlIGRlc3RpbmF0aW9uIOKAlCByZWFkaW5nIG5vZGUubGV2ZWwvbm9kZS5wYXJlbnQgaGVyZSB3b3VsZFxuICAgICAgLy8gZGVzY3JpYmUgd2hlcmUgaXQgY2FtZSBmcm9tLiBBIHJlcG9ydCBjYW4gbmV2ZXIgYmUgYSBwYXJlbnQgYmVjYXVzZSBpdHNcbiAgICAgIC8vIHR5cGUgc2F5cyBzbywgYW5kIHRoYXQgc2luZ2xlIHRlc3QgaXMgdGhlIHdob2xlIFwiZm9sZGVycyBuZXN0LCByZXBvcnRzXG4gICAgICAvLyBhcmUgbGVhdmVzXCIgcnVsZSBvbiB0aGlzIHNpZGUuXG4gICAgICBjYW5Ecm9wOiAobm9kZTogRmxhdEl0ZW1Ob2RlLCBmcm9tUGFyZW50OiBGbGF0SXRlbU5vZGUsIHRvUGFyZW50OiBGbGF0SXRlbU5vZGUpID0+IHtcbiAgICAgICAgcmV0dXJuICF0b1BhcmVudCB8fCB0b1BhcmVudC5kYXRhPy50eXBlID09PSBSZXBvcnROb2RlVHlwZS5Gb2xkZXI7XG4gICAgICB9LFxuICAgICAgY2hhbmdlUmVvcmRlcjogKGV2ZW50OiBJVHJlZUNoYW5nZVJlb3JkZXIpID0+IHRoaXMuX21vdmUoZXZlbnQpLFxuICAgICAgbm9kZUNsYXNzOiAobm9kZTogRmxhdEl0ZW1Ob2RlKSA9PiBub2RlLmRhdGE/LnR5cGUsXG4gICAgICAvLyBNYXRjaCBvbiB0aGUgbmFtZSBvbmx5LiBUaGUgbGlicmFyeSdzIGRlZmF1bHQgbWF0Y2hlciBzdHJpbmdpZmllcyB0aGVcbiAgICAgIC8vIHdob2xlIG5vZGUsIHNvIGl0IHdvdWxkIGhpdCBpZHMsIHRoZSBsaXRlcmFsIHR5cGUgd29yZCwgYW5kIGV2ZXJ5dGhpbmdcbiAgICAgIC8vIGVsc2UgcmlkaW5nIG9uIHRoZSByb3cuXG4gICAgICBmaWx0ZXJJdGVtOiAobm9kZSwgcXVlcnkpID0+IHtcbiAgICAgICAgcmV0dXJuIFN0cmluZyhub2RlLmRhdGE/Lm5hbWUgPz8gJycpXG4gICAgICAgICAgLnRvTG93ZXJDYXNlKClcbiAgICAgICAgICAuaW5jbHVkZXMoU3RyaW5nKHF1ZXJ5ID8/ICcnKS50b0xvd2VyQ2FzZSgpKTtcbiAgICAgIH0sXG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICB0eXBlOiBUcmVlQWN0aW9uVHlwZS5NZW51LFxuICAgICAgICAgIGljb246ICdtb3JlX3ZlcnQnLFxuICAgICAgICAgIGl0ZW1zOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGxhYmVsOiAnUmVuYW1lJyxcbiAgICAgICAgICAgICAgc2hvdzogKG5vZGU6IEZsYXRJdGVtTm9kZSkgPT4gIXRoaXMuX2lzRGVsZXRlZE5vZGUobm9kZSksXG4gICAgICAgICAgICAgIGNsaWNrOiAobm9kZTogRmxhdEl0ZW1Ob2RlKSA9PiB0aGlzLl9yZW5hbWUobm9kZSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBsYWJlbDogJ05ldyBGb2xkZXIgSW5zaWRlJyxcbiAgICAgICAgICAgICAgc2hvdzogKG5vZGU6IEZsYXRJdGVtTm9kZSkgPT4gdGhpcy5faXNGb2xkZXJOb2RlKG5vZGUpLFxuICAgICAgICAgICAgICBjbGljazogKG5vZGU6IEZsYXRJdGVtTm9kZSkgPT4gdGhpcy5fY3JlYXRlRm9sZGVyKG5vZGUuZGF0YT8uaWQpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbGFiZWw6ICdEZWxldGUnLFxuICAgICAgICAgICAgICBzaG93OiAobm9kZTogRmxhdEl0ZW1Ob2RlKSA9PiAhdGhpcy5faXNEZWxldGVkTm9kZShub2RlKSxcbiAgICAgICAgICAgICAgY2xpY2s6IChub2RlOiBGbGF0SXRlbU5vZGUpID0+IHRoaXMuX2RlbGV0ZShub2RlKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAvLyBGb2xkZXJzIG5ldmVyIHJlYWNoIHRoaXM6IHRoZXkgaGFyZCBkZWxldGUsIHNvIGEgZGVsZXRlZCBmb2xkZXJcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IGV4aXN0IHRvIGJlIHJlc3RvcmVkLlxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBsYWJlbDogJ1Jlc3RvcmUnLFxuICAgICAgICAgICAgICBzaG93OiAobm9kZTogRmxhdEl0ZW1Ob2RlKSA9PiB0aGlzLl9pc0RlbGV0ZWROb2RlKG5vZGUpLFxuICAgICAgICAgICAgICBjbGljazogKG5vZGU6IEZsYXRJdGVtTm9kZSkgPT4gdGhpcy5fcmVzdG9yZShub2RlKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgX2lzRm9sZGVyTm9kZShub2RlOiBGbGF0SXRlbU5vZGUpOiBib29sZWFuIHtcbiAgICByZXR1cm4gbm9kZT8uZGF0YT8udHlwZSA9PT0gUmVwb3J0Tm9kZVR5cGUuRm9sZGVyO1xuICB9XG5cbiAgcHJpdmF0ZSBfaXNEZWxldGVkTm9kZShub2RlOiBGbGF0SXRlbU5vZGUpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0RlbGV0ZWQobm9kZT8uZGF0YT8ucmVwb3J0KTtcbiAgfVxuXG4gIC8vIERyaXZlIHRoZSB0cmVlJ3MgYnVpbHQtaW4gc2VhcmNoOiBpdCBjb2xsYXBzZXMgZXZlcnl0aGluZywgaGlkZXMgZXZlcnkgbm9kZSxcbiAgLy8gdGhlbiB1bmhpZGVzIGVhY2ggbWF0Y2ggYW5kIHdhbGtzIGl0cyBhbmNlc3RvcnMgb3Blbiwgc28gYSByZXBvcnQgc2V2ZXJhbFxuICAvLyBmb2xkZXJzIGRlZXAgc3VyZmFjZXMgd2l0aCBpdHMgcGF0aCBleHBhbmRlZC4gQ2xlYXJpbmcgZG9lcyBOT1QgdW5kbyB0aGF0XG4gIC8vIGluaXRpYWwgY29sbGFwc2UsIHNvIHRoZSB0cmVlIGlzIHJlLW9wZW5lZCBoZXJlIOKAlCBvdGhlcndpc2UgdGhlIGxpc3RpbmcgaXNcbiAgLy8gbGVmdCBmdWxseSBjb2xsYXBzZWQgdGhlIG1vbWVudCBzb21lYm9keSBlbXB0aWVzIHRoZSBzZWFyY2ggYm94LlxuICBwcml2YXRlIF9zZWFyY2goa2V5d29yZDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgdHJlZSA9IHRoaXMuX3RyZWUoKTtcbiAgICBpZiAoIXRyZWUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoa2V5d29yZCkge1xuICAgICAgdHJlZS5zZWFyY2goa2V5d29yZCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJlZS5jbGVhclNlYXJjaCgpO1xuICAgIHRyZWUuZXhwYW5kQWxsKCk7XG4gIH1cblxuICBwcml2YXRlIF9sb2FkKCk6IHZvaWQge1xuICAgIHRoaXMuX3JlcG9ydERhdGEudHJlZSh0aGlzLl9xdWVyeSlcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCh0cmVlOiBSZXBvcnRUcmVlKSA9PiB7XG4gICAgICAgIGNvbnN0IG5vZGVzID0gdGhpcy5fYnVpbGROb2Rlcyh0cmVlKTtcbiAgICAgICAgdGhpcy5ub2Rlcy5zZXQobm9kZXMpO1xuXG4gICAgICAgIC8vIFRoZSB0cmVlIHJlYWRzIGBjb25maWdgIG9uY2UsIGluIGl0cyBvd24gbmdPbkluaXQuIFRoZSBmaXJzdCBsb2FkXG4gICAgICAgIC8vIGxhbmRzIGJlZm9yZSBpdCBleGlzdHMsIHNvIHRoZSBkYXRhIGhhcyB0byBhcnJpdmUgdGhyb3VnaCB0aGUgY29uZmlnO1xuICAgICAgICAvLyBldmVyeSBsYXRlciBvbmUgaGFzIHRvIGdvIHRocm91Z2ggdGhlIGluc3RhbmNlIG9yIG5vdGhpbmcgY2hhbmdlcy5cbiAgICAgICAgdGhpcy50cmVlQ29uZmlnID0geyAuLi50aGlzLnRyZWVDb25maWcsIGRhdGE6IG5vZGVzIH07XG4gICAgICAgIHRoaXMuX3RyZWUoKT8uc2V0RGF0YShub2Rlcyk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIEZsYXQgQVBJIHJvd3Mg4oaSIHRoZSBuZXN0ZWQgc2hhcGUgZnMtdHJlZSByZW5kZXJzLiBGb2xkZXJzIGNvbWUgYmVmb3JlXG4gIC8vIHJlcG9ydHMgYXQgZXZlcnkgbGV2ZWwsIGVhY2ggYWxyZWFkeSBuYW1lLW9yZGVyZWQgYnkgdGhlIGJhY2tlbmQuXG4gIHByaXZhdGUgX2J1aWxkTm9kZXModHJlZTogUmVwb3J0VHJlZSk6IFJlcG9ydE5vZGVbXSB7XG4gICAgY29uc3QgZm9sZGVycyA9IHRyZWU/LmZvbGRlcnMgPz8gW107XG4gICAgY29uc3QgcmVwb3J0cyA9IHRyZWU/LnJlcG9ydHMgPz8gW107XG5cbiAgICBjb25zdCBidWlsZCA9IChwYXJlbnRJZDogbnVtYmVyIHwgbnVsbCk6IFJlcG9ydE5vZGVbXSA9PiB7XG4gICAgICBjb25zdCBmb2xkZXJOb2RlczogUmVwb3J0Tm9kZVtdID0gZm9sZGVyc1xuICAgICAgICAuZmlsdGVyKChmb2xkZXI6IFJlcG9ydEZvbGRlcikgPT4gKGZvbGRlci5wYXJlbnRSZXBvcnRGb2xkZXJJZCA/PyBudWxsKSA9PT0gcGFyZW50SWQpXG4gICAgICAgIC5tYXAoKGZvbGRlcjogUmVwb3J0Rm9sZGVyKSA9PiAoe1xuICAgICAgICAgIGtleTogYGY6JHtmb2xkZXIuaWR9YCxcbiAgICAgICAgICBpZDogZm9sZGVyLmlkLFxuICAgICAgICAgIG5hbWU6IGZvbGRlci5uYW1lLFxuICAgICAgICAgIHR5cGU6IFJlcG9ydE5vZGVUeXBlLkZvbGRlcixcbiAgICAgICAgICBjaGlsZHJlbjogYnVpbGQoZm9sZGVyLmlkKSxcbiAgICAgICAgfSkpO1xuXG4gICAgICBjb25zdCByZXBvcnROb2RlczogUmVwb3J0Tm9kZVtdID0gcmVwb3J0c1xuICAgICAgICAuZmlsdGVyKChyZXBvcnQ6IFJlcG9ydExpc3RJdGVtKSA9PiAocmVwb3J0LnJlcG9ydEZvbGRlcklkID8/IG51bGwpID09PSBwYXJlbnRJZClcbiAgICAgICAgLm1hcCgocmVwb3J0OiBSZXBvcnRMaXN0SXRlbSkgPT4gKHtcbiAgICAgICAgICBrZXk6IGByOiR7cmVwb3J0LmlkfWAsXG4gICAgICAgICAgaWQ6IHJlcG9ydC5pZCxcbiAgICAgICAgICBuYW1lOiByZXBvcnQubmFtZSxcbiAgICAgICAgICB0eXBlOiBSZXBvcnROb2RlVHlwZS5SZXBvcnQsXG4gICAgICAgICAgY2hpbGRyZW46IFtdLFxuICAgICAgICAgIHJlcG9ydCxcbiAgICAgICAgfSkpO1xuXG4gICAgICByZXR1cm4gWy4uLmZvbGRlck5vZGVzLCAuLi5yZXBvcnROb2Rlc107XG4gICAgfTtcblxuICAgIHJldHVybiBidWlsZChudWxsKTtcbiAgfVxuXG4gIC8vIEEgZHJvcCBtb3ZlZCBhIG5vZGUgdW5kZXIgYSBuZXcgcGFyZW50LCBvciBvdXQgdG8gdGhlIHJvb3QuIFRoZSB0cmVlIGhhc1xuICAvLyBhbHJlYWR5IG1vdmVkIGl0IG9uIHNjcmVlbiwgc28gYm90aCBvdXRjb21lcyByZWxvYWQ6IGEgc3VjY2VzcyB0byBwaWNrIHVwXG4gIC8vIHRoZSBzZXJ2ZXIncyBvcmRlcmluZywgYSBmYWlsdXJlIHRvIHB1dCB0aGUgcm93IGJhY2sgd2hlcmUgaXQgcmVhbGx5IGlzLlxuICBwcml2YXRlIF9tb3ZlKGV2ZW50OiBJVHJlZUNoYW5nZVJlb3JkZXIpOiB2b2lkIHtcbiAgICBjb25zdCBub2RlOiBSZXBvcnROb2RlID0gZXZlbnQubm9kZT8uZGF0YTtcbiAgICBpZiAoIW5vZGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwYXJlbnRSZXBvcnRGb2xkZXJJZDogbnVtYmVyID0gZXZlbnQudG9QYXJlbnQ/LmRhdGE/LmlkID8/IG51bGw7XG5cbiAgICBpZiAoZXZlbnQudG9QYXJlbnQgJiYgIWV2ZW50LnRvUGFyZW50LmlzRXhwYW5kZWQoKSkge1xuICAgICAgZXZlbnQudG9QYXJlbnQuZXhwYW5kKCk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2F2ZSQ6IE9ic2VydmFibGU8dW5rbm93bj4gPSBub2RlLnR5cGUgPT09IFJlcG9ydE5vZGVUeXBlLkZvbGRlclxuICAgICAgPyB0aGlzLl9yZXBvcnREYXRhLnVwZGF0ZUZvbGRlcihub2RlLmlkLCB7IHBhcmVudFJlcG9ydEZvbGRlcklkIH0pXG4gICAgICA6IHRoaXMuX3JlcG9ydERhdGEubW92ZVJlcG9ydChub2RlLmlkLCBwYXJlbnRSZXBvcnRGb2xkZXJJZCk7XG5cbiAgICBzYXZlJFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoe1xuICAgICAgICBuZXh0OiAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5fbWVzc2FnZS5zdWNjZXNzKCdTYXZlZCBjaGFuZ2VzJyk7XG4gICAgICAgICAgdGhpcy5fbG9hZCgpO1xuICAgICAgICB9LFxuICAgICAgICBlcnJvcjogKCkgPT4gdGhpcy5fbG9hZCgpLFxuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9jcmVhdGVGb2xkZXIocGFyZW50UmVwb3J0Rm9sZGVySWQ6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuX3Byb21wdC5pbnB1dCh7XG4gICAgICB0aXRsZTogJ05ldyBGb2xkZXInLFxuICAgICAgbGFiZWw6ICdOYW1lJyxcbiAgICAgIGNvbW1pdExhYmVsOiAnQ3JlYXRlJyxcbiAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgIH0pXG4gICAgICAucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKChuYW1lOiBzdHJpbmcpID0+IHRoaXMuX3JlcG9ydERhdGEuY3JlYXRlRm9sZGVyKG5hbWUsIHBhcmVudFJlcG9ydEZvbGRlcklkKSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3MoJ0NyZWF0ZWQgZm9sZGVyJyk7XG4gICAgICAgIHRoaXMuX2xvYWQoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVuYW1lKG5vZGU6IEZsYXRJdGVtTm9kZSk6IHZvaWQge1xuICAgIGNvbnN0IGRhdGE6IFJlcG9ydE5vZGUgPSBub2RlPy5kYXRhO1xuICAgIGlmICghZGF0YSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGZvbGRlciA9IGRhdGEudHlwZSA9PT0gUmVwb3J0Tm9kZVR5cGUuRm9sZGVyO1xuXG4gICAgdGhpcy5fcHJvbXB0LmlucHV0KHtcbiAgICAgIHRpdGxlOiBmb2xkZXIgPyAnUmVuYW1lIEZvbGRlcicgOiAnUmVuYW1lIFJlcG9ydCcsXG4gICAgICBsYWJlbDogJ05hbWUnLFxuICAgICAgZGVmYXVsdDogZGF0YS5uYW1lLFxuICAgICAgY29tbWl0TGFiZWw6ICdTYXZlJyxcbiAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgIH0pXG4gICAgICAucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKChuYW1lOiBzdHJpbmcpID0+IChmb2xkZXJcbiAgICAgICAgICA/IHRoaXMuX3JlcG9ydERhdGEudXBkYXRlRm9sZGVyKGRhdGEuaWQsIHsgbmFtZSB9KVxuICAgICAgICAgIDogdGhpcy5fcmVwb3J0RGF0YS5yZW5hbWUoZGF0YS5pZCwgbmFtZSkpKSxcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuX21lc3NhZ2Uuc3VjY2VzcygnU2F2ZWQgY2hhbmdlcycpO1xuICAgICAgICB0aGlzLl9sb2FkKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIERlbGV0aW5nIGEgZm9sZGVyIGlzIHJlZnVzZWQgc2VydmVyLXNpZGUgd2hpbGUgaXQgc3RpbGwgaG9sZHMgYSBzdWItZm9sZGVyXG4gIC8vIG9yIGFuIGFjdGl2ZSByZXBvcnQsIGFuZCB0aGUgbWVzc2FnZSBzYXlzIHdoaWNoIOKAlCBzbyB0aGUgY29uZmlybSBoZXJlIHdhcm5zXG4gIC8vIHRoYXQgYSBmb2xkZXIgZGVsZXRlIGlzIHBlcm1hbmVudCByYXRoZXIgdGhhbiB0cnlpbmcgdG8gcmVzdGF0ZSB0aGUgcnVsZS5cbiAgcHJpdmF0ZSBfZGVsZXRlKG5vZGU6IEZsYXRJdGVtTm9kZSk6IHZvaWQge1xuICAgIGNvbnN0IGRhdGE6IFJlcG9ydE5vZGUgPSBub2RlPy5kYXRhO1xuICAgIGlmICghZGF0YSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGZvbGRlciA9IGRhdGEudHlwZSA9PT0gUmVwb3J0Tm9kZVR5cGUuRm9sZGVyO1xuXG4gICAgdGhpcy5fcHJvbXB0LmNvbmZpcm0oe1xuICAgICAgdGl0bGU6ICdDb25maXJtJyxcbiAgICAgIHRlbXBsYXRlOiBmb2xkZXJcbiAgICAgICAgPyBgQXJlIHlvdSBzdXJlIHlvdSB3b3VsZCBsaWtlIHRvIGRlbGV0ZSB0aGUgZm9sZGVyIFwiJHtkYXRhLm5hbWV9XCI/IFRoaXMgY2Fubm90IGJlIHVuZG9uZS5gXG4gICAgICAgIDogJ0FyZSB5b3Ugc3VyZSB5b3Ugd291bGQgbGlrZSB0byBkZWxldGUgdGhpcyByZXBvcnQ/JyxcbiAgICB9KVxuICAgICAgLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoKSA9PiAoZm9sZGVyXG4gICAgICAgICAgPyB0aGlzLl9yZXBvcnREYXRhLmRlbGV0ZUZvbGRlcihkYXRhLmlkKVxuICAgICAgICAgIDogdGhpcy5fcmVwb3J0RGF0YS5kZWxldGUoZGF0YS5pZCkpKSxcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuX21lc3NhZ2Uuc3VjY2Vzcyhmb2xkZXIgPyAnRGVsZXRlZCBmb2xkZXInIDogJ0RlbGV0ZWQgcmVwb3J0Jyk7XG4gICAgICAgIHRoaXMuX2xvYWQoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVzdG9yZShub2RlOiBGbGF0SXRlbU5vZGUpOiB2b2lkIHtcbiAgICBjb25zdCBkYXRhOiBSZXBvcnROb2RlID0gbm9kZT8uZGF0YTtcbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl9yZXBvcnREYXRhLnVuZGVsZXRlKGRhdGEuaWQpXG4gICAgICAucGlwZShcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuX21lc3NhZ2Uuc3VjY2VzcygnUmVzdG9yZWQgcmVwb3J0Jyk7XG4gICAgICAgIHRoaXMuX2xvYWQoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gVHVybiBhICc6aWQnIHBhdHRlcm4gaW50byByb3V0ZXIgY29tbWFuZHMuIFJlbGF0aXZlIHVubGVzcyBpdCBzdGFydHNcbiAgLy8gd2l0aCAnLycsIGluIHdoaWNoIGNhc2UgdGhlIGZpcnN0IHNlZ21lbnQgY2FycmllcyB0aGUgbGVhZGluZyBzbGFzaC5cbiAgcHJpdmF0ZSBfcGF0dGVybkNvbW1hbmRzKHBhdHRlcm46IHN0cmluZywgaWQ6IG51bWJlcik6IHVua25vd25bXSB7XG4gICAgY29uc3QgYWJzb2x1dGUgPSBwYXR0ZXJuLnN0YXJ0c1dpdGgoJy8nKTtcbiAgICBjb25zdCBzZWdtZW50czogdW5rbm93bltdID0gcGF0dGVybi5zcGxpdCgnLycpXG4gICAgICAuZmlsdGVyKChzZWdtZW50KSA9PiBzZWdtZW50Lmxlbmd0aCA+IDApXG4gICAgICAubWFwKChzZWdtZW50KSA9PiAoc2VnbWVudCA9PT0gJzppZCcgPyBpZCA6IHNlZ21lbnQpKTtcblxuICAgIGlmICghc2VnbWVudHMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gW2lkXTtcbiAgICB9XG5cbiAgICBpZiAoYWJzb2x1dGUpIHtcbiAgICAgIHNlZ21lbnRzWzBdID0gYC8ke3NlZ21lbnRzWzBdfWA7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlZ21lbnRzO1xuICB9XG59XG4iLCI8ZnMtZmlsdGVyIFtjb25maWddPVwiZmlsdGVyQ29uZmlnXCI+PC9mcy1maWx0ZXI+XG5cbjxuZy1jb250YWluZXIgKmZzU2tlbGV0b249XCJub2RlcygpXCI+XG4gIDxmcy10cmVlIFtjb25maWddPVwidHJlZUNvbmZpZ1wiPlxuICAgIDxuZy10ZW1wbGF0ZVxuICAgICAgICBmc1RyZWVOb2RlXG4gICAgICAgIGxldC1kYXRhPVwiZGF0YVwiPlxuICAgICAgPGRpdiBjbGFzcz1cImZzLXJvdy5nYXAtc20uYWxpZ24tY2VudGVyIG5vZGUtcm93XCI+XG4gICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cIm5vZGUtaWNvblwiPlxuICAgICAgICAgIHt7IGRhdGEudHlwZSA9PT0gbm9kZVR5cGUuRm9sZGVyID8gJ2ZvbGRlcicgOiAnaW5zZXJ0X2NoYXJ0X291dGxpbmVkJyB9fVxuICAgICAgICA8L21hdC1pY29uPlxuXG4gICAgICAgIEBpZiAoZGF0YS50eXBlID09PSBub2RlVHlwZS5Gb2xkZXIpIHtcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5vZGUtbmFtZVwiPnt7IGRhdGEubmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgfSBAZWxzZSBpZiAoaXNEZWxldGVkKGRhdGEucmVwb3J0KSkge1xuICAgICAgICAgIDwhLS0gQSBkZWxldGVkIHJlcG9ydCBjYW4ndCBiZSBvcGVuZWQgKHRoZSBiYWNrZW5kIG9ubHkgYXNzZW1ibGVzXG4gICAgICAgICAgICAgICBhY3RpdmUgb25lcyksIHNvIGluIFNob3cgRGVsZXRlZCBtb2RlIHRoZSBuYW1lIGlzIHBsYWluIHRleHQg4oCUXG4gICAgICAgICAgICAgICByZXN0b3JlIGl0IGZyb20gdGhlIHJvdyBtZW51IGZpcnN0LiAtLT5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5vZGUtbmFtZVwiPnt7IGRhdGEubmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgPGFcbiAgICAgICAgICAgICAgY2xhc3M9XCJub2RlLW5hbWVcIlxuICAgICAgICAgICAgICBbcm91dGVyTGlua109XCJvcGVuTGluayhkYXRhLnJlcG9ydClcIj5cbiAgICAgICAgICAgIHt7IGRhdGEubmFtZSB9fVxuICAgICAgICAgIDwvYT5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9mcy10cmVlPlxuXG4gIEBpZiAoIW5vZGVzKCkubGVuZ3RoKSB7XG4gICAgPHAgY2xhc3M9XCJzbWFsbCB0cmVlLWVtcHR5XCI+XG4gICAgICBObyByZXBvcnRzIHlldC4gQ3JlYXRlIG9uZSwgb3IgYWRkIGEgZm9sZGVyIHRvIGdyb3VwIHRoZW0uXG4gICAgPC9wPlxuICB9XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==