@firestitch/report 18.10.1 → 18.10.2

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 (37) hide show
  1. package/app/reports/components/component-text/component-text.component.d.ts +1 -0
  2. package/app/reports/components/component-text/value-embed.plugin.d.ts +25 -1
  3. package/app/reports/components/report-canvas/report-canvas.component.d.ts +12 -0
  4. package/app/reports/components/report-component/report-component.component.d.ts +1 -0
  5. package/app/reports/data/report.data.d.ts +2 -2
  6. package/app/reports/dialogs/component-settings/component-settings.component.d.ts +13 -1
  7. package/app/reports/export/report-export-collector.service.d.ts +13 -5
  8. package/app/reports/export/report-filter-lines.d.ts +3 -0
  9. package/app/reports/filter-text.d.ts +8 -0
  10. package/app/reports/format.d.ts +1 -0
  11. package/app/reports/interfaces/report-export-lines-input.interface.d.ts +1 -0
  12. package/app/reports/report-filter-items.d.ts +9 -0
  13. package/app/reports/text.d.ts +16 -0
  14. package/esm2022/app/reports/components/component-text/component-text.component.mjs +34 -22
  15. package/esm2022/app/reports/components/component-text/value-embed.plugin.mjs +254 -42
  16. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +118 -13
  17. package/esm2022/app/reports/components/report-component/report-component.component.mjs +30 -11
  18. package/esm2022/app/reports/data/report.data.mjs +12 -7
  19. package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +57 -14
  20. package/esm2022/app/reports/export/report-export-collector.service.mjs +84 -33
  21. package/esm2022/app/reports/export/report-filter-lines.mjs +25 -8
  22. package/esm2022/app/reports/export/report-pdf.service.mjs +31 -21
  23. package/esm2022/app/reports/export/report-pptx.service.mjs +21 -11
  24. package/esm2022/app/reports/filter-text.mjs +154 -0
  25. package/esm2022/app/reports/format.mjs +3 -2
  26. package/esm2022/app/reports/interfaces/report-export-lines-input.interface.mjs +1 -1
  27. package/esm2022/app/reports/report-filter-items.mjs +24 -2
  28. package/esm2022/app/reports/text.mjs +59 -13
  29. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +14 -11
  30. package/esm2022/app/reports/views/report/report.component.mjs +15 -12
  31. package/fesm2022/{firestitch-report-echarts-DHEH_K_q.mjs → firestitch-report-echarts-CyHkFToO.mjs} +2 -2
  32. package/fesm2022/{firestitch-report-echarts-DHEH_K_q.mjs.map → firestitch-report-echarts-CyHkFToO.mjs.map} +1 -1
  33. package/fesm2022/{firestitch-report-firestitch-report-ZcHTnNKq.mjs → firestitch-report-firestitch-report-DftB7M1o.mjs} +2653 -1955
  34. package/fesm2022/firestitch-report-firestitch-report-DftB7M1o.mjs.map +1 -0
  35. package/fesm2022/firestitch-report.mjs +1 -1
  36. package/package.json +1 -1
  37. package/fesm2022/firestitch-report-firestitch-report-ZcHTnNKq.mjs.map +0 -1
