@firestitch/report 18.0.0

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 (58) hide show
  1. package/app/reports/components/component-chart/component-chart.component.d.ts +16 -0
  2. package/app/reports/components/component-kpi/component-kpi.component.d.ts +12 -0
  3. package/app/reports/components/component-list/component-list.component.d.ts +27 -0
  4. package/app/reports/components/report-canvas/report-canvas.component.d.ts +84 -0
  5. package/app/reports/components/report-component/report-component.component.d.ts +71 -0
  6. package/app/reports/components/timezone-select/timezone-select.component.d.ts +18 -0
  7. package/app/reports/data/report.data.d.ts +48 -0
  8. package/app/reports/dialogs/component-settings/component-settings.component.d.ts +49 -0
  9. package/app/reports/dialogs/report-settings/report-settings.component.d.ts +25 -0
  10. package/app/reports/export/offscreen-chart.d.ts +2 -0
  11. package/app/reports/export/report-export-collector.service.d.ts +26 -0
  12. package/app/reports/export/report-pdf.service.d.ts +13 -0
  13. package/app/reports/export/report-pptx.service.d.ts +14 -0
  14. package/app/reports/format.d.ts +1 -0
  15. package/app/reports/interfaces/report.interface.d.ts +174 -0
  16. package/app/reports/layout.d.ts +11 -0
  17. package/app/reports/option-builder.d.ts +15 -0
  18. package/app/reports/report-filter-items.d.ts +9 -0
  19. package/app/reports/services/report-filter-state.service.d.ts +25 -0
  20. package/app/reports/services/report.service.d.ts +15 -0
  21. package/app/reports/theme/echarts.d.ts +2 -0
  22. package/app/reports/theme/palette.d.ts +2 -0
  23. package/app/reports/views/report/report.component.d.ts +50 -0
  24. package/esm2022/app/reports/components/component-chart/component-chart.component.mjs +47 -0
  25. package/esm2022/app/reports/components/component-kpi/component-kpi.component.mjs +33 -0
  26. package/esm2022/app/reports/components/component-list/component-list.component.mjs +178 -0
  27. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +347 -0
  28. package/esm2022/app/reports/components/report-component/report-component.component.mjs +453 -0
  29. package/esm2022/app/reports/components/timezone-select/timezone-select.component.mjs +70 -0
  30. package/esm2022/app/reports/data/report.data.mjs +152 -0
  31. package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +221 -0
  32. package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +109 -0
  33. package/esm2022/app/reports/export/offscreen-chart.mjs +33 -0
  34. package/esm2022/app/reports/export/report-export-collector.service.mjs +94 -0
  35. package/esm2022/app/reports/export/report-pdf.service.mjs +155 -0
  36. package/esm2022/app/reports/export/report-pptx.service.mjs +224 -0
  37. package/esm2022/app/reports/format.mjs +25 -0
  38. package/esm2022/app/reports/interfaces/report.interface.mjs +16 -0
  39. package/esm2022/app/reports/layout.mjs +50 -0
  40. package/esm2022/app/reports/option-builder.mjs +293 -0
  41. package/esm2022/app/reports/report-filter-items.mjs +125 -0
  42. package/esm2022/app/reports/services/report-filter-state.service.mjs +177 -0
  43. package/esm2022/app/reports/services/report.service.mjs +56 -0
  44. package/esm2022/app/reports/theme/echarts.mjs +59 -0
  45. package/esm2022/app/reports/theme/palette.mjs +10 -0
  46. package/esm2022/app/reports/views/report/report.component.mjs +354 -0
  47. package/esm2022/firestitch-report.mjs +5 -0
  48. package/esm2022/public_api.mjs +13 -0
  49. package/fesm2022/firestitch-report-echarts-BxYnpz7n.mjs +60 -0
  50. package/fesm2022/firestitch-report-echarts-BxYnpz7n.mjs.map +1 -0
  51. package/fesm2022/firestitch-report-firestitch-report-Cnotycly.mjs +3107 -0
  52. package/fesm2022/firestitch-report-firestitch-report-Cnotycly.mjs.map +1 -0
  53. package/fesm2022/firestitch-report.mjs +2 -0
  54. package/fesm2022/firestitch-report.mjs.map +1 -0
  55. package/index.d.ts +5 -0
  56. package/package.json +39 -0
  57. package/public_api.d.ts +5 -0
  58. package/styles.scss +1 -0
