obsidian-integration-testing 12.1.2 → 12.3.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 (90) hide show
  1. package/README.md +1 -5
  2. package/dist/lib/cjs/app-config.cjs +137 -0
  3. package/dist/lib/cjs/app-config.d.cts +190 -0
  4. package/dist/lib/cjs/appium-session-config.cjs +7 -1
  5. package/dist/lib/cjs/appium-session-config.d.cts +20 -0
  6. package/dist/lib/cjs/cdp-command-timeout-error.cjs +50 -0
  7. package/dist/lib/cjs/cdp-command-timeout-error.d.cts +48 -0
  8. package/dist/lib/cjs/connect-to-cdp.cjs +1 -1
  9. package/dist/lib/cjs/connect-to-cdp.d.cts +5 -0
  10. package/dist/lib/cjs/emulator-arguments.cjs +19 -3
  11. package/dist/lib/cjs/emulator-arguments.d.cts +44 -0
  12. package/dist/lib/cjs/emulator-device-id.cjs +1 -1
  13. package/dist/lib/cjs/emulator-device-id.d.cts +7 -6
  14. package/dist/lib/cjs/emulator-marker.cjs +169 -0
  15. package/dist/lib/cjs/emulator-marker.d.cts +224 -0
  16. package/dist/lib/cjs/emulator-reaper.cjs +248 -0
  17. package/dist/lib/cjs/emulator-reaper.d.cts +225 -0
  18. package/dist/lib/cjs/emulator-reclaim.cjs +312 -0
  19. package/dist/lib/cjs/emulator-reclaim.d.cts +179 -0
  20. package/dist/lib/cjs/eval-cap-exceeded-error.cjs +61 -0
  21. package/dist/lib/cjs/eval-cap-exceeded-error.d.cts +92 -0
  22. package/dist/lib/cjs/eval-cap.cjs +29 -0
  23. package/dist/lib/cjs/eval-cap.d.cts +43 -0
  24. package/dist/lib/cjs/global-setup-core.cjs +2 -3
  25. package/dist/lib/cjs/index.cjs +21 -1
  26. package/dist/lib/cjs/index.d.cts +7 -0
  27. package/dist/lib/cjs/library.cjs +1 -1
  28. package/dist/lib/cjs/poll-in-obsidian.cjs +1 -1
  29. package/dist/lib/cjs/poll-in-obsidian.d.cts +7 -2
  30. package/dist/lib/cjs/setup-lock.cjs +56 -8
  31. package/dist/lib/cjs/setup-lock.d.cts +53 -0
  32. package/dist/lib/cjs/soft-keyboard-geometry.cjs +17 -8
  33. package/dist/lib/cjs/soft-keyboard-geometry.d.cts +46 -9
  34. package/dist/lib/cjs/soft-keyboard.cjs +7 -4
  35. package/dist/lib/cjs/soft-keyboard.d.cts +16 -2
  36. package/dist/lib/cjs/transport-appium.cjs +70 -5
  37. package/dist/lib/cjs/transport-appium.d.cts +35 -0
  38. package/dist/lib/cjs/transport-desktop-cdp.cjs +98 -19
  39. package/dist/lib/cjs/transport-desktop-cdp.d.cts +44 -1
  40. package/dist/lib/cjs/transport-factory.cjs +297 -190
  41. package/dist/lib/cjs/transport-factory.d.cts +15 -0
  42. package/dist/lib/cjs/transport-options.cjs +1 -1
  43. package/dist/lib/cjs/transport-options.d.cts +38 -1
  44. package/dist/lib/cjs/webview-cdp.cjs +45 -14
  45. package/dist/lib/cjs/webview-cdp.d.cts +17 -0
  46. package/dist/lib/esm/app-config.d.mts +190 -0
  47. package/dist/lib/esm/app-config.mjs +110 -0
  48. package/dist/lib/esm/appium-session-config.d.mts +20 -0
  49. package/dist/lib/esm/appium-session-config.mjs +6 -1
  50. package/dist/lib/esm/cdp-command-timeout-error.d.mts +48 -0
  51. package/dist/lib/esm/cdp-command-timeout-error.mjs +26 -0
  52. package/dist/lib/esm/connect-to-cdp.d.mts +5 -0
  53. package/dist/lib/esm/connect-to-cdp.mjs +1 -1
  54. package/dist/lib/esm/emulator-arguments.d.mts +44 -0
  55. package/dist/lib/esm/emulator-arguments.mjs +16 -2
  56. package/dist/lib/esm/emulator-device-id.d.mts +7 -6
  57. package/dist/lib/esm/emulator-device-id.mjs +1 -1
  58. package/dist/lib/esm/emulator-marker.d.mts +224 -0
  59. package/dist/lib/esm/emulator-marker.mjs +134 -0
  60. package/dist/lib/esm/emulator-reaper.d.mts +225 -0
  61. package/dist/lib/esm/emulator-reaper.mjs +211 -0
  62. package/dist/lib/esm/emulator-reclaim.d.mts +179 -0
  63. package/dist/lib/esm/emulator-reclaim.mjs +291 -0
  64. package/dist/lib/esm/eval-cap-exceeded-error.d.mts +92 -0
  65. package/dist/lib/esm/eval-cap-exceeded-error.mjs +36 -0
  66. package/dist/lib/esm/eval-cap.d.mts +43 -0
  67. package/dist/lib/esm/eval-cap.mjs +5 -0
  68. package/dist/lib/esm/global-setup-core.mjs +6 -4
  69. package/dist/lib/esm/index.d.mts +7 -0
  70. package/dist/lib/esm/index.mjs +21 -1
  71. package/dist/lib/esm/library.mjs +1 -1
  72. package/dist/lib/esm/poll-in-obsidian.d.mts +7 -2
  73. package/dist/lib/esm/poll-in-obsidian.mjs +1 -1
  74. package/dist/lib/esm/setup-lock.d.mts +53 -0
  75. package/dist/lib/esm/setup-lock.mjs +52 -7
  76. package/dist/lib/esm/soft-keyboard-geometry.d.mts +46 -9
  77. package/dist/lib/esm/soft-keyboard-geometry.mjs +17 -8
  78. package/dist/lib/esm/soft-keyboard.d.mts +16 -2
  79. package/dist/lib/esm/soft-keyboard.mjs +7 -4
  80. package/dist/lib/esm/transport-appium.d.mts +35 -0
  81. package/dist/lib/esm/transport-appium.mjs +73 -5
  82. package/dist/lib/esm/transport-desktop-cdp.d.mts +44 -1
  83. package/dist/lib/esm/transport-desktop-cdp.mjs +98 -19
  84. package/dist/lib/esm/transport-factory.d.mts +15 -0
  85. package/dist/lib/esm/transport-factory.mjs +305 -184
  86. package/dist/lib/esm/transport-options.d.mts +38 -1
  87. package/dist/lib/esm/transport-options.mjs +1 -1
  88. package/dist/lib/esm/webview-cdp.d.mts +17 -0
  89. package/dist/lib/esm/webview-cdp.mjs +45 -14
  90. package/package.json +4 -4
