@firestitch/report 18.8.1 → 18.10.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 (208) hide show
  1. package/app/reports/anchor-at-point.d.ts +14 -0
  2. package/app/reports/canvas-landing-page.d.ts +2 -0
  3. package/app/reports/components/component-chart/component-chart.component.d.ts +18 -2
  4. package/app/reports/components/component-kpi/component-kpi.component.d.ts +4 -1
  5. package/app/reports/components/component-text/component-text.component.d.ts +47 -2
  6. package/app/reports/components/component-text/value-embed.plugin.d.ts +67 -0
  7. package/app/reports/components/report-canvas/report-canvas.component.d.ts +37 -9
  8. package/app/reports/components/report-component/report-component.component.d.ts +45 -2
  9. package/app/reports/components/report-view-picker/report-view-picker.component.d.ts +21 -0
  10. package/app/reports/data/report.data.d.ts +18 -2
  11. package/app/reports/dialogs/component-settings/component-settings.component.d.ts +25 -2
  12. package/app/reports/dialogs/report-settings/report-settings.component.d.ts +15 -6
  13. package/app/reports/dialogs/report-view/report-view-dialog.component.d.ts +13 -0
  14. package/app/reports/drill-crumbs.d.ts +12 -0
  15. package/app/reports/enums/report-value-formula.enum.d.ts +6 -0
  16. package/app/reports/export/report-export-collector.service.d.ts +35 -4
  17. package/app/reports/export/report-export.service.d.ts +3 -1
  18. package/app/reports/export/report-filter-lines.d.ts +18 -0
  19. package/app/reports/export/report-pdf.service.d.ts +18 -2
  20. package/app/reports/export/report-pptx.service.d.ts +15 -2
  21. package/app/reports/export/report-text-layout.service.d.ts +35 -0
  22. package/app/reports/filter-settings-rules.d.ts +33 -0
  23. package/app/reports/format.d.ts +2 -1
  24. package/app/reports/interfaces/canvas-landing-input.interface.d.ts +8 -0
  25. package/app/reports/interfaces/component-data-applied.interface.d.ts +13 -0
  26. package/app/reports/interfaces/component-data-drill.interface.d.ts +22 -0
  27. package/app/reports/interfaces/filter-bar-placement.type.d.ts +1 -0
  28. package/app/reports/interfaces/filter-component-toggle-state.interface.d.ts +4 -0
  29. package/app/reports/interfaces/filter-settings-option.interface.d.ts +4 -0
  30. package/app/reports/interfaces/filter-type-select-state.interface.d.ts +5 -0
  31. package/app/reports/interfaces/report-chart-hit.interface.d.ts +5 -0
  32. package/app/reports/interfaces/report-chat-viewer-cross-filter-field.interface.d.ts +4 -0
  33. package/app/reports/interfaces/report-chat-viewer-cross-filter.interface.d.ts +7 -0
  34. package/app/reports/interfaces/report-chat-viewer-detail.interface.d.ts +4 -0
  35. package/app/reports/interfaces/report-chat-viewer-drill-step.interface.d.ts +5 -0
  36. package/app/reports/interfaces/report-chat-viewer-drill.interface.d.ts +5 -0
  37. package/app/reports/interfaces/report-chat-viewer-filter.interface.d.ts +3 -0
  38. package/app/reports/interfaces/report-chat-viewer-selection.interface.d.ts +5 -0
  39. package/app/reports/interfaces/report-chat-viewer-state.interface.d.ts +12 -0
  40. package/app/reports/interfaces/report-drill-crumb.interface.d.ts +6 -0
  41. package/app/reports/interfaces/report-drill-refusal.type.d.ts +1 -0
  42. package/app/reports/interfaces/report-drill-step.interface.d.ts +5 -0
  43. package/app/reports/interfaces/report-export-line-kind.type.d.ts +1 -0
  44. package/app/reports/interfaces/report-export-line.interface.d.ts +8 -0
  45. package/app/reports/interfaces/report-export-lines-input.interface.d.ts +9 -0
  46. package/app/reports/interfaces/report-export-snapshot.interface.d.ts +15 -0
  47. package/app/reports/interfaces/report-filter-line-context.interface.d.ts +8 -0
  48. package/app/reports/interfaces/report-filter-line-form.type.d.ts +1 -0
  49. package/app/reports/interfaces/report-filter-match.type.d.ts +1 -0
  50. package/app/reports/interfaces/report-filter-option-pair.interface.d.ts +4 -0
  51. package/app/reports/interfaces/report-filter-options-ask.interface.d.ts +6 -0
  52. package/app/reports/interfaces/report-filter-options-list.interface.d.ts +7 -0
  53. package/app/reports/interfaces/report-filter-options-request.interface.d.ts +6 -0
  54. package/app/reports/interfaces/report-filter-options-stream.interface.d.ts +11 -0
  55. package/app/reports/interfaces/report-filter-options.interface.d.ts +7 -0
  56. package/app/reports/interfaces/report-filter-skip.type.d.ts +1 -0
  57. package/app/reports/interfaces/report-mark-action.type.d.ts +1 -0
  58. package/app/reports/interfaces/report-mark-click.interface.d.ts +13 -0
  59. package/app/reports/interfaces/report-mark-context.interface.d.ts +6 -0
  60. package/app/reports/interfaces/report-mark-decision.interface.d.ts +6 -0
  61. package/app/reports/interfaces/report-mark-event.interface.d.ts +11 -0
  62. package/app/reports/interfaces/report-mark-point.interface.d.ts +8 -0
  63. package/app/reports/interfaces/report-temporary-state.interface.d.ts +4 -0
  64. package/app/reports/interfaces/report-tile-state.interface.d.ts +8 -0
  65. package/app/reports/interfaces/report-url-link.interface.d.ts +4 -0
  66. package/app/reports/interfaces/report-url-value-name.type.d.ts +1 -0
  67. package/app/reports/interfaces/report-url-write.interface.d.ts +4 -0
  68. package/app/reports/interfaces/report-view-config.interface.d.ts +11 -0
  69. package/app/reports/interfaces/report-view-create.interface.d.ts +7 -0
  70. package/app/reports/interfaces/report-view-deleted.interface.d.ts +4 -0
  71. package/app/reports/interfaces/report-view-dialog-data.interface.d.ts +7 -0
  72. package/app/reports/interfaces/report-view-dropped.interface.d.ts +5 -0
  73. package/app/reports/interfaces/report-view-menu-item.interface.d.ts +10 -0
  74. package/app/reports/interfaces/report-view-summary.interface.d.ts +11 -0
  75. package/app/reports/interfaces/report-view.interface.d.ts +7 -0
  76. package/app/reports/interfaces/report-viewer-feature.type.d.ts +1 -0
  77. package/app/reports/interfaces/report-views.interface.d.ts +7 -0
  78. package/app/reports/interfaces/report.interface.d.ts +48 -5
  79. package/app/reports/interfaces/tile-load-result.interface.d.ts +4 -0
  80. package/app/reports/layout.d.ts +2 -0
  81. package/app/reports/mark-click.d.ts +20 -0
  82. package/app/reports/option-builder.d.ts +12 -1
  83. package/app/reports/report-chat-viewer-state.d.ts +8 -0
  84. package/app/reports/report-date-presets.d.ts +2 -0
  85. package/app/reports/report-filter-items.d.ts +27 -22
  86. package/app/reports/report-tile.d.ts +2 -0
  87. package/app/reports/report-url-state.d.ts +27 -10
  88. package/app/reports/report-view-config.d.ts +36 -0
  89. package/app/reports/report-view-menu.d.ts +15 -0
  90. package/app/reports/report-viewer-features.d.ts +5 -0
  91. package/app/reports/services/report-filter-options.service.d.ts +26 -0
  92. package/app/reports/services/report-filter-state.service.d.ts +65 -2
  93. package/app/reports/services/report-view.service.d.ts +51 -0
  94. package/app/reports/text.d.ts +50 -0
  95. package/app/reports/tile-data-state.d.ts +7 -0
  96. package/app/reports/tile-loads.d.ts +4 -0
  97. package/app/reports/values.d.ts +17 -0
  98. package/app/reports/views/report/fs-ai-report.component.d.ts +9 -1
  99. package/app/reports/views/report/report.component.d.ts +6 -0
  100. package/esm2022/app/reports/anchor-at-point.mjs +49 -0
  101. package/esm2022/app/reports/canvas-landing-page.mjs +25 -0
  102. package/esm2022/app/reports/components/component-chart/component-chart.component.mjs +97 -5
  103. package/esm2022/app/reports/components/component-kpi/component-kpi.component.mjs +11 -4
  104. package/esm2022/app/reports/components/component-list/component-list.component.mjs +7 -1
  105. package/esm2022/app/reports/components/component-text/component-text.component.mjs +213 -16
  106. package/esm2022/app/reports/components/component-text/value-embed.plugin.mjs +484 -0
  107. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +296 -55
  108. package/esm2022/app/reports/components/report-component/report-component.component.mjs +318 -76
  109. package/esm2022/app/reports/components/report-view-picker/report-view-picker.component.mjs +115 -0
  110. package/esm2022/app/reports/data/report.data.mjs +103 -8
  111. package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +210 -44
  112. package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +86 -90
  113. package/esm2022/app/reports/dialogs/report-view/report-view-dialog.component.mjs +52 -0
  114. package/esm2022/app/reports/drill-crumbs.mjs +73 -0
  115. package/esm2022/app/reports/enums/report-value-formula.enum.mjs +14 -0
  116. package/esm2022/app/reports/export/report-export-collector.service.mjs +299 -125
  117. package/esm2022/app/reports/export/report-export.service.mjs +57 -19
  118. package/esm2022/app/reports/export/report-filter-lines.mjs +235 -0
  119. package/esm2022/app/reports/export/report-pdf.service.mjs +315 -71
  120. package/esm2022/app/reports/export/report-pptx.service.mjs +293 -71
  121. package/esm2022/app/reports/export/report-text-layout.service.mjs +241 -0
  122. package/esm2022/app/reports/filter-settings-rules.mjs +283 -0
  123. package/esm2022/app/reports/format.mjs +13 -30
  124. package/esm2022/app/reports/interfaces/canvas-landing-input.interface.mjs +2 -0
  125. package/esm2022/app/reports/interfaces/component-data-applied.interface.mjs +2 -0
  126. package/esm2022/app/reports/interfaces/component-data-drill.interface.mjs +2 -0
  127. package/esm2022/app/reports/interfaces/filter-bar-placement.type.mjs +2 -0
  128. package/esm2022/app/reports/interfaces/filter-component-toggle-state.interface.mjs +2 -0
  129. package/esm2022/app/reports/interfaces/filter-settings-option.interface.mjs +2 -0
  130. package/esm2022/app/reports/interfaces/filter-type-select-state.interface.mjs +2 -0
  131. package/esm2022/app/reports/interfaces/report-chart-hit.interface.mjs +2 -0
  132. package/esm2022/app/reports/interfaces/report-chat-viewer-cross-filter-field.interface.mjs +2 -0
  133. package/esm2022/app/reports/interfaces/report-chat-viewer-cross-filter.interface.mjs +2 -0
  134. package/esm2022/app/reports/interfaces/report-chat-viewer-detail.interface.mjs +2 -0
  135. package/esm2022/app/reports/interfaces/report-chat-viewer-drill-step.interface.mjs +2 -0
  136. package/esm2022/app/reports/interfaces/report-chat-viewer-drill.interface.mjs +2 -0
  137. package/esm2022/app/reports/interfaces/report-chat-viewer-filter.interface.mjs +1 -1
  138. package/esm2022/app/reports/interfaces/report-chat-viewer-selection.interface.mjs +2 -0
  139. package/esm2022/app/reports/interfaces/report-chat-viewer-state.interface.mjs +1 -1
  140. package/esm2022/app/reports/interfaces/report-drill-crumb.interface.mjs +2 -0
  141. package/esm2022/app/reports/interfaces/report-drill-refusal.type.mjs +2 -0
  142. package/esm2022/app/reports/interfaces/report-drill-step.interface.mjs +2 -0
  143. package/esm2022/app/reports/interfaces/report-export-line-kind.type.mjs +2 -0
  144. package/esm2022/app/reports/interfaces/report-export-line.interface.mjs +2 -0
  145. package/esm2022/app/reports/interfaces/report-export-lines-input.interface.mjs +2 -0
  146. package/esm2022/app/reports/interfaces/report-export-snapshot.interface.mjs +2 -0
  147. package/esm2022/app/reports/interfaces/report-filter-line-context.interface.mjs +2 -0
  148. package/esm2022/app/reports/interfaces/report-filter-line-form.type.mjs +2 -0
  149. package/esm2022/app/reports/interfaces/report-filter-match.type.mjs +2 -0
  150. package/esm2022/app/reports/interfaces/report-filter-option-pair.interface.mjs +2 -0
  151. package/esm2022/app/reports/interfaces/report-filter-options-ask.interface.mjs +2 -0
  152. package/esm2022/app/reports/interfaces/report-filter-options-list.interface.mjs +2 -0
  153. package/esm2022/app/reports/interfaces/report-filter-options-request.interface.mjs +2 -0
  154. package/esm2022/app/reports/interfaces/report-filter-options-stream.interface.mjs +2 -0
  155. package/esm2022/app/reports/interfaces/report-filter-options.interface.mjs +2 -0
  156. package/esm2022/app/reports/interfaces/report-filter-skip.type.mjs +2 -0
  157. package/esm2022/app/reports/interfaces/report-mark-action.type.mjs +2 -0
  158. package/esm2022/app/reports/interfaces/report-mark-click.interface.mjs +2 -0
  159. package/esm2022/app/reports/interfaces/report-mark-context.interface.mjs +2 -0
  160. package/esm2022/app/reports/interfaces/report-mark-decision.interface.mjs +2 -0
  161. package/esm2022/app/reports/interfaces/report-mark-event.interface.mjs +2 -0
  162. package/esm2022/app/reports/interfaces/report-mark-point.interface.mjs +2 -0
  163. package/esm2022/app/reports/interfaces/report-temporary-state.interface.mjs +2 -0
  164. package/esm2022/app/reports/interfaces/report-tile-state.interface.mjs +2 -0
  165. package/esm2022/app/reports/interfaces/report-url-link.interface.mjs +2 -0
  166. package/esm2022/app/reports/interfaces/report-url-value-name.type.mjs +2 -0
  167. package/esm2022/app/reports/interfaces/report-url-write.interface.mjs +2 -0
  168. package/esm2022/app/reports/interfaces/report-view-config.interface.mjs +2 -0
  169. package/esm2022/app/reports/interfaces/report-view-create.interface.mjs +2 -0
  170. package/esm2022/app/reports/interfaces/report-view-deleted.interface.mjs +2 -0
  171. package/esm2022/app/reports/interfaces/report-view-dialog-data.interface.mjs +2 -0
  172. package/esm2022/app/reports/interfaces/report-view-dropped.interface.mjs +2 -0
  173. package/esm2022/app/reports/interfaces/report-view-menu-item.interface.mjs +2 -0
  174. package/esm2022/app/reports/interfaces/report-view-summary.interface.mjs +2 -0
  175. package/esm2022/app/reports/interfaces/report-view.interface.mjs +2 -0
  176. package/esm2022/app/reports/interfaces/report-viewer-feature.type.mjs +2 -0
  177. package/esm2022/app/reports/interfaces/report-views.interface.mjs +2 -0
  178. package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
  179. package/esm2022/app/reports/interfaces/tile-load-result.interface.mjs +2 -0
  180. package/esm2022/app/reports/layout.mjs +11 -1
  181. package/esm2022/app/reports/mark-click.mjs +193 -0
  182. package/esm2022/app/reports/option-builder.mjs +159 -15
  183. package/esm2022/app/reports/report-chat-viewer-state.mjs +34 -0
  184. package/esm2022/app/reports/report-date-presets.mjs +18 -0
  185. package/esm2022/app/reports/report-filter-items.mjs +343 -72
  186. package/esm2022/app/reports/report-tile.mjs +12 -0
  187. package/esm2022/app/reports/report-url-state.mjs +596 -108
  188. package/esm2022/app/reports/report-view-config.mjs +697 -0
  189. package/esm2022/app/reports/report-view-menu.mjs +119 -0
  190. package/esm2022/app/reports/report-viewer-features.mjs +42 -0
  191. package/esm2022/app/reports/services/report-filter-options.service.mjs +238 -0
  192. package/esm2022/app/reports/services/report-filter-state.service.mjs +715 -71
  193. package/esm2022/app/reports/services/report-view.service.mjs +358 -0
  194. package/esm2022/app/reports/text.mjs +293 -85
  195. package/esm2022/app/reports/tile-data-state.mjs +127 -0
  196. package/esm2022/app/reports/tile-loads.mjs +38 -0
  197. package/esm2022/app/reports/values.mjs +183 -0
  198. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +180 -46
  199. package/esm2022/app/reports/views/report/report.component.mjs +106 -23
  200. package/esm2022/public_api.mjs +24 -1
  201. package/fesm2022/{firestitch-report-echarts-CFnbJx44.mjs → firestitch-report-echarts-UBg8Wlhd.mjs} +2 -2
  202. package/fesm2022/{firestitch-report-echarts-CFnbJx44.mjs.map → firestitch-report-echarts-UBg8Wlhd.mjs.map} +1 -1
  203. package/fesm2022/{firestitch-report-firestitch-report-CSylkyko.mjs → firestitch-report-firestitch-report-B1keNrcK.mjs} +11315 -4201
  204. package/fesm2022/firestitch-report-firestitch-report-B1keNrcK.mjs.map +1 -0
  205. package/fesm2022/firestitch-report.mjs +1 -1
  206. package/package.json +1 -1
  207. package/public_api.d.ts +23 -0
  208. package/fesm2022/firestitch-report-firestitch-report-CSylkyko.mjs.map +0 -1
@@ -20,10 +20,14 @@ import { switchMap, tap } from 'rxjs/operators';
20
20
  import { ReportData } from '../../data/report.data';
21
21
  import { ReportChangePolarity } from '../../enums/report-change-polarity.enum';
22
22
  import { ReportValueFormat } from '../../enums/report-value-format.enum';
23
+ import { ReportValueFormula } from '../../enums/report-value-formula.enum';
23
24
  import { resolveFormatContext } from '../../format';
24
25
  import { KPI_SPARKLINE_DEFAULT_GRANULARITY, KPI_SPARKLINE_DEFAULT_PERIODS, kpiCardSettings, sameKpiCardSettings, } from '../../kpi-card';
25
26
  import { GRANULARITY_OPTIONS, } from '../../interfaces/report.interface';
26
27
  import { DEFAULT_COMPONENT_PADDING } from '../../layout';
28
+ import { FILTER_TYPE_OPTIONS, barPlacement, barPlacementOptions, componentToggleState, filterLevel, filterLevelChoices, shownOnComponent, typeSelectState, valueFilterLevel, valuePlacementOptions, } from '../../filter-settings-rules';
29
+ import { escapeHtml } from '../../text';
30
+ import { operandKeys, reportComponents, valueKey } from '../../values';
27
31
  import * as i0 from "@angular/core";
28
32
  import * as i1 from "@angular/forms";
29
33
  import * as i2 from "@firestitch/form";
@@ -45,8 +49,17 @@ const KPI_SPARKLINE_MAX_PERIODS = 60;
45
49
  // stored as the 0-1 ratio its value arrives in; the server refuses a stored
46
50
  // target above 100, which is 10,000% here.
47
51
  const KPI_PERCENT_TARGET_MAX = 10000;
52
+ // How a formula value's Settings tab writes out what it works out, in its
53
+ // operands' names.
54
+ const FORMULA_LINES = {
55
+ [ReportValueFormula.Change]: (names) => names.join(' − '),
56
+ [ReportValueFormula.PercentChange]: ([a, b]) => `% change of ${a} over ${b}`,
57
+ [ReportValueFormula.Ratio]: (names) => names.join(' ÷ '),
58
+ [ReportValueFormula.Sum]: (names) => names.join(' + '),
59
+ };
48
60
  // Component settings, in tabs:
49
- // Settings — title and content padding, and on a derived KPI its card:
61
+ // Settings — title and content padding (a value: just its name, since it
62
+ // sits inside a text block's words and has no box), and on a derived KPI its card:
50
63
  // what a rise means, a target and a sparkline (number formats stay with
51
64
  // the AI). Position/size are tuned by dragging on the canvas; height
52
65
  // behaviour follows from the component type.
@@ -54,8 +67,12 @@ const KPI_PERCENT_TARGET_MAX = 10000;
54
67
  // row carries two toggles: show in the report bar and/or show on this
55
68
  // component (both, either, or neither). The interface (date range vs value
56
69
  // picker) is inferred from the data, never chosen. Each toggle persists
57
- // immediately and refreshes the in-dialog list.
70
+ // immediately and refreshes the in-dialog list. A value has no component
71
+ // to show a filter on, so it gets the report bar toggle only.
58
72
  // SQL / Config — read-only diagnostics.