@@ -0,0 +1,293 @@
1
+ import { format, isValid, parseISO } from 'date-fns';
2
+ const BUCKET_GRANULARITIES = ['day', 'week', 'month', 'quarter', 'year'];
3
+ // colorBy applies only to single-dimension bar charts, and only when splitBy
4
+ // isn't already driving multiple series: it colors each bar by its category and
5
+ // shows a legend (one series per category, overlapped to full width).
6
+ export function isColorBy(config) {
7
+ return !!config.colorBy?.column && !config.splitBy?.column && (config.chartType ?? 'bar') === 'bar';
8
+ }
9
+ export function extractChartSeries(component, data) {
10
+ const config = component.config;
11
+ const xColumn = config.xAxis?.column ?? data.columns[0];
12
+ const splitColumn = config.splitBy?.column;
13
+ // colorBy emits one series per category too (so each bar carries its own
14
+ // color + legend entry), but the bars are overlapped to full width in
15
+ // buildAxisOption rather than laid side-by-side. splitBy wins if both are set.
16
+ const groupColumn = splitColumn || (isColorBy(config) ? config.colorBy?.column : undefined);
17
+ const measures = config.measures?.length
18
+ ? config.measures
19
+ : [{ column: data.columns[data.columns.length - 1] }];
20
+ const rawCategories = uniqueValues(data.rows, xColumn);
21
+ const categories = rawCategories.map((category) => String(category ?? '—'));
22
+ const series = [];
23
+ if (groupColumn) {
24
+ // One series per group value (splitBy/colorBy), pivoted over the first measure.
25
+ const measure = measures[0];
26
+ for (const groupValue of uniqueValues(data.rows, groupColumn)) {
27
+ const byCategory = new Map();
28
+ for (const row of data.rows) {
29
+ if (row[groupColumn] === groupValue) {
30
+ byCategory.set(row[xColumn], row[measure.column]);
31
+ }
32
+ }
33
+ series.push({
34
+ name: String(groupValue ?? '—'),
35
+ values: rawCategories.map((category) => numeric(byCategory.get(category))),
36
+ });
37
+ }
38
+ }
39
+ else {
40
+ for (const measure of measures) {
41
+ const byCategory = new Map();
42
+ for (const row of data.rows) {
43
+ byCategory.set(row[xColumn], row[measure.column]);
44
+ }
45
+ series.push({
46
+ name: measure.label ?? measure.column,
47
+ values: rawCategories.map((category) => numeric(byCategory.get(category))),
48
+ });
49
+ }
50
+ }
51
+ return { categories, series };
52
+ }
53
+ // The one pure mapping from our standard camelCase chart config + the data
54
+ // endpoint's rows to an ECharts option. Everything visual that isn't in the
55
+ // registered 'report' theme is decided here, so report standards have exactly
56
+ // two homes.
57
+ export function buildChartOption(component, data) {
58
+ const config = component.config;
59
+ const chartType = config.chartType ?? 'bar';
60
+ if (chartType === 'pie' || chartType === 'donut') {
61
+ return buildPieOption(component, data, chartType === 'donut');
62
+ }
63
+ return buildAxisOption(component, data, chartType);
64
+ }
65
+ function buildAxisOption(component, data, chartType) {
66
+ const config = component.config;
67
+ const extracted = extractChartSeries(component, data);
68
+ const horizontal = config.orientation === 'horizontal';
69
+ const colorBy = isColorBy(config);
70
+ // colorBy emits one series per category; overlapping them (barGap -100%) makes
71
+ // each render at the full category-band width — one full-width, distinctly
72
+ // colored bar per category — instead of side-by-side slivers. The layout props
73
+ // are read from the first series of the coordinate system.
74
+ const series = extracted.series.map((extractedSeries, index) => buildSeries(extractedSeries.name, extractedSeries.values, chartType, config.stacked, colorBy && index === 0));
75
+ const granularity = bucketGranularity(data);
76
+ const categoryAxis = {
77
+ type: 'category',
78
+ data: extracted.categories,
79
+ name: config.xAxis?.label,
80
+ nameLocation: 'middle',
81
+ nameGap: granularity && spansMultipleYears(extracted.categories) ? 40 : 28,
82
+ ...periodAxisLabel(granularity, extracted.categories),
83
+ };
84
+ const valueAxis = { type: 'value' };
85
+ const legendPosition = resolveLegendPosition(config, series.length, colorBy);
86
+ return {
87
+ grid: axisGrid(legendPosition),
88
+ legend: legendOption(legendPosition),
89
+ // colorBy charts overlap N mostly-null series, so an axis tooltip would list
90
+ // every category; an item tooltip shows just the hovered bar.
91
+ tooltip: { trigger: colorBy ? 'item' : 'axis' },
92
+ xAxis: horizontal ? valueAxis : categoryAxis,
93
+ yAxis: horizontal ? categoryAxis : valueAxis,
94
+ series,
95
+ };
96
+ }
97
+ // Default legend placement when the config doesn't pin one: pie charts read
98
+ // best with the slice key beside them (right); axis charts only need a legend
99
+ // to tell multiple series apart, so a single-series chart hides it. An explicit
100
+ // config.legend (including 'hidden') always wins. Shared with the PowerPoint
101
+ // export so both media place the legend identically.
102
+ export function resolveLegendPosition(config, seriesCount, colorBy = false) {
103
+ if (config.legend) {
104
+ return config.legend;
105
+ }
106
+ const pie = config.chartType === 'pie' || config.chartType === 'donut';
107
+ // colorBy maps each bar's color to its category, so it needs a legend even
108
+ // though it's a single measure.
109
+ return pie || colorBy || seriesCount > 1 ? (pie ? 'right' : 'top') : 'hidden';
110
+ }
111
+ function legendOption(position) {
112
+ if (position === 'hidden') {
113
+ return { show: false };
114
+ }
115
+ const base = { type: 'scroll' };
116
+ switch (position) {
117
+ case 'bottom':
118
+ return { ...base, bottom: 0 };
119
+ case 'left':
120
+ return { ...base, orient: 'vertical', left: 0, top: 'middle' };
121
+ case 'right':
122
+ return { ...base, orient: 'vertical', right: 0, top: 'middle' };
123
+ default:
124
+ return { ...base, top: 0 };
125
+ }
126
+ }
127
+ // Reserve plot-edge room on whichever side the legend occupies so it never
128
+ // overlaps the bars/lines; containLabel already accounts for the axis labels.
129
+ function axisGrid(position) {
130
+ const base = { left: 8, right: 16, top: 8, bottom: 8, containLabel: true };
131
+ switch (position) {
132
+ case 'bottom':
133
+ return { ...base, bottom: 32 };
134
+ case 'left':
135
+ return { ...base, left: 96 };
136
+ case 'right':
137
+ return { ...base, right: 96 };
138
+ case 'hidden':
139
+ return base;
140
+ default:
141
+ return { ...base, top: 32 };
142
+ }
143
+ }
144
+ function buildSeries(name, values, chartType, stacked, overlap) {
145
+ if (chartType === 'bar') {
146
+ return {
147
+ name,
148
+ type: 'bar',
149
+ data: values,
150
+ stack: stacked ? 'total' : undefined,
151
+ barMaxWidth: 48,
152
+ // colorBy: overlap the per-category series so each bar renders full-width.
153
+ ...(overlap ? { barGap: '-100%', barCategoryGap: '20%' } : {}),
154
+ };
155
+ }
156
+ return {
157
+ name,
158
+ type: 'line',
159
+ data: values,
160
+ stack: stacked ? 'total' : undefined,
161
+ smooth: true,
162
+ symbolSize: 6,
163
+ areaStyle: chartType === 'area' ? { opacity: 0.25 } : undefined,
164
+ };
165
+ }
166
+ function buildPieOption(component, data, donut) {
167
+ const config = component.config;
168
+ const extracted = extractChartSeries(component, data);
169
+ const values = extracted.series[0]?.values ?? [];
170
+ const legendPosition = resolveLegendPosition(config, extracted.series.length);
171
+ return {
172
+ tooltip: { trigger: 'item' },
173
+ legend: legendOption(legendPosition),
174
+ series: [
175
+ {
176
+ type: 'pie',
177
+ radius: donut ? ['45%', '72%'] : '72%',
178
+ center: pieCenter(legendPosition),
179
+ label: { show: false },
180
+ data: extracted.categories.map((category, index) => ({
181
+ name: category,
182
+ value: values[index] ?? 0,
183
+ })),
184
+ },
185
+ ],
186
+ };
187
+ }
188
+ // Nudge the pie off-center toward the opposite edge from its legend so the two
189
+ // don't collide; centered when the legend is hidden.
190
+ function pieCenter(position) {
191
+ switch (position) {
192
+ case 'left':
193
+ return ['60%', '50%'];
194
+ case 'right':
195
+ return ['40%', '50%'];
196
+ case 'top':
197
+ return ['50%', '58%'];
198
+ case 'bottom':
199
+ return ['50%', '46%'];
200
+ default:
201
+ return ['50%', '50%'];
202
+ }
203
+ }
204
+ function uniqueValues(rows, column) {
205
+ const seen = new Set();
206
+ const values = [];
207
+ for (const row of rows) {
208
+ const value = row[column];
209
+ if (!seen.has(value)) {
210
+ seen.add(value);
211
+ values.push(value);
212
+ }
213
+ }
214
+ return values;
215
+ }
216
+ function numeric(value) {
217
+ if (value === null || value === undefined || value === '') {
218
+ return null;
219
+ }
220
+ const parsed = Number(value);
221
+ return Number.isFinite(parsed) ? parsed : null;
222
+ }
223
+ // The effective time bucket the rows were grouped into (from the data endpoint),
224
+ // or null when the x-axis isn't a time axis — gates the compact period labels.
225
+ function bucketGranularity(data) {
226
+ return data.granularity && BUCKET_GRANULARITIES.includes(data.granularity) ? data.granularity : null;
227
+ }
228
+ // Whether the period-start categories cross a year boundary. When they don't,
229
+ // the year is pure noise on every label, so it's dropped entirely.
230
+ export function spansMultipleYears(categories) {
231
+ const years = new Set();
232
+ for (const category of categories) {
233
+ const date = parseISO(category);
234
+ if (isValid(date)) {
235
+ years.add(date.getFullYear());
236
+ }
237
+ }
238
+ return years.size > 1;
239
+ }
240
+ // A bucket's period-start split into its primary label and its year. Day/week
241
+ // read as "May 1", month as "May", quarter as "Q2", year as "2025". Returns null
242
+ // for a value that isn't a parseable date (left as-is by callers).
243
+ function periodLabelParts(value, granularity) {
244
+ const date = parseISO(value);
245
+ if (!isValid(date)) {
246
+ return null;
247
+ }
248
+ const year = String(date.getFullYear());
249
+ switch (granularity) {
250
+ case 'year':
251
+ return { primary: year, year };
252
+ case 'quarter':
253
+ return { primary: `Q${Math.floor(date.getMonth() / 3) + 1}`, year };
254
+ case 'month':
255
+ return { primary: format(date, 'MMMM'), year };
256
+ default: // day, week — the bucket start as a compact "MMM d"
257
+ return { primary: format(date, 'MMM d'), year };
258
+ }
259
+ }
260
+ // A compact single-line period label (year appended only when the data spans
261
+ // years) — for media that can't do a styled second line, e.g. PowerPoint.
262
+ export function formatPeriodLabel(value, granularity, multiYear) {
263
+ const parts = periodLabelParts(value, granularity);
264
+ if (!parts) {
265
+ return value;
266
+ }
267
+ return multiYear && granularity !== 'year' ? `${parts.primary} ${parts.year}` : parts.primary;
268
+ }
269
+ // ECharts category-axis label config for a time bucket: the primary label on
270
+ // line one, and — only when the data spans multiple years — the year on a small
271
+ // gray second line, centered under the tick (year granularity needs no second
272
+ // line, it already is the year). Empty for a non-time axis (labels as-is).
273
+ function periodAxisLabel(granularity, categories) {
274
+ if (!granularity) {
275
+ return {};
276
+ }
277
+ const multiYear = spansMultipleYears(categories);
278
+ return {
279
+ axisLabel: {
280
+ formatter: (value) => {
281
+ const parts = periodLabelParts(value, granularity);
282
+ if (!parts) {
283
+ return value;
284
+ }
285
+ return multiYear && granularity !== 'year'
286
+ ? `${parts.primary}\n{yr|${parts.year}}`
287
+ : parts.primary;
288
+ },
289
+ rich: { yr: { fontSize: 10, color: '#9aa0a6', lineHeight: 14 } },
290
+ },
291
+ };
292
+ }
293
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW9uLWJ1aWxkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXBwL3JlcG9ydHMvb3B0aW9uLWJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBS3JELE1BQU0sb0JBQW9CLEdBQXVCLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBRzdGLDZFQUE2RTtBQUM3RSxnRkFBZ0Y7QUFDaEYsc0VBQXNFO0FBQ3RFLE1BQU0sVUFBVSxTQUFTLENBQUMsTUFBbUI7SUFDM0MsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLElBQUksS0FBSyxDQUFDLEtBQUssS0FBSyxDQUFDO0FBQ3RHLENBQUM7QUFZRCxNQUFNLFVBQVUsa0JBQWtCLENBQUMsU0FBMEIsRUFBRSxJQUFtQjtJQUNoRixNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsTUFBcUIsQ0FBQztJQUMvQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDO0lBQzNDLHlFQUF5RTtJQUN6RSxzRUFBc0U7SUFDdEUsK0VBQStFO0lBQy9FLE1BQU0sV0FBVyxHQUFHLFdBQVcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzVGLE1BQU0s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Q0FBQztRQUNqQixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxNQUFNLFNBQVMsR0FBRyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVqRCxPQUFPO1FBQ0wsU0FBUyxFQUFFO1lBQ1QsU0FBUyxFQUFFLENBQUMsS0FBYSxFQUFFLEVBQUU7Z0JBQzNCLE1BQU0sS0FBSyxHQUFHLGdCQUFnQixDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQztnQkFDbkQsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUNYLE9BQU8sS0FBSyxDQUFDO2dCQUNmLENBQUM7Z0JBRUQsT0FBTyxTQUFTLElBQUksV0FBVyxLQUFLLE1BQU07b0JBQ3hDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxPQUFPLFNBQVMsS0FBSyxDQUFDLElBQUksR0FBRztvQkFDeEMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7WUFDcEIsQ0FBQztZQUNELElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLEVBQUU7U0FDakU7S0FDRixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRUNoYXJ0c09wdGlvbiwgTGVnZW5kQ29tcG9uZW50T3B0aW9uLCBTZXJpZXNPcHRpb24gfSBmcm9tICdlY2hhcnRzJztcblxuaW1wb3J0IHsgZm9ybWF0LCBpc1ZhbGlkLCBwYXJzZUlTTyB9IGZyb20gJ2RhdGUtZm5zJztcblxuaW1wb3J0IHsgQ2hhcnRDb25maWcsIENoYXJ0R3JhbnVsYXJpdHksIENvbXBvbmVudERhdGEsIExlZ2VuZFBvc2l0aW9uLCBSZXBvcnRDb21wb25lbnQgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5cblxuY29uc3QgQlVDS0VUX0dSQU5VTEFSSVRJRVM6IENoYXJ0R3JhbnVsYXJpdHlbXSA9IFsnZGF5JywgJ3dlZWsnLCAnbW9udGgnLCAncXVhcnRlcicsICd5ZWFyJ107XG5cblxuLy8gY29sb3JCeSBhcHBsaWVzIG9ubHkgdG8gc2luZ2xlLWRpbWVuc2lvbiBiYXIgY2hhcnRzLCBhbmQgb25seSB3aGVuIHNwbGl0Qnlcbi8vIGlzbid0IGFscmVhZHkgZHJpdmluZyBtdWx0aXBsZSBzZXJpZXM6IGl0IGNvbG9ycyBlYWNoIGJhciBieSBpdHMgY2F0ZWdvcnkgYW5kXG4vLyBzaG93cyBhIGxlZ2VuZCAob25lIHNlcmllcyBwZXIgY2F0ZWdvcnksIG92ZXJsYXBwZWQgdG8gZnVsbCB3aWR0aCkuXG5leHBvcnQgZnVuY3Rpb24gaXNDb2xvckJ5KGNvbmZpZzogQ2hhcnRDb25maWcpOiBib29sZWFuIHtcbiAgcmV0dXJuICEhY29uZmlnLmNvbG9yQnk/LmNvbHVtbiAmJiAhY29uZmlnLnNwbGl0Qnk/LmNvbHVtbiAmJiAoY29uZmlnLmNoYXJ0VHlwZSA/PyAnYmFyJykgPT09ICdiYXInO1xufVxuXG5cbi8vIENhdGVnb3JpZXMgKyBuYW1lZCBzZXJpZXMgZXh0cmFjdGVkIGZyb20gYSBjaGFydCBjb21wb25lbnQncyBjb25maWcgKyByb3dzIOKAlFxuLy8gdGhlIG9uZSBwaXZvdCAoc3BsaXRCeSDihpIgc2VyaWVzLCBtZWFzdXJlcyDihpIgc2VyaWVzKSBzaGFyZWQgYnkgdGhlIG9uLXNjcmVlblxuLy8gRUNoYXJ0cyBvcHRpb24gYmVsb3cgQU5EIHRoZSBQb3dlclBvaW50IGV4cG9ydCdzIG5hdGl2ZSBjaGFydCBkYXRhLCBzbyBib3RoXG4vLyBtZWRpYSBwbG90IGlkZW50aWNhbCBudW1iZXJzLlxuZXhwb3J0IGludGVyZmFjZSBFeHRyYWN0ZWRDaGFydFNlcmllcyB7XG4gIGNhdGVnb3JpZXM6IHN0cmluZ1tdO1xuICBzZXJpZXM6IHsgbmFtZTogc3RyaW5nOyB2YWx1ZXM6IChudW1iZXIgfCBudWxsKVtdIH1bXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RDaGFydFNlcmllcyhjb21wb25lbnQ6IFJlcG9ydENvbXBvbmVudCwgZGF0YTogQ29tcG9uZW50RGF0YSk6IEV4dHJhY3RlZENoYXJ0U2VyaWVzIHtcbiAgY29uc3QgY29uZmlnID0gY29tcG9uZW50LmNvbmZpZyBhcyBDaGFydENvbmZpZztcbiAgY29uc3QgeENvbHVtbiA9IGNvbmZpZy54QXhpcz8uY29sdW1uID8/IGRhdGEuY29sdW1uc1swXTtcbiAgY29uc3Qgc3BsaXRDb2x1bW4gPSBjb25maWcuc3BsaXRCeT8uY29sdW1uO1xuICAvLyBjb2xvckJ5IGVtaXRzIG9uZSBzZXJpZXMgcGVyIGNhdGVnb3J5IHRvbyAoc28gZWFjaCBiYXIgY2FycmllcyBpdHMgb3duXG4gIC8vIGNvbG9yICsgbGVnZW5kIGVudHJ5KSwgYnV0IHRoZSBiYXJzIGFyZSBvdmVybGFwcGVkIHRvIGZ1bGwgd2lkdGggaW5cbiAgLy8gYnVpbGRBeGlzT3B0aW9uIHJhdGhlciB0aGFuIGxhaWQgc2lkZS1ieS1zaWRlLiBzcGxpdEJ5IHdpbnMgaWYgYm90aCBhcmUgc2V0LlxuICBjb25zdCBncm91cENvbHVtbiA9IHNwbGl0Q29sdW1uIHx8IChpc0NvbG9yQnkoY29uZmlnKSA/IGNvbmZpZy5jb2xvckJ5Py5jb2x1bW4gOiB1bmRlZmluZWQpO1xuICBjb25zdCBtZWFzdXJlcyA9IGNvbmZpZy5tZWFzdXJlcz8ubGVuZ3RoXG4gICAgPyBjb25maWcubWVhc3VyZXNcbiAgICA6IFt7IGNvbHVtbjogZGF0YS5jb2x1bW5zW2RhdGEuY29sdW1ucy5sZW5ndGggLSAxXSB9XTtcblxuICBjb25zdCByYXdDYXRlZ29yaWVzID0gdW5pcXVlVmFsdWVzKGRhdGEucm93cywgeENvbHVtbik7XG4gIGNvbnN0IGNhdGVnb3JpZXMgPSByYXdDYXRlZ29yaWVzLm1hcCgoY2F0ZWdvcnkpID0+IFN0cmluZyhjYXRlZ29yeSA/PyAn4oCUJykpO1xuICBjb25zdCBzZXJpZXM6IEV4dHJhY3RlZENoYXJ0U2VyaWVzWydzZXJpZXMnXSA9IFtdO1xuXG4gIGlmIChncm91cENvbHVtbikge1xuICAgIC8vIE9uZSBzZXJpZXMgcGVyIGdyb3VwIHZhbHVlIChzcGxpdEJ5L2NvbG9yQnkpLCBwaXZvdGVkIG92ZXIgdGhlIGZpcnN0IG1lYXN1cmUuXG4gICAgY29uc3QgbWVhc3VyZSA9IG1lYXN1cmVzWzBdO1xuICAgIGZvciAoY29uc3QgZ3JvdXBWYWx1ZSBvZiB1bmlxdWVWYWx1ZXMoZGF0YS5yb3dzLCBncm91cENvbHVtbikpIHtcbiAgICAgIGNvbnN0IGJ5Q2F0ZWdvcnkgPSBuZXcgTWFwPHVua25vd24sIHVua25vd24+KCk7XG4gICAgICBmb3IgKGNvbnN0IHJvdyBvZiBkYXRhLnJvd3MpIHtcbiAgICAgICAgaWYgKHJvd1tncm91cENvbHVtbl0gPT09IGdyb3VwVmFsdWUpIHtcbiAgICAgICAgICBieUNhdGVnb3J5LnNldChyb3dbeENvbHVtbl0sIHJvd1ttZWFzdXJlLmNvbHVtbl0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHNlcmllcy5wdXNoKHtcbiAgICAgICAgbmFtZTogU3RyaW5nKGdyb3VwVmFsdWUgPz8gJ+KAlCcpLFxuICAgICAgICB2YWx1ZXM6IHJhd0NhdGVnb3JpZXMubWFwKChjYXRlZ29yeSkgPT4gbnVtZXJpYyhieUNhdGVnb3J5LmdldChjYXRlZ29yeSkpKSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBmb3IgKGNvbnN0IG1lYXN1cmUgb2YgbWVhc3VyZXMpIHtcbiAgICAgIGNvbnN0IGJ5Q2F0ZWdvcnkgPSBuZXcgTWFwPHVua25vd24sIHVua25vd24+KCk7XG4gICAgICBmb3IgKGNvbnN0IHJvdyBvZiBkYXRhLnJvd3MpIHtcbiAgICAgICAgYnlDYXRlZ29yeS5zZXQocm93W3hDb2x1bW5dLCByb3dbbWVhc3VyZS5jb2x1bW5dKTtcbiAgICAgIH1cblxuICAgICAgc2VyaWVzLnB1c2goe1xuICAgICAgICBuYW1lOiBtZWFzdXJlLmxhYmVsID8/IG1lYXN1cmUuY29sdW1uLFxuICAgICAgICB2YWx1ZXM6IHJhd0NhdGVnb3JpZXMubWFwKChjYXRlZ29yeSkgPT4gbnVtZXJpYyhieUNhdGVnb3J5LmdldChjYXRlZ29yeSkpKSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IGNhdGVnb3JpZXMsIHNlcmllcyB9O1xufVxuXG4vLyBUaGUgb25lIHB1cmUgbWFwcGluZyBmcm9tIG91ciBzdGFuZGFyZCBjYW1lbENhc2UgY2hhcnQgY29uZmlnICsgdGhlIGRhdGFcbi8vIGVuZHBvaW50J3Mgcm93cyB0byBhbiBFQ2hhcnRzIG9wdGlvbi4gRXZlcnl0aGluZyB2aXN1YWwgdGhhdCBpc24ndCBpbiB0aGVcbi8vIHJlZ2lzdGVyZWQgJ3JlcG9ydCcgdGhlbWUgaXMgZGVjaWRlZCBoZXJlLCBzbyByZXBvcnQgc3RhbmRhcmRzIGhhdmUgZXhhY3RseVxuLy8gdHdvIGhvbWVzLlxuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkQ2hhcnRPcHRpb24oY29tcG9uZW50OiBSZXBvcnRDb21wb25lbnQsIGRhdGE6IENvbXBvbmVudERhdGEpOiBFQ2hhcnRzT3B0aW9uIHtcbiAgY29uc3QgY29uZmlnID0gY29tcG9uZW50LmNvbmZpZyBhcyBDaGFydENvbmZpZztcbiAgY29uc3QgY2hhcnRUeXBlID0gY29uZmlnLmNoYXJ0VHlwZSA/PyAnYmFyJztcblxuICBpZiAoY2hhcnRUeXBlID09PSAncGllJyB8fCBjaGFydFR5cGUgPT09ICdkb251dCcpIHtcbiAgICByZXR1cm4gYnVpbGRQaWVPcHRpb24oY29tcG9uZW50LCBkYXRhLCBjaGFydFR5cGUgPT09ICdkb251dCcpO1xuICB9XG5cbiAgcmV0dXJuIGJ1aWxkQXhpc09wdGlvbihjb21wb25lbnQsIGRhdGEsIGNoYXJ0VHlwZSk7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkQXhpc09wdGlvbihcbiAgY29tcG9uZW50OiBSZXBvcnRDb21wb25lbnQsXG4gIGRhdGE6IENvbXBvbmVudERhdGEsXG4gIGNoYXJ0VHlwZTogJ2JhcicgfCAnbGluZScgfCAnYXJlYScsXG4pOiBFQ2hhcnRzT3B0aW9uIHtcbiAgY29uc3QgY29uZmlnID0gY29tcG9uZW50LmNvbmZpZyBhcyBDaGFydENvbmZpZztcbiAgY29uc3QgZXh0cmFjdGVkID0gZXh0cmFjdENoYXJ0U2VyaWVzKGNvbXBvbmVudCwgZGF0YSk7XG4gIGNvbnN0IGhvcml6b250YWwgPSBjb25maWcub3JpZW50YXRpb24gPT09ICdob3Jpem9udGFsJztcbiAgY29uc3QgY29sb3JCeSA9IGlzQ29sb3JCeShjb25maWcpO1xuXG4gIC8vIGNvbG9yQnkgZW1pdHMgb25lIHNlcmllcyBwZXIgY2F0ZWdvcnk7IG92ZXJsYXBwaW5nIHRoZW0gKGJhckdhcCAtMTAwJSkgbWFrZXNcbiAgLy8gZWFjaCByZW5kZXIgYXQgdGhlIGZ1bGwgY2F0ZWdvcnktYmFuZCB3aWR0aCDigJQgb25lIGZ1bGwtd2lkdGgsIGRpc3RpbmN0bHlcbiAgLy8gY29sb3JlZCBiYXIgcGVyIGNhdGVnb3J5IOKAlCBpbnN0ZWFkIG9mIHNpZGUtYnktc2lkZSBzbGl2ZXJzLiBUaGUgbGF5b3V0IHByb3BzXG4gIC8vIGFyZSByZWFkIGZyb20gdGhlIGZpcnN0IHNlcmllcyBvZiB0aGUgY29vcmRpbmF0ZSBzeXN0ZW0uXG4gIGNvbnN0IHNlcmllczogU2VyaWVzT3B0aW9uW10gPSBleHRyYWN0ZWQuc2VyaWVzLm1hcCgoZXh0cmFjdGVkU2VyaWVzLCBpbmRleCkgPT5cbiAgICBidWlsZFNlcmllcyhleHRyYWN0ZWRTZXJpZXMubmFtZSwgZXh0cmFjdGVkU2VyaWVzLnZhbHVlcywgY2hhcnRUeXBlLCBjb25maWcuc3RhY2tlZCwgY29sb3JCeSAmJiBpbmRleCA9PT0gMCkpO1xuXG4gIGNvbnN0IGdyYW51bGFyaXR5ID0gYnVja2V0R3JhbnVsYXJpdHkoZGF0YSk7XG4gIGNvbnN0IGNhdGVnb3J5QXhpcyA9IHtcbiAgICB0eXBlOiAnY2F0ZWdvcnknIGFzIGNvbnN0LFxuICAgIGRhdGE6IGV4dHJhY3RlZC5jYXRlZ29yaWVzLFxuICAgIG5hbWU6IGNvbmZpZy54QXhpcz8ubGFiZWwsXG4gICAgbmFtZUxvY2F0aW9uOiAnbWlkZGxlJyBhcyBjb25zdCxcbiAgICBuYW1lR2FwOiBncmFudWxhcml0eSAmJiBzcGFuc011bHRpcGxlWWVhcnMoZXh0cmFjdGVkLmNhdGVnb3JpZXMpID8gNDAgOiAyOCxcbiAgICAuLi5wZXJpb2RBeGlzTGFiZWwoZ3JhbnVsYXJpdHksIGV4dHJhY3RlZC5jYXRlZ29yaWVzKSxcbiAgfTtcbiAgY29uc3QgdmFsdWVBeGlzID0geyB0eXBlOiAndmFsdWUnIGFzIGNvbnN0IH07XG5cbiAgY29uc3QgbGVnZW5kUG9zaXRpb24gPSByZXNvbHZlTGVnZW5kUG9zaXRpb24oY29uZmlnLCBzZXJpZXMubGVuZ3RoLCBjb2xvckJ5KTtcblxuICByZXR1cm4ge1xuICAgIGdyaWQ6IGF4aXNHcmlkKGxlZ2VuZFBvc2l0aW9uKSxcbiAgICBsZWdlbmQ6IGxlZ2VuZE9wdGlvbihsZWdlbmRQb3NpdGlvbiksXG4gICAgLy8gY29sb3JCeSBjaGFydHMgb3ZlcmxhcCBOIG1vc3RseS1udWxsIHNlcmllcywgc28gYW4gYXhpcyB0b29sdGlwIHdvdWxkIGxpc3RcbiAgICAvLyBldmVyeSBjYXRlZ29yeTsgYW4gaXRlbSB0b29sdGlwIHNob3dzIGp1c3QgdGhlIGhvdmVyZWQgYmFyLlxuICAgIHRvb2x0aXA6IHsgdHJpZ2dlcjogY29sb3JCeSA/ICdpdGVtJyA6ICdheGlzJyB9LFxuICAgIHhBeGlzOiBob3Jpem9udGFsID8gdmFsdWVBeGlzIDogY2F0ZWdvcnlBeGlzLFxuICAgIHlBeGlzOiBob3Jpem9udGFsID8gY2F0ZWdvcnlBeGlzIDogdmFsdWVBeGlzLFxuICAgIHNlcmllcyxcbiAgfTtcbn1cblxuLy8gRGVmYXVsdCBsZWdlbmQgcGxhY2VtZW50IHdoZW4gdGhlIGNvbmZpZyBkb2Vzbid0IHBpbiBvbmU6IHBpZSBjaGFydHMgcmVhZFxuLy8gYmVzdCB3aXRoIHRoZSBzbGljZSBrZXkgYmVzaWRlIHRoZW0gKHJpZ2h0KTsgYXhpcyBjaGFydHMgb25seSBuZWVkIGEgbGVnZW5kXG4vLyB0byB0ZWxsIG11bHRpcGxlIHNlcmllcyBhcGFydCwgc28gYSBzaW5nbGUtc2VyaWVzIGNoYXJ0IGhpZGVzIGl0LiBBbiBleHBsaWNpdFxuLy8gY29uZmlnLmxlZ2VuZCAoaW5jbHVkaW5nICdoaWRkZW4nKSBhbHdheXMgd2lucy4gU2hhcmVkIHdpdGggdGhlIFBvd2VyUG9pbnRcbi8vIGV4cG9ydCBzbyBib3RoIG1lZGlhIHBsYWNlIHRoZSBsZWdlbmQgaWRlbnRpY2FsbHkuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUxlZ2VuZFBvc2l0aW9uKGNvbmZpZzogQ2hhcnRDb25maWcsIHNlcmllc0NvdW50OiBudW1iZXIsIGNvbG9yQnkgPSBmYWxzZSk6IExlZ2VuZFBvc2l0aW9uIHtcbiAgaWYgKGNvbmZpZy5sZWdlbmQpIHtcbiAgICByZXR1cm4gY29uZmlnLmxlZ2VuZDtcbiAgfVxuXG4gIGNvbnN0IHBpZSA9IGNvbmZpZy5jaGFydFR5cGUgPT09ICdwaWUnIHx8IGNvbmZpZy5jaGFydFR5cGUgPT09ICdkb251dCc7XG5cbiAgLy8gY29sb3JCeSBtYXBzIGVhY2ggYmFyJ3MgY29sb3IgdG8gaXRzIGNhdGVnb3J5LCBzbyBpdCBuZWVkcyBhIGxlZ2VuZCBldmVuXG4gIC8vIHRob3VnaCBpdCdzIGEgc2luZ2xlIG1lYXN1cmUuXG4gIHJldHVybiBwaWUgfHwgY29sb3JCeSB8fCBzZXJpZXNDb3VudCA+IDEgPyAocGllID8gJ3JpZ2h0JyA6ICd0b3AnKSA6ICdoaWRkZW4nO1xufVxuXG5mdW5jdGlvbiBsZWdlbmRPcHRpb24ocG9zaXRpb246IExlZ2VuZFBvc2l0aW9uKTogTGVnZW5kQ29tcG9uZW50T3B0aW9uIHtcbiAgaWYgKHBvc2l0aW9uID09PSAnaGlkZGVuJykge1xuICAgIHJldHVybiB7IHNob3c6IGZhbHNlIH07XG4gIH1cblxuICBjb25zdCBiYXNlOiBMZWdlbmRDb21wb25lbnRPcHRpb24gPSB7IHR5cGU6ICdzY3JvbGwnIH07XG5cbiAgc3dpdGNoIChwb3NpdGlvbikge1xuICAgIGNhc2UgJ2JvdHRvbSc6XG4gICAgICByZXR1cm4geyAuLi5iYXNlLCBib3R0b206IDAgfTtcbiAgICBjYXNlICdsZWZ0JzpcbiAgICAgIHJldHVybiB7IC4uLmJhc2UsIG9yaWVudDogJ3ZlcnRpY2FsJywgbGVmdDogMCwgdG9wOiAnbWlkZGxlJyB9O1xuICAgIGNhc2UgJ3JpZ2h0JzpcbiAgICAgIHJldHVybiB7IC4uLmJhc2UsIG9yaWVudDogJ3ZlcnRpY2FsJywgcmlnaHQ6IDAsIHRvcDogJ21pZGRsZScgfTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIHsgLi4uYmFzZSwgdG9wOiAwIH07XG4gIH1cbn1cblxuLy8gUmVzZXJ2ZSBwbG90LWVkZ2Ugcm9vbSBvbiB3aGljaGV2ZXIgc2lkZSB0aGUgbGVnZW5kIG9jY3VwaWVzIHNvIGl0IG5ldmVyXG4vLyBvdmVybGFwcyB0aGUgYmFycy9saW5lczsgY29udGFpbkxhYmVsIGFscmVhZHkgYWNjb3VudHMgZm9yIHRoZSBheGlzIGxhYmVscy5cbmZ1bmN0aW9uIGF4aXNHcmlkKHBvc2l0aW9uOiBMZWdlbmRQb3NpdGlvbik6IEVDaGFydHNPcHRpb25bJ2dyaWQnXSB7XG4gIGNvbnN0IGJhc2UgPSB7IGxlZnQ6IDgsIHJpZ2h0OiAxNiwgdG9wOiA4LCBib3R0b206IDgsIGNvbnRhaW5MYWJlbDogdHJ1ZSB9O1xuXG4gIHN3aXRjaCAocG9zaXRpb24pIHtcbiAgICBjYXNlICdib3R0b20nOlxuICAgICAgcmV0dXJuIHsgLi4uYmFzZSwgYm90dG9tOiAzMiB9O1xuICAgIGNhc2UgJ2xlZnQnOlxuICAgICAgcmV0dXJuIHsgLi4uYmFzZSwgbGVmdDogOTYgfTtcbiAgICBjYXNlICdyaWdodCc6XG4gICAgICByZXR1cm4geyAuLi5iYXNlLCByaWdodDogOTYgfTtcbiAgICBjYXNlICdoaWRkZW4nOlxuICAgICAgcmV0dXJuIGJhc2U7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB7IC4uLmJhc2UsIHRvcDogMzIgfTtcbiAgfVxufVxuXG5mdW5jdGlvbiBidWlsZFNlcmllcyhcbiAgbmFtZTogc3RyaW5nLFxuICB2YWx1ZXM6IChudW1iZXIgfCBudWxsKVtdLFxuICBjaGFydFR5cGU6ICdiYXInIHwgJ2xpbmUnIHwgJ2FyZWEnLFxuICBzdGFja2VkPzogYm9vbGVhbixcbiAgb3ZlcmxhcD86IGJvb2xlYW4sXG4pOiBTZXJpZXNPcHRpb24ge1xuICBpZiAoY2hhcnRUeXBlID09PSAnYmFyJykge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lLFxuICAgICAgdHlwZTogJ2JhcicsXG4gICAgICBkYXRhOiB2YWx1ZXMsXG4gICAgICBzdGFjazogc3RhY2tlZCA/ICd0b3RhbCcgOiB1bmRlZmluZWQsXG4gICAgICBiYXJNYXhXaWR0aDogNDgsXG4gICAgICAvLyBjb2xvckJ5OiBvdmVybGFwIHRoZSBwZXItY2F0ZWdvcnkgc2VyaWVzIHNvIGVhY2ggYmFyIHJlbmRlcnMgZnVsbC13aWR0aC5cbiAgICAgIC4uLihvdmVybGFwID8geyBiYXJHYXA6ICctMTAwJScsIGJhckNhdGVnb3J5R2FwOiAnMjAlJyB9IDoge30pLFxuICAgIH07XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5hbWUsXG4gICAgdHlwZTogJ2xpbmUnLFxuICAgIGRhdGE6IHZhbHVlcyxcbiAgICBzdGFjazogc3RhY2tlZCA/ICd0b3RhbCcgOiB1bmRlZmluZWQsXG4gICAgc21vb3RoOiB0cnVlLFxuICAgIHN5bWJvbFNpemU6IDYsXG4gICAgYXJlYVN0eWxlOiBjaGFydFR5cGUgPT09ICdhcmVhJyA/IHsgb3BhY2l0eTogMC4yNSB9IDogdW5kZWZpbmVkLFxuICB9O1xufVxuXG5mdW5jdGlvbiBidWlsZFBpZU9wdGlvbihjb21wb25lbnQ6IFJlcG9ydENvbXBvbmVudCwgZGF0YTogQ29tcG9uZW50RGF0YSwgZG9udXQ6IGJvb2xlYW4pOiBFQ2hhcnRzT3B0aW9uIHtcbiAgY29uc3QgY29uZmlnID0gY29tcG9uZW50LmNvbmZpZyBhcyBDaGFydENvbmZpZztcbiAgY29uc3QgZXh0cmFjdGVkID0gZXh0cmFjdENoYXJ0U2VyaWVzKGNvbXBvbmVudCwgZGF0YSk7XG4gIGNvbnN0IHZhbHVlcyA9IGV4dHJhY3RlZC5zZXJpZXNbMF0/LnZhbHVlcyA/PyBbXTtcbiAgY29uc3QgbGVnZW5kUG9zaXRpb24gPSByZXNvbHZlTGVnZW5kUG9zaXRpb24oY29uZmlnLCBleHRyYWN0ZWQuc2VyaWVzLmxlbmd0aCk7XG5cbiAgcmV0dXJuIHtcbiAgICB0b29sdGlwOiB7IHRyaWdnZXI6ICdpdGVtJyB9LFxuICAgIGxlZ2VuZDogbGVnZW5kT3B0aW9uKGxlZ2VuZFBvc2l0aW9uKSxcbiAgICBzZXJpZXM6IFtcbiAgICAgIHtcbiAgICAgICAgdHlwZTogJ3BpZScsXG4gICAgICAgIHJhZGl1czogZG9udXQgPyBbJzQ1JScsICc3MiUnXSA6ICc3MiUnLFxuICAgICAgICBjZW50ZXI6IHBpZUNlbnRlcihsZWdlbmRQb3NpdGlvbiksXG4gICAgICAgIGxhYmVsOiB7IHNob3c6IGZhbHNlIH0sXG4gICAgICAgIGRhdGE6IGV4dHJhY3RlZC5jYXRlZ29yaWVzLm1hcCgoY2F0ZWdvcnksIGluZGV4KSA9PiAoe1xuICAgICAgICAgIG5hbWU6IGNhdGVnb3J5LFxuICAgICAgICAgIHZhbHVlOiB2YWx1ZXNbaW5kZXhdID8/IDAsXG4gICAgICAgIH0pKSxcbiAgICAgIH0sXG4gICAgXSxcbiAgfTtcbn1cblxuLy8gTnVkZ2UgdGhlIHBpZSBvZmYtY2VudGVyIHRvd2FyZCB0aGUgb3Bwb3NpdGUgZWRnZSBmcm9tIGl0cyBsZWdlbmQgc28gdGhlIHR3b1xuLy8gZG9uJ3QgY29sbGlkZTsgY2VudGVyZWQgd2hlbiB0aGUgbGVnZW5kIGlzIGhpZGRlbi5cbmZ1bmN0aW9uIHBpZUNlbnRlcihwb3NpdGlvbjogTGVnZW5kUG9zaXRpb24pOiBbc3RyaW5nLCBzdHJpbmddIHtcbiAgc3dpdGNoIChwb3NpdGlvbikge1xuICAgIGNhc2UgJ2xlZnQnOlxuICAgICAgcmV0dXJuIFsnNjAlJywgJzUwJSddO1xuICAgIGNhc2UgJ3JpZ2h0JzpcbiAgICAgIHJldHVybiBbJzQwJScsICc1MCUnXTtcbiAgICBjYXNlICd0b3AnOlxuICAgICAgcmV0dXJuIFsnNTAlJywgJzU4JSddO1xuICAgIGNhc2UgJ2JvdHRvbSc6XG4gICAgICByZXR1cm4gWyc1MCUnLCAnNDYlJ107XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBbJzUwJScsICc1MCUnXTtcbiAgfVxufVxuXG5mdW5jdGlvbiB1bmlxdWVWYWx1ZXMocm93czogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSwgY29sdW1uOiBzdHJpbmcpOiB1bmtub3duW10ge1xuICBjb25zdCBzZWVuID0gbmV3IFNldDx1bmtub3duPigpO1xuICBjb25zdCB2YWx1ZXM6IHVua25vd25bXSA9IFtdO1xuICBmb3IgKGNvbnN0IHJvdyBvZiByb3dzKSB7XG4gICAgY29uc3QgdmFsdWUgPSByb3dbY29sdW1uXTtcbiAgICBpZiAoIXNlZW4uaGFzKHZhbHVlKSkge1xuICAgICAgc2Vlbi5hZGQodmFsdWUpO1xuICAgICAgdmFsdWVzLnB1c2godmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB2YWx1ZXM7XG59XG5cbmZ1bmN0aW9uIG51bWVyaWModmFsdWU6IHVua25vd24pOiBudW1iZXIgfCBudWxsIHtcbiAgaWYgKHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09ICcnKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBwYXJzZWQgPSBOdW1iZXIodmFsdWUpO1xuXG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUocGFyc2VkKSA/IHBhcnNlZCA6IG51bGw7XG59XG5cbi8vIFRoZSBlZmZlY3RpdmUgdGltZSBidWNrZXQgdGhlIHJvd3Mgd2VyZSBncm91cGVkIGludG8gKGZyb20gdGhlIGRhdGEgZW5kcG9pbnQpLFxuLy8gb3IgbnVsbCB3aGVuIHRoZSB4LWF4aXMgaXNuJ3QgYSB0aW1lIGF4aXMg4oCUIGdhdGVzIHRoZSBjb21wYWN0IHBlcmlvZCBsYWJlbHMuXG5mdW5jdGlvbiBidWNrZXRHcmFudWxhcml0eShkYXRhOiBDb21wb25lbnREYXRhKTogQ2hhcnRHcmFudWxhcml0eSB8IG51bGwge1xuICByZXR1cm4gZGF0YS5ncmFudWxhcml0eSAmJiBCVUNLRVRfR1JBTlVMQVJJVElFUy5pbmNsdWRlcyhkYXRhLmdyYW51bGFyaXR5KSA/IGRhdGEuZ3JhbnVsYXJpdHkgOiBudWxsO1xufVxuXG4vLyBXaGV0aGVyIHRoZSBwZXJpb2Qtc3RhcnQgY2F0ZWdvcmllcyBjcm9zcyBhIHllYXIgYm91bmRhcnkuIFdoZW4gdGhleSBkb24ndCxcbi8vIHRoZSB5ZWFyIGlzIHB1cmUgbm9pc2Ugb24gZXZlcnkgbGFiZWwsIHNvIGl0J3MgZHJvcHBlZCBlbnRpcmVseS5cbmV4cG9ydCBmdW5jdGlvbiBzcGFuc011bHRpcGxlWWVhcnMoY2F0ZWdvcmllczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgY29uc3QgeWVhcnMgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgZm9yIChjb25zdCBjYXRlZ29yeSBvZiBjYXRlZ29yaWVzKSB7XG4gICAgY29uc3QgZGF0ZSA9IHBhcnNlSVNPKGNhdGVnb3J5KTtcbiAgICBpZiAoaXNWYWxpZChkYXRlKSkge1xuICAgICAgeWVhcnMuYWRkKGRhdGUuZ2V0RnVsbFllYXIoKSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHllYXJzLnNpemUgPiAxO1xufVxuXG4vLyBBIGJ1Y2tldCdzIHBlcmlvZC1zdGFydCBzcGxpdCBpbnRvIGl0cyBwcmltYXJ5IGxhYmVsIGFuZCBpdHMgeWVhci4gRGF5L3dlZWtcbi8vIHJlYWQgYXMgXCJNYXkgMVwiLCBtb250aCBhcyBcIk1heVwiLCBxdWFydGVyIGFzIFwiUTJcIiwgeWVhciBhcyBcIjIwMjVcIi4gUmV0dXJucyBudWxsXG4vLyBmb3IgYSB2YWx1ZSB0aGF0IGlzbid0IGEgcGFyc2VhYmxlIGRhdGUgKGxlZnQgYXMtaXMgYnkgY2FsbGVycykuXG5mdW5jdGlvbiBwZXJpb2RMYWJlbFBhcnRzKHZhbHVlOiBzdHJpbmcsIGdyYW51bGFyaXR5OiBDaGFydEdyYW51bGFyaXR5KTogeyBwcmltYXJ5OiBzdHJpbmc7IHllYXI6IHN0cmluZyB9IHwgbnVsbCB7XG4gIGNvbnN0IGRhdGUgPSBwYXJzZUlTTyh2YWx1ZSk7XG4gIGlmICghaXNWYWxpZChkYXRlKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgeWVhciA9IFN0cmluZyhkYXRlLmdldEZ1bGxZZWFyKCkpO1xuICBzd2l0Y2ggKGdyYW51bGFyaXR5KSB7XG4gICAgY2FzZSAneWVhcic6XG4gICAgICByZXR1cm4geyBwcmltYXJ5OiB5ZWFyLCB5ZWFyIH07XG4gICAgY2FzZSAncXVhcnRlcic6XG4gICAgICByZXR1cm4geyBwcmltYXJ5OiBgUSR7TWF0aC5mbG9vcihkYXRlLmdldE1vbnRoKCkgLyAzKSArIDF9YCwgeWVhciB9O1xuICAgIGNhc2UgJ21vbnRoJzpcbiAgICAgIHJldHVybiB7IHByaW1hcnk6IGZvcm1hdChkYXRlLCAnTU1NTScpLCB5ZWFyIH07XG4gICAgZGVmYXVsdDogLy8gZGF5LCB3ZWVrIOKAlCB0aGUgYnVja2V0IHN0YXJ0IGFzIGEgY29tcGFjdCBcIk1NTSBkXCJcbiAgICAgIHJldHVybiB7IHByaW1hcnk6IGZvcm1hdChkYXRlLCAnTU1NIGQnKSwgeWVhciB9O1xuICB9XG59XG5cbi8vIEEgY29tcGFjdCBzaW5nbGUtbGluZSBwZXJpb2QgbGFiZWwgKHllYXIgYXBwZW5kZWQgb25seSB3aGVuIHRoZSBkYXRhIHNwYW5zXG4vLyB5ZWFycykg4oCUIGZvciBtZWRpYSB0aGF0IGNhbid0IGRvIGEgc3R5bGVkIHNlY29uZCBsaW5lLCBlLmcuIFBvd2VyUG9pbnQuXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0UGVyaW9kTGFiZWwodmFsdWU6IHN0cmluZywgZ3JhbnVsYXJpdHk6IENoYXJ0R3JhbnVsYXJpdHksIG11bHRpWWVhcjogYm9vbGVhbik6IHN0cmluZyB7XG4gIGNvbnN0IHBhcnRzID0gcGVyaW9kTGFiZWxQYXJ0cyh2YWx1ZSwgZ3JhbnVsYXJpdHkpO1xuICBpZiAoIXBhcnRzKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG5cbiAgcmV0dXJuIG11bHRpWWVhciAmJiBncmFudWxhcml0eSAhPT0gJ3llYXInID8gYCR7cGFydHMucHJpbWFyeX0gJHtwYXJ0cy55ZWFyfWAgOiBwYXJ0cy5wcmltYXJ5O1xufVxuXG4vLyBFQ2hhcnRzIGNhdGVnb3J5LWF4aXMgbGFiZWwgY29uZmlnIGZvciBhIHRpbWUgYnVja2V0OiB0aGUgcHJpbWFyeSBsYWJlbCBvblxuLy8gbGluZSBvbmUsIGFuZCDigJQgb25seSB3aGVuIHRoZSBkYXRhIHNwYW5zIG11bHRpcGxlIHllYXJzIOKAlCB0aGUgeWVhciBvbiBhIHNtYWxsXG4vLyBncmF5IHNlY29uZCBsaW5lLCBjZW50ZXJlZCB1bmRlciB0aGUgdGljayAoeWVhciBncmFudWxhcml0eSBuZWVkcyBubyBzZWNvbmRcbi8vIGxpbmUsIGl0IGFscmVhZHkgaXMgdGhlIHllYXIpLiBFbXB0eSBmb3IgYSBub24tdGltZSBheGlzIChsYWJlbHMgYXMtaXMpLlxuZnVuY3Rpb24gcGVyaW9kQXhpc0xhYmVsKGdyYW51bGFyaXR5OiBDaGFydEdyYW51bGFyaXR5IHwgbnVsbCwgY2F0ZWdvcmllczogc3RyaW5nW10pOiB7IGF4aXNMYWJlbD86IFJlY29yZDxzdHJpbmcsIHVua25vd24+IH0ge1xuICBpZiAoIWdyYW51bGFyaXR5KSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgY29uc3QgbXVsdGlZZWFyID0gc3BhbnNNdWx0aXBsZVllYXJzKGNhdGVnb3JpZXMpO1xuXG4gIHJldHVybiB7XG4gICAgYXhpc0xhYmVsOiB7XG4gICAgICBmb3JtYXR0ZXI6ICh2YWx1ZTogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IHBhcnRzID0gcGVyaW9kTGFiZWxQYXJ0cyh2YWx1ZSwgZ3JhbnVsYXJpdHkpO1xuICAgICAgICBpZiAoIXBhcnRzKSB7XG4gICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG11bHRpWWVhciAmJiBncmFudWxhcml0eSAhPT0gJ3llYXInXG4gICAgICAgICAgPyBgJHtwYXJ0cy5wcmltYXJ5fVxcbnt5cnwke3BhcnRzLnllYXJ9fWBcbiAgICAgICAgICA6IHBhcnRzLnByaW1hcnk7XG4gICAgICB9LFxuICAgICAgcmljaDogeyB5cjogeyBmb250U2l6ZTogMTAsIGNvbG9yOiAnIzlhYTBhNicsIGxpbmVIZWlnaHQ6IDE0IH0gfSxcbiAgICB9LFxuICB9O1xufVxuIl19
@@ -0,0 +1,125 @@
1
+ import { ItemType } from '@firestitch/filter';
2
+ import { format } from 'date-fns';
3
+ import { of } from 'rxjs';
4
+ import { map, shareReplay } from 'rxjs/operators';
5
+ // A date-range boundary as the picked LOCAL calendar day (no time, no tz).
6
+ // Date-range filters are calendar-day semantics, so the boundary must carry
7
+ // only Y-M-D — never a timezone-bearing instant the backend would shift.
8
+ export function dateBoundString(value) {
9
+ if (value instanceof Date) {
10
+ return format(value, 'yyyy-MM-dd');
11
+ }
12
+ // Authored/relative defaults arrive as strings already in Y-M-D form;
13
+ // keep just the date portion.
14
+ return value ? String(value).slice(0, 10) : undefined;
15
+ }
16
+ // Maps a report filter GROUP to an fs-filter config item, and reads fs-filter
17
+ // query values back into per-group FilterGroupValues. Shared by the report-bar
18
+ // fs-filter and the per-component fs-filter so both render through the same
19
+ // library and write into ReportFilterStateService identically. Items are named
20
+ // `g<groupId>` so the query keys map straight back to the group.
21
+ //
22
+ // (Lists keep their own filters in FsList and name items `f<filterId>`; this is
23
+ // the group-keyed path for charts/KPIs and the report bar.)
24
+ // The query key fs-filter uses for a group's item(s).
25
+ const itemName = (group) => `g${group.id}`;
26
+ // Build the fs-filter config item for a group, seeding its default from the
27
+ // current session value so authored/relative defaults show selected on open.
28
+ export function filterItemForGroup(group, reportData, reportId, initial) {
29
+ const name = itemName(group);
30
+ const label = group.label || group.filters?.[0]?.filterColumn || '';
31
+ switch (group.type) {
32
+ case 'dateRange':
33
+ return {
34
+ name,
35
+ type: ItemType.DateRange,
36
+ label: { from: `${label} From`, to: `${label} To` },
37
+ default: (initial?.start || initial?.end)
38
+ ? { from: initial.start ?? undefined, to: initial.end ?? undefined }
39
+ : undefined,
40
+ };
41
+ case 'select': {
42
+ // Options come from the first member filter that declares them — members
43
+ // are the same data point, so any member's list serves the group.
44
+ const optionFilter = (group.filters ?? []).find((member) => member.hasOptions);
45
+ // The distinct option list is fetched once (server caps it) and replayed
46
+ // to every keystroke, so typing never refetches.
47
+ let options$ = null;
48
+ const loadOptions = () => {
49
+ if (!optionFilter) {
50
+ return of([]);
51
+ }
52
+ if (!options$) {
53
+ options$ = reportData.filterOptions(reportId, optionFilter.id)
54
+ .pipe(map((options) => (options ?? [])
55
+ .map((option) => ({ name: String(option), value: option }))), shareReplay({ bufferSize: 1, refCount: false }));
56
+ }
57
+ return options$;
58
+ };
59
+ return {
60
+ name,
61
+ type: ItemType.AutoCompleteChips,
62
+ label,
63
+ fetchOnFocus: true,
64
+ // fs-autocomplete renders whatever we return verbatim, so the typed
65
+ // keyword has to be matched here. Match case-insensitively against the
66
+ // displayed name — works for any select filter regardless of its column.
67
+ values: (keyword) => loadOptions()
68
+ .pipe(map((options) => {
69
+ const term = (keyword ?? '').trim().toLowerCase();
70
+ return term
71
+ ? options.filter((option) => option.name.toLowerCase().includes(term))
72
+ : options;
73
+ })),
74
+ default: initial?.values?.length
75
+ ? initial.values.map((value) => ({ name: String(value), value }))
76
+ : undefined,
77
+ };
78
+ }
79
+ case 'keyword':
80
+ default:
81
+ return {
82
+ name,
83
+ type: ItemType.Keyword,
84
+ label,
85
+ default: initial?.value,
86
+ };
87
+ }
88
+ }
89
+ // Read an fs-filter change query into per-group values. Returns one entry per
90
+ // group with the value to store (or null to clear) — callers feed these to
91
+ // ReportFilterStateService.setValue.
92
+ export function groupValuesFromQuery(query, groups) {
93
+ return groups.map((group) => {
94
+ const name = itemName(group);
95
+ if (group.type === 'dateRange') {
96
+ const start = query[`${name}From`];
97
+ const end = query[`${name}To`];
98
+ return {
99
+ groupId: group.id,
100
+ value: (start || end) ? { start: start || null, end: end || null } : null,
101
+ };
102
+ }
103
+ if (group.type === 'select') {
104
+ const values = selectQueryValues(query[name]);
105
+ return { groupId: group.id, value: values.length ? { values } : null };
106
+ }
107
+ const keyword = String(query[name] ?? '').trim();
108
+ return { groupId: group.id, value: keyword ? { value: keyword } : null };
109
+ });
110
+ }
111
+ // fs-filter's AutoCompleteChips serialises a multi-select into ONE query value:
112
+ // the selected values joined by "," (its `query` getter does `.map(value).join(',')`).
113
+ // So a 2+ selection arrives as the string "a,b", not an array — splitting on ","
114
+ // reverses that faithfully. Without this, a multi-select was sent as the single
115
+ // value ["a,b"], producing `col IN ('a,b')` server-side, which matches nothing.
116
+ function selectQueryValues(raw) {
117
+ if (Array.isArray(raw)) {
118
+ return raw;
119
+ }
120
+ if (raw === null || raw === undefined || raw === '') {
121
+ return [];
122
+ }
123
+ return String(raw).split(',');
124
+ }
125
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LWZpbHRlci1pdGVtcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy9yZXBvcnQtZmlsdGVyLWl0ZW1zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBcUIsUUFBUSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFakUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUVsQyxPQUFPLEVBQWMsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxHQUFHLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFNbEQsMkVBQTJFO0FBQzNFLDRFQUE0RTtBQUM1RSx5RUFBeUU7QUFDekUsTUFBTSxVQUFVLGVBQWUsQ0FBQyxLQUF1QztJQUNyRSxJQUFJLEtBQUssWUFBWSxJQUFJLEVBQUUsQ0FBQztRQUMxQixPQUFPLE1BQU0sQ0FBQyxLQUFLLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVELHNFQUFzRTtJQUN0RSw4QkFBOEI7SUFDOUIsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDeEQsQ0FBQztBQUdELDhFQUE4RTtBQUM5RSwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSxpRUFBaUU7QUFDakUsRUFBRTtBQUNGLGdGQUFnRjtBQUNoRiw0REFBNEQ7QUFFNUQsc0RBQXNEO0FBQ3RELE1BQU0sUUFBUSxHQUFHLENBQUMsS0FBd0IsRUFBVSxFQUFFLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUM7QUFFdEUsNEVBQTRFO0FBQzVFLDZFQUE2RTtBQUM3RSxNQUFNLFVBQVUsa0JBQWtCLENBQ2hDLEtBQXdCLEVBQ3hCLFVBQXNC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IjpbImltcG9ydCB7IElGaWx0ZXJDb25maWdJdGVtLCBJdGVtVHlwZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2ZpbHRlcic7XG5cbmltcG9ydCB7IGZvcm1hdCB9IGZyb20gJ2RhdGUtZm5zJztcblxuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCwgc2hhcmVSZXBsYXkgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IFJlcG9ydERhdGEgfSBmcm9tICcuL2RhdGEvcmVwb3J0LmRhdGEnO1xuaW1wb3J0IHsgRmlsdGVyR3JvdXBWYWx1ZSwgUmVwb3J0RmlsdGVyR3JvdXAgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5cblxuLy8gQSBkYXRlLXJhbmdlIGJvdW5kYXJ5IGFzIHRoZSBwaWNrZWQgTE9DQUwgY2FsZW5kYXIgZGF5IChubyB0aW1lLCBubyB0eikuXG4vLyBEYXRlLXJhbmdlIGZpbHRlcnMgYXJlIGNhbGVuZGFyLWRheSBzZW1hbnRpY3MsIHNvIHRoZSBib3VuZGFyeSBtdXN0IGNhcnJ5XG4vLyBvbmx5IFktTS1EIOKAlCBuZXZlciBhIHRpbWV6b25lLWJlYXJpbmcgaW5zdGFudCB0aGUgYmFja2VuZCB3b3VsZCBzaGlmdC5cbmV4cG9ydCBmdW5jdGlvbiBkYXRlQm91bmRTdHJpbmcodmFsdWU6IERhdGUgfCBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHZhbHVlIGluc3RhbmNlb2YgRGF0ZSkge1xuICAgIHJldHVybiBmb3JtYXQodmFsdWUsICd5eXl5LU1NLWRkJyk7XG4gIH1cblxuICAvLyBBdXRob3JlZC9yZWxhdGl2ZSBkZWZhdWx0cyBhcnJpdmUgYXMgc3RyaW5ncyBhbHJlYWR5IGluIFktTS1EIGZvcm07XG4gIC8vIGtlZXAganVzdCB0aGUgZGF0ZSBwb3J0aW9uLlxuICByZXR1cm4gdmFsdWUgPyBTdHJpbmcodmFsdWUpLnNsaWNlKDAsIDEwKSA6IHVuZGVmaW5lZDtcbn1cblxuXG4vLyBNYXBzIGEgcmVwb3J0IGZpbHRlciBHUk9VUCB0byBhbiBmcy1maWx0ZXIgY29uZmlnIGl0ZW0sIGFuZCByZWFkcyBmcy1maWx0ZXJcbi8vIHF1ZXJ5IHZhbHVlcyBiYWNrIGludG8gcGVyLWdyb3VwIEZpbHRlckdyb3VwVmFsdWVzLiBTaGFyZWQgYnkgdGhlIHJlcG9ydC1iYXJcbi8vIGZzLWZpbHRlciBhbmQgdGhlIHBlci1jb21wb25lbnQgZnMtZmlsdGVyIHNvIGJvdGggcmVuZGVyIHRocm91Z2ggdGhlIHNhbWVcbi8vIGxpYnJhcnkgYW5kIHdyaXRlIGludG8gUmVwb3J0RmlsdGVyU3RhdGVTZXJ2aWNlIGlkZW50aWNhbGx5LiBJdGVtcyBhcmUgbmFtZWRcbi8vIGBnPGdyb3VwSWQ+YCBzbyB0aGUgcXVlcnkga2V5cyBtYXAgc3RyYWlnaHQgYmFjayB0byB0aGUgZ3JvdXAuXG4vL1xuLy8gKExpc3RzIGtlZXAgdGhlaXIgb3duIGZpbHRlcnMgaW4gRnNMaXN0IGFuZCBuYW1lIGl0ZW1zIGBmPGZpbHRlcklkPmA7IHRoaXMgaXNcbi8vIHRoZSBncm91cC1rZXllZCBwYXRoIGZvciBjaGFydHMvS1BJcyBhbmQgdGhlIHJlcG9ydCBiYXIuKVxuXG4vLyBUaGUgcXVlcnkga2V5IGZzLWZpbHRlciB1c2VzIGZvciBhIGdyb3VwJ3MgaXRlbShzKS5cbmNvbnN0IGl0ZW1OYW1lID0gKGdyb3VwOiBSZXBvcnRGaWx0ZXJHcm91cCk6IHN0cmluZyA9PiBgZyR7Z3JvdXAuaWR9YDtcblxuLy8gQnVpbGQgdGhlIGZzLWZpbHRlciBjb25maWcgaXRlbSBmb3IgYSBncm91cCwgc2VlZGluZyBpdHMgZGVmYXVsdCBmcm9tIHRoZVxuLy8gY3VycmVudCBzZXNzaW9uIHZhbHVlIHNvIGF1dGhvcmVkL3JlbGF0aXZlIGRlZmF1bHRzIHNob3cgc2VsZWN0ZWQgb24gb3Blbi5cbmV4cG9ydCBmdW5jdGlvbiBmaWx0ZXJJdGVtRm9yR3JvdXAoXG4gIGdyb3VwOiBSZXBvcnRGaWx0ZXJHcm91cCxcbiAgcmVwb3J0RGF0YTogUmVwb3J0RGF0YSxcbiAgcmVwb3J0SWQ6IG51bWJlcixcbiAgaW5pdGlhbD86IEZpbHRlckdyb3VwVmFsdWUsXG4pOiBJRmlsdGVyQ29uZmlnSXRlbSB7XG4gIGNvbnN0IG5hbWUgPSBpdGVtTmFtZShncm91cCk7XG4gIGNvbnN0IGxhYmVsID0gZ3JvdXAubGFiZWwgfHwgZ3JvdXAuZmlsdGVycz8uWzBdPy5maWx0ZXJDb2x1bW4gfHwgJyc7XG5cbiAgc3dpdGNoIChncm91cC50eXBlKSB7XG4gICAgY2FzZSAnZGF0ZVJhbmdlJzpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIHR5cGU6IEl0ZW1UeXBlLkRhdGVSYW5nZSxcbiAgICAgICAgbGFiZWw6IHsgZnJvbTogYCR7bGFiZWx9IEZyb21gLCB0bzogYCR7bGFiZWx9IFRvYCB9LFxuICAgICAgICBkZWZhdWx0OiAoaW5pdGlhbD8uc3RhcnQgfHwgaW5pdGlhbD8uZW5kKVxuICAgICAgICAgID8geyBmcm9tOiBpbml0aWFsLnN0YXJ0ID8/IHVuZGVmaW5lZCwgdG86IGluaXRpYWwuZW5kID8/IHVuZGVmaW5lZCB9XG4gICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICB9O1xuXG4gICAgY2FzZSAnc2VsZWN0Jzoge1xuICAgICAgLy8gT3B0aW9ucyBjb21lIGZyb20gdGhlIGZpcnN0IG1lbWJlciBmaWx0ZXIgdGhhdCBkZWNsYXJlcyB0aGVtIOKAlCBtZW1iZXJzXG4gICAgICAvLyBhcmUgdGhlIHNhbWUgZGF0YSBwb2ludCwgc28gYW55IG1lbWJlcidzIGxpc3Qgc2VydmVzIHRoZSBncm91cC5cbiAgICAgIGNvbnN0IG9wdGlvbkZpbHRlciA9IChncm91cC5maWx0ZXJzID8/IFtdKS5maW5kKChtZW1iZXIpID0+IG1lbWJlci5oYXNPcHRpb25zKTtcblxuICAgICAgLy8gVGhlIGRpc3RpbmN0IG9wdGlvbiBsaXN0IGlzIGZldGNoZWQgb25jZSAoc2VydmVyIGNhcHMgaXQpIGFuZCByZXBsYXllZFxuICAgICAgLy8gdG8gZXZlcnkga2V5c3Ryb2tlLCBzbyB0eXBpbmcgbmV2ZXIgcmVmZXRjaGVzLlxuICAgICAgbGV0IG9wdGlvbnMkOiBPYnNlcnZhYmxlPHsgbmFtZTogc3RyaW5nOyB2YWx1ZTogdW5rbm93biB9W10+IHwgbnVsbCA9IG51bGw7XG4gICAgICBjb25zdCBsb2FkT3B0aW9ucyA9ICgpID0+IHtcbiAgICAgICAgaWYgKCFvcHRpb25GaWx0ZXIpIHtcbiAgICAgICAgICByZXR1cm4gb2YoW10gYXMgeyBuYW1lOiBzdHJpbmc7IHZhbHVlOiB1bmtub3duIH1bXSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIW9wdGlvbnMkKSB7XG4gICAgICAgICAgb3B0aW9ucyQgPSByZXBvcnREYXRhLmZpbHRlck9wdGlvbnMocmVwb3J0SWQsIG9wdGlvbkZpbHRlci5pZClcbiAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICBtYXAoKG9wdGlvbnM6IHVua25vd25bXSkgPT4gKG9wdGlvbnMgPz8gW10pXG4gICAgICAgICAgICAgICAgLm1hcCgob3B0aW9uKSA9PiAoeyBuYW1lOiBTdHJpbmcob3B0aW9uKSwgdmFsdWU6IG9wdGlvbiB9KSkpLFxuICAgICAgICAgICAgICBzaGFyZVJlcGxheSh7IGJ1ZmZlclNpemU6IDEsIHJlZkNvdW50OiBmYWxzZSB9KSxcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gb3B0aW9ucyQ7XG4gICAgICB9O1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBuYW1lLFxuICAgICAgICB0eXBlOiBJdGVtVHlwZS5BdXRvQ29tcGxldGVDaGlwcyxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIGZldGNoT25Gb2N1czogdHJ1ZSxcbiAgICAgICAgLy8gZnMtYXV0b2NvbXBsZXRlIHJlbmRlcnMgd2hhdGV2ZXIgd2UgcmV0dXJuIHZlcmJhdGltLCBzbyB0aGUgdHlwZWRcbiAgICAgICAgLy8ga2V5d29yZCBoYXMgdG8gYmUgbWF0Y2hlZCBoZXJlLiBNYXRjaCBjYXNlLWluc2Vuc2l0aXZlbHkgYWdhaW5zdCB0aGVcbiAgICAgICAgLy8gZGlzcGxheWVkIG5hbWUg4oCUIHdvcmtzIGZvciBhbnkgc2VsZWN0IGZpbHRlciByZWdhcmRsZXNzIG9mIGl0cyBjb2x1bW4uXG4gICAgICAgIHZhbHVlczogKGtleXdvcmQ/OiBzdHJpbmcpID0+IGxvYWRPcHRpb25zKClcbiAgICAgICAgICAucGlwZShtYXAoKG9wdGlvbnMpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHRlcm0gPSAoa2V5d29yZCA/PyAnJykudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG5cbiAgICAgICAgICAgIHJldHVybiB0ZXJtXG4gICAgICAgICAgICAgID8gb3B0aW9ucy5maWx0ZXIoKG9wdGlvbikgPT4gb3B0aW9uLm5hbWUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyh0ZXJtKSlcbiAgICAgICAgICAgICAgOiBvcHRpb25zO1xuICAgICAgICAgIH0pKSxcbiAgICAgICAgZGVmYXVsdDogaW5pdGlhbD8udmFsdWVzPy5sZW5ndGhcbiAgICAgICAgICA/IGluaXRpYWwudmFsdWVzLm1hcCgodmFsdWUpID0+ICh7IG5hbWU6IFN0cmluZyh2YWx1ZSksIHZhbHVlIH0pKVxuICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjYXNlICdrZXl3b3JkJzpcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZSxcbiAgICAgICAgdHlwZTogSXRlbVR5cGUuS2V5d29yZCxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIGRlZmF1bHQ6IGluaXRpYWw/LnZhbHVlLFxuICAgICAgfTtcbiAgfVxufVxuXG4vLyBSZWFkIGFuIGZzLWZpbHRlciBjaGFuZ2UgcXVlcnkgaW50byBwZXItZ3JvdXAgdmFsdWVzLiBSZXR1cm5zIG9uZSBlbnRyeSBwZXJcbi8vIGdyb3VwIHdpdGggdGhlIHZhbHVlIHRvIHN0b3JlIChvciBudWxsIHRvIGNsZWFyKSDigJQgY2FsbGVycyBmZWVkIHRoZXNlIHRvXG4vLyBSZXBvcnRGaWx0ZXJTdGF0ZVNlcnZpY2Uuc2V0VmFsdWUuXG5leHBvcnQgZnVuY3Rpb24gZ3JvdXBWYWx1ZXNGcm9tUXVlcnkoXG4gIHF1ZXJ5OiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICBncm91cHM6IFJlcG9ydEZpbHRlckdyb3VwW10sXG4pOiB7IGdyb3VwSWQ6IG51bWJlcjsgdmFsdWU6IEZpbHRlckdyb3VwVmFsdWUgfCBudWxsIH1bXSB7XG4gIHJldHVybiBncm91cHMubWFwKChncm91cCkgPT4ge1xuICAgIGNvbnN0IG5hbWUgPSBpdGVtTmFtZShncm91cCk7XG5cbiAgICBpZiAoZ3JvdXAudHlwZSA9PT0gJ2RhdGVSYW5nZScpIHtcbiAgICAgIGNvbnN0IHN0YXJ0ID0gcXVlcnlbYCR7bmFtZX1Gcm9tYF07XG4gICAgICBjb25zdCBlbmQgPSBxdWVyeVtgJHtuYW1lfVRvYF07XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGdyb3VwSWQ6IGdyb3VwLmlkLFxuICAgICAgICB2YWx1ZTogKHN0YXJ0IHx8IGVuZCkgPyB7IHN0YXJ0OiBzdGFydCB8fCBudWxsLCBlbmQ6IGVuZCB8fCBudWxsIH0gOiBudWxsLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAoZ3JvdXAudHlwZSA9PT0gJ3NlbGVjdCcpIHtcbiAgICAgIGNvbnN0IHZhbHVlcyA9IHNlbGVjdFF1ZXJ5VmFsdWVzKHF1ZXJ5W25hbWVdKTtcblxuICAgICAgcmV0dXJuIHsgZ3JvdXBJZDogZ3JvdXAuaWQsIHZhbHVlOiB2YWx1ZXMubGVuZ3RoID8geyB2YWx1ZXMgfSA6IG51bGwgfTtcbiAgICB9XG5cbiAgICBjb25zdCBrZXl3b3JkID0gU3RyaW5nKHF1ZXJ5W25hbWVdID8/ICcnKS50cmltKCk7XG5cbiAgICByZXR1cm4geyBncm91cElkOiBncm91cC5pZCwgdmFsdWU6IGtleXdvcmQgPyB7IHZhbHVlOiBrZXl3b3JkIH0gOiBudWxsIH07XG4gIH0pO1xufVxuXG4vLyBmcy1maWx0ZXIncyBBdXRvQ29tcGxldGVDaGlwcyBzZXJpYWxpc2VzIGEgbXVsdGktc2VsZWN0IGludG8gT05FIHF1ZXJ5IHZhbHVlOlxuLy8gdGhlIHNlbGVjdGVkIHZhbHVlcyBqb2luZWQgYnkgXCIsXCIgKGl0cyBgcXVlcnlgIGdldHRlciBkb2VzIGAubWFwKHZhbHVlKS5qb2luKCcsJylgKS5cbi8vIFNvIGEgMisgc2VsZWN0aW9uIGFycml2ZXMgYXMgdGhlIHN0cmluZyBcImEsYlwiLCBub3QgYW4gYXJyYXkg4oCUIHNwbGl0dGluZyBvbiBcIixcIlxuLy8gcmV2ZXJzZXMgdGhhdCBmYWl0aGZ1bGx5LiBXaXRob3V0IHRoaXMsIGEgbXVsdGktc2VsZWN0IHdhcyBzZW50IGFzIHRoZSBzaW5nbGVcbi8vIHZhbHVlIFtcImEsYlwiXSwgcHJvZHVjaW5nIGBjb2wgSU4gKCdhLGInKWAgc2VydmVyLXNpZGUsIHdoaWNoIG1hdGNoZXMgbm90aGluZy5cbmZ1bmN0aW9uIHNlbGVjdFF1ZXJ5VmFsdWVzKHJhdzogdW5rbm93bik6IHVua25vd25bXSB7XG4gIGlmIChBcnJheS5pc0FycmF5KHJhdykpIHtcbiAgICByZXR1cm4gcmF3O1xuICB9XG5cbiAgaWYgKHJhdyA9PT0gbnVsbCB8fCByYXcgPT09IHVuZGVmaW5lZCB8fCByYXcgPT09ICcnKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgcmV0dXJuIFN0cmluZyhyYXcpLnNwbGl0KCcsJyk7XG59XG4iXX0=