obsidian-integration-testing 16.0.0 → 17.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/lib/cjs/adb.cjs +2 -2
  2. package/dist/lib/cjs/adb.d.cts +10 -0
  3. package/dist/lib/cjs/avd-name-channel.cjs +74 -0
  4. package/dist/lib/cjs/avd-name-channel.d.cts +152 -0
  5. package/dist/lib/cjs/avd-probe-verdict.cjs +11 -4
  6. package/dist/lib/cjs/avd-probe-verdict.d.cts +7 -0
  7. package/dist/lib/cjs/device-screenshot.cjs +1 -1
  8. package/dist/lib/cjs/device-screenshot.d.cts +3 -1
  9. package/dist/lib/cjs/emulator-backend.cjs +22 -1
  10. package/dist/lib/cjs/emulator-backend.d.cts +81 -0
  11. package/dist/lib/cjs/emulator-reclaim.cjs +78 -34
  12. package/dist/lib/cjs/emulator-reclaim.d.cts +57 -9
  13. package/dist/lib/cjs/enable-plugin.cjs +17 -8
  14. package/dist/lib/cjs/enable-plugin.d.cts +3 -1
  15. package/dist/lib/cjs/eval-in-obsidian.cjs +1 -1
  16. package/dist/lib/cjs/eval-in-obsidian.d.cts +12 -0
  17. package/dist/lib/cjs/host-process-query-verdict.cjs +103 -0
  18. package/dist/lib/cjs/host-process-query-verdict.d.cts +196 -0
  19. package/dist/lib/cjs/index.cjs +14 -1
  20. package/dist/lib/cjs/index.d.cts +3 -1
  21. package/dist/lib/cjs/launched-device-selection.cjs +46 -0
  22. package/dist/lib/cjs/launched-device-selection.d.cts +112 -0
  23. package/dist/lib/cjs/library.cjs +1 -1
  24. package/dist/lib/cjs/namespace-bootstrap.cjs +62 -1
  25. package/dist/lib/cjs/paint-out-status-bar.cjs +170 -0
  26. package/dist/lib/cjs/paint-out-status-bar.d.cts +236 -0
  27. package/dist/lib/cjs/port-owner-query-verdict.cjs +94 -0
  28. package/dist/lib/cjs/port-owner-query-verdict.d.cts +161 -0
  29. package/dist/lib/cjs/resolve-emulator-device-id.cjs +27 -4
  30. package/dist/lib/cjs/sharp-loader.cjs +1 -1
  31. package/dist/lib/cjs/sharp-loader.d.cts +67 -2
  32. package/dist/lib/cjs/soft-keyboard-geometry.cjs +12 -2
  33. package/dist/lib/cjs/soft-keyboard-geometry.d.cts +17 -2
  34. package/dist/lib/cjs/soft-keyboard.cjs +130 -28
  35. package/dist/lib/cjs/soft-keyboard.d.cts +65 -6
  36. package/dist/lib/cjs/transport-appium.cjs +74 -4
  37. package/dist/lib/cjs/transport-appium.d.cts +49 -2
  38. package/dist/lib/cjs/transport-factory.cjs +162 -42
  39. package/dist/lib/esm/adb.d.mts +10 -0
  40. package/dist/lib/esm/adb.mjs +2 -2
  41. package/dist/lib/esm/avd-name-channel.d.mts +152 -0
  42. package/dist/lib/esm/avd-name-channel.mjs +45 -0
  43. package/dist/lib/esm/avd-probe-verdict.d.mts +7 -0
  44. package/dist/lib/esm/avd-probe-verdict.mjs +15 -4
  45. package/dist/lib/esm/device-screenshot.d.mts +3 -1
  46. package/dist/lib/esm/device-screenshot.mjs +1 -1
  47. package/dist/lib/esm/emulator-backend.d.mts +81 -0
  48. package/dist/lib/esm/emulator-backend.mjs +19 -1
  49. package/dist/lib/esm/emulator-reclaim.d.mts +57 -9
  50. package/dist/lib/esm/emulator-reclaim.mjs +84 -36
  51. package/dist/lib/esm/enable-plugin.d.mts +3 -1
  52. package/dist/lib/esm/enable-plugin.mjs +17 -8
  53. package/dist/lib/esm/eval-in-obsidian.d.mts +12 -0
  54. package/dist/lib/esm/eval-in-obsidian.mjs +1 -1
  55. package/dist/lib/esm/host-process-query-verdict.d.mts +196 -0
  56. package/dist/lib/esm/host-process-query-verdict.mjs +74 -0
  57. package/dist/lib/esm/index.d.mts +3 -1
  58. package/dist/lib/esm/index.mjs +15 -1
  59. package/dist/lib/esm/launched-device-selection.d.mts +112 -0
  60. package/dist/lib/esm/launched-device-selection.mjs +21 -0
  61. package/dist/lib/esm/library.mjs +1 -1
  62. package/dist/lib/esm/namespace-bootstrap.mjs +62 -1
  63. package/dist/lib/esm/paint-out-status-bar.d.mts +236 -0
  64. package/dist/lib/esm/paint-out-status-bar.mjs +142 -0
  65. package/dist/lib/esm/port-owner-query-verdict.d.mts +161 -0
  66. package/dist/lib/esm/port-owner-query-verdict.mjs +73 -0
  67. package/dist/lib/esm/resolve-emulator-device-id.mjs +32 -4
  68. package/dist/lib/esm/sharp-loader.d.mts +67 -2
  69. package/dist/lib/esm/sharp-loader.mjs +1 -1
  70. package/dist/lib/esm/soft-keyboard-geometry.d.mts +17 -2
  71. package/dist/lib/esm/soft-keyboard-geometry.mjs +11 -2
  72. package/dist/lib/esm/soft-keyboard.d.mts +65 -6
  73. package/dist/lib/esm/soft-keyboard.mjs +131 -28
  74. package/dist/lib/esm/transport-appium.d.mts +49 -2
  75. package/dist/lib/esm/transport-appium.mjs +74 -4
  76. package/dist/lib/esm/transport-factory.mjs +176 -44
  77. package/package.json +1 -1
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var paint_out_status_bar_exports = {};
20
+ __export(paint_out_status_bar_exports, {
21
+ DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS: () => DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS,
22
+ DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS: () => DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS,
23
+ buildStatusBarBandFailureMessage: () => buildStatusBarBandFailureMessage,
24
+ paintOutStatusBar: () => paintOutStatusBar,
25
+ resolveStatusBarBand: () => resolveStatusBarBand
26
+ });
27
+ module.exports = __toCommonJS(paint_out_status_bar_exports);
28
+ var import_sharp_loader = require("./sharp-loader.cjs");
29
+ const DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS = 100;
30
+ const DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS = 4;
31
+ const BLUE_CHANNEL_OFFSET = 2;
32
+ const FILL_CHANNEL_COUNT = 3;
33
+ const GREEN_CHANNEL_OFFSET = 1;
34
+ const MINIMUM_SCANNED_COLUMN_COUNT = 2;
35
+ const RED_CHANNEL_OFFSET = 0;
36
+ function buildStatusBarBandFailureMessage(params) {
37
+ const {
38
+ edgeMarginInPixels,
39
+ heightInPixels,
40
+ verdict,
41
+ widthInPixels
42
+ } = params;
43
+ const lines = [
44
+ `paintOutStatusBar: the row under the status bar holds more than one color, so a band of ${String(heightInPixels)}px would paint over the app rather than over the device.`,
45
+ `band=${String(heightInPixels)}px sampleRow=y${String(verdict.sampleRowYInPixels)} scanned x${String(edgeMarginInPixels)}..${String(widthInPixels - edgeMarginInPixels)} of ${String(widthInPixels)}px distinctColors=${String(verdict.distinctColorCount)}`,
46
+ `sampled ${formatColor(verdict.backgroundColor)}, but x=${String(verdict.firstDifferentColumnXInPixels)} is ${formatColor(verdict.firstDifferentColor)}`,
47
+ "A taller status bar, or an Obsidian that draws higher, both look like this. Measure the band on a fresh frame and pass the height you measured: enlarging it until the check passes is how a capture paints over the product."
48
+ ];
49
+ return lines.join("\n");
50
+ }
51
+ async function paintOutStatusBar(bytes, options) {
52
+ const { heightInPixels } = options;
53
+ const edgeMarginInPixels = options.edgeMarginInPixels ?? DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS;
54
+ const sharp = await (0, import_sharp_loader.importSharp)("paintOutStatusBar");
55
+ const { data, info } = await sharp(bytes).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
56
+ if (heightInPixels >= info.height) {
57
+ throw new Error(
58
+ `paintOutStatusBar: a band of ${String(heightInPixels)}px would cover a frame that is only ${String(info.height)}px tall. That is a measurement of some other device, not of this frame.`
59
+ );
60
+ }
61
+ const verdict = resolveStatusBarBand({
62
+ channelCount: info.channels,
63
+ edgeMarginInPixels,
64
+ heightInPixels,
65
+ pixels: data,
66
+ ...options.sampleInsetInPixels !== void 0 && { sampleInsetInPixels: options.sampleInsetInPixels },
67
+ widthInPixels: info.width
68
+ });
69
+ if (!verdict.isClear) {
70
+ throw new Error(buildStatusBarBandFailureMessage({
71
+ edgeMarginInPixels,
72
+ heightInPixels,
73
+ verdict,
74
+ widthInPixels: info.width
75
+ }));
76
+ }
77
+ const layer = {
78
+ input: {
79
+ create: {
80
+ background: verdict.backgroundColor,
81
+ channels: FILL_CHANNEL_COUNT,
82
+ height: heightInPixels,
83
+ width: info.width
84
+ }
85
+ },
86
+ left: 0,
87
+ top: 0
88
+ };
89
+ const painted = await sharp(bytes).composite([layer]).png().toBuffer();
90
+ return new Uint8Array(painted);
91
+ }
92
+ function resolveStatusBarBand(params) {
93
+ const {
94
+ channelCount,
95
+ heightInPixels,
96
+ pixels,
97
+ widthInPixels
98
+ } = params;
99
+ const edgeMarginInPixels = params.edgeMarginInPixels ?? DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS;
100
+ const sampleInsetInPixels = params.sampleInsetInPixels ?? DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS;
101
+ assertPositive("widthInPixels", widthInPixels);
102
+ assertPositive("heightInPixels", heightInPixels);
103
+ assertPositive("channelCount", channelCount);
104
+ const sampleRowYInPixels = heightInPixels - sampleInsetInPixels;
105
+ if (sampleRowYInPixels < 0) {
106
+ throw new Error(
107
+ `resolveStatusBarBand: a sample inset of ${String(sampleInsetInPixels)}px puts the sample row above the top of the frame for a band of ${String(heightInPixels)}px.`
108
+ );
109
+ }
110
+ const lastScannedColumnXInPixels = widthInPixels - edgeMarginInPixels;
111
+ if (lastScannedColumnXInPixels - edgeMarginInPixels < MINIMUM_SCANNED_COLUMN_COUNT) {
112
+ throw new Error(
113
+ `resolveStatusBarBand: an edge margin of ${String(edgeMarginInPixels)}px leaves fewer than ${String(MINIMUM_SCANNED_COLUMN_COUNT)} columns of a ${String(widthInPixels)}px frame to scan, which is a check that cannot fail.`
114
+ );
115
+ }
116
+ const rowStartOffset = sampleRowYInPixels * widthInPixels * channelCount;
117
+ const requiredLength = rowStartOffset + widthInPixels * channelCount;
118
+ if (pixels.length < requiredLength) {
119
+ throw new Error(
120
+ `resolveStatusBarBand: the frame holds ${String(pixels.length)} bytes, too few for row y${String(sampleRowYInPixels)} of a ${String(widthInPixels)}px-wide frame at ${String(channelCount)} channels, which needs ${String(requiredLength)}.`
121
+ );
122
+ }
123
+ const backgroundColor = readColor(pixels, rowStartOffset + edgeMarginInPixels * channelCount);
124
+ const backgroundKey = formatColor(backgroundColor);
125
+ const colorKeys = /* @__PURE__ */ new Set();
126
+ let firstDifferentColor = null;
127
+ let firstDifferentColumnXInPixels = null;
128
+ for (let x = edgeMarginInPixels; x < lastScannedColumnXInPixels; x++) {
129
+ const color = readColor(pixels, rowStartOffset + x * channelCount);
130
+ const colorKey = formatColor(color);
131
+ colorKeys.add(colorKey);
132
+ if (firstDifferentColumnXInPixels !== null || colorKey === backgroundKey) {
133
+ continue;
134
+ }
135
+ firstDifferentColor = color;
136
+ firstDifferentColumnXInPixels = x;
137
+ }
138
+ return {
139
+ backgroundColor,
140
+ distinctColorCount: colorKeys.size,
141
+ firstDifferentColor,
142
+ firstDifferentColumnXInPixels,
143
+ isClear: colorKeys.size === 1,
144
+ sampleRowYInPixels
145
+ };
146
+ }
147
+ function assertPositive(name, value) {
148
+ if (!Number.isFinite(value) || value <= 0) {
149
+ throw new Error(`resolveStatusBarBand: ${name} must be a positive number, got ${String(value)}.`);
150
+ }
151
+ }
152
+ function formatColor(color) {
153
+ return color === null ? "(none)" : `rgb(${String(color.r)},${String(color.g)},${String(color.b)})`;
154
+ }
155
+ function readColor(pixels, offset) {
156
+ return {
157
+ b: pixels[offset + BLUE_CHANNEL_OFFSET] ?? 0,
158
+ g: pixels[offset + GREEN_CHANNEL_OFFSET] ?? 0,
159
+ r: pixels[offset + RED_CHANNEL_OFFSET] ?? 0
160
+ };
161
+ }
162
+ // Annotate the CommonJS export names for ESM import in node:
163
+ 0 && (module.exports = {
164
+ DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS,
165
+ DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS,
166
+ buildStatusBarBandFailureMessage,
167
+ paintOutStatusBar,
168
+ resolveStatusBarBand
169
+ });
170
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL3BhaW50LW91dC1zdGF0dXMtYmFyLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogUGFpbnRzIHRoZSBkZXZpY2UncyBzdGF0dXMgYmFyIG91dCBvZiBhIGNhcHR1cmVkIGZyYW1lLCBzbyBhIGRldmljZSBjYXB0dXJlXG4gKiBjYW4gYmUgY29tbWl0dGVkLlxuICpcbiAqIEEgZnJhbWVidWZmZXIgY2FycmllcyB0aGUgc3RhdHVzIGJhciwgYW5kIGEgc3RhdHVzIGJhciBjYXJyaWVzIGEgd2FsbCBjbG9jaywgYVxuICogYmF0dGVyeSB0aGF0IGNoYXJnZXMgd2hpbGUgdGhlIGVtdWxhdG9yIHJ1bnMgYW5kIGEgcmFkaW8gdGhhdCBjb21lcyBhbmQgZ29lcy5cbiAqIFNvIHJlLXJ1bm5pbmcgYSBjYXB0dXJlIHN1aXRlIG9uIGFuIHVuY2hhbmdlZCB0cmVlIHJld3JpdGVzIGl0cyBQTkdzIHdpdGhcbiAqIGNvbnRlbnQgbm9ib2R5IGNhbiBjb21taXQsIGFuZCB0aGUgY2h1cm4gaXMgaW52aXNpYmxlIHVudGlsIHNvbWVvbmUgZGlmZnMgdHdvXG4gKiBydW5zLiBgZGV2aWNlLXNjcmVlbnNob3RgJ3MgaGVhZGVyIGhhcyBhbHdheXMgc2FpZCBhIGRldmljZSBjYXB0dXJlIGlzIG5vdFxuICogYnl0ZS1yZXByb2R1Y2libGU7IHRoaXMgaXMgd2hhdCBtYWtlcyBvbmUuXG4gKlxuICogKipQaW5uaW5nIHRoZSBiYXIgd2FzIHRyaWVkIGZpcnN0LCBhbmQgaXMgTk9UIHN1ZmZpY2llbnQgXHUyMDE0IHRoYXQgZmluZGluZyBpcyB0aGVcbiAqIHJlYXNvbiB0aGlzIGhlbHBlciBleGlzdHMgcmF0aGVyIHRoYW4gYSBgd2l0aFN5c3RlbVVpRGVtb01vZGVgIG9uZS4qKiBTeXN0ZW1VSVxuICogZGVtbyBtb2RlIChgc3lzdWlfZGVtb19hbGxvd2VkYCwgcGx1cyBvbmUgYGNvbS5hbmRyb2lkLnN5c3RlbXVpLmRlbW9gXG4gKiBicm9hZGNhc3QgcGVyIGFyZWE6IGNsb2NrIGF0IGEgZml4ZWQgYGhobW1gLCBiYXR0ZXJ5IGZ1bGwgYW5kIHVucGx1Z2dlZCxcbiAqIHJhZGlvcyBoaWRkZW4sIG5vdGlmaWNhdGlvbiBpY29ucyBvZmYpIGhlbGQgdGhlIGNsb2NrIGF0IGAxMjowMGAgYW5kIHR3byBydW5zXG4gKiBzdGlsbCBkaXNhZ3JlZWQgb24gKioxODIzIGZ1bGwtY29udHJhc3QgcGl4ZWxzKiosIGJlY2F1c2UgdGhlIGJhcidzIGxlYWRpbmdcbiAqIGdyb3VwIGlzIGxhaWQgb3V0IGF0IGEgZGlmZmVyZW50IG9mZnNldCBiZXR3ZWVuIGVtdWxhdG9yIGJvb3RzIFx1MjAxNFxuICogaW50ZXJtaXR0ZW50bHksIHJvdWdobHkgb25lIGJvb3QgaW4gZm91ci4gVGhlIFR1bmVyJ3MgYGljb25fYmxhY2tsaXN0YCBkb2VzXG4gKiBub3QgaGVscCBlaXRoZXI6IGRlbW8gbW9kZSBkcmF3cyBpdHMgb3duIGljb24gbGF5ZXIgYW5kIGlnbm9yZXMgaXQuIE1lYXN1cmVkXG4gKiBvbiBhIHJlYWwgQVZEIGFjcm9zcyBmaXZlIHBhaXJlZCBjYXB0dXJlIHJ1bnMgZm9yIGBvYnNpZGlhbi1saW5rLXBpY2tlcmAnc1xuICogc3RvcmUgZnJhbWVzLCB3aGljaCBpcyB3aGVyZSB0aGlzIHJlY2lwZSB3YXMgd29ya2VkIG91dCBiZWZvcmUgaXQgbW92ZWQgaGVyZS5cbiAqXG4gKiBSZW1vdmluZyB0aGUgYmFuZCByYXRoZXIgdGhhbiBwaW5uaW5nIGl0IGFsc28gcmV0aXJlcyBldmVyeSBkZXZpY2Ugc2V0dGluZ1xuICogdGhhdCBwaW5uaW5nIG5lZWRlZCwgYW5kIG5vdGhpbmcgaW4gYSBzdGF0dXMgYmFyIGlzIGV2aWRlbmNlIGFib3V0IGEgcGx1Z2luLiBBXG4gKiBsaXN0aW5nIGZyYW1lIHdpdGhvdXQgb25lIGlzIHdoYXQgYSBsaXN0aW5nIGZyYW1lIG5vcm1hbGx5IGxvb2tzIGxpa2UuXG4gKlxuICogKipUaGUgYmFuZCdzIGhlaWdodCBpcyB0aGUgY2FsbGVyJ3MgdG8gbWVhc3VyZSwgYW5kIHRoZXJlIGlzIGRlbGliZXJhdGVseSBub1xuICogZGVmYXVsdC4qKiBBIHdyb25nIGhlaWdodCBkb2VzIG5vdCBmYWlsIGxvdWRseSBieSBpdHNlbGYgXHUyMDE0IGl0IHBhaW50cyBvdmVyIHRoZVxuICogcHJvZHVjdC4gV2hhdCBzdGFuZHMgYmV0d2VlbiB0aGUgdHdvIGlzIHtAbGluayByZXNvbHZlU3RhdHVzQmFyQmFuZH06IHRoZSByb3dcbiAqIGp1c3QgdW5kZXIgdGhlIGJhcidzIG93biBjb250ZW50IG11c3QgYmUgb25lIGZsYXQgY29sb3IgYWxsIHRoZSB3YXkgYWNyb3NzLFxuICogd2hpY2ggaXMgd2hhdCBhbiBlbXB0eSBiYW5kIGxvb2tzIGxpa2UgYW5kIGlzIGFsc28gd2hlcmUgdGhlIGZpbGwgY29sb3IgaXNcbiAqIHNhbXBsZWQgZnJvbS4gQSB0YWxsZXIgYmFyLCBvciBhbiBPYnNpZGlhbiB0aGF0IGRyYXdzIGhpZ2hlciwgZmFpbHMgdGhlXG4gKiBjYXB0dXJlIGluc3RlYWQuXG4gKlxuICogQ29tcG9zaXRpbmcgb3ZlciBhIGNhcHR1cmVkIGZyYW1lIGlzIG5vdCBhIG5ldyBsaWJlcnR5OiBgbGFiZWxTY3JlZW5zaG90YFxuICogYWxyZWFkeSBkcmF3cyB0aGUgY2FwdGlvbiBiYW5kIGFjcm9zcyB0aGUgYm90dG9tIG9mIHRoZSBzYW1lIGltYWdlLlxuICovXG5cbmltcG9ydCB0eXBlIHsgU2hhcnBDb21wb3NpdGVMYXllciB9IGZyb20gJy4vc2hhcnAtbG9hZGVyLmNqcyc7XG5cbmltcG9ydCB7IGltcG9ydFNoYXJwIH0gZnJvbSAnLi9zaGFycC1sb2FkZXIuY2pzJztcblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciB7QGxpbmsgYnVpbGRTdGF0dXNCYXJCYW5kRmFpbHVyZU1lc3NhZ2V9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkU3RhdHVzQmFyQmFuZEZhaWx1cmVNZXNzYWdlUGFyYW1zIHtcbiAgLyoqXG4gICAqIEhvdyBmYXIgaW4gZnJvbSBlYWNoIGVkZ2UgdGhlIHJvdyB3YXMgc2Nhbm5lZCwgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgZWRnZU1hcmdpbkluUGl4ZWxzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBoZWlnaHQgb2YgdGhlIGJhbmQgdGhhdCB3YXMgYWJvdXQgdG8gYmUgcGFpbnRlZCwgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgaGVpZ2h0SW5QaXhlbHM6IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIHZlcmRpY3QgYmVpbmcgcmVwb3J0ZWQuXG4gICAqL1xuICByZWFkb25seSB2ZXJkaWN0OiBTdGF0dXNCYXJCYW5kVmVyZGljdDtcblxuICAvKipcbiAgICogVGhlIGZyYW1lJ3Mgd2lkdGgsIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IHdpZHRoSW5QaXhlbHM6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciB7QGxpbmsgcGFpbnRPdXRTdGF0dXNCYXJ9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBhaW50T3V0U3RhdHVzQmFyT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBIb3cgZmFyIGluIGZyb20gZWFjaCBlZGdlIHRoZSBjbGVhci1vZi1jaHJvbWUgY2hlY2sgcmVhZHMuXG4gICAqXG4gICAqIEBkZWZhdWx0IHtAbGluayBERUZBVUxUX1NUQVRVU19CQVJfRURHRV9NQVJHSU5fSU5fUElYRUxTfVxuICAgKi9cbiAgcmVhZG9ubHkgZWRnZU1hcmdpbkluUGl4ZWxzPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBIb3cgdGFsbCB0aGUgZGV2aWNlJ3Mgc3RhdHVzIGJhciBpcywgaW4gZnJhbWVidWZmZXIgcGl4ZWxzLlxuICAgKlxuICAgKiAqKk1lYXN1cmVkLCBuZXZlciBhc3N1bWVkLCBhbmQgZGVsaWJlcmF0ZWx5IHdpdGhvdXQgYSBkZWZhdWx0LioqIDI0ZHAgYXQgYVxuICAgKiBkZW5zaXR5IG9mIDMyMCBpcyA0OHB4LCBhbmQgdGhhdCBpcyBvbmUgQVZEJ3MgbnVtYmVyIHJhdGhlciB0aGFuIGEgY29uc3RhbnRcbiAgICogb2YgQW5kcm9pZC4gTWVhc3VyZSBpdCBvbiBhIGZyYW1lOiB0aGUgYmFyJ3Mgb3duIGNvbnRlbnQgb2NjdXBpZXMgdGhlIHRvcFxuICAgKiByb3dzLCBhIGZldyBlbXB0eSByb3dzIGZvbGxvdywgYW5kIHRoZSBhcHAncyB0b3AgY2hyb21lIHN0YXJ0cyBhdCBleGFjdGx5XG4gICAqIHRoaXMgb2Zmc2V0LlxuICAgKi9cbiAgcmVhZG9ubHkgaGVpZ2h0SW5QaXhlbHM6IG51bWJlcjtcblxuICAvKipcbiAgICogSG93IGZhciBhYm92ZSB0aGUgYmFuZCdzIGJvdHRvbSBlZGdlIHRoZSBmaWxsIGNvbG9yIGlzIHNhbXBsZWQsIGluIHBpeGVscy5cbiAgICpcbiAgICogQGRlZmF1bHQge0BsaW5rIERFRkFVTFRfU1RBVFVTX0JBUl9TQU1QTEVfSU5TRVRfSU5fUElYRUxTfVxuICAgKi9cbiAgcmVhZG9ubHkgc2FtcGxlSW5zZXRJblBpeGVscz86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciB7QGxpbmsgcmVzb2x2ZVN0YXR1c0JhckJhbmR9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVTdGF0dXNCYXJCYW5kUGFyYW1zIHtcbiAgLyoqXG4gICAqIEhvdyBtYW55IGJ5dGVzIGVhY2ggcGl4ZWwgb2NjdXBpZXMgaW4ge0BsaW5rIFJlc29sdmVTdGF0dXNCYXJCYW5kUGFyYW1zLnBpeGVsc30gXHUyMDE0IDMgZm9yIFJHQiwgNCBmb3IgUkdCQS5cbiAgICovXG4gIHJlYWRvbmx5IGNoYW5uZWxDb3VudDogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBIb3cgZmFyIGluIGZyb20gZWFjaCBlZGdlIHRvIHN0YXJ0IHJlYWRpbmcsIGluIHBpeGVscy5cbiAgICpcbiAgICogQSBkZXZpY2UncyByb3VuZGVkIGNvcm5lcnMgZGFya2VuIGEgaGFuZGZ1bCBvZiBwaXhlbHMgYXQgYm90aCBlbmRzIG9mIGV2ZXJ5XG4gICAqIHJvdyBpbiB0aGUgYmFuZCwgY29uc3RhbnRseSBhbmQgaGFybWxlc3NseTsgdGhlIGNoZWNrIGlzIGFib3V0IHdoYXQgdGhlIEFQUFxuICAgKiBkcmF3cywgc28gaXQgaWdub3JlcyB0aGVtLlxuICAgKlxuICAgKiBAZGVmYXVsdCB7QGxpbmsgREVGQVVMVF9TVEFUVVNfQkFSX0VER0VfTUFSR0lOX0lOX1BJWEVMU31cbiAgICovXG4gIHJlYWRvbmx5IGVkZ2VNYXJnaW5JblBpeGVscz86IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIGhlaWdodCBvZiB0aGUgYmFuZCwgaW4gcGl4ZWxzIFx1MjAxNCB0aGUgc2FtZSBudW1iZXIge0BsaW5rIHBhaW50T3V0U3RhdHVzQmFyfSB3b3VsZCBwYWludC5cbiAgICovXG4gIHJlYWRvbmx5IGhlaWdodEluUGl4ZWxzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBmcmFtZSdzIHJhdyBwaXhlbHMsIHJvdy1tYWpvciwgYXMgYHNoYXJwYCdzIGByYXcoKWAgcmVwb3J0cyB0aGVtLlxuICAgKi9cbiAgcmVhZG9ubHkgcGl4ZWxzOiBVaW50OEFycmF5O1xuXG4gIC8qKlxuICAgKiBIb3cgZmFyIGFib3ZlIHRoZSBiYW5kJ3MgYm90dG9tIGVkZ2UgdGhlIHJvdyBpcyByZWFkIGZyb20sIGluIHBpeGVscy5cbiAgICpcbiAgICogVGhlIGJhcidzIG93biBjb250ZW50IHN0b3BzIHNob3J0IG9mIHRoZSBiYW5kJ3MgYm90dG9tIGVkZ2UsIHNvIHRoZSByb3dzXG4gICAqIGltbWVkaWF0ZWx5IHVuZGVyIGl0IGFyZSBlbXB0eTsgdGhpcyBwaWNrcyBvbmUgb2YgdGhlbS5cbiAgICpcbiAgICogQGRlZmF1bHQge0BsaW5rIERFRkFVTFRfU1RBVFVTX0JBUl9TQU1QTEVfSU5TRVRfSU5fUElYRUxTfVxuICAgKi9cbiAgcmVhZG9ubHkgc2FtcGxlSW5zZXRJblBpeGVscz86IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIGZyYW1lJ3Mgd2lkdGgsIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IHdpZHRoSW5QaXhlbHM6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBBIGNvbG9yIHJlYWQgb3V0IG9mIGEgZnJhbWUsIGNoYW5uZWwgYnkgY2hhbm5lbC5cbiAqXG4gKiBUaGlzIHBhY2thZ2UncyBvd24gdHlwZSByYXRoZXIgdGhhbiBgc2hhcnBgJ3MsIGJlY2F1c2UgaXQgaXMgcGFydCBvZiB0aGVcbiAqIHB1YmxpYyBzdXJmYWNlIGFuZCBgc2hhcnBgIGlzIGFuIE9QVElPTkFMIHBlZXI6IGEgY29uc3VtZXIgdGhhdCBuZXZlciBpbnN0YWxsc1xuICogaXQgc3RpbGwgbmFtZXMgdGhpcy4gU3RydWN0dXJhbGx5IHdoYXQgYHNoYXJwYCdzIGBiYWNrZ3JvdW5kYCB0YWtlcywgd2hpY2ggaXNcbiAqIGhvdyB0aGUgZmlsbCBibG9jayBpcyBjcmVhdGVkIGZyb20gb25lIHdpdGggbm8gY29udmVyc2lvbiBpbiBiZXR3ZWVuLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0YXR1c0JhckJhbmRDb2xvciB7XG4gIC8qKlxuICAgKiBUaGUgYmx1ZSBjaGFubmVsLCAwLTI1NS5cbiAgICovXG4gIHJlYWRvbmx5IGI6IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIGdyZWVuIGNoYW5uZWwsIDAtMjU1LlxuICAgKi9cbiAgcmVhZG9ubHkgZzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVkIGNoYW5uZWwsIDAtMjU1LlxuICAgKi9cbiAgcmVhZG9ubHkgcjogbnVtYmVyO1xufVxuXG4vKipcbiAqIFdoYXQgdGhlIHJvdyB1bmRlciB0aGUgc3RhdHVzIGJhcidzIGNvbnRlbnQgdHVybmVkIG91dCB0byBob2xkLlxuICpcbiAqIFZlcmRpY3QtYXMtZGF0YSwgbGlrZSB0aGUgY29tcGF0aWJpbGl0eSBhbmQgdGVhcmRvd24gY2hlY2tzOiB0aGUgcmVhZGluZyBhbmRcbiAqIHRoZSB0aHJvd2luZyBhcmUgc2VwYXJhdGUsIHNvIGEgY2FsbGVyIGNhbiBhc2sgd2hhdCBhIGZyYW1lIGxvb2tzIGxpa2Ugd2l0aG91dFxuICogaGF2aW5nIHRvIGNhdGNoIGFuIGVycm9yIHRvIGZpbmQgb3V0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0YXR1c0JhckJhbmRWZXJkaWN0IHtcbiAgLyoqXG4gICAqIFRoZSBjb2xvciB0aGUgYmFuZCB3b3VsZCBiZSBmaWxsZWQgd2l0aCBcdTIwMTQgcmVhZCBmcm9tIHRoZSBmaXJzdCBzY2FubmVkIGNvbHVtbiBvZiB0aGUgc2FtcGxlIHJvdy5cbiAgICovXG4gIHJlYWRvbmx5IGJhY2tncm91bmRDb2xvcjogU3RhdHVzQmFyQmFuZENvbG9yO1xuXG4gIC8qKlxuICAgKiBIb3cgbWFueSBkaXN0aW5jdCBjb2xvcnMgdGhlIHNjYW5uZWQgcm93IGhvbGRzLiBPbmUgaXMgd2hhdCBhbiBlbXB0eSBiYW5kIGxvb2tzIGxpa2UuXG4gICAqL1xuICByZWFkb25seSBkaXN0aW5jdENvbG9yQ291bnQ6IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIGNvbG9yIGF0IHtAbGluayBTdGF0dXNCYXJCYW5kVmVyZGljdC5maXJzdERpZmZlcmVudENvbHVtblhJblBpeGVsc30sIG9yIGBudWxsYCB3aGVuIHRoZSByb3cgaXMgZmxhdC5cbiAgICovXG4gIHJlYWRvbmx5IGZpcnN0RGlmZmVyZW50Q29sb3I6IG51bGwgfCBTdGF0dXNCYXJCYW5kQ29sb3I7XG5cbiAgLyoqXG4gICAqIFRoZSBmaXJzdCBzY2FubmVkIGNvbHVtbiB0aGF0IGRpZmZlcnMgZnJvbSB7QGxpbmsgU3RhdHVzQmFyQmFuZFZlcmRpY3QuYmFja2dyb3VuZENvbG9yfSwgb3IgYG51bGxgIHdoZW4gdGhlIHJvdyBpcyBmbGF0LlxuICAgKi9cbiAgcmVhZG9ubHkgZmlyc3REaWZmZXJlbnRDb2x1bW5YSW5QaXhlbHM6IG51bGwgfCBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHJvdyBpcyBvbmUgZmxhdCBjb2xvciwgYW5kIHNvIHdoZXRoZXIgdGhlIGJhbmQgaG9sZHMgbm90aGluZyBidXQgZGV2aWNlIGNocm9tZS5cbiAgICovXG4gIHJlYWRvbmx5IGlzQ2xlYXI6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoaWNoIHJvdyB3YXMgcmVhZCwgYXMgYSBkaXN0YW5jZSBmcm9tIHRoZSB0b3Agb2YgdGhlIGZyYW1lIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IHNhbXBsZVJvd1lJblBpeGVsczogbnVtYmVyO1xufVxuXG4vKipcbiAqIEhvdyBmYXIgaW4gZnJvbSBlYWNoIGVkZ2UgdGhlIGNsZWFyLW9mLWNocm9tZSBjaGVjayByZWFkcywgaW4gcGl4ZWxzLlxuICpcbiAqIEV4cG9ydGVkIGJlY2F1c2UgYSBjYWxsZXIgdGlnaHRlbmluZyBvciBsb29zZW5pbmcgaXQgd2FudHMgdG8gc2F5IHNvIHJlbGF0aXZlXG4gKiB0byB0aGlzIHJhdGhlciB0aGFuIGluIHRoZSBhYnN0cmFjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfU1RBVFVTX0JBUl9FREdFX01BUkdJTl9JTl9QSVhFTFMgPSAxMDA7XG5cbi8qKlxuICogSG93IGZhciBhYm92ZSB0aGUgYmFuZCdzIGJvdHRvbSBlZGdlIHRoZSBzYW1wbGUgcm93IHNpdHMsIGluIHBpeGVscy5cbiAqXG4gKiBGb3VyIHJvd3MgdXA6IGZhciBlbm91Z2ggdG8gY2xlYXIgdGhlIGJhcidzIG93biBjb250ZW50LCBjbG9zZSBlbm91Z2ggdG8gc3RpbGxcbiAqIGJlIGluc2lkZSB0aGUgYmFuZCBvbiBldmVyeSBkZXZpY2UgdGhpcyBoYXMgYmVlbiBtZWFzdXJlZCBvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfU1RBVFVTX0JBUl9TQU1QTEVfSU5TRVRfSU5fUElYRUxTID0gNDtcblxuLyoqXG4gKiBCeXRlIG9mZnNldCBvZiB0aGUgYmx1ZSBjaGFubmVsIHdpdGhpbiBvbmUgcGl4ZWwgb2YgYSByYXcgZnJhbWUuXG4gKi9cbmNvbnN0IEJMVUVfQ0hBTk5FTF9PRkZTRVQgPSAyO1xuXG4vKipcbiAqIEhvdyBtYW55IGNoYW5uZWxzIHRoZSBmaWxsIGJsb2NrIGlzIGNyZWF0ZWQgd2l0aCBcdTIwMTQgUkdCLCB3aXRoIG5vIGFscGhhLCBiZWNhdXNlIGl0IGlzIG9wYXF1ZSBieSBjb25zdHJ1Y3Rpb24uXG4gKi9cbmNvbnN0IEZJTExfQ0hBTk5FTF9DT1VOVCA9IDM7XG5cbi8qKlxuICogQnl0ZSBvZmZzZXQgb2YgdGhlIGdyZWVuIGNoYW5uZWwgd2l0aGluIG9uZSBwaXhlbCBvZiBhIHJhdyBmcmFtZS5cbiAqL1xuY29uc3QgR1JFRU5fQ0hBTk5FTF9PRkZTRVQgPSAxO1xuXG4vKipcbiAqIFRoZSBmZXdlc3QgY29sdW1ucyBhIG1lYW5pbmdmdWwgc2NhbiBjYW4gY292ZXIuXG4gKlxuICogT25lIGNvbHVtbiBpcyB0cml2aWFsbHkgZmxhdCwgc28gYSBtYXJnaW4gdGhhdCBsZWF2ZXMgZmV3ZXIgdGhhbiB0d28gaXMgYVxuICogY2hlY2sgdGhhdCBjYW5ub3QgZmFpbCBcdTIwMTQgdGhlIGV4YWN0IHNoYXBlIHRoaXMgaGVscGVyIGV4aXN0cyB0byBhdm9pZC5cbiAqL1xuY29uc3QgTUlOSU1VTV9TQ0FOTkVEX0NPTFVNTl9DT1VOVCA9IDI7XG5cbi8qKlxuICogQnl0ZSBvZmZzZXQgb2YgdGhlIHJlZCBjaGFubmVsIHdpdGhpbiBvbmUgcGl4ZWwgb2YgYSByYXcgZnJhbWUuXG4gKi9cbmNvbnN0IFJFRF9DSEFOTkVMX09GRlNFVCA9IDA7XG5cbi8qKlxuICogQnVpbGRzIHRoZSBtZXNzYWdlIGEgYmFuZCB0aGF0IGlzIG5vdCBjbGVhciBpcyByZWZ1c2VkIHdpdGguXG4gKlxuICogU2VwYXJhdGUgZnJvbSB0aGUgdGhyb3dpbmcgc28gaXQgY2FuIGJlIGFzc2VydGVkIG9uIGRpcmVjdGx5OiB3aGF0IG1ha2VzIHRoaXNcbiAqIGZhaWx1cmUgYWN0aW9uYWJsZSBpcyB0aGUgbWVhc3VyZW1lbnQsIG5vdCB0aGUgd29yZGluZyBhcm91bmQgaXQuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRoZSB2ZXJkaWN0IGFuZCB0aGUgZ2VvbWV0cnkgaXQgd2FzIHJlYWQgd2l0aC5cbiAqIEByZXR1cm5zIFRoZSBtZXNzYWdlLCByZWFkeSB0byB0aHJvdy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkU3RhdHVzQmFyQmFuZEZhaWx1cmVNZXNzYWdlKHBhcmFtczogQnVpbGRTdGF0dXNCYXJCYW5kRmFpbHVyZU1lc3NhZ2VQYXJhbXMpOiBzdHJpbmcge1xuICBjb25zdCB7XG4gICAgZWRnZU1hcmdpbkluUGl4ZWxzLFxuICAgIGhlaWdodEluUGl4ZWxzLFxuICAgIHZlcmRpY3QsXG4gICAgd2lkdGhJblBpeGVsc1xuICB9ID0gcGFyYW1zO1xuXG4gIGNvbnN0IGxpbmVzID0gW1xuICAgICdwYWludE91dFN0YXR1c0JhcjogdGhlIHJvdyB1bmRlciB0aGUgc3RhdHVzIGJhciBob2xkcyBtb3JlIHRoYW4gb25lIGNvbG9yLCBzbyBhIGJhbmQgb2YgJ1xuICAgICsgYCR7U3RyaW5nKGhlaWdodEluUGl4ZWxzKX1weCB3b3VsZCBwYWludCBvdmVyIHRoZSBhcHAgcmF0aGVyIHRoYW4gb3ZlciB0aGUgZGV2aWNlLmAsXG4gICAgYGJhbmQ9JHtTdHJpbmcoaGVpZ2h0SW5QaXhlbHMpfXB4IHNhbXBsZVJvdz15JHtTdHJpbmcodmVyZGljdC5zYW1wbGVSb3dZSW5QaXhlbHMpfSBgXG4gICAgKyBgc2Nhbm5lZCB4JHtTdHJpbmcoZWRnZU1hcmdpbkluUGl4ZWxzKX0uLiR7U3RyaW5nKHdpZHRoSW5QaXhlbHMgLSBlZGdlTWFyZ2luSW5QaXhlbHMpfSBgXG4gICAgKyBgb2YgJHtTdHJpbmcod2lkdGhJblBpeGVscyl9cHggZGlzdGluY3RDb2xvcnM9JHtTdHJpbmcodmVyZGljdC5kaXN0aW5jdENvbG9yQ291bnQpfWAsXG4gICAgYHNhbXBsZWQgJHtmb3JtYXRDb2xvcih2ZXJkaWN0LmJhY2tncm91bmRDb2xvcil9LCBidXQgeD0ke1N0cmluZyh2ZXJkaWN0LmZpcnN0RGlmZmVyZW50Q29sdW1uWEluUGl4ZWxzKX0gYFxuICAgICsgYGlzICR7Zm9ybWF0Q29sb3IodmVyZGljdC5maXJzdERpZmZlcmVudENvbG9yKX1gLFxuICAgICdBIHRhbGxlciBzdGF0dXMgYmFyLCBvciBhbiBPYnNpZGlhbiB0aGF0IGRyYXdzIGhpZ2hlciwgYm90aCBsb29rIGxpa2UgdGhpcy4gTWVhc3VyZSB0aGUgYmFuZCBvbiBhIGZyZXNoICdcbiAgICArICdmcmFtZSBhbmQgcGFzcyB0aGUgaGVpZ2h0IHlvdSBtZWFzdXJlZDogZW5sYXJnaW5nIGl0IHVudGlsIHRoZSBjaGVjayBwYXNzZXMgaXMgaG93IGEgY2FwdHVyZSBwYWludHMgJ1xuICAgICsgJ292ZXIgdGhlIHByb2R1Y3QuJ1xuICBdO1xuXG4gIHJldHVybiBsaW5lcy5qb2luKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBGaWxscyB0aGUgc3RhdHVzLWJhciBiYW5kIHdpdGggdGhlIGJhY2tncm91bmQgYmVoaW5kIGl0LCBzbyB0aGUgZnJhbWUgY2FycmllcyBubyBkZXZpY2UgY2hyb21lLlxuICpcbiAqIFRoZSBpbWFnZSBrZWVwcyBpdHMgZGltZW5zaW9ucyBleGFjdGx5OiB0aGUgYmFuZCBpcyBjb21wb3NpdGVkIE9WRVIgdGhlIGZyYW1lLFxuICogbmV2ZXIgY3JvcHBlZCBvZmYgaXQsIGJlY2F1c2UgYSBzdG9yZSBsaXN0aW5nIGV4cGVjdHMgYSBzcGVjaWZpYyBzaXplIGFuZCBhXG4gKiBjcm9wcGVkIGZyYW1lIGlzIGEgZGlmZmVyZW50IHBpY3R1cmUuXG4gKlxuICogQHBhcmFtIGJ5dGVzIC0gVGhlIGRldmljZSBmcmFtZWJ1ZmZlciwgYXMgYGNhcHR1cmVEZXZpY2VTY3JlZW5zaG90YCByZXR1cm5lZCBpdC5cbiAqIEBwYXJhbSBvcHRpb25zIC0gSG93IHRhbGwgdGhlIGJhbmQgaXMsIGFuZCBob3cgdGhlIGNoZWNrIHJlYWRzIGl0LlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyB0byB0aGUgc2FtZSBmcmFtZSB3aXRoIHRoZSBiYW5kIHBhaW50ZWQgb3V0LCBhcyBQTkcgYnl0ZXMuXG4gKiBAdGhyb3dzIEVycm9yIGlmIGBzaGFycGAgaXMgbm90IGluc3RhbGxlZCwgdGhlIGJhbmQgaXMgYXMgdGFsbCBhcyB0aGUgZnJhbWUgb3IgdGFsbGVyLCBvciB0aGUgcm93IHVuZGVyXG4gKiAgIHRoZSBiYXIncyBjb250ZW50IGlzIG5vdCBvbmUgZmxhdCBjb2xvciBcdTIwMTQgc2VlIHtAbGluayBidWlsZFN0YXR1c0JhckJhbmRGYWlsdXJlTWVzc2FnZX0uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwYWludE91dFN0YXR1c0JhcihieXRlczogVWludDhBcnJheSwgb3B0aW9uczogUGFpbnRPdXRTdGF0dXNCYXJPcHRpb25zKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIGNvbnN0IHsgaGVpZ2h0SW5QaXhlbHMgfSA9IG9wdGlvbnM7XG4gIGNvbnN0IGVkZ2VNYXJnaW5JblBpeGVscyA9IG9wdGlvbnMuZWRnZU1hcmdpbkluUGl4ZWxzID8/IERFRkFVTFRfU1RBVFVTX0JBUl9FREdFX01BUkdJTl9JTl9QSVhFTFM7XG4gIGNvbnN0IHNoYXJwID0gYXdhaXQgaW1wb3J0U2hhcnAoJ3BhaW50T3V0U3RhdHVzQmFyJyk7XG4gIGNvbnN0IHsgZGF0YSwgaW5mbyB9ID0gYXdhaXQgc2hhcnAoYnl0ZXMpXG4gICAgLmVuc3VyZUFscGhhKClcbiAgICAucmF3KClcbiAgICAudG9CdWZmZXIoeyByZXNvbHZlV2l0aE9iamVjdDogdHJ1ZSB9KTtcblxuICBpZiAoaGVpZ2h0SW5QaXhlbHMgPj0gaW5mby5oZWlnaHQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgcGFpbnRPdXRTdGF0dXNCYXI6IGEgYmFuZCBvZiAke1N0cmluZyhoZWlnaHRJblBpeGVscyl9cHggd291bGQgY292ZXIgYSBmcmFtZSB0aGF0IGlzIG9ubHkgYFxuICAgICAgICArIGAke1N0cmluZyhpbmZvLmhlaWdodCl9cHggdGFsbC4gVGhhdCBpcyBhIG1lYXN1cmVtZW50IG9mIHNvbWUgb3RoZXIgZGV2aWNlLCBub3Qgb2YgdGhpcyBmcmFtZS5gXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IHZlcmRpY3QgPSByZXNvbHZlU3RhdHVzQmFyQmFuZCh7XG4gICAgY2hhbm5lbENvdW50OiBpbmZvLmNoYW5uZWxzLFxuICAgIGVkZ2VNYXJnaW5JblBpeGVscyxcbiAgICBoZWlnaHRJblBpeGVscyxcbiAgICBwaXhlbHM6IGRhdGEsXG4gICAgLi4uKG9wdGlvbnMuc2FtcGxlSW5zZXRJblBpeGVscyAhPT0gdW5kZWZpbmVkICYmIHsgc2FtcGxlSW5zZXRJblBpeGVsczogb3B0aW9ucy5zYW1wbGVJbnNldEluUGl4ZWxzIH0pLFxuICAgIHdpZHRoSW5QaXhlbHM6IGluZm8ud2lkdGhcbiAgfSk7XG5cbiAgaWYgKCF2ZXJkaWN0LmlzQ2xlYXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYnVpbGRTdGF0dXNCYXJCYW5kRmFpbHVyZU1lc3NhZ2Uoe1xuICAgICAgZWRnZU1hcmdpbkluUGl4ZWxzLFxuICAgICAgaGVpZ2h0SW5QaXhlbHMsXG4gICAgICB2ZXJkaWN0LFxuICAgICAgd2lkdGhJblBpeGVsczogaW5mby53aWR0aFxuICAgIH0pKTtcbiAgfVxuXG4gIGNvbnN0IGxheWVyOiBTaGFycENvbXBvc2l0ZUxheWVyID0ge1xuICAgIGlucHV0OiB7XG4gICAgICBjcmVhdGU6IHtcbiAgICAgICAgYmFja2dyb3VuZDogdmVyZGljdC5iYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGNoYW5uZWxzOiBGSUxMX0NIQU5ORUxfQ09VTlQsXG4gICAgICAgIGhlaWdodDogaGVpZ2h0SW5QaXhlbHMsXG4gICAgICAgIHdpZHRoOiBpbmZvLndpZHRoXG4gICAgICB9XG4gICAgfSxcbiAgICBsZWZ0OiAwLFxuICAgIHRvcDogMFxuICB9O1xuXG4gIGNvbnN0IHBhaW50ZWQgPSBhd2FpdCBzaGFycChieXRlcylcbiAgICAuY29tcG9zaXRlKFtsYXllcl0pXG4gICAgLnBuZygpXG4gICAgLnRvQnVmZmVyKCk7XG5cbiAgcmV0dXJuIG5ldyBVaW50OEFycmF5KHBhaW50ZWQpO1xufVxuXG4vKipcbiAqIFJlYWRzIHRoZSByb3cgdW5kZXIgdGhlIHN0YXR1cyBiYXIncyBjb250ZW50IGFuZCBzYXlzIHdoZXRoZXIgdGhlIGJhbmQgaXMgY2xlYXIgb2YgdGhlIGFwcC5cbiAqXG4gKiBUaGUgYmFuZCdzIGhlaWdodCBpcyBhIG51bWJlciBhIGNhbGxlciBtZWFzdXJlZCBvbmNlLCBhbmQgYSBtZWFzdXJlZCBudW1iZXJcbiAqIGNhbiBnbyBzdGFsZSBcdTIwMTQgYSB0YWxsZXIgc3RhdHVzIGJhciwgb3IgYW4gT2JzaWRpYW4gdGhhdCBkcmF3cyBoaWdoZXIsIHdvdWxkXG4gKiBoYXZlIHRoZSBjYXB0dXJlIHF1aWV0bHkgcGFpbnQgb3ZlciB0aGUgcHJvZHVjdC4gU28gdGhlIHJvdyBqdXN0IGJlbG93IHRoZVxuICogYmFyJ3Mgb3duIGNvbnRlbnQgaXMgcmVxdWlyZWQgdG8gYmUgb25lIGZsYXQgY29sb3IgYWxsIHRoZSB3YXkgYWNyb3NzOiB0aGF0XG4gKiBpcyB3aGF0IGFuIGVtcHR5IGJhbmQgbG9va3MgbGlrZSwgYW5kIGl0IGlzIHdoYXQgdGhlIGZpbGwgY29sb3IgaXMgcmVhZCBmcm9tLlxuICpcbiAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgZnJhbWUncyByYXcgcGl4ZWxzIGFuZCB0aGUgYmFuZCdzIGdlb21ldHJ5LlxuICogQHJldHVybnMgV2hhdCB0aGUgc2Nhbm5lZCByb3cgaG9sZHMuXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBnZW9tZXRyeSBpcyBkZWdlbmVyYXRlIFx1MjAxNCBhIG5vbi1wb3NpdGl2ZSBkaW1lbnNpb24sIGEgc2FtcGxlIHJvdyBhYm92ZSB0aGUgdG9wIG9mXG4gKiAgIHRoZSBmcmFtZSwgYSBtYXJnaW4gdGhhdCBsZWF2ZXMgbm90aGluZyB0byBzY2FuLCBvciBhIGJ1ZmZlciB0b28gc2hvcnQgdG8gaG9sZCB0aGUgcm93LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVN0YXR1c0JhckJhbmQocGFyYW1zOiBSZXNvbHZlU3RhdHVzQmFyQmFuZFBhcmFtcyk6IFN0YXR1c0JhckJhbmRWZXJkaWN0IHtcbiAgY29uc3Qge1xuICAgIGNoYW5uZWxDb3VudCxcbiAgICBoZWlnaHRJblBpeGVscyxcbiAgICBwaXhlbHMsXG4gICAgd2lkdGhJblBpeGVsc1xuICB9ID0gcGFyYW1zO1xuICBjb25zdCBlZGdlTWFyZ2luSW5QaXhlbHMgPSBwYXJhbXMuZWRnZU1hcmdpbkluUGl4ZWxzID8/IERFRkFVTFRfU1RBVFVTX0JBUl9FREdFX01BUkdJTl9JTl9QSVhFTFM7XG4gIGNvbnN0IHNhbXBsZUluc2V0SW5QaXhlbHMgPSBwYXJhbXMuc2FtcGxlSW5zZXRJblBpeGVscyA/PyBERUZBVUxUX1NUQVRVU19CQVJfU0FNUExFX0lOU0VUX0lOX1BJWEVMUztcblxuICBhc3NlcnRQb3NpdGl2ZSgnd2lkdGhJblBpeGVscycsIHdpZHRoSW5QaXhlbHMpO1xuICBhc3NlcnRQb3NpdGl2ZSgnaGVpZ2h0SW5QaXhlbHMnLCBoZWlnaHRJblBpeGVscyk7XG4gIGFzc2VydFBvc2l0aXZlKCdjaGFubmVsQ291bnQnLCBjaGFubmVsQ291bnQpO1xuXG4gIGNvbnN0IHNhbXBsZVJvd1lJblBpeGVscyA9IGhlaWdodEluUGl4ZWxzIC0gc2FtcGxlSW5zZXRJblBpeGVscztcblxuICBpZiAoc2FtcGxlUm93WUluUGl4ZWxzIDwgMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGByZXNvbHZlU3RhdHVzQmFyQmFuZDogYSBzYW1wbGUgaW5zZXQgb2YgJHtTdHJpbmcoc2FtcGxlSW5zZXRJblBpeGVscyl9cHggcHV0cyB0aGUgc2FtcGxlIHJvdyBhYm92ZSB0aGUgdG9wIGBcbiAgICAgICAgKyBgb2YgdGhlIGZyYW1lIGZvciBhIGJhbmQgb2YgJHtTdHJpbmcoaGVpZ2h0SW5QaXhlbHMpfXB4LmBcbiAgICApO1xuICB9XG5cbiAgY29uc3QgbGFzdFNjYW5uZWRDb2x1bW5YSW5QaXhlbHMgPSB3aWR0aEluUGl4ZWxzIC0gZWRnZU1hcmdpbkluUGl4ZWxzO1xuXG4gIGlmIChsYXN0U2Nhbm5lZENvbHVtblhJblBpeGVscyAtIGVkZ2VNYXJnaW5JblBpeGVscyA8IE1JTklNVU1fU0NBTk5FRF9DT0xVTU5fQ09VTlQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgcmVzb2x2ZVN0YXR1c0JhckJhbmQ6IGFuIGVkZ2UgbWFyZ2luIG9mICR7U3RyaW5nKGVkZ2VNYXJnaW5JblBpeGVscyl9cHggbGVhdmVzIGZld2VyIHRoYW4gYFxuICAgICAgICArIGAke1N0cmluZyhNSU5JTVVNX1NDQU5ORURfQ09MVU1OX0NPVU5UKX0gY29sdW1ucyBvZiBhICR7U3RyaW5nKHdpZHRoSW5QaXhlbHMpfXB4IGZyYW1lIHRvIHNjYW4sIGBcbiAgICAgICAgKyAnd2hpY2ggaXMgYSBjaGVjayB0aGF0IGNhbm5vdCBmYWlsLidcbiAgICApO1xuICB9XG5cbiAgY29uc3Qgcm93U3RhcnRPZmZzZXQgPSBzYW1wbGVSb3dZSW5QaXhlbHMgKiB3aWR0aEluUGl4ZWxzICogY2hhbm5lbENvdW50O1xuICBjb25zdCByZXF1aXJlZExlbmd0aCA9IHJvd1N0YXJ0T2Zmc2V0ICsgd2lkdGhJblBpeGVscyAqIGNoYW5uZWxDb3VudDtcblxuICBpZiAocGl4ZWxzLmxlbmd0aCA8IHJlcXVpcmVkTGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYHJlc29sdmVTdGF0dXNCYXJCYW5kOiB0aGUgZnJhbWUgaG9sZHMgJHtTdHJpbmcocGl4ZWxzLmxlbmd0aCl9IGJ5dGVzLCB0b28gZmV3IGZvciByb3cgYFxuICAgICAgICArIGB5JHtTdHJpbmcoc2FtcGxlUm93WUluUGl4ZWxzKX0gb2YgYSAke1N0cmluZyh3aWR0aEluUGl4ZWxzKX1weC13aWRlIGZyYW1lIGF0IGBcbiAgICAgICAgKyBgJHtTdHJpbmcoY2hhbm5lbENvdW50KX0gY2hhbm5lbHMsIHdoaWNoIG5lZWRzICR7U3RyaW5nKHJlcXVpcmVkTGVuZ3RoKX0uYFxuICAgICk7XG4gIH1cblxuICBjb25zdCBiYWNrZ3JvdW5kQ29sb3IgPSByZWFkQ29sb3IocGl4ZWxzLCByb3dTdGFydE9mZnNldCArIGVkZ2VNYXJnaW5JblBpeGVscyAqIGNoYW5uZWxDb3VudCk7XG4gIGNvbnN0IGJhY2tncm91bmRLZXkgPSBmb3JtYXRDb2xvcihiYWNrZ3JvdW5kQ29sb3IpO1xuICBjb25zdCBjb2xvcktleXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgbGV0IGZpcnN0RGlmZmVyZW50Q29sb3I6IG51bGwgfCBTdGF0dXNCYXJCYW5kQ29sb3IgPSBudWxsO1xuICBsZXQgZmlyc3REaWZmZXJlbnRDb2x1bW5YSW5QaXhlbHM6IG51bGwgfCBudW1iZXIgPSBudWxsO1xuXG4gIGZvciAobGV0IHggPSBlZGdlTWFyZ2luSW5QaXhlbHM7IHggPCBsYXN0U2Nhbm5lZENvbHVtblhJblBpeGVsczsgeCsrKSB7XG4gICAgY29uc3QgY29sb3IgPSByZWFkQ29sb3IocGl4ZWxzLCByb3dTdGFydE9mZnNldCArIHggKiBjaGFubmVsQ291bnQpO1xuICAgIGNvbnN0IGNvbG9yS2V5ID0gZm9ybWF0Q29sb3IoY29sb3IpO1xuICAgIGNvbG9yS2V5cy5hZGQoY29sb3JLZXkpO1xuXG4gICAgaWYgKGZpcnN0RGlmZmVyZW50Q29sdW1uWEluUGl4ZWxzICE9PSBudWxsIHx8IGNvbG9yS2V5ID09PSBiYWNrZ3JvdW5kS2V5KSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBmaXJzdERpZmZlcmVudENvbG9yID0gY29sb3I7XG4gICAgZmlyc3REaWZmZXJlbnRDb2x1bW5YSW5QaXhlbHMgPSB4O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBiYWNrZ3JvdW5kQ29sb3IsXG4gICAgZGlzdGluY3RDb2xvckNvdW50OiBjb2xvcktleXMuc2l6ZSxcbiAgICBmaXJzdERpZmZlcmVudENvbG9yLFxuICAgIGZpcnN0RGlmZmVyZW50Q29sdW1uWEluUGl4ZWxzLFxuICAgIGlzQ2xlYXI6IGNvbG9yS2V5cy5zaXplID09PSAxLFxuICAgIHNhbXBsZVJvd1lJblBpeGVsc1xuICB9O1xufVxuXG4vKipcbiAqIFJlZnVzZXMgYSBkaW1lbnNpb24gdGhhdCBjYW5ub3QgZGVzY3JpYmUgYSBmcmFtZS5cbiAqXG4gKiBAcGFyYW0gbmFtZSAtIFRoZSBwYXJhbWV0ZXIgYmVpbmcgY2hlY2tlZCwgc28gdGhlIG1lc3NhZ2UgbmFtZXMgaXQuXG4gKiBAcGFyYW0gdmFsdWUgLSBXaGF0IHdhcyBwYXNzZWQuXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSB2YWx1ZSBpcyBub3QgYSBwb3NpdGl2ZSBmaW5pdGUgbnVtYmVyLlxuICovXG5mdW5jdGlvbiBhc3NlcnRQb3NpdGl2ZShuYW1lOiBzdHJpbmcsIHZhbHVlOiBudW1iZXIpOiB2b2lkIHtcbiAgaWYgKCFOdW1iZXIuaXNGaW5pdGUodmFsdWUpIHx8IHZhbHVlIDw9IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYHJlc29sdmVTdGF0dXNCYXJCYW5kOiAke25hbWV9IG11c3QgYmUgYSBwb3NpdGl2ZSBudW1iZXIsIGdvdCAke1N0cmluZyh2YWx1ZSl9LmApO1xuICB9XG59XG5cbi8qKlxuICogUmVuZGVycyBhIGNvbG9yIGFzIHRleHQsIGZvciBjb21wYXJpc29uIGFuZCBmb3IgdGhlIGRpYWdub3N0aWMuXG4gKlxuICogVGhlIHNhbWUgcmVuZGVyaW5nIGRvZXMgYm90aCBqb2JzIG9uIHB1cnBvc2U6IHdoYXQgYSByZWFkZXIgaXMgc2hvd24gaXMgdGhlXG4gKiB2YWx1ZSB0aGUgY29tcGFyaXNvbiB3YXMgbWFkZSBvbiwgcmF0aGVyIHRoYW4gYSByZS1mb3JtYXR0aW5nIG9mIGl0LlxuICpcbiAqIEBwYXJhbSBjb2xvciAtIFRoZSBjb2xvciwgb3IgYG51bGxgIHdoZW4gdGhlcmUgd2FzIG5vbmUgdG8gcmVwb3J0LlxuICogQHJldHVybnMgVGhlIGNvbG9yIGFzIGByZ2IocixnLGIpYCwgb3IgYChub25lKWAuXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdENvbG9yKGNvbG9yOiBudWxsIHwgU3RhdHVzQmFyQmFuZENvbG9yKTogc3RyaW5nIHtcbiAgcmV0dXJuIGNvbG9yID09PSBudWxsID8gJyhub25lKScgOiBgcmdiKCR7U3RyaW5nKGNvbG9yLnIpfSwke1N0cmluZyhjb2xvci5nKX0sJHtTdHJpbmcoY29sb3IuYil9KWA7XG59XG5cbi8qKlxuICogUmVhZHMgb25lIHBpeGVsJ3MgY29sb3Igb3V0IG9mIGEgcmF3IGZyYW1lLCBpZ25vcmluZyBhbnkgYWxwaGEgY2hhbm5lbC5cbiAqXG4gKiBAcGFyYW0gcGl4ZWxzIC0gVGhlIGZyYW1lJ3MgcmF3IGJ5dGVzLlxuICogQHBhcmFtIG9mZnNldCAtIFRoZSBieXRlIG9mZnNldCBvZiB0aGUgcGl4ZWwuXG4gKiBAcmV0dXJucyBUaGUgY29sb3IgYXQgdGhhdCBvZmZzZXQuXG4gKi9cbmZ1bmN0aW9uIHJlYWRDb2xvcihwaXhlbHM6IFVpbnQ4QXJyYXksIG9mZnNldDogbnVtYmVyKTogU3RhdHVzQmFyQmFuZENvbG9yIHtcbiAgLyogdjggaWdub3JlIHN0YXJ0IC0tIFRoZSBmYWxsYmFja3MgYXJlIHVucmVhY2hhYmxlOiBldmVyeSByZWFkIGlzIGluc2lkZSBhIHJvdyBgcmVzb2x2ZVN0YXR1c0JhckJhbmRgIGhhcyBhbHJlYWR5IHByb3ZlZCB0aGUgYnVmZmVyIGxvbmcgZW5vdWdoIHRvIGhvbGQuIFRoZXkgYXJlIGhlcmUgYmVjYXVzZSBhbiBpbmRleCByZWFkIGlzIHR5cGVkIGBudW1iZXIgfCB1bmRlZmluZWRgLCBub3QgYmVjYXVzZSBhIHBpeGVsIGNhbiBiZSBtaXNzaW5nLiAqL1xuICByZXR1cm4ge1xuICAgIGI6IHBpeGVsc1tvZmZzZXQgKyBCTFVFX0NIQU5ORUxfT0ZGU0VUXSA/PyAwLFxuICAgIGc6IHBpeGVsc1tvZmZzZXQgKyBHUkVFTl9DSEFOTkVMX09GRlNFVF0gPz8gMCxcbiAgICByOiBwaXhlbHNbb2Zmc2V0ICsgUkVEX0NIQU5ORUxfT0ZGU0VUXSA/PyAwXG4gIH07XG4gIC8qIHY4IGlnbm9yZSBzdG9wICovXG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUEyQ0EsMEJBQTRCO0FBNktyQixNQUFNLDJDQUEyQztBQVFqRCxNQUFNLDRDQUE0QztBQUt6RCxNQUFNLHNCQUFzQjtBQUs1QixNQUFNLHFCQUFxQjtBQUszQixNQUFNLHVCQUF1QjtBQVE3QixNQUFNLCtCQUErQjtBQUtyQyxNQUFNLHFCQUFxQjtBQVdwQixTQUFTLGlDQUFpQyxRQUF3RDtBQUN2RyxRQUFNO0FBQUEsSUFDSjtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0YsSUFBSTtBQUVKLFFBQU0sUUFBUTtBQUFBLElBQ1osMkZBQ0ssT0FBTyxjQUFjLENBQUM7QUFBQSxJQUMzQixRQUFRLE9BQU8sY0FBYyxDQUFDLGlCQUFpQixPQUFPLFFBQVEsa0JBQWtCLENBQUMsYUFDbkUsT0FBTyxrQkFBa0IsQ0FBQyxLQUFLLE9BQU8sZ0JBQWdCLGtCQUFrQixDQUFDLE9BQy9FLE9BQU8sYUFBYSxDQUFDLHFCQUFxQixPQUFPLFFBQVEsa0JBQWtCLENBQUM7QUFBQSxJQUNwRixXQUFXLFlBQVksUUFBUSxlQUFlLENBQUMsV0FBVyxPQUFPLFFBQVEsNkJBQTZCLENBQUMsT0FDL0YsWUFBWSxRQUFRLG1CQUFtQixDQUFDO0FBQUEsSUFDaEQ7QUFBQSxFQUdGO0FBRUEsU0FBTyxNQUFNLEtBQUssSUFBSTtBQUN4QjtBQWVBLGVBQXNCLGtCQUFrQixPQUFtQixTQUF3RDtBQUNqSCxRQUFNLEVBQUUsZUFBZSxJQUFJO0FBQzNCLFFBQU0scUJBQXFCLFFBQVEsc0JBQXNCO0FBQ3pELFFBQU0sUUFBUSxVQUFNLGlDQUFZLG1CQUFtQjtBQUNuRCxRQUFNLEVBQUUsTUFBTSxLQUFLLElBQUksTUFBTSxNQUFNLEtBQUss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
@@ -0,0 +1,236 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * Paints the device's status bar out of a captured frame, so a device capture
5
+ * can be committed.
6
+ *
7
+ * A framebuffer carries the status bar, and a status bar carries a wall clock, a
8
+ * battery that charges while the emulator runs and a radio that comes and goes.
9
+ * So re-running a capture suite on an unchanged tree rewrites its PNGs with
10
+ * content nobody can commit, and the churn is invisible until someone diffs two
11
+ * runs. `device-screenshot`'s header has always said a device capture is not
12
+ * byte-reproducible; this is what makes one.
13
+ *
14
+ * **Pinning the bar was tried first, and is NOT sufficient — that finding is the
15
+ * reason this helper exists rather than a `withSystemUiDemoMode` one.** SystemUI
16
+ * demo mode (`sysui_demo_allowed`, plus one `com.android.systemui.demo`
17
+ * broadcast per area: clock at a fixed `hhmm`, battery full and unplugged,
18
+ * radios hidden, notification icons off) held the clock at `12:00` and two runs
19
+ * still disagreed on **1823 full-contrast pixels**, because the bar's leading
20
+ * group is laid out at a different offset between emulator boots —
21
+ * intermittently, roughly one boot in four. The Tuner's `icon_blacklist` does
22
+ * not help either: demo mode draws its own icon layer and ignores it. Measured
23
+ * on a real AVD across five paired capture runs for `obsidian-link-picker`'s
24
+ * store frames, which is where this recipe was worked out before it moved here.
25
+ *
26
+ * Removing the band rather than pinning it also retires every device setting
27
+ * that pinning needed, and nothing in a status bar is evidence about a plugin. A
28
+ * listing frame without one is what a listing frame normally looks like.
29
+ *
30
+ * **The band's height is the caller's to measure, and there is deliberately no
31
+ * default.** A wrong height does not fail loudly by itself — it paints over the
32
+ * product. What stands between the two is {@link resolveStatusBarBand}: the row
33
+ * just under the bar's own content must be one flat color all the way across,
34
+ * which is what an empty band looks like and is also where the fill color is
35
+ * sampled from. A taller bar, or an Obsidian that draws higher, fails the
36
+ * capture instead.
37
+ *
38
+ * Compositing over a captured frame is not a new liberty: `labelScreenshot`
39
+ * already draws the caption band across the bottom of the same image.
40
+ */
41
+ /**
42
+ * Parameters for {@link buildStatusBarBandFailureMessage}.
43
+ */
44
+ export interface BuildStatusBarBandFailureMessageParams {
45
+ /**
46
+ * How far in from each edge the row was scanned, in pixels.
47
+ */
48
+ readonly edgeMarginInPixels: number;
49
+ /**
50
+ * The height of the band that was about to be painted, in pixels.
51
+ */
52
+ readonly heightInPixels: number;
53
+ /**
54
+ * The verdict being reported.
55
+ */
56
+ readonly verdict: StatusBarBandVerdict;
57
+ /**
58
+ * The frame's width, in pixels.
59
+ */
60
+ readonly widthInPixels: number;
61
+ }
62
+ /**
63
+ * Options for {@link paintOutStatusBar}.
64
+ */
65
+ export interface PaintOutStatusBarOptions {
66
+ /**
67
+ * How far in from each edge the clear-of-chrome check reads.
68
+ *
69
+ * @default {@link DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS}
70
+ */
71
+ readonly edgeMarginInPixels?: number;
72
+ /**
73
+ * How tall the device's status bar is, in framebuffer pixels.
74
+ *
75
+ * **Measured, never assumed, and deliberately without a default.** 24dp at a
76
+ * density of 320 is 48px, and that is one AVD's number rather than a constant
77
+ * of Android. Measure it on a frame: the bar's own content occupies the top
78
+ * rows, a few empty rows follow, and the app's top chrome starts at exactly
79
+ * this offset.
80
+ */
81
+ readonly heightInPixels: number;
82
+ /**
83
+ * How far above the band's bottom edge the fill color is sampled, in pixels.
84
+ *
85
+ * @default {@link DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS}
86
+ */
87
+ readonly sampleInsetInPixels?: number;
88
+ }
89
+ /**
90
+ * Parameters for {@link resolveStatusBarBand}.
91
+ */
92
+ export interface ResolveStatusBarBandParams {
93
+ /**
94
+ * How many bytes each pixel occupies in {@link ResolveStatusBarBandParams.pixels} — 3 for RGB, 4 for RGBA.
95
+ */
96
+ readonly channelCount: number;
97
+ /**
98
+ * How far in from each edge to start reading, in pixels.
99
+ *
100
+ * A device's rounded corners darken a handful of pixels at both ends of every
101
+ * row in the band, constantly and harmlessly; the check is about what the APP
102
+ * draws, so it ignores them.
103
+ *
104
+ * @default {@link DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS}
105
+ */
106
+ readonly edgeMarginInPixels?: number;
107
+ /**
108
+ * The height of the band, in pixels — the same number {@link paintOutStatusBar} would paint.
109
+ */
110
+ readonly heightInPixels: number;
111
+ /**
112
+ * The frame's raw pixels, row-major, as `sharp`'s `raw()` reports them.
113
+ */
114
+ readonly pixels: Uint8Array;
115
+ /**
116
+ * How far above the band's bottom edge the row is read from, in pixels.
117
+ *
118
+ * The bar's own content stops short of the band's bottom edge, so the rows
119
+ * immediately under it are empty; this picks one of them.
120
+ *
121
+ * @default {@link DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS}
122
+ */
123
+ readonly sampleInsetInPixels?: number;
124
+ /**
125
+ * The frame's width, in pixels.
126
+ */
127
+ readonly widthInPixels: number;
128
+ }
129
+ /**
130
+ * A color read out of a frame, channel by channel.
131
+ *
132
+ * This package's own type rather than `sharp`'s, because it is part of the
133
+ * public surface and `sharp` is an OPTIONAL peer: a consumer that never installs
134
+ * it still names this. Structurally what `sharp`'s `background` takes, which is
135
+ * how the fill block is created from one with no conversion in between.
136
+ */
137
+ export interface StatusBarBandColor {
138
+ /**
139
+ * The blue channel, 0-255.
140
+ */
141
+ readonly b: number;
142
+ /**
143
+ * The green channel, 0-255.
144
+ */
145
+ readonly g: number;
146
+ /**
147
+ * The red channel, 0-255.
148
+ */
149
+ readonly r: number;
150
+ }
151
+ /**
152
+ * What the row under the status bar's content turned out to hold.
153
+ *
154
+ * Verdict-as-data, like the compatibility and teardown checks: the reading and
155
+ * the throwing are separate, so a caller can ask what a frame looks like without
156
+ * having to catch an error to find out.
157
+ */
158
+ export interface StatusBarBandVerdict {
159
+ /**
160
+ * The color the band would be filled with — read from the first scanned column of the sample row.
161
+ */
162
+ readonly backgroundColor: StatusBarBandColor;
163
+ /**
164
+ * How many distinct colors the scanned row holds. One is what an empty band looks like.
165
+ */
166
+ readonly distinctColorCount: number;
167
+ /**
168
+ * The color at {@link StatusBarBandVerdict.firstDifferentColumnXInPixels}, or `null` when the row is flat.
169
+ */
170
+ readonly firstDifferentColor: null | StatusBarBandColor;
171
+ /**
172
+ * The first scanned column that differs from {@link StatusBarBandVerdict.backgroundColor}, or `null` when the row is flat.
173
+ */
174
+ readonly firstDifferentColumnXInPixels: null | number;
175
+ /**
176
+ * Whether the row is one flat color, and so whether the band holds nothing but device chrome.
177
+ */
178
+ readonly isClear: boolean;
179
+ /**
180
+ * Which row was read, as a distance from the top of the frame in pixels.
181
+ */
182
+ readonly sampleRowYInPixels: number;
183
+ }
184
+ /**
185
+ * How far in from each edge the clear-of-chrome check reads, in pixels.
186
+ *
187
+ * Exported because a caller tightening or loosening it wants to say so relative
188
+ * to this rather than in the abstract.
189
+ */
190
+ export declare const DEFAULT_STATUS_BAR_EDGE_MARGIN_IN_PIXELS = 100;
191
+ /**
192
+ * How far above the band's bottom edge the sample row sits, in pixels.
193
+ *
194
+ * Four rows up: far enough to clear the bar's own content, close enough to still
195
+ * be inside the band on every device this has been measured on.
196
+ */
197
+ export declare const DEFAULT_STATUS_BAR_SAMPLE_INSET_IN_PIXELS = 4;
198
+ /**
199
+ * Builds the message a band that is not clear is refused with.
200
+ *
201
+ * Separate from the throwing so it can be asserted on directly: what makes this
202
+ * failure actionable is the measurement, not the wording around it.
203
+ *
204
+ * @param params - The verdict and the geometry it was read with.
205
+ * @returns The message, ready to throw.
206
+ */
207
+ export declare function buildStatusBarBandFailureMessage(params: BuildStatusBarBandFailureMessageParams): string;
208
+ /**
209
+ * Fills the status-bar band with the background behind it, so the frame carries no device chrome.
210
+ *
211
+ * The image keeps its dimensions exactly: the band is composited OVER the frame,
212
+ * never cropped off it, because a store listing expects a specific size and a
213
+ * cropped frame is a different picture.
214
+ *
215
+ * @param bytes - The device framebuffer, as `captureDeviceScreenshot` returned it.
216
+ * @param options - How tall the band is, and how the check reads it.
217
+ * @returns A {@link Promise} that resolves to the same frame with the band painted out, as PNG bytes.
218
+ * @throws Error if `sharp` is not installed, the band is as tall as the frame or taller, or the row under
219
+ * the bar's content is not one flat color — see {@link buildStatusBarBandFailureMessage}.
220
+ */
221
+ export declare function paintOutStatusBar(bytes: Uint8Array, options: PaintOutStatusBarOptions): Promise<Uint8Array>;
222
+ /**
223
+ * Reads the row under the status bar's content and says whether the band is clear of the app.
224
+ *
225
+ * The band's height is a number a caller measured once, and a measured number
226
+ * can go stale — a taller status bar, or an Obsidian that draws higher, would
227
+ * have the capture quietly paint over the product. So the row just below the
228
+ * bar's own content is required to be one flat color all the way across: that
229
+ * is what an empty band looks like, and it is what the fill color is read from.
230
+ *
231
+ * @param params - The frame's raw pixels and the band's geometry.
232
+ * @returns What the scanned row holds.
233
+ * @throws Error if the geometry is degenerate — a non-positive dimension, a sample row above the top of
234
+ * the frame, a margin that leaves nothing to scan, or a buffer too short to hold the row.
235
+ */
236
+ export declare function resolveStatusBarBand(params: ResolveStatusBarBandParams): StatusBarBandVerdict;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var port_owner_query_verdict_exports = {};
20
+ __export(port_owner_query_verdict_exports, {
21
+ buildPortOwnerQueryMessage: () => buildPortOwnerQueryMessage,
22
+ normalizeSyncExecError: () => normalizeSyncExecError,
23
+ resolvePortOwnerQueryOutcome: () => resolvePortOwnerQueryOutcome
24
+ });
25
+ module.exports = __toCommonJS(port_owner_query_verdict_exports);
26
+ var import_node_buffer = require("node:buffer");
27
+ var import_host_process_query_verdict = require("./host-process-query-verdict.cjs");
28
+ var import_type_guards = require("./type-guards.cjs");
29
+ const LSOF_NOTHING_FOUND_EXIT_CODE = 1;
30
+ function buildPortOwnerQueryMessage(params) {
31
+ const cost = `after ${(0, import_host_process_query_verdict.formatDuration)(params.elapsedInMilliseconds)}`;
32
+ const subject = `\`${params.command}\` (asking who listens on port ${String(params.port)})`;
33
+ const consequence = `Nothing is known about what still holds port ${String(params.port)}, so the escalation has no PID to kill \u2014 this is not the same as nothing holding it.`;
34
+ switch (params.outcome) {
35
+ case "answered": {
36
+ return void 0;
37
+ }
38
+ case "crashed": {
39
+ return `Warning: ${subject} died ${cost} without explaining itself (exit ${(0, import_host_process_query_verdict.formatExitCode)(params.exitCode)}, nothing on stderr). Suspect a crash or an interfering security product, and try the command by hand. ${consequence}`;
40
+ }
41
+ case "not-found": {
42
+ return `Warning: ${subject} could not be run at all ${cost}: the executable was not found on PATH. ${consequence}`;
43
+ }
44
+ case "output-overran": {
45
+ return `Warning: ${subject} produced more output ${cost} than the query's buffer allows, so none of it could be read. Raise the buffer. ${consequence}`;
46
+ }
47
+ case "refused": {
48
+ return `Warning: ${subject} refused the request ${cost} (exit ${(0, import_host_process_query_verdict.formatExitCode)(params.exitCode)}): ${(0, import_host_process_query_verdict.formatRefusal)(params.standardError)} ${consequence}`;
49
+ }
50
+ case "timed-out": {
51
+ return `Warning: ${subject} did not finish within its ${(0, import_host_process_query_verdict.formatDuration)(params.timeoutInMilliseconds)} budget and was killed ${cost}${params.signal === null ? "" : ` (${params.signal})`}. ${consequence}`;
52
+ }
53
+ default: {
54
+ return (0, import_type_guards.assertNever)(params.outcome);
55
+ }
56
+ }
57
+ }
58
+ function normalizeSyncExecError(error) {
59
+ const record = typeof error === "object" && error !== null ? error : {};
60
+ const code = typeof record["code"] === "string" ? record["code"] : void 0;
61
+ const status = typeof record["status"] === "number" ? record["status"] : null;
62
+ const signal = typeof record["signal"] === "string" ? record["signal"] : null;
63
+ const isKilled = code === "ETIMEDOUT";
64
+ let errorCode = status;
65
+ if (code === "ENOBUFS") {
66
+ errorCode = "ERR_CHILD_PROCESS_STDIO_MAXBUFFER";
67
+ } else if (code !== void 0 && !isKilled) {
68
+ errorCode = code;
69
+ }
70
+ return {
71
+ errorCode,
72
+ exitCode: status,
73
+ isKilled,
74
+ signal,
75
+ standardError: toText(record["stderr"]),
76
+ standardOutput: toText(record["stdout"])
77
+ };
78
+ }
79
+ function resolvePortOwnerQueryOutcome(params) {
80
+ return !params.hasFailed || params.platform !== "win32" && !params.isKilled && params.errorCode === LSOF_NOTHING_FOUND_EXIT_CODE && params.standardError.trim() === "" && params.standardOutput.trim() === "" ? "answered" : (0, import_host_process_query_verdict.resolveHostQueryFailure)(params);
81
+ }
82
+ function toText(stream) {
83
+ if (typeof stream === "string") {
84
+ return stream;
85
+ }
86
+ return import_node_buffer.Buffer.isBuffer(stream) ? stream.toString("utf-8") : "";
87
+ }
88
+ // Annotate the CommonJS export names for ESM import in node:
89
+ 0 && (module.exports = {
90
+ buildPortOwnerQueryMessage,
91
+ normalizeSyncExecError,
92
+ resolvePortOwnerQueryOutcome
93
+ });
94
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL3BvcnQtb3duZXItcXVlcnktdmVyZGljdC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIFB1cmUgY2xhc3NpZmljYXRpb24gb2YgdGhlIHBvcnQtb3duZXIgcXVlcnkgXHUyMDE0IGBuZXRzdGF0IC1hbm9gIG9uIFdpbmRvd3MsXG4gKiBgbHNvZiAtdGkgdGNwOjxwb3J0PmAgZWxzZXdoZXJlIFx1MjAxNCBkZWNpZGluZywgZnJvbSBob3cgaXQgZW5kZWQsIHdoZXRoZXIgaXRcbiAqICoqYW5zd2VyZWQqKiBvciAqKmZhaWxlZCoqLCBhbmQgc2F5aW5nIHdoaWNoIGZhaWx1cmUgaW4gb25lIGxpbmUuXG4gKlxuICogVGhlIHF1ZXJ5IGlzIHRoZSBvbmx5IHJlYWwgZXNjYWxhdGlvbiB0aGUgQXBwaXVtIHRlYXJkb3duIGhhczogdGhlIFBJRCB0aGVcbiAqIGhhcm5lc3MgaG9sZHMgaXMgdGhlIGBzaGVsbDogdHJ1ZWAgd3JhcHBlciBpdCBzcGF3bmVkLCBzbyB3aGF0IHN1cnZpdmVzIGEga2lsbFxuICogaXMgZm91bmQgYnkgYXNraW5nIHdobyBzdGlsbCBsaXN0ZW5zIG9uIHRoZSBwb3J0ICgqKkw0NioqKS4gSXQgdXNlZCB0byByZXNvbHZlXG4gKiBhbiBlbXB0eSBsaXN0IGZvciBldmVyeSBlcnJvciwgd2hpY2ggbWFkZSB0aHJlZSBkaWZmZXJlbnQgZW5kaW5ncyBvbmUgc2lsZW50XG4gKiB2YWx1ZTpcbiAqXG4gKiAtIGBsc29mYCBleGl0aW5nIDEgd2l0aCBub3RoaW5nIG9uIGVpdGhlciBzdHJlYW0gXHUyMDE0IHdoaWNoIGlzIGhvdyBpdCBzYXlzXG4gKiAgIG5vdGhpbmcgaG9sZHMgdGhlIHBvcnQqLCBhIGxlZ2l0aW1hdGUgZW1wdHkgYW5zd2VyO1xuICogLSB0aGUgYnVkZ2V0IHJ1bm5pbmcgb3V0IG9uIGEgY29udGVuZGVkIGhvc3Q7XG4gKiAtIHRoZSBjaGlsZCBkeWluZy5cbiAqXG4gKiBPbmx5IHRoZSBmaXJzdCBpcyBhbiBhbnN3ZXIuIFRoZSBvdGhlciB0d28gZGlzYXJtIHRoZSBlc2NhbGF0aW9uIGV4YWN0bHkgdGhlXG4gKiB3YXkgYSBzaWxlbnRseSBmYWlsZWQgcHJvY2VzcyBsaXN0aW5nIGRpc2FybWVkIHRoZSBlbXVsYXRvcidzXG4gKiAoYGhvc3QtcHJvY2Vzcy1xdWVyeS12ZXJkaWN0LnRzYCksIHNvIHRoZXkgYXJlIGNsYXNzaWZpZWQgYnkgdGhlIHNhbWUgcnVsZXNcbiAqIGFuZCByZXBvcnRlZCwgbm90IHN3YWxsb3dlZC5cbiAqXG4gKiAqKldoeSBhIG1vZHVsZSBvZiBpdHMgb3duIHJhdGhlciB0aGFuIGFuIG9wdGlvbiBvbiB0aGUgcHJvY2Vzcy1saXN0aW5nXG4gKiB2ZXJkaWN0LioqIFRoZSB0d28gcXVlcmllcyBkaXNhZ3JlZSBpbiB0d28gcGxhY2VzLCBub3Qgb25lLiBaZXJvIG93bmVycyBpcyBhXG4gKiBsZWdpdGltYXRlIGFuc3dlciBoZXJlLCBzbyBgemVyby1yb3dzYCBuZXZlciBhcHBsaWVzOyBhbmQgYGxzb2ZgJ3Mgc2lsZW50IGV4aXRcbiAqIDEgbWVhbnMgKm5vdGhpbmcgbGlzdGVucyosIHdoZXJlIGZvciBgdGFza2xpc3RgIGEgc2lsZW50IG5vbi16ZXJvIGV4aXQgaXMgYVxuICogY3Jhc2guIFRoZSBmYWlsdXJlIGJyYW5jaGVzIHRoZW1zZWx2ZXMgYXJlIGRlbGVnYXRlZCB0b1xuICoge0BsaW5rIHJlc29sdmVIb3N0UXVlcnlGYWlsdXJlfSwgc28gdGhlcmUgaXMgc3RpbGwgb25lIGRlZmluaXRpb24gb2ZcbiAqIGBjcmFzaGVkYCwgYHRpbWVkLW91dGAgYW5kIGByZWZ1c2VkYC5cbiAqL1xuXG5pbXBvcnQgeyBCdWZmZXIgfSBmcm9tICdub2RlOmJ1ZmZlcic7XG5cbmltcG9ydCB0eXBlIHsgSG9zdFF1ZXJ5RmFpbHVyZSB9IGZyb20gJy4vaG9zdC1wcm9jZXNzLXF1ZXJ5LXZlcmRpY3QuY2pzJztcblxuaW1wb3J0IHtcbiAgZm9ybWF0RHVyYXRpb24sXG4gIGZvcm1hdEV4aXRDb2RlLFxuICBmb3JtYXRSZWZ1c2FsLFxuICByZXNvbHZlSG9zdFF1ZXJ5RmFpbHVyZVxufSBmcm9tICcuL2hvc3QtcHJvY2Vzcy1xdWVyeS12ZXJkaWN0LmNqcyc7XG5pbXBvcnQgeyBhc3NlcnROZXZlciB9IGZyb20gJy4vdHlwZS1ndWFyZHMuY2pzJztcblxuLyoqXG4gKiBUaGUgZXhpdCBjb2RlIGBsc29mYCB1c2VzIGZvciBcImZvdW5kIG5vdGhpbmdcIiwgd2hpY2ggaXQgcmVwb3J0cyBvbiBuZWl0aGVyIHN0cmVhbS5cbiAqL1xuY29uc3QgTFNPRl9OT1RISU5HX0ZPVU5EX0VYSVRfQ09ERSA9IDE7XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIGJ1aWxkUG9ydE93bmVyUXVlcnlNZXNzYWdlfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCdWlsZFBvcnRPd25lclF1ZXJ5TWVzc2FnZVBhcmFtcyB7XG4gIC8qKlxuICBUaGUgY29tbWFuZCB0aGF0IHdhcyBydW4sIGZvciB0aGUgcmVhZGVyIHRvIHRyeSBieSBoYW5kIFx1MjAxNCBlLmcuIGBuZXRzdGF0IC1hbm9gLlxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWFuZDogc3RyaW5nO1xuXG4gIC8qKlxuICBIb3cgbG9uZyB0aGUgY2FsbCB0b29rIGJlZm9yZSBpdCBlbmRlZCwgaW4gbWlsbGlzZWNvbmRzLlxuICAgKi9cbiAgcmVhZG9ubHkgZWxhcHNlZEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG5cbiAgLyoqXG4gIFRoZSBjaGlsZCdzIGV4aXQgY29kZSwgd2hlbiBpdCBleGl0ZWQgcmF0aGVyIHRoYW4gZmFpbGluZyB0byBzdGFydCBvciBiZWluZyBraWxsZWQuXG4gICAqL1xuICByZWFkb25seSBleGl0Q29kZTogbnVsbCB8IG51bWJlcjtcblxuICAvKipcbiAgVGhlIHZlcmRpY3QgZnJvbSB7QGxpbmsgcmVzb2x2ZVBvcnRPd25lclF1ZXJ5T3V0Y29tZX0uXG4gICAqL1xuICByZWFkb25seSBvdXRjb21lOiBQb3J0T3duZXJRdWVyeU91dGNvbWU7XG5cbiAgLyoqXG4gIFRoZSBwb3J0IHdob3NlIG93bmVycyB3ZXJlIGFza2VkIGZvci5cbiAgICovXG4gIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcblxuICAvKipcbiAgVGhlIHNpZ25hbCB0aGUgY2hpbGQgd2FzIGtpbGxlZCB3aXRoLCB3aGVuIGl0IHdhcyBraWxsZWQuXG4gICAqL1xuICByZWFkb25seSBzaWduYWw6IG51bGwgfCBzdHJpbmc7XG5cbiAgLyoqXG4gIFdoYXRldmVyIHRoZSBjaGlsZCB3cm90ZSB0byBzdGRlcnIuXG4gICAqL1xuICByZWFkb25seSBzdGFuZGFyZEVycm9yOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFRoZSBidWRnZXQgdGhlIGNhbGwgd2FzIGdpdmVuLCBpbiBtaWxsaXNlY29uZHMuXG4gICAqL1xuICByZWFkb25seSB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBUaGUgZmllbGRzIHtAbGluayBub3JtYWxpemVTeW5jRXhlY0Vycm9yfSBleHRyYWN0cyBmcm9tIGFuIGBleGVjRmlsZVN5bmNgIHRocm93LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE5vcm1hbGl6ZWRTeW5jRXhlY0Vycm9yIHtcbiAgLyoqXG4gIFRoZSBlcnJvciBjb2RlIGluIGBleGVjRmlsZWAncyB2b2NhYnVsYXJ5OiB0aGUgbnVtZXJpYyBleGl0IGNvZGUsIG9yIGEgc3RyaW5nIHN1Y2ggYXMgYEVOT0VOVGAgb3IgYEVSUl9DSElMRF9QUk9DRVNTX1NURElPX01BWEJVRkZFUmAuXG4gICAqL1xuICByZWFkb25seSBlcnJvckNvZGU6IG51bGwgfCBudW1iZXIgfCBzdHJpbmc7XG5cbiAgLyoqXG4gIFRoZSBjaGlsZCdzIGV4aXQgY29kZSwgd2hlbiBpdCBleGl0ZWQuXG4gICAqL1xuICByZWFkb25seSBleGl0Q29kZTogbnVsbCB8IG51bWJlcjtcblxuICAvKipcbiAgV2hldGhlciB0aGUgYnVkZ2V0IGV4cGlyZWQgYW5kIHRoZSBjaGlsZCB3YXMga2lsbGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgaXNLaWxsZWQ6IGJvb2xlYW47XG5cbiAgLyoqXG4gIFRoZSBzaWduYWwgdGhlIGNoaWxkIHdhcyBraWxsZWQgd2l0aC5cbiAgICovXG4gIHJlYWRvbmx5IHNpZ25hbDogbnVsbCB8IHN0cmluZztcblxuICAvKipcbiAgV2hhdGV2ZXIgdGhlIGNoaWxkIHdyb3RlIHRvIHN0ZGVyci5cbiAgICovXG4gIHJlYWRvbmx5IHN0YW5kYXJkRXJyb3I6IHN0cmluZztcblxuICAvKipcbiAgV2hhdGV2ZXIgdGhlIGNoaWxkIHdyb3RlIHRvIHN0ZG91dCBiZWZvcmUgaXQgZW5kZWQuXG4gICAqL1xuICByZWFkb25seSBzdGFuZGFyZE91dHB1dDogc3RyaW5nO1xufVxuXG4vKipcbiAqIEhvdyB0aGUgcG9ydC1vd25lciBxdWVyeSBlbmRlZC5cbiAqXG4gKiBgYW5zd2VyZWRgIGNvdmVycyBib3RoIGEgbGlzdGVuZXIgZm91bmQgYW5kIG5vbmUgZm91bmQgXHUyMDE0IHRoZSBxdWVyeSBzdWNjZWVkZWRcbiAqIGVpdGhlciB3YXkuIFRoZSByZXN0IGFyZSB7QGxpbmsgcmVzb2x2ZUhvc3RRdWVyeUZhaWx1cmV9J3MgZmFpbHVyZXMuXG4gKi9cbmV4cG9ydCB0eXBlIFBvcnRPd25lclF1ZXJ5T3V0Y29tZSA9ICdhbnN3ZXJlZCcgfCBIb3N0UXVlcnlGYWlsdXJlO1xuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayByZXNvbHZlUG9ydE93bmVyUXVlcnlPdXRjb21lfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlUG9ydE93bmVyUXVlcnlPdXRjb21lUGFyYW1zIHtcbiAgLyoqXG4gIGBleGVjRmlsZWAncyBgZXJyb3IuY29kZWA6IHRoZSBudW1lcmljIGV4aXQgY29kZSwgb3IgYSBzdHJpbmcgbGlrZSBgRU5PRU5UYCB3aGVuIHRoZSBjaGlsZCBuZXZlciByYW4uXG4gICAqL1xuICByZWFkb25seSBlcnJvckNvZGU6IG51bGwgfCBudW1iZXIgfCBzdHJpbmc7XG5cbiAgLyoqXG4gIFdoZXRoZXIgYGV4ZWNGaWxlYCByZXBvcnRlZCBhbiBlcnJvciBhdCBhbGwuXG4gICAqL1xuICByZWFkb25seSBoYXNGYWlsZWQ6IGJvb2xlYW47XG5cbiAgLyoqXG4gIGBleGVjRmlsZWAncyBgZXJyb3Iua2lsbGVkYDogd2hldGhlciB0aGUgYnVkZ2V0IGV4cGlyZWQgYW5kIHRoZSBjaGlsZCB3YXMga2lsbGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgaXNLaWxsZWQ6IGJvb2xlYW47XG5cbiAgLyoqXG4gIFRoZSBob3N0IHBsYXRmb3JtLCB3aGljaCBkZWNpZGVzIHdoZXRoZXIgYSBzaWxlbnQgZXhpdCAxIGlzIGBsc29mYCBzYXlpbmcgKm5vdGhpbmcgbGlzdGVucyouXG4gICAqL1xuICByZWFkb25seSBwbGF0Zm9ybTogTm9kZUpTLlBsYXRmb3JtO1xuXG4gIC8qKlxuICBXaGF0ZXZlciB0aGUgY2hpbGQgd3JvdGUgdG8gc3RkZXJyLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhbmRhcmRFcnJvcjogc3RyaW5nO1xuXG4gIC8qKlxuICBXaGF0ZXZlciB0aGUgY2hpbGQgd3JvdGUgdG8gc3Rkb3V0LlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhbmRhcmRPdXRwdXQ6IHN0cmluZztcbn1cblxuLyoqXG4gKiBCdWlsZHMgdGhlIHNpbmdsZSBsaW5lIHRoZSBxdWVyeSBsb2dzIGZvciBhbiBvdXRjb21lLlxuICpcbiAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgb3V0Y29tZSBwbHVzIHRoZSBjb21tYW5kLCB0aGUgcG9ydCwgdGhlIGJ1ZGdldCBhbmQgd2hhdCB0aGUgY2hpbGQgbGVmdCBiZWhpbmQuXG4gKiBAcmV0dXJucyBUaGUgd2FybmluZyB0byBsb2csIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhlIHF1ZXJ5IGFuc3dlcmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRQb3J0T3duZXJRdWVyeU1lc3NhZ2UocGFyYW1zOiBCdWlsZFBvcnRPd25lclF1ZXJ5TWVzc2FnZVBhcmFtcyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGNvc3QgPSBgYWZ0ZXIgJHtmb3JtYXREdXJhdGlvbihwYXJhbXMuZWxhcHNlZEluTWlsbGlzZWNvbmRzKX1gO1xuICBjb25zdCBzdWJqZWN0ID0gYFxcYCR7cGFyYW1zLmNvbW1hbmR9XFxgIChhc2tpbmcgd2hvIGxpc3RlbnMgb24gcG9ydCAke1N0cmluZyhwYXJhbXMucG9ydCl9KWA7XG4gIGNvbnN0IGNvbnNlcXVlbmNlID0gYE5vdGhpbmcgaXMga25vd24gYWJvdXQgd2hhdCBzdGlsbCBob2xkcyBwb3J0ICR7U3RyaW5nKHBhcmFtcy5wb3J0KX0sIHNvIHRoZSBlc2NhbGF0aW9uIGhhcyBubyBQSUQgdG8ga2lsbCBcdTIwMTQgdGhpcyBpcyBub3QgdGhlIHNhbWUgYXMgbm90aGluZyBob2xkaW5nIGl0LmA7XG5cbiAgc3dpdGNoIChwYXJhbXMub3V0Y29tZSkge1xuICAgIGNhc2UgJ2Fuc3dlcmVkJzoge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY2FzZSAnY3Jhc2hlZCc6IHtcbiAgICAgIHJldHVybiBgV2FybmluZzogJHtzdWJqZWN0fSBkaWVkICR7Y29zdH0gd2l0aG91dCBleHBsYWluaW5nIGl0c2VsZiAoZXhpdCAke2Zvcm1hdEV4aXRDb2RlKHBhcmFtcy5leGl0Q29kZSl9LCBub3RoaW5nIG9uIHN0ZGVycikuIFN1c3BlY3QgYSBjcmFzaCBvciBhbiBpbnRlcmZlcmluZyBzZWN1cml0eSBwcm9kdWN0LCBhbmQgdHJ5IHRoZSBjb21tYW5kIGJ5IGhhbmQuICR7Y29uc2VxdWVuY2V9YDtcbiAgICB9XG4gICAgY2FzZSAnbm90LWZvdW5kJzoge1xuICAgICAgcmV0dXJuIGBXYXJuaW5nOiAke3N1YmplY3R9IGNvdWxkIG5vdCBiZSBydW4gYXQgYWxsICR7Y29zdH06IHRoZSBleGVjdXRhYmxlIHdhcyBub3QgZm91bmQgb24gUEFUSC4gJHtjb25zZXF1ZW5jZX1gO1xuICAgIH1cbiAgICBjYXNlICdvdXRwdXQtb3ZlcnJhbic6IHtcbiAgICAgIHJldHVybiBgV2FybmluZzogJHtzdWJqZWN0fSBwcm9kdWNlZCBtb3JlIG91dHB1dCAke2Nvc3R9IHRoYW4gdGhlIHF1ZXJ5J3MgYnVmZmVyIGFsbG93cywgc28gbm9uZSBvZiBpdCBjb3VsZCBiZSByZWFkLiBSYWlzZSB0aGUgYnVmZmVyLiAke2NvbnNlcXVlbmNlfWA7XG4gICAgfVxuICAgIGNhc2UgJ3JlZnVzZWQnOiB7XG4gICAgICByZXR1cm4gYFdhcm5pbmc6ICR7c3ViamVjdH0gcmVmdXNlZCB0aGUgcmVxdWVzdCAke2Nvc3R9IChleGl0ICR7Zm9ybWF0RXhpdENvZGUocGFyYW1zLmV4aXRDb2RlKX0pOiAke2Zvcm1hdFJlZnVzYWwocGFyYW1zLnN0YW5kYXJkRXJyb3IpfSAke2NvbnNlcXVlbmNlfWA7XG4gICAgfVxuICAgIGNhc2UgJ3RpbWVkLW91dCc6IHtcbiAgICAgIHJldHVybiBgV2FybmluZzogJHtzdWJqZWN0fSBkaWQgbm90IGZpbmlzaCB3aXRoaW4gaXRzICR7Zm9ybWF0RHVyYXRpb24ocGFyYW1zLnRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9IGJ1ZGdldCBhbmQgd2FzIGtpbGxlZCAke2Nvc3R9JHtwYXJhbXMuc2lnbmFsID09PSBudWxsID8gJycgOiBgICgke3BhcmFtcy5zaWduYWx9KWB9LiAke2NvbnNlcXVlbmNlfWA7XG4gICAgfVxuICAgIGRlZmF1bHQ6IHtcbiAgICAgIHJldHVybiBhc3NlcnROZXZlcihwYXJhbXMub3V0Y29tZSk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogRXh0cmFjdHMgd2hhdCBhbiBgZXhlY0ZpbGVTeW5jYCB0aHJvdyBjYXJyaWVzLCBpbiBgZXhlY0ZpbGVgJ3Mgdm9jYWJ1bGFyeS5cbiAqXG4gKiBUaGUgc3luY2hyb25vdXMgQVBJIHJlcG9ydHMgdGhlIHNhbWUgZW5kaW5ncyB3aXRoIGRpZmZlcmVudCBmaWVsZHM6IGFuXG4gKiBleHBpcmVkIGJ1ZGdldCBpcyBgY29kZTogJ0VUSU1FRE9VVCdgIHJhdGhlciB0aGFuIGBraWxsZWQ6IHRydWVgLCBhbiBvdmVycnVuXG4gKiBidWZmZXIgaXMgYEVOT0JVRlNgLCBhbmQgdGhlIGV4aXQgY29kZSBpcyBgc3RhdHVzYCByYXRoZXIgdGhhbiBgY29kZWAuXG4gKiBOb3JtYWxpemluZyBoZXJlIGxldHMgdGhlIHN5bmMgdGVhcmRvd24gY2xhc3NpZnkgd2l0aCB0aGUgc2FtZSB2ZXJkaWN0IGFzIHRoZVxuICogYXN5bmMgb25lLlxuICpcbiAqIEBwYXJhbSBlcnJvciAtIFdoYXRldmVyIGBleGVjRmlsZVN5bmNgIHRocmV3LlxuICogQHJldHVybnMgVGhlIG5vcm1hbGl6ZWQgZmllbGRzOyBhbiB1bnJlY29nbml6YWJsZSB0aHJvdyByZWFkcyBhcyBhIGNyYXNoIHdpdGggbm8gZXZpZGVuY2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVTeW5jRXhlY0Vycm9yKGVycm9yOiB1bmtub3duKTogTm9ybWFsaXplZFN5bmNFeGVjRXJyb3Ige1xuICBjb25zdCByZWNvcmQgPSB0eXBlb2YgZXJyb3IgPT09ICdvYmplY3QnICYmIGVycm9yICE9PSBudWxsID8gZXJyb3IgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gOiB7fTtcbiAgY29uc3QgY29kZSA9IHR5cGVvZiByZWNvcmRbJ2NvZGUnXSA9PT0gJ3N0cmluZycgPyByZWNvcmRbJ2NvZGUnXSA6IHVuZGVmaW5lZDtcbiAgY29uc3Qgc3RhdHVzID0gdHlwZW9mIHJlY29yZFsnc3RhdHVzJ10gPT09ICdudW1iZXInID8gcmVjb3JkWydzdGF0dXMnXSA6IG51bGw7XG4gIGNvbnN0IHNpZ25hbCA9IHR5cGVvZiByZWNvcmRbJ3NpZ25hbCddID09PSAnc3RyaW5nJyA/IHJlY29yZFsnc2lnbmFsJ10gOiBudWxsO1xuICBjb25zdCBpc0tpbGxlZCA9IGNvZGUgPT09ICdFVElNRURPVVQnO1xuXG4gIGxldCBlcnJvckNvZGU6IG51bGwgfCBudW1iZXIgfCBzdHJpbmcgPSBzdGF0dXM7XG4gIGlmIChjb2RlID09PSAnRU5PQlVGUycpIHtcbiAgICBlcnJvckNvZGUgPSAnRVJSX0NISUxEX1BST0NFU1NfU1RESU9fTUFYQlVGRkVSJztcbiAgfSBlbHNlIGlmIChjb2RlICE9PSB1bmRlZmluZWQgJiYgIWlzS2lsbGVkKSB7XG4gICAgZXJyb3JDb2RlID0gY29kZTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZXJyb3JDb2RlLFxuICAgIGV4aXRDb2RlOiBzdGF0dXMsXG4gICAgaXNLaWxsZWQsXG4gICAgc2lnbmFsLFxuICAgIHN0YW5kYXJkRXJyb3I6IHRvVGV4dChyZWNvcmRbJ3N0ZGVyciddKSxcbiAgICBzdGFuZGFyZE91dHB1dDogdG9UZXh0KHJlY29yZFsnc3Rkb3V0J10pXG4gIH07XG59XG5cbi8qKlxuICogRGVjaWRlcyBob3cgdGhlIHBvcnQtb3duZXIgcXVlcnkgZW5kZWQuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFdoYXQgYGV4ZWNGaWxlYCByZXBvcnRlZCwgYW5kIHRoZSBwbGF0Zm9ybSBpdCByYW4gb24uXG4gKiBAcmV0dXJucyBUaGUgb3V0Y29tZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVQb3J0T3duZXJRdWVyeU91dGNvbWUocGFyYW1zOiBSZXNvbHZlUG9ydE93bmVyUXVlcnlPdXRjb21lUGFyYW1zKTogUG9ydE93bmVyUXVlcnlPdXRjb21lIHtcbiAgcmV0dXJuICFwYXJhbXMuaGFzRmFpbGVkIHx8IChwYXJhbXMucGxhdGZvcm0gIT09ICd3aW4zMidcbiAgICAgICYmICFwYXJhbXMuaXNLaWxsZWRcbiAgICAgICYmIHBhcmFtcy5lcnJvckNvZGUgPT09IExTT0ZfTk9USElOR19GT1VORF9FWElUX0NPREVcbiAgICAgICYmIHBhcmFtcy5zdGFuZGFyZEVycm9yLnRyaW0oKSA9PT0gJydcbiAgICAgICYmIHBhcmFtcy5zdGFuZGFyZE91dHB1dC50cmltKCkgPT09ICcnKVxuICAgID8gJ2Fuc3dlcmVkJ1xuICAgIDogcmVzb2x2ZUhvc3RRdWVyeUZhaWx1cmUocGFyYW1zKTtcbn1cblxuLyoqXG4gKiBSZWFkcyBhIGNoaWxkJ3MgY2FwdHVyZWQgc3RyZWFtLCB3aGljaGV2ZXIgZm9ybSBgZXhlY0ZpbGVTeW5jYCBsZWZ0IGl0IGluLlxuICpcbiAqIEBwYXJhbSBzdHJlYW0gLSBBIHN0cmluZywgYSBgQnVmZmVyYCwgb3Igbm90aGluZy5cbiAqIEByZXR1cm5zIFRoZSB0ZXh0LCBvciBhbiBlbXB0eSBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIHRvVGV4dChzdHJlYW06IHVua25vd24pOiBzdHJpbmcge1xuICBpZiAodHlwZW9mIHN0cmVhbSA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gc3RyZWFtO1xuICB9XG5cbiAgcmV0dXJuIEJ1ZmZlci5pc0J1ZmZlcihzdHJlYW0pID8gc3RyZWFtLnRvU3RyaW5nKCd1dGYtOCcpIDogJyc7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQWdDQSx5QkFBdUI7QUFJdkIsd0NBS087QUFDUCx5QkFBNEI7QUFLNUIsTUFBTSwrQkFBK0I7QUFtSTlCLFNBQVMsMkJBQTJCLFFBQThEO0FBQ3ZHLFFBQU0sT0FBTyxhQUFTLGtEQUFlLE9BQU8scUJBQXFCLENBQUM7QUFDbEUsUUFBTSxVQUFVLEtBQUssT0FBTyxPQUFPLGtDQUFrQyxPQUFPLE9BQU8sSUFBSSxDQUFDO0FBQ3hGLFFBQU0sY0FBYyxnREFBZ0QsT0FBTyxPQUFPLElBQUksQ0FBQztBQUV2RixVQUFRLE9BQU8sU0FBUztBQUFBLElBQ3RCLEtBQUssWUFBWTtBQUNmLGFBQU87QUFBQSxJQUNUO0FBQUEsSUFDQSxLQUFLLFdBQVc7QUFDZCxhQUFPLFlBQVksT0FBTyxTQUFTLElBQUksd0NBQW9DLGtEQUFlLE9BQU8sUUFBUSxDQUFDLDBHQUEwRyxXQUFXO0FBQUEsSUFDak87QUFBQSxJQUNBLEtBQUssYUFBYTtBQUNoQixhQUFPLFlBQVksT0FBTyw0QkFBNEIsSUFBSSwyQ0FBMkMsV0FBVztBQUFBLElBQ2xIO0FBQUEsSUFDQSxLQUFLLGtCQUFrQjtBQUNyQixhQUFPLFlBQVksT0FBTyx5QkFBeUIsSUFBSSxtRkFBbUYsV0FBVztBQUFBLElBQ3ZKO0FBQUEsSUFDQSxLQUFLLFdBQVc7QUFDZCxhQUFPLFlBQVksT0FBTyx3QkFBd0IsSUFBSSxjQUFVLGtEQUFlLE9BQU8sUUFBUSxDQUFDLFVBQU0saURBQWMsT0FBTyxhQUFhLENBQUMsSUFBSSxXQUFXO0FBQUEsSUFDeko7QUFBQSxJQUNBLEtBQUssYUFBYTtBQUNoQixhQUFPLFlBQVksT0FBTyxrQ0FBOEIsa0RBQWUsT0FBTyxxQkFBcUIsQ0FBQywwQkFBMEIsSUFBSSxHQUFHLE9BQU8sV0FBVyxPQUFPLEtBQUssS0FBSyxPQUFPLE1BQU0sR0FBRyxLQUFLLFdBQVc7QUFBQSxJQUMxTTtBQUFBLElBQ0EsU0FBUztBQUNQLGlCQUFPLGdDQUFZLE9BQU8sT0FBTztBQUFBLElBQ25DO0FBQUEsRUFDRjtBQUNGO0FBY08sU0FBUyx1QkFBdUIsT0FBeUM7QUFDOUUsUUFBTSxTQUFTLE9BQU8sVUFBVSxZQUFZLFVBQVUsT0FBTyxRQUFtQyxDQUFDO0FBQ2pHLFFBQU0sT0FBTyxPQUFPLE9BQU8sTUFBTSxNQUFNLFdBQVcsT0FBTyxNQUFNLElBQUk7QUFDbkUsUUFBTSxTQUFTLE9BQU8sT0FBTyxRQUFRLE1BQU0sV0FBVyxPQUFPLFFBQVEsSUFBSTtBQUN6RSxRQUFNLFNBQVMsT0FBTyxPQUFPLFFBQVEsTUFBTSxXQUFXLE9BQU8sUUFBUSxJQUFJO0FBQ3pFLFFBQU0sV0FBVyxTQUFTO0FBRTFCLE1BQUksWUFBb0M7QUFDeEMsTUFBSSxTQUFTLFdBQVc7QUFDdEIsZ0JBQVk7QUFBQSxFQUNkLFdBQVcsU0FBUyxVQUFhLENBQUMsVUFBVTtBQUMxQyxnQkFBWTtBQUFBLEVBQ2Q7QUFFQSxTQUFPO0FBQUEsSUFDTDtBQUFBLElBQ0EsVUFBVTtBQUFBLElBQ1Y7QUFBQSxJQUNBO0FBQUEsSUFDQSxlQUFlLE9BQU8sT0FBTyxRQUFRLENBQUM7QUFBQSxJQUN0QyxnQkFBZ0IsT0FBTyxPQUFPLFFBQVEsQ0FBQztBQUFBLEVBQ3pDO0FBQ0Y7QUFRTyxTQUFTLDZCQUE2QixRQUFtRTtBQUM5RyxTQUFPLENBQUMsT0FBTyxhQUFjLE9BQU8sYUFBYSxXQUMxQyxDQUFDLE9BQU8sWUFDUixPQUFPLGNBQWMsZ0NBQ3JCLE9BQU8sY0FBYyxLQUFLLE1BQU0sTUFDaEMsT0FBTyxlQUFlLEtBQUssTUFBTSxLQUNwQyxpQkFDQSwyREFBd0IsTUFBTTtBQUNwQztBQVFBLFNBQVMsT0FBTyxRQUF5QjtBQUN2QyxNQUFJLE9BQU8sV0FBVyxVQUFVO0FBQzlCLFdBQU87QUFBQSxFQUNUO0FBRUEsU0FBTywwQkFBTyxTQUFTLE1BQU0sSUFBSSxPQUFPLFNBQVMsT0FBTyxJQUFJO0FBQzlEOyIsCiAgIm5hbWVzIjogW10KfQo=