@@ -0,0 +1,224 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * Records which emulator this harness started for an AVD, so the emulator
5
+ * stays **the harness's** until a stop of it has been verified — whichever run,
6
+ * or whichever process of a run, gets to that stop.
7
+ *
8
+ * Ownership used to live only in the memory of the run that launched the
9
+ * emulator, and three ordinary things lose that memory:
10
+ *
11
+ * - **The launching process is a test worker.** A project with no transport
12
+ * global setup creates its transport — and auto-starts its emulator — inside a
13
+ * Vitest worker, and Vitest ends workers abruptly, so the worker's teardown
14
+ * never gets a turn. The project's own global teardown runs, but held no
15
+ * handle to the emulator. This repo's `integration-tests:android`
16
+ * project is exactly this, and on 2026-09-10 the emulator it left idle kept
17
+ * `netsimd` writing until a 278 GB log filled the drive (**L56**).
18
+ * - **The runner is killed** — SIGKILL, Task Manager, an IDE stop button — and
19
+ * neither teardown path runs at all.
20
+ * - **A later run adopts the leftover.** A device this run did not start is
21
+ * correctly not this run's to stop — which, without a record, made every
22
+ * leftover nobody's to stop, for ever.
23
+ *
24
+ * The marker is the record: a small JSON sentinel per AVD next to the setup lock,
25
+ * written from the moment the emulator is launched and removed only by a verified
26
+ * stop. It is deliberately tolerant — a missing, unreadable or mismatched marker
27
+ * reads as "not ours", the same answer the harness gave before markers existed.
28
+ *
29
+ * **It records a launch, not a booted emulator**, and that is the difference
30
+ * between covering the third case above and covering it only after the ~45s a
31
+ * cold boot takes. A launch-time marker names the `emulator` launcher alone and
32
+ * no device yet; the device id arrives when one appears, and the QEMU backend's
33
+ * PID once the boot completes. Each write keeps the original launch time, so the
34
+ * reaper armed by the first still recognizes the last as the same emulator.
35
+ *
36
+ * What makes a marker's emulator ours is evidence, not the file: at least one
37
+ * PID it records must still be a **live emulator process** on the host (the
38
+ * caller intersects with the process listing, not a bare signal-0 probe), so a
39
+ * recycled PID or an emulator somebody booted by hand is never mistaken for one
40
+ * this harness started. A launch-time marker satisfies that as written, because
41
+ * `emulator-backend.ts` counts the `emulator` launcher as one of the emulator
42
+ * processes — which is why phasing the marker needed no change to the verdict.
43
+ */
44
+ /**
45
+ * Identifies the emulator this harness started for an AVD.
46
+ */
47
+ export interface EmulatorMarker {
48
+ /**
49
+ The AVD the emulator is running.
50
+ */
51
+ readonly avdName: string;
52
+ /**
53
+ * The adb serial of the device it serves, e.g. `emulator-5554`. Absent while
54
+ * the emulator is still booting and no device has appeared yet — a marker is
55
+ * written from the launch, before there is anything to name.
56
+ */
57
+ readonly deviceId?: string | undefined;
58
+ /**
59
+ * The emulator processes the harness owns: the launcher plus the QEMU backend
60
+ * it forked — or, until the device appears, the launcher alone.
61
+ */
62
+ readonly ownedEmulatorPids: readonly number[];
63
+ /**
64
+ * PID of the harness process responsible for stopping the emulator — the one
65
+ * that started it, or the one that later took it over as a leftover.
66
+ */
67
+ readonly ownerPid: number;
68
+ /**
69
+ * The emulator processes that were already running when this launch spawned
70
+ * its own — present only while the record is still provisional, i.e. before
71
+ * the backend's own PID is known.
72
+ *
73
+ * It is what makes a launch-time marker convictable at all. Killing the
74
+ * launcher does **not** kill the `qemu-system-*-headless` backend it forked
75
+ * (**L46**), so a record naming the launcher alone goes stale over an
76
+ * emulator that is still running — the leak this marker exists to prevent.
77
+ * With the snapshot, anything in the host's emulator listing that is not in
78
+ * it was forked by this launch, which is the same pre-launch diff the
79
+ * successful path uses (`emulator-backend.ts`) and the same one **L46**
80
+ * requires instead of a `qemu*` sweep.
81
+ */
82
+ readonly preLaunchEmulatorPids?: readonly number[] | undefined;
83
+ /**
84
+ When the emulator was started (`Date.now()` epoch milliseconds).
85
+ */
86
+ readonly startedAtInMilliseconds: number;
87
+ }
88
+ /**
89
+ * What a marker says about the emulator it describes.
90
+ *
91
+ * - `harness-leftover` — ours, and no live harness process is responsible for
92
+ * it: the caller may take it over or stop it.
93
+ * - `in-use-by-live-run` — ours, but another live harness process owns it.
94
+ * - `stale-marker` — none of its PIDs is a live emulator any more; the marker
95
+ * outlived its emulator and proves nothing.
96
+ */
97
+ export type EmulatorMarkerVerdict = 'harness-leftover' | 'in-use-by-live-run' | 'stale-marker';
98
+ /**
99
+ * Parameters for {@link resolveEmulatorMarkerVerdict}.
100
+ */
101
+ export interface ResolveEmulatorMarkerVerdictParams {
102
+ /**
103
+ PID of the process asking.
104
+ */
105
+ readonly currentPid: number;
106
+ /**
107
+ Whether the marker's owner process is still running.
108
+ */
109
+ readonly isOwnerAlive: boolean;
110
+ /**
111
+ The emulator processes currently running on the host.
112
+ */
113
+ readonly liveEmulatorPids: readonly number[];
114
+ /**
115
+ The marker to judge.
116
+ */
117
+ readonly marker: EmulatorMarker;
118
+ }
119
+ /**
120
+ * Parameters for {@link writeEmulatorMarker}.
121
+ */
122
+ export interface WriteEmulatorMarkerParams {
123
+ /**
124
+ The AVD the emulator is running.
125
+ */
126
+ readonly avdName: string;
127
+ /**
128
+ The adb serial of the device it serves; omitted while the emulator is still booting.
129
+ */
130
+ readonly deviceId?: string | undefined;
131
+ /**
132
+ The emulator processes the harness owns.
133
+ */
134
+ readonly ownedEmulatorPids: readonly number[];
135
+ /**
136
+ The emulator processes that predate this launch. Written only while the backend's own PID is not known yet.
137
+ */
138
+ readonly preLaunchEmulatorPids?: readonly number[] | undefined;
139
+ /**
140
+ When the emulator was launched; omitted → now. A takeover keeps the original launch time.
141
+ */
142
+ readonly startedAtInMilliseconds?: number | undefined;
143
+ }
144
+ /**
145
+ * Says whether a marker still names a process that is running.
146
+ *
147
+ * A signal-0 probe, not the emulator listing `resolveEmulatorMarkerVerdict`
148
+ * intersects with: this answers the cheap question "is there anything left of
149
+ * what this marker recorded", which is what deciding whether a marker may be
150
+ * overwritten or removed needs. Convicting one as another run's leftover is the
151
+ * stronger question, and costs a host process listing.
152
+ *
153
+ * @param marker - The marker, or `undefined` when there is none.
154
+ * @returns `true` when the marker records a PID that is still alive.
155
+ */
156
+ export declare function checkIsMarkedEmulatorRunning(marker: EmulatorMarker | undefined): boolean;
157
+ /**
158
+ * Removes the marker for an AVD. Called once its emulator is verifiably gone, so
159
+ * a later run cannot mistake a recycled PID for ours.
160
+ *
161
+ * @param avdName - The AVD name.
162
+ */
163
+ export declare function clearEmulatorMarker(avdName: string): void;
164
+ /**
165
+ * Removes the marker for an AVD once none of the processes it records is still
166
+ * running — the form a stop uses.
167
+ *
168
+ * A stop is verified against the PIDs **it** owned, which is not always the
169
+ * emulator the marker describes: a launch that died at once (the emulator's own
170
+ * `Running multiple emulators with the same AVD` FATAL) owns nothing, verifies
171
+ * trivially, and must not erase the record of an emulator that is still up.
172
+ *
173
+ * @param avdName - The AVD name.
174
+ */
175
+ export declare function clearEmulatorMarkerIfStopped(avdName: string): void;
176
+ /**
177
+ * Lists every emulator marker on this host.
178
+ *
179
+ * @returns The readable markers, in directory order.
180
+ */
181
+ export declare function listEmulatorMarkers(): EmulatorMarker[];
182
+ /**
183
+ * Reads the marker for an AVD.
184
+ *
185
+ * @param avdName - The AVD name.
186
+ * @returns The marker, or `undefined` when there is none, it is unreadable, or it describes another AVD.
187
+ */
188
+ export declare function readEmulatorMarker(avdName: string): EmulatorMarker | undefined;
189
+ /**
190
+ * Decides what a marker says about the emulator it describes.
191
+ *
192
+ * Evidence first: a marker none of whose PIDs is a live emulator is stale,
193
+ * whoever owns it. Only then does ownership matter — and a live owner that is
194
+ * not the caller keeps it, because that run will stop it itself.
195
+ *
196
+ * @param params - The marker, the host's live emulator PIDs, and who is asking.
197
+ * @returns The verdict.
198
+ */
199
+ export declare function resolveEmulatorMarkerVerdict(params: ResolveEmulatorMarkerVerdictParams): EmulatorMarkerVerdict;
200
+ /**
201
+ * Selects the emulator processes a marker convicts: the PIDs it records that
202
+ * are still running, plus — while the record is still provisional — whatever
203
+ * the launch it describes has forked since.
204
+ *
205
+ * The second half is what makes a launch-time marker usable. It names the
206
+ * launcher, and killing the launcher leaves the QEMU backend running
207
+ * (**L46**), so without the `preLaunchEmulatorPids` diff a stop would kill the
208
+ * one process that does not hold the AVD and the marker would then read as
209
+ * stale over a live emulator. The diff claims exactly what the successful path
210
+ * claims — the emulator processes that appeared across this launch — and never
211
+ * one that predates it.
212
+ *
213
+ * @param marker - The marker.
214
+ * @param liveEmulatorPids - The emulator processes currently running on the host.
215
+ * @returns The marked PIDs still running, in marker order, then any this launch forked, in listed order.
216
+ */
217
+ export declare function selectLiveMarkedPids(marker: EmulatorMarker, liveEmulatorPids: readonly number[]): number[];
218
+ /**
219
+ * Records that the current process is responsible for stopping an AVD's
220
+ * emulator — one it just started, or a leftover it is taking over.
221
+ *
222
+ * @param params - The emulator's AVD, device and PIDs.
223
+ */
224
+ export declare function writeEmulatorMarker(params: WriteEmulatorMarkerParams): void;
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var emulator_reaper_exports = {};
30
+ __export(emulator_reaper_exports, {
31
+ EMULATOR_REAPER_ENTRY_NAME: () => EMULATOR_REAPER_ENTRY_NAME,
32
+ EMULATOR_REAPER_LOCK_SILENCE_IN_MILLISECONDS: () => EMULATOR_REAPER_LOCK_SILENCE_IN_MILLISECONDS,
33
+ EMULATOR_REAPER_LOG_MAX_SIZE_IN_BYTES: () => EMULATOR_REAPER_LOG_MAX_SIZE_IN_BYTES,
34
+ EMULATOR_REAPER_POLL_INTERVAL_IN_MILLISECONDS: () => EMULATOR_REAPER_POLL_INTERVAL_IN_MILLISECONDS,
35
+ buildEmulatorReaperArguments: () => buildEmulatorReaperArguments,
36
+ buildEmulatorReaperBootstrap: () => buildEmulatorReaperBootstrap,
37
+ buildEmulatorReaperRelayBootstrap: () => buildEmulatorReaperRelayBootstrap,
38
+ parseEmulatorReaperArguments: () => parseEmulatorReaperArguments,
39
+ resolveEmulatorReaperLogOpenFlag: () => resolveEmulatorReaperLogOpenFlag,
40
+ resolveEmulatorReaperWatch: () => resolveEmulatorReaperWatch,
41
+ runEmulatorReaper: () => runEmulatorReaper,
42
+ spawnEmulatorReaper: () => spawnEmulatorReaper
43
+ });
44
+ module.exports = __toCommonJS(emulator_reaper_exports);
45
+ var import_node_child_process = require("node:child_process");
46
+ var import_node_fs = require("node:fs");
47
+ var import_node_os = require("node:os");
48
+ var import_node_path = require("node:path");
49
+ var import_node_process = __toESM(require("node:process"), 1);
50
+ var import_node_url = require("node:url");
51
+ var import_emulator_marker = require("./emulator-marker.cjs");
52
+ var import_emulator_reclaim = require("./emulator-reclaim.cjs");
53
+ var import_leftover_cleanup = require("./leftover-cleanup.cjs");
54
+ var import_log = require("./log.cjs");
55
+ var import_process_liveness = require("./process-liveness.cjs");
56
+ var import_setup_lock = require("./setup-lock.cjs");
57
+ const import_meta = {};
58
+ const EMULATOR_REAPER_POLL_INTERVAL_IN_MILLISECONDS = 5e3;
59
+ const EMULATOR_REAPER_LOCK_SILENCE_IN_MILLISECONDS = 18e5;
60
+ const EMULATOR_REAPER_LOG_MAX_SIZE_IN_BYTES = 1048576;
61
+ const EMULATOR_REAPER_ENTRY_NAME = "runEmulatorReaper";
62
+ const LOCK_LABEL = "emulator-reaper";
63
+ const REAPER_LOG_FILE_SUFFIX = ".emulator-reaper.log";
64
+ function buildEmulatorReaperArguments(reaperArguments) {
65
+ return [reaperArguments.avdName, String(reaperArguments.startedAtInMilliseconds)];
66
+ }
67
+ function buildEmulatorReaperBootstrap() {
68
+ return [
69
+ "import(process.argv[1]).then((reaperModule) => {",
70
+ ` const run = reaperModule.${EMULATOR_REAPER_ENTRY_NAME} ?? reaperModule.default.${EMULATOR_REAPER_ENTRY_NAME};`,
71
+ " return run(process.argv.slice(2));",
72
+ "}).catch((error) => {",
73
+ " console.error(error);",
74
+ " process.exitCode = 1;",
75
+ "});"
76
+ ].join("\n");
77
+ }
78
+ function buildEmulatorReaperRelayBootstrap() {
79
+ return [
80
+ 'const { spawn } = require("node:child_process");',
81
+ "try {",
82
+ ' const child = spawn(process.execPath, ["-e", process.argv[1], ...process.argv.slice(2)], {',
83
+ " detached: true,",
84
+ ' stdio: ["ignore", 1, 2],',
85
+ " windowsHide: true",
86
+ " });",
87
+ ' child.once("error", (error) => { console.error(error); });',
88
+ " child.unref();",
89
+ "} catch (error) {",
90
+ " console.error(error);",
91
+ " process.exitCode = 1;",
92
+ "}"
93
+ ].join("\n");
94
+ }
95
+ function parseEmulatorReaperArguments(argv) {
96
+ const [avdName, startedAtText, ...rest] = argv;
97
+ if (!avdName || startedAtText === void 0 || rest.length > 0) {
98
+ return void 0;
99
+ }
100
+ const startedAtInMilliseconds = Number(startedAtText);
101
+ if (!Number.isSafeInteger(startedAtInMilliseconds) || startedAtInMilliseconds <= 0) {
102
+ return void 0;
103
+ }
104
+ return { avdName, startedAtInMilliseconds };
105
+ }
106
+ function resolveEmulatorReaperLogOpenFlag(sizeInBytes) {
107
+ return sizeInBytes !== void 0 && sizeInBytes > EMULATOR_REAPER_LOG_MAX_SIZE_IN_BYTES ? "w" : "a";
108
+ }
109
+ function resolveEmulatorReaperWatch(params) {
110
+ const { marker } = params;
111
+ if (marker === void 0) {
112
+ return "emulator-stopped";
113
+ }
114
+ if (marker.startedAtInMilliseconds !== params.armedStartedAtInMilliseconds) {
115
+ return "superseded";
116
+ }
117
+ if (marker.preLaunchEmulatorPids !== void 0) {
118
+ return "watch";
119
+ }
120
+ return marker.ownedEmulatorPids.some((pid) => params.checkIsPidAlive(pid)) ? "watch" : "emulator-stopped";
121
+ }
122
+ async function runEmulatorReaper(argv) {
123
+ const reaperArguments = parseEmulatorReaperArguments(argv);
124
+ if (!reaperArguments) {
125
+ (0, import_log.log)(`[emulator-reaper] Refusing to run: expected <avdName> <startedAtInMilliseconds>, got ${JSON.stringify(argv)}.`);
126
+ import_node_process.default.exitCode = 1;
127
+ return;
128
+ }
129
+ const { avdName, startedAtInMilliseconds } = reaperArguments;
130
+ reaperLog(
131
+ `Watching the emulator started at ${new Date(startedAtInMilliseconds).toISOString()} (reaper PID ${String(import_node_process.default.pid)}); it is stopped once no Android run holds the '${import_setup_lock.ANDROID_SETUP_LOCK_SCOPE}' setup lock.`
132
+ );
133
+ for (; ; ) {
134
+ const verdict = readWatchVerdict(reaperArguments);
135
+ if (verdict !== "watch") {
136
+ reaperLog(describeExit(verdict));
137
+ return;
138
+ }
139
+ let lock;
140
+ try {
141
+ lock = (0, import_setup_lock.tryAcquireSetupLock)({
142
+ label: LOCK_LABEL,
143
+ scope: import_setup_lock.ANDROID_SETUP_LOCK_SCOPE,
144
+ staleAfterSilenceInMilliseconds: EMULATOR_REAPER_LOCK_SILENCE_IN_MILLISECONDS
145
+ });
146
+ } catch (error) {
147
+ reaperLog(`Giving up: the setup lock could not be read (${error instanceof Error ? error.message : String(error)}). The next Android run reclaims the emulator instead.`);
148
+ return;
149
+ }
150
+ if (lock) {
151
+ try {
152
+ const lockedVerdict = readWatchVerdict(reaperArguments);
153
+ if (lockedVerdict !== "watch") {
154
+ reaperLog(describeExit(lockedVerdict));
155
+ return;
156
+ }
157
+ reaperLog("No Android run holds the setup lock any more, so nothing is left to stop the emulator. Stopping the leftovers this harness started...");
158
+ await new import_emulator_reclaim.EmulatorReclaimer(reaperLog).reclaimLeftoverEmulators({ scope: "end-of-run" });
159
+ } finally {
160
+ lock.release();
161
+ }
162
+ return;
163
+ }
164
+ await new Promise((resolve) => {
165
+ setTimeout(resolve, EMULATOR_REAPER_POLL_INTERVAL_IN_MILLISECONDS);
166
+ });
167
+ }
168
+ function reaperLog(message) {
169
+ (0, import_log.log)(`[emulator-reaper:${avdName}] ${message}`);
170
+ }
171
+ }
172
+ function spawnEmulatorReaper(params) {
173
+ const { avdName } = params;
174
+ if (!(0, import_setup_lock.checkIsSetupLockHeld)(import_setup_lock.ANDROID_SETUP_LOCK_SCOPE)) {
175
+ params.log(
176
+ `No emulator reaper armed for AVD "${avdName}": no run holds the '${import_setup_lock.ANDROID_SETUP_LOCK_SCOPE}' setup lock, so a reaper could not tell this run ending from it being killed. If this process is killed, only the next Android run on this host stops the emulator.`
177
+ );
178
+ return;
179
+ }
180
+ const logFilePath = (0, import_node_path.join)(getReaperLogDirectory(), `${avdName}${REAPER_LOG_FILE_SUFFIX}`);
181
+ try {
182
+ (0, import_node_fs.mkdirSync)(getReaperLogDirectory(), { recursive: true });
183
+ const logFileDescriptor = (0, import_node_fs.openSync)(logFilePath, resolveEmulatorReaperLogOpenFlag(readFileSize(logFilePath)));
184
+ try {
185
+ const relay = (0, import_node_child_process.spawn)(
186
+ import_node_process.default.execPath,
187
+ [
188
+ "-e",
189
+ buildEmulatorReaperRelayBootstrap(),
190
+ buildEmulatorReaperBootstrap(),
191
+ resolveOwnModuleUrl(),
192
+ ...buildEmulatorReaperArguments({ avdName, startedAtInMilliseconds: params.startedAtInMilliseconds })
193
+ ],
194
+ { detached: true, stdio: ["ignore", logFileDescriptor, logFileDescriptor], windowsHide: true }
195
+ );
196
+ relay.once("error", (error) => {
197
+ params.log(`The emulator reaper relay for AVD "${avdName}" failed to start: ${error.message}`);
198
+ });
199
+ relay.unref();
200
+ params.log(
201
+ `Emulator reaper armed for AVD "${avdName}": if this run is killed \u2014 a process-tree kill included, since the reaper is started through a relay that exits at once \u2014 it stops the emulator once no Android run holds the '${import_setup_lock.ANDROID_SETUP_LOCK_SCOPE}' setup lock. Its PID is the first line of its log: ${logFilePath}`
202
+ );
203
+ } finally {
204
+ (0, import_node_fs.closeSync)(logFileDescriptor);
205
+ }
206
+ } catch (error) {
207
+ params.log(`Could not arm the emulator reaper for AVD "${avdName}": ${error instanceof Error ? error.message : String(error)}`);
208
+ }
209
+ }
210
+ function describeExit(verdict) {
211
+ return verdict === "superseded" ? "The marker now records a later emulator of this AVD, which has its own reaper; nothing left to watch." : "The emulator was stopped; nothing left to watch.";
212
+ }
213
+ function getReaperLogDirectory() {
214
+ return (0, import_node_path.join)((0, import_node_os.tmpdir)(), import_leftover_cleanup.HARNESS_TEMP_DIR_NAME);
215
+ }
216
+ function readFileSize(path) {
217
+ try {
218
+ return (0, import_node_fs.statSync)(path).size;
219
+ } catch {
220
+ return void 0;
221
+ }
222
+ }
223
+ function readWatchVerdict(reaperArguments) {
224
+ return resolveEmulatorReaperWatch({
225
+ armedStartedAtInMilliseconds: reaperArguments.startedAtInMilliseconds,
226
+ checkIsPidAlive: import_process_liveness.checkIsProcessAlive,
227
+ marker: (0, import_emulator_marker.readEmulatorMarker)(reaperArguments.avdName)
228
+ });
229
+ }
230
+ function resolveOwnModuleUrl() {
231
+ return typeof __filename === "string" ? (0, import_node_url.pathToFileURL)(__filename).href : import_meta.url;
232
+ }
233
+ // Annotate the CommonJS export names for ESM import in node:
234
+ 0 && (module.exports = {
235
+ EMULATOR_REAPER_ENTRY_NAME,
236
+ EMULATOR_REAPER_LOCK_SILENCE_IN_MILLISECONDS,
237
+ EMULATOR_REAPER_LOG_MAX_SIZE_IN_BYTES,
238
+ EMULATOR_REAPER_POLL_INTERVAL_IN_MILLISECONDS,
239
+ buildEmulatorReaperArguments,
240
+ buildEmulatorReaperBootstrap,
241
+ buildEmulatorReaperRelayBootstrap,
242
+ parseEmulatorReaperArguments,
243
+ resolveEmulatorReaperLogOpenFlag,
244
+ resolveEmulatorReaperWatch,
245
+ runEmulatorReaper,
246
+ spawnEmulatorReaper
247
+ });
248
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2VtdWxhdG9yLXJlYXBlci50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIFN0b3BzIGFuIGVtdWxhdG9yIHRoaXMgaGFybmVzcyBzdGFydGVkIG9uY2UgaXRzIHJ1biBpcyBnb25lIGZvciBnb29kIFx1MjAxNCB0aGVcbiAqIGNhc2Ugbm90aGluZyBlbHNlIGNvdmVycywgKipMNTYqKidzIHBhdGggQiB3aXRoIG5vIGxhdGVyIHJ1bjogdGhlIHJ1bm5lciBpc1xuICoga2lsbGVkIChTSUdLSUxMLCBUYXNrIE1hbmFnZXIsIGFuIElERSBzdG9wIGJ1dHRvbiksIG5vIHRlYXJkb3duIHJ1bnMsIGFuZCBub1xuICogb3RoZXIgQW5kcm9pZCBydW4gZXZlciBjb21lcyBhbG9uZyB0byByZWNsYWltIHRoZSBsZWZ0b3ZlciBmcm9tIGl0cyBtYXJrZXIuXG4gKiBPbiAyMDI2LTA5LTEwIGFuIGVtdWxhdG9yIGxlZnQgbGlrZSB0aGF0IGtlcHQgYG5ldHNpbWRgIHNwaW5uaW5nIGZvciBzaXggaG91cnMuXG4gKlxuICogVGhlIHJlYXBlciBpcyBhIHNtYWxsIGRldGFjaGVkIE5vZGUgcHJvY2VzcyBzcGF3bmVkIGJlc2lkZSBldmVyeSBlbXVsYXRvciB0aGVcbiAqIGhhcm5lc3Mgc3RhcnRzIG9yIHRha2VzIG92ZXIuIEl0IGhvbGRzIG5vIGhhbmRsZSB0byB0aGUgZW11bGF0b3IgYW5kIG5lZWRzXG4gKiBub25lOiB0aGUgbWFya2VyIChgZW11bGF0b3ItbWFya2VyLnRzYCkgc2F5cyB3aGF0IHRvIHN0b3AsIGFuZCB0aGUgdmVyaWZpZWRcbiAqIHN0b3AgKGBlbXVsYXRvci1yZWNsYWltLnRzYCkgaXMgdGhlIG9uZSB0aGUgcnVuJ3Mgb3duIHRlYXJkb3duIHVzZXMuXG4gKlxuICogIyMgSXQgd2F0Y2hlcyB0aGUgYGFuZHJvaWRgIHNldHVwIGxvY2ssIG5vdCB0aGUgcHJvY2VzcyB0aGF0IHN0YXJ0ZWQgaXRcbiAqXG4gKiBUaGUgcHJvY2VzcyB0aGF0IHN0YXJ0cyB0aGUgZW11bGF0b3IgaXMgbm90IGFsd2F5cyB0aGUgcnVuLiBBIHByb2plY3Qgd2l0aCBub1xuICogdHJhbnNwb3J0IGdsb2JhbCBzZXR1cCBib290cyBpdCBmcm9tIGEgKip0ZXN0IHdvcmtlcioqICgqKkw1NioqIHBhdGggQSksIGFuZFxuICogVml0ZXN0IGVuZHMgd29ya2VycyBkdXJpbmcgYSBwZXJmZWN0bHkgaGVhbHRoeSBydW4gXHUyMDE0IHNvIGEgcmVhcGVyIHRpZWQgdG8gaXRzXG4gKiBzcGF3bmVyJ3MgbGlmZXRpbWUgKHRoZSAqKkwzMyoqIGxpdmVuZXNzIHNvY2tldCwgdGhlIGZpcnN0IGlkZWEpIHdvdWxkIHN0b3BcbiAqIHRoZSBlbXVsYXRvciBtaWQtcnVuLCBvciByYWNlIHRoZSBuZXh0IHdvcmtlciB0YWtpbmcgaXQgb3Zlci4gVGhlIGBhbmRyb2lkYFxuICogc2V0dXAgbG9jayAoKipMNyoqKSBpcyBoZWxkIGJ5IHRoZSBydW4ncyBtYWluIHByb2Nlc3MgZm9yIHRoZSB3aG9sZSBydW4sIGFuZFxuICogaXRzIGhvbGRlciBiZWluZyBhbGl2ZSBpcyBleGFjdGx5IHdoYXQgXCJhbiBBbmRyb2lkIHJ1biBpcyBpbiBmbGlnaHRcIiBtZWFucy5cbiAqXG4gKiBTbyB0aGUgcmVhcGVyIHBvbGxzIHRoYXQgbG9jaywgYW5kIG9uY2UgaXQgY2FuICoqdGFrZSoqIGl0IFx1MjAxNCBubyBsaXZlIHJ1blxuICogaG9sZHMgaXQgXHUyMDE0IGl0IHN0b3BzIHRoZSBoYXJuZXNzJ3MgbGVmdG92ZXJzIHdoaWxlIGhvbGRpbmcgaXQsIHdoaWNoIGlzIHRoZVxuICogcHJlY29uZGl0aW9uIGV2ZXJ5IGxlZnRvdmVyIHN0b3AgZG9jdW1lbnRzOiBubyBydW4gY2FuIGFkb3B0IGFuIGVtdWxhdG9yIHRoYXRcbiAqIGlzIG1pZC1zaHV0ZG93bi4gVGhhdCBpcyBwcmVjaXNlbHkgd2hhdCB0aGUgbmV4dCBydW4ncyBwcmVmbGlnaHQgd291bGQgZG8sXG4gKiBkb25lIGF0IHRoZSBmaXJzdCBtb21lbnQgdGhhdCBydW4gY291bGQgaGF2ZSBkb25lIGl0LlxuICpcbiAqIEEgZGVhZCBzYW1lLWhvc3QgaG9sZGVyIGlzIGFiYW5kb25lZCBhdCBvbmNlLiBBIGxpdmUtUElEIGhvbGRlciB0aGF0IGhhcyBnb25lXG4gKiBzaWxlbnQgaXMgb25seSBhYmFuZG9uZWQgYWZ0ZXJcbiAqIHtAbGluayBFTVVMQVRPUl9SRUFQRVJfTE9DS19TSUxFTkNFX0lOX01JTExJU0VDT05EU30sIGZhciB3aWRlciB0aGFuIHRoZVxuICogdHdvIG1pbnV0ZXMgYSB3YWl0aW5nIHJ1biBzdGVhbHMgb246IGEgcmVhcGVyIGlzIGFsd2F5cyB3YWl0aW5nLCBzbyBhdCB0d29cbiAqIG1pbnV0ZXMgYSBsaXZlIHJ1biB0aGF0IGJsb2NrZWQgaXRzIGV2ZW50IGxvb3Agd291bGQgbG9zZSBpdHMgZW11bGF0b3IuXG4gKlxuICogIyMgRmFpbC1vcGVuLCBsaWtlIHRoZSByZW5kZXJlciB3YXRjaGRvZ1xuICpcbiAqIEEgcmVhcGVyIGlzIGFybWVkIG9ubHkgd2hlbiBhIGxpdmUgcnVuIGhvbGRzIHRoZSBsb2NrIGF0IHRoZSBtb21lbnQgdGhlXG4gKiBlbXVsYXRvciBpcyByZWNvcmRlZC4gQSBydW4gdGhhdCB0YWtlcyBubyBsb2NrIFx1MjAxNCBhIGhhbmQtd2lyZWRcbiAqIGBjcmVhdGVUcmFuc3BvcnRGcm9tT3B0aW9uc2AgXHUyMDE0IGdldHMgbm9uZSwgYW5kIHNheXMgc28sIHJhdGhlciB0aGFuIGEgcmVhcGVyXG4gKiB0aGF0IHdvdWxkIHJlYWQgaXRzIG1pc3NpbmcgbG9jayBhcyBcInRoZSBydW4gaXMgb3ZlclwiIGFuZCBzdG9wIGFuIGVtdWxhdG9yXG4gKiBzb21lYm9keSBpcyB1c2luZy4gQSBzcGF3biB0aGF0IGZhaWxzIGlzIGxvZ2dlZCBhbmQgbmV2ZXIgZmFpbHMgdGhlIGxhdW5jaC5cbiAqXG4gKiAjIyBIb3cgaXQgcnVuc1xuICpcbiAqIGBwcm9jZXNzLmV4ZWNQYXRoIC1lIDxib290c3RyYXA+IDx0aGlzIG1vZHVsZSdzIFVSTD4gPGF2ZE5hbWU+IDxzdGFydGVkQXQ+YDpcbiAqIHRoZSBib290c3RyYXAgYGltcG9ydCgpYHMgdGhpcyB2ZXJ5IG1vZHVsZSBhbmQgY2FsbHMge0BsaW5rIHJ1bkVtdWxhdG9yUmVhcGVyfS5cbiAqIFRoZSBVUkwgaXMgdGhlIGJ1aWx0IGAubWpzYCAvIGAuY2pzYCBpbiBhIGNvbnN1bWVyJ3MgaW5zdGFsbCwgYW5kIHRoZSBgLnRzYFxuICogc291cmNlIGluIHRoaXMgcmVwbydzIG93biBzdWl0ZXMsIHdoaWNoIE5vZGUncyB0eXBlIHN0cmlwcGluZyBydW5zIGFzLWlzIFx1MjAxNCBzb1xuICogbm90aGluZyB0aGlzIG1vZHVsZSBpbXBvcnRzIG1heSByZWFjaCBhIG1vZHVsZSB0aGF0IHJlYWRzIHRoZSBidWlsZC10aW1lXG4gKiBgT0JTSURJQU5fTUVUQURBVEFgIGdsb2JhbC4gSXRzIHN0ZG91dC9zdGRlcnIgZ28gdG8gYSBwZXItQVZEIGxvZyBmaWxlLCBjYXBwZWRcbiAqIGF0IHtAbGluayBFTVVMQVRPUl9SRUFQRVJfTE9HX01BWF9TSVpFX0lOX0JZVEVTfSwgc28gdGhlIHZlcmRpY3QgbGluZXMgdGhlIHN0b3BcbiAqIHByaW50cyBhcmUgb24gcmVjb3JkIGV2ZW4gdGhvdWdoIG5vIHRlcm1pbmFsIGlzIGxlZnQgdG8gc2hvdyB0aGVtLlxuICpcbiAqICMjIEl0IGlzIHN0YXJ0ZWQgdGhyb3VnaCBhIHJlbGF5LCBzbyBhIHByb2Nlc3MtdHJlZSBraWxsIGNhbm5vdCB0YWtlIGl0XG4gKlxuICogYGRldGFjaGVkYCBkb2VzIG5vdCByZXBhcmVudCBvbiBXaW5kb3dzOiBhIGNoaWxkIHNwYXduZWQgc3RyYWlnaHQgZnJvbSB0aGUgcnVuXG4gKiBzdGF5cyBpbiB0aGUgcnVuJ3MgcHJvY2VzcyB0cmVlLCBzbyB0aGUga2lsbCBzaGFwZXMgdGhhdCB3YWxrIHRoYXQgdHJlZSB0YWtlXG4gKiB0aGUgc2FmZXR5IG5ldCBhbG9uZyB3aXRoIHRoZSB0aGluZyBpdCB3YXMgZ3VhcmRpbmcgXHUyMDE0IFRhc2sgTWFuYWdlcidzICpFbmRcbiAqIHRhc2sqLCBgdGFza2tpbGwgL1RgLCBhbiBJREUgc3RvcCBidXR0b24sIGEgYFBhcmVudFByb2Nlc3NJZGAgZGVzY2VuZGFudFxuICogc3dlZXAuIE1lYXN1cmVkIG9uIDIwMjYtMDktMTE6IGEgcmVhcGVyIGRpZWQgd2l0aCB0aGUgcnVuIGl0IHdhcyB3YXRjaGluZywgYW5kXG4gKiB0aGUgZW11bGF0b3IgaXQgd291bGQgaGF2ZSBzdG9wcGVkIGlkbGVkIG9uIGZvciB0ZW4gbWludXRlcy5cbiAqXG4gKiBTbyB0aGUgc3Bhd24gZ29lcyB0aHJvdWdoIGEgcmVsYXkgXHUyMDE0IHtAbGluayBidWlsZEVtdWxhdG9yUmVhcGVyUmVsYXlCb290c3RyYXB9IFx1MjAxNFxuICogd2hpY2ggc3RhcnRzIHRoZSByZWFwZXIgYW5kIGV4aXRzIGF0IG9uY2UuIEJ5IHRoZSB0aW1lIGFueSB0cmVlLXdhbGtlciB0YWtlc1xuICogaXRzIHNuYXBzaG90IHRoZSByZWxheSBpcyBnb25lLCBzbyB0aGVyZSBpcyBubyBlZGdlIGZyb20gdGhlIHJ1biB0byB0aGUgcmVhcGVyXG4gKiBsZWZ0IHRvIGZvbGxvdy4gVGhpcyBpcyB0aGUgZG91YmxlLWZvcmsgaWRpb20sIGFuZCBpdCBob2xkcyBvbiBQT1NJWCBmb3IgdGhlXG4gKiBzYW1lIHJlYXNvbjogb25jZSB0aGUgcmVsYXkgZXhpdHMsIHRoZSByZWFwZXIgYmVsb25ncyB0byBgaW5pdGAuXG4gKi9cblxuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdub2RlOmNoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHtcbiAgY2xvc2VTeW5jLFxuICBta2RpclN5bmMsXG4gIG9wZW5TeW5jLFxuICBzdGF0U3luY1xufSBmcm9tICdub2RlOmZzJztcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gJ25vZGU6b3MnO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgcHJvY2VzcyBmcm9tICdub2RlOnByb2Nlc3MnO1xuaW1wb3J0IHsgcGF0aFRvRmlsZVVSTCB9IGZyb20gJ25vZGU6dXJsJztcblxuaW1wb3J0IHR5cGUgeyBFbXVsYXRvck1hcmtlciB9IGZyb20gJy4vZW11bGF0b3ItbWFya2VyLmNqcyc7XG5pbXBvcnQgdHlwZSB7IFNldHVwTG9jayB9IGZyb20gJy4vc2V0dXAtbG9jay5janMnO1xuXG5pbXBvcnQgeyByZWFkRW11bGF0b3JNYXJrZXIgfSBmcm9tICcuL2VtdWxhdG9yLW1hcmtlci5janMnO1xuaW1wb3J0IHsgRW11bGF0b3JSZWNsYWltZXIgfSBmcm9tICcuL2VtdWxhdG9yLXJlY2xhaW0uY2pzJztcbmltcG9ydCB7IEhBUk5FU1NfVEVNUF9ESVJfTkFNRSB9IGZyb20gJy4vbGVmdG92ZXItY2xlYW51cC5janMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2cuY2pzJztcbmltcG9ydCB7IGNoZWNrSXNQcm9jZXNzQWxpdmUgfSBmcm9tICcuL3Byb2Nlc3MtbGl2ZW5lc3MuY2pzJztcbmltcG9ydCB7XG4gIEFORFJPSURfU0VUVVBfTE9DS19TQ09QRSxcbiAgY2hlY2tJc1NldHVwTG9ja0hlbGQsXG4gIHRyeUFjcXVpcmVTZXR1cExvY2tcbn0gZnJvbSAnLi9zZXR1cC1sb2NrLmNqcyc7XG5cbi8qKlxuICogSG93IG9mdGVuIHRoZSByZWFwZXIgbG9va3MgYXQgdGhlIG1hcmtlciBhbmQgdGhlIGxvY2sgXHUyMDE0IHRoZSBsb2NrJ3Mgb3duXG4gKiBoZWFydGJlYXQgaW50ZXJ2YWwsIHNvIGEga2lsbGVkIHJ1biBpcyBub3RpY2VkIHdpdGhpbiBvbmUgYmVhdC5cbiAqL1xuZXhwb3J0IGNvbnN0IEVNVUxBVE9SX1JFQVBFUl9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyA9IDUwMDA7XG5cbi8qKlxuICogSG93IGxvbmcgYSBzYW1lLWhvc3QgbG9jayBob2xkZXIgd2hvc2UgUElEIGlzIHN0aWxsIGFsaXZlIG1heSBzdGF5IHNpbGVudFxuICogYmVmb3JlIHRoZSByZWFwZXIgdHJlYXRzIGl0cyBydW4gYXMgZ29uZTogMzAgbWludXRlcywgdGhlIHRocmVzaG9sZCB0aGUgbG9ja1xuICogYWxyZWFkeSB1c2VzIGFjcm9zcyBob3N0cy4gT25seSBhIHJlY3ljbGVkIFBJRCBzaG91bGQgZXZlciByZWFjaCBpdC5cbiAqL1xuZXhwb3J0IGNvbnN0IEVNVUxBVE9SX1JFQVBFUl9MT0NLX1NJTEVOQ0VfSU5fTUlMTElTRUNPTkRTID0gMV84MDBfMDAwO1xuXG4vKipcbiAqIFRoZSBzaXplIHBhc3Qgd2hpY2ggdGhlIHJlYXBlciBsb2cgaXMgc3RhcnRlZCBhZnJlc2ggcmF0aGVyIHRoYW4gYXBwZW5kZWQgdG8uXG4gKi9cbmV4cG9ydCBjb25zdCBFTVVMQVRPUl9SRUFQRVJfTE9HX01BWF9TSVpFX0lOX0JZVEVTID0gMV8wNDhfNTc2O1xuXG4vKipcbiAqIFRoZSBleHBvcnQgdGhlIGJvb3RzdHJhcCBjYWxscy4gTmFtZWQgaGVyZSBzbyB0aGUgYm9vdHN0cmFwIGFuZCB0aGUgZXhwb3J0XG4gKiBjYW5ub3QgZHJpZnQgYXBhcnQuXG4gKi9cbmV4cG9ydCBjb25zdCBFTVVMQVRPUl9SRUFQRVJfRU5UUllfTkFNRSA9ICdydW5FbXVsYXRvclJlYXBlcic7XG5cbmNvbnN0IExPQ0tfTEFCRUwgPSAnZW11bGF0b3ItcmVhcGVyJztcbmNvbnN0IFJFQVBFUl9MT0dfRklMRV9TVUZGSVggPSAnLmVtdWxhdG9yLXJlYXBlci5sb2cnO1xuXG4vKipcbiAqIFdoYXQgdGhlIHJlYXBlciB3YXRjaGVzIGZvcjogdGhlIGVtdWxhdG9yIGEgbWFya2VyIHJlY29yZGVkIHdoZW4gaXQgd2FzIGFybWVkLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVtdWxhdG9yUmVhcGVyQXJndW1lbnRzIHtcbiAgLyoqXG4gIFRoZSBBVkQgd2hvc2UgbWFya2VyIGl0IHdhdGNoZXMuXG4gICAqL1xuICByZWFkb25seSBhdmROYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFdoZW4gdGhlIHdhdGNoZWQgZW11bGF0b3Igd2FzIGxhdW5jaGVkLiBBIHRha2VvdmVyIGtlZXBzIGl0LCBzbyBpdCBuYW1lcyBvbmVcbiAgICogZW11bGF0b3IgYWNyb3NzIGV2ZXJ5IHJ1biB0aGF0IG93bnMgaXQsIGFuZCB0ZWxscyBhIGxhdGVyIGVtdWxhdG9yIG9mIHRoZVxuICAgKiBzYW1lIEFWRCBhcGFydC5cbiAgICovXG4gIHJlYWRvbmx5IHN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogV2hhdCB0aGUgbWFya2VyIHNheXMgdGhlIHJlYXBlciBzaG91bGQgZG8gbmV4dC5cbiAqXG4gKiAtIGBlbXVsYXRvci1zdG9wcGVkYCBcdTIwMTQgdGhlIG1hcmtlciBpcyBnb25lLCBvciBub25lIG9mIGl0cyBQSURzIGlzIGFsaXZlOiB0aGVcbiAqICAgZW11bGF0b3Igd2FzIHN0b3BwZWQsIHNvIHRoZXJlIGlzIG5vdGhpbmcgbGVmdCB0byB3YXRjaC5cbiAqIC0gYHN1cGVyc2VkZWRgIFx1MjAxNCB0aGUgbWFya2VyIG5vdyByZWNvcmRzIGEgZGlmZmVyZW50IGVtdWxhdG9yIG9mIHRoZSBzYW1lIEFWRCxcbiAqICAgd2hpY2ggaGFzIGl0cyBvd24gcmVhcGVyLlxuICogLSBgd2F0Y2hgIFx1MjAxNCB0aGUgZW11bGF0b3IgaXMgc3RpbGwgdXAuXG4gKi9cbmV4cG9ydCB0eXBlIEVtdWxhdG9yUmVhcGVyV2F0Y2hWZXJkaWN0ID0gJ2VtdWxhdG9yLXN0b3BwZWQnIHwgJ3N1cGVyc2VkZWQnIHwgJ3dhdGNoJztcblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciB7QGxpbmsgcmVzb2x2ZUVtdWxhdG9yUmVhcGVyV2F0Y2h9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVFbXVsYXRvclJlYXBlcldhdGNoUGFyYW1zIHtcbiAgLyoqXG4gIFRoZSBsYXVuY2ggdGltZSBvZiB0aGUgZW11bGF0b3IgdGhpcyByZWFwZXIgd2FzIGFybWVkIGZvci5cbiAgICovXG4gIHJlYWRvbmx5IGFybWVkU3RhcnRlZEF0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcblxuICAvKipcbiAgV2hldGhlciBhIFBJRCBpcyBzdGlsbCBydW5uaW5nLlxuICAgKi9cbiAgcmVhZG9ubHkgY2hlY2tJc1BpZEFsaXZlOiAocGlkOiBudW1iZXIpID0+IGJvb2xlYW47XG5cbiAgLyoqXG4gIFRoZSBBVkQncyBtYXJrZXIgYXMgaXQgcmVhZHMgbm93LCBpZiBhbnkuXG4gICAqL1xuICByZWFkb25seSBtYXJrZXI6IEVtdWxhdG9yTWFya2VyIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBzcGF3bkVtdWxhdG9yUmVhcGVyfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcGF3bkVtdWxhdG9yUmVhcGVyUGFyYW1zIHtcbiAgLyoqXG4gIFRoZSBBVkQgd2hvc2UgZW11bGF0b3Igd2FzIGp1c3QgcmVjb3JkZWQuXG4gICAqL1xuICByZWFkb25seSBhdmROYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFJlY2VpdmVzIHRoZSBhcm1lZCAvIG5vdC1hcm1lZCBsaW5lLlxuICAgKi9cbiAgcmVhZG9ubHkgbG9nOiAobWVzc2FnZTogc3RyaW5nKSA9PiB2b2lkO1xuXG4gIC8qKlxuICBUaGUgcmVjb3JkZWQgZW11bGF0b3IncyBsYXVuY2ggdGltZSwgYXMgd3JpdHRlbiBpbnRvIGl0cyBtYXJrZXIuXG4gICAqL1xuICByZWFkb25seSBzdGFydGVkQXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xufVxuXG4vKipcbiAqIEVuY29kZXMgdGhlIHJlYXBlcidzIGFyZ3VtZW50cyBmb3IgaXRzIGNvbW1hbmQgbGluZS5cbiAqXG4gKiBAcGFyYW0gcmVhcGVyQXJndW1lbnRzIC0gV2hhdCB0aGUgcmVhcGVyIHdhdGNoZXMgZm9yLlxuICogQHJldHVybnMgVGhlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMsIGluIHRoZSBvcmRlciB7QGxpbmsgcGFyc2VFbXVsYXRvclJlYXBlckFyZ3VtZW50c30gcmVhZHMgdGhlbS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkRW11bGF0b3JSZWFwZXJBcmd1bWVudHMocmVhcGVyQXJndW1lbnRzOiBFbXVsYXRvclJlYXBlckFyZ3VtZW50cyk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIFtyZWFwZXJBcmd1bWVudHMuYXZkTmFtZSwgU3RyaW5nKHJlYXBlckFyZ3VtZW50cy5zdGFydGVkQXRJbk1pbGxpc2Vjb25kcyldO1xufVxuXG4vKipcbiAqIEJ1aWxkcyB0aGUgc2NyaXB0IGBub2RlIC1lYCBydW5zIHRvIHN0YXJ0IHRoZSByZWFwZXIuXG4gKlxuICogSXQgYGltcG9ydCgpYHMgdGhlIG1vZHVsZSB3aG9zZSBVUkwgaXMgaXRzIGZpcnN0IGFyZ3VtZW50IGFuZCBoYW5kcyB0aGUgcmVzdFxuICogdG8ge0BsaW5rIHJ1bkVtdWxhdG9yUmVhcGVyfS4gYGltcG9ydCgpYCByYXRoZXIgdGhhbiBgcmVxdWlyZWAsIGJlY2F1c2UgaXRcbiAqIGxvYWRzIGFsbCB0aHJlZSBmb3JtcyB0aGUgbW9kdWxlIHNoaXBzIGFzIFx1MjAxNCBFU00sIENKUywgYW5kIHRoaXMgcmVwbydzIG93blxuICogYC50c2Agc291cmNlIHVuZGVyIE5vZGUncyB0eXBlIHN0cmlwcGluZy4gQSBDSlMgbW9kdWxlJ3MgbmFtZWQgZXhwb3J0cyBhcmVcbiAqIGZvdW5kIGJ5IE5vZGUncyBzdGF0aWMgYW5hbHlzaXM7IGBkZWZhdWx0YCBpcyB0aGUgZmFsbGJhY2sgd2hlbiB0aGV5IGFyZSBub3QuXG4gKlxuICogQHJldHVybnMgVGhlIHNjcmlwdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkRW11bGF0b3JSZWFwZXJCb290c3RyYXAoKTogc3RyaW5nIHtcbiAgcmV0dXJuIFtcbiAgICAnaW1wb3J0KHByb2Nlc3MuYXJndlsxXSkudGhlbigocmVhcGVyTW9kdWxlKSA9PiB7JyxcbiAgICBgICBjb25zdCBydW4gPSByZWFwZXJNb2R1bGUuJHtFTVVMQVRPUl9SRUFQRVJfRU5UUllfTkFNRX0gPz8gcmVhcGVyTW9kdWxlLmRlZmF1bHQuJHtFTVVMQVRPUl9SRUFQRVJfRU5UUllfTkFNRX07YCxcbiAgICAnICByZXR1cm4gcnVuKHByb2Nlc3MuYXJndi5zbGljZSgyKSk7JyxcbiAgICAnfSkuY2F0Y2goKGVycm9yKSA9PiB7JyxcbiAgICAnICBjb25zb2xlLmVycm9yKGVycm9yKTsnLFxuICAgICcgIHByb2Nlc3MuZXhpdENvZGUgPSAxOycsXG4gICAgJ30pOydcbiAgXS5qb2luKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBCdWlsZHMgdGhlIHNjcmlwdCBgbm9kZSAtZWAgcnVucyBhcyB0aGUgKipyZWxheSoqOiBpdCBzdGFydHMgdGhlIHJlYXBlciBhbmRcbiAqIGV4aXRzIGF0IG9uY2UsIHNvIHRoZSByZWFwZXIgaXMgbGVmdCB3aXRoIGEgZGVhZCBwYXJlbnQgYW5kIG5vIHRyZWUtd2Fsa2luZ1xuICoga2lsbCBvZiB0aGUgcnVuIGNhbiByZWFjaCBpdC4gU2VlIHRoZSByZWxheSBzZWN0aW9uIGluIHRoaXMgbW9kdWxlJ3MgaGVhZGVyXG4gKiBmb3Igd2h5IHRoYXQgaW5kaXJlY3Rpb24gZXhpc3RzIGF0IGFsbC5cbiAqXG4gKiBJdHMgb3duIGFyZ3VtZW50cyBhcmUgdGhlIHJlYXBlcidzIHdob2xlIGNvbW1hbmQgbGluZSBcdTIwMTQgdGhlIGJvb3RzdHJhcCBzY3JpcHRcbiAqIGZpcnN0LCB0aGVuIGV2ZXJ5dGhpbmcgdGhhdCBib290c3RyYXAgcmVhZHMgXHUyMDE0IHNvIHRoZSByZWxheSBuZXZlciBoYXMgdG8ga25vd1xuICogd2hhdCBhbnkgb2YgdGhlbSBtZWFuLiBJdCBoYW5kcyB0aGUgcmVhcGVyIGl0cyBvd24gc3Rkb3V0IGFuZCBzdGRlcnIsIHdoaWNoXG4gKiBhcmUgdGhlIGNhcHBlZCBsb2cgZmlsZSB0aGUgc3Bhd25lciBvcGVuZWQsIHNvIHRoZSBsb2cgaXMgdW5hZmZlY3RlZCBieSB0aGVcbiAqIGV4dHJhIGhvcC5cbiAqXG4gKiBAcmV0dXJucyBUaGUgc2NyaXB0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRFbXVsYXRvclJlYXBlclJlbGF5Qm9vdHN0cmFwKCk6IHN0cmluZyB7XG4gIHJldHVybiBbXG4gICAgJ2NvbnN0IHsgc3Bhd24gfSA9IHJlcXVpcmUoXCJub2RlOmNoaWxkX3Byb2Nlc3NcIik7JyxcbiAgICAndHJ5IHsnLFxuICAgICcgIGNvbnN0IGNoaWxkID0gc3Bhd24ocHJvY2Vzcy5leGVjUGF0aCwgW1wiLWVcIiwgcHJvY2Vzcy5hcmd2WzFdLCAuLi5wcm9jZXNzLmFyZ3Yuc2xpY2UoMildLCB7JyxcbiAgICAnICAgIGRldGFjaGVkOiB0cnVlLCcsXG4gICAgJyAgICBzdGRpbzogW1wiaWdub3JlXCIsIDEsIDJdLCcsXG4gICAgJyAgICB3aW5kb3dzSGlkZTogdHJ1ZScsXG4gICAgJyAgfSk7JyxcbiAgICAnICBjaGlsZC5vbmNlKFwiZXJyb3JcIiwgKGVycm9yKSA9PiB7IGNvbnNvbGUuZXJyb3IoZXJyb3IpOyB9KTsnLFxuICAgICcgIGNoaWxkLnVucmVmKCk7JyxcbiAgICAnfSBjYXRjaCAoZXJyb3IpIHsnLFxuICAgICcgIGNvbnNvbGUuZXJyb3IoZXJyb3IpOycsXG4gICAgJyAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7JyxcbiAgICAnfSdcbiAgXS5qb2luKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBEZWNvZGVzIHRoZSByZWFwZXIncyBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxuICpcbiAqIEBwYXJhbSBhcmd2IC0gVGhlIGFyZ3VtZW50cyBhZnRlciB0aGUgbW9kdWxlIFVSTC5cbiAqIEByZXR1cm5zIFRoZSBhcmd1bWVudHMsIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhleSBhcmUgbm90IHRoZSB0d28ge0BsaW5rIGJ1aWxkRW11bGF0b3JSZWFwZXJBcmd1bWVudHN9IHdyaXRlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRW11bGF0b3JSZWFwZXJBcmd1bWVudHMoYXJndjogcmVhZG9ubHkgc3RyaW5nW10pOiBFbXVsYXRvclJlYXBlckFyZ3VtZW50cyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IFthdmROYW1lLCBzdGFydGVkQXRUZXh0LCAuLi5yZXN0XSA9IGFyZ3Y7XG4gIGlmICghYXZkTmFtZSB8fCBzdGFydGVkQXRUZXh0ID09PSB1bmRlZmluZWQgfHwgcmVzdC5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGNvbnN0IHN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzID0gTnVtYmVyKHN0YXJ0ZWRBdFRleHQpO1xuICBpZiAoIU51bWJlci5pc1NhZmVJbnRlZ2VyKHN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzKSB8fCBzdGFydGVkQXRJbk1pbGxpc2Vjb25kcyA8PSAwKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJldHVybiB7IGF2ZE5hbWUsIHN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzIH07XG59XG5cbi8qKlxuICogRGVjaWRlcyBob3cgdGhlIHJlYXBlciBsb2cgaXMgb3BlbmVkLCBzbyBpdCBjYW4gbmV2ZXIgZ3JvdyB3aXRob3V0IGJvdW5kLlxuICpcbiAqIEBwYXJhbSBzaXplSW5CeXRlcyAtIFRoZSBsb2cncyBjdXJyZW50IHNpemUsIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhlcmUgaXMgbm9uZS5cbiAqIEByZXR1cm5zIGAnYSdgIHRvIGFwcGVuZCwgb3IgYCd3J2AgdG8gc3RhcnQgaXQgYWZyZXNoIG9uY2UgaXQgaGFzIHBhc3NlZCB0aGUgY2FwLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUVtdWxhdG9yUmVhcGVyTG9nT3BlbkZsYWcoc2l6ZUluQnl0ZXM6IG51bWJlciB8IHVuZGVmaW5lZCk6ICdhJyB8ICd3JyB7XG4gIHJldHVybiBzaXplSW5CeXRlcyAhPT0gdW5kZWZpbmVkICYmIHNpemVJbkJ5dGVzID4gRU1VTEFUT1JfUkVBUEVSX0xPR19NQVhfU0laRV9JTl9CWVRFUyA/ICd3JyA6ICdhJztcbn1cblxuLyoqXG4gKiBEZWNpZGVzIHdoYXQgdGhlIG1hcmtlciBzYXlzIHRoZSByZWFwZXIgc2hvdWxkIGRvIG5leHQuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRoZSBtYXJrZXIgYXMgaXQgcmVhZHMgbm93LCBhbmQgdGhlIGVtdWxhdG9yIHRoZSByZWFwZXIgd2FzIGFybWVkIGZvci5cbiAqIEByZXR1cm5zIFRoZSB2ZXJkaWN0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUVtdWxhdG9yUmVhcGVyV2F0Y2gocGFyYW1zOiBSZXNvbHZlRW11bGF0b3JSZWFwZXJXYXRjaFBhcmFtcyk6IEVtdWxhdG9yUmVhcGVyV2F0Y2hWZXJkaWN0IHtcbiAgY29uc3QgeyBtYXJrZXIgfSA9IHBhcmFtcztcbiAgaWYgKG1hcmtlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuICdlbXVsYXRvci1zdG9wcGVkJztcbiAgfVxuXG4gIGlmIChtYXJrZXIuc3RhcnRlZEF0SW5NaWxsaXNlY29uZHMgIT09IHBhcmFtcy5hcm1lZFN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzKSB7XG4gICAgcmV0dXJuICdzdXBlcnNlZGVkJztcbiAgfVxuXG4gIC8qXG4gICAqIEEgbGF1bmNoLXRpbWUgbWFya2VyJ3MgUElEIGxpc3QgaXMgZGVsaWJlcmF0ZWx5IGluY29tcGxldGUgXHUyMDE0IGl0IG5hbWVzIHRoZVxuICAgKiBsYXVuY2hlciwgYW5kIHRoZSBiYWNrZW5kIGl0IGZvcmtzIGlzIGlkZW50aWZpZWQgYnkgdGhlIHByZS1sYXVuY2ggZGlmZixcbiAgICogd2hpY2ggY29zdHMgYSBob3N0IHByb2Nlc3MgbGlzdGluZyB0aGlzIHBvbGwgZGVsaWJlcmF0ZWx5IGRvZXMgbm90IG1ha2UuXG4gICAqIFNvIGl0IGlzIG5ldmVyIHJlYWQgYXMgc3RvcHBlZCBmcm9tIFBJRHMgYWxvbmU6IHRoZSByZWNsYWltLCB3aGljaCBkb2VzXG4gICAqIG1ha2UgdGhhdCBsaXN0aW5nLCBpcyB3aGF0IGp1ZGdlcyBpdC5cbiAgICovXG4gIGlmIChtYXJrZXIucHJlTGF1bmNoRW11bGF0b3JQaWRzICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gJ3dhdGNoJztcbiAgfVxuXG4gIHJldHVybiBtYXJrZXIub3duZWRFbXVsYXRvclBpZHMuc29tZSgocGlkKSA9PiBwYXJhbXMuY2hlY2tJc1BpZEFsaXZlKHBpZCkpID8gJ3dhdGNoJyA6ICdlbXVsYXRvci1zdG9wcGVkJztcbn1cblxuLyogdjggaWdub3JlIHN0YXJ0IC0tIERldGFjaGVkLXByb2Nlc3MgZ2x1ZSBjb3ZlcmVkIGJ5IHRoZSBBbmRyb2lkIGludGVncmF0aW9uIHN1aXRlLCBub3QgdW5pdCB0ZXN0cy4gKi9cblxuLyoqXG4gKiBUaGUgcmVhcGVyIHByb2Nlc3MncyBib2R5OiB3YXRjaGVzIHRoZSBtYXJrZXIgYW5kIHRoZSBsb2NrIHVudGlsIGVpdGhlciB0aGVcbiAqIGVtdWxhdG9yIGlzIGdvbmUgb3Igbm8gcnVuIGhvbGRzIHRoZSBsb2NrLCBhbmQgaW4gdGhlIHNlY29uZCBjYXNlIHN0b3BzIHRoZVxuICogaGFybmVzcydzIGxlZnRvdmVycyB3aGlsZSBob2xkaW5nIGl0LlxuICpcbiAqIEV4cG9ydGVkIGZvciB0aGUgYm9vdHN0cmFwLCB3aGljaCBpcyBpdHMgb25seSBjYWxsZXIuXG4gKlxuICogQHBhcmFtIGFyZ3YgLSBUaGUgcmVhcGVyJ3MgYXJndW1lbnRzLCBhcyB7QGxpbmsgYnVpbGRFbXVsYXRvclJlYXBlckFyZ3VtZW50c30gd3JvdGUgdGhlbS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bkVtdWxhdG9yUmVhcGVyKGFyZ3Y6IHJlYWRvbmx5IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHJlYXBlckFyZ3VtZW50cyA9IHBhcnNlRW11bGF0b3JSZWFwZXJBcmd1bWVudHMoYXJndik7XG4gIGlmICghcmVhcGVyQXJndW1lbnRzKSB7XG4gICAgbG9nKGBbZW11bGF0b3ItcmVhcGVyXSBSZWZ1c2luZyB0byBydW46IGV4cGVjdGVkIDxhdmROYW1lPiA8c3RhcnRlZEF0SW5NaWxsaXNlY29uZHM+LCBnb3QgJHtKU09OLnN0cmluZ2lmeShhcmd2KX0uYCk7XG4gICAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgeyBhdmROYW1lLCBzdGFydGVkQXRJbk1pbGxpc2Vjb25kcyB9ID0gcmVhcGVyQXJndW1lbnRzO1xuICByZWFwZXJMb2coXG4gICAgYFdhdGNoaW5nIHRoZSBlbXVsYXRvciBzdGFydGVkIGF0ICR7bmV3IERhdGUoc3RhcnRlZEF0SW5NaWxsaXNlY29uZHMpLnRvSVNPU3RyaW5nKCl9IChyZWFwZXIgUElEICR7U3RyaW5nKHByb2Nlc3MucGlkKX0pOyBpdCBpcyBzdG9wcGVkIG9uY2Ugbm8gQW5kcm9pZCBydW4gaG9sZHMgdGhlICcke0FORFJPSURfU0VUVVBfTE9DS19TQ09QRX0nIHNldHVwIGxvY2suYFxuICApO1xuXG4gIGZvciAoOzspIHtcbiAgICBjb25zdCB2ZXJkaWN0ID0gcmVhZFdhdGNoVmVyZGljdChyZWFwZXJBcmd1bWVudHMpO1xuICAgIGlmICh2ZXJkaWN0ICE9PSAnd2F0Y2gnKSB7XG4gICAgICByZWFwZXJMb2coZGVzY3JpYmVFeGl0KHZlcmRpY3QpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsZXQgbG9jazogU2V0dXBMb2NrIHwgdW5kZWZpbmVkO1xuICAgIHRyeSB7XG4gICAgICBsb2NrID0gdHJ5QWNxdWlyZVNldHVwTG9jayh7XG4gICAgICAgIGxhYmVsOiBMT0NLX0xBQkVMLFxuICAgICAgICBzY29wZTogQU5EUk9JRF9TRVRVUF9MT0NLX1NDT1BFLFxuICAgICAgICBzdGFsZUFmdGVyU2lsZW5jZUluTWlsbGlzZWNvbmRzOiBFTVVMQVRPUl9SRUFQRVJfTE9DS19TSUxFTkNFX0lOX01JTExJU0VDT05EU1xuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIC8vIEZhaWwgb3BlbjogYSBsb2NrIHRoaXMgcHJvY2VzcyBjYW5ub3QgZXZlbiBsb29rIGF0IGlzIG5vIGV2aWRlbmNlIHRoZSBydW4gaXMgb3Zlci5cbiAgICAgIHJlYXBlckxvZyhgR2l2aW5nIHVwOiB0aGUgc2V0dXAgbG9jayBjb3VsZCBub3QgYmUgcmVhZCAoJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9KS4gVGhlIG5leHQgQW5kcm9pZCBydW4gcmVjbGFpbXMgdGhlIGVtdWxhdG9yIGluc3RlYWQuYCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGxvY2spIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIFRoZSBydW4gbWF5IGhhdmUgZW5kZWQgbm9ybWFsbHkgYmV0d2VlbiB0aGUgbG9vayBhYm92ZSBhbmQgdGhlIGxvY2s6IGl0cyB0ZWFyZG93biB0aGVuIHN0b3BwZWQgdGhlIGVtdWxhdG9yLlxuICAgICAgICBjb25zdCBsb2NrZWRWZXJkaWN0ID0gcmVhZFdhdGNoVmVyZGljdChyZWFwZXJBcmd1bWVudHMpO1xuICAgICAgICBpZiAobG9ja2VkVmVyZGljdCAhPT0gJ3dhdGNoJykge1xuICAgICAgICAgIHJlYXBlckxvZyhkZXNjcmliZUV4aXQobG9ja2VkVmVyZGljdCkpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlYXBlckxvZygnTm8gQW5kcm9pZCBydW4gaG9sZHMgdGhlIHNldHVwIGxvY2sgYW55IG1vcmUsIHNvIG5vdGhpbmcgaXMgbGVmdCB0byBzdG9wIHRoZSBlbXVsYXRvci4gU3RvcHBpbmcgdGhlIGxlZnRvdmVycyB0aGlzIGhhcm5lc3Mgc3RhcnRlZC4uLicpO1xuICAgICAgICBhd2FpdCBuZXcgRW11bGF0b3JSZWNsYWltZXIocmVhcGVyTG9nKS5yZWNsYWltTGVmdG92ZXJFbXVsYXRvcnMoeyBzY29wZTogJ2VuZC1vZi1ydW4nIH0pO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgbG9jay5yZWxlYXNlKCk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgRU1VTEFUT1JfUkVBUEVSX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKTtcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHJlYXBlckxvZyhtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBsb2coYFtlbXVsYXRvci1yZWFwZXI6JHthdmROYW1lfV0gJHttZXNzYWdlfWApO1xuICB9XG59XG5cbi8qKlxuICogU3RhcnRzIHRoZSByZWFwZXIgZm9yIGFuIGVtdWxhdG9yIHRoZSBoYXJuZXNzIGp1c3QgcmVjb3JkZWQgYXMgaXRzIG93biwgd2hlblxuICogYSBsaXZlIHJ1biBob2xkcyB0aGUgYGFuZHJvaWRgIHNldHVwIGxvY2sgXHUyMDE0IGFuZCBzYXlzIHdoaWNoIGl0IGRpZC5cbiAqXG4gKiBOZXZlciB0aHJvd3M6IGEgcmVhcGVyIHRoYXQgY2Fubm90IGJlIHNwYXduZWQgaXMgYSBsb3N0IHNhZmV0eSBuZXQsIG5vdCBhXG4gKiByZWFzb24gdG8gZmFpbCB0aGUgbGF1bmNoIGl0IHdvdWxkIGhhdmUgZ3VhcmRlZC5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHJlY29yZGVkIGVtdWxhdG9yLCBhbmQgd2hlcmUgdG8gcmVwb3J0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc3Bhd25FbXVsYXRvclJlYXBlcihwYXJhbXM6IFNwYXduRW11bGF0b3JSZWFwZXJQYXJhbXMpOiB2b2lkIHtcbiAgY29uc3QgeyBhdmROYW1lIH0gPSBwYXJhbXM7XG4gIGlmICghY2hlY2tJc1NldHVwTG9ja0hlbGQoQU5EUk9JRF9TRVRVUF9MT0NLX1NDT1BFKSkge1xuICAgIHBhcmFtcy5sb2coXG4gICAgICBgTm8gZW11bGF0b3IgcmVhcGVyIGFybWVkIGZvciBBVkQgXCIke2F2ZE5hbWV9XCI6IG5vIHJ1biBob2xkcyB0aGUgJyR7QU5EUk9JRF9TRVRVUF9MT0NLX1NDT1BFfScgc2V0dXAgbG9jaywgc28gYSByZWFwZXIgY291bGQgbm90IHRlbGwgdGhpcyBydW4gZW5kaW5nIGZyb20gaXQgYmVpbmcga2lsbGVkLiBJZiB0aGlzIHByb2Nlc3MgaXMga2lsbGVkLCBvbmx5IHRoZSBuZXh0IEFuZHJvaWQgcnVuIG9uIHRoaXMgaG9zdCBzdG9wcyB0aGUgZW11bGF0b3IuYFxuICAgICk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgbG9nRmlsZVBhdGggPSBqb2luKGdldFJlYXBlckxvZ0RpcmVjdG9yeSgpLCBgJHthdmROYW1lfSR7UkVBUEVSX0xPR19GSUxFX1NVRkZJWH1gKTtcbiAgdHJ5IHtcbiAgICBta2RpclN5bmMoZ2V0UmVhcGVyTG9nRGlyZWN0b3J5KCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGNvbnN0IGxvZ0ZpbGVEZXNjcmlwdG9yID0gb3BlblN5bmMobG9nRmlsZVBhdGgsIHJlc29sdmVFbXVsYXRvclJlYXBlckxvZ09wZW5GbGFnKHJlYWRGaWxlU2l6ZShsb2dGaWxlUGF0aCkpKTtcbiAgICB0cnkge1xuICAgICAgLypcbiAgICAgICAqIFRocm91Z2ggdGhlIHJlbGF5LCBuZXZlciBzdHJhaWdodCBhdCB0aGUgcmVhcGVyOiBhIHJlYXBlciBzcGF3bmVkIGhlcmVcbiAgICAgICAqIHdvdWxkIGJlIGEgY2hpbGQgb2YgdGhpcyBydW4gYW5kIHdvdWxkIGRpZSB3aXRoIGl0IHVuZGVyIGFueSBraWxsIHRoYXRcbiAgICAgICAqIHdhbGtzIHRoZSBwcm9jZXNzIHRyZWUuIFRoZSByZWxheSBleGl0cyBhdCBvbmNlLCBsZWF2aW5nIHRoZSByZWFwZXIgd2l0aFxuICAgICAgICogYSBkZWFkIHBhcmVudCBhbmQgbm8gZWRnZSBiYWNrIHRvIHRoaXMgcnVuLlxuICAgICAgICovXG4gICAgICBjb25zdCByZWxheSA9IHNwYXduKFxuICAgICAgICBwcm9jZXNzLmV4ZWNQYXRoLFxuICAgICAgICBbXG4gICAgICAgICAgJy1lJyxcbiAgICAgICAgICBidWlsZEVtdWxhdG9yUmVhcGVyUmVsYXlCb290c3RyYXAoKSxcbiAgICAgICAgICBidWlsZEVtdWxhdG9yUmVhcGVyQm9vdHN0cmFwKCksXG4gICAgICAgICAgcmVzb2x2ZU93bk1vZHVsZVVybCgpLFxuICAgICAgICAgIC4uLmJ1aWxkRW11bGF0b3JSZWFwZXJBcmd1bWVudHMoeyBhdmROYW1lLCBzdGFydGVkQXRJbk1pbGxpc2Vjb25kczogcGFyYW1zLnN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzIH0pXG4gICAgICAgIF0sXG4gICAgICAgIHsgZGV0YWNoZWQ6IHRydWUsIHN0ZGlvOiBbJ2lnbm9yZScsIGxvZ0ZpbGVEZXNjcmlwdG9yLCBsb2dGaWxlRGVzY3JpcHRvcl0sIHdpbmRvd3NIaWRlOiB0cnVlIH1cbiAgICAgICk7XG4gICAgICByZWxheS5vbmNlKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgICBwYXJhbXMubG9nKGBUaGUgZW11bGF0b3IgcmVhcGVyIHJlbGF5IGZvciBBVkQgXCIke2F2ZE5hbWV9XCIgZmFpbGVkIHRvIHN0YXJ0OiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgICB9KTtcbiAgICAgIHJlbGF5LnVucmVmKCk7XG4gICAgICBwYXJhbXMubG9nKFxuICAgICAgICBgRW11bGF0b3IgcmVhcGVyIGFybWVkIGZvciBBVkQgXCIke2F2ZE5hbWV9XCI6IGlmIHRoaXMgcnVuIGlzIGtpbGxlZCBcdTIwMTQgYSBwcm9jZXNzLXRyZWUga2lsbCBpbmNsdWRlZCwgc2luY2UgdGhlIHJlYXBlciBpcyBzdGFydGVkIHRocm91Z2ggYSByZWxheSB0aGF0IGV4aXRzIGF0IG9uY2UgXHUyMDE0IGl0IHN0b3BzIHRoZSBlbXVsYXRvciBvbmNlIG5vIEFuZHJvaWQgcnVuIGhvbGRzIHRoZSAnJHtBTkRST0lEX1NFVFVQX0xPQ0tfU0NPUEV9JyBzZXR1cCBsb2NrLiBJdHMgUElEIGlzIHRoZSBmaXJzdCBsaW5lIG9mIGl0cyBsb2c6ICR7bG9nRmlsZVBhdGh9YFxuICAgICAgKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgY2xvc2VTeW5jKGxvZ0ZpbGVEZXNjcmlwdG9yKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgcGFyYW1zLmxvZyhgQ291bGQgbm90IGFybSB0aGUgZW11bGF0b3IgcmVhcGVyIGZvciBBVkQgXCIke2F2ZE5hbWV9XCI6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xuICB9XG59XG5cbmZ1bmN0aW9uIGRlc2NyaWJlRXhpdCh2ZXJkaWN0OiBFeGNsdWRlPEVtdWxhdG9yUmVhcGVyV2F0Y2hWZXJkaWN0LCAnd2F0Y2gnPik6IHN0cmluZyB7XG4gIHJldHVybiB2ZXJkaWN0ID09PSAnc3VwZXJzZWRlZCdcbiAgICA/ICdUaGUgbWFya2VyIG5vdyByZWNvcmRzIGEgbGF0ZXIgZW11bGF0b3Igb2YgdGhpcyBBVkQsIHdoaWNoIGhhcyBpdHMgb3duIHJlYXBlcjsgbm90aGluZyBsZWZ0IHRvIHdhdGNoLidcbiAgICA6ICdUaGUgZW11bGF0b3Igd2FzIHN0b3BwZWQ7IG5vdGhpbmcgbGVmdCB0byB3YXRjaC4nO1xufVxuXG5mdW5jdGlvbiBnZXRSZWFwZXJMb2dEaXJlY3RvcnkoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGpvaW4odG1wZGlyKCksIEhBUk5FU1NfVEVNUF9ESVJfTkFNRSk7XG59XG5cbmZ1bmN0aW9uIHJlYWRGaWxlU2l6ZShwYXRoOiBzdHJpbmcpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICB0cnkge1xuICAgIHJldHVybiBzdGF0U3luYyhwYXRoKS5zaXplO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlYWRXYXRjaFZlcmRpY3QocmVhcGVyQXJndW1lbnRzOiBFbXVsYXRvclJlYXBlckFyZ3VtZW50cyk6IEVtdWxhdG9yUmVhcGVyV2F0Y2hWZXJkaWN0IHtcbiAgcmV0dXJuIHJlc29sdmVFbXVsYXRvclJlYXBlcldhdGNoKHtcbiAgICBhcm1lZFN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzOiByZWFwZXJBcmd1bWVudHMuc3RhcnRlZEF0SW5NaWxsaXNlY29uZHMsXG4gICAgY2hlY2tJc1BpZEFsaXZlOiBjaGVja0lzUHJvY2Vzc0FsaXZlLFxuICAgIG1hcmtlcjogcmVhZEVtdWxhdG9yTWFya2VyKHJlYXBlckFyZ3VtZW50cy5hdmROYW1lKVxuICB9KTtcbn1cblxuLyoqXG4gKiBGaW5kcyB0aGlzIG1vZHVsZSdzIG93biBVUkwgXHUyMDE0IHRoZSBvbmUgdGhlIGJvb3RzdHJhcCBpbXBvcnRzLlxuICpcbiAqIFRoZSBDSlMgYnVpbGQgaGFzIG5vIGBpbXBvcnQubWV0YWAgKGVzYnVpbGQgZW1wdGllcyBpdCksIGJ1dCBpdCBoYXNcbiAqIGBfX2ZpbGVuYW1lYDsgdGhlIEVTTSBidWlsZCBhbmQgdGhlIGAudHNgIHNvdXJjZSBoYXZlIGBpbXBvcnQubWV0YS51cmxgLlxuICpcbiAqIEByZXR1cm5zIFRoZSBVUkwgb2YgdGhpcyBtb2R1bGUgYXMgaXQgaXMgcnVubmluZy5cbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZU93bk1vZHVsZVVybCgpOiBzdHJpbmcge1xuICByZXR1cm4gdHlwZW9mIF9fZmlsZW5hbWUgPT09ICdzdHJpbmcnID8gcGF0aFRvRmlsZVVSTChfX2ZpbGVuYW1lKS5ocmVmIDogaW1wb3J0Lm1ldGEudXJsO1xufVxuXG4vKiB2OCBpZ25vcmUgc3RvcCAqL1xuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBdUVBLGdDQUFzQjtBQUN0QixxQkFLTztBQUNQLHFCQUF1QjtBQUN2Qix1QkFBcUI7QUFDckIsMEJBQW9C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