@@ -0,0 +1,154 @@
1
+ import { isLastDayOfMonth } from 'date-fns';
2
+ import { excludes, filterChipValueText, valuePicks } from './export/report-filter-lines';
3
+ import { DAY_SHORT, MONTH_YEAR, formatLocalDate, writeDayRange } from './format';
4
+ import { dateBoundString, dateFromBound } from './report-filter-items';
5
+ // Filters inside text blocks: what each {{filter.<id>}} token reads as. The
6
+ // value is the viewer's current one for the group, the one the filter bar
7
+ // shows, so a heading follows a filter the moment it changes. Pure, so the
8
+ // canvas and both exports word a filter the same way.
9
+ // What a filter with neither a label nor a name is called.
10
+ const UNNAMED_FILTER = 'Filter';
11
+ // What a date range, or a select or number range with nothing in it, reads as.
12
+ const ALL_DATES_TEXT = 'All dates';
13
+ const ALL_TEXT = 'All';
14
+ // What a select leaving values out reads as before their names.
15
+ const ALL_EXCEPT_TEXT = 'All except';
16
+ // '2026': a whole calendar year.
17
+ const YEAR = { year: 'numeric' };
18
+ // The filter groups whose tokens a layer reads: every group but a page
19
+ // group, which belongs to its page (pageId; null for the header and footer,
20
+ // which belong to no page). Elsewhere its token reads the em dash, and the
21
+ // Insert field menus do not list it.
22
+ export function layerFilterGroups(groups, pageId) {
23
+ return groups.filter((group) => group.level !== 'page' || (!!pageId && group.pageId === pageId));
24
+ }
25
+ // Out of every group's fields, the ones a layer reads (layerFilterGroups): a
26
+ // file words every filter once and hands each page, and the header and
27
+ // footer, its own.
28
+ export function layerFilterFields(fields, groups, pageId) {
29
+ return Object.fromEntries(layerFilterGroups(groups, pageId)
30
+ .filter((group) => !!fields[group.id])
31
+ .map((group) => [group.id, fields[group.id]]));
32
+ }
33
+ // What a filter is called where an author picks and sees it (the Insert
34
+ // field menus and the editor's chips): its label, else its name, else
35
+ // 'Filter'.
36
+ export function filterFieldName(group) {
37
+ return group.label || group.name || UNNAMED_FILTER;
38
+ }
39
+ // Each of the groups as its token reads, by group id. value is a group's
40
+ // current value; names are the names of a select's picks (kept or left out):
41
+ // undefined while they load, null when they could not be read.
42
+ export function textFilterFields(groups, value, locale, names) {
43
+ return Object.fromEntries(groups.map((group) => {
44
+ const groupValue = value(group.id);
45
+ const picked = group.type === 'select' ? valuePicks(groupValue) : [];
46
+ return [group.id, textFilterField(group, groupValue, locale, picked.length ? names(group, picked) : [])];
47
+ }));
48
+ }
49
+ // What one filter token prints for a group's value, in the report's locale.
50
+ // - A date range fits the range: one whole calendar month 'September 2026',
51
+ // one whole quarter 'Q3 2026' (in English only: Intl has no word for a
52
+ // quarter, so another language writes it as its months), one whole year
53
+ // '2026', several whole months 'August – October 2026', any other days the
54
+ // day range ('Sep 1 – 15, 2026', one day that day). Only a start reads
55
+ // 'From Sep 1, 2026', only an end 'Until Sep 30, 2026', neither 'All dates'.
56
+ // The bounds are calendar days, the end the last one included, read as
57
+ // local midnight and written with no zone, so no day shifts.
58
+ // - A select and a number range read as their chip after its label
59
+ // (filterChipValueText): the picked names joined by ', ' (a blank row's
60
+ // pick by its label, 'No region'), '0 to 10', '0 or more', '50 or less'.
61
+ // A select leaving values out reads 'All except West, East'. Nothing
62
+ // picked or no end reads 'All'.
63
+ // - A keyword, its text, trimmed ('' when there is none).
64
+ export function filterFieldText(group, value, locale, names = []) {
65
+ switch (group.type) {
66
+ case 'dateRange':
67
+ return periodText(calendarDay(value?.start), calendarDay(value?.end), locale);
68
+ case 'keyword':
69
+ return value?.value?.trim() ?? '';
70
+ default:
71
+ return chosenText(value, locale, names);
72
+ }
73
+ }
74
+ // Whether two filter field sets read the same, so a recomputed set that
75
+ // changed nothing a token or an Insert field menu shows does not repaint
76
+ // every block.
77
+ export function sameFilterFields(a, b) {
78
+ if (a === b) {
79
+ return true;
80
+ }
81
+ if (!a || !b) {
82
+ return false;
83
+ }
84
+ const ids = Object.keys(a).map(Number);
85
+ return ids.length === Object.keys(b).length
86
+ && ids.every((id) => {
87
+ const other = b[id];
88
+ return !!other
89
+ && a[id].name === other.name
90
+ && a[id].order === other.order
91
+ && a[id].text === other.text
92
+ && !!a[id].loading === !!other.loading;
93
+ });
94
+ }
95
+ // One group's token. A select whose picked names have not arrived reads as
96
+ // loading, and one whose names could not be read has no text (the em dash).
97
+ function textFilterField(group, value, locale, names) {
98
+ const name = filterFieldName(group);
99
+ const order = group.order;
100
+ if (names === undefined) {
101
+ return { name, order, loading: true };
102
+ }
103
+ return names ? { name, order, text: filterFieldText(group, value, locale, names) } : { name, order };
104
+ }
105
+ // A select's picks or a number range's ends, in the chip's words.
106
+ function chosenText(value, locale, names) {
107
+ const text = filterChipValueText(value, { locale, names });
108
+ if (text === null) {
109
+ return ALL_TEXT;
110
+ }
111
+ return excludes(value) ? `${ALL_EXCEPT_TEXT} ${text}` : text;
112
+ }
113
+ // A date-range bound as the calendar day the filter sends the server
114
+ // (dateBoundString), read as local midnight, or null for none.
115
+ function calendarDay(bound) {
116
+ return dateFromBound(dateBoundString(bound));
117
+ }
118
+ function periodText(start, end, locale) {
119
+ if (start && end) {
120
+ return start <= end ? rangeText(start, end, locale) : rangeText(end, start, locale);
121
+ }
122
+ if (start) {
123
+ return `From ${formatLocalDate(start, locale, DAY_SHORT)}`;
124
+ }
125
+ return end ? `Until ${formatLocalDate(end, locale, DAY_SHORT)}` : ALL_DATES_TEXT;
126
+ }
127
+ // The days from first to last, both included, first not after last.
128
+ function rangeText(first, last, locale) {
129
+ const months = wholeMonths(first, last);
130
+ const quarterStart = first.getMonth() % 3 === 0;
131
+ if (months === 1) {
132
+ return formatLocalDate(first, locale, MONTH_YEAR);
133
+ }
134
+ if (months === 12 && first.getMonth() === 0) {
135
+ return formatLocalDate(first, locale, YEAR);
136
+ }
137
+ if (months === 3 && quarterStart && isEnglish(locale)) {
138
+ return `Q${first.getMonth() / 3 + 1} ${formatLocalDate(first, locale, YEAR)}`;
139
+ }
140
+ return writeDayRange(first, last, locale, months ? MONTH_YEAR : DAY_SHORT);
141
+ }
142
+ // How many whole calendar months the days cover: none unless they start on a
143
+ // month's first day and end on a month's last.
144
+ function wholeMonths(first, last) {
145
+ if (first.getDate() !== 1 || !isLastDayOfMonth(last)) {
146
+ return 0;
147
+ }
148
+ return (last.getFullYear() - first.getFullYear()) * 12 + last.getMonth() - first.getMonth() + 1;
149
+ }
150
+ // Whether the locale's language is English, the one a quarter is written in.
151
+ function isEnglish(locale) {
152
+ return locale.split('-')[0].toLowerCase() === 'en';
153
+ }
154
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyLXRleHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXBwL3JlcG9ydHMvZmlsdGVyLXRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRTVDLE9BQU8sRUFBRSxRQUFRLEVBQUUsbUJBQW1CLEVBQUUsVUFBVSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDekYsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUVqRixPQUFPLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBSXZFLDRFQUE0RTtBQUM1RSwwRUFBMEU7QUFDMUUsMkVBQTJFO0FBQzNFLHNEQUFzRDtBQUV0RCwyREFBMkQ7QUFDM0QsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDO0FBRWhDLCtFQUErRTtBQUMvRSxNQUFNLGNBQWMsR0FBRyxXQUFXLENBQUM7QUFDbkMsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDO0FBRXZCLGdFQUFnRTtBQUNoRSxNQUFNLGVBQWUsR0FBRyxZQUFZLENBQUM7QUFFckMsaUNBQWlDO0FBQ2pDLE1BQU0sSUFBSSxHQUErQixFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsQ0FBQztBQUU3RCx1RUFBdUU7QUFDdkUsNEVBQTRFO0FBQzVFLDJFQUEyRTtBQUMzRSxxQ0FBcUM7QUFDckMsTUFBTSxVQUFVLGlCQUFpQixDQUFDLE1BQTJCLEVBQUUsTUFBcUI7SUFDbEYsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLE1BQU0sSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDO0FBQ25HLENB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O0FBQzdFLCtDQUErQztBQUMvQyxTQUFTLFdBQVcsQ0FBQyxLQUFXLEVBQUUsSUFBVTtJQUMxQyxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ3JELE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUVELE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQ2xHLENBQUM7QUFFRCw2RUFBNkU7QUFDN0UsU0FBUyxTQUFTLENBQUMsTUFBdUI7SUFDeEMsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLElBQUksQ0FBQztBQUNyRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNMYXN0RGF5T2ZNb250aCB9IGZyb20gJ2RhdGUtZm5zJztcblxuaW1wb3J0IHsgZXhjbHVkZXMsIGZpbHRlckNoaXBWYWx1ZVRleHQsIHZhbHVlUGlja3MgfSBmcm9tICcuL2V4cG9ydC9yZXBvcnQtZmlsdGVyLWxpbmVzJztcbmltcG9ydCB7IERBWV9TSE9SVCwgTU9OVEhfWUVBUiwgZm9ybWF0TG9jYWxEYXRlLCB3cml0ZURheVJhbmdlIH0gZnJvbSAnLi9mb3JtYXQnO1xuaW1wb3J0IHsgRmlsdGVyR3JvdXBWYWx1ZSwgUmVwb3J0RmlsdGVyR3JvdXAsIFJlcG9ydExvY2FsZVRhZyB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQuaW50ZXJmYWNlJztcbmltcG9ydCB7IGRhdGVCb3VuZFN0cmluZywgZGF0ZUZyb21Cb3VuZCB9IGZyb20gJy4vcmVwb3J0LWZpbHRlci1pdGVtcyc7XG5pbXBvcnQgeyBUZXh0RmlsdGVyRmllbGQgfSBmcm9tICcuL3RleHQnO1xuXG5cbi8vIEZpbHRlcnMgaW5zaWRlIHRleHQgYmxvY2tzOiB3aGF0IGVhY2gge3tmaWx0ZXIuPGlkPn19IHRva2VuIHJlYWRzIGFzLiBUaGVcbi8vIHZhbHVlIGlzIHRoZSB2aWV3ZXIncyBjdXJyZW50IG9uZSBmb3IgdGhlIGdyb3VwLCB0aGUgb25lIHRoZSBmaWx0ZXIgYmFyXG4vLyBzaG93cywgc28gYSBoZWFkaW5nIGZvbGxvd3MgYSBmaWx0ZXIgdGhlIG1vbWVudCBpdCBjaGFuZ2VzLiBQdXJlLCBzbyB0aGVcbi8vIGNhbnZhcyBhbmQgYm90aCBleHBvcnRzIHdvcmQgYSBmaWx0ZXIgdGhlIHNhbWUgd2F5LlxuXG4vLyBXaGF0IGEgZmlsdGVyIHdpdGggbmVpdGhlciBhIGxhYmVsIG5vciBhIG5hbWUgaXMgY2FsbGVkLlxuY29uc3QgVU5OQU1FRF9GSUxURVIgPSAnRmlsdGVyJztcblxuLy8gV2hhdCBhIGRhdGUgcmFuZ2UsIG9yIGEgc2VsZWN0IG9yIG51bWJlciByYW5nZSB3aXRoIG5vdGhpbmcgaW4gaXQsIHJlYWRzIGFzLlxuY29uc3QgQUxMX0RBVEVTX1RFWFQgPSAnQWxsIGRhdGVzJztcbmNvbnN0IEFMTF9URVhUID0gJ0FsbCc7XG5cbi8vIFdoYXQgYSBzZWxlY3QgbGVhdmluZyB2YWx1ZXMgb3V0IHJlYWRzIGFzIGJlZm9yZSB0aGVpciBuYW1lcy5cbmNvbnN0IEFMTF9FWENFUFRfVEVYVCA9ICdBbGwgZXhjZXB0JztcblxuLy8gJzIwMjYnOiBhIHdob2xlIGNhbGVuZGFyIHllYXIuXG5jb25zdCBZRUFSOiBJbnRsLkRhdGVUaW1lRm9ybWF0T3B0aW9ucyA9IHsgeWVhcjogJ251bWVyaWMnIH07XG5cbi8vIFRoZSBmaWx0ZXIgZ3JvdXBzIHdob3NlIHRva2VucyBhIGxheWVyIHJlYWRzOiBldmVyeSBncm91cCBidXQgYSBwYWdlXG4vLyBncm91cCwgd2hpY2ggYmVsb25ncyB0byBpdHMgcGFnZSAocGFnZUlkOyBudWxsIGZvciB0aGUgaGVhZGVyIGFuZCBmb290ZXIsXG4vLyB3aGljaCBiZWxvbmcgdG8gbm8gcGFnZSkuIEVsc2V3aGVyZSBpdHMgdG9rZW4gcmVhZHMgdGhlIGVtIGRhc2gsIGFuZCB0aGVcbi8vIEluc2VydCBmaWVsZCBtZW51cyBkbyBub3QgbGlzdCBpdC5cbmV4cG9ydCBmdW5jdGlvbiBsYXllckZpbHRlckdyb3Vwcyhncm91cHM6IFJlcG9ydEZpbHRlckdyb3VwW10sIHBhZ2VJZDogbnVtYmVyIHwgbnVsbCk6IFJlcG9ydEZpbHRlckdyb3VwW10ge1xuICByZXR1cm4gZ3JvdXBzLmZpbHRlcigoZ3JvdXApID0+IGdyb3VwLmxldmVsICE9PSAncGFnZScgfHwgKCEhcGFnZUlkICYmIGdyb3VwLnBhZ2VJZCA9PT0gcGFnZUlkKSk7XG59XG5cbi8vIE91dCBvZiBldmVyeSBncm91cCdzIGZpZWxkcywgdGhlIG9uZXMgYSBsYXllciByZWFkcyAobGF5ZXJGaWx0ZXJHcm91cHMpOiBhXG4vLyBmaWxlIHdvcmRzIGV2ZXJ5IGZpbHRlciBvbmNlIGFuZCBoYW5kcyBlYWNoIHBhZ2UsIGFuZCB0aGUgaGVhZGVyIGFuZFxuLy8gZm9vdGVyLCBpdHMgb3duLlxuZXhwb3J0IGZ1bmN0aW9uIGxheWVyRmlsdGVyRmllbGRzKFxuICBmaWVsZHM6IFJlY29yZDxudW1iZXIsIFRleHRGaWx0ZXJGaWVsZD4sXG4gIGdyb3VwczogUmVwb3J0RmlsdGVyR3JvdXBbXSxcbiAgcGFnZUlkOiBudW1iZXIgfCBudWxsLFxuKTogUmVjb3JkPG51bWJlciwgVGV4dEZpbHRlckZpZWxkPiB7XG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMobGF5ZXJGaWx0ZXJHcm91cHMoZ3JvdXBzLCBwYWdlSWQpXG4gICAgLmZpbHRlcigoZ3JvdXApID0+ICEhZmllbGRzW2dyb3VwLmlkXSlcbiAgICAubWFwKChncm91cCkgPT4gW2dyb3VwLmlkLCBmaWVsZHNbZ3JvdXAuaWRdXSkpO1xufVxuXG4vLyBXaGF0IGEgZmlsdGVyIGlzIGNhbGxlZCB3aGVyZSBhbiBhdXRob3IgcGlja3MgYW5kIHNlZXMgaXQgKHRoZSBJbnNlcnRcbi8vIGZpZWxkIG1lbnVzIGFuZCB0aGUgZWRpdG9yJ3MgY2hpcHMpOiBpdHMgbGFiZWwsIGVsc2UgaXRzIG5hbWUsIGVsc2Vcbi8vICdGaWx0ZXInLlxuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlckZpZWxkTmFtZShncm91cDogUGljazxSZXBvcnRGaWx0ZXJHcm91cCwgJ2xhYmVsJyB8ICduYW1lJz4pOiBzdHJpbmcge1xuICByZXR1cm4gZ3JvdXAubGFiZWwgfHwgZ3JvdXAubmFtZSB8fCBVTk5BTUVEX0ZJTFRFUjtcbn1cblxuLy8gRWFjaCBvZiB0aGUgZ3JvdXBzIGFzIGl0cyB0b2tlbiByZWFkcywgYnkgZ3JvdXAgaWQuIHZhbHVlIGlzIGEgZ3JvdXAnc1xuLy8gY3VycmVudCB2YWx1ZTsgbmFtZXMgYXJlIHRoZSBuYW1lcyBvZiBhIHNlbGVjdCdzIHBpY2tzIChrZXB0IG9yIGxlZnQgb3V0KTpcbi8vIHVuZGVmaW5lZCB3aGlsZSB0aGV5IGxvYWQsIG51bGwgd2hlbiB0aGV5IGNvdWxkIG5vdCBiZSByZWFkLlxuZXhwb3J0IGZ1bmN0aW9uIHRleHRGaWx0ZXJGaWVsZHMoXG4gIGdyb3VwczogUmVwb3J0RmlsdGVyR3JvdXBbXSxcbiAgdmFsdWU6IChncm91cElkOiBudW1iZXIpID0+IEZpbHRlckdyb3VwVmFsdWUgfCBudWxsIHwgdW5kZWZpbmVkLFxuICBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyxcbiAgbmFtZXM6IChncm91cDogUmVwb3J0RmlsdGVyR3JvdXAsIHZhbHVlczogdW5rbm93bltdKSA9PiByZWFkb25seSBzdHJpbmdbXSB8IG51bGwgfCB1bmRlZmluZWQsXG4pOiBSZWNvcmQ8bnVtYmVyLCBUZXh0RmlsdGVyRmllbGQ+IHtcbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhncm91cHMubWFwKChncm91cCkgPT4ge1xuICAgIGNvbnN0IGdyb3VwVmFsdWUgPSB2YWx1ZShncm91cC5pZCk7XG4gICAgY29uc3QgcGlja2VkID0gZ3JvdXAudHlwZSA9PT0gJ3NlbGVjdCcgPyB2YWx1ZVBpY2tzKGdyb3VwVmFsdWUpIDogW107XG5cbiAgICByZXR1cm4gW2dyb3VwLmlkLCB0ZXh0RmlsdGVyRmllbGQoZ3JvdXAsIGdyb3VwVmFsdWUsIGxvY2FsZSwgcGlja2VkLmxlbmd0aCA/IG5hbWVzKGdyb3VwLCBwaWNrZWQpIDogW10pXTtcbiAgfSkpO1xufVxuXG4vLyBXaGF0IG9uZSBmaWx0ZXIgdG9rZW4gcHJpbnRzIGZvciBhIGdyb3VwJ3MgdmFsdWUsIGluIHRoZSByZXBvcnQncyBsb2NhbGUuXG4vLyAtIEEgZGF0ZSByYW5nZSBmaXRzIHRoZSByYW5nZTogb25lIHdob2xlIGNhbGVuZGFyIG1vbnRoICdTZXB0ZW1iZXIgMjAyNicsXG4vLyAgIG9uZSB3aG9sZSBxdWFydGVyICdRMyAyMDI2JyAoaW4gRW5nbGlzaCBvbmx5OiBJbnRsIGhhcyBubyB3b3JkIGZvciBhXG4vLyAgIHF1YXJ0ZXIsIHNvIGFub3RoZXIgbGFuZ3VhZ2Ugd3JpdGVzIGl0IGFzIGl0cyBtb250aHMpLCBvbmUgd2hvbGUgeWVhclxuLy8gICAnMjAyNicsIHNldmVyYWwgd2hvbGUgbW9udGhzICdBdWd1c3Qg4oCTIE9jdG9iZXIgMjAyNicsIGFueSBvdGhlciBkYXlzIHRoZVxuLy8gICBkYXkgcmFuZ2UgKCdTZXAgMSDigJMgMTUsIDIwMjYnLCBvbmUgZGF5IHRoYXQgZGF5KS4gT25seSBhIHN0YXJ0IHJlYWRzXG4vLyAgICdGcm9tIFNlcCAxLCAyMDI2Jywgb25seSBhbiBlbmQgJ1VudGlsIFNlcCAzMCwgMjAyNicsIG5laXRoZXIgJ0FsbCBkYXRlcycuXG4vLyAgIFRoZSBib3VuZHMgYXJlIGNhbGVuZGFyIGRheXMsIHRoZSBlbmQgdGhlIGxhc3Qgb25lIGluY2x1ZGVkLCByZWFkIGFzXG4vLyAgIGxvY2FsIG1pZG5pZ2h0IGFuZCB3cml0dGVuIHdpdGggbm8gem9uZSwgc28gbm8gZGF5IHNoaWZ0cy5cbi8vIC0gQSBzZWxlY3QgYW5kIGEgbnVtYmVyIHJhbmdlIHJlYWQgYXMgdGhlaXIgY2hpcCBhZnRlciBpdHMgbGFiZWxcbi8vICAgKGZpbHRlckNoaXBWYWx1ZVRleHQpOiB0aGUgcGlja2VkIG5hbWVzIGpvaW5lZCBieSAnLCAnIChhIGJsYW5rIHJvdydzXG4vLyAgIHBpY2sgYnkgaXRzIGxhYmVsLCAnTm8gcmVnaW9uJyksICcwIHRvIDEwJywgJzAgb3IgbW9yZScsICc1MCBvciBsZXNzJy5cbi8vICAgQSBzZWxlY3QgbGVhdmluZyB2YWx1ZXMgb3V0IHJlYWRzICdBbGwgZXhjZXB0IFdlc3QsIEVhc3QnLiBOb3RoaW5nXG4vLyAgIHBpY2tlZCBvciBubyBlbmQgcmVhZHMgJ0FsbCcuXG4vLyAtIEEga2V5d29yZCwgaXRzIHRleHQsIHRyaW1tZWQgKCcnIHdoZW4gdGhlcmUgaXMgbm9uZSkuXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyRmllbGRUZXh0KFxuICBncm91cDogUGljazxSZXBvcnRGaWx0ZXJHcm91cCwgJ3R5cGUnPixcbiAgdmFsdWU6IEZpbHRlckdyb3VwVmFsdWUgfCBudWxsIHwgdW5kZWZpbmVkLFxuICBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyxcbiAgbmFtZXM6IHJlYWRvbmx5IHN0cmluZ1tdID0gW10sXG4pOiBzdHJpbmcge1xuICBzd2l0Y2ggKGdyb3VwLnR5cGUpIHtcbiAgICBjYXNlICdkYXRlUmFuZ2UnOlxuICAgICAgcmV0dXJuIHBlcmlvZFRleHQoY2FsZW5kYXJEYXkodmFsdWU/LnN0YXJ0KSwgY2FsZW5kYXJEYXkodmFsdWU/LmVuZCksIGxvY2FsZSk7XG4gICAgY2FzZSAna2V5d29yZCc6XG4gICAgICByZXR1cm4gdmFsdWU/LnZhbHVlPy50cmltKCkgPz8gJyc7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBjaG9zZW5UZXh0KHZhbHVlLCBsb2NhbGUsIG5hbWVzKTtcbiAgfVxufVxuXG4vLyBXaGV0aGVyIHR3byBmaWx0ZXIgZmllbGQgc2V0cyByZWFkIHRoZSBzYW1lLCBzbyBhIHJlY29tcHV0ZWQgc2V0IHRoYXRcbi8vIGNoYW5nZWQgbm90aGluZyBhIHRva2VuIG9yIGFuIEluc2VydCBmaWVsZCBtZW51IHNob3dzIGRvZXMgbm90IHJlcGFpbnRcbi8vIGV2ZXJ5IGJsb2NrLlxuZXhwb3J0IGZ1bmN0aW9uIHNhbWVGaWx0ZXJGaWVsZHMoXG4gIGE6IFJlY29yZDxudW1iZXIsIFRleHRGaWx0ZXJGaWVsZD4gfCB1bmRlZmluZWQsXG4gIGI6IFJlY29yZDxudW1iZXIsIFRleHRGaWx0ZXJGaWVsZD4gfCB1bmRlZmluZWQsXG4pOiBib29sZWFuIHtcbiAgaWYgKGEgPT09IGIpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGlmICghYSB8fCAhYikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGNvbnN0IGlkcyA9IE9iamVjdC5rZXlzKGEpLm1hcChOdW1iZXIpO1xuXG4gIHJldHVybiBpZHMubGVuZ3RoID09PSBPYmplY3Qua2V5cyhiKS5sZW5ndGhcbiAgICAmJiBpZHMuZXZlcnkoKGlkKSA9PiB7XG4gICAgICBjb25zdCBvdGhlciA9IGJbaWRdO1xuXG4gICAgICByZXR1cm4gISFvdGhlclxuICAgICAgICAmJiBhW2lkXS5uYW1lID09PSBvdGhlci5uYW1lXG4gICAgICAgICYmIGFbaWRdLm9yZGVyID09PSBvdGhlci5vcmRlclxuICAgICAgICAmJiBhW2lkXS50ZXh0ID09PSBvdGhlci50ZXh0XG4gICAgICAgICYmICEhYVtpZF0ubG9hZGluZyA9PT0gISFvdGhlci5sb2FkaW5nO1xuICAgIH0pO1xufVxuXG4vLyBPbmUgZ3JvdXAncyB0b2tlbi4gQSBzZWxlY3Qgd2hvc2UgcGlja2VkIG5hbWVzIGhhdmUgbm90IGFycml2ZWQgcmVhZHMgYXNcbi8vIGxvYWRpbmcsIGFuZCBvbmUgd2hvc2UgbmFtZXMgY291bGQgbm90IGJlIHJlYWQgaGFzIG5vIHRleHQgKHRoZSBlbSBkYXNoKS5cbmZ1bmN0aW9uIHRleHRGaWx0ZXJGaWVsZChcbiAgZ3JvdXA6IFJlcG9ydEZpbHRlckdyb3VwLFxuICB2YWx1ZTogRmlsdGVyR3JvdXBWYWx1ZSB8IG51bGwgfCB1bmRlZmluZWQsXG4gIGxvY2FsZTogUmVwb3J0TG9jYWxlVGFnLFxuICBuYW1lczogcmVhZG9ubHkgc3RyaW5nW10gfCBudWxsIHwgdW5kZWZpbmVkLFxuKTogVGV4dEZpbHRlckZpZWxkIHtcbiAgY29uc3QgbmFtZSA9IGZpbHRlckZpZWxkTmFtZShncm91cCk7XG4gIGNvbnN0IG9yZGVyID0gZ3JvdXAub3JkZXI7XG5cbiAgaWYgKG5hbWVzID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4geyBuYW1lLCBvcmRlciwgbG9hZGluZzogdHJ1ZSB9O1xuICB9XG5cbiAgcmV0dXJuIG5hbWVzID8geyBuYW1lLCBvcmRlciwgdGV4dDogZmlsdGVyRmllbGRUZXh0KGdyb3VwLCB2YWx1ZSwgbG9jYWxlLCBuYW1lcykgfSA6IHsgbmFtZSwgb3JkZXIgfTtcbn1cblxuLy8gQSBzZWxlY3QncyBwaWNrcyBvciBhIG51bWJlciByYW5nZSdzIGVuZHMsIGluIHRoZSBjaGlwJ3Mgd29yZHMuXG5mdW5jdGlvbiBjaG9zZW5UZXh0KFxuICB2YWx1ZTogRmlsdGVyR3JvdXBWYWx1ZSB8IG51bGwgfCB1bmRlZmluZWQsXG4gIGxvY2FsZTogUmVwb3J0TG9jYWxlVGFnLFxuICBuYW1lczogcmVhZG9ubHkgc3RyaW5nW10sXG4pOiBzdHJpbmcge1xuICBjb25zdCB0ZXh0ID0gZmlsdGVyQ2hpcFZhbHVlVGV4dCh2YWx1ZSwgeyBsb2NhbGUsIG5hbWVzIH0pO1xuXG4gIGlmICh0ZXh0ID09PSBudWxsKSB7XG4gICAgcmV0dXJuIEFMTF9URVhUO1xuICB9XG5cbiAgcmV0dXJuIGV4Y2x1ZGVzKHZhbHVlKSA/IGAke0FMTF9FWENFUFRfVEVYVH0gJHt0ZXh0fWAgOiB0ZXh0O1xufVxuXG4vLyBBIGRhdGUtcmFuZ2UgYm91bmQgYXMgdGhlIGNhbGVuZGFyIGRheSB0aGUgZmlsdGVyIHNlbmRzIHRoZSBzZXJ2ZXJcbi8vIChkYXRlQm91bmRTdHJpbmcpLCByZWFkIGFzIGxvY2FsIG1pZG5pZ2h0LCBvciBudWxsIGZvciBub25lLlxuZnVuY3Rpb24gY2FsZW5kYXJEYXkoYm91bmQ6IERhdGUgfCBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogRGF0ZSB8IG51bGwge1xuICByZXR1cm4gZGF0ZUZyb21Cb3VuZChkYXRlQm91bmRTdHJpbmcoYm91bmQpKTtcbn1cblxuZnVuY3Rpb24gcGVyaW9kVGV4dChzdGFydDogRGF0ZSB8IG51bGwsIGVuZDogRGF0ZSB8IG51bGwsIGxvY2FsZTogUmVwb3J0TG9jYWxlVGFnKTogc3RyaW5nIHtcbiAgaWYgKHN0YXJ0ICYmIGVuZCkge1xuICAgIHJldHVybiBzdGFydCA8PSBlbmQgPyByYW5nZVRleHQoc3RhcnQsIGVuZCwgbG9jYWxlKSA6IHJhbmdlVGV4dChlbmQsIHN0YXJ0LCBsb2NhbGUpO1xuICB9XG5cbiAgaWYgKHN0YXJ0KSB7XG4gICAgcmV0dXJuIGBGcm9tICR7Zm9ybWF0TG9jYWxEYXRlKHN0YXJ0LCBsb2NhbGUsIERBWV9TSE9SVCl9YDtcbiAgfVxuXG4gIHJldHVybiBlbmQgPyBgVW50aWwgJHtmb3JtYXRMb2NhbERhdGUoZW5kLCBsb2NhbGUsIERBWV9TSE9SVCl9YCA6IEFMTF9EQVRFU19URVhUO1xufVxuXG4vLyBUaGUgZGF5cyBmcm9tIGZpcnN0IHRvIGxhc3QsIGJvdGggaW5jbHVkZWQsIGZpcnN0IG5vdCBhZnRlciBsYXN0LlxuZnVuY3Rpb24gcmFuZ2VUZXh0KGZpcnN0OiBEYXRlLCBsYXN0OiBEYXRlLCBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyk6IHN0cmluZyB7XG4gIGNvbnN0IG1vbnRocyA9IHdob2xlTW9udGhzKGZpcnN0LCBsYXN0KTtcbiAgY29uc3QgcXVhcnRlclN0YXJ0ID0gZmlyc3QuZ2V0TW9udGgoKSAlIDMgPT09IDA7XG5cbiAgaWYgKG1vbnRocyA9PT0gMSkge1xuICAgIHJldHVybiBmb3JtYXRMb2NhbERhdGUoZmlyc3QsIGxvY2FsZSwgTU9OVEhfWUVBUik7XG4gIH1cblxuICBpZiAobW9udGhzID09PSAxMiAmJiBmaXJzdC5nZXRNb250aCgpID09PSAwKSB7XG4gICAgcmV0dXJuIGZvcm1hdExvY2FsRGF0ZShmaXJzdCwgbG9jYWxlLCBZRUFSKTtcbiAgfVxuXG4gIGlmIChtb250aHMgPT09IDMgJiYgcXVhcnRlclN0YXJ0ICYmIGlzRW5nbGlzaChsb2NhbGUpKSB7XG4gICAgcmV0dXJuIGBRJHtmaXJzdC5nZXRNb250aCgpIC8gMyArIDF9ICR7Zm9ybWF0TG9jYWxEYXRlKGZpcnN0LCBsb2NhbGUsIFlFQVIpfWA7XG4gIH1cblxuICByZXR1cm4gd3JpdGVEYXlSYW5nZShmaXJzdCwgbGFzdCwgbG9jYWxlLCBtb250aHMgPyBNT05USF9ZRUFSIDogREFZX1NIT1JUKTtcbn1cblxuLy8gSG93IG1hbnkgd2hvbGUgY2FsZW5kYXIgbW9udGhzIHRoZSBkYXlzIGNvdmVyOiBub25lIHVubGVzcyB0aGV5IHN0YXJ0IG9uIGFcbi8vIG1vbnRoJ3MgZmlyc3QgZGF5IGFuZCBlbmQgb24gYSBtb250aCdzIGxhc3QuXG5mdW5jdGlvbiB3aG9sZU1vbnRocyhmaXJzdDogRGF0ZSwgbGFzdDogRGF0ZSk6IG51bWJlciB7XG4gIGlmIChmaXJzdC5nZXREYXRlKCkgIT09IDEgfHwgIWlzTGFzdERheU9mTW9udGgobGFzdCkpIHtcbiAgICByZXR1cm4gMDtcbiAgfVxuXG4gIHJldHVybiAobGFzdC5nZXRGdWxsWWVhcigpIC0gZmlyc3QuZ2V0RnVsbFllYXIoKSkgKiAxMiArIGxhc3QuZ2V0TW9udGgoKSAtIGZpcnN0LmdldE1vbnRoKCkgKyAxO1xufVxuXG4vLyBXaGV0aGVyIHRoZSBsb2NhbGUncyBsYW5ndWFnZSBpcyBFbmdsaXNoLCB0aGUgb25lIGEgcXVhcnRlciBpcyB3cml0dGVuIGluLlxuZnVuY3Rpb24gaXNFbmdsaXNoKGxvY2FsZTogUmVwb3J0TG9jYWxlVGFnKTogYm9vbGVhbiB7XG4gIHJldHVybiBsb2NhbGUuc3BsaXQoJy0nKVswXS50b0xvd2VyQ2FzZSgpID09PSAnZW4nO1xufVxuIl19