73
+ // A formula value has no Filters or SQL tab: the server works it out of other
74
+ // values on its page, so it runs no statement and follows the filters of the
75
+ // values it reads. Its Settings tab says what it works out, under its name.
59
76
  export class ComponentSettingsComponent {
60
77
  // A filter was added, removed or re-levelled, so the report's filter groups
61
78
  // changed. Those mutations persist the moment they are clicked and the dialog
@@ -80,6 +97,13 @@ export class ComponentSettingsComponent {
80
97
  sparklineMinPeriods = KPI_SPARKLINE_MIN_PERIODS;
81
98
  sparklineMaxPeriods = KPI_SPARKLINE_MAX_PERIODS;
82
99
  kpiCard = signal(false);
100
+ // A value inside a text block: no box, so no padding.
101
+ isValue = signal(false);
102
+ // A formula value: no statement, columns or filters of its own.
103
+ isFormula = signal(false);
104
+ // What a formula works out, in its operands' names; empty for any other
105
+ // component.
106
+ formulaLine = computed(() => (this.isFormula() ? this._formulaLine() : ''));
83
107
  increaseIs = signal(ReportChangePolarity.Good);
84
108
  // The target as typed: fsMaskNumber hands back the unmasked string. Empty
85
109
  // means no target. A percent KPI's is in percent (targetPercent).
@@ -104,19 +128,25 @@ export class ComponentSettingsComponent {
104
128
  sqlTimezone = signal('UTC');
105
129
  sqlError = signal(null);
106
130
  // ---- filter management state ----
107
- // One row per filterable column. The two booleans drive the toggles; we flip
108
- // them optimistically on click (so the UI never blinks while the request is
109
- // in flight) and reconcile from the server on reload.
131
+ // One row per filterable column. The placement and the toggle change
132
+ // optimistically on click (so the UI never blinks while the request is in
133
+ // flight) and reconcile from the server on reload.
110
134
  rows = signal([]);
111
135
  columnsError = signal(null);
136
+ // The Type select's choices. A row's Type select, Report bar select and
137
+ // This component toggle follow the rules in filter-settings-rules.ts.
138
+ typeOptions = FILTER_TYPE_OPTIONS;
112
139
  // The raw inputs the rows are built from.
113
140
  _filterableColumns = [];
114
141
  _filters = [];
115
142
  _groupsById = new Map();
143
+ // The type picked for a column with no filter yet, so a reload keeps it.
144
+ _pickedTypes = new Map();
116
145
  _typeLabels = {
117
146
  select: 'Pick values',
118
147
  dateRange: 'Date range',
119
148
  keyword: 'Search text',
149
+ numberRange: 'Number range',
120
150
  };
121
151
  _data = inject(MAT_DIALOG_DATA);
122
152
  _dialogRef = inject(MatDialogRef);
@@ -128,6 +158,8 @@ export class ComponentSettingsComponent {
128
158
  this.report = this._data.report;
129
159
  this.component = this._data.component;
130
160
  this.title = this.component.title ?? '';
161
+ this.isValue.set(this.component.type === 'value');
162
+ this.isFormula.set(!!this.component.config?.formula);
131
163
  const padding = this.component.config?.padding;
132
164
  this.paddingTop = padding?.top ?? DEFAULT_COMPONENT_PADDING;
133
165
  this.paddingRight = padding?.right ?? DEFAULT_COMPONENT_PADDING;
@@ -136,8 +168,12 @@ export class ComponentSettingsComponent {
136
168
  this.configJson = JSON.stringify(this.component.config ?? {}, null, 2);
137
169
  this._seedKpiCard();
138
170
  this._seedFilters(this.report, this.component.id);
139
- this._loadColumns();
140
- this._loadSql();
171
+ // A formula has no statement to compile and no columns to filter on, and
172
+ // the server would refuse both requests.
173
+ if (!this.isFormula()) {
174
+ this._loadColumns();
175
+ this._loadSql();
176
+ }
141
177
  }
142
178
  // Human-friendly name for the inferred interface shown beside each column.
143
179
  typeLabel(type) {
@@ -149,16 +185,26 @@ export class ComponentSettingsComponent {
149
185
  //
150
186
  // The confirm says it cannot be undone because, from the UI, it cannot: the
151
187
  // row is soft-deleted server-side but nothing here restores a component.
188
+ // A value's confirm also says what goes with it: the server takes its
189
+ // tokens out of every text on its page, not just the one it was opened from,
190
+ // and deletes the formulas that read it (_dependentsNote).
191
+ //
192
+ // The prompt renders its template as html, so every name in it is escaped.
152
193
  delete() {
153
- this._prompt.confirm({
154
- title: 'Delete Component',
155
- template: `Are you sure you would like to delete "${this.component.title || 'this component'}"? This cannot be undone.`,
156
- })
157
- .pipe(switchMap(() => this._reportData.deleteComponent(this.report.id, this.component.id)), takeUntilDestroyed(this._destroyRef))
158
- .subscribe(() => {
159
- this._message.success('Component deleted');
194
+ this._prompt.confirm(this.isValue()
195
+ ? {
196
+ title: 'Delete Value',
197
+ template: `Delete the value "${escapeHtml(this.component.title || valueKey(this.component))}"? It is also taken out of every text on this page. This cannot be undone.${this._dependentsNote()}`,
198
+ }
199
+ : {
200
+ title: 'Delete Component',
201
+ template: `Are you sure you would like to delete "${escapeHtml(this.component.title || 'this component')}"? This cannot be undone.`,
202
+ })
203
+ .pipe(switchMap(() => this._reportData.deleteComponent(this.report.id, this.component.id)), tap(() => {
204
+ this._message.success(this.isValue() ? 'Value deleted' : 'Component deleted');
160
205
  this._dialogRef.close({ deleted: true });
161
- });
206
+ }), takeUntilDestroyed(this._destroyRef))
207
+ .subscribe();
162
208
  }
163
209
  // A percent target's bound, in the percent it is typed in. It reads the
164
210
  // control, which fsForm validates before ngModelChange updates the signal.
@@ -170,7 +216,9 @@ export class ComponentSettingsComponent {
170
216
  };
171
217
  save = () => {
172
218
  const settings = {
173
- title: this.title,
219
+ // The server trims a title; a value's Name is what its chips show, so it
220
+ // goes as the server keeps it.
221
+ title: this.isValue() ? this.title.trim() : this.title,
174
222
  padding: {
175
223
  top: this._padding(this.paddingTop),
176
224
  right: this._padding(this.paddingRight),
@@ -186,7 +234,7 @@ export class ComponentSettingsComponent {
186
234
  && !sameKpiCardSettings(kpi, kpiCardSettings(this.component.config));
187
235
  return this._reportData.updateComponent(this.report.id, this.component.id, {
188
236
  title: settings.title,
189
- padding: settings.padding,
237
+ ...(this.isValue() ? {} : { padding: settings.padding }),
190
238
  ...(kpiChanged ? kpi : {}),
191
239
  })
192
240
  .pipe(tap((response) => {
@@ -198,39 +246,135 @@ export class ComponentSettingsComponent {
198
246
  this._message.warning('Component saved, but the server did not save the card settings');
199
247
  }
200
248
  else {
201
- this._message.success('Component saved');
249
+ this._message.success(this.isValue() ? 'Value saved' : 'Component saved');
202
250
  }
203
251
  this._dialogRef.close({ settings: saved ? { ...settings, kpi: saved } : settings });
204
252
  }));
205
253
  };
206
- // Flip one exposure (report bar or this component) for a row. We update the
207
- // row's boolean first — so the toggle stays put with no blink — then persist
208
- // and reconcile on reload. Neither on → no filter (removed); either on → the
209
- // filter exists at the combined level. The interface type is inferred
210
- // server-side.
211
- setExposure(row, target, on) {
212
- row[target] = on;
254
+ // The type a column's filter will be made with. Only a column with no
255
+ // filter offers the pick (the Type select is locked otherwise), and nothing
256
+ // is saved until the filter is made.
257
+ setType(row, type) {
258
+ this._pickedTypes.set(row.column, type);
259
+ this._patchRow(row, { type });
260
+ }
261
+ // Where the row's filter shows in the report bar. This page only shows it
262
+ // in its page's bar alone, so the This component toggle goes off and locks.
263
+ // A value has this select only, with its own rules (_applyValueLevel).
264
+ setPlacement(row, placement) {
265
+ const patched = this._patchRow(row, {
266
+ placement,
267
+ component: placement === 'page' ? false : row.component,
268
+ componentToggle: componentToggleState(placement),
269
+ });
270
+ if (this.isValue()) {
271
+ this._applyValueLevel(patched);
272
+ }
273
+ else {
274
+ this._applyLevel(patched);
275
+ }
276
+ }
277
+ // A value has no This component toggle.
278
+ setComponent(row, component) {
279
+ if (this.isValue()) {
280
+ return;
281
+ }
282
+ this._applyLevel(this._patchRow(row, { component }));
283
+ }
284
+ // Persist the level the row's controls ask for, then reconcile on reload.
285
+ // No level → no filter (removed); otherwise the filter exists at that
286
+ // level. A server refusal (a page filter whose members sit on two pages)
287
+ // shows its own text and the row snaps back.
288
+ _applyLevel(row) {
289
+ const level = filterLevel(row.placement, row.component);
213
290
  const existing = this._filters.find((filter) => filter.filterColumn === row.column);
214
- if (!row.report && !row.component) {
291
+ if (!level) {
215
292
  if (existing) {
216
293
  this._run(this._reportData.deleteFilter(this.report.id, existing.id));
217
294
  }
218
295
  return;
219
296
  }
220
- const level = row.report && row.component
221
- ? 'both'
222
- : (row.report ? 'report' : 'component');
223
297
  if (existing) {
224
298
  this._run(this._reportData.updateFilterGroup(this.report.id, existing.filterGroupId, { level }));
225
299
  }
226
300
  else {
227
- this._run(this._reportData.addFilter(this.report.id, this.component.id, {
228
- filterColumn: row.column,
229
- label: row.label,
230
- level,
231
- }));
301
+ this._addFilter(row, level);
302
+ }
303
+ }
304
+ // A value's Report bar select, the only control it has. Its filter's group
305
+ // may be shared (the report's Period, say), and a value has no strip of its
306
+ // own, so a pick never lowers the group (valueFilterLevel). A pick that
307
+ // moves nothing puts the row back as the group stands.
308
+ _applyValueLevel(row) {
309
+ const existing = this._filters.find((filter) => filter.filterColumn === row.column);
310
+ const current = existing ? this._groupsById.get(existing.filterGroupId)?.level : undefined;
311
+ const level = valueFilterLevel(row.placement, current);
312
+ if (!level) {
313
+ if (existing) {
314
+ this._run(this._reportData.deleteFilter(this.report.id, existing.id));
315
+ }
316
+ }
317
+ else if (!existing) {
318
+ this._addFilter(row, level);
319
+ }
320
+ else if (level !== current) {
321
+ this._run(this._reportData.updateFilterGroup(this.report.id, existing.filterGroupId, { level }));
322
+ }
323
+ else {
324
+ this._rebuildRows();
232
325
  }
233
326
  }
327
+ // The type goes only when the author could pick it; otherwise the server
328
+ // infers it, as it always has.
329
+ _addFilter(row, level) {
330
+ this._run(this._reportData.addFilter(this.report.id, this.component.id, {
331
+ filterColumn: row.column,
332
+ label: row.label,
333
+ level,
334
+ ...(row.typeSelect.show ? { type: row.type } : {}),
335
+ }));
336
+ }
337
+ // A new row object rather than a mutation, so the signal sees the change;
338
+ // the @for tracks the column, so the row's controls survive the swap.
339
+ _patchRow(row, patch) {
340
+ const patched = { ...row, ...patch };
341
+ this.rows.update((rows) => rows.map((item) => (item.column === row.column ? patched : item)));
342
+ return patched;
343
+ }
344
+ // What a formula works out, naming each operand as its chips do. An op this
345
+ // viewer does not know reads nothing.
346
+ _formulaLine() {
347
+ const formula = this.component.config?.formula;
348
+ const line = formula ? FORMULA_LINES[formula.op] : undefined;
349
+ const values = this._layerValues();
350
+ return line ? line(operandKeys(this.component).map((key) => this._valueName(values, key))) : '';
351
+ }
352
+ // The sentence a query value's delete confirm ends with when formulas on its
353
+ // layer read it: the server deletes those with it. Empty when none does, and
354
+ // for a formula, whose operands stay.
355
+ _dependentsNote() {
356
+ if (this.isFormula()) {
357
+ return '';
358
+ }
359
+ const key = valueKey(this.component);
360
+ const names = this._layerValues()
361
+ .filter((value) => operandKeys(value).includes(key))
362
+ .map((value) => escapeHtml(value.title || valueKey(value)));
363
+ return names.length ? ` The values worked out from it are deleted too: ${names.join(', ')}.` : '';
364
+ }
365
+ // The values of the layer this value belongs to: the page whose values hold
366
+ // it, else the master's (a header or footer value).
367
+ _layerValues() {
368
+ const page = (this.report.pages ?? [])
369
+ .find((candidate) => (candidate.values ?? []).some((value) => value.id === this.component.id));
370
+ return (page ?? this.report.master)?.values ?? [];
371
+ }
372
+ // What a value is called where its chips show it: its name, else its key.
373
+ // The newest value holds a key, as it does in the text's tokens.
374
+ _valueName(values, key) {
375
+ const value = values.filter((candidate) => valueKey(candidate) === key).pop();
376
+ return value?.title || key;
377
+ }
234
378
  // A derived KPI's card keys, from its config. A sql-mode KPI cannot carry
235
379
  // them, so it gets no card fields.
236
380
  _seedKpiCard() {
@@ -297,22 +441,43 @@ export class ComponentSettingsComponent {
297
441
  });
298
442
  }
299
443
  // Build the row view-model from the loaded columns + filters/groups. Each
300
- // row's toggles reflect where its filter group is currently exposed.
444
+ // row's controls reflect where its filter group currently shows; a column
445
+ // with a filter shows the filter's own type. A value's rows never read as
446
+ // on a component: it has no strip, whatever level a group it shares is at,
447
+ // and its Report bar select offers no pick that lowers that group.
301
448
  _rebuildRows() {
449
+ const levelChoices = filterLevelChoices(this.report.viewerFeatures, this._onPage());
302
450
  this.rows.set(this._filterableColumns.map((column) => {
303
451
  const filter = this._filters.find((candidate) => candidate.filterColumn === column.column);
304
- const level = filter ? this._groupsById.get(filter.filterGroupId)?.level : undefined;
452
+ const group = filter ? this._groupsById.get(filter.filterGroupId) : undefined;
453
+ const placement = barPlacement(group?.level);
305
454
  return {
306
455
  column: column.column,
307
- type: column.type,
456
+ type: group?.type
457
+ ?? this._pickedTypes.get(column.column)
458
+ ?? column.types?.[0]
459
+ ?? column.type,
308
460
  label: filter?.label
309
461
  || this._groupsById.get(filter?.filterGroupId ?? -1)?.label
310
462
  || this._humanize(column.column),
311
- report: level === 'report' || level === 'both',
312
- component: level === 'component' || level === 'both',
463
+ placement,
464
+ component: !this.isValue() && shownOnComponent(group?.level),
465
+ typeSelect: typeSelectState(column.types, !!filter, this.report.viewerFeatures),
466
+ placementOptions: this.isValue()
467
+ ? valuePlacementOptions(levelChoices, group?.level)
468
+ : barPlacementOptions(levelChoices, placement),
469
+ componentToggle: componentToggleState(placement),
313
470
  };
314
471
  }));
315
472
  }
473
+ // Whether the component sits on a page: among its components, or, for a
474
+ // value, its values. A header or footer component or value sits on none,
475
+ // so its filters cannot be page filters.
476
+ _onPage() {
477
+ return (this.report.pages ?? [])
478
+ .some((page) => [...(page.components ?? []), ...(page.values ?? [])]
479
+ .some((candidate) => candidate.id === this.component.id));
480
+ }
316
481
  // After any filter mutation: re-fetch the report so the dialog's filter list
317
482
  // (and the parent canvas, on close) reflect the new groups/levels.
318
483
  _afterMutation() {
@@ -328,10 +493,11 @@ export class ComponentSettingsComponent {
328
493
  // Re-seed from the server so the optimistic toggle snaps back to truth.
329
494
  this._afterMutation();
330
495
  }
496
+ // The component's filters and the groups they sit in, from the report as
497
+ // last loaded. A value is listed in its page's values, not its components.
331
498
  _seedFilters(report, componentId) {
332
499
  this._groupsById = new Map((report.filterGroups ?? []).map((group) => [group.id, group]));
333
- const component = report.pages
334
- .flatMap((page) => page.components)
500
+ const component = reportComponents(report)
335
501
  .find((candidate) => candidate.id === componentId);
336
502
  this._filters = component?.filters ?? [];
337
503
  this._rebuildRows();
@@ -381,7 +547,7 @@ export class ComponentSettingsComponent {
381
547
  .replace(/\b\w/g, (character) => character.toUpperCase());
382
548
  }
383
549
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentSettingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
384
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentSettingsComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n <h1 mat-dialog-title>\n {{ component.title || 'Component' }}\n </h1>\n <mat-dialog-content>\n <mat-tab-group [(selected)]=\"selectedTab\">\n <mat-tab\n label=\"Settings\"\n name=\"settings\">\n <div class=\"fs-column tab-body\">\n <mat-form-field>\n <mat-label>\n Title\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"title\"\n name=\"title\">\n </mat-form-field>\n <div class=\"subheading-2\">\n Padding\n </div>\n <div class=\"geometry-row\">\n <mat-form-field>\n <mat-label>\n Top\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingTop\"\n name=\"paddingTop\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Right\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingRight\"\n name=\"paddingRight\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Bottom\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingBottom\"\n name=\"paddingBottom\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Left\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingLeft\"\n name=\"paddingLeft\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n </div>\n <!-- A derived KPI's card: what a rise means, a target and a\n sparkline. The server computes the progress and the points. -->\n @if (kpiCard()) {\n <div class=\"subheading-2\">\n Card\n </div>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Increase is\n </mat-label>\n <mat-select\n [ngModel]=\"increaseIs()\"\n (ngModelChange)=\"increaseIs.set($event)\"\n name=\"increaseIs\">\n @for (option of kpiPolarityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n Colors the change and decides when the target is met.\n </mat-hint>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"6\"\n [signed]=\"true\"\n [ngModel]=\"targetValue()\"\n (ngModelChange)=\"targetValue.set($event)\"\n name=\"targetValue\"\n [validate]=\"validateTarget\">\n @if (targetPercent()) {\n <div matTextSuffix>\n %\n </div>\n }\n <mat-hint>\n The value to reach. Leave empty for no target.\n </mat-hint>\n </mat-form-field>\n @if (hasTarget()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target label\n </mat-label>\n <input\n matInput\n [ngModel]=\"targetLabel()\"\n (ngModelChange)=\"targetLabel.set($event)\"\n name=\"targetLabel\">\n <mat-hint>\n Shown before the target, such as Goal. Empty reads Target.\n </mat-hint>\n </mat-form-field>\n }\n <fs-label-field>\n <mat-slide-toggle\n [ngModel]=\"sparkline()\"\n (ngModelChange)=\"sparkline.set($event)\"\n name=\"sparkline\">\n Sparkline\n </mat-slide-toggle>\n <mat-hint>\n A small trend line of the value over its last periods.\n </mat-hint>\n </fs-label-field>\n @if (sparkline()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline period\n </mat-label>\n <mat-select\n [ngModel]=\"sparklineGranularity()\"\n (ngModelChange)=\"sparklineGranularity.set($event)\"\n name=\"sparklineGranularity\">\n @for (option of granularityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline periods\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"0\"\n [ngModel]=\"sparklinePeriods()\"\n (ngModelChange)=\"sparklinePeriods.set($event)\"\n name=\"sparklinePeriods\"\n [fsFormRequired]=\"true\"\n [fsFormInteger]=\"true\"\n [fsFormMin]=\"sparklineMinPeriods\"\n [fsFormMax]=\"sparklineMaxPeriods\">\n <mat-hint>\n How many periods the line covers, {{ sparklineMinPeriods }} to {{ sparklineMaxPeriods }}.\n </mat-hint>\n </mat-form-field>\n }\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"Filters\"\n name=\"filters\">\n <div class=\"tab-body\">\n @if (columnsError()) {\n <div class=\"filters-empty error\">\n {{ columnsError() }}\n </div>\n } @else if (rows().length) {\n <!-- Every filterable column. Toggle where its control shows: in\n the report bar, on this component, both, or neither. The\n interface (date range vs value picker) follows the data. -->\n <table class=\"filter-table\">\n <thead>\n <tr>\n <th class=\"filter-col-name\">\n Filter\n </th>\n <th class=\"filter-col-type\">\n Type\n </th>\n <th class=\"filter-col-toggle\">\n Report bar\n </th>\n <th class=\"filter-col-toggle\">\n This component\n </th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.column) {\n <tr>\n <td class=\"filter-col-name\">\n {{ row.label }}\n </td>\n <td class=\"filter-col-type\">\n {{ typeLabel(row.type) }}\n </td>\n <td class=\"filter-col-toggle\">\n <mat-slide-toggle\n [ngModel]=\"row.report\"\n (ngModelChange)=\"setExposure(row, 'report', $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n matTooltip=\"Show in the report bar\">\n </mat-slide-toggle>\n </td>\n <td class=\"filter-col-toggle\">\n <mat-slide-toggle\n [ngModel]=\"row.component\"\n (ngModelChange)=\"setExposure(row, 'component', $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n matTooltip=\"Show on this component\">\n </mat-slide-toggle>\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"filters-empty\">\n This component has no filterable columns yet \u2014 give it some SQL first.\n </div>\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"SQL\"\n name=\"sql\">\n <div class=\"tab-body\">\n @if (sqlError()) {\n <div class=\"filters-empty error\">\n {{ sqlError() }}\n </div>\n } @else if (sql()) {\n @if (sqlBaseline()) {\n <!-- A derived component's statement is compiled from its\n document with no viewer state, so it is not byte-for-byte\n what produced the numbers on screen. Said here rather than\n left for the reader to discover. -->\n <div class=\"filters-empty\">\n Compiled from this component's query \u2014 no filters applied, times in {{ sqlTimezone() }}.\n </div>\n }\n <pre class=\"code-block\">{{ sql() }}</pre>\n } @else {\n <div class=\"filters-empty\">\n This component has no SQL yet.\n </div>\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"Config\"\n name=\"config\">\n <div class=\"tab-body\">\n <pre class=\"code-block\">\n {{ configJson }}\n </pre>\n </div>\n </mat-tab>\n </mat-tab-group>\n </mat-dialog-content>\n <mat-dialog-actions>\n <!-- Save | Delete | Cancel, the standard order. fs-form-dialog-actions\n renders its own Save/Done BEFORE the projected content, which would\n put Delete after Cancel, so `[save]=\"false\"` foots the row here and\n all three buttons are projected in order. Save submits the Settings\n tab; the other tabs persist as you touch them, so they get Done. -->\n <fs-form-dialog-actions [save]=\"false\">\n @if (selectedTab === 'settings') {\n <button\n mat-button\n type=\"submit\"\n color=\"primary\">\n Save\n </button>\n } @else {\n <button\n mat-button\n type=\"button\"\n color=\"primary\"\n [mat-dialog-close]=\"null\">\n Done\n </button>\n }\n <button\n mat-button\n type=\"button\"\n color=\"warn\"\n (click)=\"delete()\">\n Delete\n </button>\n <button\n mat-button\n type=\"button\"\n class=\"cancel-button\"\n [mat-dialog-close]=\"null\">\n Cancel\n </button>\n </fs-form-dialog-actions>\n </mat-dialog-actions>\n </fs-dialog>\n</form>", styles: ["mat-form-field{width:100%}.tab-body{padding-top:16px}.geometry-row{display:flex;gap:8px}.geometry-row mat-form-field{flex:1}.filter-table{border-spacing:0;width:100%;border-collapse:collapse}.filter-table thead th{color:#8f8f8f;font-weight:400;font-size:85%;text-align:left;padding:8px 16px}.filter-table tbody tr{clip-path:xywh(0 3px 100% calc(100% - 6px) round 10px)}.filter-table tbody td{border:none;background-color:#fafafa;padding:8px 16px;vertical-align:middle;text-align:left}.filter-table .filter-col-name{font-weight:600;color:#1f2933}.filter-table .filter-col-type{color:#7b8794;width:120px}.filter-table .filter-col-toggle,.filter-table th.filter-col-toggle{width:130px;text-align:center}.filters-empty{font-size:13px;color:#7b8794;padding:8px 0 4px}.filters-empty.error{color:#e15759}.code-block{margin:0;padding:10px 12px;background:#1f2933;color:#e4e7eb;border-radius:6px;font-family:JetBrains Mono,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:240px;overflow:auto}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormDirective, selector: "[fsForm]", inputs: ["wrapperSelector", "messageSelector", "hintSelector", "labelSelector", "autocomplete", "shortcuts", "confirm", "confirmDialog", "confirmDrawer", "confirmBrowser", "dirtySubmitButton", "submit", "successDelay", "errorDelay", "deactivationGuard"], outputs: ["fsForm", "invalid", "valid", "submitted", "reseted", "cleared"], exportAs: ["fsForm"] }, { kind: "directive", type: i2.FsFormRequiredDirective, selector: "[fsFormRequired],[ngModel][required]", inputs: ["fsFormRequired", "required", "fsFormRequiredMessage"] }, { kind: "directive", type: i2.FsFormMinDirective, selector: "[fsFormMin]", inputs: ["fsFormMin", "fsFormMinMessage"] }, { kind: "directive", type: i2.FsFormMaxDirective, selector: "[fsFormMax]", inputs: ["fsFormMax", "fsFormMaxMessage"] }, { kind: "directive", type: i2.FsFormIntegerDirective, selector: "[fsFormInteger]", inputs: ["fsFormInteger", "fsFormIntegerMessage"] }, { kind: "directive", type: i2.FsFormValidateDirective, selector: "[validate]", inputs: ["validate", "validateData", "validateOnSubmit"] }, { kind: "component", type: i2.FsFormDialogActionsComponent, selector: "fs-form-dialog-actions", inputs: ["save", "create", "close", "done", "closeData", "name"] }, { kind: "directive", type: i2.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "directive", type: i2.FsButtonDirective, selector: "[mat-raised-button],[mat-button],[mat-flat-button],[mat-stroked-button]", inputs: ["name", "dirtySubmit"] }, { kind: "ngmodule", type: FsMaskModule }, { kind: "directive", type: i3.FsMaskNumberDirective, selector: "[fsMaskNumber]" }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i4.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "ngmodule", type: FsLabelModule }, { kind: "component", type: i5.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["appearance", "showOutline", "disabled", "focused", "hoverable", "padless"] }, { kind: "ngmodule", type: FsTabsModule }, { kind: "directive", type: i6.FsTabsHeaderTabGroupDirective, selector: "mat-tab-group, matTabGroup, [matTabGroup]", inputs: ["orientation", "selected", "selectedData"], outputs: ["selectedChange", "selectedDataChange"], exportAs: ["fsTabsHeaderTabGroup"] }, { kind: "directive", type: i6.FsTabsTabDirective, selector: "mat-tab,matTab", inputs: ["name", "data"], exportAs: ["fsTabsTab"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i7.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
550
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentSettingsComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n <h1 mat-dialog-title>\n {{ component.title || (isValue() ? 'Value' : 'Component') }}\n </h1>\n <mat-dialog-content>\n <mat-tab-group [(selected)]=\"selectedTab\">\n <mat-tab\n label=\"Settings\"\n name=\"settings\">\n <div class=\"fs-column tab-body\">\n <mat-form-field>\n <mat-label>\n {{ isValue() ? 'Name' : 'Title' }}\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"title\"\n name=\"title\"\n [fsFormRequired]=\"isValue()\">\n </mat-form-field>\n <!-- A formula value is read-only beyond its name: what it works\n out is the AI's to change. A formula this viewer cannot\n read has no line, and no row. -->\n @if (formulaLine()) {\n <fs-label-field>\n <fs-label>\n Formula\n </fs-label>\n {{ formulaLine() }}\n <fs-label-message>\n Worked out on the server; it follows the filters of the values it reads.\n </fs-label-message>\n </fs-label-field>\n }\n <!-- A value sits inside a text block's words: no box, no padding. -->\n @if (!isValue()) {\n <div class=\"subheading-2\">\n Padding\n </div>\n <div class=\"geometry-row\">\n <mat-form-field>\n <mat-label>\n Top\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingTop\"\n name=\"paddingTop\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Right\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingRight\"\n name=\"paddingRight\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Bottom\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingBottom\"\n name=\"paddingBottom\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Left\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingLeft\"\n name=\"paddingLeft\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n </div>\n }\n <!-- A derived KPI's card: what a rise means, a target and a\n sparkline. The server computes the progress and the points. -->\n @if (kpiCard()) {\n <div class=\"subheading-2\">\n Card\n </div>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Increase is\n </mat-label>\n <mat-select\n [ngModel]=\"increaseIs()\"\n (ngModelChange)=\"increaseIs.set($event)\"\n name=\"increaseIs\">\n @for (option of kpiPolarityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n Colors the change and decides when the target is met.\n </mat-hint>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"6\"\n [signed]=\"true\"\n [ngModel]=\"targetValue()\"\n (ngModelChange)=\"targetValue.set($event)\"\n name=\"targetValue\"\n [validate]=\"validateTarget\">\n @if (targetPercent()) {\n <div matTextSuffix>\n %\n </div>\n }\n <mat-hint>\n The value to reach. Leave empty for no target.\n </mat-hint>\n </mat-form-field>\n @if (hasTarget()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target label\n </mat-label>\n <input\n matInput\n [ngModel]=\"targetLabel()\"\n (ngModelChange)=\"targetLabel.set($event)\"\n name=\"targetLabel\">\n <mat-hint>\n Shown before the target, such as Goal. Empty reads Target.\n </mat-hint>\n </mat-form-field>\n }\n <fs-label-field>\n <mat-slide-toggle\n [ngModel]=\"sparkline()\"\n (ngModelChange)=\"sparkline.set($event)\"\n name=\"sparkline\">\n Sparkline\n </mat-slide-toggle>\n <mat-hint>\n A small trend line of the value over its last periods.\n </mat-hint>\n </fs-label-field>\n @if (sparkline()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline period\n </mat-label>\n <mat-select\n [ngModel]=\"sparklineGranularity()\"\n (ngModelChange)=\"sparklineGranularity.set($event)\"\n name=\"sparklineGranularity\">\n @for (option of granularityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline periods\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"0\"\n [ngModel]=\"sparklinePeriods()\"\n (ngModelChange)=\"sparklinePeriods.set($event)\"\n name=\"sparklinePeriods\"\n [fsFormRequired]=\"true\"\n [fsFormInteger]=\"true\"\n [fsFormMin]=\"sparklineMinPeriods\"\n [fsFormMax]=\"sparklineMaxPeriods\">\n <mat-hint>\n How many periods the line covers, {{ sparklineMinPeriods }} to {{ sparklineMaxPeriods }}.\n </mat-hint>\n </mat-form-field>\n }\n }\n </div>\n </mat-tab>\n <!-- A formula runs no statement and follows the filters of the values\n it reads, so it has neither a Filters nor an SQL tab. -->\n @if (!isFormula()) {\n <mat-tab\n label=\"Filters\"\n name=\"filters\">\n <div class=\"tab-body\">\n @if (columnsError()) {\n <div class=\"filters-empty error\">\n {{ columnsError() }}\n </div>\n } @else if (rows().length) {\n <!-- Every filterable column. Pick where its control shows: in\n the report bar (every page, or this page only), on this\n component, both, or neither. The interface follows the\n data; a numeric column can be values or a number range.\n A value sits inside text and has no component to show a\n control on, so it gets the report bar column only. -->\n <table class=\"filter-table\">\n <thead>\n <tr>\n <th class=\"filter-col-name\">\n Filter\n </th>\n <th class=\"filter-col-type\">\n Type\n </th>\n <th class=\"filter-col-select\">\n Report bar\n </th>\n @if (!isValue()) {\n <th class=\"filter-col-toggle\">\n This component\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.column) {\n <tr>\n <td class=\"filter-col-name\">\n {{ row.label }}\n </td>\n <td class=\"filter-col-type\">\n @if (row.typeSelect.show) {\n <mat-form-field\n [subscriptSizing]=\"'dynamic'\"\n [matTooltip]=\"row.typeSelect.tooltip\">\n <mat-select\n [panelWidth]=\"null\"\n [ngModel]=\"row.type\"\n (ngModelChange)=\"setType(row, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [disabled]=\"row.typeSelect.disabled\"\n aria-label=\"Type\">\n @for (option of typeOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n {{ typeLabel(row.type) }}\n }\n </td>\n <td class=\"filter-col-select\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-select\n [panelWidth]=\"null\"\n [ngModel]=\"row.placement\"\n (ngModelChange)=\"setPlacement(row, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n aria-label=\"Report bar\">\n @for (option of row.placementOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </td>\n @if (!isValue()) {\n <td class=\"filter-col-toggle\">\n <mat-slide-toggle\n [ngModel]=\"row.component\"\n (ngModelChange)=\"setComponent(row, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [disabled]=\"row.componentToggle.disabled\"\n [matTooltip]=\"row.componentToggle.tooltip\">\n </mat-slide-toggle>\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"filters-empty\">\n This component has no filterable columns yet \u2014 give it some SQL first.\n </div>\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"SQL\"\n name=\"sql\">\n <div class=\"tab-body\">\n @if (sqlError()) {\n <div class=\"filters-empty error\">\n {{ sqlError() }}\n </div>\n } @else if (sql()) {\n @if (sqlBaseline()) {\n <!-- A derived component's statement is compiled from its\n document with no viewer state, so it is not byte-for-byte\n what produced the numbers on screen. Said here rather than\n left for the reader to discover. -->\n <div class=\"filters-empty\">\n Compiled from this component's query \u2014 no filters applied, times in {{ sqlTimezone() }}.\n </div>\n }\n <pre class=\"code-block\">{{ sql() }}</pre>\n } @else {\n <div class=\"filters-empty\">\n This component has no SQL yet.\n </div>\n }\n </div>\n </mat-tab>\n }\n <mat-tab\n label=\"Config\"\n name=\"config\">\n <div class=\"tab-body\">\n <pre class=\"code-block\">\n {{ configJson }}\n </pre>\n </div>\n </mat-tab>\n </mat-tab-group>\n </mat-dialog-content>\n <mat-dialog-actions>\n <!-- Save | Delete | Cancel, the standard order. fs-form-dialog-actions\n renders its own Save/Done BEFORE the projected content, which would\n put Delete after Cancel, so `[save]=\"false\"` foots the row here and\n all three buttons are projected in order. Save submits the Settings\n tab; the other tabs persist as you touch them, so they get Done. -->\n <fs-form-dialog-actions [save]=\"false\">\n @if (selectedTab === 'settings') {\n <button\n mat-button\n type=\"submit\"\n color=\"primary\">\n Save\n </button>\n } @else {\n <button\n mat-button\n type=\"button\"\n color=\"primary\"\n [mat-dialog-close]=\"null\">\n Done\n </button>\n }\n <button\n mat-button\n type=\"button\"\n color=\"warn\"\n (click)=\"delete()\">\n Delete\n </button>\n <button\n mat-button\n type=\"button\"\n class=\"cancel-button\"\n [mat-dialog-close]=\"null\">\n Cancel\n </button>\n </fs-form-dialog-actions>\n </mat-dialog-actions>\n </fs-dialog>\n</form>", styles: ["mat-form-field{width:100%}.tab-body{padding-top:16px}.geometry-row{display:flex;gap:8px}.geometry-row mat-form-field{flex:1}.filter-table{border-spacing:0;width:100%;border-collapse:collapse}.filter-table thead th{color:#8f8f8f;font-weight:400;font-size:85%;text-align:left;padding:8px 16px}.filter-table tbody tr{clip-path:xywh(0 3px 100% calc(100% - 6px) round 10px)}.filter-table tbody td{border:none;background-color:#fafafa;padding:8px 16px;vertical-align:middle;text-align:left}.filter-table .filter-col-name{font-weight:600;color:#1f2933}.filter-table .filter-col-type{color:#7b8794;width:150px}.filter-table .filter-col-select{width:160px}.filter-table td.filter-col-type,.filter-table td.filter-col-select{padding-left:8px;padding-right:8px}.filter-table td.filter-col-type mat-form-field,.filter-table td.filter-col-select mat-form-field{width:100%;--mat-form-field-container-height: 36px;--mat-form-field-container-vertical-padding: 6px}.filter-table td.filter-col-type ::ng-deep .mat-mdc-form-field-infix,.filter-table td.filter-col-select ::ng-deep .mat-mdc-form-field-infix{width:auto}.filter-table td.filter-col-type ::ng-deep .mat-mdc-form-field-subscript-wrapper,.filter-table td.filter-col-select ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.filter-table .filter-col-toggle,.filter-table th.filter-col-toggle{width:110px;text-align:center}.filters-empty{font-size:13px;color:#7b8794;padding:8px 0 4px}.filters-empty.error{color:#e15759}.code-block{margin:0;padding:10px 12px;background:#1f2933;color:#e4e7eb;border-radius:6px;font-family:JetBrains Mono,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:240px;overflow:auto}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormDirective, selector: "[fsForm]", inputs: ["wrapperSelector", "messageSelector", "hintSelector", "labelSelector", "autocomplete", "shortcuts", "confirm", "confirmDialog", "confirmDrawer", "confirmBrowser", "dirtySubmitButton", "submit", "successDelay", "errorDelay", "deactivationGuard"], outputs: ["fsForm", "invalid", "valid", "submitted", "reseted", "cleared"], exportAs: ["fsForm"] }, { kind: "directive", type: i2.FsFormRequiredDirective, selector: "[fsFormRequired],[ngModel][required]", inputs: ["fsFormRequired", "required", "fsFormRequiredMessage"] }, { kind: "directive", type: i2.FsFormMinDirective, selector: "[fsFormMin]", inputs: ["fsFormMin", "fsFormMinMessage"] }, { kind: "directive", type: i2.FsFormMaxDirective, selector: "[fsFormMax]", inputs: ["fsFormMax", "fsFormMaxMessage"] }, { kind: "directive", type: i2.FsFormIntegerDirective, selector: "[fsFormInteger]", inputs: ["fsFormInteger", "fsFormIntegerMessage"] }, { kind: "directive", type: i2.FsFormValidateDirective, selector: "[validate]", inputs: ["validate", "validateData", "validateOnSubmit"] }, { kind: "component", type: i2.FsFormDialogActionsComponent, selector: "fs-form-dialog-actions", inputs: ["save", "create", "close", "done", "closeData", "name"] }, { kind: "directive", type: i2.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "directive", type: i2.FsButtonDirective, selector: "[mat-raised-button],[mat-button],[mat-flat-button],[mat-stroked-button]", inputs: ["name", "dirtySubmit"] }, { kind: "ngmodule", type: FsMaskModule }, { kind: "directive", type: i3.FsMaskNumberDirective, selector: "[fsMaskNumber]" }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i4.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "ngmodule", type: FsLabelModule }, { kind: "component", type: i5.FsLabelComponent, selector: "fs-label" }, { kind: "component", type: i5.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["appearance", "showOutline", "disabled", "focused", "hoverable", "padless"] }, { kind: "component", type: i5.FsLabelMessageComponent, selector: "fs-label-message" }, { kind: "ngmodule", type: FsTabsModule }, { kind: "directive", type: i6.FsTabsHeaderTabGroupDirective, selector: "mat-tab-group, matTabGroup, [matTabGroup]", inputs: ["orientation", "selected", "selectedData"], outputs: ["selectedChange", "selectedDataChange"], exportAs: ["fsTabsHeaderTabGroup"] }, { kind: "directive", type: i6.FsTabsTabDirective, selector: "mat-tab,matTab", inputs: ["name", "data"], exportAs: ["fsTabsTab"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i7.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
385
551
  }
386
552
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentSettingsComponent, decorators: [{
387
553
  type: Component,
@@ -407,6 +573,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
407
573
  MatSelect,
408
574
  MatSlideToggle,
409
575
  MatTooltip,
410
- ], template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n <h1 mat-dialog-title>\n {{ component.title || 'Component' }}\n </h1>\n <mat-dialog-content>\n <mat-tab-group [(selected)]=\"selectedTab\">\n <mat-tab\n label=\"Settings\"\n name=\"settings\">\n <div class=\"fs-column tab-body\">\n <mat-form-field>\n <mat-label>\n Title\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"title\"\n name=\"title\">\n </mat-form-field>\n <div class=\"subheading-2\">\n Padding\n </div>\n <div class=\"geometry-row\">\n <mat-form-field>\n <mat-label>\n Top\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingTop\"\n name=\"paddingTop\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Right\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingRight\"\n name=\"paddingRight\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Bottom\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingBottom\"\n name=\"paddingBottom\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Left\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingLeft\"\n name=\"paddingLeft\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n </div>\n <!-- A derived KPI's card: what a rise means, a target and a\n sparkline. The server computes the progress and the points. -->\n @if (kpiCard()) {\n <div class=\"subheading-2\">\n Card\n </div>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Increase is\n </mat-label>\n <mat-select\n [ngModel]=\"increaseIs()\"\n (ngModelChange)=\"increaseIs.set($event)\"\n name=\"increaseIs\">\n @for (option of kpiPolarityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n Colors the change and decides when the target is met.\n </mat-hint>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"6\"\n [signed]=\"true\"\n [ngModel]=\"targetValue()\"\n (ngModelChange)=\"targetValue.set($event)\"\n name=\"targetValue\"\n [validate]=\"validateTarget\">\n @if (targetPercent()) {\n <div matTextSuffix>\n %\n </div>\n }\n <mat-hint>\n The value to reach. Leave empty for no target.\n </mat-hint>\n </mat-form-field>\n @if (hasTarget()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target label\n </mat-label>\n <input\n matInput\n [ngModel]=\"targetLabel()\"\n (ngModelChange)=\"targetLabel.set($event)\"\n name=\"targetLabel\">\n <mat-hint>\n Shown before the target, such as Goal. Empty reads Target.\n </mat-hint>\n </mat-form-field>\n }\n <fs-label-field>\n <mat-slide-toggle\n [ngModel]=\"sparkline()\"\n (ngModelChange)=\"sparkline.set($event)\"\n name=\"sparkline\">\n Sparkline\n </mat-slide-toggle>\n <mat-hint>\n A small trend line of the value over its last periods.\n </mat-hint>\n </fs-label-field>\n @if (sparkline()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline period\n </mat-label>\n <mat-select\n [ngModel]=\"sparklineGranularity()\"\n (ngModelChange)=\"sparklineGranularity.set($event)\"\n name=\"sparklineGranularity\">\n @for (option of granularityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline periods\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"0\"\n [ngModel]=\"sparklinePeriods()\"\n (ngModelChange)=\"sparklinePeriods.set($event)\"\n name=\"sparklinePeriods\"\n [fsFormRequired]=\"true\"\n [fsFormInteger]=\"true\"\n [fsFormMin]=\"sparklineMinPeriods\"\n [fsFormMax]=\"sparklineMaxPeriods\">\n <mat-hint>\n How many periods the line covers, {{ sparklineMinPeriods }} to {{ sparklineMaxPeriods }}.\n </mat-hint>\n </mat-form-field>\n }\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"Filters\"\n name=\"filters\">\n <div class=\"tab-body\">\n @if (columnsError()) {\n <div class=\"filters-empty error\">\n {{ columnsError() }}\n </div>\n } @else if (rows().length) {\n <!-- Every filterable column. Toggle where its control shows: in\n the report bar, on this component, both, or neither. The\n interface (date range vs value picker) follows the data. -->\n <table class=\"filter-table\">\n <thead>\n <tr>\n <th class=\"filter-col-name\">\n Filter\n </th>\n <th class=\"filter-col-type\">\n Type\n </th>\n <th class=\"filter-col-toggle\">\n Report bar\n </th>\n <th class=\"filter-col-toggle\">\n This component\n </th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.column) {\n <tr>\n <td class=\"filter-col-name\">\n {{ row.label }}\n </td>\n <td class=\"filter-col-type\">\n {{ typeLabel(row.type) }}\n </td>\n <td class=\"filter-col-toggle\">\n <mat-slide-toggle\n [ngModel]=\"row.report\"\n (ngModelChange)=\"setExposure(row, 'report', $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n matTooltip=\"Show in the report bar\">\n </mat-slide-toggle>\n </td>\n <td class=\"filter-col-toggle\">\n <mat-slide-toggle\n [ngModel]=\"row.component\"\n (ngModelChange)=\"setExposure(row, 'component', $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n matTooltip=\"Show on this component\">\n </mat-slide-toggle>\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"filters-empty\">\n This component has no filterable columns yet \u2014 give it some SQL first.\n </div>\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"SQL\"\n name=\"sql\">\n <div class=\"tab-body\">\n @if (sqlError()) {\n <div class=\"filters-empty error\">\n {{ sqlError() }}\n </div>\n } @else if (sql()) {\n @if (sqlBaseline()) {\n <!-- A derived component's statement is compiled from its\n document with no viewer state, so it is not byte-for-byte\n what produced the numbers on screen. Said here rather than\n left for the reader to discover. -->\n <div class=\"filters-empty\">\n Compiled from this component's query \u2014 no filters applied, times in {{ sqlTimezone() }}.\n </div>\n }\n <pre class=\"code-block\">{{ sql() }}</pre>\n } @else {\n <div class=\"filters-empty\">\n This component has no SQL yet.\n </div>\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"Config\"\n name=\"config\">\n <div class=\"tab-body\">\n <pre class=\"code-block\">\n {{ configJson }}\n </pre>\n </div>\n </mat-tab>\n </mat-tab-group>\n </mat-dialog-content>\n <mat-dialog-actions>\n <!-- Save | Delete | Cancel, the standard order. fs-form-dialog-actions\n renders its own Save/Done BEFORE the projected content, which would\n put Delete after Cancel, so `[save]=\"false\"` foots the row here and\n all three buttons are projected in order. Save submits the Settings\n tab; the other tabs persist as you touch them, so they get Done. -->\n <fs-form-dialog-actions [save]=\"false\">\n @if (selectedTab === 'settings') {\n <button\n mat-button\n type=\"submit\"\n color=\"primary\">\n Save\n </button>\n } @else {\n <button\n mat-button\n type=\"button\"\n color=\"primary\"\n [mat-dialog-close]=\"null\">\n Done\n </button>\n }\n <button\n mat-button\n type=\"button\"\n color=\"warn\"\n (click)=\"delete()\">\n Delete\n </button>\n <button\n mat-button\n type=\"button\"\n class=\"cancel-button\"\n [mat-dialog-close]=\"null\">\n Cancel\n </button>\n </fs-form-dialog-actions>\n </mat-dialog-actions>\n </fs-dialog>\n</form>", styles: ["mat-form-field{width:100%}.tab-body{padding-top:16px}.geometry-row{display:flex;gap:8px}.geometry-row mat-form-field{flex:1}.filter-table{border-spacing:0;width:100%;border-collapse:collapse}.filter-table thead th{color:#8f8f8f;font-weight:400;font-size:85%;text-align:left;padding:8px 16px}.filter-table tbody tr{clip-path:xywh(0 3px 100% calc(100% - 6px) round 10px)}.filter-table tbody td{border:none;background-color:#fafafa;padding:8px 16px;vertical-align:middle;text-align:left}.filter-table .filter-col-name{font-weight:600;color:#1f2933}.filter-table .filter-col-type{color:#7b8794;width:120px}.filter-table .filter-col-toggle,.filter-table th.filter-col-toggle{width:130px;text-align:center}.filters-empty{font-size:13px;color:#7b8794;padding:8px 0 4px}.filters-empty.error{color:#e15759}.code-block{margin:0;padding:10px 12px;background:#1f2933;color:#e4e7eb;border-radius:6px;font-family:JetBrains Mono,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:240px;overflow:auto}\n"] }]
576
+ ], template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n <h1 mat-dialog-title>\n {{ component.title || (isValue() ? 'Value' : 'Component') }}\n </h1>\n <mat-dialog-content>\n <mat-tab-group [(selected)]=\"selectedTab\">\n <mat-tab\n label=\"Settings\"\n name=\"settings\">\n <div class=\"fs-column tab-body\">\n <mat-form-field>\n <mat-label>\n {{ isValue() ? 'Name' : 'Title' }}\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"title\"\n name=\"title\"\n [fsFormRequired]=\"isValue()\">\n </mat-form-field>\n <!-- A formula value is read-only beyond its name: what it works\n out is the AI's to change. A formula this viewer cannot\n read has no line, and no row. -->\n @if (formulaLine()) {\n <fs-label-field>\n <fs-label>\n Formula\n </fs-label>\n {{ formulaLine() }}\n <fs-label-message>\n Worked out on the server; it follows the filters of the values it reads.\n </fs-label-message>\n </fs-label-field>\n }\n <!-- A value sits inside a text block's words: no box, no padding. -->\n @if (!isValue()) {\n <div class=\"subheading-2\">\n Padding\n </div>\n <div class=\"geometry-row\">\n <mat-form-field>\n <mat-label>\n Top\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingTop\"\n name=\"paddingTop\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Right\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingRight\"\n name=\"paddingRight\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Bottom\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingBottom\"\n name=\"paddingBottom\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Left\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"3\"\n [(ngModel)]=\"paddingLeft\"\n name=\"paddingLeft\"\n [fsFormMin]=\"0\">\n <div matTextSuffix>\n in\n </div>\n </mat-form-field>\n </div>\n }\n <!-- A derived KPI's card: what a rise means, a target and a\n sparkline. The server computes the progress and the points. -->\n @if (kpiCard()) {\n <div class=\"subheading-2\">\n Card\n </div>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Increase is\n </mat-label>\n <mat-select\n [ngModel]=\"increaseIs()\"\n (ngModelChange)=\"increaseIs.set($event)\"\n name=\"increaseIs\">\n @for (option of kpiPolarityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n Colors the change and decides when the target is met.\n </mat-hint>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"6\"\n [signed]=\"true\"\n [ngModel]=\"targetValue()\"\n (ngModelChange)=\"targetValue.set($event)\"\n name=\"targetValue\"\n [validate]=\"validateTarget\">\n @if (targetPercent()) {\n <div matTextSuffix>\n %\n </div>\n }\n <mat-hint>\n The value to reach. Leave empty for no target.\n </mat-hint>\n </mat-form-field>\n @if (hasTarget()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Target label\n </mat-label>\n <input\n matInput\n [ngModel]=\"targetLabel()\"\n (ngModelChange)=\"targetLabel.set($event)\"\n name=\"targetLabel\">\n <mat-hint>\n Shown before the target, such as Goal. Empty reads Target.\n </mat-hint>\n </mat-form-field>\n }\n <fs-label-field>\n <mat-slide-toggle\n [ngModel]=\"sparkline()\"\n (ngModelChange)=\"sparkline.set($event)\"\n name=\"sparkline\">\n Sparkline\n </mat-slide-toggle>\n <mat-hint>\n A small trend line of the value over its last periods.\n </mat-hint>\n </fs-label-field>\n @if (sparkline()) {\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline period\n </mat-label>\n <mat-select\n [ngModel]=\"sparklineGranularity()\"\n (ngModelChange)=\"sparklineGranularity.set($event)\"\n name=\"sparklineGranularity\">\n @for (option of granularityOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <mat-form-field class=\"full-width\">\n <mat-label>\n Sparkline periods\n </mat-label>\n <input\n matInput\n fsMaskNumber\n [scale]=\"0\"\n [ngModel]=\"sparklinePeriods()\"\n (ngModelChange)=\"sparklinePeriods.set($event)\"\n name=\"sparklinePeriods\"\n [fsFormRequired]=\"true\"\n [fsFormInteger]=\"true\"\n [fsFormMin]=\"sparklineMinPeriods\"\n [fsFormMax]=\"sparklineMaxPeriods\">\n <mat-hint>\n How many periods the line covers, {{ sparklineMinPeriods }} to {{ sparklineMaxPeriods }}.\n </mat-hint>\n </mat-form-field>\n }\n }\n </div>\n </mat-tab>\n <!-- A formula runs no statement and follows the filters of the values\n it reads, so it has neither a Filters nor an SQL tab. -->\n @if (!isFormula()) {\n <mat-tab\n label=\"Filters\"\n name=\"filters\">\n <div class=\"tab-body\">\n @if (columnsError()) {\n <div class=\"filters-empty error\">\n {{ columnsError() }}\n </div>\n } @else if (rows().length) {\n <!-- Every filterable column. Pick where its control shows: in\n the report bar (every page, or this page only), on this\n component, both, or neither. The interface follows the\n data; a numeric column can be values or a number range.\n A value sits inside text and has no component to show a\n control on, so it gets the report bar column only. -->\n <table class=\"filter-table\">\n <thead>\n <tr>\n <th class=\"filter-col-name\">\n Filter\n </th>\n <th class=\"filter-col-type\">\n Type\n </th>\n <th class=\"filter-col-select\">\n Report bar\n </th>\n @if (!isValue()) {\n <th class=\"filter-col-toggle\">\n This component\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.column) {\n <tr>\n <td class=\"filter-col-name\">\n {{ row.label }}\n </td>\n <td class=\"filter-col-type\">\n @if (row.typeSelect.show) {\n <mat-form-field\n [subscriptSizing]=\"'dynamic'\"\n [matTooltip]=\"row.typeSelect.tooltip\">\n <mat-select\n [panelWidth]=\"null\"\n [ngModel]=\"row.type\"\n (ngModelChange)=\"setType(row, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [disabled]=\"row.typeSelect.disabled\"\n aria-label=\"Type\">\n @for (option of typeOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n {{ typeLabel(row.type) }}\n }\n </td>\n <td class=\"filter-col-select\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-select\n [panelWidth]=\"null\"\n [ngModel]=\"row.placement\"\n (ngModelChange)=\"setPlacement(row, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n aria-label=\"Report bar\">\n @for (option of row.placementOptions; track option.value) {\n <mat-option [value]=\"option.value\">\n {{ option.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </td>\n @if (!isValue()) {\n <td class=\"filter-col-toggle\">\n <mat-slide-toggle\n [ngModel]=\"row.component\"\n (ngModelChange)=\"setComponent(row, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [disabled]=\"row.componentToggle.disabled\"\n [matTooltip]=\"row.componentToggle.tooltip\">\n </mat-slide-toggle>\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"filters-empty\">\n This component has no filterable columns yet \u2014 give it some SQL first.\n </div>\n }\n </div>\n </mat-tab>\n <mat-tab\n label=\"SQL\"\n name=\"sql\">\n <div class=\"tab-body\">\n @if (sqlError()) {\n <div class=\"filters-empty error\">\n {{ sqlError() }}\n </div>\n } @else if (sql()) {\n @if (sqlBaseline()) {\n <!-- A derived component's statement is compiled from its\n document with no viewer state, so it is not byte-for-byte\n what produced the numbers on screen. Said here rather than\n left for the reader to discover. -->\n <div class=\"filters-empty\">\n Compiled from this component's query \u2014 no filters applied, times in {{ sqlTimezone() }}.\n </div>\n }\n <pre class=\"code-block\">{{ sql() }}</pre>\n } @else {\n <div class=\"filters-empty\">\n This component has no SQL yet.\n </div>\n }\n </div>\n </mat-tab>\n }\n <mat-tab\n label=\"Config\"\n name=\"config\">\n <div class=\"tab-body\">\n <pre class=\"code-block\">\n {{ configJson }}\n </pre>\n </div>\n </mat-tab>\n </mat-tab-group>\n </mat-dialog-content>\n <mat-dialog-actions>\n <!-- Save | Delete | Cancel, the standard order. fs-form-dialog-actions\n renders its own Save/Done BEFORE the projected content, which would\n put Delete after Cancel, so `[save]=\"false\"` foots the row here and\n all three buttons are projected in order. Save submits the Settings\n tab; the other tabs persist as you touch them, so they get Done. -->\n <fs-form-dialog-actions [save]=\"false\">\n @if (selectedTab === 'settings') {\n <button\n mat-button\n type=\"submit\"\n color=\"primary\">\n Save\n </button>\n } @else {\n <button\n mat-button\n type=\"button\"\n color=\"primary\"\n [mat-dialog-close]=\"null\">\n Done\n </button>\n }\n <button\n mat-button\n type=\"button\"\n color=\"warn\"\n (click)=\"delete()\">\n Delete\n </button>\n <button\n mat-button\n type=\"button\"\n class=\"cancel-button\"\n [mat-dialog-close]=\"null\">\n Cancel\n </button>\n </fs-form-dialog-actions>\n </mat-dialog-actions>\n </fs-dialog>\n</form>", styles: ["mat-form-field{width:100%}.tab-body{padding-top:16px}.geometry-row{display:flex;gap:8px}.geometry-row mat-form-field{flex:1}.filter-table{border-spacing:0;width:100%;border-collapse:collapse}.filter-table thead th{color:#8f8f8f;font-weight:400;font-size:85%;text-align:left;padding:8px 16px}.filter-table tbody tr{clip-path:xywh(0 3px 100% calc(100% - 6px) round 10px)}.filter-table tbody td{border:none;background-color:#fafafa;padding:8px 16px;vertical-align:middle;text-align:left}.filter-table .filter-col-name{font-weight:600;color:#1f2933}.filter-table .filter-col-type{color:#7b8794;width:150px}.filter-table .filter-col-select{width:160px}.filter-table td.filter-col-type,.filter-table td.filter-col-select{padding-left:8px;padding-right:8px}.filter-table td.filter-col-type mat-form-field,.filter-table td.filter-col-select mat-form-field{width:100%;--mat-form-field-container-height: 36px;--mat-form-field-container-vertical-padding: 6px}.filter-table td.filter-col-type ::ng-deep .mat-mdc-form-field-infix,.filter-table td.filter-col-select ::ng-deep .mat-mdc-form-field-infix{width:auto}.filter-table td.filter-col-type ::ng-deep .mat-mdc-form-field-subscript-wrapper,.filter-table td.filter-col-select ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.filter-table .filter-col-toggle,.filter-table th.filter-col-toggle{width:110px;text-align:center}.filters-empty{font-size:13px;color:#7b8794;padding:8px 0 4px}.filters-empty.error{color:#e15759}.code-block{margin:0;padding:10px 12px;background:#1f2933;color:#e4e7eb;border-radius:6px;font-family:JetBrains Mono,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:240px;overflow:auto}\n"] }]
411
577
  }] });
412
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LXNldHRpbmdzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy9kaWFsb2dzL2NvbXBvbmVudC1zZXR0aW5ncy9jb21wb25lbnQtc2V0dGluZ3MuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvY29tcG9uZW50LXNldHRpbmdzL2NvbXBvbmVudC1zZXR0aW5ncy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQVUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEdBQy9GLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBbUIsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFOUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxFQUFFLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzdJLE9BQU8sRUFBRSxZQUFZLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMxRixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDaEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUs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QUFVOzs0RkFHRCwwQkFBMEI7a0JBN0J0QyxTQUFTO3NDQUdTLHVCQUF1QixDQUFDLE1BQU0sY0FDbkMsSUFBSSxXQUNQO3dCQUNQLFdBQVc7d0JBQ1gsWUFBWTt3QkFDWixZQUFZO3dCQUNaLGNBQWM7d0JBQ2QsYUFBYTt3QkFDYixZQUFZO3dCQUNaLGFBQWE7d0JBQ2IsY0FBYzt3QkFDZCxnQkFBZ0I7d0JBQ2hCLGdCQUFnQjt3QkFDaEIsY0FBYzt3QkFDZCxZQUFZO3dCQUNaLE9BQU87d0JBQ1AsUUFBUTt3QkFDUixTQUFTO3dCQUNULFNBQVM7d0JBQ1QsUUFBUTt3QkFDUixTQUFTO3dCQUNULFNBQVM7d0JBQ1QsY0FBYzt3QkFDZCxVQUFVO3FCQUNYIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRGVzdHJveVJlZiwgRXZlbnRFbWl0dGVyLCBPbkluaXQsIGNvbXB1dGVkLCBpbmplY3QsIHNpZ25hbCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBNQVRfRElBTE9HX0RBVEEsIE1hdERpYWxvZ0FjdGlvbnMsIE1hdERpYWxvZ0Nsb3NlLCBNYXREaWFsb2dDb250ZW50LCBNYXREaWFsb2dSZWYsIE1hdERpYWxvZ1RpdGxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IE1hdEZvcm1GaWVsZCwgTWF0SGludCwgTWF0TGFiZWwsIE1hdFN1ZmZpeCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xuaW1wb3J0IHsgTWF0QnV0dG9uIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcbmltcG9ydCB7IE1hdElucHV0IH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaW5wdXQnO1xuaW1wb3J0IHsgTWF0T3B0aW9uLCBNYXRTZWxlY3QgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zZWxlY3QnO1xuaW1wb3J0IHsgTWF0U2xpZGVUb2dnbGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zbGlkZS10b2dnbGUnO1xuaW1wb3J0IHsgTWF0VGFic01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3RhYnMnO1xuaW1wb3J0IHsgTWF0VG9vbHRpcCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuXG5pbXBvcnQgeyBGc0RpYWxvZ01vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2RpYWxvZyc7XG5pbXBvcnQgeyBGc0Zvcm1Nb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9mb3JtJztcbmltcG9ydCB7IEZzTGFiZWxNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9sYWJlbCc7XG5pbXBvcnQgeyBGc01hc2tNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9tYXNrJztcbmltcG9ydCB7IEZzTWVzc2FnZSB9IGZyb20gJ0BmaXJlc3RpdGNoL21lc3NhZ2UnO1xuaW1wb3J0IHsgRnNQcm9tcHQgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9tcHQnO1xuaW1wb3J0IHsgRnNUYWJzTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvdGFicyc7XG5cbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHN3aXRjaE1hcCwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQgeyBSZXBvcnRDaGFuZ2VQb2xhcml0eSB9IGZyb20gJy4uLy4uL2VudW1zL3JlcG9ydC1jaGFuZ2UtcG9sYXJpdHkuZW51bSc7XG5pbXBvcnQgeyBSZXBvcnRWYWx1ZUZvcm1hdCB9IGZyb20gJy4uLy4uL2VudW1zL3JlcG9ydC12YWx1ZS1mb3JtYXQuZW51bSc7XG5pbXBvcnQgeyByZXNvbHZlRm9ybWF0Q29udGV4dCB9IGZyb20gJy4uLy4uL2Zvcm1hdCc7XG5pbXBvcnQge1xuICBLUElfU1BBUktMSU5FX0RFRkFVTFRfR1JBTlVMQVJJVFksXG4gIEtQSV9TUEFSS0xJTkVfREVGQVVMVF9QRVJJT0RTLFxuICBrcGlDYXJkU2V0dGluZ3MsXG4gIHNhbWVLcGlDYXJkU2V0dGluZ3MsXG59IGZyb20gJy4uLy4uL2twaS1jYXJkJztcbmltcG9ydCB7XG4gIENoYXJ0R3JhbnVsYXJpdHksXG4gIENvbXBvbmVudFNldHRpbmdzLFxuICBHUkFOVUxBUklUWV9PUFRJT05TLFxuICBLcGlDYXJkU2V0dGluZ3MsXG4gIEtwaUNvbmZpZyxcbiAgUmVwb3J0LFxuICBSZXBvcnRDb21wb25lbnQsXG4gIFJlcG9ydENvbXBvbmVudFNxbCxcbiAgUmVwb3J0RmlsdGVyLFxuICBSZXBvcnRGaWx0ZXJHcm91cCxcbiAgUmVwb3J0RmlsdGVyTGV2ZWwsXG4gIFJlcG9ydEZpbHRlclR5cGUsXG4gIFJlcG9ydEZpbHRlcmFibGVDb2x1bW4sXG59IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBERUZBVUxUX0NPTVBPTkVOVF9QQURESU5HIH0gZnJvbSAnLi4vLi4vbGF5b3V0JztcblxuXG4vLyBXaGF0IHRoZSBkaWFsb2cgaGFuZHMgYmFjay4gVGhlIFNldHRpbmdzIHRhYidzIFNhdmUgY2FycmllcyB0aGUgbmV3XG4vLyBgc2V0dGluZ3NgOyBEZWxldGUgY2FycmllcyBgZGVsZXRlZGAgYW5kIG5vIHNldHRpbmdzLCBiZWNhdXNlIHRoZSBjb21wb25lbnRcbi8vIGl0IHdhcyBvcGVuZWQgZm9yIG5vIGxvbmdlciBleGlzdHMuIEV2ZXJ5IG90aGVyIGV4aXQgKENhbmNlbCwgRG9uZSwgRXNjYXBlLFxuLy8gYmFja2Ryb3ApIGNsb3NlcyB3aXRoIG5vIHJlc3VsdCDigJQgZmlsdGVyIHdvcmsgaXMgYW5ub3VuY2VkIGFzIGl0IGhhcHBlbnNcbi8vIGluc3RlYWQsIHRocm91Z2ggYGZpbHRlcnNDaGFuZ2VkYC5cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcG9uZW50U2V0dGluZ3NSZXN1bHQge1xuICBzZXR0aW5ncz86IENvbXBvbmVudFNldHRpbmdzO1xuICBkZWxldGVkPzogYm9vbGVhbjtcbn1cblxuLy8gV2hhdCB0aGUgc2V0dGluZ3MgZW5kcG9pbnQgcmV0dXJucyBmb3IgdGhlIGNvbXBvbmVudDogaXRzIGlkIGFuZCwgZnJvbSBhXG4vLyBzZXJ2ZXIgdGhhdCBzYXZlcyBhIEtQSSdzIGNhcmQga2V5cywgdGhlIHdob2xlIGNvbmZpZyBhcyBzYXZlZC5cbmludGVyZmFjZSBDb21wb25lbnRTZXR0aW5nc1Jlc3BvbnNlIHtcbiAgaWQ6IG51bWJlcjtcbiAgY29uZmlnPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsO1xufVxuXG5cbi8vIFdoYXQgYSByaXNlIGluIGEgS1BJJ3MgdmFsdWUgbWVhbnMsIGZvciB0aGUgSW5jcmVhc2UgaXMgc2VsZWN0LlxuY29uc3QgS1BJX0NIQU5HRV9QT0xBUklUWV9PUFRJT05TOiB7IHZhbHVlOiBSZXBvcnRDaGFuZ2VQb2xhcml0eTsgbmFtZTogc3RyaW5nIH1bXSA9IFtcbiAgeyB2YWx1ZTogUmVwb3J0Q2hhbmdlUG9sYXJpdHkuR29vZCwgbmFtZTogJ0dvb2QgbmV3cyDigJQgYSByaXNlIHNob3dzIGdyZWVuJyB9LFxuICB7IHZhbHVlOiBSZXBvcnRDaGFuZ2VQb2xhcml0eS5CYWQsIG5hbWU6ICdCYWQgbmV3cyDigJQgYSByaXNlIHNob3dzIHJlZCcgfSxcbiAgeyB2YWx1ZTogUmVwb3J0Q2hhbmdlUG9sYXJpdHkuTmV1dHJhbCwgbmFtZTogJ05laXRoZXIg4oCUIG5vIGNvbG9yJyB9LFxuXTtcblxuLy8gQSBLUEkgc3BhcmtsaW5lJ3MgcGVyaW9kcyBzdGF5IHdpdGhpbiAyIHRvIDYwLlxuY29uc3QgS1BJX1NQQVJLTElORV9NSU5fUEVSSU9EUyA9IDI7XG5jb25zdCBLUElfU1BBUktMSU5FX01BWF9QRVJJT0RTID0gNjA7XG5cbi8vIEEgcGVyY2VudCBLUEkncyB0YXJnZXQgaXMgZW50ZXJlZCBhcyB0aGUgcGVyY2VudCBzaG93biAoMTUgZm9yIDE1JSkgYW5kXG4vLyBzdG9yZWQgYXMgdGhlIDAtMSByYXRpbyBpdHMgdmFsdWUgYXJyaXZlcyBpbjsgdGhlIHNlcnZlciByZWZ1c2VzIGEgc3RvcmVkXG4vLyB0YXJnZXQgYWJvdmUgMTAwLCB3aGljaCBpcyAxMCwwMDAlIGhlcmUuXG5jb25zdCBLUElfUEVSQ0VOVF9UQVJHRVRfTUFYID0gMTAwMDA7XG5cblxuLy8gT25lIHJvdyBvZiB0aGUgRmlsdGVycyB0YWIgbGlzdGluZzogYSBmaWx0ZXJhYmxlIGNvbHVtbiwgdGhlIGludGVyZmFjZVxuLy8gaW5mZXJyZWQgZnJvbSBpdHMgZGF0YSwgYW5kIHdoZXJlIGl0cyBmaWx0ZXIgaXMgZXhwb3NlZCAodGhlIHR3byB0b2dnbGVzKS5cbmludGVyZmFjZSBGaWx0ZXJSb3cge1xuICBjb2x1bW46IHN0cmluZztcbiAgdHlwZTogUmVwb3J0RmlsdGVyVHlwZTtcbiAgbGFiZWw6IHN0cmluZztcbiAgcmVwb3J0OiBib29sZWFuO1xuICBjb21wb25lbnQ6IGJvb2xlYW47XG59XG5cblxuLy8gQ29tcG9uZW50IHNldHRpbmdzLCBpbiB0YWJzOlxuLy8gICBTZXR0aW5ncyDigJQgdGl0bGUgYW5kIGNvbnRlbnQgcGFkZGluZywgYW5kIG9uIGEgZGVyaXZlZCBLUEkgaXRzIGNhcmQ6XG4vLyAgIHdoYXQgYSByaXNlIG1lYW5zLCBhIHRhcmdldCBhbmQgYSBzcGFya2xpbmUgKG51bWJlciBmb3JtYXRzIHN0YXkgd2l0aFxuLy8gICB0aGUgQUkpLiBQb3NpdGlvbi9zaXplIGFyZSB0dW5lZCBieSBkcmFnZ2luZyBvbiB0aGUgY2FudmFzOyBoZWlnaHRcbi8vICAgYmVoYXZpb3VyIGZvbGxvd3MgZnJvbSB0aGUgY29tcG9uZW50IHR5cGUuXG4vLyAgIEZpbHRlcnMgIOKAlCBPTkUgbGlzdGluZyBvZiBldmVyeSBmaWx0ZXJhYmxlIGNvbHVtbiBvbiB0aGlzIGNvbXBvbmVudC4gRWFjaFxuLy8gICByb3cgY2FycmllcyB0d28gdG9nZ2xlczogc2hvdyBpbiB0aGUgcmVwb3J0IGJhciBhbmQvb3Igc2hvdyBvbiB0aGlzXG4vLyAgIGNvbXBvbmVudCAoYm90aCwgZWl0aGVyLCBvciBuZWl0aGVyKS4gVGhlIGludGVyZmFjZSAoZGF0ZSByYW5nZSB2cyB2YWx1ZVxuLy8gICBwaWNrZXIpIGlzIGluZmVycmVkIGZyb20gdGhlIGRhdGEsIG5ldmVyIGNob3Nlbi4gRWFjaCB0b2dnbGUgcGVyc2lzdHNcbi8vICAgaW1tZWRpYXRlbHkgYW5kIHJlZnJlc2hlcyB0aGUgaW4tZGlhbG9nIGxpc3QuXG4vLyAgIFNRTCAvIENvbmZpZyDigJQgcmVhZC1vbmx5IGRpYWdub3N0aWNzLlxuQENvbXBvbmVudCh7XG4gIHRlbXBsYXRlVXJsOiAnLi9jb21wb25lbnQtc2V0dGluZ3MuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9jb21wb25lbnQtc2V0dGluZ3MuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBGb3Jtc01vZHVsZSxcbiAgICBGc0Zvcm1Nb2R1bGUsXG4gICAgRnNNYXNrTW9kdWxlLFxuICAgIEZzRGlhbG9nTW9kdWxlLFxuICAgIEZzTGFiZWxNb2R1bGUsXG4gICAgRnNUYWJzTW9kdWxlLFxuICAgIE1hdFRhYnNNb2R1bGUsXG4gICAgTWF0RGlhbG9nVGl0bGUsXG4gICAgTWF0RGlhbG9nQ29udGVudCxcbiAgICBNYXREaWFsb2dBY3Rpb25zLFxuICAgIE1hdERpYWxvZ0Nsb3NlLFxuICAgIE1hdEZvcm1GaWVsZCxcbiAgICBNYXRIaW50LFxuICAgIE1hdExhYmVsLFxuICAgIE1hdFN1ZmZpeCxcbiAgICBNYXRCdXR0b24sXG4gICAgTWF0SW5wdXQsXG4gICAgTWF0T3B0aW9uLFxuICAgIE1hdFNlbGVjdCxcbiAgICBNYXRTbGlkZVRvZ2dsZSxcbiAgICBNYXRUb29sdGlwLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBDb21wb25lbnRTZXR0aW5nc0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cbiAgLy8gQSBmaWx0ZXIgd2FzIGFkZGVkLCByZW1vdmVkIG9yIHJlLWxldmVsbGVkLCBzbyB0aGUgcmVwb3J0J3MgZmlsdGVyIGdyb3Vwc1xuICAvLyBjaGFuZ2VkLiBUaG9zZSBtdXRhdGlvbnMgcGVyc2lzdCB0aGUgbW9tZW50IHRoZXkgYXJlIGNsaWNrZWQgYW5kIHRoZSBkaWFsb2dcbiAgLy8gY2FuIHRoZW4gYmUgZGlzbWlzc2VkIGJ5IGEgcm91dGUgdGhhdCBjYXJyaWVzIG5vIHJlc3VsdCAoRXNjYXBlLCBiYWNrZHJvcCksXG4gIC8vIHNvIHRoZSBwYWdlIGlzIHRvbGQgaGVyZSByYXRoZXIgdGhhbiB0aHJvdWdoIHRoZSBjbG9zZSByZXN1bHQuXG4gIHB1YmxpYyByZWFkb25seSBmaWx0ZXJzQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBwdWJsaWMgY29tcG9uZW50OiBSZXBvcnRDb21wb25lbnQ7XG4gIHB1YmxpYyByZXBvcnQ6IFJlcG9ydDtcblxuICBwdWJsaWMgc2VsZWN0ZWRUYWIgPSAnc2V0dGluZ3MnO1xuXG4gIHB1YmxpYyB0aXRsZSA9ICcnO1xuXG4gIC8vIENvbXBvbmVudCBwYWRkaW5nIGluIGluY2hlcy4gYG51bWJlciB8IHN0cmluZ2AgZm9yIHRoZSBzYW1lIHJlYXNvbiBhcyB0aGVcbiAgLy8gcGFnZSBkaW1lbnNpb25zIGluIHJlcG9ydC1zZXR0aW5nczogZnNNYXNrTnVtYmVyIHNlZWRzIGZyb20gdGhlIG51bWJlciBidXRcbiAgLy8gaGFuZHMgYmFjayB0aGUgdW5tYXNrZWQgc3RyaW5nLCBhbmQgc2F2ZSBjYXN0cyBpdCBvbmNlIG9uIHRoZSB3YXkgb3V0LlxuICBwdWJsaWMgcGFkZGluZ1RvcDogbnVtYmVyIHwgc3RyaW5nID0gREVGQVVMVF9DT01QT05FTlRfUEFERElORztcbiAgcHVibGljIHBhZGRpbmdSaWdodDogbnVtYmVyIHwgc3RyaW5nID0gREVGQVVMVF9DT01QT05FTlRfUEFERElORztcbiAgcHVibGljIHBhZGRpbmdCb3R0b206IG51bWJlciB8IHN0cmluZyA9IERFRkFVTFRfQ09NUE9ORU5UX1BBRERJTkc7XG4gIHB1YmxpYyBwYWRkaW5nTGVmdDogbnVtYmVyIHwgc3RyaW5nID0gREVGQVVMVF9DT01QT05FTlRfUEFERElORztcblxuICBwdWJsaWMgY29uZmlnSnNvbiA9ICcnO1xuXG4gIC8vIC0tLS0gS1BJIGNhcmQgc3RhdGUgKGEgZGVyaXZlZCBLUEkgb25seSkgLS0tLVxuICBwdWJsaWMgcmVhZG9ubHkga3BpUG9sYXJpdHlPcHRpb25zID0gS1BJX0NIQU5HRV9QT0xBUklUWV9PUFRJT05TO1xuICBwdWJsaWMgcmVhZG9ubHkgZ3JhbnVsYXJpdHlPcHRpb25zID0gR1JBTlVMQVJJVFlfT1BUSU9OUztcbiAgcHVibGljIHJlYWRvbmx5IHNwYXJrbGluZU1pblBlcmlvZHMgPSBLUElfU1BBUktMSU5FX01JTl9QRVJJT0RTO1xuICBwdWJsaWMgcmVhZG9ubHkgc3BhcmtsaW5lTWF4UGVyaW9kcyA9IEtQSV9TUEFSS0xJTkVfTUFYX1BFUklPRFM7XG4gIHB1YmxpYyByZWFkb25seSBrcGlDYXJkID0gc2lnbmFsKGZhbHNlKTtcbiAgcHVibGljIHJlYWRvbmx5IGluY3JlYXNlSXMgPSBzaWduYWw8UmVwb3J0Q2hhbmdlUG9sYXJpdHk+KFJlcG9ydENoYW5nZVBvbGFyaXR5Lkdvb2QpO1xuICAvLyBUaGUgdGFyZ2V0IGFzIHR5cGVkOiBmc01hc2tOdW1iZXIgaGFuZHMgYmFjayB0aGUgdW5tYXNrZWQgc3RyaW5nLiBFbXB0eVxuICAvLyBtZWFucyBubyB0YXJnZXQuIEEgcGVyY2VudCBLUEkncyBpcyBpbiBwZXJjZW50ICh0YXJnZXRQZXJjZW50KS5cbiAgcHVibGljIHJlYWRvbmx5IHRhcmdldFZhbHVlID0gc2lnbmFsPG51bWJlciB8IHN0cmluZyB8IG51bGw+KG51bGwpO1xuICBwdWJsaWMgcmVhZG9ubHkgdGFyZ2V0TGFiZWwgPSBzaWduYWwoJycpO1xuICBwdWJsaWMgcmVhZG9ubHkgdGFyZ2V0UGVyY2VudCA9IHNpZ25hbChmYWxzZSk7XG4gIHB1YmxpYyByZWFkb25seSBoYXNUYXJnZXQgPSBjb21wdXRlZCgoKSA9PiB0aGlzLl9udW1iZXIodGhpcy50YXJnZXRWYWx1ZSgpKSAhPT0gbnVsbCk7XG4gIHB1YmxpYyByZWFkb25seSBzcGFya2xpbmUgPSBzaWduYWwoZmFsc2UpO1xuICBwdWJsaWMgcmVhZG9ubHkgc3BhcmtsaW5lR3JhbnVsYXJpdHkgPSBzaWduYWw8Q2hhcnRHcmFudWxhcml0eT4oS1BJX1NQQVJLTElORV9ERUZBVUxUX0dSQU5VTEFSSVRZKTtcbiAgcHVibGljIHJlYWRvbmx5IHNwYXJrbGluZVBlcmlvZHMgPSBzaWduYWw8bnVtYmVyIHwgc3RyaW5nPihLUElfU1BBUktMSU5FX0RFRkFVTFRfUEVSSU9EUyk7XG5cbiAgLy8gLS0tLSBTUUwgdGFiIHN0YXRlIC0tLS1cbiAgLy8gVGhlIHN0YXRlbWVudCwgb25jZSBmZXRjaGVkLiBOdWxsIHdoaWxlIGl0IGlzIGluIGZsaWdodCwgYW5kIG51bGwgd2hlbiB0aGVcbiAgLy8gY29tcG9uZW50J3MgZG9jdW1lbnQgY291bGQgbm90IGJlIGNvbXBpbGVkIChzcWxFcnJvciB0aGVuIHNheXMgd2h5KS5cbiAgcHVibGljIHJlYWRvbmx5IHNxbCA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcbiAgLy8gVHJ1ZSB3aGVuIHRoZSBzdGF0ZW1lbnQgaXMgYSBERVJJVkVEIGJhc2VsaW5lOiBubyBmaWx0ZXJzLCB0aGUgYXV0aG9yZWRcbiAgLy8gZ3JhaW4sIHRpbWVzIGluIHRoZSByZXBvcnQncyBlZmZlY3RpdmUgem9uZS4gVGhlIHRhYiBzYXlzIHNvLCBiZWNhdXNlIHRoZVxuICAvLyBudW1iZXJzIG9uIHNjcmVlbiBjb21lIGZyb20gdGhpcyBzdGF0ZW1lbnQgcGx1cyB0aGUgdmlld2VyJ3Mgb3duIGNob2ljZXNcbiAgLy8gYW5kIHRoZSB0d28gY2FuIGRpZmZlci5cbiAgcHVibGljIHJlYWRvbmx5IHNxbEJhc2VsaW5lID0gc2lnbmFsKGZhbHNlKTtcbiAgLy8gVGhlIHpvbmUgdGhlIHN0YXRlbWVudCB3YXMgY29tcGlsZWQgaW46IHRoZSByZXBvcnQncyBlZmZlY3RpdmUgem9uZSwgc2VudFxuICAvLyB3aXRoIHRoZSBTUUwuIEEgc2VydmVyIHRvbyBvbGQgdG8gc2VuZCBpdCBjb21waWxlZCBpbiBVVEMuXG4gIHB1YmxpYyByZWFkb25seSBzcWxUaW1lem9uZSA9IHNpZ25hbCgnVVRDJyk7XG4gIHB1YmxpYyByZWFkb25seSBzcWxFcnJvciA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuICAvLyAtLS0tIGZpbHRlciBtYW5hZ2VtZW50IHN0YXRlIC0tLS1cbiAgLy8gT25lIHJvdyBwZXIgZmlsdGVyYWJsZSBjb2x1bW4uIFRoZSB0d28gYm9vbGVhbnMgZHJpdmUgdGhlIHRvZ2dsZXM7IHdlIGZsaXBcbiAgLy8gdGhlbSBvcHRpbWlzdGljYWxseSBvbiBjbGljayAoc28gdGhlIFVJIG5ldmVyIGJsaW5rcyB3aGlsZSB0aGUgcmVxdWVzdCBpc1xuICAvLyBpbiBmbGlnaHQpIGFuZCByZWNvbmNpbGUgZnJvbSB0aGUgc2VydmVyIG9uIHJlbG9hZC5cbiAgcHVibGljIHJlYWRvbmx5IHJvd3MgPSBzaWduYWw8RmlsdGVyUm93W10+KFtdKTtcbiAgcHVibGljIHJlYWRvbmx5IGNvbHVtbnNFcnJvciA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuICAvLyBUaGUgcmF3IGlucHV0cyB0aGUgcm93cyBhcmUgYnVpbHQgZnJvbS5cbiAgcHJpdmF0ZSBfZmlsdGVyYWJsZUNvbHVtbnM6IFJlcG9ydEZpbHRlcmFibGVDb2x1bW5bXSA9IFtdO1xuICBwcml2YXRlIF9maWx0ZXJzOiBSZXBvcnRGaWx0ZXJbXSA9IFtdO1xuICBwcml2YXRlIF9ncm91cHNCeUlkID0gbmV3IE1hcDxudW1iZXIsIFJlcG9ydEZpbHRlckdyb3VwPigpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3R5cGVMYWJlbHM6IFJlY29yZDxSZXBvcnRGaWx0ZXJUeXBlLCBzdHJpbmc+ID0ge1xuICAgIHNlbGVjdDogJ1BpY2sgdmFsdWVzJyxcbiAgICBkYXRlUmFuZ2U6ICdEYXRlIHJhbmdlJyxcbiAgICBrZXl3b3JkOiAnU2VhcmNoIHRleHQnLFxuICB9O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX2RhdGE6IHsgcmVwb3J0OiBSZXBvcnQ7IGNvbXBvbmVudDogUmVwb3J0Q29tcG9uZW50IH0gPSBpbmplY3QoTUFUX0RJQUxPR19EQVRBKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfZGlhbG9nUmVmID0gaW5qZWN0PE1hdERpYWxvZ1JlZjxDb21wb25lbnRTZXR0aW5nc0NvbXBvbmVudCwgQ29tcG9uZW50U2V0dGluZ3NSZXN1bHQ+PihNYXREaWFsb2dSZWYpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9yZXBvcnREYXRhID0gaW5qZWN0KFJlcG9ydERhdGEpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9tZXNzYWdlID0gaW5qZWN0KEZzTWVzc2FnZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Byb21wdCA9IGluamVjdChGc1Byb21wdCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2Rlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cbiAgcHVibGljIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMucmVwb3J0ID0gdGhpcy5fZGF0YS5yZXBvcnQ7XG4gICAgdGhpcy5jb21wb25lbnQgPSB0aGlzLl9kYXRhLmNvbXBvbmVudDtcblxuICAgIHRoaXMudGl0bGUgPSB0aGlzLmNvbXBvbmVudC50aXRsZSA/PyAnJztcblxuICAgIGNvbnN0IHBhZGRpbmcgPSB0aGlzLmNvbXBvbmVudC5jb25maWc/LnBhZGRpbmc7XG4gICAgdGhpcy5wYWRkaW5nVG9wID0gcGFkZGluZz8udG9wID8/IERFRkFVTFRfQ09NUE9ORU5UX1BBRERJTkc7XG4gICAgdGhpcy5wYWRkaW5nUmlnaHQgPSBwYWRkaW5nPy5yaWdodCA/PyBERUZBVUxUX0NPTVBPTkVOVF9QQURESU5HO1xuICAgIHRoaXMucGFkZGluZ0JvdHRvbSA9IHBhZGRpbmc/LmJvdHRvbSA/PyBERUZBVUxUX0NPTVBPTkVOVF9QQURESU5HO1xuICAgIHRoaXMucGFkZGluZ0xlZnQgPSBwYWRkaW5nPy5sZWZ0ID8/IERFRkFVTFRfQ09NUE9ORU5UX1BBRERJTkc7XG5cbiAgICB0aGlzLmNvbmZpZ0pzb24gPSBKU09OLnN0cmluZ2lmeSh0aGlzLmNvbXBvbmVudC5jb25maWcgPz8ge30sIG51bGwsIDIpO1xuXG4gICAgdGhpcy5fc2VlZEtwaUNhcmQoKTtcblxuICAgIHRoaXMuX3NlZWRGaWx0ZXJzKHRoaXMucmVwb3J0LCB0aGlzLmNvbXBvbmVudC5pZCk7XG4gICAgdGhpcy5fbG9hZENvbHVtbnMoKTtcbiAgICB0aGlzLl9sb2FkU3FsKCk7XG4gIH1cblxuICAvLyBIdW1hbi1mcmllbmRseSBuYW1lIGZvciB0aGUgaW5mZXJyZWQgaW50ZXJmYWNlIHNob3duIGJlc2lkZSBlYWNoIGNvbHVtbi5cbiAgcHVibGljIHR5cGVMYWJlbCh0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fdHlwZUxhYmVsc1t0eXBlXSA/PyB0eXBlO1xuICB9XG5cbiAgLy8gQ29uZmlybSBhbmQgZGVsZXRlIGhlcmUsIHdoaWxlIHRoZSBkaWFsb2cgaXMgc3RpbGwgb3BlbiwgdGhlbiBjbG9zZSB3aXRoIGFcbiAgLy8gYGRlbGV0ZWRgIHJlc3VsdCBmb3IgdGhlIHBhZ2UgdG8gYWN0IG9uIOKAlCB0aGUgc2FtZSBzaGFwZSB0aGUgcmVwb3J0XG4gIC8vIHNldHRpbmdzIGRpYWxvZyB1c2VzIGZvciBkZWxldGluZyBhIHJlcG9ydC5cbiAgLy9cbiAgLy8gVGhlIGNvbmZpcm0gc2F5cyBpdCBjYW5ub3QgYmUgdW5kb25lIGJlY2F1c2UsIGZyb20gdGhlIFVJLCBpdCBjYW5ub3Q6IHRoZVxuICAvLyByb3cgaXMgc29mdC1kZWxldGVkIHNlcnZlci1zaWRlIGJ1dCBub3RoaW5nIGhlcmUgcmVzdG9yZXMgYSBjb21wb25lbnQuXG4gIHB1YmxpYyBkZWxldGUoKTogdm9pZCB7XG4gICAgdGhpcy5fcHJvbXB0LmNvbmZpcm0oe1xuICAgICAgdGl0bGU6ICdEZWxldGUgQ29tcG9uZW50JyxcbiAgICAgIHRlbXBsYXRlOiBgQXJlIHlvdSBzdXJlIHlvdSB3b3VsZCBsaWtlIHRvIGRlbGV0ZSBcIiR7dGhpcy5jb21wb25lbnQudGl0bGUgfHwgJ3RoaXMgY29tcG9uZW50J31cIj8gVGhpcyBjYW5ub3QgYmUgdW5kb25lLmAsXG4gICAgfSlcbiAgICAgIC5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoKCkgPT4gdGhpcy5fcmVwb3J0RGF0YS5kZWxldGVDb21wb25lbnQodGhpcy5yZXBvcnQuaWQsIHRoaXMuY29tcG9uZW50LmlkKSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3MoJ0NvbXBvbmVudCBkZWxldGVkJyk7XG4gICAgICAgIHRoaXMuX2RpYWxvZ1JlZi5jbG9zZSh7IGRlbGV0ZWQ6IHRydWUgfSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIEEgcGVyY2VudCB0YXJnZXQncyBib3VuZCwgaW4gdGhlIHBlcmNlbnQgaXQgaXMgdHlwZWQgaW4uIEl0IHJlYWRzIHRoZVxuICAvLyBjb250cm9sLCB3aGljaCBmc0Zvcm0gdmFsaWRhdGVzIGJlZm9yZSBuZ01vZGVsQ2hhbmdlIHVwZGF0ZXMgdGhlIHNpZ25hbC5cbiAgcHVibGljIHZhbGlkYXRlVGFyZ2V0ID0gKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCk6IHZvaWQgPT4ge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fbnVtYmVyKGNvbnRyb2wudmFsdWUpO1xuXG4gICAgaWYgKHRoaXMudGFyZ2V0UGVyY2VudCgpICYmIHZhbHVlICE9PSBudWxsICYmIHZhbHVlID4gS1BJX1BFUkNFTlRfVEFSR0VUX01BWCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBIHBlcmNlbnQgdGFyZ2V0IGNhbiBiZSBhdCBtb3N0IDEwLDAwMCUnKTtcbiAgICB9XG4gIH07XG5cbiAgcHVibGljIHNhdmUgPSAoKSA9PiB7XG4gICAgY29uc3Qgc2V0dGluZ3M6IENvbXBvbmVudFNldHRpbmdzID0ge1xuICAgICAgdGl0bGU6IHRoaXMudGl0bGUsXG4gICAgICBwYWRkaW5nOiB7XG4gICAgICAgIHRvcDogdGhpcy5fcGFkZGluZyh0aGlzLnBhZGRpbmdUb3ApLFxuICAgICAgICByaWdodDogdGhpcy5fcGFkZGluZyh0aGlzLnBhZGRpbmdSaWdodCksXG4gICAgICAgIGJvdHRvbTogdGhpcy5fcGFkZGluZyh0aGlzLnBhZGRpbmdCb3R0b20pLFxuICAgICAgICBsZWZ0OiB0aGlzLl9wYWRkaW5nKHRoaXMucGFkZGluZ0xlZnQpLFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgLy8gVGhlIGNhcmQga2V5cyBnbyBhcyBjb25maWcga2V5cyBiZXNpZGUgdGhlIHBhZGRpbmcgKGluY3JlYXNlSXMsIHRhcmdldFxuICAgIC8vIGFuZCBzcGFya2xpbmUsIG51bGwgdG8gcmVtb3ZlIG9uZSksIGFuZCBvbmx5IHdoZW4gdGhleSBjaGFuZ2VkLCBzbyBhXG4gICAgLy8gdGl0bGUgZWRpdCBuZXZlciB0b3VjaGVzIHRoZW0uXG4gICAgY29uc3Qga3BpID0gdGhpcy5rcGlDYXJkKCkgPyB0aGlzLl9rcGlDYXJkU2V0dGluZ3MoKSA6IG51bGw7XG4gICAgY29uc3Qga3BpQ2hhbmdlZCA9ICEha3BpXG4gICAgICAmJiAhc2FtZUtwaUNhcmRTZXR0aW5ncyhrcGksIGtwaUNhcmRTZXR0aW5ncyh0aGlzLmNvbXBvbmVudC5jb25maWcgYXMgS3BpQ29uZmlnKSk7XG5cbiAgICByZXR1cm4gdGhpcy5fcmVwb3J0RGF0YS51cGRhdGVDb21wb25lbnQodGhpcy5yZXBvcnQuaWQsIHRoaXMuY29tcG9uZW50LmlkLCB7XG4gICAgICB0aXRsZTogc2V0dGluZ3MudGl0bGUsXG4gICAgICBwYWRkaW5nOiBzZXR0aW5ncy5wYWRkaW5nLFxuICAgICAgLi4uKGtwaUNoYW5nZWQgPyBrcGkgOiB7fSksXG4gICAgfSlcbiAgICAgIC5waXBlKFxuICAgICAgICB0YXAoKHJlc3BvbnNlOiBDb21wb25lbnRTZXR0aW5nc1Jlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgLy8gVGhlIGNhcmQgaXMgZHJhd24gZnJvbSB0aGUga2V5cyB0aGUgc2VydmVyIHNhdmVkLCByZWFkIGJhY2sgZnJvbVxuICAgICAgICAgIC8vIHRoZSBjb25maWcgaXQgcmV0dXJucy4gQSBzZXJ2ZXIgdGhhdCByZXR1cm5zIG5vIGNvbmZpZyBkaWQgbm90XG4gICAgICAgICAgLy8gc2F2ZSB0aGVtLCBzbyB0aGUgY2FyZCBrZWVwcyB3aGF0IGl0IGhhZCBhbmQgdGhlIGRpYWxvZyBzYXlzIHNvLlxuICAgICAgICAgIGNvbnN0IHNhdmVkID0ga3BpQ2hhbmdlZCA/IHRoaXMuX3NhdmVkS3BpQ2FyZChyZXNwb25zZSkgOiBudWxsO1xuXG4gICAgICAgICAgaWYgKGtwaUNoYW5nZWQgJiYgIXNhdmVkKSB7XG4gICAgICAgICAgICB0aGlzLl9tZXNzYWdlLndhcm5pbmcoJ0NvbXBvbmVudCBzYXZlZCwgYnV0IHRoZSBzZXJ2ZXIgZGlkIG5vdCBzYXZlIHRoZSBjYXJkIHNldHRpbmdzJyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX21lc3NhZ2Uuc3VjY2VzcygnQ29tcG9uZW50IHNhdmVkJyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5fZGlhbG9nUmVmLmNsb3NlKHsgc2V0dGluZ3M6IHNhdmVkID8geyAuLi5zZXR0aW5ncywga3BpOiBzYXZlZCB9IDogc2V0dGluZ3MgfSk7XG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgfTtcblxuICAvLyBGbGlwIG9uZSBleHBvc3VyZSAocmVwb3J0IGJhciBvciB0aGlzIGNvbXBvbmVudCkgZm9yIGEgcm93LiBXZSB1cGRhdGUgdGhlXG4gIC8vIHJvdydzIGJvb2xlYW4gZmlyc3Qg4oCUIHNvIHRoZSB0b2dnbGUgc3RheXMgcHV0IHdpdGggbm8gYmxpbmsg4oCUIHRoZW4gcGVyc2lzdFxuICAvLyBhbmQgcmVjb25jaWxlIG9uIHJlbG9hZC4gTmVpdGhlciBvbiDihpIgbm8gZmlsdGVyIChyZW1vdmVkKTsgZWl0aGVyIG9uIOKGkiB0aGVcbiAgLy8gZmlsdGVyIGV4aXN0cyBhdCB0aGUgY29tYmluZWQgbGV2ZWwuIFRoZSBpbnRlcmZhY2UgdHlwZSBpcyBpbmZlcnJlZFxuICAvLyBzZXJ2ZXItc2lkZS5cbiAgcHVibGljIHNldEV4cG9zdXJlKHJvdzogRmlsdGVyUm93LCB0YXJnZXQ6ICdyZXBvcnQnIHwgJ2NvbXBvbmVudCcsIG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgcm93W3RhcmdldF0gPSBvbjtcblxuICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5fZmlsdGVycy5maW5kKChmaWx0ZXIpID0+IGZpbHRlci5maWx0ZXJDb2x1bW4gPT09IHJvdy5jb2x1bW4pO1xuXG4gICAgaWYgKCFyb3cucmVwb3J0ICYmICFyb3cuY29tcG9uZW50KSB7XG4gICAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgICAgdGhpcy5fcnVuKHRoaXMuX3JlcG9ydERhdGEuZGVsZXRlRmlsdGVyKHRoaXMucmVwb3J0LmlkLCBleGlzdGluZy5pZCkpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgbGV2ZWw6IFJlcG9ydEZpbHRlckxldmVsID0gcm93LnJlcG9ydCAmJiByb3cuY29tcG9uZW50XG4gICAgICA/ICdib3RoJ1xuICAgICAgOiAocm93LnJlcG9ydCA/ICdyZXBvcnQnIDogJ2NvbXBvbmVudCcpO1xuXG4gICAgaWYgKGV4aXN0aW5nKSB7XG4gICAgICB0aGlzLl9ydW4odGhpcy5fcmVwb3J0RGF0YS51cGRhdGVGaWx0ZXJHcm91cCh0aGlzLnJlcG9ydC5pZCwgZXhpc3RpbmcuZmlsdGVyR3JvdXBJZCwgeyBsZXZlbCB9KSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX3J1bih0aGlzLl9yZXBvcnREYXRhLmFkZEZpbHRlcih0aGlzLnJlcG9ydC5pZCwgdGhpcy5jb21wb25lbnQuaWQsIHtcbiAgICAgICAgZmlsdGVyQ29sdW1uOiByb3cuY29sdW1uLFxuICAgICAgICBsYWJlbDogcm93LmxhYmVsLFxuICAgICAgICBsZXZlbCxcbiAgICAgIH0pKTtcbiAgICB9XG4gIH1cblxuICAvLyBBIGRlcml2ZWQgS1BJJ3MgY2FyZCBrZXlzLCBmcm9tIGl0cyBjb25maWcuIEEgc3FsLW1vZGUgS1BJIGNhbm5vdCBjYXJyeVxuICAvLyB0aGVtLCBzbyBpdCBnZXRzIG5vIGNhcmQgZmllbGRzLlxuICBwcml2YXRlIF9zZWVkS3BpQ2FyZCgpOiB2b2lkIHtcbiAgICBjb25zdCBjb25maWcgPSAodGhpcy5jb21wb25lbnQuY29uZmlnID8/IHt9KSBhcyBLcGlDb25maWc7XG5cbiAgICB0aGlzLmtwaUNhcmQuc2V0KHRoaXMuY29tcG9uZW50LnR5cGUgPT09ICdrcGknICYmICF0aGlzLmNvbXBvbmVudC5zcWwpO1xuICAgIHRoaXMuaW5jcmVhc2VJcy5zZXQoY29uZmlnLmluY3JlYXNlSXMgPz8gUmVwb3J0Q2hhbmdlUG9sYXJpdHkuR29vZCk7XG4gICAgdGhpcy50YXJnZXRQZXJjZW50LnNldChjb25maWcubWVhc3VyZT8uZm9ybWF0ID09PSBSZXBvcnRWYWx1ZUZvcm1hdC5QZXJjZW50XG4gICAgICAmJiByZXNvbHZlRm9ybWF0Q29udGV4dCh0aGlzLnJlcG9ydCkucmF0aW9QZXJjZW50KTtcbiAgICB0aGlzLnRhcmdldFZhbHVlLnNldCh0aGlzLl90YXJnZXRTaG93bihjb25maWcudGFyZ2V0Py52YWx1ZSA/PyBudWxsKSk7XG4gICAgdGhpcy50YXJnZXRMYWJlbC5zZXQoY29uZmlnLnRhcmdldD8ubGFiZWwgPz8gJycpO1xuICAgIHRoaXMuc3BhcmtsaW5lLnNldCghIWNvbmZpZy5zcGFya2xpbmUpO1xuICAgIHRoaXMuc3BhcmtsaW5lR3JhbnVsYXJpdHkuc2V0KGNvbmZpZy5zcGFya2xpbmU/LmdyYW51bGFyaXR5ID8/IEtQSV9TUEFSS0xJTkVfREVGQVVMVF9HUkFOVUxBUklUWSk7XG4gICAgdGhpcy5zcGFya2xpbmVQZXJpb2RzLnNldChjb25maWcuc3BhcmtsaW5lPy5wZXJpb2RzID8/IEtQSV9TUEFSS0xJTkVfREVGQVVMVF9QRVJJT0RTKTtcbiAgfVxuXG4gIC8vIFRoZSBjYXJkIGtleXMgdGhlIHNlcnZlciBzYXZlZCwgZnJvbSB0aGUgY29uZmlnIGl0cyByZXNwb25zZSBjYXJyaWVzO1xuICAvLyBudWxsIHdoZW4gaXQgY2FycmllcyBub25lIChhIHNlcnZlciB0aGF0IGRvZXMgbm90IHNhdmUgdGhlbSkuXG4gIHByaXZhdGUgX3NhdmVkS3BpQ2FyZChyZXNwb25zZTogQ29tcG9uZW50U2V0dGluZ3NSZXNwb25zZSB8IG51bGwgfCB1bmRlZmluZWQpOiBLcGlDYXJkU2V0dGluZ3MgfCBudWxsIHtcbiAgICBjb25zdCBjb25maWcgPSByZXNwb25zZT8uY29uZmlnO1xuXG4gICAgcmV0dXJuIGNvbmZpZyAmJiB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyA/IGtwaUNhcmRTZXR0aW5ncyhjb25maWcgYXMgS3BpQ29uZmlnKSA6IG51bGw7XG4gIH1cblxuICAvLyBHb29kIGlzIHdoYXQgYW4gYWJzZW50IGluY3JlYXNlSXMgcmVhZHMsIHNvIGl0IGlzIHNhdmVkIGFzIGFic2VudC5cbiAgcHJpdmF0ZSBfa3BpQ2FyZFNldHRpbmdzKCk6IEtwaUNhcmRTZXR0aW5ncyB7XG4gICAgY29uc3QgdGFyZ2V0ID0gdGhpcy5fbnVtYmVyKHRoaXMudGFyZ2V0VmFsdWUoKSk7XG4gICAgY29uc3QgbGFiZWwgPSB0aGlzLnRhcmdldExhYmVsKCkudHJpbSgpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGluY3JlYXNlSXM6IHRoaXMuaW5jcmVhc2VJcygpID09PSBSZXBvcnRDaGFuZ2VQb2xhcml0eS5Hb29kID8gbnVsbCA6IHRoaXMuaW5jcmVhc2VJcygpLFxuICAgICAgdGFyZ2V0OiB0YXJnZXQgPT09IG51bGwgPyBudWxsIDogeyB2YWx1ZTogdGhpcy5fdGFyZ2V0U3RvcmVkKHRhcmdldCksIGxhYmVsOiBsYWJlbCB8fCBudWxsIH0sXG4gICAgICBzcGFya2xpbmU6IHRoaXMuc3BhcmtsaW5lKClcbiAgICAgICAgPyB7IGdyYW51bGFyaXR5OiB0aGlzLnNwYXJrbGluZUdyYW51bGFyaXR5KCksIHBlcmlvZHM6IHRoaXMuX251bWJlcih0aGlzLnNwYXJrbGluZVBlcmlvZHMoKSkgfVxuICAgICAgICA6IG51bGwsXG4gICAgfTtcbiAgfVxuXG4gIC8vIEEgc3RvcmVkIHJhdGlvIGFzIHRoZSBwZXJjZW50IHR5cGVkLCByb3VuZGVkIHNvIDAuMTUgcmVhZHMgMTUgYW5kIG5vdFxuICAvLyAxNS4wMDAwMDAwMDAwMDAwMDIuXG4gIHByaXZhdGUgX3RhcmdldFNob3duKHZhbHVlOiBudW1iZXIgfCBudWxsKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgaWYgKHZhbHVlID09PSBudWxsIHx8ICF0aGlzLnRhcmdldFBlcmNlbnQoKSkge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cblxuICAgIHJldHVybiBNYXRoLnJvdW5kKHZhbHVlICogMTAwICogMWU2KSAvIDFlNjtcbiAgfVxuXG4gIHByaXZhdGUgX3RhcmdldFN0b3JlZCh2YWx1ZTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50YXJnZXRQZXJjZW50KCkgPyB2YWx1ZSAvIDEwMCA6IHZhbHVlO1xuICB9XG5cbiAgLy8gQSB0eXBlZCBudW1iZXIsIG9yIG51bGwgd2hlbiB0aGUgZmllbGQgaXMgZW1wdHkuXG4gIHByaXZhdGUgX251bWJlcih2YWx1ZTogbnVtYmVyIHwgc3RyaW5nIHwgbnVsbCk6IG51bWJlciB8IG51bGwge1xuICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gJycpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IG51bWJlciA9IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgPyB2YWx1ZSA6IHBhcnNlRmxvYXQodmFsdWUpO1xuXG4gICAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShudW1iZXIpID8gbnVtYmVyIDogbnVsbDtcbiAgfVxuXG4gIC8vIFRoZSBwYWRkaW5nIGFzIGEgcmVhbCBudW1iZXIgZm9yIHRoZSB3aXJlLiBmc01hc2tOdW1iZXIgaGFuZHMgYmFjayB0aGVcbiAgLy8gdW5tYXNrZWQgc3RyaW5nIGl0IGJ1aWx0IHdpdGggYSBmaXhlZCAnLicgcmFkaXgsIHNvIHRoaXMgaXMgYSBzdHJhaWdodFxuICAvLyBwYXJzZSAtIHRoZSB3aG9sZSByZWFzb24gZm9yIHRoZSBtYXNrIGlzIHRoYXQgYSBuYXRpdmUgbnVtYmVyIGlucHV0IHdvdWxkXG4gIC8vIHBhaW50IChhbmQgcmVhZCBiYWNrKSB0aGUgdmlld2VyJ3Mgb3duIGxvY2FsZSBzZXBhcmF0b3IgaW5zdGVhZC5cbiAgcHJpdmF0ZSBfcGFkZGluZyh2YWx1ZTogbnVtYmVyIHwgc3RyaW5nKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyA/IHZhbHVlIDogcGFyc2VGbG9hdCh2YWx1ZSk7XG4gIH1cblxuICAvLyBSdW4gYSBmaWx0ZXIgbXV0YXRpb24sIHRoZW4gcmVsb2FkIHRvIHJlY29uY2lsZSB0aGUgb3B0aW1pc3RpYyBzdGF0ZS5cbiAgcHJpdmF0ZSBfcnVuKHJlcXVlc3Q6IE9ic2VydmFibGU8dW5rbm93bj4pOiB2b2lkIHtcbiAgICByZXF1ZXN0LnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoKSA9PiB0aGlzLl9hZnRlck11dGF0aW9uKCksXG4gICAgICBlcnJvcjogKGVycm9yKSA9PiB0aGlzLl9tdXRhdGlvbkVycm9yKGVycm9yKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8vIEJ1aWxkIHRoZSByb3cgdmlldy1tb2RlbCBmcm9tIHRoZSBsb2FkZWQgY29sdW1ucyArIGZpbHRlcnMvZ3JvdXBzLiBFYWNoXG4gIC8vIHJvdydzIHRvZ2dsZXMgcmVmbGVjdCB3aGVyZSBpdHMgZmlsdGVyIGdyb3VwIGlzIGN1cnJlbnRseSBleHBvc2VkLlxuICBwcml2YXRlIF9yZWJ1aWxkUm93cygpOiB2b2lkIHtcbiAgICB0aGlzLnJvd3Muc2V0KHRoaXMuX2ZpbHRlcmFibGVDb2x1bW5zLm1hcCgoY29sdW1uKSA9PiB7XG4gICAgICBjb25zdCBmaWx0ZXIgPSB0aGlzLl9maWx0ZXJzLmZpbmQoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLmZpbHRlckNvbHVtbiA9PT0gY29sdW1uLmNvbHVtbik7XG4gICAgICBjb25zdCBsZXZlbCA9IGZpbHRlciA/IHRoaXMuX2dyb3Vwc0J5SWQuZ2V0KGZpbHRlci5maWx0ZXJHcm91cElkKT8ubGV2ZWwgOiB1bmRlZmluZWQ7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbHVtbjogY29sdW1uLmNvbHVtbixcbiAgICAgICAgdHlwZTogY29sdW1uLnR5cGUsXG4gICAgICAgIGxhYmVsOiBmaWx0ZXI/LmxhYmVsXG4gICAgICAgICAgfHwgdGhpcy5fZ3JvdXBzQnlJZC5nZXQoZmlsdGVyPy5maWx0ZXJHcm91cElkID8/IC0xKT8ubGFiZWxcbiAgICAgICAgICB8fCB0aGlzLl9odW1hbml6ZShjb2x1bW4uY29sdW1uKSxcbiAgICAgICAgcmVwb3J0OiBsZXZlbCA9PT0gJ3JlcG9ydCcgfHwgbGV2ZWwgPT09ICdib3RoJyxcbiAgICAgICAgY29tcG9uZW50OiBsZXZlbCA9PT0gJ2NvbXBvbmVudCcgfHwgbGV2ZWwgPT09ICdib3RoJyxcbiAgICAgIH07XG4gICAgfSkpO1xuICB9XG5cbiAgLy8gQWZ0ZXIgYW55IGZpbHRlciBtdXRhdGlvbjogcmUtZmV0Y2ggdGhlIHJlcG9ydCBzbyB0aGUgZGlhbG9nJ3MgZmlsdGVyIGxpc3RcbiAgLy8gKGFuZCB0aGUgcGFyZW50IGNhbnZhcywgb24gY2xvc2UpIHJlZmxlY3QgdGhlIG5ldyBncm91cHMvbGV2ZWxzLlxuICBwcml2YXRlIF9hZnRlck11dGF0aW9uKCk6IHZvaWQge1xuICAgIHRoaXMuZmlsdGVyc0NoYW5nZWQuZW1pdCgpO1xuXG4gICAgdGhpcy5fcmVwb3J0RGF0YS5nZXQodGhpcy5yZXBvcnQuaWQpXG4gICAgICAuc3Vic2NyaWJlKChyZXBvcnQ6IFJlcG9ydCkgPT4ge1xuICAgICAgICB0aGlzLnJlcG9ydCA9IHJlcG9ydDtcbiAgICAgICAgdGhpcy5fc2VlZEZpbHRlcnMocmVwb3J0LCB0aGlzLmNvbXBvbmVudC5pZCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX211dGF0aW9uRXJyb3IoZXJyb3I6IGFueSk6IHZvaWQge1xuICAgIHRoaXMuX21lc3NhZ2UuZXJyb3IoZXJyb3I/LmVycm9yPy5tZXNzYWdlID8/IGVycm9yPy5tZXNzYWdlID8/ICdGaWx0ZXIgb3BlcmF0aW9uIGZhaWxlZCcpO1xuICAgIC8vIFJlLXNlZWQgZnJvbSB0aGUgc2VydmVyIHNvIHRoZSBvcHRpbWlzdGljIHRvZ2dsZSBzbmFwcyBiYWNrIHRvIHRydXRoLlxuICAgIHRoaXMuX2FmdGVyTXV0YXRpb24oKTtcbiAgfVxuXG4gIHByaXZhdGUgX3NlZWRGaWx0ZXJzKHJlcG9ydDogUmVwb3J0LCBjb21wb25lbnRJZDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5fZ3JvdXBzQnlJZCA9IG5ldyBNYXAoKHJlcG9ydC5maWx0ZXJHcm91cHMgPz8gW10pLm1hcCgoZ3JvdXApID0+IFtncm91cC5pZCwgZ3JvdXBdKSk7XG5cbiAgICBjb25zdCBjb21wb25lbnQgPSByZXBvcnQucGFnZXNcbiAgICAgIC5mbGF0TWFwKChwYWdlKSA9PiBwYWdlLmNvbXBvbmVudHMpXG4gICAgICAuZmluZCgoY2FuZGlkYXRlKSA9PiBjYW5kaWRhdGUuaWQgPT09IGNvbXBvbmVudElkKTtcblxuICAgIHRoaXMuX2ZpbHRlcnMgPSBjb21wb25lbnQ/LmZpbHRlcnMgPz8gW107XG4gICAgdGhpcy5fcmVidWlsZFJvd3MoKTtcbiAgfVxuXG4gIC8vIFRoZSBzdGF0ZW1lbnQgdGhlIFNRTCB0YWIgc2hvd3MuIEZldGNoZWQgcmF0aGVyIHRoYW4gcmVhZCBvZmYgdGhlXG4gIC8vIGNvbXBvbmVudDogYSBkZXJpdmVkIGNvbXBvbmVudCBzdG9yZXMgYSBkb2N1bWVudCwgbm90IFNRTCwgc28gaXRzXG4gIC8vIHN0YXRlbWVudCBvbmx5IGV4aXN0cyBvbmNlIHRoZSBiYWNrZW5kIGNvbXBpbGVzIGl0LlxuICAvL1xuICAvLyBMb2FkZWQgaW4gbmdPbkluaXQgYmVzaWRlIHRoZSBjb2x1bW5zLCBOT1Qgb24gdGFiIGFjdGl2YXRpb24uIFRoZSB0YWJzIGFyZVxuICAvLyBub3QgbGF6eSAobm8gbWF0VGFiQ29udGVudCksIGFuZCBzd2l0Y2hpbmcgdGhlIHRhYi1ncm91cCdzIGBbKHNlbGVjdGVkKV1gXG4gIC8vIGJhbmFuYS1ib3ggdG8gYSBvbmUtd2F5IGJpbmRpbmcgcGx1cyAoc2VsZWN0ZWRDaGFuZ2UpIHRvIGdldCBhIGhvb2sgd291bGRcbiAgLy8gYnJlYWsgaXQ6IEZzVGFic0hlYWRlclRhYkdyb3VwRGlyZWN0aXZlIHNlbGYtYXNzaWducyBgdGhpcy5zZWxlY3RlZGAgYmVmb3JlXG4gIC8vIGl0IGVtaXRzLCBzbyB0aGUgZXZlbnQgaXMgZmlsdGVyZWQgb3V0IGFuZCB0aGUgbG9hZCB3b3VsZCBuZXZlciBmaXJlLiBPbmVcbiAgLy8gc21hbGwgcmVxdWVzdCB3aGVuIGEgZGlhbG9nIG9wZW5zIGlzIG5vdCB3b3J0aCB0aGF0IHJpc2suXG4gIHByaXZhdGUgX2xvYWRTcWwoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVwb3J0RGF0YS5jb21wb25lbnRTcWwodGhpcy5yZXBvcnQuaWQsIHRoaXMuY29tcG9uZW50LmlkKVxuICAgICAgLnN1YnNjcmliZSh7XG4gICAgICAgIG5leHQ6IChwcmV2aWV3OiBSZXBvcnRDb21wb25lbnRTcWwpID0+IHtcbiAgICAgICAgICB0aGlzLnNxbC5zZXQocHJldmlldz8uc3FsID8/IG51bGwpO1xuICAgICAgICAgIHRoaXMuc3FsQmFzZWxpbmUuc2V0KCEhcHJldmlldz8uYmFzZWxpbmUpO1xuICAgICAgICAgIHRoaXMuc3FsVGltZXpvbmUuc2V0KHByZXZpZXc/LnRpbWV6b25lIHx8ICdVVEMnKTtcbiAgICAgICAgICB0aGlzLnNxbEVycm9yLnNldChwcmV2aWV3Py5lcnJvciA/PyBudWxsKTtcbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3I6IChlcnJvcikgPT4ge1xuICAgICAgICAgIHRoaXMuc3FsLnNldChudWxsKTtcbiAgICAgICAgICB0aGlzLnNxbEVycm9yLnNldChlcnJvcj8uZXJyb3I/Lm1lc3NhZ2UgPz8gJ0NvdWxkIG5vdCByZWFkIHRoZSBjb21wb25lbnQgU1FMJyk7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2xvYWRDb2x1bW5zKCk6IHZvaWQge1xuICAgIHRoaXMuX3JlcG9ydERhdGEuY29tcG9uZW50Q29sdW1ucyh0aGlzLnJlcG9ydC5pZCwgdGhpcy5jb21wb25lbnQuaWQpXG4gICAgICAuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKGNvbHVtbnM6IFJlcG9ydEZpbHRlcmFibGVDb2x1bW5bXSkgPT4ge1xuICAgICAgICAgIHRoaXMuX2ZpbHRlcmFibGVDb2x1bW5zID0gY29sdW1ucyA/PyBbXTtcbiAgICAgICAgICB0aGlzLl9yZWJ1aWxkUm93cygpO1xuICAgICAgICB9LFxuICAgICAgICBlcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgICAgdGhpcy5jb2x1bW5zRXJyb3Iuc2V0KGVycm9yPy5lcnJvcj8ubWVzc2FnZSA/PyAnQ291bGQgbm90IHJlYWQgdGhlIGNvbXBvbmVudCBjb2x1bW5zJyk7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2h1bWFuaXplKGNvbHVtbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY29sdW1uXG4gICAgICAucmVwbGFjZSgvW19cXC1dKy9nLCAnICcpXG4gICAgICAucmVwbGFjZSgvXFxzKy9nLCAnICcpXG4gICAgICAudHJpbSgpXG4gICAgICAucmVwbGFjZSgvXFxiXFx3L2csIChjaGFyYWN0ZXIpID0+IGNoYXJhY3Rlci50b1VwcGVyQ2FzZSgpKTtcbiAgfVxufVxuIiwiPGZvcm1cbiAgICBmc0Zvcm1cbiAgICBbc3VibWl0XT1cInNhdmVcIj5cbiAgPGZzLWRpYWxvZz5cbiAgICA8aDEgbWF0LWRpYWxvZy10aXRsZT5cbiAgICAgIHt7IGNvbXBvbmVudC50aXRsZSB8fCAnQ29tcG9uZW50JyB9fVxuICAgIDwvaDE+XG4gICAgPG1hdC1kaWFsb2ctY29udGVudD5cbiAgICAgIDxtYXQtdGFiLWdyb3VwIFsoc2VsZWN0ZWQpXT1cInNlbGVjdGVkVGFiXCI+XG4gICAgICAgIDxtYXQtdGFiXG4gICAgICAgICAgICBsYWJlbD1cIlNldHRpbmdzXCJcbiAgICAgICAgICAgIG5hbWU9XCJzZXR0aW5nc1wiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJmcy1jb2x1bW4gdGFiLWJvZHlcIj5cbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICBUaXRsZVxuICAgICAgICAgICAgICA8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cInRpdGxlXCJcbiAgICAgICAgICAgICAgICBuYW1lPVwidGl0bGVcIj5cbiAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3ViaGVhZGluZy0yXCI+XG4gICAgICAgICAgICAgIFBhZGRpbmdcbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImdlb21ldHJ5LXJvd1wiPlxuICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgIFRvcFxuICAgICAgICAgICAgICAgIDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICAgIGZzTWFza051bWJlclxuICAgICAgICAgICAgICAgICAgW3NjYWxlXT1cIjNcIlxuICAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJwYWRkaW5nVG9wXCJcbiAgICAgICAgICAgICAgICAgIG5hbWU9XCJwYWRkaW5nVG9wXCJcbiAgICAgICAgICAgICAgICAgIFtmc0Zvcm1NaW5dPVwiMFwiPlxuICAgICAgICAgICAgICAgIDxkaXYgbWF0VGV4dFN1ZmZpeD5cbiAgICAgICAgICAgICAgICAgIGluXG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgUmlnaHRcbiAgICAgICAgICAgICAgICA8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgICAgICBmc01hc2tOdW1iZXJcbiAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCIzXCJcbiAgICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwicGFkZGluZ1JpZ2h0XCJcbiAgICAgICAgICAgICAgICAgIG5hbWU9XCJwYWRkaW5nUmlnaHRcIlxuICAgICAgICAgICAgICAgICAgW2ZzRm9ybU1pbl09XCIwXCI+XG4gICAgICAgICAgICAgICAgPGRpdiBtYXRUZXh0U3VmZml4PlxuICAgICAgICAgICAgICAgICAgaW5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICBCb3R0b21cbiAgICAgICAgICAgICAgICA8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgICAgICBmc01hc2tOdW1iZXJcbiAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCIzXCJcbiAgICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwicGFkZGluZ0JvdHRvbVwiXG4gICAgICAgICAgICAgICAgICBuYW1lPVwicGFkZGluZ0JvdHRvbVwiXG4gICAgICAgICAgICAgICAgICBbZnNGb3JtTWluXT1cIjBcIj5cbiAgICAgICAgICAgICAgICA8ZGl2IG1hdFRleHRTdWZmaXg+XG4gICAgICAgICAgICAgICAgICBpblxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgIExlZnRcbiAgICAgICAgICAgICAgICA8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgICAgICBmc01hc2tOdW1iZXJcbiAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCIzXCJcbiAgICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwicGFkZGluZ0xlZnRcIlxuICAgICAgICAgICAgICAgICAgbmFtZT1cInBhZGRpbmdMZWZ0XCJcbiAgICAgICAgICAgICAgICAgIFtmc0Zvcm1NaW5dPVwiMFwiPlxuICAgICAgICAgICAgICAgIDxkaXYgbWF0VGV4dFN1ZmZpeD5cbiAgICAgICAgICAgICAgICAgIGluXG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwhLS0gQSBkZXJpdmVkIEtQSSdzIGNhcmQ6IHdoYXQgYSByaXNlIG1lYW5zLCBhIHRhcmdldCBhbmQgYVxuICAgICAgICAgICAgICAgICBzcGFya2xpbmUuIFRoZSBzZXJ2ZXIgY29tcHV0ZXMgdGhlIHByb2dyZXNzIGFuZCB0aGUgcG9pbnRzLiAtLT5cbiAgICAgICAgICAgIEBpZiAoa3BpQ2FyZCgpKSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdWJoZWFkaW5nLTJcIj5cbiAgICAgICAgICAgICAgICBDYXJkXG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJmdWxsLXdpZHRoXCI+XG4gICAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgIEluY3JlYXNlIGlzXG4gICAgICAgICAgICAgICAgPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgPG1hdC1zZWxlY3RcbiAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiaW5jcmVhc2VJcygpXCJcbiAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwiaW5jcmVhc2VJcy5zZXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIG5hbWU9XCJpbmNyZWFzZUlzXCI+XG4gICAgICAgICAgICAgICAgICBAZm9yIChvcHRpb24gb2Yga3BpUG9sYXJpdHlPcHRpb25zOyB0cmFjayBvcHRpb24udmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgPG1hdC1vcHRpb24gW3ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiPlxuICAgICAgICAgICAgICAgICAgICAgIHt7IG9wdGlvbi5uYW1lIH19XG4gICAgICAgICAgICAgICAgICAgIDwvbWF0LW9wdGlvbj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA8L21hdC1zZWxlY3Q+XG4gICAgICAgICAgICAgICAgPG1hdC1oaW50PlxuICAgICAgICAgICAgICAgICAgQ29sb3JzIHRoZSBjaGFuZ2UgYW5kIGRlY2lkZXMgd2hlbiB0aGUgdGFyZ2V0IGlzIG1ldC5cbiAgICAgICAgICAgICAgICA8L21hdC1oaW50PlxuICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJmdWxsLXdpZHRoXCI+XG4gICAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgIFRhcmdldFxuICAgICAgICAgICAgICAgIDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICAgIGZzTWFza051bWJlclxuICAgICAgICAgICAgICAgICAgW3NjYWxlXT1cIjZcIlxuICAgICAgICAgICAgICAgICAgW3NpZ25lZF09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInRhcmdldFZhbHVlKClcIlxuICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidGFyZ2V0VmFsdWUuc2V0KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgbmFtZT1cInRhcmdldFZhbHVlXCJcbiAgICAgICAgICAgICAgICAgIFt2YWxpZGF0ZV09XCJ2YWxpZGF0ZVRhcmdldFwiPlxuICAgICAgICAgICAgICAgIEBpZiAodGFyZ2V0UGVyY2VudCgpKSB7XG4gICAgICAgICAgICAgICAgICA8ZGl2IG1hdFRleHRTdWZmaXg+XG4gICAgICAgICAgICAgICAgICAgICVcbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA8bWF0LWhpbnQ+XG4gICAgICAgICAgICAgICAgICBUaGUgdmFsdWUgdG8gcmVhY2guIExlYXZlIGVtcHR5IGZvciBubyB0YXJnZXQuXG4gICAgICAgICAgICAgICAgPC9tYXQtaGludD5cbiAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgQGlmIChoYXNUYXJnZXQoKSkge1xuICAgICAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImZ1bGwtd2lkdGhcIj5cbiAgICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICAgIFRhcmdldCBsYWJlbFxuICAgICAgICAgICAgICAgICAgPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwidGFyZ2V0TGFiZWwoKVwiXG4gICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInRhcmdldExhYmVsLnNldCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgbmFtZT1cInRhcmdldExhYmVsXCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LWhpbnQ+XG4gICAgICAgICAgICAgICAgICAgIFNob3duIGJlZm9yZSB0aGUgdGFyZ2V0LCBzdWNoIGFzIEdvYWwuIEVtcHR5IHJlYWRzIFRhcmdldC5cbiAgICAgICAgICAgICAgICAgIDwvbWF0LWhpbnQ+XG4gICAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8ZnMtbGFiZWwtZmllbGQ+XG4gICAgICAgICAgICAgICAgPG1hdC1zbGlkZS10b2dnbGVcbiAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwic3BhcmtsaW5lKClcIlxuICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzcGFya2xpbmUuc2V0KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICBuYW1lPVwic3BhcmtsaW5lXCI+XG4gICAgICAgICAgICAgICAgICBTcGFya2xpbmVcbiAgICAgICAgICAgICAgICA8L21hdC1zbGlkZS10b2dnbGU+XG4gICAgICAgICAgICAgICAgPG1hdC1oaW50PlxuICAgICAgICAgICAgICAgICAgQSBzbWFsbCB0cmVuZCBsaW5lIG9mIHRoZSB2YWx1ZSBvdmVyIGl0cyBsYXN0IHBlcmlvZHMuXG4gICAgICAgICAgICAgICAgPC9tYXQtaGludD5cbiAgICAgICAgICAgICAgPC9mcy1sYWJlbC1maWVsZD5cbiAgICAgICAgICAgICAgQGlmIChzcGFya2xpbmUoKSkge1xuICAgICAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImZ1bGwtd2lkdGhcIj5cbiAgICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICAgIFNwYXJrbGluZSBwZXJpb2RcbiAgICAgICAgICAgICAgICAgIDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgPG1hdC1zZWxlY3RcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJzcGFya2xpbmVHcmFudWxhcml0eSgpXCJcbiAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzcGFya2xpbmVHcmFudWxhcml0eS5zZXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgbmFtZT1cInNwYXJrbGluZUdyYW51bGFyaXR5XCI+XG4gICAgICAgICAgICAgICAgICAgIEBmb3IgKG9wdGlvbiBvZiBncmFudWxhcml0eU9wdGlvbnM7IHRyYWNrIG9wdGlvbi52YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxtYXQtb3B0aW9uIFt2YWx1ZV09XCJvcHRpb24udmFsdWVcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IG9wdGlvbi5uYW1lIH19XG4gICAgICAgICAgICAgICAgICAgICAgPC9tYXQtb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICA8L21hdC1zZWxlY3Q+XG4gICAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJmdWxsLXdpZHRoXCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgICBTcGFya2xpbmUgcGVyaW9kc1xuICAgICAgICAgICAgICAgICAgPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICAgICAgZnNNYXNrTnVtYmVyXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCIwXCJcbiAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwic3BhcmtsaW5lUGVyaW9kcygpXCJcbiAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3BhcmtsaW5lUGVyaW9kcy5zZXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIG5hbWU9XCJzcGFya2xpbmVQZXJpb2RzXCJcbiAgICAgICAgICAgICAgICAgICAgW2ZzRm9ybVJlcXVpcmVkXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgICBbZnNGb3JtSW50ZWdlcl09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgICAgW2ZzRm9ybU1pbl09XCJzcGFya2xpbmVNaW5QZXJpb2RzXCJcbiAgICAgICAgICAgICAgICAgICAgW2ZzRm9ybU1heF09XCJzcGFya2xpbmVNYXhQZXJpb2RzXCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LWhpbnQ+XG4gICAgICAgICAgICAgICAgICAgIEhvdyBtYW55IHBlcmlvZHMgdGhlIGxpbmUgY292ZXJzLCB7eyBzcGFya2xpbmVNaW5QZXJpb2RzIH19IHRvIHt7IHNwYXJrbGluZU1heFBlcmlvZHMgfX0uXG4gICAgICAgICAgICAgICAgICA8L21hdC1oaW50PlxuICAgICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9tYXQtdGFiPlxuICAgICAgICA8bWF0LXRhYlxuICAgICAgICAgICAgbGFiZWw9XCJGaWx0ZXJzXCJcbiAgICAgICAgICAgIG5hbWU9XCJmaWx0ZXJzXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInRhYi1ib2R5XCI+XG4gICAgICAgICAgICBAaWYgKGNvbHVtbnNFcnJvcigpKSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWx0ZXJzLWVtcHR5IGVycm9yXCI+XG4gICAgICAgICAgICAgICAge3sgY29sdW1uc0Vycm9yKCkgfX1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICB9IEBlbHNlIGlmIChyb3dzKCkubGVuZ3RoKSB7XG4gICAgICAgICAgICAgIDwhLS0gRXZlcnkgZmlsdGVyYWJsZSBjb2x1bW4uIFRvZ2dsZSB3aGVyZSBpdHMgY29udHJvbCBzaG93czogaW5cbiAgICAgICAgICAgICAgICAgICB0aGUgcmVwb3J0IGJhciwgb24gdGhpcyBjb21wb25lbnQsIGJvdGgsIG9yIG5laXRoZXIuIFRoZVxuICAgICAgICAgICAgICAgICAgIGludGVyZmFjZSAoZGF0ZSByYW5nZSB2cyB2YWx1ZSBwaWNrZXIpIGZvbGxvd3MgdGhlIGRhdGEuIC0tPlxuICAgICAgICAgICAgICA8dGFibGUgY2xhc3M9XCJmaWx0ZXItdGFibGVcIj5cbiAgICAgICAgICAgICAgICA8dGhlYWQ+XG4gICAgICAgICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgICAgICAgIDx0aCBjbGFzcz1cImZpbHRlci1jb2wtbmFtZVwiPlxuICAgICAgICAgICAgICAgICAgICAgIEZpbHRlclxuICAgICAgICAgICAgICAgICAgICA8L3RoPlxuICAgICAgICAgICAgICAgICAgICA8dGggY2xhc3M9XCJmaWx0ZXItY29sLXR5cGVcIj5cbiAgICAgICAgICAgICAgICAgICAgICBUeXBlXG4gICAgICAgICAgICAgICAgICAgIDwvdGg+XG4gICAgICAgICAgICAgICAgICAgIDx0aCBjbGFzcz1cImZpbHRlci1jb2wtdG9nZ2xlXCI+XG4gICAgICAgICAgICAgICAgICAgICAgUmVwb3J0IGJhclxuICAgICAgICAgICAgICAgICAgICA8L3RoPlxuICAgICAgICAgICAgICAgICAgICA8dGggY2xhc3M9XCJmaWx0ZXItY29sLXRvZ2dsZVwiPlxuICAgICAgICAgICAgICAgICAgICAgIFRoaXMgY29tcG9uZW50XG4gICAgICAgICAgICAgICAgICAgIDwvdGg+XG4gICAgICAgICAgICAgICAgICA8L3RyPlxuICAgICAgICAgICAgICAgIDwvdGhlYWQ+XG4gICAgICAgICAgICAgICAgPHRib2R5PlxuICAgICAgICAgICAgICAgICAgQGZvciAocm93IG9mIHJvd3MoKTsgdHJhY2sgcm93LmNvbHVtbikge1xuICAgICAgICAgICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZmlsdGVyLWNvbC1uYW1lXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICB7eyByb3cubGFiZWwgfX1cbiAgICAgICAgICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZpbHRlci1jb2wtdHlwZVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAge3sgdHlwZUxhYmVsKHJvdy50eXBlKSB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZmlsdGVyLWNvbC10b2dnbGVcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvdy5yZXBvcnRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzZXRFeHBvc3VyZShyb3csICdyZXBvcnQnLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxPcHRpb25zXT1cInsgc3RhbmRhbG9uZTogdHJ1ZSB9XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIlNob3cgaW4gdGhlIHJlcG9ydCBiYXJcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvbWF0LXNsaWRlLXRvZ2dsZT5cbiAgICAgICAgICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZpbHRlci1jb2wtdG9nZ2xlXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxuICAgICAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJyb3cuY29tcG9uZW50XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic2V0RXhwb3N1cmUocm93LCAnY29tcG9uZW50JywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsT3B0aW9uc109XCJ7IHN0YW5kYWxvbmU6IHRydWUgfVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJTaG93IG9uIHRoaXMgY29tcG9uZW50XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L21hdC1zbGlkZS10b2dnbGU+XG4gICAgICAgICAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA8L3Rib2R5PlxuICAgICAgICAgICAgICA8L3RhYmxlPlxuICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWx0ZXJzLWVtcHR5XCI+XG4gICAgICAgICAgICAgICAgVGhpcyBjb21wb25lbnQgaGFzIG5vIGZpbHRlcmFibGUgY29sdW1ucyB5ZXQg4oCUIGdpdmUgaXQgc29tZSBTUUwgZmlyc3QuXG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L21hdC10YWI+XG4gICAgICAgIDxtYXQtdGFiXG4gICAgICAgICAgICBsYWJlbD1cIlNRTFwiXG4gICAgICAgICAgICBuYW1lPVwic3FsXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInRhYi1ib2R5XCI+XG4gICAgICAgICAgICBAaWYgKHNxbEVycm9yKCkpIHtcbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpbHRlcnMtZW1wdHkgZXJyb3JcIj5cbiAgICAgICAgICAgICAgICB7eyBzcWxFcnJvcigpIH19XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgfSBAZWxzZSBpZiAoc3FsKCkpIHtcbiAgICAgICAgICAgICAgQGlmIChzcWxCYXNlbGluZSgpKSB7XG4gICAgICAgICAgICAgICAgPCEtLSBBIGRlcml2ZWQgY29tcG9uZW50J3Mgc3RhdGVtZW50IGlzIGNvbXBpbGVkIGZyb20gaXRzXG4gICAgICAgICAgICAgICAgICAgICBkb2N1bWVudCB3aXRoIG5vIHZpZXdlciBzdGF0ZSwgc28gaXQgaXMgbm90IGJ5dGUtZm9yLWJ5dGVcbiAgICAgICAgICAgICAgICAgICAgIHdoYXQgcHJvZHVjZWQgdGhlIG51bWJlcnMgb24gc2NyZWVuLiBTYWlkIGhlcmUgcmF0aGVyIHRoYW5cbiAgICAgICAgICAgICAgICAgICAgIGxlZnQgZm9yIHRoZSByZWFkZXIgdG8gZGlzY292ZXIuIC0tPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWx0ZXJzLWVtcHR5XCI+XG4gICAgICAgICAgICAgICAgICBDb21waWxlZCBmcm9tIHRoaXMgY29tcG9uZW50J3MgcXVlcnkg4oCUIG5vIGZpbHRlcnMgYXBwbGllZCwgdGltZXMgaW4ge3sgc3FsVGltZXpvbmUoKSB9fS5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8cHJlIGNsYXNzPVwiY29kZS1ibG9ja1wiPnt7IHNxbCgpIH19PC9wcmU+XG4gICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpbHRlcnMtZW1wdHlcIj5cbiAgICAgICAgICAgICAgICBUaGlzIGNvbXBvbmVudCBoYXMgbm8gU1FMIHlldC5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbWF0LXRhYj5cbiAgICAgICAgPG1hdC10YWJcbiAgICAgICAgICAgIGxhYmVsPVwiQ29uZmlnXCJcbiAgICAgICAgICAgIG5hbWU9XCJjb25maWdcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwidGFiLWJvZHlcIj5cbiAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJjb2RlLWJsb2NrXCI+XG4gICAgICAgICAgICAgIHt7IGNvbmZpZ0pzb24gfX1cbiAgICAgICAgICAgIDwvcHJlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L21hdC10YWI+XG4gICAgICA8L21hdC10YWItZ3JvdXA+XG4gICAgPC9tYXQtZGlhbG9nLWNvbnRlbnQ+XG4gICAgPG1hdC1kaWFsb2ctYWN0aW9ucz5cbiAgICAgIDwhLS0gU2F2ZSB8IERlbGV0ZSB8IENhbmNlbCwgdGhlIHN0YW5kYXJkIG9yZGVyLiBmcy1mb3JtLWRpYWxvZy1hY3Rpb25zXG4gICAgICAgICAgIHJlbmRlcnMgaXRzIG93biBTYXZlL0RvbmUgQkVGT1JFIHRoZSBwcm9qZWN0ZWQgY29udGVudCwgd2hpY2ggd291bGRcbiAgICAgICAgICAgcHV0IERlbGV0ZSBhZnRlciBDYW5jZWwsIHNvIGBbc2F2ZV09XCJmYWxzZVwiYCBmb290cyB0aGUgcm93IGhlcmUgYW5kXG4gICAgICAgICAgIGFsbCB0aHJlZSBidXR0b25zIGFyZSBwcm9qZWN0ZWQgaW4gb3JkZXIuIFNhdmUgc3VibWl0cyB0aGUgU2V0dGluZ3NcbiAgICAgICAgICAgdGFiOyB0aGUgb3RoZXIgdGFicyBwZXJzaXN0IGFzIHlvdSB0b3VjaCB0aGVtLCBzbyB0aGV5IGdldCBEb25lLiAtLT5cbiAgICAgIDxmcy1mb3JtLWRpYWxvZy1hY3Rpb25zIFtzYXZlXT1cImZhbHNlXCI+XG4gICAgICAgIEBpZiAoc2VsZWN0ZWRUYWIgPT09ICdzZXR0aW5ncycpIHtcbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cInN1Ym1pdFwiXG4gICAgICAgICAgICAgIGNvbG9yPVwicHJpbWFyeVwiPlxuICAgICAgICAgICAgU2F2ZVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGNvbG9yPVwicHJpbWFyeVwiXG4gICAgICAgICAgICAgIFttYXQtZGlhbG9nLWNsb3NlXT1cIm51bGxcIj5cbiAgICAgICAgICAgIERvbmVcbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBtYXQtYnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNvbG9yPVwid2FyblwiXG4gICAgICAgICAgICAoY2xpY2spPVwiZGVsZXRlKClcIj5cbiAgICAgICAgICBEZWxldGVcbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJjYW5jZWwtYnV0dG9uXCJcbiAgICAgICAgICAgIFttYXQtZGlhbG9nLWNsb3NlXT1cIm51bGxcIj5cbiAgICAgICAgICBDYW5jZWxcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2ZzLWZvcm0tZGlhbG9nLWFjdGlvbnM+XG4gICAgPC9tYXQtZGlhbG9nLWFjdGlvbnM+XG4gIDwvZnMtZGlhbG9nPlxuPC9mb3JtPiJdfQ==
578
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LXNldHRpbmdzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy9kaWFsb2dzL2NvbXBvbmVudC1zZXR0aW5ncy9jb21wb25lbnQtc2V0dGluZ3MuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvY29tcG9uZW50LXNldHRpbmdzL2NvbXBvbmVudC1zZXR0aW5ncy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQVUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEdBQy9GLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBbUIsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFOUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxFQUFFLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzdJLE9BQU8sRUFBRSxZQUFZLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMxRixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDaEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUs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QUFFO2FBQ04sT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDOUQsQ0FBQzt3R0F0aUJVLDBCQUEwQjs0RkFBMUIsMEJBQTBCLHdFQ2pMdkMseW5mQThZTywydUREcFBILFdBQVcsdWlDQUNYLFlBQVksNjZEQUNaLFlBQVksaUhBQ1osY0FBYyxnTUFDZCxhQUFhLHNXQUNiLFlBQVksbWFBQ1osYUFBYSw2b0JBQ2IsY0FBYywrSEFDZCxnQkFBZ0IseUdBQ2hCLGdCQUFnQiw0SEFDaEIsY0FBYyxxTEFDZCxZQUFZLDRMQUNaLE9BQU8sOEVBQ1AsUUFBUSxzREFDUixTQUFTLHFIQUNULFNBQVMsaUxBQ1QsUUFBUSxpVUFDUixTQUFTLHFKQUNULFNBQVMsd2VBQ1QsY0FBYywwVUFDZCxVQUFVOzs0RkFHRCwwQkFBMEI7a0JBN0J0QyxTQUFTO3NDQUdTLHVCQUF1QixDQUFDLE1BQU0sY0FDbkMsSUFBSSxXQUNQO3dCQUNQLFdBQVc7d0JBQ1gsWUFBWTt3QkFDWixZQUFZO3dCQUNaLGNBQWM7d0JBQ2QsYUFBYTt3QkFDYixZQUFZO3dCQUNaLGFBQWE7d0JBQ2IsY0FBYzt3QkFDZCxnQkFBZ0I7d0JBQ2hCLGdCQUFnQjt3QkFDaEIsY0FBYzt3QkFDZCxZQUFZO3dCQUNaLE9BQU87d0JBQ1AsUUFBUTt3QkFDUixTQUFTO3dCQUNULFNBQVM7d0JBQ1QsUUFBUTt3QkFDUixTQUFTO3dCQUNULFNBQVM7d0JBQ1QsY0FBYzt3QkFDZCxVQUFVO3FCQUNYIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRGVzdHJveVJlZiwgRXZlbnRFbWl0dGVyLCBPbkluaXQsIGNvbXB1dGVkLCBpbmplY3QsIHNpZ25hbCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBNQVRfRElBTE9HX0RBVEEsIE1hdERpYWxvZ0FjdGlvbnMsIE1hdERpYWxvZ0Nsb3NlLCBNYXREaWFsb2dDb250ZW50LCBNYXREaWFsb2dSZWYsIE1hdERpYWxvZ1RpdGxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IE1hdEZvcm1GaWVsZCwgTWF0SGludCwgTWF0TGFiZWwsIE1hdFN1ZmZpeCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xuaW1wb3J0IHsgTWF0QnV0dG9uIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcbmltcG9ydCB7IE1hdElucHV0IH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaW5wdXQnO1xuaW1wb3J0IHsgTWF0T3B0aW9uLCBNYXRTZWxlY3QgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zZWxlY3QnO1xuaW1wb3J0IHsgTWF0U2xpZGVUb2dnbGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zbGlkZS10b2dnbGUnO1xuaW1wb3J0IHsgTWF0VGFic01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3RhYnMnO1xuaW1wb3J0IHsgTWF0VG9vbHRpcCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuXG5pbXBvcnQgeyBGc0RpYWxvZ01vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2RpYWxvZyc7XG5pbXBvcnQgeyBGc0Zvcm1Nb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9mb3JtJztcbmltcG9ydCB7IEZzTGFiZWxNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9sYWJlbCc7XG5pbXBvcnQgeyBGc01hc2tNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9tYXNrJztcbmltcG9ydCB7IEZzTWVzc2FnZSB9IGZyb20gJ0BmaXJlc3RpdGNoL21lc3NhZ2UnO1xuaW1wb3J0IHsgRnNQcm9tcHQgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9tcHQnO1xuaW1wb3J0IHsgRnNUYWJzTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvdGFicyc7XG5cbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHN3aXRjaE1hcCwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQgeyBSZXBvcnRDaGFuZ2VQb2xhcml0eSB9IGZyb20gJy4uLy4uL2VudW1zL3JlcG9ydC1jaGFuZ2UtcG9sYXJpdHkuZW51bSc7XG5pbXBvcnQgeyBSZXBvcnRWYWx1ZUZvcm1hdCB9IGZyb20gJy4uLy4uL2VudW1zL3JlcG9ydC12YWx1ZS1mb3JtYXQuZW51bSc7XG5pbXBvcnQgeyBSZXBvcnRWYWx1ZUZvcm11bGEgfSBmcm9tICcuLi8uLi9lbnVtcy9yZXBvcnQtdmFsdWUtZm9ybXVsYS5lbnVtJztcbmltcG9ydCB7IHJlc29sdmVGb3JtYXRDb250ZXh0IH0gZnJvbSAnLi4vLi4vZm9ybWF0JztcbmltcG9ydCB7XG4gIEtQSV9TUEFSS0xJTkVfREVGQVVMVF9HUkFOVUxBUklUWSxcbiAgS1BJX1NQQVJLTElORV9ERUZBVUxUX1BFUklPRFMsXG4gIGtwaUNhcmRTZXR0aW5ncyxcbiAgc2FtZUtwaUNhcmRTZXR0aW5ncyxcbn0gZnJvbSAnLi4vLi4va3BpLWNhcmQnO1xuaW1wb3J0IHtcbiAgQ2hhcnRHcmFudWxhcml0eSxcbiAgQ29tcG9uZW50U2V0dGluZ3MsXG4gIEdSQU5VTEFSSVRZX09QVElPTlMsXG4gIEtwaUNhcmRTZXR0aW5ncyxcbiAgS3BpQ29uZmlnLFxuICBSZXBvcnQsXG4gIFJlcG9ydENvbXBvbmVudCxcbiAgUmVwb3J0Q29tcG9uZW50U3FsLFxuICBSZXBvcnRGaWx0ZXIsXG4gIFJlcG9ydEZpbHRlckdyb3VwLFxuICBSZXBvcnRGaWx0ZXJMZXZlbCxcbiAgUmVwb3J0RmlsdGVyVHlwZSxcbiAgUmVwb3J0RmlsdGVyYWJsZUNvbHVtbixcbn0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9yZXBvcnQuaW50ZXJmYWNlJztcbmltcG9ydCB7IERFRkFVTFRfQ09NUE9ORU5UX1BBRERJTkcgfSBmcm9tICcuLi8uLi9sYXlvdXQnO1xuaW1wb3J0IHtcbiAgRklMVEVSX1RZUEVfT1BUSU9OUyxcbiAgYmFyUGxhY2VtZW50LFxuICBiYXJQbGFjZW1lbnRPcHRpb25zLFxuICBjb21wb25lbnRUb2dnbGVTdGF0ZSxcbiAgZmlsdGVyTGV2ZWwsXG4gIGZpbHRlckxldmVsQ2hvaWNlcyxcbiAgc2hvd25PbkNvbXBvbmVudCxcbiAgdHlwZVNlbGVjdFN0YXRlLFxuICB2YWx1ZUZpbHRlckxldmVsLFxuICB2YWx1ZVBsYWNlbWVudE9wdGlvbnMsXG59IGZyb20gJy4uLy4uL2ZpbHRlci1zZXR0aW5ncy1ydWxlcyc7XG5pbXBvcnQgeyBGaWx0ZXJCYXJQbGFjZW1lbnQgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL2ZpbHRlci1iYXItcGxhY2VtZW50LnR5cGUnO1xuaW1wb3J0IHsgRmlsdGVyQ29tcG9uZW50VG9nZ2xlU3RhdGUgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL2ZpbHRlci1jb21wb25lbnQtdG9nZ2xlLXN0YXRlLmludGVyZmFjZSc7XG5pbXBvcnQgeyBGaWx0ZXJTZXR0aW5nc09wdGlvbiB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvZmlsdGVyLXNldHRpbmdzLW9wdGlvbi5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgRmlsdGVyVHlwZVNlbGVjdFN0YXRlIH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9maWx0ZXItdHlwZS1zZWxlY3Qtc3RhdGUuaW50ZXJmYWNlJztcbmltcG9ydCB7IGVzY2FwZUh0bWwgfSBmcm9tICcuLi8uLi90ZXh0JztcbmltcG9ydCB7IG9wZXJhbmRLZXlzLCByZXBvcnRDb21wb25lbnRzLCB2YWx1ZUtleSB9IGZyb20gJy4uLy4uL3ZhbHVlcyc7XG5cblxuLy8gV2hhdCB0aGUgZGlhbG9nIGhhbmRzIGJhY2suIFRoZSBTZXR0aW5ncyB0YWIncyBTYXZlIGNhcnJpZXMgdGhlIG5ld1xuLy8gYHNldHRpbmdzYDsgRGVsZXRlIGNhcnJpZXMgYGRlbGV0ZWRgIGFuZCBubyBzZXR0aW5ncywgYmVjYXVzZSB0aGUgY29tcG9uZW50XG4vLyBpdCB3YXMgb3BlbmVkIGZvciBubyBsb25nZXIgZXhpc3RzLiBFdmVyeSBvdGhlciBleGl0IChDYW5jZWwsIERvbmUsIEVzY2FwZSxcbi8vIGJhY2tkcm9wKSBjbG9zZXMgd2l0aCBubyByZXN1bHQg4oCUIGZpbHRlciB3b3JrIGlzIGFubm91bmNlZCBhcyBpdCBoYXBwZW5zXG4vLyBpbnN0ZWFkLCB0aHJvdWdoIGBmaWx0ZXJzQ2hhbmdlZGAuXG5leHBvcnQgaW50ZXJmYWNlIENvbXBvbmVudFNldHRpbmdzUmVzdWx0IHtcbiAgc2V0dGluZ3M/OiBDb21wb25lbnRTZXR0aW5ncztcbiAgZGVsZXRlZD86IGJvb2xlYW47XG59XG5cbi8vIFdoYXQgdGhlIHNldHRpbmdzIGVuZHBvaW50IHJldHVybnMgZm9yIHRoZSBjb21wb25lbnQ6IGl0cyBpZCBhbmQsIGZyb20gYVxuLy8gc2VydmVyIHRoYXQgc2F2ZXMgYSBLUEkncyBjYXJkIGtleXMsIHRoZSB3aG9sZSBjb25maWcgYXMgc2F2ZWQuXG5pbnRlcmZhY2UgQ29tcG9uZW50U2V0dGluZ3NSZXNwb25zZSB7XG4gIGlkOiBudW1iZXI7XG4gIGNvbmZpZz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgbnVsbDtcbn1cblxuXG4vLyBXaGF0IGEgcmlzZSBpbiBhIEtQSSdzIHZhbHVlIG1lYW5zLCBmb3IgdGhlIEluY3JlYXNlIGlzIHNlbGVjdC5cbmNvbnN0IEtQSV9DSEFOR0VfUE9MQVJJVFlfT1BUSU9OUzogeyB2YWx1ZTogUmVwb3J0Q2hhbmdlUG9sYXJpdHk7IG5hbWU6IHN0cmluZyB9W10gPSBbXG4gIHsgdmFsdWU6IFJlcG9ydENoYW5nZVBvbGFyaXR5Lkdvb2QsIG5hbWU6ICdHb29kIG5ld3Mg4oCUIGEgcmlzZSBzaG93cyBncmVlbicgfSxcbiAgeyB2YWx1ZTogUmVwb3J0Q2hhbmdlUG9sYXJpdHkuQmFkLCBuYW1lOiAnQmFkIG5ld3Mg4oCUIGEgcmlzZSBzaG93cyByZWQnIH0sXG4gIHsgdmFsdWU6IFJlcG9ydENoYW5nZVBvbGFyaXR5Lk5ldXRyYWwsIG5hbWU6ICdOZWl0aGVyIOKAlCBubyBjb2xvcicgfSxcbl07XG5cbi8vIEEgS1BJIHNwYXJrbGluZSdzIHBlcmlvZHMgc3RheSB3aXRoaW4gMiB0byA2MC5cbmNvbnN0IEtQSV9TUEFSS0xJTkVfTUlOX1BFUklPRFMgPSAyO1xuY29uc3QgS1BJX1NQQVJLTElORV9NQVhfUEVSSU9EUyA9IDYwO1xuXG4vLyBBIHBlcmNlbnQgS1BJJ3MgdGFyZ2V0IGlzIGVudGVyZWQgYXMgdGhlIHBlcmNlbnQgc2hvd24gKDE1IGZvciAxNSUpIGFuZFxuLy8gc3RvcmVkIGFzIHRoZSAwLTEgcmF0aW8gaXRzIHZhbHVlIGFycml2ZXMgaW47IHRoZSBzZXJ2ZXIgcmVmdXNlcyBhIHN0b3JlZFxuLy8gdGFyZ2V0IGFib3ZlIDEwMCwgd2hpY2ggaXMgMTAsMDAwJSBoZXJlLlxuY29uc3QgS1BJX1BFUkNFTlRfVEFSR0VUX01BWCA9IDEwMDAwO1xuXG4vLyBIb3cgYSBmb3JtdWxhIHZhbHVlJ3MgU2V0dGluZ3MgdGFiIHdyaXRlcyBvdXQgd2hhdCBpdCB3b3JrcyBvdXQsIGluIGl0c1xuLy8gb3BlcmFuZHMnIG5hbWVzLlxuY29uc3QgRk9STVVMQV9MSU5FUzogUmVjb3JkPFJlcG9ydFZhbHVlRm9ybXVsYSwgKG5hbWVzOiBzdHJpbmdbXSkgPT4gc3RyaW5nPiA9IHtcbiAgW1JlcG9ydFZhbHVlRm9ybXVsYS5DaGFuZ2VdOiAobmFtZXMpID0+IG5hbWVzLmpvaW4oJyDiiJIgJyksXG4gIFtSZXBvcnRWYWx1ZUZvcm11bGEuUGVyY2VudENoYW5nZV06IChbYSwgYl0pID0+IGAlIGNoYW5nZSBvZiAke2F9IG92ZXIgJHtifWAsXG4gIFtSZXBvcnRWYWx1ZUZvcm11bGEuUmF0aW9dOiAobmFtZXMpID0+IG5hbWVzLmpvaW4oJyDDtyAnKSxcbiAgW1JlcG9ydFZhbHVlRm9ybXVsYS5TdW1dOiAobmFtZXMpID0+IG5hbWVzLmpvaW4oJyArICcpLFxufTtcblxuXG4vLyBPbmUgcm93IG9mIHRoZSBGaWx0ZXJzIHRhYiBsaXN0aW5nOiBhIGZpbHRlcmFibGUgY29sdW1uLCBpdHMgZmlsdGVyJ3MgdHlwZVxuLy8gKHRoZSBpbmZlcnJlZCBvbmUsIHRoZSBvbmUgcGlja2VkLCBvciB0aGUgZmlsdGVyJ3Mgb3duKSwgYW5kIHdoZXJlIGl0c1xuLy8gZmlsdGVyIHNob3dzICh0aGUgUmVwb3J0IGJhciBzZWxlY3QgYW5kIHRoZSBUaGlzIGNvbXBvbmVudCB0b2dnbGUpLlxuaW50ZXJmYWNlIEZpbHRlclJvdyB7XG4gIGNvbHVtbjogc3RyaW5nO1xuICB0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlO1xuICBsYWJlbDogc3RyaW5nO1xuICBwbGFjZW1lbnQ6IEZpbHRlckJhclBsYWNlbWVudDtcbiAgY29tcG9uZW50OiBib29sZWFuO1xuICB0eXBlU2VsZWN0OiBGaWx0ZXJUeXBlU2VsZWN0U3RhdGU7XG4gIHBsYWNlbWVudE9wdGlvbnM6IEZpbHRlclNldHRpbmdzT3B0aW9uPEZpbHRlckJhclBsYWNlbWVudD5bXTtcbiAgY29tcG9uZW50VG9nZ2xlOiBGaWx0ZXJDb21wb25lbnRUb2dnbGVTdGF0ZTtcbn1cblxuXG4vLyBDb21wb25lbnQgc2V0dGluZ3MsIGluIHRhYnM6XG4vLyAgIFNldHRpbmdzIOKAlCB0aXRsZSBhbmQgY29udGVudCBwYWRkaW5nIChhIHZhbHVlOiBqdXN0IGl0cyBuYW1lLCBzaW5jZSBpdFxuLy8gICBzaXRzIGluc2lkZSBhIHRleHQgYmxvY2sncyB3b3JkcyBhbmQgaGFzIG5vIGJveCksIGFuZCBvbiBhIGRlcml2ZWQgS1BJIGl0cyBjYXJkOlxuLy8gICB3aGF0IGEgcmlzZSBtZWFucywgYSB0YXJnZXQgYW5kIGEgc3BhcmtsaW5lIChudW1iZXIgZm9ybWF0cyBzdGF5IHdpdGhcbi8vICAgdGhlIEFJKS4gUG9zaXRpb24vc2l6ZSBhcmUgdHVuZWQgYnkgZHJhZ2dpbmcgb24gdGhlIGNhbnZhczsgaGVpZ2h0XG4vLyAgIGJlaGF2aW91ciBmb2xsb3dzIGZyb20gdGhlIGNvbXBvbmVudCB0eXBlLlxuLy8gICBGaWx0ZXJzICDigJQgT05FIGxpc3Rpbmcgb2YgZXZlcnkgZmlsdGVyYWJsZSBjb2x1bW4gb24gdGhpcyBjb21wb25lbnQuIEVhY2hcbi8vICAgcm93IGNhcnJpZXMgdHdvIHRvZ2dsZXM6IHNob3cgaW4gdGhlIHJlcG9ydCBiYXIgYW5kL29yIHNob3cgb24gdGhpc1xuLy8gICBjb21wb25lbnQgKGJvdGgsIGVpdGhlciwgb3IgbmVpdGhlcikuIFRoZSBpbnRlcmZhY2UgKGRhdGUgcmFuZ2UgdnMgdmFsdWVcbi8vICAgcGlja2VyKSBpcyBpbmZlcnJlZCBmcm9tIHRoZSBkYXRhLCBuZXZlciBjaG9zZW4uIEVhY2ggdG9nZ2xlIHBlcnNpc3RzXG4vLyAgIGltbWVkaWF0ZWx5IGFuZCByZWZyZXNoZXMgdGhlIGluLWRpYWxvZyBsaXN0LiBBIHZhbHVlIGhhcyBubyBjb21wb25lbnRcbi8vICAgdG8gc2hvdyBhIGZpbHRlciBvbiwgc28gaXQgZ2V0cyB0aGUgcmVwb3J0IGJhciB0b2dnbGUgb25seS5cbi8vICAgU1FMIC8gQ29uZmlnIOKAlCByZWFkLW9ubHkgZGlhZ25vc3RpY3MuXG4vLyBBIGZvcm11bGEgdmFsdWUgaGFzIG5vIEZpbHRlcnMgb3IgU1FMIHRhYjogdGhlIHNlcnZlciB3b3JrcyBpdCBvdXQgb2Ygb3RoZXJcbi8vIHZhbHVlcyBvbiBpdHMgcGFnZSwgc28gaXQgcnVucyBubyBzdGF0ZW1lbnQgYW5kIGZvbGxvd3MgdGhlIGZpbHRlcnMgb2YgdGhlXG4vLyB2YWx1ZXMgaXQgcmVhZHMuIEl0cyBTZXR0aW5ncyB0YWIgc2F5cyB3aGF0IGl0IHdvcmtzIG91dCwgdW5kZXIgaXRzIG5hbWUuXG5AQ29tcG9uZW50KHtcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbXBvbmVudC1zZXR0aW5ncy5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NvbXBvbmVudC1zZXR0aW5ncy5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIEZvcm1zTW9kdWxlLFxuICAgIEZzRm9ybU1vZHVsZSxcbiAgICBGc01hc2tNb2R1bGUsXG4gICAgRnNEaWFsb2dNb2R1bGUsXG4gICAgRnNMYWJlbE1vZHVsZSxcbiAgICBGc1RhYnNNb2R1bGUsXG4gICAgTWF0VGFic01vZHVsZSxcbiAgICBNYXREaWFsb2dUaXRsZSxcbiAgICBNYXREaWFsb2dDb250ZW50LFxuICAgIE1hdERpYWxvZ0FjdGlvbnMsXG4gICAgTWF0RGlhbG9nQ2xvc2UsXG4gICAgTWF0Rm9ybUZpZWxkLFxuICAgIE1hdEhpbnQsXG4gICAgTWF0TGFiZWwsXG4gICAgTWF0U3VmZml4LFxuICAgIE1hdEJ1dHRvbixcbiAgICBNYXRJbnB1dCxcbiAgICBNYXRPcHRpb24sXG4gICAgTWF0U2VsZWN0LFxuICAgIE1hdFNsaWRlVG9nZ2xlLFxuICAgIE1hdFRvb2x0aXAsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIENvbXBvbmVudFNldHRpbmdzQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcblxuICAvLyBBIGZpbHRlciB3YXMgYWRkZWQsIHJlbW92ZWQgb3IgcmUtbGV2ZWxsZWQsIHNvIHRoZSByZXBvcnQncyBmaWx0ZXIgZ3JvdXBzXG4gIC8vIGNoYW5nZWQuIFRob3NlIG11dGF0aW9ucyBwZXJzaXN0IHRoZSBtb21lbnQgdGhleSBhcmUgY2xpY2tlZCBhbmQgdGhlIGRpYWxvZ1xuICAvLyBjYW4gdGhlbiBiZSBkaXNtaXNzZWQgYnkgYSByb3V0ZSB0aGF0IGNhcnJpZXMgbm8gcmVzdWx0IChFc2NhcGUsIGJhY2tkcm9wKSxcbiAgLy8gc28gdGhlIHBhZ2UgaXMgdG9sZCBoZXJlIHJhdGhlciB0aGFuIHRocm91Z2ggdGhlIGNsb3NlIHJlc3VsdC5cbiAgcHVibGljIHJlYWRvbmx5IGZpbHRlcnNDaGFuZ2VkID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuXG4gIHB1YmxpYyBjb21wb25lbnQ6IFJlcG9ydENvbXBvbmVudDtcbiAgcHVibGljIHJlcG9ydDogUmVwb3J0O1xuXG4gIHB1YmxpYyBzZWxlY3RlZFRhYiA9ICdzZXR0aW5ncyc7XG5cbiAgcHVibGljIHRpdGxlID0gJyc7XG5cbiAgLy8gQ29tcG9uZW50IHBhZGRpbmcgaW4gaW5jaGVzLiBgbnVtYmVyIHwgc3RyaW5nYCBmb3IgdGhlIHNhbWUgcmVhc29uIGFzIHRoZVxuICAvLyBwYWdlIGRpbWVuc2lvbnMgaW4gcmVwb3J0LXNldHRpbmdzOiBmc01hc2tOdW1iZXIgc2VlZHMgZnJvbSB0aGUgbnVtYmVyIGJ1dFxuICAvLyBoYW5kcyBiYWNrIHRoZSB1bm1hc2tlZCBzdHJpbmcsIGFuZCBzYXZlIGNhc3RzIGl0IG9uY2Ugb24gdGhlIHdheSBvdXQuXG4gIHB1YmxpYyBwYWRkaW5nVG9wOiBudW1iZXIgfCBzdHJpbmcgPSBERUZBVUxUX0NPTVBPTkVOVF9QQURESU5HO1xuICBwdWJsaWMgcGFkZGluZ1JpZ2h0OiBudW1iZXIgfCBzdHJpbmcgPSBERUZBVUxUX0NPTVBPTkVOVF9QQURESU5HO1xuICBwdWJsaWMgcGFkZGluZ0JvdHRvbTogbnVtYmVyIHwgc3RyaW5nID0gREVGQVVMVF9DT01QT05FTlRfUEFERElORztcbiAgcHVibGljIHBhZGRpbmdMZWZ0OiBudW1iZXIgfCBzdHJpbmcgPSBERUZBVUxUX0NPTVBPTkVOVF9QQURESU5HO1xuXG4gIHB1YmxpYyBjb25maWdKc29uID0gJyc7XG5cbiAgLy8gLS0tLSBLUEkgY2FyZCBzdGF0ZSAoYSBkZXJpdmVkIEtQSSBvbmx5KSAtLS0tXG4gIHB1YmxpYyByZWFkb25seSBrcGlQb2xhcml0eU9wdGlvbnMgPSBLUElfQ0hBTkdFX1BPTEFSSVRZX09QVElPTlM7XG4gIHB1YmxpYyByZWFkb25seSBncmFudWxhcml0eU9wdGlvbnMgPSBHUkFOVUxBUklUWV9PUFRJT05TO1xuICBwdWJsaWMgcmVhZG9ubHkgc3BhcmtsaW5lTWluUGVyaW9kcyA9IEtQSV9TUEFSS0xJTkVfTUlOX1BFUklPRFM7XG4gIHB1YmxpYyByZWFkb25seSBzcGFya2xpbmVNYXhQZXJpb2RzID0gS1BJX1NQQVJLTElORV9NQVhfUEVSSU9EUztcbiAgcHVibGljIHJlYWRvbmx5IGtwaUNhcmQgPSBzaWduYWwoZmFsc2UpO1xuICAvLyBBIHZhbHVlIGluc2lkZSBhIHRleHQgYmxvY2s6IG5vIGJveCwgc28gbm8gcGFkZGluZy5cbiAgcHVibGljIHJlYWRvbmx5IGlzVmFsdWUgPSBzaWduYWwoZmFsc2UpO1xuICAvLyBBIGZvcm11bGEgdmFsdWU6IG5vIHN0YXRlbWVudCwgY29sdW1ucyBvciBmaWx0ZXJzIG9mIGl0cyBvd24uXG4gIHB1YmxpYyByZWFkb25seSBpc0Zvcm11bGEgPSBzaWduYWwoZmFsc2UpO1xuICAvLyBXaGF0IGEgZm9ybXVsYSB3b3JrcyBvdXQsIGluIGl0cyBvcGVyYW5kcycgbmFtZXM7IGVtcHR5IGZvciBhbnkgb3RoZXJcbiAgLy8gY29tcG9uZW50LlxuICBwdWJsaWMgcmVhZG9ubHkgZm9ybXVsYUxpbmUgPSBjb21wdXRlZCgoKSA9PiAodGhpcy5pc0Zvcm11bGEoKSA/IHRoaXMuX2Zvcm11bGFMaW5lKCkgOiAnJykpO1xuICBwdWJsaWMgcmVhZG9ubHkgaW5jcmVhc2VJcyA9IHNpZ25hbDxSZXBvcnRDaGFuZ2VQb2xhcml0eT4oUmVwb3J0Q2hhbmdlUG9sYXJpdHkuR29vZCk7XG4gIC8vIFRoZSB0YXJnZXQgYXMgdHlwZWQ6IGZzTWFza051bWJlciBoYW5kcyBiYWNrIHRoZSB1bm1hc2tlZCBzdHJpbmcuIEVtcHR5XG4gIC8vIG1lYW5zIG5vIHRhcmdldC4gQSBwZXJjZW50IEtQSSdzIGlzIGluIHBlcmNlbnQgKHRhcmdldFBlcmNlbnQpLlxuICBwdWJsaWMgcmVhZG9ubHkgdGFyZ2V0VmFsdWUgPSBzaWduYWw8bnVtYmVyIHwgc3RyaW5nIHwgbnVsbD4obnVsbCk7XG4gIHB1YmxpYyByZWFkb25seSB0YXJnZXRMYWJlbCA9IHNpZ25hbCgnJyk7XG4gIHB1YmxpYyByZWFkb25seSB0YXJnZXRQZXJjZW50ID0gc2lnbmFsKGZhbHNlKTtcbiAgcHVibGljIHJlYWRvbmx5IGhhc1RhcmdldCA9IGNvbXB1dGVkKCgpID0+IHRoaXMuX251bWJlcih0aGlzLnRhcmdldFZhbHVlKCkpICE9PSBudWxsKTtcbiAgcHVibGljIHJlYWRvbmx5IHNwYXJrbGluZSA9IHNpZ25hbChmYWxzZSk7XG4gIHB1YmxpYyByZWFkb25seSBzcGFya2xpbmVHcmFudWxhcml0eSA9IHNpZ25hbDxDaGFydEdyYW51bGFyaXR5PihLUElfU1BBUktMSU5FX0RFRkFVTFRfR1JBTlVMQVJJVFkpO1xuICBwdWJsaWMgcmVhZG9ubHkgc3BhcmtsaW5lUGVyaW9kcyA9IHNpZ25hbDxudW1iZXIgfCBzdHJpbmc+KEtQSV9TUEFSS0xJTkVfREVGQVVMVF9QRVJJT0RTKTtcblxuICAvLyAtLS0tIFNRTCB0YWIgc3RhdGUgLS0tLVxuICAvLyBUaGUgc3RhdGVtZW50LCBvbmNlIGZldGNoZWQuIE51bGwgd2hpbGUgaXQgaXMgaW4gZmxpZ2h0LCBhbmQgbnVsbCB3aGVuIHRoZVxuICAvLyBjb21wb25lbnQncyBkb2N1bWVudCBjb3VsZCBub3QgYmUgY29tcGlsZWQgKHNxbEVycm9yIHRoZW4gc2F5cyB3aHkpLlxuICBwdWJsaWMgcmVhZG9ubHkgc3FsID0gc2lnbmFsPHN0cmluZyB8IG51bGw+KG51bGwpO1xuICAvLyBUcnVlIHdoZW4gdGhlIHN0YXRlbWVudCBpcyBhIERFUklWRUQgYmFzZWxpbmU6IG5vIGZpbHRlcnMsIHRoZSBhdXRob3JlZFxuICAvLyBncmFpbiwgdGltZXMgaW4gdGhlIHJlcG9ydCdzIGVmZmVjdGl2ZSB6b25lLiBUaGUgdGFiIHNheXMgc28sIGJlY2F1c2UgdGhlXG4gIC8vIG51bWJlcnMgb24gc2NyZWVuIGNvbWUgZnJvbSB0aGlzIHN0YXRlbWVudCBwbHVzIHRoZSB2aWV3ZXIncyBvd24gY2hvaWNlc1xuICAvLyBhbmQgdGhlIHR3byBjYW4gZGlmZmVyLlxuICBwdWJsaWMgcmVhZG9ubHkgc3FsQmFzZWxpbmUgPSBzaWduYWwoZmFsc2UpO1xuICAvLyBUaGUgem9uZSB0aGUgc3RhdGVtZW50IHdhcyBjb21waWxlZCBpbjogdGhlIHJlcG9ydCdzIGVmZmVjdGl2ZSB6b25lLCBzZW50XG4gIC8vIHdpdGggdGhlIFNRTC4gQSBzZXJ2ZXIgdG9vIG9sZCB0byBzZW5kIGl0IGNvbXBpbGVkIGluIFVUQy5cbiAgcHVibGljIHJlYWRvbmx5IHNxbFRpbWV6b25lID0gc2lnbmFsKCdVVEMnKTtcbiAgcHVibGljIHJlYWRvbmx5IHNxbEVycm9yID0gc2lnbmFsPHN0cmluZyB8IG51bGw+KG51bGwpO1xuXG4gIC8vIC0tLS0gZmlsdGVyIG1hbmFnZW1lbnQgc3RhdGUgLS0tLVxuICAvLyBPbmUgcm93IHBlciBmaWx0ZXJhYmxlIGNvbHVtbi4gVGhlIHBsYWNlbWVudCBhbmQgdGhlIHRvZ2dsZSBjaGFuZ2VcbiAgLy8gb3B0aW1pc3RpY2FsbHkgb24gY2xpY2sgKHNvIHRoZSBVSSBuZXZlciBibGlua3Mgd2hpbGUgdGhlIHJlcXVlc3QgaXMgaW5cbiAgLy8gZmxpZ2h0KSBhbmQgcmVjb25jaWxlIGZyb20gdGhlIHNlcnZlciBvbiByZWxvYWQuXG4gIHB1YmxpYyByZWFkb25seSByb3dzID0gc2lnbmFsPEZpbHRlclJvd1tdPihbXSk7XG4gIHB1YmxpYyByZWFkb25seSBjb2x1bW5zRXJyb3IgPSBzaWduYWw8c3RyaW5nIHwgbnVsbD4obnVsbCk7XG4gIC8vIFRoZSBUeXBlIHNlbGVjdCdzIGNob2ljZXMuIEEgcm93J3MgVHlwZSBzZWxlY3QsIFJlcG9ydCBiYXIgc2VsZWN0IGFuZFxuICAvLyBUaGlzIGNvbXBvbmVudCB0b2dnbGUgZm9sbG93IHRoZSBydWxlcyBpbiBmaWx0ZXItc2V0dGluZ3MtcnVsZXMudHMuXG4gIHB1YmxpYyByZWFkb25seSB0eXBlT3B0aW9ucyA9IEZJTFRFUl9UWVBFX09QVElPTlM7XG5cbiAgLy8gVGhlIHJhdyBpbnB1dHMgdGhlIHJvd3MgYXJlIGJ1aWx0IGZyb20uXG4gIHByaXZhdGUgX2ZpbHRlcmFibGVDb2x1bW5zOiBSZXBvcnRGaWx0ZXJhYmxlQ29sdW1uW10gPSBbXTtcbiAgcHJpdmF0ZSBfZmlsdGVyczogUmVwb3J0RmlsdGVyW10gPSBbXTtcbiAgcHJpdmF0ZSBfZ3JvdXBzQnlJZCA9IG5ldyBNYXA8bnVtYmVyLCBSZXBvcnRGaWx0ZXJHcm91cD4oKTtcbiAgLy8gVGhlIHR5cGUgcGlja2VkIGZvciBhIGNvbHVtbiB3aXRoIG5vIGZpbHRlciB5ZXQsIHNvIGEgcmVsb2FkIGtlZXBzIGl0LlxuICBwcml2YXRlIF9waWNrZWRUeXBlcyA9IG5ldyBNYXA8c3RyaW5nLCBSZXBvcnRGaWx0ZXJUeXBlPigpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3R5cGVMYWJlbHM6IFJlY29yZDxSZXBvcnRGaWx0ZXJUeXBlLCBzdHJpbmc+ID0ge1xuICAgIHNlbGVjdDogJ1BpY2sgdmFsdWVzJyxcbiAgICBkYXRlUmFuZ2U6ICdEYXRlIHJhbmdlJyxcbiAgICBrZXl3b3JkOiAnU2VhcmNoIHRleHQnLFxuICAgIG51bWJlclJhbmdlOiAnTnVtYmVyIHJhbmdlJyxcbiAgfTtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9kYXRhOiB7IHJlcG9ydDogUmVwb3J0OyBjb21wb25lbnQ6IFJlcG9ydENvbXBvbmVudCB9ID0gaW5qZWN0KE1BVF9ESUFMT0dfREFUQSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2RpYWxvZ1JlZiA9IGluamVjdDxNYXREaWFsb2dSZWY8Q29tcG9uZW50U2V0dGluZ3NDb21wb25lbnQsIENvbXBvbmVudFNldHRpbmdzUmVzdWx0Pj4oTWF0RGlhbG9nUmVmKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcmVwb3J0RGF0YSA9IGluamVjdChSZXBvcnREYXRhKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbWVzc2FnZSA9IGluamVjdChGc01lc3NhZ2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9wcm9tcHQgPSBpbmplY3QoRnNQcm9tcHQpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIHB1YmxpYyBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnJlcG9ydCA9IHRoaXMuX2RhdGEucmVwb3J0O1xuICAgIHRoaXMuY29tcG9uZW50ID0gdGhpcy5fZGF0YS5jb21wb25lbnQ7XG5cbiAgICB0aGlzLnRpdGxlID0gdGhpcy5jb21wb25lbnQudGl0bGUgPz8gJyc7XG4gICAgdGhpcy5pc1ZhbHVlLnNldCh0aGlzLmNvbXBvbmVudC50eXBlID09PSAndmFsdWUnKTtcbiAgICB0aGlzLmlzRm9ybXVsYS5zZXQoISF0aGlzLmNvbXBvbmVudC5jb25maWc/LmZvcm11bGEpO1xuXG4gICAgY29uc3QgcGFkZGluZyA9IHRoaXMuY29tcG9uZW50LmNvbmZpZz8ucGFkZGluZztcbiAgICB0aGlzLnBhZGRpbmdUb3AgPSBwYWRkaW5nPy50b3AgPz8gREVGQVVMVF9DT01QT05FTlRfUEFERElORztcbiAgICB0aGlzLnBhZGRpbmdSaWdodCA9IHBhZGRpbmc/LnJpZ2h0ID8/IERFRkFVTFRfQ09NUE9ORU5UX1BBRERJTkc7XG4gICAgdGhpcy5wYWRkaW5nQm90dG9tID0gcGFkZGluZz8uYm90dG9tID8/IERFRkFVTFRfQ09NUE9ORU5UX1BBRERJTkc7XG4gICAgdGhpcy5wYWRkaW5nTGVmdCA9IHBhZGRpbmc/LmxlZnQgPz8gREVGQVVMVF9DT01QT05FTlRfUEFERElORztcblxuICAgIHRoaXMuY29uZmlnSnNvbiA9IEpTT04uc3RyaW5naWZ5KHRoaXMuY29tcG9uZW50LmNvbmZpZyA/PyB7fSwgbnVsbCwgMik7XG5cbiAgICB0aGlzLl9zZWVkS3BpQ2FyZCgpO1xuXG4gICAgdGhpcy5fc2VlZEZpbHRlcnModGhpcy5yZXBvcnQsIHRoaXMuY29tcG9uZW50LmlkKTtcblxuICAgIC8vIEEgZm9ybXVsYSBoYXMgbm8gc3RhdGVtZW50IHRvIGNvbXBpbGUgYW5kIG5vIGNvbHVtbnMgdG8gZmlsdGVyIG9uLCBhbmRcbiAgICAvLyB0aGUgc2VydmVyIHdvdWxkIHJlZnVzZSBib3RoIHJlcXVlc3RzLlxuICAgIGlmICghdGhpcy5pc0Zvcm11bGEoKSkge1xuICAgICAgdGhpcy5fbG9hZENvbHVtbnMoKTtcbiAgICAgIHRoaXMuX2xvYWRTcWwoKTtcbiAgICB9XG4gIH1cblxuICAvLyBIdW1hbi1mcmllbmRseSBuYW1lIGZvciB0aGUgaW5mZXJyZWQgaW50ZXJmYWNlIHNob3duIGJlc2lkZSBlYWNoIGNvbHVtbi5cbiAgcHVibGljIHR5cGVMYWJlbCh0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fdHlwZUxhYmVsc1t0eXBlXSA/PyB0eXBlO1xuICB9XG5cbiAgLy8gQ29uZmlybSBhbmQgZGVsZXRlIGhlcmUsIHdoaWxlIHRoZSBkaWFsb2cgaXMgc3RpbGwgb3BlbiwgdGhlbiBjbG9zZSB3aXRoIGFcbiAgLy8gYGRlbGV0ZWRgIHJlc3VsdCBmb3IgdGhlIHBhZ2UgdG8gYWN0IG9uIOKAlCB0aGUgc2FtZSBzaGFwZSB0aGUgcmVwb3J0XG4gIC8vIHNldHRpbmdzIGRpYWxvZyB1c2VzIGZvciBkZWxldGluZyBhIHJlcG9ydC5cbiAgLy9cbiAgLy8gVGhlIGNvbmZpcm0gc2F5cyBpdCBjYW5ub3QgYmUgdW5kb25lIGJlY2F1c2UsIGZyb20gdGhlIFVJLCBpdCBjYW5ub3Q6IHRoZVxuICAvLyByb3cgaXMgc29mdC1kZWxldGVkIHNlcnZlci1zaWRlIGJ1dCBub3RoaW5nIGhlcmUgcmVzdG9yZXMgYSBjb21wb25lbnQuXG4gIC8vIEEgdmFsdWUncyBjb25maXJtIGFsc28gc2F5cyB3aGF0IGdvZXMgd2l0aCBpdDogdGhlIHNlcnZlciB0YWtlcyBpdHNcbiAgLy8gdG9rZW5zIG91dCBvZiBldmVyeSB0ZXh0IG9uIGl0cyBwYWdlLCBub3QganVzdCB0aGUgb25lIGl0IHdhcyBvcGVuZWQgZnJvbSxcbiAgLy8gYW5kIGRlbGV0ZXMgdGhlIGZvcm11bGFzIHRoYXQgcmVhZCBpdCAoX2RlcGVuZGVudHNOb3RlKS5cbiAgLy9cbiAgLy8gVGhlIHByb21wdCByZW5kZXJzIGl0cyB0ZW1wbGF0ZSBhcyBodG1sLCBzbyBldmVyeSBuYW1lIGluIGl0IGlzIGVzY2FwZWQuXG4gIHB1YmxpYyBkZWxldGUoKTogdm9pZCB7XG4gICAgdGhpcy5fcHJvbXB0LmNvbmZpcm0odGhpcy5pc1ZhbHVlKClcbiAgICAgID8ge1xuICAgICAgICB0aXRsZTogJ0RlbGV0ZSBWYWx1ZScsXG4gICAgICAgIHRlbXBsYXRlOiBgRGVsZXRlIHRoZSB2YWx1ZSBcIiR7ZXNjYXBlSHRtbCh0aGlzLmNvbXBvbmVudC50aXRsZSB8fCB2YWx1ZUtleSh0aGlzLmNvbXBvbmVudCkpfVwiPyBJdCBpcyBhbHNvIHRha2VuIG91dCBvZiBldmVyeSB0ZXh0IG9uIHRoaXMgcGFnZS4gVGhpcyBjYW5ub3QgYmUgdW5kb25lLiR7dGhpcy5fZGVwZW5kZW50c05vdGUoKX1gLFxuICAgICAgfVxuICAgICAgOiB7XG4gICAgICAgIHRpdGxlOiAnRGVsZXRlIENvbXBvbmVudCcsXG4gICAgICAgIHRlbXBsYXRlOiBgQXJlIHlvdSBzdXJlIHlvdSB3b3VsZCBsaWtlIHRvIGRlbGV0ZSBcIiR7ZXNjYXBlSHRtbCh0aGlzLmNvbXBvbmVudC50aXRsZSB8fCAndGhpcyBjb21wb25lbnQnKX1cIj8gVGhpcyBjYW5ub3QgYmUgdW5kb25lLmAsXG4gICAgICB9KVxuICAgICAgLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLl9yZXBvcnREYXRhLmRlbGV0ZUNvbXBvbmVudCh0aGlzLnJlcG9ydC5pZCwgdGhpcy5jb21wb25lbnQuaWQpKSxcbiAgICAgICAgdGFwKCgpID0+IHtcbiAgICAgICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3ModGhpcy5pc1ZhbHVlKCkgPyAnVmFsdWUgZGVsZXRlZCcgOiAnQ29tcG9uZW50IGRlbGV0ZWQnKTtcbiAgICAgICAgICB0aGlzLl9kaWFsb2dSZWYuY2xvc2UoeyBkZWxldGVkOiB0cnVlIH0pO1xuICAgICAgICB9KSxcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgpO1xuICB9XG5cbiAgLy8gQSBwZXJjZW50IHRhcmdldCdzIGJvdW5kLCBpbiB0aGUgcGVyY2VudCBpdCBpcyB0eXBlZCBpbi4gSXQgcmVhZHMgdGhlXG4gIC8vIGNvbnRyb2wsIHdoaWNoIGZzRm9ybSB2YWxpZGF0ZXMgYmVmb3JlIG5nTW9kZWxDaGFuZ2UgdXBkYXRlcyB0aGUgc2lnbmFsLlxuICBwdWJsaWMgdmFsaWRhdGVUYXJnZXQgPSAoY29udHJvbDogQWJzdHJhY3RDb250cm9sKTogdm9pZCA9PiB7XG4gICAgY29uc3QgdmFsdWUgPSB0aGlzLl9udW1iZXIoY29udHJvbC52YWx1ZSk7XG5cbiAgICBpZiAodGhpcy50YXJnZXRQZXJjZW50KCkgJiYgdmFsdWUgIT09IG51bGwgJiYgdmFsdWUgPiBLUElfUEVSQ0VOVF9UQVJHRVRfTUFYKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0EgcGVyY2VudCB0YXJnZXQgY2FuIGJlIGF0IG1vc3QgMTAsMDAwJScpO1xuICAgIH1cbiAgfTtcblxuICBwdWJsaWMgc2F2ZSA9ICgpID0+IHtcbiAgICBjb25zdCBzZXR0aW5nczogQ29tcG9uZW50U2V0dGluZ3MgPSB7XG4gICAgICAvLyBUaGUgc2VydmVyIHRyaW1zIGEgdGl0bGU7IGEgdmFsdWUncyBOYW1lIGlzIHdoYXQgaXRzIGNoaXBzIHNob3csIHNvIGl0XG4gICAgICAvLyBnb2VzIGFzIHRoZSBzZXJ2ZXIga2VlcHMgaXQuXG4gICAgICB0aXRsZTogdGhpcy5pc1ZhbHVlKCkgPyB0aGlzLnRpdGxlLnRyaW0oKSA6IHRoaXMudGl0bGUsXG4gICAgICBwYWRkaW5nOiB7XG4gICAgICAgIHRvcDogdGhpcy5fcGFkZGluZyh0aGlzLnBhZGRpbmdUb3ApLFxuICAgICAgICByaWdodDogdGhpcy5fcGFkZGluZyh0aGlzLnBhZGRpbmdSaWdodCksXG4gICAgICAgIGJvdHRvbTogdGhpcy5fcGFkZGluZyh0aGlzLnBhZGRpbmdCb3R0b20pLFxuICAgICAgICBsZWZ0OiB0aGlzLl9wYWRkaW5nKHRoaXMucGFkZGluZ0xlZnQpLFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgLy8gVGhlIGNhcmQga2V5cyBnbyBhcyBjb25maWcga2V5cyBiZXNpZGUgdGhlIHBhZGRpbmcgKGluY3JlYXNlSXMsIHRhcmdldFxuICAgIC8vIGFuZCBzcGFya2xpbmUsIG51bGwgdG8gcmVtb3ZlIG9uZSksIGFuZCBvbmx5IHdoZW4gdGhleSBjaGFuZ2VkLCBzbyBhXG4gICAgLy8gdGl0bGUgZWRpdCBuZXZlciB0b3VjaGVzIHRoZW0uXG4gICAgY29uc3Qga3BpID0gdGhpcy5rcGlDYXJkKCkgPyB0aGlzLl9rcGlDYXJkU2V0dGluZ3MoKSA6IG51bGw7XG4gICAgY29uc3Qga3BpQ2hhbmdlZCA9ICEha3BpXG4gICAgICAmJiAhc2FtZUtwaUNhcmRTZXR0aW5ncyhrcGksIGtwaUNhcmRTZXR0aW5ncyh0aGlzLmNvbXBvbmVudC5jb25maWcgYXMgS3BpQ29uZmlnKSk7XG5cbiAgICByZXR1cm4gdGhpcy5fcmVwb3J0RGF0YS51cGRhdGVDb21wb25lbnQodGhpcy5yZXBvcnQuaWQsIHRoaXMuY29tcG9uZW50LmlkLCB7XG4gICAgICB0aXRsZTogc2V0dGluZ3MudGl0bGUsXG4gICAgICAuLi4odGhpcy5pc1ZhbHVlKCkgPyB7fSA6IHsgcGFkZGluZzogc2V0dGluZ3MucGFkZGluZyB9KSxcbiAgICAgIC4uLihrcGlDaGFuZ2VkID8ga3BpIDoge30pLFxuICAgIH0pXG4gICAgICAucGlwZShcbiAgICAgICAgdGFwKChyZXNwb25zZTogQ29tcG9uZW50U2V0dGluZ3NSZXNwb25zZSkgPT4ge1xuICAgICAgICAgIC8vIFRoZSBjYXJkIGlzIGRyYXduIGZyb20gdGhlIGtleXMgdGhlIHNlcnZlciBzYXZlZCwgcmVhZCBiYWNrIGZyb21cbiAgICAgICAgICAvLyB0aGUgY29uZmlnIGl0IHJldHVybnMuIEEgc2VydmVyIHRoYXQgcmV0dXJucyBubyBjb25maWcgZGlkIG5vdFxuICAgICAgICAgIC8vIHNhdmUgdGhlbSwgc28gdGhlIGNhcmQga2VlcHMgd2hhdCBpdCBoYWQgYW5kIHRoZSBkaWFsb2cgc2F5cyBzby5cbiAgICAgICAgICBjb25zdCBzYXZlZCA9IGtwaUNoYW5nZWQgPyB0aGlzLl9zYXZlZEtwaUNhcmQocmVzcG9uc2UpIDogbnVsbDtcblxuICAgICAgICAgIGlmIChrcGlDaGFuZ2VkICYmICFzYXZlZCkge1xuICAgICAgICAgICAgdGhpcy5fbWVzc2FnZS53YXJuaW5nKCdDb21wb25lbnQgc2F2ZWQsIGJ1dCB0aGUgc2VydmVyIGRpZCBub3Qgc2F2ZSB0aGUgY2FyZCBzZXR0aW5ncycpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3ModGhpcy5pc1ZhbHVlKCkgPyAnVmFsdWUgc2F2ZWQnIDogJ0NvbXBvbmVudCBzYXZlZCcpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuX2RpYWxvZ1JlZi5jbG9zZSh7IHNldHRpbmdzOiBzYXZlZCA/IHsgLi4uc2V0dGluZ3MsIGtwaTogc2F2ZWQgfSA6IHNldHRpbmdzIH0pO1xuICAgICAgICB9KSxcbiAgICAgICk7XG4gIH07XG5cbiAgLy8gVGhlIHR5cGUgYSBjb2x1bW4ncyBmaWx0ZXIgd2lsbCBiZSBtYWRlIHdpdGguIE9ubHkgYSBjb2x1bW4gd2l0aCBub1xuICAvLyBmaWx0ZXIgb2ZmZXJzIHRoZSBwaWNrICh0aGUgVHlwZSBzZWxlY3QgaXMgbG9ja2VkIG90aGVyd2lzZSksIGFuZCBub3RoaW5nXG4gIC8vIGlzIHNhdmVkIHVudGlsIHRoZSBmaWx0ZXIgaXMgbWFkZS5cbiAgcHVibGljIHNldFR5cGUocm93OiBGaWx0ZXJSb3csIHR5cGU6IFJlcG9ydEZpbHRlclR5cGUpOiB2b2lkIHtcbiAgICB0aGlzLl9waWNrZWRUeXBlcy5zZXQocm93LmNvbHVtbiwgdHlwZSk7XG4gICAgdGhpcy5fcGF0Y2hSb3cocm93LCB7IHR5cGUgfSk7XG4gIH1cblxuICAvLyBXaGVyZSB0aGUgcm93J3MgZmlsdGVyIHNob3dzIGluIHRoZSByZXBvcnQgYmFyLiBUaGlzIHBhZ2Ugb25seSBzaG93cyBpdFxuICAvLyBpbiBpdHMgcGFnZSdzIGJhciBhbG9uZSwgc28gdGhlIFRoaXMgY29tcG9uZW50IHRvZ2dsZSBnb2VzIG9mZiBhbmQgbG9ja3MuXG4gIC8vIEEgdmFsdWUgaGFzIHRoaXMgc2VsZWN0IG9ubHksIHdpdGggaXRzIG93biBydWxlcyAoX2FwcGx5VmFsdWVMZXZlbCkuXG4gIHB1YmxpYyBzZXRQbGFjZW1lbnQocm93OiBGaWx0ZXJSb3csIHBsYWNlbWVudDogRmlsdGVyQmFyUGxhY2VtZW50KTogdm9pZCB7XG4gICAgY29uc3QgcGF0Y2hlZCA9IHRoaXMuX3BhdGNoUm93KHJvdywge1xuICAgICAgcGxhY2VtZW50LFxuICAgICAgY29tcG9uZW50OiBwbGFjZW1lbnQgPT09ICdwYWdlJyA/IGZhbHNlIDogcm93LmNvbXBvbmVudCxcbiAgICAgIGNvbXBvbmVudFRvZ2dsZTogY29tcG9uZW50VG9nZ2xlU3RhdGUocGxhY2VtZW50KSxcbiAgICB9KTtcblxuICAgIGlmICh0aGlzLmlzVmFsdWUoKSkge1xuICAgICAgdGhpcy5fYXBwbHlWYWx1ZUxldmVsKHBhdGNoZWQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9hcHBseUxldmVsKHBhdGNoZWQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIEEgdmFsdWUgaGFzIG5vIFRoaXMgY29tcG9uZW50IHRvZ2dsZS5cbiAgcHVibGljIHNldENvbXBvbmVudChyb3c6IEZpbHRlclJvdywgY29tcG9uZW50OiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaXNWYWx1ZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fYXBwbHlMZXZlbCh0aGlzLl9wYXRjaFJvdyhyb3csIHsgY29tcG9uZW50IH0pKTtcbiAgfVxuXG4gIC8vIFBlcnNpc3QgdGhlIGxldmVsIHRoZSByb3cncyBjb250cm9scyBhc2sgZm9yLCB0aGVuIHJlY29uY2lsZSBvbiByZWxvYWQuXG4gIC8vIE5vIGxldmVsIOKGkiBubyBmaWx0ZXIgKHJlbW92ZWQpOyBvdGhlcndpc2UgdGhlIGZpbHRlciBleGlzdHMgYXQgdGhhdFxuICAvLyBsZXZlbC4gQSBzZXJ2ZXIgcmVmdXNhbCAoYSBwYWdlIGZpbHRlciB3aG9zZSBtZW1iZXJzIHNpdCBvbiB0d28gcGFnZXMpXG4gIC8vIHNob3dzIGl0cyBvd24gdGV4dCBhbmQgdGhlIHJvdyBzbmFwcyBiYWNrLlxuICBwcml2YXRlIF9hcHBseUxldmVsKHJvdzogRmlsdGVyUm93KTogdm9pZCB7XG4gICAgY29uc3QgbGV2ZWwgPSBmaWx0ZXJMZXZlbChyb3cucGxhY2VtZW50LCByb3cuY29tcG9uZW50KTtcbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMuX2ZpbHRlcnMuZmluZCgoZmlsdGVyKSA9PiBmaWx0ZXIuZmlsdGVyQ29sdW1uID09PSByb3cuY29sdW1uKTtcblxuICAgIGlmICghbGV2ZWwpIHtcbiAgICAgIGlmIChleGlzdGluZykge1xuICAgICAgICB0aGlzLl9ydW4odGhpcy5fcmVwb3J0RGF0YS5kZWxldGVGaWx0ZXIodGhpcy5yZXBvcnQuaWQsIGV4aXN0aW5nLmlkKSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIHRoaXMuX3J1bih0aGlzLl9yZXBvcnREYXRhLnVwZGF0ZUZpbHRlckdyb3VwKHRoaXMucmVwb3J0LmlkLCBleGlzdGluZy5maWx0ZXJHcm91cElkLCB7IGxldmVsIH0pKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fYWRkRmlsdGVyKHJvdywgbGV2ZWwpO1xuICAgIH1cbiAgfVxuXG4gIC8vIEEgdmFsdWUncyBSZXBvcnQgYmFyIHNlbGVjdCwgdGhlIG9ubHkgY29udHJvbCBpdCBoYXMuIEl0cyBmaWx0ZXIncyBncm91cFxuICAvLyBtYXkgYmUgc2hhcmVkICh0aGUgcmVwb3J0J3MgUGVyaW9kLCBzYXkpLCBhbmQgYSB2YWx1ZSBoYXMgbm8gc3RyaXAgb2YgaXRzXG4gIC8vIG93biwgc28gYSBwaWNrIG5ldmVyIGxvd2VycyB0aGUgZ3JvdXAgKHZhbHVlRmlsdGVyTGV2ZWwpLiBBIHBpY2sgdGhhdFxuICAvLyBtb3ZlcyBub3RoaW5nIHB1dHMgdGhlIHJvdyBiYWNrIGFzIHRoZSBncm91cCBzdGFuZHMuXG4gIHByaXZhdGUgX2FwcGx5VmFsdWVMZXZlbChyb3c6IEZpbHRlclJvdyk6IHZvaWQge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5fZmlsdGVycy5maW5kKChmaWx0ZXIpID0+IGZpbHRlci5maWx0ZXJDb2x1bW4gPT09IHJvdy5jb2x1bW4pO1xuICAgIGNvbnN0IGN1cnJlbnQgPSBleGlzdGluZyA/IHRoaXMuX2dyb3Vwc0J5SWQuZ2V0KGV4aXN0aW5nLmZpbHRlckdyb3VwSWQpPy5sZXZlbCA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBsZXZlbCA9IHZhbHVlRmlsdGVyTGV2ZWwocm93LnBsYWNlbWVudCwgY3VycmVudCk7XG5cbiAgICBpZiAoIWxldmVsKSB7XG4gICAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgICAgdGhpcy5fcnVuKHRoaXMuX3JlcG9ydERhdGEuZGVsZXRlRmlsdGVyKHRoaXMucmVwb3J0LmlkLCBleGlzdGluZy5pZCkpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoIWV4aXN0aW5nKSB7XG4gICAgICB0aGlzLl9hZGRGaWx0ZXIocm93LCBsZXZlbCk7XG4gICAgfSBlbHNlIGlmIChsZXZlbCAhPT0gY3VycmVudCkge1xuICAgICAgdGhpcy5fcnVuKHRoaXMuX3JlcG9ydERhdGEudXBkYXRlRmlsdGVyR3JvdXAodGhpcy5yZXBvcnQuaWQsIGV4aXN0aW5nLmZpbHRlckdyb3VwSWQsIHsgbGV2ZWwgfSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9yZWJ1aWxkUm93cygpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFRoZSB0eXBlIGdvZXMgb25seSB3aGVuIHRoZSBhdXRob3IgY291bGQgcGljayBpdDsgb3RoZXJ3aXNlIHRoZSBzZXJ2ZXJcbiAgLy8gaW5mZXJzIGl0LCBhcyBpdCBhbHdheXMgaGFzLlxuICBwcml2YXRlIF9hZGRGaWx0ZXIocm93OiBGaWx0ZXJSb3csIGxldmVsOiBSZXBvcnRGaWx0ZXJMZXZlbCk6IHZvaWQge1xuICAgIHRoaXMuX3J1bih0aGlzLl9yZXBvcnREYXRhLmFkZEZpbHRlcih0aGlzLnJlcG9ydC5pZCwgdGhpcy5jb21wb25lbnQuaWQsIHtcbiAgICAgIGZpbHRlckNvbHVtbjogcm93LmNvbHVtbixcbiAgICAgIGxhYmVsOiByb3cubGFiZWwsXG4gICAgICBsZXZlbCxcbiAgICAgIC4uLihyb3cudHlwZVNlbGVjdC5zaG93ID8geyB0eXBlOiByb3cudHlwZSB9IDoge30pLFxuICAgIH0pKTtcbiAgfVxuXG4gIC8vIEEgbmV3IHJvdyBvYmplY3QgcmF0aGVyIHRoYW4gYSBtdXRhdGlvbiwgc28gdGhlIHNpZ25hbCBzZWVzIHRoZSBjaGFuZ2U7XG4gIC8vIHRoZSBAZm9yIHRyYWNrcyB0aGUgY29sdW1uLCBzbyB0aGUgcm93J3MgY29udHJvbHMgc3Vydml2ZSB0aGUgc3dhcC5cbiAgcHJpdmF0ZSBfcGF0Y2hSb3cocm93OiBGaWx0ZXJSb3csIHBhdGNoOiBQYXJ0aWFsPEZpbHRlclJvdz4pOiBGaWx0ZXJSb3cge1xuICAgIGNvbnN0IHBhdGNoZWQgPSB7IC4uLnJvdywgLi4ucGF0Y2ggfTtcbiAgICB0aGlzLnJvd3MudXBkYXRlKChyb3dzKSA9PiByb3dzLm1hcCgoaXRlbSkgPT4gKGl0ZW0uY29sdW1uID09PSByb3cuY29sdW1uID8gcGF0Y2hlZCA6IGl0ZW0pKSk7XG5cbiAgICByZXR1cm4gcGF0Y2hlZDtcbiAgfVxuXG4gIC8vIFdoYXQgYSBmb3JtdWxhIHdvcmtzIG91dCwgbmFtaW5nIGVhY2ggb3BlcmFuZCBhcyBpdHMgY2hpcHMgZG8uIEFuIG9wIHRoaXNcbiAgLy8gdmlld2VyIGRvZXMgbm90IGtub3cgcmVhZHMgbm90aGluZy5cbiAgcHJpdmF0ZSBfZm9ybXVsYUxpbmUoKTogc3RyaW5nIHtcbiAgICBjb25zdCBmb3JtdWxhID0gdGhpcy5jb21wb25lbnQuY29uZmlnPy5mb3JtdWxhO1xuICAgIGNvbnN0IGxpbmUgPSBmb3JtdWxhID8gRk9STVVMQV9MSU5FU1tmb3JtdWxhLm9wXSA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCB2YWx1ZXMgPSB0aGlzLl9sYXllclZhbHVlcygpO1xuXG4gICAgcmV0dXJuIGxpbmUgPyBsaW5lKG9wZXJhbmRLZXlzKHRoaXMuY29tcG9uZW50KS5tYXAoKGtleSkgPT4gdGhpcy5fdmFsdWVOYW1lKHZhbHVlcywga2V5KSkpIDogJyc7XG4gIH1cblxuICAvLyBUaGUgc2VudGVuY2UgYSBxdWVyeSB2YWx1ZSdzIGRlbGV0ZSBjb25maXJtIGVuZHMgd2l0aCB3aGVuIGZvcm11bGFzIG9uIGl0c1xuICAvLyBsYXllciByZWFkIGl0OiB0aGUgc2VydmVyIGRlbGV0ZXMgdGhvc2Ugd2l0aCBpdC4gRW1wdHkgd2hlbiBub25lIGRvZXMsIGFuZFxuICAvLyBmb3IgYSBmb3JtdWxhLCB3aG9zZSBvcGVyYW5kcyBzdGF5LlxuICBwcml2YXRlIF9kZXBlbmRlbnRzTm90ZSgpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLmlzRm9ybXVsYSgpKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5ID0gdmFsdWVLZXkodGhpcy5jb21wb25lbnQpO1xuICAgIGNvbnN0IG5hbWVzID0gdGhpcy5fbGF5ZXJWYWx1ZXMoKVxuICAgICAgLmZpbHRlcigodmFsdWUpID0+IG9wZXJhbmRLZXlzKHZhbHVlKS5pbmNsdWRlcyhrZXkpKVxuICAgICAgLm1hcCgodmFsdWUpID0+IGVzY2FwZUh0bWwodmFsdWUudGl0bGUgfHwgdmFsdWVLZXkodmFsdWUpKSk7XG5cbiAgICByZXR1cm4gbmFtZXMubGVuZ3RoID8gYCBUaGUgdmFsdWVzIHdvcmtlZCBvdXQgZnJvbSBpdCBhcmUgZGVsZXRlZCB0b286ICR7bmFtZXMuam9pbignLCAnKX0uYCA6ICcnO1xuICB9XG5cbiAgLy8gVGhlIHZhbHVlcyBvZiB0aGUgbGF5ZXIgdGhpcyB2YWx1ZSBiZWxvbmdzIHRvOiB0aGUgcGFnZSB3aG9zZSB2YWx1ZXMgaG9sZFxuICAvLyBpdCwgZWxzZSB0aGUgbWFzdGVyJ3MgKGEgaGVhZGVyIG9yIGZvb3RlciB2YWx1ZSkuXG4gIHByaXZhdGUgX2xheWVyVmFsdWVzKCk6IFJlcG9ydENvbXBvbmVudFtdIHtcbiAgICBjb25zdCBwYWdlID0gKHRoaXMucmVwb3J0LnBhZ2VzID8/IFtdKVxuICAgICAgLmZpbmQoKGNhbmRpZGF0ZSkgPT4gKGNhbmRpZGF0ZS52YWx1ZXMgPz8gW10pLnNvbWUoKHZhbHVlKSA9PiB2YWx1ZS5pZCA9PT0gdGhpcy5jb21wb25lbnQuaWQpKTtcblxuICAgIHJldHVybiAocGFnZSA/PyB0aGlzLnJlcG9ydC5tYXN0ZXIpPy52YWx1ZXMgPz8gW107XG4gIH1cblxuICAvLyBXaGF0IGEgdmFsdWUgaXMgY2FsbGVkIHdoZXJlIGl0cyBjaGlwcyBzaG93IGl0OiBpdHMgbmFtZSwgZWxzZSBpdHMga2V5LlxuICAvLyBUaGUgbmV3ZXN0IHZhbHVlIGhvbGRzIGEga2V5LCBhcyBpdCBkb2VzIGluIHRoZSB0ZXh0J3MgdG9rZW5zLlxuICBwcml2YXRlIF92YWx1ZU5hbWUodmFsdWVzOiBSZXBvcnRDb21wb25lbnRbXSwga2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHZhbHVlID0gdmFsdWVzLmZpbHRlcigoY2FuZGlkYXRlKSA9PiB2YWx1ZUtleShjYW5kaWRhdGUpID09PSBrZXkpLnBvcCgpO1xuXG4gICAgcmV0dXJuIHZhbHVlPy50aXRsZSB8fCBrZXk7XG4gIH1cblxuICAvLyBBIGRlcml2ZWQgS1BJJ3MgY2FyZCBrZXlzLCBmcm9tIGl0cyBjb25maWcuIEEgc3FsLW1vZGUgS1BJIGNhbm5vdCBjYXJyeVxuICAvLyB0aGVtLCBzbyBpdCBnZXRzIG5vIGNhcmQgZmllbGRzLlxuICBwcml2YXRlIF9zZWVkS3BpQ2FyZCgpOiB2b2lkIHtcbiAgICBjb25zdCBjb25maWcgPSAodGhpcy5jb21wb25lbnQuY29uZmlnID8/IHt9KSBhcyBLcGlDb25maWc7XG5cbiAgICB0aGlzLmtwaUNhcmQuc2V0KHRoaXMuY29tcG9uZW50LnR5cGUgPT09ICdrcGknICYmICF0aGlzLmNvbXBvbmVudC5zcWwpO1xuICAgIHRoaXMuaW5jcmVhc2VJcy5zZXQoY29uZmlnLmluY3JlYXNlSXMgPz8gUmVwb3J0Q2hhbmdlUG9sYXJpdHkuR29vZCk7XG4gICAgdGhpcy50YXJnZXRQZXJjZW50LnNldChjb25maWcubWVhc3VyZT8uZm9ybWF0ID09PSBSZXBvcnRWYWx1ZUZvcm1hdC5QZXJjZW50XG4gICAgICAmJiByZXNvbHZlRm9ybWF0Q29udGV4dCh0aGlzLnJlcG9ydCkucmF0aW9QZXJjZW50KTtcbiAgICB0aGlzLnRhcmdldFZhbHVlLnNldCh0aGlzLl90YXJnZXRTaG93bihjb25maWcudGFyZ2V0Py52YWx1ZSA/PyBudWxsKSk7XG4gICAgdGhpcy50YXJnZXRMYWJlbC5zZXQoY29uZmlnLnRhcmdldD8ubGFiZWwgPz8gJycpO1xuICAgIHRoaXMuc3BhcmtsaW5lLnNldCghIWNvbmZpZy5zcGFya2xpbmUpO1xuICAgIHRoaXMuc3BhcmtsaW5lR3JhbnVsYXJpdHkuc2V0KGNvbmZpZy5zcGFya2xpbmU/LmdyYW51bGFyaXR5ID8/IEtQSV9TUEFSS0xJTkVfREVGQVVMVF9HUkFOVUxBUklUWSk7XG4gICAgdGhpcy5zcGFya2xpbmVQZXJpb2RzLnNldChjb25maWcuc3BhcmtsaW5lPy5wZXJpb2RzID8/IEtQSV9TUEFSS0xJTkVfREVGQVVMVF9QRVJJT0RTKTtcbiAgfVxuXG4gIC8vIFRoZSBjYXJkIGtleXMgdGhlIHNlcnZlciBzYXZlZCwgZnJvbSB0aGUgY29uZmlnIGl0cyByZXNwb25zZSBjYXJyaWVzO1xuICAvLyBudWxsIHdoZW4gaXQgY2FycmllcyBub25lIChhIHNlcnZlciB0aGF0IGRvZXMgbm90IHNhdmUgdGhlbSkuXG4gIHByaXZhdGUgX3NhdmVkS3BpQ2FyZChyZXNwb25zZTogQ29tcG9uZW50U2V0dGluZ3NSZXNwb25zZSB8IG51bGwgfCB1bmRlZmluZWQpOiBLcGlDYXJkU2V0dGluZ3MgfCBudWxsIHtcbiAgICBjb25zdCBjb25maWcgPSByZXNwb25zZT8uY29uZmlnO1xuXG4gICAgcmV0dXJuIGNvbmZpZyAmJiB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyA/IGtwaUNhcmRTZXR0aW5ncyhjb25maWcgYXMgS3BpQ29uZmlnKSA6IG51bGw7XG4gIH1cblxuICAvLyBHb29kIGlzIHdoYXQgYW4gYWJzZW50IGluY3JlYXNlSXMgcmVhZHMsIHNvIGl0IGlzIHNhdmVkIGFzIGFic2VudC5cbiAgcHJpdmF0ZSBfa3BpQ2FyZFNldHRpbmdzKCk6IEtwaUNhcmRTZXR0aW5ncyB7XG4gICAgY29uc3QgdGFyZ2V0ID0gdGhpcy5fbnVtYmVyKHRoaXMudGFyZ2V0VmFsdWUoKSk7XG4gICAgY29uc3QgbGFiZWwgPSB0aGlzLnRhcmdldExhYmVsKCkudHJpbSgpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGluY3JlYXNlSXM6IHRoaXMuaW5jcmVhc2VJcygpID09PSBSZXBvcnRDaGFuZ2VQb2xhcml0eS5Hb29kID8gbnVsbCA6IHRoaXMuaW5jcmVhc2VJcygpLFxuICAgICAgdGFyZ2V0OiB0YXJnZXQgPT09IG51bGwgPyBudWxsIDogeyB2YWx1ZTogdGhpcy5fdGFyZ2V0U3RvcmVkKHRhcmdldCksIGxhYmVsOiBsYWJlbCB8fCBudWxsIH0sXG4gICAgICBzcGFya2xpbmU6IHRoaXMuc3BhcmtsaW5lKClcbiAgICAgICAgPyB7IGdyYW51bGFyaXR5OiB0aGlzLnNwYXJrbGluZUdyYW51bGFyaXR5KCksIHBlcmlvZHM6IHRoaXMuX251bWJlcih0aGlzLnNwYXJrbGluZVBlcmlvZHMoKSkgfVxuICAgICAgICA6IG51bGwsXG4gICAgfTtcbiAgfVxuXG4gIC8vIEEgc3RvcmVkIHJhdGlvIGFzIHRoZSBwZXJjZW50IHR5cGVkLCByb3VuZGVkIHNvIDAuMTUgcmVhZHMgMTUgYW5kIG5vdFxuICAvLyAxNS4wMDAwMDAwMDAwMDAwMDIuXG4gIHByaXZhdGUgX3RhcmdldFNob3duKHZhbHVlOiBudW1iZXIgfCBudWxsKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgaWYgKHZhbHVlID09PSBudWxsIHx8ICF0aGlzLnRhcmdldFBlcmNlbnQoKSkge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cblxuICAgIHJldHVybiBNYXRoLnJvdW5kKHZhbHVlICogMTAwICogMWU2KSAvIDFlNjtcbiAgfVxuXG4gIHByaXZhdGUgX3RhcmdldFN0b3JlZCh2YWx1ZTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50YXJnZXRQZXJjZW50KCkgPyB2YWx1ZSAvIDEwMCA6IHZhbHVlO1xuICB9XG5cbiAgLy8gQSB0eXBlZCBudW1iZXIsIG9yIG51bGwgd2hlbiB0aGUgZmllbGQgaXMgZW1wdHkuXG4gIHByaXZhdGUgX251bWJlcih2YWx1ZTogbnVtYmVyIHwgc3RyaW5nIHwgbnVsbCk6IG51bWJlciB8IG51bGwge1xuICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gJycpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IG51bWJlciA9IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgPyB2YWx1ZSA6IHBhcnNlRmxvYXQodmFsdWUpO1xuXG4gICAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShudW1iZXIpID8gbnVtYmVyIDogbnVsbDtcbiAgfVxuXG4gIC8vIFRoZSBwYWRkaW5nIGFzIGEgcmVhbCBudW1iZXIgZm9yIHRoZSB3aXJlLiBmc01hc2tOdW1iZXIgaGFuZHMgYmFjayB0aGVcbiAgLy8gdW5tYXNrZWQgc3RyaW5nIGl0IGJ1aWx0IHdpdGggYSBmaXhlZCAnLicgcmFkaXgsIHNvIHRoaXMgaXMgYSBzdHJhaWdodFxuICAvLyBwYXJzZSAtIHRoZSB3aG9sZSByZWFzb24gZm9yIHRoZSBtYXNrIGlzIHRoYXQgYSBuYXRpdmUgbnVtYmVyIGlucHV0IHdvdWxkXG4gIC8vIHBhaW50IChhbmQgcmVhZCBiYWNrKSB0aGUgdmlld2VyJ3Mgb3duIGxvY2FsZSBzZXBhcmF0b3IgaW5zdGVhZC5cbiAgcHJpdmF0ZSBfcGFkZGluZyh2YWx1ZTogbnVtYmVyIHwgc3RyaW5nKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyA/IHZhbHVlIDogcGFyc2VGbG9hdCh2YWx1ZSk7XG4gIH1cblxuICAvLyBSdW4gYSBmaWx0ZXIgbXV0YXRpb24sIHRoZW4gcmVsb2FkIHRvIHJlY29uY2lsZSB0aGUgb3B0aW1pc3RpYyBzdGF0ZS5cbiAgcHJpdmF0ZSBfcnVuKHJlcXVlc3Q6IE9ic2VydmFibGU8dW5rbm93bj4pOiB2b2lkIHtcbiAgICByZXF1ZXN0LnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoKSA9PiB0aGlzLl9hZnRlck11dGF0aW9uKCksXG4gICAgICBlcnJvcjogKGVycm9yKSA9PiB0aGlzLl9tdXRhdGlvbkVycm9yKGVycm9yKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8vIEJ1aWxkIHRoZSByb3cgdmlldy1tb2RlbCBmcm9tIHRoZSBsb2FkZWQgY29sdW1ucyArIGZpbHRlcnMvZ3JvdXBzLiBFYWNoXG4gIC8vIHJvdydzIGNvbnRyb2xzIHJlZmxlY3Qgd2hlcmUgaXRzIGZpbHRlciBncm91cCBjdXJyZW50bHkgc2hvd3M7IGEgY29sdW1uXG4gIC8vIHdpdGggYSBmaWx0ZXIgc2hvd3MgdGhlIGZpbHRlcidzIG93biB0eXBlLiBBIHZhbHVlJ3Mgcm93cyBuZXZlciByZWFkIGFzXG4gIC8vIG9uIGEgY29tcG9uZW50OiBpdCBoYXMgbm8gc3RyaXAsIHdoYXRldmVyIGxldmVsIGEgZ3JvdXAgaXQgc2hhcmVzIGlzIGF0LFxuICAvLyBhbmQgaXRzIFJlcG9ydCBiYXIgc2VsZWN0IG9mZmVycyBubyBwaWNrIHRoYXQgbG93ZXJzIHRoYXQgZ3JvdXAuXG4gIHByaXZhdGUgX3JlYnVpbGRSb3dzKCk6IHZvaWQge1xuICAgIGNvbnN0IGxldmVsQ2hvaWNlcyA9IGZpbHRlckxldmVsQ2hvaWNlcyh0aGlzLnJlcG9ydC52aWV3ZXJGZWF0dXJlcywgdGhpcy5fb25QYWdlKCkpO1xuXG4gICAgdGhpcy5yb3dzLnNldCh0aGlzLl9maWx0ZXJhYmxlQ29sdW1ucy5tYXAoKGNvbHVtbikgPT4ge1xuICAgICAgY29uc3QgZmlsdGVyID0gdGhpcy5fZmlsdGVycy5maW5kKChjYW5kaWRhdGUpID0+IGNhbmRpZGF0ZS5maWx0ZXJDb2x1bW4gPT09IGNvbHVtbi5jb2x1bW4pO1xuICAgICAgY29uc3QgZ3JvdXAgPSBmaWx0ZXIgPyB0aGlzLl9ncm91cHNCeUlkLmdldChmaWx0ZXIuZmlsdGVyR3JvdXBJZCkgOiB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBwbGFjZW1lbnQgPSBiYXJQbGFjZW1lbnQoZ3JvdXA/LmxldmVsKTtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY29sdW1uOiBjb2x1bW4uY29sdW1uLFxuICAgICAgICB0eXBlOiBncm91cD8udHlwZVxuICAgICAgICAgID8/IHRoaXMuX3BpY2tlZFR5cGVzLmdldChjb2x1bW4uY29sdW1uKVxuICAgICAgICAgID8/IGNvbHVtbi50eXBlcz8uWzBdXG4gICAgICAgICAgPz8gY29sdW1uLnR5cGUsXG4gICAgICAgIGxhYmVsOiBmaWx0ZXI/LmxhYmVsXG4gICAgICAgICAgfHwgdGhpcy5fZ3JvdXBzQnlJZC5nZXQoZmlsdGVyPy5maWx0ZXJHcm91cElkID8/IC0xKT8ubGFiZWxcbiAgICAgICAgICB8fCB0aGlzLl9odW1hbml6ZShjb2x1bW4uY29sdW1uKSxcbiAgICAgICAgcGxhY2VtZW50LFxuICAgICAgICBjb21wb25lbnQ6ICF0aGlzLmlzVmFsdWUoKSAmJiBzaG93bk9uQ29tcG9uZW50KGdyb3VwPy5sZXZlbCksXG4gICAgICAgIHR5cGVTZWxlY3Q6IHR5cGVTZWxlY3RTdGF0ZShjb2x1bW4udHlwZXMsICEhZmlsdGVyLCB0aGlzLnJlcG9ydC52aWV3ZXJGZWF0dXJlcyksXG4gICAgICAgIHBsYWNlbWVudE9wdGlvbnM6IHRoaXMuaXNWYWx1ZSgpXG4gICAgICAgICAgPyB2YWx1ZVBsYWNlbWVudE9wdGlvbnMobGV2ZWxDaG9pY2VzLCBncm91cD8ubGV2ZWwpXG4gICAgICAgICAgOiBiYXJQbGFjZW1lbnRPcHRpb25zKGxldmVsQ2hvaWNlcywgcGxhY2VtZW50KSxcbiAgICAgICAgY29tcG9uZW50VG9nZ2xlOiBjb21wb25lbnRUb2dnbGVTdGF0ZShwbGFjZW1lbnQpLFxuICAgICAgfTtcbiAgICB9KSk7XG4gIH1cblxuICAvLyBXaGV0aGVyIHRoZSBjb21wb25lbnQgc2l0cyBvbiBhIHBhZ2U6IGFtb25nIGl0cyBjb21wb25lbnRzLCBvciwgZm9yIGFcbiAgLy8gdmFsdWUsIGl0cyB2YWx1ZXMuIEEgaGVhZGVyIG9yIGZvb3RlciBjb21wb25lbnQgb3IgdmFsdWUgc2l0cyBvbiBub25lLFxuICAvLyBzbyBpdHMgZmlsdGVycyBjYW5ub3QgYmUgcGFnZSBmaWx0ZXJzLlxuICBwcml2YXRlIF9vblBhZ2UoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICh0aGlzLnJlcG9ydC5wYWdlcyA/PyBbXSlcbiAgICAgIC5zb21lKChwYWdlKSA9PiBbLi4uKHBhZ2UuY29tcG9uZW50cyA/PyBbXSksIC4uLihwYWdlLnZhbHVlcyA/PyBbXSldXG4gICAgICAgIC5zb21lKChjYW5kaWRhdGUpID0+IGNhbmRpZGF0ZS5pZCA9PT0gdGhpcy5jb21wb25lbnQuaWQpKTtcbiAgfVxuXG4gIC8vIEFmdGVyIGFueSBmaWx0ZXIgbXV0YXRpb246IHJlLWZldGNoIHRoZSByZXBvcnQgc28gdGhlIGRpYWxvZydzIGZpbHRlciBsaXN0XG4gIC8vIChhbmQgdGhlIHBhcmVudCBjYW52YXMsIG9uIGNsb3NlKSByZWZsZWN0IHRoZSBuZXcgZ3JvdXBzL2xldmVscy5cbiAgcHJpdmF0ZSBfYWZ0ZXJNdXRhdGlvbigpOiB2b2lkIHtcbiAgICB0aGlzLmZpbHRlcnNDaGFuZ2VkLmVtaXQoKTtcblxuICAgIHRoaXMuX3JlcG9ydERhdGEuZ2V0KHRoaXMucmVwb3J0LmlkKVxuICAgICAgLnN1YnNjcmliZSgocmVwb3J0OiBSZXBvcnQpID0+IHtcbiAgICAgICAgdGhpcy5yZXBvcnQgPSByZXBvcnQ7XG4gICAgICAgIHRoaXMuX3NlZWRGaWx0ZXJzKHJlcG9ydCwgdGhpcy5jb21wb25lbnQuaWQpO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9tdXRhdGlvbkVycm9yKGVycm9yOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLl9tZXNzYWdlLmVycm9yKGVycm9yPy5lcnJvcj8ubWVzc2FnZSA/PyBlcnJvcj8ubWVzc2FnZSA/PyAnRmlsdGVyIG9wZXJhdGlvbiBmYWlsZWQnKTtcbiAgICAvLyBSZS1zZWVkIGZyb20gdGhlIHNlcnZlciBzbyB0aGUgb3B0aW1pc3RpYyB0b2dnbGUgc25hcHMgYmFjayB0byB0cnV0aC5cbiAgICB0aGlzLl9hZnRlck11dGF0aW9uKCk7XG4gIH1cblxuICAvLyBUaGUgY29tcG9uZW50J3MgZmlsdGVycyBhbmQgdGhlIGdyb3VwcyB0aGV5IHNpdCBpbiwgZnJvbSB0aGUgcmVwb3J0IGFzXG4gIC8vIGxhc3QgbG9hZGVkLiBBIHZhbHVlIGlzIGxpc3RlZCBpbiBpdHMgcGFnZSdzIHZhbHVlcywgbm90IGl0cyBjb21wb25lbnRzLlxuICBwcml2YXRlIF9zZWVkRmlsdGVycyhyZXBvcnQ6IFJlcG9ydCwgY29tcG9uZW50SWQ6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuX2dyb3Vwc0J5SWQgPSBuZXcgTWFwKChyZXBvcnQuZmlsdGVyR3JvdXBzID8/IFtdKS5tYXAoKGdyb3VwKSA9PiBbZ3JvdXAuaWQsIGdyb3VwXSkpO1xuXG4gICAgY29uc3QgY29tcG9uZW50ID0gcmVwb3J0Q29tcG9uZW50cyhyZXBvcnQpXG4gICAgICAuZmluZCgoY2FuZGlkYXRlKSA9PiBjYW5kaWRhdGUuaWQgPT09IGNvbXBvbmVudElkKTtcblxuICAgIHRoaXMuX2ZpbHRlcnMgPSBjb21wb25lbnQ/LmZpbHRlcnMgPz8gW107XG4gICAgdGhpcy5fcmVidWlsZFJvd3MoKTtcbiAgfVxuXG4gIC8vIFRoZSBzdGF0ZW1lbnQgdGhlIFNRTCB0YWIgc2hvd3MuIEZldGNoZWQgcmF0aGVyIHRoYW4gcmVhZCBvZmYgdGhlXG4gIC8vIGNvbXBvbmVudDogYSBkZXJpdmVkIGNvbXBvbmVudCBzdG9yZXMgYSBkb2N1bWVudCwgbm90IFNRTCwgc28gaXRzXG4gIC8vIHN0YXRlbWVudCBvbmx5IGV4aXN0cyBvbmNlIHRoZSBiYWNrZW5kIGNvbXBpbGVzIGl0LlxuICAvL1xuICAvLyBMb2FkZWQgaW4gbmdPbkluaXQgYmVzaWRlIHRoZSBjb2x1bW5zLCBOT1Qgb24gdGFiIGFjdGl2YXRpb24uIFRoZSB0YWJzIGFyZVxuICAvLyBub3QgbGF6eSAobm8gbWF0VGFiQ29udGVudCksIGFuZCBzd2l0Y2hpbmcgdGhlIHRhYi1ncm91cCdzIGBbKHNlbGVjdGVkKV1gXG4gIC8vIGJhbmFuYS1ib3ggdG8gYSBvbmUtd2F5IGJpbmRpbmcgcGx1cyAoc2VsZWN0ZWRDaGFuZ2UpIHRvIGdldCBhIGhvb2sgd291bGRcbiAgLy8gYnJlYWsgaXQ6IEZzVGFic0hlYWRlclRhYkdyb3VwRGlyZWN0aXZlIHNlbGYtYXNzaWducyBgdGhpcy5zZWxlY3RlZGAgYmVmb3JlXG4gIC8vIGl0IGVtaXRzLCBzbyB0aGUgZXZlbnQgaXMgZmlsdGVyZWQgb3V0IGFuZCB0aGUgbG9hZCB3b3VsZCBuZXZlciBmaXJlLiBPbmVcbiAgLy8gc21hbGwgcmVxdWVzdCB3aGVuIGEgZGlhbG9nIG9wZW5zIGlzIG5vdCB3b3J0aCB0aGF0IHJpc2suXG4gIHByaXZhdGUgX2xvYWRTcWwoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVwb3J0RGF0YS5jb21wb25lbnRTcWwodGhpcy5yZXBvcnQuaWQsIHRoaXMuY29tcG9uZW50LmlkKVxuICAgICAgLnN1YnNjcmliZSh7XG4gICAgICAgIG5leHQ6IChwcmV2aWV3OiBSZXBvcnRDb21wb25lbnRTcWwpID0+IHtcbiAgICAgICAgICB0aGlzLnNxbC5zZXQocHJldmlldz8uc3FsID8/IG51bGwpO1xuICAgICAgICAgIHRoaXMuc3FsQmFzZWxpbmUuc2V0KCEhcHJldmlldz8uYmFzZWxpbmUpO1xuICAgICAgICAgIHRoaXMuc3FsVGltZXpvbmUuc2V0KHByZXZpZXc/LnRpbWV6b25lIHx8ICdVVEMnKTtcbiAgICAgICAgICB0aGlzLnNxbEVycm9yLnNldChwcmV2aWV3Py5lcnJvciA/PyBudWxsKTtcbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3I6IChlcnJvcikgPT4ge1xuICAgICAgICAgIHRoaXMuc3FsLnNldChudWxsKTtcbiAgICAgICAgICB0aGlzLnNxbEVycm9yLnNldChlcnJvcj8uZXJyb3I/Lm1lc3NhZ2UgPz8gJ0NvdWxkIG5vdCByZWFkIHRoZSBjb21wb25lbnQgU1FMJyk7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2xvYWRDb2x1bW5zKCk6IHZvaWQge1xuICAgIHRoaXMuX3JlcG9ydERhdGEuY29tcG9uZW50Q29sdW1ucyh0aGlzLnJlcG9ydC5pZCwgdGhpcy5jb21wb25lbnQuaWQpXG4gICAgICAuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKGNvbHVtbnM6IFJlcG9ydEZpbHRlcmFibGVDb2x1bW5bXSkgPT4ge1xuICAgICAgICAgIHRoaXMuX2ZpbHRlcmFibGVDb2x1bW5zID0gY29sdW1ucyA/PyBbXTtcbiAgICAgICAgICB0aGlzLl9yZWJ1aWxkUm93cygpO1xuICAgICAgICB9LFxuICAgICAgICBlcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgICAgdGhpcy5jb2x1bW5zRXJyb3Iuc2V0KGVycm9yPy5lcnJvcj8ubWVzc2FnZSA/PyAnQ291bGQgbm90IHJlYWQgdGhlIGNvbXBvbmVudCBjb2x1bW5zJyk7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2h1bWFuaXplKGNvbHVtbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY29sdW1uXG4gICAgICAucmVwbGFjZSgvW19cXC1dKy9nLCAnICcpXG4gICAgICAucmVwbGFjZSgvXFxzKy9nLCAnICcpXG4gICAgICAudHJpbSgpXG4gICAgICAucmVwbGFjZSgvXFxiXFx3L2csIChjaGFyYWN0ZXIpID0+IGNoYXJhY3Rlci50b1VwcGVyQ2FzZSgpKTtcbiAgfVxufVxuIiwiPGZvcm1cbiAgICBmc0Zvcm1cbiAgICBbc3VibWl0XT1cInNhdmVcIj5cbiAgPGZzLWRpYWxvZz5cbiAgICA8aDEgbWF0LWRpYWxvZy10aXRsZT5cbiAgICAgIHt7IGNvbXBvbmVudC50aXRsZSB8fCAoaXNWYWx1ZSgpID8gJ1ZhbHVlJyA6ICdDb21wb25lbnQnKSB9fVxuICAgIDwvaDE+XG4gICAgPG1hdC1kaWFsb2ctY29udGVudD5cbiAgICAgIDxtYXQtdGFiLWdyb3VwIFsoc2VsZWN0ZWQpXT1cInNlbGVjdGVkVGFiXCI+XG4gICAgICAgIDxtYXQtdGFiXG4gICAgICAgICAgICBsYWJlbD1cIlNldHRpbmdzXCJcbiAgICAgICAgICAgIG5hbWU9XCJzZXR0aW5nc1wiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJmcy1jb2x1bW4gdGFiLWJvZHlcIj5cbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICB7eyBpc1ZhbHVlKCkgPyAnTmFtZScgOiAnVGl0bGUnIH19XG4gICAgICAgICAgICAgIDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwidGl0bGVcIlxuICAgICAgICAgICAgICAgIG5hbWU9XCJ0aXRsZVwiXG4gICAgICAgICAgICAgICAgW2ZzRm9ybVJlcXVpcmVkXT1cImlzVmFsdWUoKVwiPlxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgIDwhLS0gQSBmb3JtdWxhIHZhbHVlIGlzIHJlYWQtb25seSBiZXlvbmQgaXRzIG5hbWU6IHdoYXQgaXQgd29ya3NcbiAgICAgICAgICAgICAgICAgb3V0IGlzIHRoZSBBSSdzIHRvIGNoYW5nZS4gQSBmb3JtdWxhIHRoaXMgdmlld2VyIGNhbm5vdFxuICAgICAgICAgICAgICAgICByZWFkIGhhcyBubyBsaW5lLCBhbmQgbm8gcm93LiAtLT5cbiAgICAgICAgICAgIEBpZiAoZm9ybXVsYUxpbmUoKSkge1xuICAgICAgICAgICAgICA8ZnMtbGFiZWwtZmllbGQ+XG4gICAgICAgICAgICAgICAgPGZzLWxhYmVsPlxuICAgICAgICAgICAgICAgICAgRm9ybXVsYVxuICAgICAgICAgICAgICAgIDwvZnMtbGFiZWw+XG4gICAgICAgICAgICAgICAge3sgZm9ybXVsYUxpbmUoKSB9fVxuICAgICAgICAgICAgICAgIDxmcy1sYWJlbC1tZXNzYWdlPlxuICAgICAgICAgICAgICAgICAgV29ya2VkIG91dCBvbiB0aGUgc2VydmVyOyBpdCBmb2xsb3dzIHRoZSBmaWx0ZXJzIG9mIHRoZSB2YWx1ZXMgaXQgcmVhZHMuXG4gICAgICAgICAgICAgICAgPC9mcy1sYWJlbC1tZXNzYWdlPlxuICAgICAgICAgICAgICA8L2ZzLWxhYmVsLWZpZWxkPlxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgPCEtLSBBIHZhbHVlIHNpdHMgaW5zaWRlIGEgdGV4dCBibG9jaydzIHdvcmRzOiBubyBib3gsIG5vIHBhZGRpbmcuIC0tPlxuICAgICAgICAgICAgQGlmICghaXNWYWx1ZSgpKSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdWJoZWFkaW5nLTJcIj5cbiAgICAgICAgICAgICAgICBQYWRkaW5nXG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZ2VvbWV0cnktcm93XCI+XG4gICAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgICAgVG9wXG4gICAgICAgICAgICAgICAgICA8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICAgICAgICBmc01hc2tOdW1iZXJcbiAgICAgICAgICAgICAgICAgICAgW3NjYWxlXT1cIjNcIlxuICAgICAgICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cInBhZGRpbmdUb3BcIlxuICAgICAgICAgICAgICAgICAgICBuYW1lPVwicGFkZGluZ1RvcFwiXG4gICAgICAgICAgICAgICAgICAgIFtmc0Zvcm1NaW5dPVwiMFwiPlxuICAgICAgICAgICAgICAgICAgPGRpdiBtYXRUZXh0U3VmZml4PlxuICAgICAgICAgICAgICAgICAgICBpblxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgICBSaWdodFxuICAgICAgICAgICAgICAgICAgPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICAgICAgZnNNYXNrTnVtYmVyXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCIzXCJcbiAgICAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJwYWRkaW5nUmlnaHRcIlxuICAgICAgICAgICAgICAgICAgICBuYW1lPVwicGFkZGluZ1JpZ2h0XCJcbiAgICAgICAgICAgICAgICAgICAgW2ZzRm9ybU1pbl09XCIwXCI+XG4gICAgICAgICAgICAgICAgICA8ZGl2IG1hdFRleHRTdWZmaXg+XG4gICAgICAgICAgICAgICAgICAgIGluXG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICAgIEJvdHRvbVxuICAgICAgICAgICAgICAgICAgPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICAgICAgZnNNYXNrTnVtYmVyXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCIzXCJcbiAgICAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJwYWRkaW5nQm90dG9tXCJcbiAgICAgICAgICAgICAgICAgICAgbmFtZT1cInBhZGRpbmdCb3R0b21cIlxuICAgICAgICAgICAgICAgICAgICBbZnNGb3JtTWluXT1cIjBcIj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgbWF0VGV4dFN1ZmZpeD5cbiAgICAgICAgICAgICAgICAgICAgaW5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgICAgTGVmdFxuICAgICAgICAgICAgICAgICAgPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgICAgICAgZnNNYXNrTnVtYmVyXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCIzXCJcbiAgICAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJwYWRkaW5nTGVmdFwiXG4gICAgICAgICAgICAgICAgICAgIG5hbWU9XCJwYWRkaW5nTGVmdFwiXG4gICAgICAgICAgICAgICAgICAgIFtmc0Zvcm1NaW5dPVwiMFwiPlxuICAgICAgICAgICAgICAgICAgPGRpdiBtYXRUZXh0U3VmZml4PlxuICAgICAgICAgICAgICAgICAgICBpblxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICA8IS0tIEEgZGVyaXZlZCBLUEkncyBjYXJkOiB3aGF0IGEgcmlzZSBtZWFucywgYSB0YXJnZXQgYW5kIGFcbiAgICAgICAgICAgICAgICAgc3BhcmtsaW5lLiBUaGUgc2VydmVyIGNvbXB1dGVzIHRoZSBwcm9ncmVzcyBhbmQgdGhlIHBvaW50cy4gLS0+XG4gICAgICAgICAgICBAaWYgKGtwaUNhcmQoKSkge1xuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3ViaGVhZGluZy0yXCI+XG4gICAgICAgICAgICAgICAgQ2FyZFxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiZnVsbC13aWR0aFwiPlxuICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICBJbmNyZWFzZSBpc1xuICAgICAgICAgICAgICAgIDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgIDxtYXQtc2VsZWN0XG4gICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImluY3JlYXNlSXMoKVwiXG4gICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cImluY3JlYXNlSXMuc2V0KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICBuYW1lPVwiaW5jcmVhc2VJc1wiPlxuICAgICAgICAgICAgICAgICAgQGZvciAob3B0aW9uIG9mIGtwaVBvbGFyaXR5T3B0aW9uczsgdHJhY2sgb3B0aW9uLnZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIDxtYXQtb3B0aW9uIFt2YWx1ZV09XCJvcHRpb24udmFsdWVcIj5cbiAgICAgICAgICAgICAgICAgICAgICB7eyBvcHRpb24ubmFtZSB9fVxuICAgICAgICAgICAgICAgICAgICA8L21hdC1vcHRpb24+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgPC9tYXQtc2VsZWN0PlxuICAgICAgICAgICAgICAgIDxtYXQtaGludD5cbiAgICAgICAgICAgICAgICAgIENvbG9ycyB0aGUgY2hhbmdlIGFuZCBkZWNpZGVzIHdoZW4gdGhlIHRhcmdldCBpcyBtZXQuXG4gICAgICAgICAgICAgICAgPC9tYXQtaGludD5cbiAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiZnVsbC13aWR0aFwiPlxuICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgICBUYXJnZXRcbiAgICAgICAgICAgICAgICA8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgICAgICBmc01hc2tOdW1iZXJcbiAgICAgICAgICAgICAgICAgIFtzY2FsZV09XCI2XCJcbiAgICAgICAgICAgICAgICAgIFtzaWduZWRdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0YXJnZXRWYWx1ZSgpXCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInRhcmdldFZhbHVlLnNldCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgIG5hbWU9XCJ0YXJnZXRWYWx1ZVwiXG4gICAgICAgICAgICAgICAgICBbdmFsaWRhdGVdPVwidmFsaWRhdGVUYXJnZXRcIj5cbiAgICAgICAgICAgICAgICBAaWYgKHRhcmdldFBlcmNlbnQoKSkge1xuICAgICAgICAgICAgICAgICAgPGRpdiBtYXRUZXh0U3VmZml4PlxuICAgICAgICAgICAgICAgICAgICAlXG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgPG1hdC1oaW50PlxuICAgICAgICAgICAgICAgICAgVGhlIHZhbHVlIHRvIHJlYWNoLiBMZWF2ZSBlbXB0eSBmb3Igbm8gdGFyZ2V0LlxuICAgICAgICAgICAgICAgIDwvbWF0LWhpbnQ+XG4gICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgIEBpZiAoaGFzVGFyZ2V0KCkpIHtcbiAgICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJmdWxsLXdpZHRoXCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgICBUYXJnZXQgbGFiZWxcbiAgICAgICAgICAgICAgICAgIDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInRhcmdldExhYmVsKClcIlxuICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ0YXJnZXRMYWJlbC5zZXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIG5hbWU9XCJ0YXJnZXRMYWJlbFwiPlxuICAgICAgICAgICAgICAgICAgPG1hdC1oaW50PlxuICAgICAgICAgICAgICAgICAgICBTaG93biBiZWZvcmUgdGhlIHRhcmdldCwgc3VjaCBhcyBHb2FsLiBFbXB0eSByZWFkcyBUYXJnZXQuXG4gICAgICAgICAgICAgICAgICA8L21hdC1oaW50PlxuICAgICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPGZzLWxhYmVsLWZpZWxkPlxuICAgICAgICAgICAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXG4gICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInNwYXJrbGluZSgpXCJcbiAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3BhcmtsaW5lLnNldCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgbmFtZT1cInNwYXJrbGluZVwiPlxuICAgICAgICAgICAgICAgICAgU3BhcmtsaW5lXG4gICAgICAgICAgICAgICAgPC9tYXQtc2xpZGUtdG9nZ2xlPlxuICAgICAgICAgICAgICAgIDxtYXQtaGludD5cbiAgICAgICAgICAgICAgICAgIEEgc21hbGwgdHJlbmQgbGluZSBvZiB0aGUgdmFsdWUgb3ZlciBpdHMgbGFzdCBwZXJpb2RzLlxuICAgICAgICAgICAgICAgIDwvbWF0LWhpbnQ+XG4gICAgICAgICAgICAgIDwvZnMtbGFiZWwtZmllbGQ+XG4gICAgICAgICAgICAgIEBpZiAoc3BhcmtsaW5lKCkpIHtcbiAgICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJmdWxsLXdpZHRoXCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgICBTcGFya2xpbmUgcGVyaW9kXG4gICAgICAgICAgICAgICAgICA8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgIDxtYXQtc2VsZWN0XG4gICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwic3BhcmtsaW5lR3JhbnVsYXJpdHkoKVwiXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3BhcmtsaW5lR3JhbnVsYXJpdHkuc2V0KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgIG5hbWU9XCJzcGFya2xpbmVHcmFudWxhcml0eVwiPlxuICAgICAgICAgICAgICAgICAgICBAZm9yIChvcHRpb24gb2YgZ3JhbnVsYXJpdHlPcHRpb25zOyB0cmFjayBvcHRpb24udmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICA8bWF0LW9wdGlvbiBbdmFsdWVdPVwib3B0aW9uLnZhbHVlXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICB7eyBvcHRpb24ubmFtZSB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvbWF0LW9wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgPC9tYXQtc2VsZWN0PlxuICAgICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiZnVsbC13aWR0aFwiPlxuICAgICAgICAgICAgICAgICAgPG1hdC1sYWJlbD5cbiAgICAgICAgICAgICAgICAgICAgU3BhcmtsaW5lIHBlcmlvZHNcbiAgICAgICAgICAgICAgICAgIDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgICAgICAgIGZzTWFza051bWJlclxuICAgICAgICAgICAgICAgICAgICBbc2NhbGVdPVwiMFwiXG4gICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInNwYXJrbGluZVBlcmlvZHMoKVwiXG4gICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInNwYXJrbGluZVBlcmlvZHMuc2V0KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICBuYW1lPVwic3BhcmtsaW5lUGVyaW9kc1wiXG4gICAgICAgICAgICAgICAgICAgIFtmc0Zvcm1SZXF1aXJlZF09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgICAgW2ZzRm9ybUludGVnZXJdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgICAgIFtmc0Zvcm1NaW5dPVwic3BhcmtsaW5lTWluUGVyaW9kc1wiXG4gICAgICAgICAgICAgICAgICAgIFtmc0Zvcm1NYXhdPVwic3BhcmtsaW5lTWF4UGVyaW9kc1wiPlxuICAgICAgICAgICAgICAgICAgPG1hdC1oaW50PlxuICAgICAgICAgICAgICAgICAgICBIb3cgbWFueSBwZXJpb2RzIHRoZSBsaW5lIGNvdmVycywge3sgc3BhcmtsaW5lTWluUGVyaW9kcyB9fSB0byB7eyBzcGFya2xpbmVNYXhQZXJpb2RzIH19LlxuICAgICAgICAgICAgICAgICAgPC9tYXQtaGludD5cbiAgICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbWF0LXRhYj5cbiAgICAgICAgPCEtLSBBIGZvcm11bGEgcnVucyBubyBzdGF0ZW1lbnQgYW5kIGZvbGxvd3MgdGhlIGZpbHRlcnMgb2YgdGhlIHZhbHVlc1xuICAgICAgICAgICAgIGl0IHJlYWRzLCBzbyBpdCBoYXMgbmVpdGhlciBhIEZpbHRlcnMgbm9yIGFuIFNRTCB0YWIuIC0tPlxuICAgICAgICBAaWYgKCFpc0Zvcm11bGEoKSkge1xuICAgICAgICAgIDxtYXQtdGFiXG4gICAgICAgICAgICAgIGxhYmVsPVwiRmlsdGVyc1wiXG4gICAgICAgICAgICAgIG5hbWU9XCJmaWx0ZXJzXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwidGFiLWJvZHlcIj5cbiAgICAgICAgICAgICAgQGlmIChjb2x1bW5zRXJyb3IoKSkge1xuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWx0ZXJzLWVtcHR5IGVycm9yXCI+XG4gICAgICAgICAgICAgICAgICB7eyBjb2x1bW5zRXJyb3IoKSB9fVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICB9IEBlbHNlIGlmIChyb3dzKCkubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgPCEtLSBFdmVyeSBmaWx0ZXJhYmxlIGNvbHVtbi4gUGljayB3aGVyZSBpdHMgY29udHJvbCBzaG93czogaW5cbiAgICAgICAgICAgICAgICAgICAgIHRoZSByZXBvcnQgYmFyIChldmVyeSBwYWdlLCBvciB0aGlzIHBhZ2Ugb25seSksIG9uIHRoaXNcbiAgICAgICAgICAgICAgICAgICAgIGNvbXBvbmVudCwgYm90aCwgb3IgbmVpdGhlci4gVGhlIGludGVyZmFjZSBmb2xsb3dzIHRoZVxuICAgICAgICAgICAgICAgICAgICAgZGF0YTsgYSBudW1lcmljIGNvbHVtbiBjYW4gYmUgdmFsdWVzIG9yIGEgbnVtYmVyIHJhbmdlLlxuICAgICAgICAgICAgICAgICAgICAgQSB2YWx1ZSBzaXRzIGluc2lkZSB0ZXh0IGFuZCBoYXMgbm8gY29tcG9uZW50IHRvIHNob3cgYVxuICAgICAgICAgICAgICAgICAgICAgY29udHJvbCBvbiwgc28gaXQgZ2V0cyB0aGUgcmVwb3J0IGJhciBjb2x1bW4gb25seS4gLS0+XG4gICAgICAgICAgICAgICAgPHRhYmxlIGNsYXNzPVwiZmlsdGVyLXRhYmxlXCI+XG4gICAgICAgICAgICAgICAgICA8dGhlYWQ+XG4gICAgICAgICAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgICAgICAgICA8dGggY2xhc3M9XCJmaWx0ZXItY29sLW5hbWVcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIEZpbHRlclxuICAgICAgICAgICAgICAgICAgICAgIDwvdGg+XG4gICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzPVwiZmlsdGVyLWNvbC10eXBlXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICBUeXBlXG4gICAgICAgICAgICAgICAgICAgICAgPC90aD5cbiAgICAgICAgICAgICAgICAgICAgICA8dGggY2xhc3M9XCJmaWx0ZXItY29sLXNlbGVjdFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgUmVwb3J0IGJhclxuICAgICAgICAgICAgICAgICAgICAgIDwvdGg+XG4gICAgICAgICAgICAgICAgICAgICAgQGlmICghaXNWYWx1ZSgpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8dGggY2xhc3M9XCJmaWx0ZXItY29sLXRvZ2dsZVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICBUaGlzIGNvbXBvbmVudFxuICAgICAgICAgICAgICAgICAgICAgICAgPC90aD5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgICAgICAgICA8L3RoZWFkPlxuICAgICAgICAgICAgICAgICAgPHRib2R5PlxuICAgICAgICAgICAgICAgICAgICBAZm9yIChyb3cgb2Ygcm93cygpOyB0cmFjayByb3cuY29sdW1uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZmlsdGVyLWNvbC1uYW1lXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHt7IHJvdy5sYWJlbCB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZpbHRlci1jb2wtdHlwZVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICBAaWYgKHJvdy50eXBlU2VsZWN0LnNob3cpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3N1YnNjcmlwdFNpemluZ109XCInZHluYW1pYydcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbWF0VG9vbHRpcF09XCJyb3cudHlwZVNlbGVjdC50b29sdGlwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bWF0LXNlbGVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtwYW5lbFdpZHRoXT1cIm51bGxcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvdy50eXBlXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzZXRUeXBlKHJvdywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxPcHRpb25zXT1cInsgc3RhbmRhbG9uZTogdHJ1ZSB9XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwicm93LnR5cGVTZWxlY3QuZGlzYWJsZWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyaWEtbGFiZWw9XCJUeXBlXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEBmb3IgKG9wdGlvbiBvZiB0eXBlT3B0aW9uczsgdHJhY2sgb3B0aW9uLnZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG1hdC1vcHRpb24gW3ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3sgb3B0aW9uLm5hbWUgfX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L21hdC1vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvbWF0LXNlbGVjdD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7eyB0eXBlTGFiZWwocm93LnR5cGUpIH19XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJmaWx0ZXItY29sLXNlbGVjdFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgW3N1YnNjcmlwdFNpemluZ109XCInZHluYW1pYydcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bWF0LXNlbGVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbcGFuZWxXaWR0aF09XCJudWxsXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwicm93LnBsYWNlbWVudFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInNldFBsYWNlbWVudChyb3csICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbE9wdGlvbnNdPVwieyBzdGFuZGFsb25lOiB0cnVlIH1cIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmlhLWxhYmVsPVwiUmVwb3J0IGJhclwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQGZvciAob3B0aW9uIG9mIHJvdy5wbGFjZW1lbnRPcHRpb25zOyB0cmFjayBvcHRpb24udmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG1hdC1vcHRpb24gW3ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7IG9wdGlvbi5uYW1lIH19XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvbWF0LW9wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L21hdC1zZWxlY3Q+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICAgICAgICAgICAgQGlmICghaXNWYWx1ZSgpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZpbHRlci1jb2wtdG9nZ2xlXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPG1hdC1zbGlkZS10b2dnbGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvdy5jb21wb25lbnRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic2V0Q29tcG9uZW50KHJvdywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbE9wdGlvbnNdPVwieyBzdGFuZGFsb25lOiB0cnVlIH1cIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cInJvdy5jb21wb25lbnRUb2dnbGUuZGlzYWJsZWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW21hdFRvb2x0aXBdPVwicm93LmNvbXBvbmVudFRvZ2dsZS50b29sdGlwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9tYXQtc2xpZGUtdG9nZ2xlPlxuICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDwvdGJvZHk+XG4gICAgICAgICAgICAgICAgPC90YWJsZT5cbiAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpbHRlcnMtZW1wdHlcIj5cbiAgICAgICAgICAgICAgICAgIFRoaXMgY29tcG9uZW50IGhhcyBubyBmaWx0ZXJhYmxlIGNvbHVtbnMgeWV0IOKAlCBnaXZlIGl0IHNvbWUgU1FMIGZpcnN0LlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L21hdC10YWI+XG4gICAgICAgICAgPG1hdC10YWJcbiAgICAgICAgICAgICAgbGFiZWw9XCJTUUxcIlxuICAgICAgICAgICAgICBuYW1lPVwic3FsXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwidGFiLWJvZHlcIj5cbiAgICAgICAgICAgICAgQGlmIChzcWxFcnJvcigpKSB7XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpbHRlcnMtZW1wdHkgZXJyb3JcIj5cbiAgICAgICAgICAgICAgICAgIHt7IHNxbEVycm9yKCkgfX1cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgfSBAZWxzZSBpZiAoc3FsKCkpIHtcbiAgICAgICAgICAgICAgICBAaWYgKHNxbEJhc2VsaW5lKCkpIHtcbiAgICAgICAgICAgICAgICAgIDwhLS0gQSBkZXJpdmVkIGNvbXBvbmVudCdzIHN0YXRlbWVudCBpcyBjb21waWxlZCBmcm9tIGl0c1xuICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudCB3aXRoIG5vIHZpZXdlciBzdGF0ZSwgc28gaXQgaXMgbm90IGJ5dGUtZm9yLWJ5dGVcbiAgICAgICAgICAgICAgICAgICAgICAgd2hhdCBwcm9kdWNlZCB0aGUgbnVtYmVycyBvbiBzY3JlZW4uIFNhaWQgaGVyZSByYXRoZXIgdGhhblxuICAgICAgICAgICAgICAgICAgICAgICBsZWZ0IGZvciB0aGUgcmVhZGVyIHRvIGRpc2NvdmVyLiAtLT5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWx0ZXJzLWVtcHR5XCI+XG4gICAgICAgICAgICAgICAgICAgIENvbXBpbGVkIGZyb20gdGhpcyBjb21wb25lbnQncyBxdWVyeSDigJQgbm8gZmlsdGVycyBhcHBsaWVkLCB0aW1lcyBpbiB7eyBzcWxUaW1lem9uZSgpIH19LlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJjb2RlLWJsb2NrXCI+e3sgc3FsKCkgfX08L3ByZT5cbiAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpbHRlcnMtZW1wdHlcIj5cbiAgICAgICAgICAgICAgICAgIFRoaXMgY29tcG9uZW50IGhhcyBubyBTUUwgeWV0LlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L21hdC10YWI+XG4gICAgICAgIH1cbiAgICAgICAgPG1hdC10YWJcbiAgICAgICAgICAgIGxhYmVsPVwiQ29uZmlnXCJcbiAgICAgICAgICAgIG5hbWU9XCJjb25maWdcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwidGFiLWJvZHlcIj5cbiAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJjb2RlLWJsb2NrXCI+XG4gICAgICAgICAgICAgIHt7IGNvbmZpZ0pzb24gfX1cbiAgICAgICAgICAgIDwvcHJlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L21hdC10YWI+XG4gICAgICA8L21hdC10YWItZ3JvdXA+XG4gICAgPC9tYXQtZGlhbG9nLWNvbnRlbnQ+XG4gICAgPG1hdC1kaWFsb2ctYWN0aW9ucz5cbiAgICAgIDwhLS0gU2F2ZSB8IERlbGV0ZSB8IENhbmNlbCwgdGhlIHN0YW5kYXJkIG9yZGVyLiBmcy1mb3JtLWRpYWxvZy1hY3Rpb25zXG4gICAgICAgICAgIHJlbmRlcnMgaXRzIG93biBTYXZlL0RvbmUgQkVGT1JFIHRoZSBwcm9qZWN0ZWQgY29udGVudCwgd2hpY2ggd291bGRcbiAgICAgICAgICAgcHV0IERlbGV0ZSBhZnRlciBDYW5jZWwsIHNvIGBbc2F2ZV09XCJmYWxzZVwiYCBmb290cyB0aGUgcm93IGhlcmUgYW5kXG4gICAgICAgICAgIGFsbCB0aHJlZSBidXR0b25zIGFyZSBwcm9qZWN0ZWQgaW4gb3JkZXIuIFNhdmUgc3VibWl0cyB0aGUgU2V0dGluZ3NcbiAgICAgICAgICAgdGFiOyB0aGUgb3RoZXIgdGFicyBwZXJzaXN0IGFzIHlvdSB0b3VjaCB0aGVtLCBzbyB0aGV5IGdldCBEb25lLiAtLT5cbiAgICAgIDxmcy1mb3JtLWRpYWxvZy1hY3Rpb25zIFtzYXZlXT1cImZhbHNlXCI+XG4gICAgICAgIEBpZiAoc2VsZWN0ZWRUYWIgPT09ICdzZXR0aW5ncycpIHtcbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cInN1Ym1pdFwiXG4gICAgICAgICAgICAgIGNvbG9yPVwicHJpbWFyeVwiPlxuICAgICAgICAgICAgU2F2ZVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGNvbG9yPVwicHJpbWFyeVwiXG4gICAgICAgICAgICAgIFttYXQtZGlhbG9nLWNsb3NlXT1cIm51bGxcIj5cbiAgICAgICAgICAgIERvbmVcbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBtYXQtYnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNvbG9yPVwid2FyblwiXG4gICAgICAgICAgICAoY2xpY2spPVwiZGVsZXRlKClcIj5cbiAgICAgICAgICBEZWxldGVcbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJjYW5jZWwtYnV0dG9uXCJcbiAgICAgICAgICAgIFttYXQtZGlhbG9nLWNsb3NlXT1cIm51bGxcIj5cbiAgICAgICAgICBDYW5jZWxcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2ZzLWZvcm0tZGlhbG9nLWFjdGlvbnM+XG4gICAgPC9tYXQtZGlhbG9nLWFjdGlvbnM+XG4gIDwvZnMtZGlhbG9nPlxuPC9mb3JtPiJdfQ==