obsidian-integration-testing 12.0.0 → 12.1.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 (176) hide show
  1. package/dist/lib/cjs/adb-device-list.cjs +54 -0
  2. package/dist/lib/cjs/adb-device-list.d.cts +72 -0
  3. package/dist/lib/cjs/android-sdk.cjs +52 -0
  4. package/dist/lib/cjs/android-sdk.d.cts +29 -0
  5. package/dist/lib/cjs/app-startup-progress.cjs +87 -0
  6. package/dist/lib/cjs/app-startup-progress.d.cts +128 -0
  7. package/dist/lib/cjs/appium-server-marker.cjs +29 -32
  8. package/dist/lib/cjs/appium-server-marker.d.cts +22 -0
  9. package/dist/lib/cjs/avd-probe-verdict.cjs +90 -0
  10. package/dist/lib/cjs/avd-probe-verdict.d.cts +175 -0
  11. package/dist/lib/cjs/community-plugin-registry.cjs +1 -1
  12. package/dist/lib/cjs/community-plugin-registry.d.cts +1 -1
  13. package/dist/lib/cjs/config-directory-fallback-error.cjs +57 -0
  14. package/dist/lib/cjs/config-directory-fallback-error.d.cts +64 -0
  15. package/dist/lib/cjs/config-directory.cjs +46 -0
  16. package/dist/lib/cjs/config-directory.d.cts +45 -0
  17. package/dist/lib/cjs/connect-to-cdp.cjs +13 -7
  18. package/dist/lib/cjs/connect-to-cdp.d.cts +19 -0
  19. package/dist/lib/cjs/demo-vault-bootstrap.cjs +1 -1
  20. package/dist/lib/cjs/demo-vault-bootstrap.d.cts +3 -2
  21. package/dist/lib/cjs/demo-vault-populate.cjs +3 -2
  22. package/dist/lib/cjs/device-readiness.cjs +38 -3
  23. package/dist/lib/cjs/device-readiness.d.cts +83 -9
  24. package/dist/lib/cjs/emulator-arguments.cjs +6 -2
  25. package/dist/lib/cjs/emulator-arguments.d.cts +26 -0
  26. package/dist/lib/cjs/emulator-backend.cjs +71 -0
  27. package/dist/lib/cjs/emulator-backend.d.cts +76 -0
  28. package/dist/lib/cjs/emulator-liveness.cjs +72 -0
  29. package/dist/lib/cjs/emulator-liveness.d.cts +158 -0
  30. package/dist/lib/cjs/emulator-snapshot.cjs +57 -0
  31. package/dist/lib/cjs/emulator-snapshot.d.cts +68 -0
  32. package/dist/lib/cjs/global-setup-core.cjs +30 -30
  33. package/dist/lib/cjs/global-setup-core.d.cts +27 -2
  34. package/dist/lib/cjs/headless-vault-config.cjs +51 -0
  35. package/dist/lib/cjs/headless-vault-config.d.cts +67 -0
  36. package/dist/lib/cjs/index.cjs +12 -1
  37. package/dist/lib/cjs/index.d.cts +6 -1
  38. package/dist/lib/cjs/library.cjs +1 -1
  39. package/dist/lib/cjs/mobile-input.cjs +14 -2
  40. package/dist/lib/cjs/mobile-input.d.cts +5 -9
  41. package/dist/lib/cjs/namespace-bootstrap.cjs +1 -1
  42. package/dist/lib/cjs/obsidian-instance.cjs +52 -3
  43. package/dist/lib/cjs/obsidian-instance.d.cts +12 -0
  44. package/dist/lib/cjs/open-obsidian-settings-tab.cjs +1 -1
  45. package/dist/lib/cjs/open-obsidian-settings-tab.d.cts +3 -2
  46. package/dist/lib/cjs/owned-instance-exit-marker.cjs +99 -0
  47. package/dist/lib/cjs/owned-instance-exit-marker.d.cts +106 -0
  48. package/dist/lib/cjs/owned-instance-exited-error.cjs +106 -0
  49. package/dist/lib/cjs/owned-instance-exited-error.d.cts +98 -0
  50. package/dist/lib/cjs/owned-vault-seed.cjs +9 -5
  51. package/dist/lib/cjs/owned-vault-seed.d.cts +24 -3
  52. package/dist/lib/cjs/parent-liveness.cjs +42 -5
  53. package/dist/lib/cjs/parent-liveness.d.cts +37 -5
  54. package/dist/lib/cjs/port-owner.cjs +61 -0
  55. package/dist/lib/cjs/port-owner.d.cts +47 -0
  56. package/dist/lib/cjs/process-capture.cjs +62 -0
  57. package/dist/lib/cjs/process-capture.d.cts +83 -0
  58. package/dist/lib/cjs/process-exit-message.cjs +14 -8
  59. package/dist/lib/cjs/process-exit-message.d.cts +37 -3
  60. package/dist/lib/cjs/process-liveness.cjs +51 -0
  61. package/dist/lib/cjs/process-liveness.d.cts +18 -0
  62. package/dist/lib/cjs/run-version-matrix.cjs +1 -1
  63. package/dist/lib/cjs/run-version-matrix.d.cts +1 -1
  64. package/dist/lib/cjs/teardown-verdict.cjs +53 -0
  65. package/dist/lib/cjs/teardown-verdict.d.cts +69 -0
  66. package/dist/lib/cjs/temporary-vault.cjs +43 -8
  67. package/dist/lib/cjs/temporary-vault.d.cts +47 -5
  68. package/dist/lib/cjs/transport-appium.cjs +102 -17
  69. package/dist/lib/cjs/transport-appium.d.cts +53 -3
  70. package/dist/lib/cjs/transport-desktop-cdp.cjs +195 -6
  71. package/dist/lib/cjs/transport-desktop-cdp.d.cts +99 -0
  72. package/dist/lib/cjs/transport-factory.cjs +951 -133
  73. package/dist/lib/cjs/transport-options.cjs +11 -3
  74. package/dist/lib/cjs/transport-options.d.cts +131 -12
  75. package/dist/lib/cjs/transport.cjs +1 -1
  76. package/dist/lib/cjs/transport.d.cts +7 -1
  77. package/dist/lib/cjs/vault-plugin-install.cjs +40 -0
  78. package/dist/lib/cjs/vault-plugin-install.d.cts +64 -0
  79. package/dist/lib/cjs/vault-teardown-verdict.cjs +42 -0
  80. package/dist/lib/cjs/vault-teardown-verdict.d.cts +57 -0
  81. package/dist/lib/cjs/version-matrix.cjs +1 -1
  82. package/dist/lib/cjs/version-matrix.d.cts +2 -2
  83. package/dist/lib/cjs/webview-cdp.cjs +6 -7
  84. package/dist/lib/cjs/webview-cdp.d.cts +5 -1
  85. package/dist/lib/esm/adb-device-list.d.mts +72 -0
  86. package/dist/lib/esm/adb-device-list.mjs +28 -0
  87. package/dist/lib/esm/android-sdk.d.mts +29 -0
  88. package/dist/lib/esm/android-sdk.mjs +18 -0
  89. package/dist/lib/esm/app-startup-progress.d.mts +128 -0
  90. package/dist/lib/esm/app-startup-progress.mjs +59 -0
  91. package/dist/lib/esm/appium-server-marker.d.mts +22 -0
  92. package/dist/lib/esm/appium-server-marker.mjs +28 -22
  93. package/dist/lib/esm/avd-probe-verdict.d.mts +175 -0
  94. package/dist/lib/esm/avd-probe-verdict.mjs +62 -0
  95. package/dist/lib/esm/community-plugin-registry.d.mts +1 -1
  96. package/dist/lib/esm/community-plugin-registry.mjs +1 -1
  97. package/dist/lib/esm/config-directory-fallback-error.d.mts +64 -0
  98. package/dist/lib/esm/config-directory-fallback-error.mjs +33 -0
  99. package/dist/lib/esm/config-directory.d.mts +45 -0
  100. package/dist/lib/esm/config-directory.mjs +21 -0
  101. package/dist/lib/esm/connect-to-cdp.d.mts +19 -0
  102. package/dist/lib/esm/connect-to-cdp.mjs +13 -7
  103. package/dist/lib/esm/demo-vault-bootstrap.d.mts +3 -2
  104. package/dist/lib/esm/demo-vault-bootstrap.mjs +1 -1
  105. package/dist/lib/esm/demo-vault-populate.mjs +3 -2
  106. package/dist/lib/esm/device-readiness.d.mts +83 -9
  107. package/dist/lib/esm/device-readiness.mjs +34 -2
  108. package/dist/lib/esm/emulator-arguments.d.mts +26 -0
  109. package/dist/lib/esm/emulator-arguments.mjs +6 -2
  110. package/dist/lib/esm/emulator-backend.d.mts +76 -0
  111. package/dist/lib/esm/emulator-backend.mjs +45 -0
  112. package/dist/lib/esm/emulator-liveness.d.mts +158 -0
  113. package/dist/lib/esm/emulator-liveness.mjs +47 -0
  114. package/dist/lib/esm/emulator-snapshot.d.mts +68 -0
  115. package/dist/lib/esm/emulator-snapshot.mjs +32 -0
  116. package/dist/lib/esm/global-setup-core.d.mts +27 -2
  117. package/dist/lib/esm/global-setup-core.mjs +34 -35
  118. package/dist/lib/esm/headless-vault-config.d.mts +67 -0
  119. package/dist/lib/esm/headless-vault-config.mjs +31 -0
  120. package/dist/lib/esm/index.d.mts +6 -1
  121. package/dist/lib/esm/index.mjs +11 -1
  122. package/dist/lib/esm/library.mjs +1 -1
  123. package/dist/lib/esm/mobile-input.d.mts +5 -9
  124. package/dist/lib/esm/mobile-input.mjs +14 -2
  125. package/dist/lib/esm/namespace-bootstrap.mjs +1 -1
  126. package/dist/lib/esm/obsidian-instance.d.mts +12 -0
  127. package/dist/lib/esm/obsidian-instance.mjs +55 -3
  128. package/dist/lib/esm/open-obsidian-settings-tab.d.mts +3 -2
  129. package/dist/lib/esm/open-obsidian-settings-tab.mjs +1 -1
  130. package/dist/lib/esm/owned-instance-exit-marker.d.mts +106 -0
  131. package/dist/lib/esm/owned-instance-exit-marker.mjs +78 -0
  132. package/dist/lib/esm/owned-instance-exited-error.d.mts +98 -0
  133. package/dist/lib/esm/owned-instance-exited-error.mjs +81 -0
  134. package/dist/lib/esm/owned-vault-seed.d.mts +24 -3
  135. package/dist/lib/esm/owned-vault-seed.mjs +9 -5
  136. package/dist/lib/esm/parent-liveness.d.mts +37 -5
  137. package/dist/lib/esm/parent-liveness.mjs +42 -5
  138. package/dist/lib/esm/port-owner.d.mts +47 -0
  139. package/dist/lib/esm/port-owner.mjs +36 -0
  140. package/dist/lib/esm/process-capture.d.mts +83 -0
  141. package/dist/lib/esm/process-capture.mjs +38 -0
  142. package/dist/lib/esm/process-exit-message.d.mts +37 -3
  143. package/dist/lib/esm/process-exit-message.mjs +13 -8
  144. package/dist/lib/esm/process-liveness.d.mts +18 -0
  145. package/dist/lib/esm/process-liveness.mjs +17 -0
  146. package/dist/lib/esm/run-version-matrix.d.mts +1 -1
  147. package/dist/lib/esm/run-version-matrix.mjs +1 -1
  148. package/dist/lib/esm/teardown-verdict.d.mts +69 -0
  149. package/dist/lib/esm/teardown-verdict.mjs +28 -0
  150. package/dist/lib/esm/temporary-vault.d.mts +47 -5
  151. package/dist/lib/esm/temporary-vault.mjs +43 -8
  152. package/dist/lib/esm/transport-appium.d.mts +53 -3
  153. package/dist/lib/esm/transport-appium.mjs +108 -17
  154. package/dist/lib/esm/transport-desktop-cdp.d.mts +99 -0
  155. package/dist/lib/esm/transport-desktop-cdp.mjs +202 -7
  156. package/dist/lib/esm/transport-factory.mjs +995 -138
  157. package/dist/lib/esm/transport-options.d.mts +131 -12
  158. package/dist/lib/esm/transport-options.mjs +9 -2
  159. package/dist/lib/esm/transport.d.mts +7 -1
  160. package/dist/lib/esm/vault-plugin-install.d.mts +64 -0
  161. package/dist/lib/esm/vault-plugin-install.mjs +20 -0
  162. package/dist/lib/esm/vault-teardown-verdict.d.mts +57 -0
  163. package/dist/lib/esm/vault-teardown-verdict.mjs +18 -0
  164. package/dist/lib/esm/version-matrix.d.mts +2 -2
  165. package/dist/lib/esm/version-matrix.mjs +1 -1
  166. package/dist/lib/esm/webview-cdp.d.mts +5 -1
  167. package/dist/lib/esm/webview-cdp.mjs +6 -7
  168. package/package.json +24 -23
  169. package/dist/lib/cjs/native-dialog-monitor.cjs +0 -192
  170. package/dist/lib/cjs/native-dialog-monitor.d.cts +0 -66
  171. package/dist/lib/cjs/obsidian-namespace.cjs +0 -17
  172. package/dist/lib/cjs/obsidian-namespace.d.cts +0 -128
  173. package/dist/lib/esm/native-dialog-monitor.d.mts +0 -66
  174. package/dist/lib/esm/native-dialog-monitor.mjs +0 -158
  175. package/dist/lib/esm/obsidian-namespace.d.mts +0 -128
  176. package/dist/lib/esm/obsidian-namespace.mjs +0 -1
@@ -9,6 +9,7 @@
9
9
  * is keyed to the user-data dir, the owned instance runs in parallel with the
10
10
  * user's own Obsidian. Confirmed by the Phase 0 spike (see the project plan).
11
11
  */
12
+ import type { ProcessExitInfo } from './process-exit-message.mjs';
12
13
  /**
13
14
  * Parameters for {@link launchOwnedObsidianInstance}.
14
15
  */
@@ -57,6 +58,17 @@ export interface OwnedObsidianInstance {
57
58
  The CDP remote-debugging port the instance was launched with.
58
59
  */
59
60
  readonly port: number;
61
+ /**
62
+ * Returns how the instance died once it is no longer running, otherwise
63
+ * `undefined`. This is the in-process half of the answer; a test worker in
64
+ * another process reads the same facts from the exit marker
65
+ * (`owned-instance-exit-marker.ts`).
66
+ */
67
+ readExitInfo(): ProcessExitInfo | undefined;
68
+ /**
69
+ Returns the tail of everything the instance wrote to stdout/stderr.
70
+ */
71
+ readOutput(): string;
60
72
  }
61
73
  /**
62
74
  * Launches an isolated, harness-owned Obsidian instance and waits until its CDP
@@ -2,31 +2,83 @@ import { spawn } from "node:child_process";
2
2
  import { createServer } from "node:net";
3
3
  import { killProcessTree } from "./kill-process-tree.mjs";
4
4
  import { log } from "./log.mjs";
5
+ import {
6
+ clearOwnedInstanceExitMarker,
7
+ writeOwnedInstanceExitMarker
8
+ } from "./owned-instance-exit-marker.mjs";
9
+ import { OwnedInstanceExitedError } from "./owned-instance-exited-error.mjs";
5
10
  import { startParentLivenessServer } from "./parent-liveness.mjs";
11
+ import { attachProcessCapture } from "./process-capture.mjs";
6
12
  const DEFAULT_CDP_HOST = "127.0.0.1";
7
13
  const CDP_READY_POLL_INTERVAL_IN_MILLISECONDS = 1e3;
8
14
  const CDP_READY_TIMEOUT_IN_MILLISECONDS = 6e4;
15
+ const OBSIDIAN_OUTPUT_TAIL_MAX_LENGTH = 8e3;
9
16
  async function launchOwnedObsidianInstance(params) {
10
17
  const cdpHost = params.cdpHost ?? DEFAULT_CDP_HOST;
11
18
  const port = await pickFreePort();
12
19
  const cdpUrl = `http://${cdpHost}:${String(port)}`;
13
20
  const livenessServer = await startParentLivenessServer();
21
+ clearOwnedInstanceExitMarker(port);
14
22
  log(`[obsidian-instance] Launching owned Obsidian: userData=${params.userDataDirectory}, cdpPort=${String(port)}`);
15
23
  const child = spawn(
16
24
  params.exePath,
17
25
  [`--user-data-dir=${params.userDataDirectory}`, `--remote-debugging-port=${String(port)}`, ...params.extraArguments ?? []],
18
- { detached: true, stdio: "ignore" }
26
+ { detached: true, stdio: ["ignore", "pipe", "pipe"] }
19
27
  );
28
+ const capture = attachProcessCapture(child, {
29
+ maxOutputLengthInCharacters: OBSIDIAN_OUTPUT_TAIL_MAX_LENGTH,
30
+ onChunk: (chunk) => {
31
+ const text = chunk.text.trimEnd();
32
+ if (text.length > 0) {
33
+ log(`[obsidian-instance:${chunk.stream}] ${text}`);
34
+ }
35
+ }
36
+ });
37
+ let isKillExpected = false;
38
+ child.once("exit", (code, signal) => {
39
+ if (isKillExpected) {
40
+ log(`[obsidian-instance] Owned Obsidian exited as asked: pid=${String(child.pid)} code=${String(code)} signal=${String(signal)}`);
41
+ return;
42
+ }
43
+ log(`[obsidian-instance] !!! OWNED OBSIDIAN EXITED: pid=${String(child.pid)} code=${String(code)} signal=${String(signal)}`);
44
+ writeOwnedInstanceExitMarker({
45
+ code,
46
+ outputTail: capture.readOutput(),
47
+ pid: child.pid,
48
+ port,
49
+ signal
50
+ });
51
+ });
20
52
  child.unref();
21
53
  try {
22
54
  await waitForCdpReady(cdpUrl);
23
55
  log(`[obsidian-instance] Owned Obsidian is serving CDP at ${cdpUrl}.`);
24
- return { cdpUrl, kill, parentLivenessPort: livenessServer.port, port };
56
+ return {
57
+ cdpUrl,
58
+ kill,
59
+ parentLivenessPort: livenessServer.port,
60
+ port,
61
+ readExitInfo: () => capture.readExitInfo(),
62
+ readOutput: () => capture.readOutput()
63
+ };
25
64
  } catch (error) {
65
+ const exitInfo = capture.readExitInfo();
26
66
  kill();
67
+ if (exitInfo) {
68
+ throw new OwnedInstanceExitedError({
69
+ cdpUrl,
70
+ code: exitInfo.code,
71
+ outputTail: capture.readOutput(),
72
+ pid: child.pid,
73
+ signal: exitInfo.signal,
74
+ spawnError: exitInfo.spawnError
75
+ });
76
+ }
27
77
  throw error;
28
78
  }
29
79
  function kill() {
80
+ isKillExpected = true;
81
+ clearOwnedInstanceExitMarker(port);
30
82
  livenessServer.close();
31
83
  killProcessTree(child);
32
84
  }
@@ -75,4 +127,4 @@ export {
75
127
  launchOwnedObsidianInstance,
76
128
  pickFreePort
77
129
  };
78
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLWluc3RhbmNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogTGF1bmNoZXMgYW5kIG1hbmFnZXMgYSBoYXJuZXNzLW93bmVkLCBpc29sYXRlZCBPYnNpZGlhbiBkZXNrdG9wIGluc3RhbmNlLlxuICpcbiAqIFRoZSBpbnN0YW5jZSBydW5zIGFnYWluc3QgYSBkZWRpY2F0ZWQgYC0tdXNlci1kYXRhLWRpcmAgKHNvIGl0IG5ldmVyIHRvdWNoZXNcbiAqIHRoZSB1c2VyJ3MgT2JzaWRpYW4gY29uZmlnLCByZWdpc3RyeSwgb3IgcnVubmluZyB3aW5kb3cpIGFuZCBleHBvc2VzIENEUCBvbiBhXG4gKiBkZWRpY2F0ZWQgYC0tcmVtb3RlLWRlYnVnZ2luZy1wb3J0YC4gQmVjYXVzZSBFbGVjdHJvbidzIHNpbmdsZS1pbnN0YW5jZSBsb2NrXG4gKiBpcyBrZXllZCB0byB0aGUgdXNlci1kYXRhIGRpciwgdGhlIG93bmVkIGluc3RhbmNlIHJ1bnMgaW4gcGFyYWxsZWwgd2l0aCB0aGVcbiAqIHVzZXIncyBvd24gT2JzaWRpYW4uIENvbmZpcm1lZCBieSB0aGUgUGhhc2UgMCBzcGlrZSAoc2VlIHRoZSBwcm9qZWN0IHBsYW4pLlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIHByb2Nlc3MgbWFuYWdlbWVudCBjb3ZlcmVkIGJ5IGludGVncmF0aW9uIHRlc3RzLCBub3QgdW5pdCB0ZXN0cy4gKi9cblxuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdub2RlOmNoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgY3JlYXRlU2VydmVyIH0gZnJvbSAnbm9kZTpuZXQnO1xuXG5pbXBvcnQgeyBraWxsUHJvY2Vzc1RyZWUgfSBmcm9tICcuL2tpbGwtcHJvY2Vzcy10cmVlLm1qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZy5tanMnO1xuaW1wb3J0IHsgc3RhcnRQYXJlbnRMaXZlbmVzc1NlcnZlciB9IGZyb20gJy4vcGFyZW50LWxpdmVuZXNzLm1qcyc7XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIGxhdW5jaE93bmVkT2JzaWRpYW5JbnN0YW5jZX0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGF1bmNoT3duZWRPYnNpZGlhbkluc3RhbmNlUGFyYW1zIHtcbiAgLyoqXG4gICAqIENEUCBob3N0IHRvIGJpbmQvcG9sbC5cbiAgICpcbiAgICogQGRlZmF1bHQgYCcxMjcuMC4wLjEnYFxuICAgKi9cbiAgcmVhZG9ubHkgY2RwSG9zdD86IHN0cmluZztcblxuICAvKipcbiAgQWJzb2x1dGUgcGF0aCB0byB0aGUgT2JzaWRpYW4gZXhlY3V0YWJsZSAoc2hlbGwpIHRvIGxhdW5jaC5cbiAgICovXG4gIHJlYWRvbmx5IGV4ZVBhdGg6IHN0cmluZztcblxuICAvKipcbiAgICogRXh0cmEgY29tbWFuZC1saW5lIGFyZ3VtZW50cyBhcHBlbmRlZCBhZnRlciBgLS11c2VyLWRhdGEtZGlyYCBhbmRcbiAgICogYC0tcmVtb3RlLWRlYnVnZ2luZy1wb3J0YCBcdTIwMTQgdXNlZCB0byBwYXNzIHRoZSBrZWVwLWFsaXZlIENocm9taXVtIGZsYWdzIHdoZW5cbiAgICogdGhlIGluc3RhbmNlIGlzIGxhdW5jaGVkIGhpZGRlbiAob2ZmLXNjcmVlbikuIEVtcHR5IGJ5IGRlZmF1bHQuXG4gICAqL1xuICByZWFkb25seSBleHRyYUFyZ3VtZW50cz86IHJlYWRvbmx5IHN0cmluZ1tdO1xuXG4gIC8qKlxuICBBYnNvbHV0ZSBwYXRoIHRvIHRoZSBpc29sYXRlZCB1c2VyLWRhdGEgZGlyIHRvIHBhc3MgdmlhIGAtLXVzZXItZGF0YS1kaXJgLlxuICAgKi9cblxuICByZWFkb25seSB1c2VyRGF0YURpcmVjdG9yeTogc3RyaW5nO1xufVxuXG4vKipcbiAqIEEgcnVubmluZywgaGFybmVzcy1vd25lZCBPYnNpZGlhbiBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBPd25lZE9ic2lkaWFuSW5zdGFuY2Uge1xuICAvKipcbiAgQmFzZSBDRFAgVVJMLCBlLmcuIGBodHRwOi8vMTI3LjAuMC4xOjUxODg4YC5cbiAgICovXG4gIHJlYWRvbmx5IGNkcFVybDogc3RyaW5nO1xuXG4gIC8qKlxuICBLaWxscyB0aGUgaW5zdGFuY2UgYW5kIGl0cyBlbnRpcmUgcHJvY2VzcyB0cmVlLlxuICAgKi9cbiAga2lsbCgpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBMb29wYmFjayBwb3J0IHRoZSBpbnN0YW5jZSdzIHJlbmRlcmVyIGNvbm5lY3RzIGJhY2sgdG8gc28gaXQgZGVzdHJveXNcbiAgICogaXRzZWxmIGlmIHRoaXMgaGFybmVzcyBwcm9jZXNzIGRpZXMgd2l0aG91dCBjbGVhbmluZyB1cC4gU2VlXG4gICAqIGBwYXJlbnQtbGl2ZW5lc3MudHNgIGZvciB3aHkgdGhlIHBhcmVudC9jaGlsZCByZWxhdGlvbnNoaXAgYWxvbmUgaXMgbm90XG4gICAqIGVub3VnaC5cbiAgICovXG4gIHJlYWRvbmx5IHBhcmVudExpdmVuZXNzUG9ydDogbnVtYmVyO1xuXG4gIC8qKlxuICBUaGUgQ0RQIHJlbW90ZS1kZWJ1Z2dpbmcgcG9ydCB0aGUgaW5zdGFuY2Ugd2FzIGxhdW5jaGVkIHdpdGguXG4gICAqL1xuICByZWFkb25seSBwb3J0OiBudW1iZXI7XG59XG5cbmNvbnN0IERFRkFVTFRfQ0RQX0hPU1QgPSAnMTI3LjAuMC4xJztcbmNvbnN0IENEUF9SRUFEWV9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyA9IDEwMDA7XG5jb25zdCBDRFBfUkVBRFlfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSA2MF8wMDA7XG5cbmludGVyZmFjZSBDZHBUYXJnZXQge1xuICB0eXBlOiBzdHJpbmc7XG59XG5cbi8qKlxuICogTGF1bmNoZXMgYW4gaXNvbGF0ZWQsIGhhcm5lc3Mtb3duZWQgT2JzaWRpYW4gaW5zdGFuY2UgYW5kIHdhaXRzIHVudGlsIGl0cyBDRFBcbiAqIGVuZHBvaW50IGlzIHNlcnZpbmcgcGFnZSB0YXJnZXRzLlxuICpcbiAqIEBwYXJhbSBwYXJhbXMgLSBMYXVuY2ggcGFyYW1ldGVycy5cbiAqIEByZXR1cm5zIFRoZSBydW5uaW5nIG93bmVkIGluc3RhbmNlLlxuICogQHRocm93cyBFcnJvciBpZiBDRFAgZG9lcyBub3QgYmVjb21lIHJlYWNoYWJsZSB3aXRoaW4gdGhlIHRpbWVvdXQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsYXVuY2hPd25lZE9ic2lkaWFuSW5zdGFuY2UoXG4gIHBhcmFtczogTGF1bmNoT3duZWRPYnNpZGlhbkluc3RhbmNlUGFyYW1zXG4pOiBQcm9taXNlPE93bmVkT2JzaWRpYW5JbnN0YW5jZT4ge1xuICBjb25zdCBjZHBIb3N0ID0gcGFyYW1zLmNkcEhvc3QgPz8gREVGQVVMVF9DRFBfSE9TVDtcbiAgY29uc3QgcG9ydCA9IGF3YWl0IHBpY2tGcmVlUG9ydCgpO1xuICBjb25zdCBjZHBVcmwgPSBgaHR0cDovLyR7Y2RwSG9zdH06JHtTdHJpbmcocG9ydCl9YDtcblxuICAvLyBMaXN0ZW4gQkVGT1JFIHNwYXduaW5nLCBzbyB0aGUgcmVuZGVyZXIgd2F0Y2hkb2cgY2FuIG5ldmVyIHJhY2UgdGhlIHNlcnZlclxuICAvLyBJbnRvIGEgZmFpbGVkIGNvbm5lY3QgKHdoaWNoIGl0IHRyZWF0cyBhcyBcIm5vIHdhdGNoZG9nXCIsIGxlYXZpbmcgdGhlIGluc3RhbmNlIGFsaXZlKS5cbiAgY29uc3QgbGl2ZW5lc3NTZXJ2ZXIgPSBhd2FpdCBzdGFydFBhcmVudExpdmVuZXNzU2VydmVyKCk7XG5cbiAgbG9nKGBbb2JzaWRpYW4taW5zdGFuY2VdIExhdW5jaGluZyBvd25lZCBPYnNpZGlhbjogdXNlckRhdGE9JHtwYXJhbXMudXNlckRhdGFEaXJlY3Rvcnl9LCBjZHBQb3J0PSR7U3RyaW5nKHBvcnQpfWApO1xuICBjb25zdCBjaGlsZCA9IHNwYXduKFxuICAgIHBhcmFtcy5leGVQYXRoLFxuICAgIFtgLS11c2VyLWRhdGEtZGlyPSR7cGFyYW1zLnVzZXJEYXRhRGlyZWN0b3J5fWAsIGAtLXJlbW90ZS1kZWJ1Z2dpbmctcG9ydD0ke1N0cmluZyhwb3J0KX1gLCAuLi4ocGFyYW1zLmV4dHJhQXJndW1lbnRzID8/IFtdKV0sXG4gICAgeyBkZXRhY2hlZDogdHJ1ZSwgc3RkaW86ICdpZ25vcmUnIH1cbiAgKTtcbiAgY2hpbGQudW5yZWYoKTtcblxuICB0cnkge1xuICAgIGF3YWl0IHdhaXRGb3JDZHBSZWFkeShjZHBVcmwpO1xuICAgIGxvZyhgW29ic2lkaWFuLWluc3RhbmNlXSBPd25lZCBPYnNpZGlhbiBpcyBzZXJ2aW5nIENEUCBhdCAke2NkcFVybH0uYCk7XG4gICAgcmV0dXJuIHsgY2RwVXJsLCBraWxsLCBwYXJlbnRMaXZlbmVzc1BvcnQ6IGxpdmVuZXNzU2VydmVyLnBvcnQsIHBvcnQgfTtcbiAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICBraWxsKCk7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cblxuICBmdW5jdGlvbiBraWxsKCk6IHZvaWQge1xuICAgIGxpdmVuZXNzU2VydmVyLmNsb3NlKCk7XG4gICAga2lsbFByb2Nlc3NUcmVlKGNoaWxkKTtcbiAgfVxufVxuXG4vKipcbiAqIFBpY2tzIGEgZnJlZSBUQ1AgcG9ydCBieSBiaW5kaW5nIHRvIHBvcnQgYDBgIGFuZCByZWFkaW5nIHRoZSBhc3NpZ25lZCBwb3J0LlxuICpcbiAqIFRoZXJlIGlzIGEgc21hbGwgdGltZS1vZi1jaGVjay90aW1lLW9mLXVzZSB3aW5kb3cgYmV0d2VlbiByZWxlYXNpbmcgdGhlIHBvcnRcbiAqIGhlcmUgYW5kIE9ic2lkaWFuIGJpbmRpbmcgaXQ7IGluIHByYWN0aWNlIGl0IGlzIG5lZ2xpZ2libGUgZm9yIHRlc3QgcnVucy5cbiAqXG4gKiBAcmV0dXJucyBBIGZyZWUgVENQIHBvcnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwaWNrRnJlZVBvcnQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBzZXJ2ZXIgPSBjcmVhdGVTZXJ2ZXIoKTtcbiAgICBzZXJ2ZXIub25jZSgnZXJyb3InLCByZWplY3QpO1xuICAgIHNlcnZlci5saXN0ZW4oMCwgREVGQVVMVF9DRFBfSE9TVCwgKCkgPT4ge1xuICAgICAgY29uc3QgYWRkcmVzcyA9IHNlcnZlci5hZGRyZXNzKCk7XG4gICAgICBpZiAoYWRkcmVzcyA9PT0gbnVsbCB8fCB0eXBlb2YgYWRkcmVzcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgc2VydmVyLmNsb3NlKCk7XG4gICAgICAgIHJlamVjdChuZXcgRXJyb3IoJ0ZhaWxlZCB0byBkZXRlcm1pbmUgYSBmcmVlIHBvcnQuJykpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCB7IHBvcnQgfSA9IGFkZHJlc3M7XG4gICAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xuICAgICAgICByZXNvbHZlKHBvcnQpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIGdpdmVuIGRlbGF5LlxuICpcbiAqIEBwYXJhbSBtcyAtIFRoZSBkZWxheSBpbiBtaWxsaXNlY29uZHMuXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgZGVsYXkuXG4gKi9cbmZ1bmN0aW9uIGRlbGF5KG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgc2V0VGltZW91dChyZXNvbHZlLCBtcyk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFBvbGxzIHRoZSBDRFAgYC9qc29uYCBlbmRwb2ludCB1bnRpbCBhdCBsZWFzdCBvbmUgcGFnZSB0YXJnZXQgYXBwZWFycy5cbiAqXG4gKiBAcGFyYW0gY2RwVXJsIC0gVGhlIGJhc2UgQ0RQIFVSTC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gd2FpdEZvckNkcFJlYWR5KGNkcFVybDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGRlYWRsaW5lID0gRGF0ZS5ub3coKSArIENEUF9SRUFEWV9USU1FT1VUX0lOX01JTExJU0VDT05EUztcbiAgd2hpbGUgKERhdGUubm93KCkgPCBkZWFkbGluZSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke2NkcFVybH0vanNvbmApO1xuICAgICAgY29uc3QgdGFyZ2V0cyA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKSBhcyBDZHBUYXJnZXRbXTtcbiAgICAgIGlmICh0YXJnZXRzLnNvbWUoKHRhcmdldCkgPT4gdGFyZ2V0LnR5cGUgPT09ICdwYWdlJykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gRW5kcG9pbnQgbm90IHVwIHlldCBcdTIwMTQga2VlcCBwb2xsaW5nLlxuICAgIH1cbiAgICBhd2FpdCBkZWxheShDRFBfUkVBRFlfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgT3duZWQgT2JzaWRpYW4gaW5zdGFuY2UgZGlkIG5vdCBleHBvc2UgQ0RQIGF0ICR7Y2RwVXJsfSB3aXRoaW4gJHtTdHJpbmcoQ0RQX1JFQURZX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTKX1tcy5gXG4gICk7XG59XG5cbi8qIHY4IGlnbm9yZSBzdG9wICovXG4iXSwKICAibWFwcGluZ3MiOiAiQUFjQSxTQUFTLGFBQWE7QUFDdEIsU0FBUyxvQkFBb0I7QUFFN0IsU0FBUyx1QkFBdUI7QUFDaEMsU0FBUyxXQUFXO0FBQ3BCLFNBQVMsaUNBQWlDO0FBNEQxQyxNQUFNLG1CQUFtQjtBQUN6QixNQUFNLDBDQUEwQztBQUNoRCxNQUFNLG9DQUFvQztBQWMxQyxlQUFzQiw0QkFDcEIsUUFDZ0M7QUFDaEMsUUFBTSxVQUFVLE9BQU8sV0FBVztBQUNsQyxRQUFNLE9BQU8sTUFBTSxhQUFhO0FBQ2hDLFFBQU0sU0FBUyxVQUFVLE9BQU8sSUFBSSxPQUFPLElBQUksQ0FBQztBQUloRCxRQUFNLGlCQUFpQixNQUFNLDBCQUEwQjtBQUV2RCxNQUFJLDBEQUEwRCxPQUFPLGlCQUFpQixhQUFhLE9BQU8sSUFBSSxDQUFDLEVBQUU7QUFDakgsUUFBTSxRQUFRO0FBQUEsSUFDWixPQUFPO0FBQUEsSUFDUCxDQUFDLG1CQUFtQixPQUFPLGlCQUFpQixJQUFJLDJCQUEyQixPQUFPLElBQUksQ0FBQyxJQUFJLEdBQUksT0FBTyxrQkFBa0IsQ0FBQyxDQUFFO0FBQUEsSUFDM0gsRUFBRSxVQUFVLE1BQU0sT0FBTyxTQUFTO0FBQUEsRUFDcEM7QUFDQSxRQUFNLE1BQU07QUFFWixNQUFJO0FBQ0YsVUFBTSxnQkFBZ0IsTUFBTTtBQUM1QixRQUFJLHdEQUF3RCxNQUFNLEdBQUc7QUFDckUsV0FBTyxFQUFFLFFBQVEsTUFBTSxvQkFBb0IsZUFBZSxNQUFNLEtBQUs7QUFBQSxFQUN2RSxTQUFTLE9BQWdCO0FBQ3ZCLFNBQUs7QUFDTCxVQUFNO0FBQUEsRUFDUjtBQUVBLFdBQVMsT0FBYTtBQUNwQixtQkFBZSxNQUFNO0FBQ3JCLG9CQUFnQixLQUFLO0FBQUEsRUFDdkI7QUFDRjtBQVVPLFNBQVMsZUFBZ0M7QUFDOUMsU0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFDdEMsVUFBTSxTQUFTLGFBQWE7QUFDNUIsV0FBTyxLQUFLLFNBQVMsTUFBTTtBQUMzQixXQUFPLE9BQU8sR0FBRyxrQkFBa0IsTUFBTTtBQUN2QyxZQUFNLFVBQVUsT0FBTyxRQUFRO0FBQy9CLFVBQUksWUFBWSxRQUFRLE9BQU8sWUFBWSxVQUFVO0FBQ25ELGVBQU8sTUFBTTtBQUNiLGVBQU8sSUFBSSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3BEO0FBQUEsTUFDRjtBQUNBLFlBQU0sRUFBRSxLQUFLLElBQUk7QUFDakIsYUFBTyxNQUFNLE1BQU07QUFDakIsZ0JBQVEsSUFBSTtBQUFBLE1BQ2QsQ0FBQztBQUFBLElBQ0gsQ0FBQztBQUFBLEVBQ0gsQ0FBQztBQUNIO0FBUUEsU0FBUyxNQUFNLElBQTJCO0FBQ3hDLFNBQU8sSUFBSSxRQUFRLENBQUMsWUFBWTtBQUM5QixlQUFXLFNBQVMsRUFBRTtBQUFBLEVBQ3hCLENBQUM7QUFDSDtBQU9BLGVBQWUsZ0JBQWdCLFFBQStCO0FBQzVELFFBQU0sV0FBVyxLQUFLLElBQUksSUFBSTtBQUM5QixTQUFPLEtBQUssSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSTtBQUNGLFlBQU0sV0FBVyxNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU87QUFDN0MsWUFBTSxVQUFVLE1BQU0sU0FBUyxLQUFLO0FBQ3BDLFVBQUksUUFBUSxLQUFLLENBQUMsV0FBVyxPQUFPLFNBQVMsTUFBTSxHQUFHO0FBQ3BEO0FBQUEsTUFDRjtBQUFBLElBQ0YsUUFBUTtBQUFBLElBRVI7QUFDQSxVQUFNLE1BQU0sdUNBQXVDO0FBQUEsRUFDckQ7QUFDQSxRQUFNLElBQUk7QUFBQSxJQUNSLGlEQUFpRCxNQUFNLFdBQVcsT0FBTyxpQ0FBaUMsQ0FBQztBQUFBLEVBQzdHO0FBQ0Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
130
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLWluc3RhbmNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogTGF1bmNoZXMgYW5kIG1hbmFnZXMgYSBoYXJuZXNzLW93bmVkLCBpc29sYXRlZCBPYnNpZGlhbiBkZXNrdG9wIGluc3RhbmNlLlxuICpcbiAqIFRoZSBpbnN0YW5jZSBydW5zIGFnYWluc3QgYSBkZWRpY2F0ZWQgYC0tdXNlci1kYXRhLWRpcmAgKHNvIGl0IG5ldmVyIHRvdWNoZXNcbiAqIHRoZSB1c2VyJ3MgT2JzaWRpYW4gY29uZmlnLCByZWdpc3RyeSwgb3IgcnVubmluZyB3aW5kb3cpIGFuZCBleHBvc2VzIENEUCBvbiBhXG4gKiBkZWRpY2F0ZWQgYC0tcmVtb3RlLWRlYnVnZ2luZy1wb3J0YC4gQmVjYXVzZSBFbGVjdHJvbidzIHNpbmdsZS1pbnN0YW5jZSBsb2NrXG4gKiBpcyBrZXllZCB0byB0aGUgdXNlci1kYXRhIGRpciwgdGhlIG93bmVkIGluc3RhbmNlIHJ1bnMgaW4gcGFyYWxsZWwgd2l0aCB0aGVcbiAqIHVzZXIncyBvd24gT2JzaWRpYW4uIENvbmZpcm1lZCBieSB0aGUgUGhhc2UgMCBzcGlrZSAoc2VlIHRoZSBwcm9qZWN0IHBsYW4pLlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIHByb2Nlc3MgbWFuYWdlbWVudCBjb3ZlcmVkIGJ5IGludGVncmF0aW9uIHRlc3RzLCBub3QgdW5pdCB0ZXN0cy4gKi9cblxuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdub2RlOmNoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgY3JlYXRlU2VydmVyIH0gZnJvbSAnbm9kZTpuZXQnO1xuXG5pbXBvcnQgdHlwZSB7IFByb2Nlc3NFeGl0SW5mbyB9IGZyb20gJy4vcHJvY2Vzcy1leGl0LW1lc3NhZ2UubWpzJztcblxuaW1wb3J0IHsga2lsbFByb2Nlc3NUcmVlIH0gZnJvbSAnLi9raWxsLXByb2Nlc3MtdHJlZS5tanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2cubWpzJztcbmltcG9ydCB7XG4gIGNsZWFyT3duZWRJbnN0YW5jZUV4aXRNYXJrZXIsXG4gIHdyaXRlT3duZWRJbnN0YW5jZUV4aXRNYXJrZXJcbn0gZnJvbSAnLi9vd25lZC1pbnN0YW5jZS1leGl0LW1hcmtlci5tanMnO1xuaW1wb3J0IHsgT3duZWRJbnN0YW5jZUV4aXRlZEVycm9yIH0gZnJvbSAnLi9vd25lZC1pbnN0YW5jZS1leGl0ZWQtZXJyb3IubWpzJztcbmltcG9ydCB7IHN0YXJ0UGFyZW50TGl2ZW5lc3NTZXJ2ZXIgfSBmcm9tICcuL3BhcmVudC1saXZlbmVzcy5tanMnO1xuaW1wb3J0IHsgYXR0YWNoUHJvY2Vzc0NhcHR1cmUgfSBmcm9tICcuL3Byb2Nlc3MtY2FwdHVyZS5tanMnO1xuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBsYXVuY2hPd25lZE9ic2lkaWFuSW5zdGFuY2V9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhdW5jaE93bmVkT2JzaWRpYW5JbnN0YW5jZVBhcmFtcyB7XG4gIC8qKlxuICAgKiBDRFAgaG9zdCB0byBiaW5kL3BvbGwuXG4gICAqXG4gICAqIEBkZWZhdWx0IGAnMTI3LjAuMC4xJ2BcbiAgICovXG4gIHJlYWRvbmx5IGNkcEhvc3Q/OiBzdHJpbmc7XG5cbiAgLyoqXG4gIEFic29sdXRlIHBhdGggdG8gdGhlIE9ic2lkaWFuIGV4ZWN1dGFibGUgKHNoZWxsKSB0byBsYXVuY2guXG4gICAqL1xuICByZWFkb25seSBleGVQYXRoOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEV4dHJhIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYXBwZW5kZWQgYWZ0ZXIgYC0tdXNlci1kYXRhLWRpcmAgYW5kXG4gICAqIGAtLXJlbW90ZS1kZWJ1Z2dpbmctcG9ydGAgXHUyMDE0IHVzZWQgdG8gcGFzcyB0aGUga2VlcC1hbGl2ZSBDaHJvbWl1bSBmbGFncyB3aGVuXG4gICAqIHRoZSBpbnN0YW5jZSBpcyBsYXVuY2hlZCBoaWRkZW4gKG9mZi1zY3JlZW4pLiBFbXB0eSBieSBkZWZhdWx0LlxuICAgKi9cbiAgcmVhZG9ubHkgZXh0cmFBcmd1bWVudHM/OiByZWFkb25seSBzdHJpbmdbXTtcblxuICAvKipcbiAgQWJzb2x1dGUgcGF0aCB0byB0aGUgaXNvbGF0ZWQgdXNlci1kYXRhIGRpciB0byBwYXNzIHZpYSBgLS11c2VyLWRhdGEtZGlyYC5cbiAgICovXG5cbiAgcmVhZG9ubHkgdXNlckRhdGFEaXJlY3Rvcnk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBBIHJ1bm5pbmcsIGhhcm5lc3Mtb3duZWQgT2JzaWRpYW4gaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3duZWRPYnNpZGlhbkluc3RhbmNlIHtcbiAgLyoqXG4gIEJhc2UgQ0RQIFVSTCwgZS5nLiBgaHR0cDovLzEyNy4wLjAuMTo1MTg4OGAuXG4gICAqL1xuICByZWFkb25seSBjZHBVcmw6IHN0cmluZztcblxuICAvKipcbiAgS2lsbHMgdGhlIGluc3RhbmNlIGFuZCBpdHMgZW50aXJlIHByb2Nlc3MgdHJlZS5cbiAgICovXG4gIGtpbGwoKTogdm9pZDtcblxuICAvKipcbiAgICogTG9vcGJhY2sgcG9ydCB0aGUgaW5zdGFuY2UncyByZW5kZXJlciBjb25uZWN0cyBiYWNrIHRvIHNvIGl0IGRlc3Ryb3lzXG4gICAqIGl0c2VsZiBpZiB0aGlzIGhhcm5lc3MgcHJvY2VzcyBkaWVzIHdpdGhvdXQgY2xlYW5pbmcgdXAuIFNlZVxuICAgKiBgcGFyZW50LWxpdmVuZXNzLnRzYCBmb3Igd2h5IHRoZSBwYXJlbnQvY2hpbGQgcmVsYXRpb25zaGlwIGFsb25lIGlzIG5vdFxuICAgKiBlbm91Z2guXG4gICAqL1xuICByZWFkb25seSBwYXJlbnRMaXZlbmVzc1BvcnQ6IG51bWJlcjtcblxuICAvKipcbiAgVGhlIENEUCByZW1vdGUtZGVidWdnaW5nIHBvcnQgdGhlIGluc3RhbmNlIHdhcyBsYXVuY2hlZCB3aXRoLlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGhvdyB0aGUgaW5zdGFuY2UgZGllZCBvbmNlIGl0IGlzIG5vIGxvbmdlciBydW5uaW5nLCBvdGhlcndpc2VcbiAgICogYHVuZGVmaW5lZGAuIFRoaXMgaXMgdGhlIGluLXByb2Nlc3MgaGFsZiBvZiB0aGUgYW5zd2VyOyBhIHRlc3Qgd29ya2VyIGluXG4gICAqIGFub3RoZXIgcHJvY2VzcyByZWFkcyB0aGUgc2FtZSBmYWN0cyBmcm9tIHRoZSBleGl0IG1hcmtlclxuICAgKiAoYG93bmVkLWluc3RhbmNlLWV4aXQtbWFya2VyLnRzYCkuXG4gICAqL1xuICByZWFkRXhpdEluZm8oKTogUHJvY2Vzc0V4aXRJbmZvIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBSZXR1cm5zIHRoZSB0YWlsIG9mIGV2ZXJ5dGhpbmcgdGhlIGluc3RhbmNlIHdyb3RlIHRvIHN0ZG91dC9zdGRlcnIuXG4gICAqL1xuICByZWFkT3V0cHV0KCk6IHN0cmluZztcbn1cblxuY29uc3QgREVGQVVMVF9DRFBfSE9TVCA9ICcxMjcuMC4wLjEnO1xuY29uc3QgQ0RQX1JFQURZX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTID0gMTAwMDtcbmNvbnN0IENEUF9SRUFEWV9USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDYwXzAwMDtcbmNvbnN0IE9CU0lESUFOX09VVFBVVF9UQUlMX01BWF9MRU5HVEggPSA4MDAwO1xuXG5pbnRlcmZhY2UgQ2RwVGFyZ2V0IHtcbiAgdHlwZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIExhdW5jaGVzIGFuIGlzb2xhdGVkLCBoYXJuZXNzLW93bmVkIE9ic2lkaWFuIGluc3RhbmNlIGFuZCB3YWl0cyB1bnRpbCBpdHMgQ0RQXG4gKiBlbmRwb2ludCBpcyBzZXJ2aW5nIHBhZ2UgdGFyZ2V0cy5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gTGF1bmNoIHBhcmFtZXRlcnMuXG4gKiBAcmV0dXJucyBUaGUgcnVubmluZyBvd25lZCBpbnN0YW5jZS5cbiAqIEB0aHJvd3MgRXJyb3IgaWYgQ0RQIGRvZXMgbm90IGJlY29tZSByZWFjaGFibGUgd2l0aGluIHRoZSB0aW1lb3V0LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbGF1bmNoT3duZWRPYnNpZGlhbkluc3RhbmNlKFxuICBwYXJhbXM6IExhdW5jaE93bmVkT2JzaWRpYW5JbnN0YW5jZVBhcmFtc1xuKTogUHJvbWlzZTxPd25lZE9ic2lkaWFuSW5zdGFuY2U+IHtcbiAgY29uc3QgY2RwSG9zdCA9IHBhcmFtcy5jZHBIb3N0ID8/IERFRkFVTFRfQ0RQX0hPU1Q7XG4gIGNvbnN0IHBvcnQgPSBhd2FpdCBwaWNrRnJlZVBvcnQoKTtcbiAgY29uc3QgY2RwVXJsID0gYGh0dHA6Ly8ke2NkcEhvc3R9OiR7U3RyaW5nKHBvcnQpfWA7XG5cbiAgLy8gTGlzdGVuIEJFRk9SRSBzcGF3bmluZywgc28gdGhlIHJlbmRlcmVyIHdhdGNoZG9nIGNhbiBuZXZlciByYWNlIHRoZSBzZXJ2ZXJcbiAgLy8gSW50byBhIGZhaWxlZCBjb25uZWN0ICh3aGljaCBpdCB0cmVhdHMgYXMgXCJubyB3YXRjaGRvZ1wiLCBsZWF2aW5nIHRoZSBpbnN0YW5jZSBhbGl2ZSkuXG4gIGNvbnN0IGxpdmVuZXNzU2VydmVyID0gYXdhaXQgc3RhcnRQYXJlbnRMaXZlbmVzc1NlcnZlcigpO1xuXG4gIC8vIFBvcnRzIGFyZSByZWN5Y2xlZCBieSB0aGUgT1MsIHNvIGFuIG9sZGVyIGluc3RhbmNlJ3MgZGVhdGggcmVjb3JkZWQgb24gdGhpc1xuICAvLyBQb3J0IHdvdWxkIG90aGVyd2lzZSBiZSByZWFkIGFzIHRoaXMgb25lJ3MuXG4gIGNsZWFyT3duZWRJbnN0YW5jZUV4aXRNYXJrZXIocG9ydCk7XG5cbiAgbG9nKGBbb2JzaWRpYW4taW5zdGFuY2VdIExhdW5jaGluZyBvd25lZCBPYnNpZGlhbjogdXNlckRhdGE9JHtwYXJhbXMudXNlckRhdGFEaXJlY3Rvcnl9LCBjZHBQb3J0PSR7U3RyaW5nKHBvcnQpfWApO1xuICAvKlxuICAgKiBQaXBlZCByYXRoZXIgdGhhbiBgJ2lnbm9yZSdgOiBhbiBFbGVjdHJvbi9DaHJvbWl1bSBmYXRhbCBpcyB3cml0dGVuIHRvXG4gICAqIHN0ZGVyciBhbmQgbm93aGVyZSBlbHNlLCBhbmQgZGlzY2FyZGluZyBpdCBpcyB3aHkgYSBkeWluZyBpbnN0YW5jZSB1c2VkIHRvXG4gICAqIGJlIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gYSBoZWFsdGh5IG9uZS4gVGhlIGNhcHR1cmUgZHJhaW5zIGJvdGggcGlwZXMgZm9yXG4gICAqIHRoZSBwcm9jZXNzJ3Mgd2hvbGUgbGlmZSAoYSBmdWxsIHBpcGUgYnVmZmVyIHdvdWxkIGJsb2NrIHRoZSBhcHAgaXRzZWxmKSBhbmRcbiAgICoga2VlcHMgb25seSBhIGJvdW5kZWQgdGFpbC5cbiAgICovXG4gIGNvbnN0IGNoaWxkID0gc3Bhd24oXG4gICAgcGFyYW1zLmV4ZVBhdGgsXG4gICAgW2AtLXVzZXItZGF0YS1kaXI9JHtwYXJhbXMudXNlckRhdGFEaXJlY3Rvcnl9YCwgYC0tcmVtb3RlLWRlYnVnZ2luZy1wb3J0PSR7U3RyaW5nKHBvcnQpfWAsIC4uLihwYXJhbXMuZXh0cmFBcmd1bWVudHMgPz8gW10pXSxcbiAgICB7IGRldGFjaGVkOiB0cnVlLCBzdGRpbzogWydpZ25vcmUnLCAncGlwZScsICdwaXBlJ10gfVxuICApO1xuICBjb25zdCBjYXB0dXJlID0gYXR0YWNoUHJvY2Vzc0NhcHR1cmUoY2hpbGQsIHtcbiAgICBtYXhPdXRwdXRMZW5ndGhJbkNoYXJhY3RlcnM6IE9CU0lESUFOX09VVFBVVF9UQUlMX01BWF9MRU5HVEgsXG4gICAgb25DaHVuazogKGNodW5rKSA9PiB7XG4gICAgICBjb25zdCB0ZXh0ID0gY2h1bmsudGV4dC50cmltRW5kKCk7XG4gICAgICBpZiAodGV4dC5sZW5ndGggPiAwKSB7XG4gICAgICAgIGxvZyhgW29ic2lkaWFuLWluc3RhbmNlOiR7Y2h1bmsuc3RyZWFtfV0gJHt0ZXh0fWApO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgLy8gU2V0IGJ5IGBraWxsKClgLCBzbyBhIGRlYXRoIHRoZSBoYXJuZXNzIG9yZGVyZWQgaXMgbmV2ZXIgcmVwb3J0ZWQgYXMgb25lIGl0XG4gIC8vIFN1ZmZlcmVkIFx1MjAxNCBhIG1hcmtlciBsZWZ0IGJ5IGEgY2xlYW4gdGVhcmRvd24gd291bGQgY29udmljdCB0aGUgbmV4dCBydW4nc1xuICAvLyBIZWFsdGh5IGluc3RhbmNlIG9mIGFuIGV4aXQgdGhhdCBuZXZlciBoYXBwZW5lZC5cbiAgbGV0IGlzS2lsbEV4cGVjdGVkID0gZmFsc2U7XG5cbiAgY2hpbGQub25jZSgnZXhpdCcsIChjb2RlOiBudWxsIHwgbnVtYmVyLCBzaWduYWw6IE5vZGVKUy5TaWduYWxzIHwgbnVsbCkgPT4ge1xuICAgIGlmIChpc0tpbGxFeHBlY3RlZCkge1xuICAgICAgbG9nKGBbb2JzaWRpYW4taW5zdGFuY2VdIE93bmVkIE9ic2lkaWFuIGV4aXRlZCBhcyBhc2tlZDogcGlkPSR7U3RyaW5nKGNoaWxkLnBpZCl9IGNvZGU9JHtTdHJpbmcoY29kZSl9IHNpZ25hbD0ke1N0cmluZyhzaWduYWwpfWApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIExvdWQgb24gcHVycG9zZS4gVGhpcyBvbmUgbGluZSBpcyB3aGF0IHNlcGFyYXRlcyBhIGNsZWFuIHF1aXQgZnJvbSBhXG4gICAgLy8gQ3Jhc2gsIGFuZCBpdHMgYWJzZW5jZSBvbmNlIGNvc3QgYSBkYXkgb2YgZ3Vlc3NpbmcuXG4gICAgbG9nKGBbb2JzaWRpYW4taW5zdGFuY2VdICEhISBPV05FRCBPQlNJRElBTiBFWElURUQ6IHBpZD0ke1N0cmluZyhjaGlsZC5waWQpfSBjb2RlPSR7U3RyaW5nKGNvZGUpfSBzaWduYWw9JHtTdHJpbmcoc2lnbmFsKX1gKTtcbiAgICB3cml0ZU93bmVkSW5zdGFuY2VFeGl0TWFya2VyKHtcbiAgICAgIGNvZGUsXG4gICAgICBvdXRwdXRUYWlsOiBjYXB0dXJlLnJlYWRPdXRwdXQoKSxcbiAgICAgIHBpZDogY2hpbGQucGlkLFxuICAgICAgcG9ydCxcbiAgICAgIHNpZ25hbFxuICAgIH0pO1xuICB9KTtcblxuICBjaGlsZC51bnJlZigpO1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgd2FpdEZvckNkcFJlYWR5KGNkcFVybCk7XG4gICAgbG9nKGBbb2JzaWRpYW4taW5zdGFuY2VdIE93bmVkIE9ic2lkaWFuIGlzIHNlcnZpbmcgQ0RQIGF0ICR7Y2RwVXJsfS5gKTtcbiAgICByZXR1cm4ge1xuICAgICAgY2RwVXJsLFxuICAgICAga2lsbCxcbiAgICAgIHBhcmVudExpdmVuZXNzUG9ydDogbGl2ZW5lc3NTZXJ2ZXIucG9ydCxcbiAgICAgIHBvcnQsXG4gICAgICByZWFkRXhpdEluZm86ICgpID0+IGNhcHR1cmUucmVhZEV4aXRJbmZvKCksXG4gICAgICByZWFkT3V0cHV0OiAoKSA9PiBjYXB0dXJlLnJlYWRPdXRwdXQoKVxuICAgIH07XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgLypcbiAgICAgKiBSZWFkIGJlZm9yZSBraWxsaW5nLCBzbyB0aGUgdmVyZGljdCBpcyB0aGUgaW5zdGFuY2UncyBvd24uIEEgQ0RQIHRpbWVvdXRcbiAgICAgKiB3aG9zZSBwcm9jZXNzIGlzIGFscmVhZHkgZ29uZSBpcyBub3QgYSBzbG93IGJvb3QgXHUyMDE0IGl0IGlzIGEgYm9vdCB0aGF0XG4gICAgICogZW5kZWQgXHUyMDE0IGFuZCBzYXlpbmcgc28gYmVhdHMgcmVwb3J0aW5nIG9ubHkgdGhlIGJ1ZGdldCBpdCBibGV3LlxuICAgICAqXG4gICAgICogRGVsaWJlcmF0ZWx5IE5PVCBhIGZhc3QtZmFpbCBpbnNpZGUgdGhlIHBvbGw6IG9uIHNvbWUgaW5zdGFsbHMgdGhlXG4gICAgICogbGF1bmNoZWQgZXhlY3V0YWJsZSBpcyBhIHNoaW0gdGhhdCBleGl0cyBvbmNlIGl0IGhhcyBoYW5kZWQgb2ZmIHRvIHRoZVxuICAgICAqIHJlYWwgYXBwLCBzbyBhIGRlYWQgY2hpbGQgbWlkLXBvbGwgZG9lcyBub3QgaW1wbHkgYSBkZWFkIGluc3RhbmNlLiBPbmx5IGFcbiAgICAgKiBkZWFkIGNoaWxkIHRoYXQgYWxzbyBuZXZlciBzZXJ2ZWQgQ0RQIGRvZXMuXG4gICAgICovXG4gICAgY29uc3QgZXhpdEluZm8gPSBjYXB0dXJlLnJlYWRFeGl0SW5mbygpO1xuICAgIGtpbGwoKTtcbiAgICBpZiAoZXhpdEluZm8pIHtcbiAgICAgIHRocm93IG5ldyBPd25lZEluc3RhbmNlRXhpdGVkRXJyb3Ioe1xuICAgICAgICBjZHBVcmwsXG4gICAgICAgIGNvZGU6IGV4aXRJbmZvLmNvZGUsXG4gICAgICAgIG91dHB1dFRhaWw6IGNhcHR1cmUucmVhZE91dHB1dCgpLFxuICAgICAgICBwaWQ6IGNoaWxkLnBpZCxcbiAgICAgICAgc2lnbmFsOiBleGl0SW5mby5zaWduYWwsXG4gICAgICAgIHNwYXduRXJyb3I6IGV4aXRJbmZvLnNwYXduRXJyb3JcbiAgICAgIH0pO1xuICAgIH1cbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxuXG4gIGZ1bmN0aW9uIGtpbGwoKTogdm9pZCB7XG4gICAgaXNLaWxsRXhwZWN0ZWQgPSB0cnVlO1xuICAgIGNsZWFyT3duZWRJbnN0YW5jZUV4aXRNYXJrZXIocG9ydCk7XG4gICAgbGl2ZW5lc3NTZXJ2ZXIuY2xvc2UoKTtcbiAgICBraWxsUHJvY2Vzc1RyZWUoY2hpbGQpO1xuICB9XG59XG5cbi8qKlxuICogUGlja3MgYSBmcmVlIFRDUCBwb3J0IGJ5IGJpbmRpbmcgdG8gcG9ydCBgMGAgYW5kIHJlYWRpbmcgdGhlIGFzc2lnbmVkIHBvcnQuXG4gKlxuICogVGhlcmUgaXMgYSBzbWFsbCB0aW1lLW9mLWNoZWNrL3RpbWUtb2YtdXNlIHdpbmRvdyBiZXR3ZWVuIHJlbGVhc2luZyB0aGUgcG9ydFxuICogaGVyZSBhbmQgT2JzaWRpYW4gYmluZGluZyBpdDsgaW4gcHJhY3RpY2UgaXQgaXMgbmVnbGlnaWJsZSBmb3IgdGVzdCBydW5zLlxuICpcbiAqIEByZXR1cm5zIEEgZnJlZSBUQ1AgcG9ydC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBpY2tGcmVlUG9ydCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHNlcnZlciA9IGNyZWF0ZVNlcnZlcigpO1xuICAgIHNlcnZlci5vbmNlKCdlcnJvcicsIHJlamVjdCk7XG4gICAgc2VydmVyLmxpc3RlbigwLCBERUZBVUxUX0NEUF9IT1NULCAoKSA9PiB7XG4gICAgICBjb25zdCBhZGRyZXNzID0gc2VydmVyLmFkZHJlc3MoKTtcbiAgICAgIGlmIChhZGRyZXNzID09PSBudWxsIHx8IHR5cGVvZiBhZGRyZXNzID09PSAnc3RyaW5nJykge1xuICAgICAgICBzZXJ2ZXIuY2xvc2UoKTtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcignRmFpbGVkIHRvIGRldGVybWluZSBhIGZyZWUgcG9ydC4nKSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHsgcG9ydCB9ID0gYWRkcmVzcztcbiAgICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XG4gICAgICAgIHJlc29sdmUocG9ydCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59XG5cbi8qKlxuICogUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgZ2l2ZW4gZGVsYXkuXG4gKlxuICogQHBhcmFtIG1zIC0gVGhlIGRlbGF5IGluIG1pbGxpc2Vjb25kcy5cbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSBkZWxheS5cbiAqL1xuZnVuY3Rpb24gZGVsYXkobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKTtcbiAgfSk7XG59XG5cbi8qKlxuICogUG9sbHMgdGhlIENEUCBgL2pzb25gIGVuZHBvaW50IHVudGlsIGF0IGxlYXN0IG9uZSBwYWdlIHRhcmdldCBhcHBlYXJzLlxuICpcbiAqIEBwYXJhbSBjZHBVcmwgLSBUaGUgYmFzZSBDRFAgVVJMLlxuICovXG5hc3luYyBmdW5jdGlvbiB3YWl0Rm9yQ2RwUmVhZHkoY2RwVXJsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgQ0RQX1JFQURZX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTO1xuICB3aGlsZSAoRGF0ZS5ub3coKSA8IGRlYWRsaW5lKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7Y2RwVXJsfS9qc29uYCk7XG4gICAgICBjb25zdCB0YXJnZXRzID0gYXdhaXQgcmVzcG9uc2UuanNvbigpIGFzIENkcFRhcmdldFtdO1xuICAgICAgaWYgKHRhcmdldHMuc29tZSgodGFyZ2V0KSA9PiB0YXJnZXQudHlwZSA9PT0gJ3BhZ2UnKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBFbmRwb2ludCBub3QgdXAgeWV0IFx1MjAxNCBrZWVwIHBvbGxpbmcuXG4gICAgfVxuICAgIGF3YWl0IGRlbGF5KENEUF9SRUFEWV9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyk7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKFxuICAgIGBPd25lZCBPYnNpZGlhbiBpbnN0YW5jZSBkaWQgbm90IGV4cG9zZSBDRFAgYXQgJHtjZHBVcmx9IHdpdGhpbiAke1N0cmluZyhDRFBfUkVBRFlfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMpfW1zLmBcbiAgKTtcbn1cblxuLyogdjggaWdub3JlIHN0b3AgKi9cbiJdLAogICJtYXBwaW5ncyI6ICJBQWNBLFNBQVMsYUFBYTtBQUN0QixTQUFTLG9CQUFvQjtBQUk3QixTQUFTLHVCQUF1QjtBQUNoQyxTQUFTLFdBQVc7QUFDcEI7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUCxTQUFTLGdDQUFnQztBQUN6QyxTQUFTLGlDQUFpQztBQUMxQyxTQUFTLDRCQUE0QjtBQXlFckMsTUFBTSxtQkFBbUI7QUFDekIsTUFBTSwwQ0FBMEM7QUFDaEQsTUFBTSxvQ0FBb0M7QUFDMUMsTUFBTSxrQ0FBa0M7QUFjeEMsZUFBc0IsNEJBQ3BCLFFBQ2dDO0FBQ2hDLFFBQU0sVUFBVSxPQUFPLFdBQVc7QUFDbEMsUUFBTSxPQUFPLE1BQU0sYUFBYTtBQUNoQyxRQUFNLFNBQVMsVUFBVSxPQUFPLElBQUksT0FBTyxJQUFJLENBQUM7QUFJaEQsUUFBTSxpQkFBaUIsTUFBTSwwQkFBMEI7QUFJdkQsK0JBQTZCLElBQUk7QUFFakMsTUFBSSwwREFBMEQsT0FBTyxpQkFBaUIsYUFBYSxPQUFPLElBQUksQ0FBQyxFQUFFO0FBUWpILFFBQU0sUUFBUTtBQUFBLElBQ1osT0FBTztBQUFBLElBQ1AsQ0FBQyxtQkFBbUIsT0FBTyxpQkFBaUIsSUFBSSwyQkFBMkIsT0FBTyxJQUFJLENBQUMsSUFBSSxHQUFJLE9BQU8sa0JBQWtCLENBQUMsQ0FBRTtBQUFBLElBQzNILEVBQUUsVUFBVSxNQUFNLE9BQU8sQ0FBQyxVQUFVLFFBQVEsTUFBTSxFQUFFO0FBQUEsRUFDdEQ7QUFDQSxRQUFNLFVBQVUscUJBQXFCLE9BQU87QUFBQSxJQUMxQyw2QkFBNkI7QUFBQSxJQUM3QixTQUFTLENBQUMsVUFBVTtBQUNsQixZQUFNLE9BQU8sTUFBTSxLQUFLLFFBQVE7QUFDaEMsVUFBSSxLQUFLLFNBQVMsR0FBRztBQUNuQixZQUFJLHNCQUFzQixNQUFNLE1BQU0sS0FBSyxJQUFJLEVBQUU7QUFBQSxNQUNuRDtBQUFBLElBQ0Y7QUFBQSxFQUNGLENBQUM7QUFLRCxNQUFJLGlCQUFpQjtBQUVyQixRQUFNLEtBQUssUUFBUSxDQUFDLE1BQXFCLFdBQWtDO0FBQ3pFLFFBQUksZ0JBQWdCO0FBQ2xCLFVBQUksMkRBQTJELE9BQU8sTUFBTSxHQUFHLENBQUMsU0FBUyxPQUFPLElBQUksQ0FBQyxXQUFXLE9BQU8sTUFBTSxDQUFDLEVBQUU7QUFDaEk7QUFBQSxJQUNGO0FBSUEsUUFBSSxzREFBc0QsT0FBTyxNQUFNLEdBQUcsQ0FBQyxTQUFTLE9BQU8sSUFBSSxDQUFDLFdBQVcsT0FBTyxNQUFNLENBQUMsRUFBRTtBQUMzSCxpQ0FBNkI7QUFBQSxNQUMzQjtBQUFBLE1BQ0EsWUFBWSxRQUFRLFdBQVc7QUFBQSxNQUMvQixLQUFLLE1BQU07QUFBQSxNQUNYO0FBQUEsTUFDQTtBQUFBLElBQ0YsQ0FBQztBQUFBLEVBQ0gsQ0FBQztBQUVELFFBQU0sTUFBTTtBQUVaLE1BQUk7QUFDRixVQUFNLGdCQUFnQixNQUFNO0FBQzVCLFFBQUksd0RBQXdELE1BQU0sR0FBRztBQUNyRSxXQUFPO0FBQUEsTUFDTDtBQUFBLE1BQ0E7QUFBQSxNQUNBLG9CQUFvQixlQUFlO0FBQUEsTUFDbkM7QUFBQSxNQUNBLGNBQWMsTUFBTSxRQUFRLGFBQWE7QUFBQSxNQUN6QyxZQUFZLE1BQU0sUUFBUSxXQUFXO0FBQUEsSUFDdkM7QUFBQSxFQUNGLFNBQVMsT0FBZ0I7QUFXdkIsVUFBTSxXQUFXLFFBQVEsYUFBYTtBQUN0QyxTQUFLO0FBQ0wsUUFBSSxVQUFVO0FBQ1osWUFBTSxJQUFJLHlCQUF5QjtBQUFBLFFBQ2pDO0FBQUEsUUFDQSxNQUFNLFNBQVM7QUFBQSxRQUNmLFlBQVksUUFBUSxXQUFXO0FBQUEsUUFDL0IsS0FBSyxNQUFNO0FBQUEsUUFDWCxRQUFRLFNBQVM7QUFBQSxRQUNqQixZQUFZLFNBQVM7QUFBQSxNQUN2QixDQUFDO0FBQUEsSUFDSDtBQUNBLFVBQU07QUFBQSxFQUNSO0FBRUEsV0FBUyxPQUFhO0FBQ3BCLHFCQUFpQjtBQUNqQixpQ0FBNkIsSUFBSTtBQUNqQyxtQkFBZSxNQUFNO0FBQ3JCLG9CQUFnQixLQUFLO0FBQUEsRUFDdkI7QUFDRjtBQVVPLFNBQVMsZUFBZ0M7QUFDOUMsU0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLFdBQVc7QUFDdEMsVUFBTSxTQUFTLGFBQWE7QUFDNUIsV0FBTyxLQUFLLFNBQVMsTUFBTTtBQUMzQixXQUFPLE9BQU8sR0FBRyxrQkFBa0IsTUFBTTtBQUN2QyxZQUFNLFVBQVUsT0FBTyxRQUFRO0FBQy9CLFVBQUksWUFBWSxRQUFRLE9BQU8sWUFBWSxVQUFVO0FBQ25ELGVBQU8sTUFBTTtBQUNiLGVBQU8sSUFBSSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3BEO0FBQUEsTUFDRjtBQUNBLFlBQU0sRUFBRSxLQUFLLElBQUk7QUFDakIsYUFBTyxNQUFNLE1BQU07QUFDakIsZ0JBQVEsSUFBSTtBQUFBLE1BQ2QsQ0FBQztBQUFBLElBQ0gsQ0FBQztBQUFBLEVBQ0gsQ0FBQztBQUNIO0FBUUEsU0FBUyxNQUFNLElBQTJCO0FBQ3hDLFNBQU8sSUFBSSxRQUFRLENBQUMsWUFBWTtBQUM5QixlQUFXLFNBQVMsRUFBRTtBQUFBLEVBQ3hCLENBQUM7QUFDSDtBQU9BLGVBQWUsZ0JBQWdCLFFBQStCO0FBQzVELFFBQU0sV0FBVyxLQUFLLElBQUksSUFBSTtBQUM5QixTQUFPLEtBQUssSUFBSSxJQUFJLFVBQVU7QUFDNUIsUUFBSTtBQUNGLFlBQU0sV0FBVyxNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU87QUFDN0MsWUFBTSxVQUFVLE1BQU0sU0FBUyxLQUFLO0FBQ3BDLFVBQUksUUFBUSxLQUFLLENBQUMsV0FBVyxPQUFPLFNBQVMsTUFBTSxHQUFHO0FBQ3BEO0FBQUEsTUFDRjtBQUFBLElBQ0YsUUFBUTtBQUFBLElBRVI7QUFDQSxVQUFNLE1BQU0sdUNBQXVDO0FBQUEsRUFDckQ7QUFDQSxRQUFNLElBQUk7QUFBQSxJQUNSLGlEQUFpRCxNQUFNLFdBQVcsT0FBTyxpQ0FBaUMsQ0FBQztBQUFBLEVBQzdHO0FBQ0Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
@@ -33,8 +33,9 @@ export interface OpenObsidianSettingsTabOptions extends OpenSettingsTabParams {
33
33
  * actually rendered, resolving the transport and vault from the current test
34
34
  * context.
35
35
  *
36
- * See {@link Lib.openSettingsTab} for why simply calling `app.setting.open()`
37
- * renders nothing, and why the container must be attached **before** it.
36
+ * See {@link Lib.openSettingsTab} for why `app.setting.open()` can put the modal
37
+ * in a second Electron window, and why the container is attached **before** it on
38
+ * a vault that lacks the harness's `settingsPopoutWindow: false` default.
38
39
  *
39
40
  * Close it again from a callback with `app.setting.close()`; re-opening works,
40
41
  * because the attach is idempotent.
@@ -24,4 +24,4 @@ async function openObsidianSettingsTab(options) {
24
24
  export {
25
25
  openObsidianSettingsTab
26
26
  };
27
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29wZW4tb2JzaWRpYW4tc2V0dGluZ3MtdGFiLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogT3BlbnMgT2JzaWRpYW4ncyBzZXR0aW5ncyBtb2RhbCBvbiBhIGdpdmVuIHRhYiBpbiB0aGUgaW5zdGFuY2UgdGhlIGN1cnJlbnRcbiAqIHRlc3QgY29udGV4dCBpcyBhbHJlYWR5IGRyaXZpbmcuXG4gKlxuICogVGhlIHJlbmRlcmVyLXNpZGUgd29yayBsaXZlcyBpbiB0aGUgaW5qZWN0ZWQgYGxpYmAgYmFnXG4gKiAoYGxpYi5vcGVuU2V0dGluZ3NUYWJgKSwgd2hlcmUgYSBjYWxsYmFjayB0aGF0IGFsc28gcHJvYmVzIHRoZSByZW5kZXJlZCBET01cbiAqIGNhbiByZWFjaCBpdC4gVGhpcyBpcyB0aGUgY29udGV4dC1yZXNvbHZpbmcgZW50cnkgcG9pbnQgZm9yIHRoZSBmYXIgbW9yZVxuICogY29tbW9uIGNhc2UgXHUyMDE0IGEgc2NyZWVuc2hvdCBzdWl0ZSB0aGF0IG9ubHkgd2FudHMgdGhlIHRhYiBvbiBzY3JlZW4gYmVmb3JlIGl0XG4gKiBjYWxscyBgY2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdGAsIGFuZCB3b3VsZCBvdGhlcndpc2Ugd3JpdGUgdGhlIHNhbWVcbiAqIGBldmFsSW5PYnNpZGlhbmAgd3JhcHBlciBpbiBldmVyeSBwbHVnaW4uXG4gKi9cblxuLyogdjggaWdub3JlIHN0YXJ0IC0tIEludGVncmF0aW9uLXRpbWUgY29kZSAoZHJpdmVzIGEgbGl2ZSBPYnNpZGlhbikgY292ZXJlZCBieSBpbnRlZ3JhdGlvbiB0ZXN0cywgbm90IHVuaXQgdGVzdHMuICovXG5cbmltcG9ydCB0eXBlIHtcbiAgRXZhbEluT2JzaWRpYW5QYXJhbXMsXG4gIE9wZW5TZXR0aW5nc1RhYlBhcmFtc1xufSBmcm9tICcuL2V2YWwtaW4tb2JzaWRpYW4ubWpzJztcbmltcG9ydCB0eXBlIHsgT2JzaWRpYW5UcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydC5tanMnO1xuXG5pbXBvcnQgeyBldmFsSW5PYnNpZGlhbiB9IGZyb20gJy4vZXZhbC1pbi1vYnNpZGlhbi5tanMnO1xuaW1wb3J0IHsgbm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzIH0gZnJvbSAnLi9ub3JtYWxpemUtb3B0aW9uYWwtcHJvcGVydGllcy5tanMnO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGluayBvcGVuT2JzaWRpYW5TZXR0aW5nc1RhYn0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3Blbk9ic2lkaWFuU2V0dGluZ3NUYWJPcHRpb25zIGV4dGVuZHMgT3BlblNldHRpbmdzVGFiUGFyYW1zIHtcbiAgLyoqXG4gICAqIE92ZXJyaWRlIHRoZSB0cmFuc3BvcnQuIFdoZW4gb21pdHRlZCwgdGhlIHRyYW5zcG9ydCB0aGUgY3VycmVudCB0ZXN0XG4gICAqIGNvbnRleHQgaXMgZHJpdmluZyBpcyB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgdHJhbnNwb3J0PzogT2JzaWRpYW5UcmFuc3BvcnQ7XG5cbiAgLyoqXG4gICAqIFRoZSB2YXVsdCB3aG9zZSBPYnNpZGlhbiB3aW5kb3cgdG8gb3BlbiB0aGUgc2V0dGluZ3MgaW4uIFdoZW4gb21pdHRlZCwgdGhlXG4gICAqIGN1cnJlbnQgdGVzdCBjb250ZXh0J3MgdmF1bHQgaXMgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IHZhdWx0UGF0aD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgc2VyaWFsaXplZCBwYXlsb2FkIGhhbmRlZCB0byB0aGUgY2FsbGJhY2sgXHUyMDE0IHRoZSB3aG9sZVxuICoge0BsaW5rIE9wZW5TZXR0aW5nc1RhYlBhcmFtc30gYmFnIGluIG9uZSBKU09OLXNhZmUgZmllbGQuXG4gKi9cbnR5cGUgT3BlblNldHRpbmdzVGFiSW5wdXQgPSBSZWNvcmQ8J29wZW5QYXJhbXMnLCBPcGVuU2V0dGluZ3NUYWJQYXJhbXM+O1xuXG4vKipcbiAqIE9wZW5zIE9ic2lkaWFuJ3Mgc2V0dGluZ3MgbW9kYWwgb24gYSBnaXZlbiB0YWIgYW5kIHdhaXRzIHVudGlsIHRoYXQgdGFiIGhhc1xuICogYWN0dWFsbHkgcmVuZGVyZWQsIHJlc29sdmluZyB0aGUgdHJhbnNwb3J0IGFuZCB2YXVsdCBmcm9tIHRoZSBjdXJyZW50IHRlc3RcbiAqIGNvbnRleHQuXG4gKlxuICogU2VlIHtAbGluayBMaWIub3BlblNldHRpbmdzVGFifSBmb3Igd2h5IHNpbXBseSBjYWxsaW5nIGBhcHAuc2V0dGluZy5vcGVuKClgXG4gKiByZW5kZXJzIG5vdGhpbmcsIGFuZCB3aHkgdGhlIGNvbnRhaW5lciBtdXN0IGJlIGF0dGFjaGVkICoqYmVmb3JlKiogaXQuXG4gKlxuICogQ2xvc2UgaXQgYWdhaW4gZnJvbSBhIGNhbGxiYWNrIHdpdGggYGFwcC5zZXR0aW5nLmNsb3NlKClgOyByZS1vcGVuaW5nIHdvcmtzLFxuICogYmVjYXVzZSB0aGUgYXR0YWNoIGlzIGlkZW1wb3RlbnQuXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBUaGUgdGFiIHRvIG9wZW4sIGhvdyBsb25nIHRvIHdhaXQsIGFuZCB0cmFuc3BvcnQgLyB2YXVsdFxuICogICBvdmVycmlkZXMuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSByZXNvbHZpbmcgdG8gdGhlIG5hbWVzIG9mIHRoZSBzZXR0aW5nIHJvd3MgdGhlIHRhYlxuICogICByZW5kZXJlZC5cbiAqIEB0aHJvd3MgRXJyb3IgaWYgbm8gdGFiIGNhcnJpZXMge0BsaW5rIE9wZW5TZXR0aW5nc1RhYlBhcmFtcy50YWJJZH0sIG9yIGlmIHRoZVxuICogICB0YWIgZG9lcyBub3QgcmVuZGVyIHdpdGhpbiB0aGUgdGltZW91dC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG9wZW5PYnNpZGlhblNldHRpbmdzVGFiKG9wdGlvbnM6IE9wZW5PYnNpZGlhblNldHRpbmdzVGFiT3B0aW9ucyk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgY29uc3Qge1xuICAgIHRhYklkLFxuICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kcyxcbiAgICB0cmFuc3BvcnQsXG4gICAgdmF1bHRQYXRoXG4gIH0gPSBvcHRpb25zO1xuXG4gIHJldHVybiBhd2FpdCBldmFsSW5PYnNpZGlhbihub3JtYWxpemVPcHRpb25hbFByb3BlcnRpZXM8RXZhbEluT2JzaWRpYW5QYXJhbXM8T3BlblNldHRpbmdzVGFiSW5wdXQsIHN0cmluZ1tdPj4oe1xuICAgIGFzeW5jIGNhbGxiYWNrKHsgbGliLCBvcGVuUGFyYW1zIH0pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgICByZXR1cm4gYXdhaXQgbGliLm9wZW5TZXR0aW5nc1RhYihvcGVuUGFyYW1zKTtcbiAgICB9LFxuICAgIGlucHV0OiB7XG4gICAgICBvcGVuUGFyYW1zOiBub3JtYWxpemVPcHRpb25hbFByb3BlcnRpZXM8T3BlblNldHRpbmdzVGFiUGFyYW1zPih7XG4gICAgICAgIHRhYklkLFxuICAgICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHNcbiAgICAgIH0pXG4gICAgfSxcbiAgICB0cmFuc3BvcnQsXG4gICAgdmF1bHRQYXRoXG4gIH0pKTtcbn1cblxuLyogdjggaWdub3JlIHN0b3AgKi9cbiJdLAogICJtYXBwaW5ncyI6ICJBQXNCQSxTQUFTLHNCQUFzQjtBQUMvQixTQUFTLG1DQUFtQztBQTJDNUMsZUFBc0Isd0JBQXdCLFNBQTREO0FBQ3hHLFFBQU07QUFBQSxJQUNKO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsRUFDRixJQUFJO0FBRUosU0FBTyxNQUFNLGVBQWUsNEJBQWtGO0FBQUEsSUFDNUcsTUFBTSxTQUFTLEVBQUUsS0FBSyxXQUFXLEdBQXNCO0FBQ3JELGFBQU8sTUFBTSxJQUFJLGdCQUFnQixVQUFVO0FBQUEsSUFDN0M7QUFBQSxJQUNBLE9BQU87QUFBQSxNQUNMLFlBQVksNEJBQW1EO0FBQUEsUUFDN0Q7QUFBQSxRQUNBO0FBQUEsTUFDRixDQUFDO0FBQUEsSUFDSDtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsRUFDRixDQUFDLENBQUM7QUFDSjsiLAogICJuYW1lcyI6IFtdCn0K
27
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29wZW4tb2JzaWRpYW4tc2V0dGluZ3MtdGFiLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogT3BlbnMgT2JzaWRpYW4ncyBzZXR0aW5ncyBtb2RhbCBvbiBhIGdpdmVuIHRhYiBpbiB0aGUgaW5zdGFuY2UgdGhlIGN1cnJlbnRcbiAqIHRlc3QgY29udGV4dCBpcyBhbHJlYWR5IGRyaXZpbmcuXG4gKlxuICogVGhlIHJlbmRlcmVyLXNpZGUgd29yayBsaXZlcyBpbiB0aGUgaW5qZWN0ZWQgYGxpYmAgYmFnXG4gKiAoYGxpYi5vcGVuU2V0dGluZ3NUYWJgKSwgd2hlcmUgYSBjYWxsYmFjayB0aGF0IGFsc28gcHJvYmVzIHRoZSByZW5kZXJlZCBET01cbiAqIGNhbiByZWFjaCBpdC4gVGhpcyBpcyB0aGUgY29udGV4dC1yZXNvbHZpbmcgZW50cnkgcG9pbnQgZm9yIHRoZSBmYXIgbW9yZVxuICogY29tbW9uIGNhc2UgXHUyMDE0IGEgc2NyZWVuc2hvdCBzdWl0ZSB0aGF0IG9ubHkgd2FudHMgdGhlIHRhYiBvbiBzY3JlZW4gYmVmb3JlIGl0XG4gKiBjYWxscyBgY2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdGAsIGFuZCB3b3VsZCBvdGhlcndpc2Ugd3JpdGUgdGhlIHNhbWVcbiAqIGBldmFsSW5PYnNpZGlhbmAgd3JhcHBlciBpbiBldmVyeSBwbHVnaW4uXG4gKi9cblxuLyogdjggaWdub3JlIHN0YXJ0IC0tIEludGVncmF0aW9uLXRpbWUgY29kZSAoZHJpdmVzIGEgbGl2ZSBPYnNpZGlhbikgY292ZXJlZCBieSBpbnRlZ3JhdGlvbiB0ZXN0cywgbm90IHVuaXQgdGVzdHMuICovXG5cbmltcG9ydCB0eXBlIHtcbiAgRXZhbEluT2JzaWRpYW5QYXJhbXMsXG4gIE9wZW5TZXR0aW5nc1RhYlBhcmFtc1xufSBmcm9tICcuL2V2YWwtaW4tb2JzaWRpYW4ubWpzJztcbmltcG9ydCB0eXBlIHsgT2JzaWRpYW5UcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydC5tanMnO1xuXG5pbXBvcnQgeyBldmFsSW5PYnNpZGlhbiB9IGZyb20gJy4vZXZhbC1pbi1vYnNpZGlhbi5tanMnO1xuaW1wb3J0IHsgbm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzIH0gZnJvbSAnLi9ub3JtYWxpemUtb3B0aW9uYWwtcHJvcGVydGllcy5tanMnO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGluayBvcGVuT2JzaWRpYW5TZXR0aW5nc1RhYn0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3Blbk9ic2lkaWFuU2V0dGluZ3NUYWJPcHRpb25zIGV4dGVuZHMgT3BlblNldHRpbmdzVGFiUGFyYW1zIHtcbiAgLyoqXG4gICAqIE92ZXJyaWRlIHRoZSB0cmFuc3BvcnQuIFdoZW4gb21pdHRlZCwgdGhlIHRyYW5zcG9ydCB0aGUgY3VycmVudCB0ZXN0XG4gICAqIGNvbnRleHQgaXMgZHJpdmluZyBpcyB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgdHJhbnNwb3J0PzogT2JzaWRpYW5UcmFuc3BvcnQ7XG5cbiAgLyoqXG4gICAqIFRoZSB2YXVsdCB3aG9zZSBPYnNpZGlhbiB3aW5kb3cgdG8gb3BlbiB0aGUgc2V0dGluZ3MgaW4uIFdoZW4gb21pdHRlZCwgdGhlXG4gICAqIGN1cnJlbnQgdGVzdCBjb250ZXh0J3MgdmF1bHQgaXMgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IHZhdWx0UGF0aD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgc2VyaWFsaXplZCBwYXlsb2FkIGhhbmRlZCB0byB0aGUgY2FsbGJhY2sgXHUyMDE0IHRoZSB3aG9sZVxuICoge0BsaW5rIE9wZW5TZXR0aW5nc1RhYlBhcmFtc30gYmFnIGluIG9uZSBKU09OLXNhZmUgZmllbGQuXG4gKi9cbnR5cGUgT3BlblNldHRpbmdzVGFiSW5wdXQgPSBSZWNvcmQ8J29wZW5QYXJhbXMnLCBPcGVuU2V0dGluZ3NUYWJQYXJhbXM+O1xuXG4vKipcbiAqIE9wZW5zIE9ic2lkaWFuJ3Mgc2V0dGluZ3MgbW9kYWwgb24gYSBnaXZlbiB0YWIgYW5kIHdhaXRzIHVudGlsIHRoYXQgdGFiIGhhc1xuICogYWN0dWFsbHkgcmVuZGVyZWQsIHJlc29sdmluZyB0aGUgdHJhbnNwb3J0IGFuZCB2YXVsdCBmcm9tIHRoZSBjdXJyZW50IHRlc3RcbiAqIGNvbnRleHQuXG4gKlxuICogU2VlIHtAbGluayBMaWIub3BlblNldHRpbmdzVGFifSBmb3Igd2h5IGBhcHAuc2V0dGluZy5vcGVuKClgIGNhbiBwdXQgdGhlIG1vZGFsXG4gKiBpbiBhIHNlY29uZCBFbGVjdHJvbiB3aW5kb3csIGFuZCB3aHkgdGhlIGNvbnRhaW5lciBpcyBhdHRhY2hlZCAqKmJlZm9yZSoqIGl0IG9uXG4gKiBhIHZhdWx0IHRoYXQgbGFja3MgdGhlIGhhcm5lc3MncyBgc2V0dGluZ3NQb3BvdXRXaW5kb3c6IGZhbHNlYCBkZWZhdWx0LlxuICpcbiAqIENsb3NlIGl0IGFnYWluIGZyb20gYSBjYWxsYmFjayB3aXRoIGBhcHAuc2V0dGluZy5jbG9zZSgpYDsgcmUtb3BlbmluZyB3b3JrcyxcbiAqIGJlY2F1c2UgdGhlIGF0dGFjaCBpcyBpZGVtcG90ZW50LlxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIHRhYiB0byBvcGVuLCBob3cgbG9uZyB0byB3YWl0LCBhbmQgdHJhbnNwb3J0IC8gdmF1bHRcbiAqICAgb3ZlcnJpZGVzLlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gcmVzb2x2aW5nIHRvIHRoZSBuYW1lcyBvZiB0aGUgc2V0dGluZyByb3dzIHRoZSB0YWJcbiAqICAgcmVuZGVyZWQuXG4gKiBAdGhyb3dzIEVycm9yIGlmIG5vIHRhYiBjYXJyaWVzIHtAbGluayBPcGVuU2V0dGluZ3NUYWJQYXJhbXMudGFiSWR9LCBvciBpZiB0aGVcbiAqICAgdGFiIGRvZXMgbm90IHJlbmRlciB3aXRoaW4gdGhlIHRpbWVvdXQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvcGVuT2JzaWRpYW5TZXR0aW5nc1RhYihvcHRpb25zOiBPcGVuT2JzaWRpYW5TZXR0aW5nc1RhYk9wdGlvbnMpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGNvbnN0IHtcbiAgICB0YWJJZCxcbiAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHMsXG4gICAgdHJhbnNwb3J0LFxuICAgIHZhdWx0UGF0aFxuICB9ID0gb3B0aW9ucztcblxuICByZXR1cm4gYXdhaXQgZXZhbEluT2JzaWRpYW4obm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzPEV2YWxJbk9ic2lkaWFuUGFyYW1zPE9wZW5TZXR0aW5nc1RhYklucHV0LCBzdHJpbmdbXT4+KHtcbiAgICBhc3luYyBjYWxsYmFjayh7IGxpYiwgb3BlblBhcmFtcyB9KTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgICAgcmV0dXJuIGF3YWl0IGxpYi5vcGVuU2V0dGluZ3NUYWIob3BlblBhcmFtcyk7XG4gICAgfSxcbiAgICBpbnB1dDoge1xuICAgICAgb3BlblBhcmFtczogbm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzPE9wZW5TZXR0aW5nc1RhYlBhcmFtcz4oe1xuICAgICAgICB0YWJJZCxcbiAgICAgICAgdGltZW91dEluTWlsbGlzZWNvbmRzXG4gICAgICB9KVxuICAgIH0sXG4gICAgdHJhbnNwb3J0LFxuICAgIHZhdWx0UGF0aFxuICB9KSk7XG59XG5cbi8qIHY4IGlnbm9yZSBzdG9wICovXG4iXSwKICAibWFwcGluZ3MiOiAiQUFzQkEsU0FBUyxzQkFBc0I7QUFDL0IsU0FBUyxtQ0FBbUM7QUE0QzVDLGVBQXNCLHdCQUF3QixTQUE0RDtBQUN4RyxRQUFNO0FBQUEsSUFDSjtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0YsSUFBSTtBQUVKLFNBQU8sTUFBTSxlQUFlLDRCQUFrRjtBQUFBLElBQzVHLE1BQU0sU0FBUyxFQUFFLEtBQUssV0FBVyxHQUFzQjtBQUNyRCxhQUFPLE1BQU0sSUFBSSxnQkFBZ0IsVUFBVTtBQUFBLElBQzdDO0FBQUEsSUFDQSxPQUFPO0FBQUEsTUFDTCxZQUFZLDRCQUFtRDtBQUFBLFFBQzdEO0FBQUEsUUFDQTtBQUFBLE1BQ0YsQ0FBQztBQUFBLElBQ0g7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0YsQ0FBQyxDQUFDO0FBQ0o7IiwKICAibmFtZXMiOiBbXQp9Cg==
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * Records that the harness-owned Obsidian instance on a CDP port died, so a
5
+ * process that did not spawn it can still say **why** it is unreachable.
6
+ *
7
+ * Only the process that launched the instance holds the child handle and sees
8
+ * `exit`; the test workers get nothing but the port (see the repo's L9). So the
9
+ * one fact worth having — the exit code — has to cross a process boundary, and
10
+ * this is the channel: a small JSON sentinel next to the setup lock
11
+ * (`setup-lock.ts`) and the Appium server marker (`appium-server-marker.ts`),
12
+ * keyed by port.
13
+ *
14
+ * Written **only for a death the harness did not order.** A deliberate kill
15
+ * (teardown, or the relaunch loop killing an instance before starting the next)
16
+ * clears the marker instead, because a marker left behind by a clean run would
17
+ * convict the next run's healthy instance of an exit that never happened.
18
+ *
19
+ * Reads are deliberately tolerant, exactly as the Appium marker's are: missing,
20
+ * unreadable, or describing another port all read as "no marker", and the
21
+ * caller falls back to saying only that the instance is gone.
22
+ */
23
+ /**
24
+ * Records the death of the owned instance that was serving CDP on a port.
25
+ */
26
+ export interface OwnedInstanceExitMarker {
27
+ /**
28
+ Exit code, or `null` when terminated by a signal or when it failed to spawn.
29
+ */
30
+ readonly code: null | number;
31
+ /**
32
+ When the instance exited (`Date.now()` epoch milliseconds).
33
+ */
34
+ readonly exitedAtInMilliseconds: number;
35
+ /**
36
+ The tail of everything the instance wrote to stdout/stderr (empty when it wrote nothing).
37
+ */
38
+ readonly outputTail: string;
39
+ /**
40
+ PID of the instance's process, or `undefined` when it never got one.
41
+ */
42
+ readonly pid: number | undefined;
43
+ /**
44
+ The CDP port the dead instance was serving.
45
+ */
46
+ readonly port: number;
47
+ /**
48
+ Terminating signal, or `null` when it exited normally or failed to spawn.
49
+ */
50
+ readonly signal: NodeJS.Signals | null;
51
+ /**
52
+ The spawn-failure message when the instance never started (e.g. `ENOENT`), otherwise absent.
53
+ */
54
+ readonly spawnError?: string | undefined;
55
+ }
56
+ /**
57
+ * Parameters for {@link writeOwnedInstanceExitMarker}.
58
+ */
59
+ export interface WriteOwnedInstanceExitMarkerParams {
60
+ /**
61
+ Exit code, or `null` when terminated by a signal or when it failed to spawn.
62
+ */
63
+ readonly code: null | number;
64
+ /**
65
+ The tail of everything the instance wrote to stdout/stderr.
66
+ */
67
+ readonly outputTail: string;
68
+ /**
69
+ PID of the instance's process, or `undefined` when it never got one.
70
+ */
71
+ readonly pid: number | undefined;
72
+ /**
73
+ The CDP port the dead instance was serving.
74
+ */
75
+ readonly port: number;
76
+ /**
77
+ Terminating signal, or `null` when it exited normally or failed to spawn.
78
+ */
79
+ readonly signal: NodeJS.Signals | null;
80
+ /**
81
+ The spawn-failure message when the instance never started, otherwise absent.
82
+ */
83
+ readonly spawnError?: string | undefined;
84
+ }
85
+ /**
86
+ * Removes the marker for a port. Called when an instance is launched on it (a
87
+ * recycled port must not inherit an older instance's death) and whenever the
88
+ * harness kills an instance on purpose.
89
+ *
90
+ * @param port - The CDP port.
91
+ */
92
+ export declare function clearOwnedInstanceExitMarker(port: number): void;
93
+ /**
94
+ * Reads the marker for a port.
95
+ *
96
+ * @param port - The CDP port.
97
+ * @returns The marker, or `undefined` when there is none, it is unreadable, or it does not describe this port.
98
+ */
99
+ export declare function readOwnedInstanceExitMarker(port: number): OwnedInstanceExitMarker | undefined;
100
+ /**
101
+ * Records that the instance serving a port has died, stamping it with the
102
+ * current time so a reader can report how long ago it happened.
103
+ *
104
+ * @param params - The dead instance's port, exit details, and output tail.
105
+ */
106
+ export declare function writeOwnedInstanceExitMarker(params: WriteOwnedInstanceExitMarkerParams): void;
@@ -0,0 +1,78 @@
1
+ import {
2
+ mkdirSync,
3
+ readFileSync,
4
+ rmSync,
5
+ writeFileSync
6
+ } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { log } from "./log.mjs";
10
+ const MARKER_DIR_NAME = "obsidian-integration-testing";
11
+ const MARKER_FILE_SUFFIX = ".owned-instance-exit.json";
12
+ function clearOwnedInstanceExitMarker(port) {
13
+ try {
14
+ rmSync(getMarkerFilePath(port), { force: true });
15
+ } catch (error) {
16
+ log(`[owned-instance-exit-marker] Could not remove the marker for port ${String(port)}: ${getErrorMessage(error)}`);
17
+ }
18
+ }
19
+ function readOwnedInstanceExitMarker(port) {
20
+ let parsed;
21
+ try {
22
+ parsed = JSON.parse(readFileSync(getMarkerFilePath(port), "utf-8"));
23
+ } catch {
24
+ return void 0;
25
+ }
26
+ return parseMarker(parsed, port);
27
+ }
28
+ function writeOwnedInstanceExitMarker(params) {
29
+ const marker = {
30
+ code: params.code,
31
+ exitedAtInMilliseconds: Date.now(),
32
+ outputTail: params.outputTail,
33
+ pid: params.pid,
34
+ port: params.port,
35
+ signal: params.signal,
36
+ ...params.spawnError !== void 0 && { spawnError: params.spawnError }
37
+ };
38
+ try {
39
+ mkdirSync(getMarkerDirectory(), { recursive: true });
40
+ writeFileSync(getMarkerFilePath(marker.port), JSON.stringify(marker));
41
+ } catch (error) {
42
+ log(`[owned-instance-exit-marker] Could not record the exit on port ${String(marker.port)}: ${getErrorMessage(error)}`);
43
+ }
44
+ }
45
+ function getErrorMessage(error) {
46
+ return error instanceof Error ? error.message : String(error);
47
+ }
48
+ function getMarkerDirectory() {
49
+ return join(tmpdir(), MARKER_DIR_NAME);
50
+ }
51
+ function getMarkerFilePath(port) {
52
+ return join(getMarkerDirectory(), `${String(port)}${MARKER_FILE_SUFFIX}`);
53
+ }
54
+ function parseMarker(parsed, port) {
55
+ if (typeof parsed !== "object" || parsed === null) {
56
+ return void 0;
57
+ }
58
+ const record = parsed;
59
+ const { code, exitedAtInMilliseconds, outputTail, pid, port: markedPort, signal, spawnError } = record;
60
+ if (typeof exitedAtInMilliseconds !== "number" || markedPort !== port) {
61
+ return void 0;
62
+ }
63
+ return {
64
+ code: typeof code === "number" ? code : null,
65
+ exitedAtInMilliseconds,
66
+ outputTail: typeof outputTail === "string" ? outputTail : "",
67
+ pid: typeof pid === "number" ? pid : void 0,
68
+ port,
69
+ signal: typeof signal === "string" ? signal : null,
70
+ ...typeof spawnError === "string" && { spawnError }
71
+ };
72
+ }
73
+ export {
74
+ clearOwnedInstanceExitMarker,
75
+ readOwnedInstanceExitMarker,
76
+ writeOwnedInstanceExitMarker
77
+ };
78
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL293bmVkLWluc3RhbmNlLWV4aXQtbWFya2VyLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogUmVjb3JkcyB0aGF0IHRoZSBoYXJuZXNzLW93bmVkIE9ic2lkaWFuIGluc3RhbmNlIG9uIGEgQ0RQIHBvcnQgZGllZCwgc28gYVxuICogcHJvY2VzcyB0aGF0IGRpZCBub3Qgc3Bhd24gaXQgY2FuIHN0aWxsIHNheSAqKndoeSoqIGl0IGlzIHVucmVhY2hhYmxlLlxuICpcbiAqIE9ubHkgdGhlIHByb2Nlc3MgdGhhdCBsYXVuY2hlZCB0aGUgaW5zdGFuY2UgaG9sZHMgdGhlIGNoaWxkIGhhbmRsZSBhbmQgc2Vlc1xuICogYGV4aXRgOyB0aGUgdGVzdCB3b3JrZXJzIGdldCBub3RoaW5nIGJ1dCB0aGUgcG9ydCAoc2VlIHRoZSByZXBvJ3MgTDkpLiBTbyB0aGVcbiAqIG9uZSBmYWN0IHdvcnRoIGhhdmluZyBcdTIwMTQgdGhlIGV4aXQgY29kZSBcdTIwMTQgaGFzIHRvIGNyb3NzIGEgcHJvY2VzcyBib3VuZGFyeSwgYW5kXG4gKiB0aGlzIGlzIHRoZSBjaGFubmVsOiBhIHNtYWxsIEpTT04gc2VudGluZWwgbmV4dCB0byB0aGUgc2V0dXAgbG9ja1xuICogKGBzZXR1cC1sb2NrLnRzYCkgYW5kIHRoZSBBcHBpdW0gc2VydmVyIG1hcmtlciAoYGFwcGl1bS1zZXJ2ZXItbWFya2VyLnRzYCksXG4gKiBrZXllZCBieSBwb3J0LlxuICpcbiAqIFdyaXR0ZW4gKipvbmx5IGZvciBhIGRlYXRoIHRoZSBoYXJuZXNzIGRpZCBub3Qgb3JkZXIuKiogQSBkZWxpYmVyYXRlIGtpbGxcbiAqICh0ZWFyZG93biwgb3IgdGhlIHJlbGF1bmNoIGxvb3Aga2lsbGluZyBhbiBpbnN0YW5jZSBiZWZvcmUgc3RhcnRpbmcgdGhlIG5leHQpXG4gKiBjbGVhcnMgdGhlIG1hcmtlciBpbnN0ZWFkLCBiZWNhdXNlIGEgbWFya2VyIGxlZnQgYmVoaW5kIGJ5IGEgY2xlYW4gcnVuIHdvdWxkXG4gKiBjb252aWN0IHRoZSBuZXh0IHJ1bidzIGhlYWx0aHkgaW5zdGFuY2Ugb2YgYW4gZXhpdCB0aGF0IG5ldmVyIGhhcHBlbmVkLlxuICpcbiAqIFJlYWRzIGFyZSBkZWxpYmVyYXRlbHkgdG9sZXJhbnQsIGV4YWN0bHkgYXMgdGhlIEFwcGl1bSBtYXJrZXIncyBhcmU6IG1pc3NpbmcsXG4gKiB1bnJlYWRhYmxlLCBvciBkZXNjcmliaW5nIGFub3RoZXIgcG9ydCBhbGwgcmVhZCBhcyBcIm5vIG1hcmtlclwiLCBhbmQgdGhlXG4gKiBjYWxsZXIgZmFsbHMgYmFjayB0byBzYXlpbmcgb25seSB0aGF0IHRoZSBpbnN0YW5jZSBpcyBnb25lLlxuICovXG5cbmltcG9ydCB7XG4gIG1rZGlyU3luYyxcbiAgcmVhZEZpbGVTeW5jLFxuICBybVN5bmMsXG4gIHdyaXRlRmlsZVN5bmNcbn0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tICdub2RlOm9zJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdub2RlOnBhdGgnO1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZy5tanMnO1xuXG5jb25zdCBNQVJLRVJfRElSX05BTUUgPSAnb2JzaWRpYW4taW50ZWdyYXRpb24tdGVzdGluZyc7XG5jb25zdCBNQVJLRVJfRklMRV9TVUZGSVggPSAnLm93bmVkLWluc3RhbmNlLWV4aXQuanNvbic7XG5cbi8qKlxuICogUmVjb3JkcyB0aGUgZGVhdGggb2YgdGhlIG93bmVkIGluc3RhbmNlIHRoYXQgd2FzIHNlcnZpbmcgQ0RQIG9uIGEgcG9ydC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBPd25lZEluc3RhbmNlRXhpdE1hcmtlciB7XG4gIC8qKlxuICBFeGl0IGNvZGUsIG9yIGBudWxsYCB3aGVuIHRlcm1pbmF0ZWQgYnkgYSBzaWduYWwgb3Igd2hlbiBpdCBmYWlsZWQgdG8gc3Bhd24uXG4gICAqL1xuICByZWFkb25seSBjb2RlOiBudWxsIHwgbnVtYmVyO1xuXG4gIC8qKlxuICBXaGVuIHRoZSBpbnN0YW5jZSBleGl0ZWQgKGBEYXRlLm5vdygpYCBlcG9jaCBtaWxsaXNlY29uZHMpLlxuICAgKi9cbiAgcmVhZG9ubHkgZXhpdGVkQXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xuXG4gIC8qKlxuICBUaGUgdGFpbCBvZiBldmVyeXRoaW5nIHRoZSBpbnN0YW5jZSB3cm90ZSB0byBzdGRvdXQvc3RkZXJyIChlbXB0eSB3aGVuIGl0IHdyb3RlIG5vdGhpbmcpLlxuICAgKi9cbiAgcmVhZG9ubHkgb3V0cHV0VGFpbDogc3RyaW5nO1xuXG4gIC8qKlxuICBQSUQgb2YgdGhlIGluc3RhbmNlJ3MgcHJvY2Vzcywgb3IgYHVuZGVmaW5lZGAgd2hlbiBpdCBuZXZlciBnb3Qgb25lLlxuICAgKi9cbiAgcmVhZG9ubHkgcGlkOiBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBDRFAgcG9ydCB0aGUgZGVhZCBpbnN0YW5jZSB3YXMgc2VydmluZy5cbiAgICovXG4gIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcblxuICAvKipcbiAgVGVybWluYXRpbmcgc2lnbmFsLCBvciBgbnVsbGAgd2hlbiBpdCBleGl0ZWQgbm9ybWFsbHkgb3IgZmFpbGVkIHRvIHNwYXduLlxuICAgKi9cbiAgcmVhZG9ubHkgc2lnbmFsOiBOb2RlSlMuU2lnbmFscyB8IG51bGw7XG5cbiAgLyoqXG4gIFRoZSBzcGF3bi1mYWlsdXJlIG1lc3NhZ2Ugd2hlbiB0aGUgaW5zdGFuY2UgbmV2ZXIgc3RhcnRlZCAoZS5nLiBgRU5PRU5UYCksIG90aGVyd2lzZSBhYnNlbnQuXG4gICAqL1xuICByZWFkb25seSBzcGF3bkVycm9yPzogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayB3cml0ZU93bmVkSW5zdGFuY2VFeGl0TWFya2VyfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBXcml0ZU93bmVkSW5zdGFuY2VFeGl0TWFya2VyUGFyYW1zIHtcbiAgLyoqXG4gIEV4aXQgY29kZSwgb3IgYG51bGxgIHdoZW4gdGVybWluYXRlZCBieSBhIHNpZ25hbCBvciB3aGVuIGl0IGZhaWxlZCB0byBzcGF3bi5cbiAgICovXG4gIHJlYWRvbmx5IGNvZGU6IG51bGwgfCBudW1iZXI7XG5cbiAgLyoqXG4gIFRoZSB0YWlsIG9mIGV2ZXJ5dGhpbmcgdGhlIGluc3RhbmNlIHdyb3RlIHRvIHN0ZG91dC9zdGRlcnIuXG4gICAqL1xuICByZWFkb25seSBvdXRwdXRUYWlsOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFBJRCBvZiB0aGUgaW5zdGFuY2UncyBwcm9jZXNzLCBvciBgdW5kZWZpbmVkYCB3aGVuIGl0IG5ldmVyIGdvdCBvbmUuXG4gICAqL1xuICByZWFkb25seSBwaWQ6IG51bWJlciB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgVGhlIENEUCBwb3J0IHRoZSBkZWFkIGluc3RhbmNlIHdhcyBzZXJ2aW5nLlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xuXG4gIC8qKlxuICBUZXJtaW5hdGluZyBzaWduYWwsIG9yIGBudWxsYCB3aGVuIGl0IGV4aXRlZCBub3JtYWxseSBvciBmYWlsZWQgdG8gc3Bhd24uXG4gICAqL1xuICByZWFkb25seSBzaWduYWw6IE5vZGVKUy5TaWduYWxzIHwgbnVsbDtcblxuICAvKipcbiAgVGhlIHNwYXduLWZhaWx1cmUgbWVzc2FnZSB3aGVuIHRoZSBpbnN0YW5jZSBuZXZlciBzdGFydGVkLCBvdGhlcndpc2UgYWJzZW50LlxuICAgKi9cbiAgcmVhZG9ubHkgc3Bhd25FcnJvcj86IHN0cmluZyB8IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIHRoZSBtYXJrZXIgZm9yIGEgcG9ydC4gQ2FsbGVkIHdoZW4gYW4gaW5zdGFuY2UgaXMgbGF1bmNoZWQgb24gaXQgKGFcbiAqIHJlY3ljbGVkIHBvcnQgbXVzdCBub3QgaW5oZXJpdCBhbiBvbGRlciBpbnN0YW5jZSdzIGRlYXRoKSBhbmQgd2hlbmV2ZXIgdGhlXG4gKiBoYXJuZXNzIGtpbGxzIGFuIGluc3RhbmNlIG9uIHB1cnBvc2UuXG4gKlxuICogQHBhcmFtIHBvcnQgLSBUaGUgQ0RQIHBvcnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjbGVhck93bmVkSW5zdGFuY2VFeGl0TWFya2VyKHBvcnQ6IG51bWJlcik6IHZvaWQge1xuICB0cnkge1xuICAgIHJtU3luYyhnZXRNYXJrZXJGaWxlUGF0aChwb3J0KSwgeyBmb3JjZTogdHJ1ZSB9KTtcbiAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICBsb2coYFtvd25lZC1pbnN0YW5jZS1leGl0LW1hcmtlcl0gQ291bGQgbm90IHJlbW92ZSB0aGUgbWFya2VyIGZvciBwb3J0ICR7U3RyaW5nKHBvcnQpfTogJHtnZXRFcnJvck1lc3NhZ2UoZXJyb3IpfWApO1xuICB9XG59XG5cbi8qKlxuICogUmVhZHMgdGhlIG1hcmtlciBmb3IgYSBwb3J0LlxuICpcbiAqIEBwYXJhbSBwb3J0IC0gVGhlIENEUCBwb3J0LlxuICogQHJldHVybnMgVGhlIG1hcmtlciwgb3IgYHVuZGVmaW5lZGAgd2hlbiB0aGVyZSBpcyBub25lLCBpdCBpcyB1bnJlYWRhYmxlLCBvciBpdCBkb2VzIG5vdCBkZXNjcmliZSB0aGlzIHBvcnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkT3duZWRJbnN0YW5jZUV4aXRNYXJrZXIocG9ydDogbnVtYmVyKTogT3duZWRJbnN0YW5jZUV4aXRNYXJrZXIgfCB1bmRlZmluZWQge1xuICBsZXQgcGFyc2VkOiB1bmtub3duO1xuICB0cnkge1xuICAgIHBhcnNlZCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGdldE1hcmtlckZpbGVQYXRoKHBvcnQpLCAndXRmLTgnKSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICByZXR1cm4gcGFyc2VNYXJrZXIocGFyc2VkLCBwb3J0KTtcbn1cblxuLyoqXG4gKiBSZWNvcmRzIHRoYXQgdGhlIGluc3RhbmNlIHNlcnZpbmcgYSBwb3J0IGhhcyBkaWVkLCBzdGFtcGluZyBpdCB3aXRoIHRoZVxuICogY3VycmVudCB0aW1lIHNvIGEgcmVhZGVyIGNhbiByZXBvcnQgaG93IGxvbmcgYWdvIGl0IGhhcHBlbmVkLlxuICpcbiAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgZGVhZCBpbnN0YW5jZSdzIHBvcnQsIGV4aXQgZGV0YWlscywgYW5kIG91dHB1dCB0YWlsLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd3JpdGVPd25lZEluc3RhbmNlRXhpdE1hcmtlcihwYXJhbXM6IFdyaXRlT3duZWRJbnN0YW5jZUV4aXRNYXJrZXJQYXJhbXMpOiB2b2lkIHtcbiAgY29uc3QgbWFya2VyOiBPd25lZEluc3RhbmNlRXhpdE1hcmtlciA9IHtcbiAgICBjb2RlOiBwYXJhbXMuY29kZSxcbiAgICBleGl0ZWRBdEluTWlsbGlzZWNvbmRzOiBEYXRlLm5vdygpLFxuICAgIG91dHB1dFRhaWw6IHBhcmFtcy5vdXRwdXRUYWlsLFxuICAgIHBpZDogcGFyYW1zLnBpZCxcbiAgICBwb3J0OiBwYXJhbXMucG9ydCxcbiAgICBzaWduYWw6IHBhcmFtcy5zaWduYWwsXG4gICAgLi4uKHBhcmFtcy5zcGF3bkVycm9yICE9PSB1bmRlZmluZWQgJiYgeyBzcGF3bkVycm9yOiBwYXJhbXMuc3Bhd25FcnJvciB9KVxuICB9O1xuXG4gIHRyeSB7XG4gICAgbWtkaXJTeW5jKGdldE1hcmtlckRpcmVjdG9yeSgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB3cml0ZUZpbGVTeW5jKGdldE1hcmtlckZpbGVQYXRoKG1hcmtlci5wb3J0KSwgSlNPTi5zdHJpbmdpZnkobWFya2VyKSk7XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgbG9nKGBbb3duZWQtaW5zdGFuY2UtZXhpdC1tYXJrZXJdIENvdWxkIG5vdCByZWNvcmQgdGhlIGV4aXQgb24gcG9ydCAke1N0cmluZyhtYXJrZXIucG9ydCl9OiAke2dldEVycm9yTWVzc2FnZShlcnJvcil9YCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0RXJyb3JNZXNzYWdlKGVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgcmV0dXJuIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcbn1cblxuZnVuY3Rpb24gZ2V0TWFya2VyRGlyZWN0b3J5KCk6IHN0cmluZyB7XG4gIHJldHVybiBqb2luKHRtcGRpcigpLCBNQVJLRVJfRElSX05BTUUpO1xufVxuXG5mdW5jdGlvbiBnZXRNYXJrZXJGaWxlUGF0aChwb3J0OiBudW1iZXIpOiBzdHJpbmcge1xuICByZXR1cm4gam9pbihnZXRNYXJrZXJEaXJlY3RvcnkoKSwgYCR7U3RyaW5nKHBvcnQpfSR7TUFSS0VSX0ZJTEVfU1VGRklYfWApO1xufVxuXG5mdW5jdGlvbiBwYXJzZU1hcmtlcihwYXJzZWQ6IHVua25vd24sIHBvcnQ6IG51bWJlcik6IE93bmVkSW5zdGFuY2VFeGl0TWFya2VyIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHR5cGVvZiBwYXJzZWQgIT09ICdvYmplY3QnIHx8IHBhcnNlZCA9PT0gbnVsbCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCByZWNvcmQgPSBwYXJzZWQgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNvbnN0IHsgY29kZSwgZXhpdGVkQXRJbk1pbGxpc2Vjb25kcywgb3V0cHV0VGFpbCwgcGlkLCBwb3J0OiBtYXJrZWRQb3J0LCBzaWduYWwsIHNwYXduRXJyb3IgfSA9IHJlY29yZDtcblxuICBpZiAodHlwZW9mIGV4aXRlZEF0SW5NaWxsaXNlY29uZHMgIT09ICdudW1iZXInIHx8IG1hcmtlZFBvcnQgIT09IHBvcnQpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBjb2RlOiB0eXBlb2YgY29kZSA9PT0gJ251bWJlcicgPyBjb2RlIDogbnVsbCxcbiAgICBleGl0ZWRBdEluTWlsbGlzZWNvbmRzLFxuICAgIG91dHB1dFRhaWw6IHR5cGVvZiBvdXRwdXRUYWlsID09PSAnc3RyaW5nJyA/IG91dHB1dFRhaWwgOiAnJyxcbiAgICBwaWQ6IHR5cGVvZiBwaWQgPT09ICdudW1iZXInID8gcGlkIDogdW5kZWZpbmVkLFxuICAgIHBvcnQsXG4gICAgc2lnbmFsOiB0eXBlb2Ygc2lnbmFsID09PSAnc3RyaW5nJyA/IHNpZ25hbCBhcyBOb2RlSlMuU2lnbmFscyA6IG51bGwsXG4gICAgLi4uKHR5cGVvZiBzcGF3bkVycm9yID09PSAnc3RyaW5nJyAmJiB7IHNwYXduRXJyb3IgfSlcbiAgfTtcbn1cbiJdLAogICJtYXBwaW5ncyI6ICJBQXVCQTtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxjQUFjO0FBQ3ZCLFNBQVMsWUFBWTtBQUVyQixTQUFTLFdBQVc7QUFFcEIsTUFBTSxrQkFBa0I7QUFDeEIsTUFBTSxxQkFBcUI7QUFvRnBCLFNBQVMsNkJBQTZCLE1BQW9CO0FBQy9ELE1BQUk7QUFDRixXQUFPLGtCQUFrQixJQUFJLEdBQUcsRUFBRSxPQUFPLEtBQUssQ0FBQztBQUFBLEVBQ2pELFNBQVMsT0FBZ0I7QUFDdkIsUUFBSSxxRUFBcUUsT0FBTyxJQUFJLENBQUMsS0FBSyxnQkFBZ0IsS0FBSyxDQUFDLEVBQUU7QUFBQSxFQUNwSDtBQUNGO0FBUU8sU0FBUyw0QkFBNEIsTUFBbUQ7QUFDN0YsTUFBSTtBQUNKLE1BQUk7QUFDRixhQUFTLEtBQUssTUFBTSxhQUFhLGtCQUFrQixJQUFJLEdBQUcsT0FBTyxDQUFDO0FBQUEsRUFDcEUsUUFBUTtBQUNOLFdBQU87QUFBQSxFQUNUO0FBRUEsU0FBTyxZQUFZLFFBQVEsSUFBSTtBQUNqQztBQVFPLFNBQVMsNkJBQTZCLFFBQWtEO0FBQzdGLFFBQU0sU0FBa0M7QUFBQSxJQUN0QyxNQUFNLE9BQU87QUFBQSxJQUNiLHdCQUF3QixLQUFLLElBQUk7QUFBQSxJQUNqQyxZQUFZLE9BQU87QUFBQSxJQUNuQixLQUFLLE9BQU87QUFBQSxJQUNaLE1BQU0sT0FBTztBQUFBLElBQ2IsUUFBUSxPQUFPO0FBQUEsSUFDZixHQUFJLE9BQU8sZUFBZSxVQUFhLEVBQUUsWUFBWSxPQUFPLFdBQVc7QUFBQSxFQUN6RTtBQUVBLE1BQUk7QUFDRixjQUFVLG1CQUFtQixHQUFHLEVBQUUsV0FBVyxLQUFLLENBQUM7QUFDbkQsa0JBQWMsa0JBQWtCLE9BQU8sSUFBSSxHQUFHLEtBQUssVUFBVSxNQUFNLENBQUM7QUFBQSxFQUN0RSxTQUFTLE9BQWdCO0FBQ3ZCLFFBQUksa0VBQWtFLE9BQU8sT0FBTyxJQUFJLENBQUMsS0FBSyxnQkFBZ0IsS0FBSyxDQUFDLEVBQUU7QUFBQSxFQUN4SDtBQUNGO0FBRUEsU0FBUyxnQkFBZ0IsT0FBd0I7QUFDL0MsU0FBTyxpQkFBaUIsUUFBUSxNQUFNLFVBQVUsT0FBTyxLQUFLO0FBQzlEO0FBRUEsU0FBUyxxQkFBNkI7QUFDcEMsU0FBTyxLQUFLLE9BQU8sR0FBRyxlQUFlO0FBQ3ZDO0FBRUEsU0FBUyxrQkFBa0IsTUFBc0I7QUFDL0MsU0FBTyxLQUFLLG1CQUFtQixHQUFHLEdBQUcsT0FBTyxJQUFJLENBQUMsR0FBRyxrQkFBa0IsRUFBRTtBQUMxRTtBQUVBLFNBQVMsWUFBWSxRQUFpQixNQUFtRDtBQUN2RixNQUFJLE9BQU8sV0FBVyxZQUFZLFdBQVcsTUFBTTtBQUNqRCxXQUFPO0FBQUEsRUFDVDtBQUVBLFFBQU0sU0FBUztBQUNmLFFBQU0sRUFBRSxNQUFNLHdCQUF3QixZQUFZLEtBQUssTUFBTSxZQUFZLFFBQVEsV0FBVyxJQUFJO0FBRWhHLE1BQUksT0FBTywyQkFBMkIsWUFBWSxlQUFlLE1BQU07QUFDckUsV0FBTztBQUFBLEVBQ1Q7QUFFQSxTQUFPO0FBQUEsSUFDTCxNQUFNLE9BQU8sU0FBUyxXQUFXLE9BQU87QUFBQSxJQUN4QztBQUFBLElBQ0EsWUFBWSxPQUFPLGVBQWUsV0FBVyxhQUFhO0FBQUEsSUFDMUQsS0FBSyxPQUFPLFFBQVEsV0FBVyxNQUFNO0FBQUEsSUFDckM7QUFBQSxJQUNBLFFBQVEsT0FBTyxXQUFXLFdBQVcsU0FBMkI7QUFBQSxJQUNoRSxHQUFJLE9BQU8sZUFBZSxZQUFZLEVBQUUsV0FBVztBQUFBLEVBQ3JEO0FBQ0Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * The distinct error thrown when the harness-owned Obsidian instance is gone —
5
+ * it exited, and the CDP endpoint it was serving answers nothing.
6
+ *
7
+ * It exists to replace an anonymous cascade with one named cause. Before it,
8
+ * every test file scheduled after a mid-run death failed in ~60–90 ms with
9
+ * `TypeError: fetch failed` wrapping `connect ECONNREFUSED 127.0.0.1:<port>` —
10
+ * measured at **156 such failures across 21 files** in `obsidian-patterns` on
11
+ * 2026-09-05, not one of them a test result. The absence of an app is not a test
12
+ * outcome, and this error says so in the words a reader needs: the instance
13
+ * died, here is its exit code, and these failures are not about your code.
14
+ *
15
+ * Exported so callers can `instanceof`-match it, like `SilentAsarFallbackError`
16
+ * and `RendererFailedToInitializeError`.
17
+ */
18
+ import type { OwnedInstanceExitMarker } from './owned-instance-exit-marker.mjs';
19
+ /**
20
+ * Parameters for the {@link OwnedInstanceExitedError} constructor.
21
+ *
22
+ * Everything but the URL is optional: the exit details come from the process
23
+ * that launched the instance, and a caller in another process has them only
24
+ * when the exit marker survived (see `owned-instance-exit-marker.ts`).
25
+ */
26
+ export interface OwnedInstanceExitedErrorConstructorParams {
27
+ /**
28
+ The CDP URL the dead instance was serving.
29
+ */
30
+ readonly cdpUrl: string;
31
+ /**
32
+ Exit code, when known.
33
+ */
34
+ readonly code?: null | number | undefined;
35
+ /**
36
+ When the instance exited (`Date.now()` epoch milliseconds), when known.
37
+ */
38
+ readonly exitedAtInMilliseconds?: number | undefined;
39
+ /**
40
+ The tail of what the instance wrote to stdout/stderr, when any was captured.
41
+ */
42
+ readonly outputTail?: string | undefined;
43
+ /**
44
+ PID of the dead instance, when known.
45
+ */
46
+ readonly pid?: number | undefined;
47
+ /**
48
+ Terminating signal, when known.
49
+ */
50
+ readonly signal?: NodeJS.Signals | null | undefined;
51
+ /**
52
+ The spawn-failure message when the instance never started, otherwise absent.
53
+ */
54
+ readonly spawnError?: string | undefined;
55
+ }
56
+ /**
57
+ * Thrown when the harness-owned Obsidian instance has exited and its CDP
58
+ * endpoint is therefore unreachable. Carries whatever is known about the death
59
+ * — exit code, signal, when it happened, and the output tail — so the failure
60
+ * names its own cause instead of a refused connection.
61
+ */
62
+ export declare class OwnedInstanceExitedError extends Error {
63
+ /**
64
+ The CDP URL the dead instance was serving.
65
+ */
66
+ readonly cdpUrl: string;
67
+ /**
68
+ Exit code, when known.
69
+ */
70
+ readonly code: null | number | undefined;
71
+ /**
72
+ When the instance exited (`Date.now()` epoch milliseconds), when known.
73
+ */
74
+ readonly exitedAtInMilliseconds: number | undefined;
75
+ /**
76
+ Terminating signal, when known.
77
+ */
78
+ readonly signal: NodeJS.Signals | null | undefined;
79
+ /**
80
+ * Creates the error from whatever is known about the instance's death.
81
+ *
82
+ * @param params - The CDP URL, and the exit details when they are available.
83
+ */
84
+ constructor(params: OwnedInstanceExitedErrorConstructorParams);
85
+ }
86
+ /**
87
+ * Builds the error from an exit marker, for a process that did not launch the
88
+ * instance and so has nothing else to go on.
89
+ *
90
+ * A missing marker is expected rather than exceptional — it is cleared on every
91
+ * deliberate kill, and a hard enough kill records nothing — so the error is
92
+ * still built, naming the instance without claiming to know how it died.
93
+ *
94
+ * @param cdpUrl - The CDP URL the dead instance was serving.
95
+ * @param marker - The exit marker read for its port, or `undefined` when there is none.
96
+ * @returns The error to throw in place of a refused connection.
97
+ */
98
+ export declare function buildOwnedInstanceExitedErrorFromMarker(cdpUrl: string, marker: OwnedInstanceExitMarker | undefined): OwnedInstanceExitedError;
@@ -0,0 +1,81 @@
1
+ import { appendProcessOutputTail } from "./process-exit-message.mjs";
2
+ const MILLISECONDS_PER_SECOND = 1e3;
3
+ class OwnedInstanceExitedError extends Error {
4
+ /**
5
+ The CDP URL the dead instance was serving.
6
+ */
7
+ cdpUrl;
8
+ /**
9
+ Exit code, when known.
10
+ */
11
+ code;
12
+ /**
13
+ When the instance exited (`Date.now()` epoch milliseconds), when known.
14
+ */
15
+ exitedAtInMilliseconds;
16
+ /**
17
+ Terminating signal, when known.
18
+ */
19
+ signal;
20
+ /**
21
+ * Creates the error from whatever is known about the instance's death.
22
+ *
23
+ * @param params - The CDP URL, and the exit details when they are available.
24
+ */
25
+ constructor(params) {
26
+ super(buildMessage(params));
27
+ this.name = "OwnedInstanceExitedError";
28
+ this.cdpUrl = params.cdpUrl;
29
+ this.code = params.code;
30
+ this.exitedAtInMilliseconds = params.exitedAtInMilliseconds;
31
+ this.signal = params.signal;
32
+ }
33
+ }
34
+ function buildOwnedInstanceExitedErrorFromMarker(cdpUrl, marker) {
35
+ if (!marker) {
36
+ return new OwnedInstanceExitedError({ cdpUrl });
37
+ }
38
+ return new OwnedInstanceExitedError({
39
+ cdpUrl,
40
+ code: marker.code,
41
+ exitedAtInMilliseconds: marker.exitedAtInMilliseconds,
42
+ outputTail: marker.outputTail,
43
+ pid: marker.pid,
44
+ signal: marker.signal,
45
+ spawnError: marker.spawnError
46
+ });
47
+ }
48
+ function buildMessage(params) {
49
+ const message = `The harness-owned Obsidian instance at ${params.cdpUrl} is gone: ${describeExit(params)}. Whatever ran after it had no app to talk to, so these failures are not test results \u2014 look for the \`!!! OWNED OBSIDIAN EXITED\` line in the run log for the moment it happened.`;
50
+ return appendProcessOutputTail(message, { output: params.outputTail ?? "", outputLabel: "Obsidian output" });
51
+ }
52
+ function describeExit(params) {
53
+ if (params.spawnError !== void 0) {
54
+ return `it failed to start (${params.spawnError})`;
55
+ }
56
+ if (params.code === void 0 && params.signal === void 0) {
57
+ return "it exited at some point during this run, and the harness recorded nothing about how (the run that owns it logs the exit code; a worker sees only what the exit marker preserved)";
58
+ }
59
+ return `${describeProcess(params)} ${describeReason(params)}${describeWhen(params.exitedAtInMilliseconds)}`;
60
+ }
61
+ function describeProcess(params) {
62
+ return params.pid === void 0 ? "it" : `its process (pid ${String(params.pid)})`;
63
+ }
64
+ function describeReason(params) {
65
+ if (params.signal !== void 0 && params.signal !== null) {
66
+ return `was terminated by signal ${params.signal}`;
67
+ }
68
+ return params.code === void 0 || params.code === null ? "exited with no exit code" : `exited with code ${String(params.code)}`;
69
+ }
70
+ function describeWhen(exitedAtInMilliseconds) {
71
+ if (exitedAtInMilliseconds === void 0) {
72
+ return "";
73
+ }
74
+ const elapsedInSeconds = Math.max(0, Math.round((Date.now() - exitedAtInMilliseconds) / MILLISECONDS_PER_SECOND));
75
+ return ` ${String(elapsedInSeconds)}s ago, at ${new Date(exitedAtInMilliseconds).toISOString()}`;
76
+ }
77
+ export {
78
+ OwnedInstanceExitedError,
79
+ buildOwnedInstanceExitedErrorFromMarker
80
+ };
81
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL293bmVkLWluc3RhbmNlLWV4aXRlZC1lcnJvci50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIFRoZSBkaXN0aW5jdCBlcnJvciB0aHJvd24gd2hlbiB0aGUgaGFybmVzcy1vd25lZCBPYnNpZGlhbiBpbnN0YW5jZSBpcyBnb25lIFx1MjAxNFxuICogaXQgZXhpdGVkLCBhbmQgdGhlIENEUCBlbmRwb2ludCBpdCB3YXMgc2VydmluZyBhbnN3ZXJzIG5vdGhpbmcuXG4gKlxuICogSXQgZXhpc3RzIHRvIHJlcGxhY2UgYW4gYW5vbnltb3VzIGNhc2NhZGUgd2l0aCBvbmUgbmFtZWQgY2F1c2UuIEJlZm9yZSBpdCxcbiAqIGV2ZXJ5IHRlc3QgZmlsZSBzY2hlZHVsZWQgYWZ0ZXIgYSBtaWQtcnVuIGRlYXRoIGZhaWxlZCBpbiB+NjBcdTIwMTM5MCBtcyB3aXRoXG4gKiBgVHlwZUVycm9yOiBmZXRjaCBmYWlsZWRgIHdyYXBwaW5nIGBjb25uZWN0IEVDT05OUkVGVVNFRCAxMjcuMC4wLjE6PHBvcnQ+YCBcdTIwMTRcbiAqIG1lYXN1cmVkIGF0ICoqMTU2IHN1Y2ggZmFpbHVyZXMgYWNyb3NzIDIxIGZpbGVzKiogaW4gYG9ic2lkaWFuLXBhdHRlcm5zYCBvblxuICogMjAyNi0wOS0wNSwgbm90IG9uZSBvZiB0aGVtIGEgdGVzdCByZXN1bHQuIFRoZSBhYnNlbmNlIG9mIGFuIGFwcCBpcyBub3QgYSB0ZXN0XG4gKiBvdXRjb21lLCBhbmQgdGhpcyBlcnJvciBzYXlzIHNvIGluIHRoZSB3b3JkcyBhIHJlYWRlciBuZWVkczogdGhlIGluc3RhbmNlXG4gKiBkaWVkLCBoZXJlIGlzIGl0cyBleGl0IGNvZGUsIGFuZCB0aGVzZSBmYWlsdXJlcyBhcmUgbm90IGFib3V0IHlvdXIgY29kZS5cbiAqXG4gKiBFeHBvcnRlZCBzbyBjYWxsZXJzIGNhbiBgaW5zdGFuY2VvZmAtbWF0Y2ggaXQsIGxpa2UgYFNpbGVudEFzYXJGYWxsYmFja0Vycm9yYFxuICogYW5kIGBSZW5kZXJlckZhaWxlZFRvSW5pdGlhbGl6ZUVycm9yYC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IE93bmVkSW5zdGFuY2VFeGl0TWFya2VyIH0gZnJvbSAnLi9vd25lZC1pbnN0YW5jZS1leGl0LW1hcmtlci5tanMnO1xuXG5pbXBvcnQgeyBhcHBlbmRQcm9jZXNzT3V0cHV0VGFpbCB9IGZyb20gJy4vcHJvY2Vzcy1leGl0LW1lc3NhZ2UubWpzJztcblxuY29uc3QgTUlMTElTRUNPTkRTX1BFUl9TRUNPTkQgPSAxMDAwO1xuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHRoZSB7QGxpbmsgT3duZWRJbnN0YW5jZUV4aXRlZEVycm9yfSBjb25zdHJ1Y3Rvci5cbiAqXG4gKiBFdmVyeXRoaW5nIGJ1dCB0aGUgVVJMIGlzIG9wdGlvbmFsOiB0aGUgZXhpdCBkZXRhaWxzIGNvbWUgZnJvbSB0aGUgcHJvY2Vzc1xuICogdGhhdCBsYXVuY2hlZCB0aGUgaW5zdGFuY2UsIGFuZCBhIGNhbGxlciBpbiBhbm90aGVyIHByb2Nlc3MgaGFzIHRoZW0gb25seVxuICogd2hlbiB0aGUgZXhpdCBtYXJrZXIgc3Vydml2ZWQgKHNlZSBgb3duZWQtaW5zdGFuY2UtZXhpdC1tYXJrZXIudHNgKS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBPd25lZEluc3RhbmNlRXhpdGVkRXJyb3JDb25zdHJ1Y3RvclBhcmFtcyB7XG4gIC8qKlxuICBUaGUgQ0RQIFVSTCB0aGUgZGVhZCBpbnN0YW5jZSB3YXMgc2VydmluZy5cbiAgICovXG4gIHJlYWRvbmx5IGNkcFVybDogc3RyaW5nO1xuXG4gIC8qKlxuICBFeGl0IGNvZGUsIHdoZW4ga25vd24uXG4gICAqL1xuICByZWFkb25seSBjb2RlPzogbnVsbCB8IG51bWJlciB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgV2hlbiB0aGUgaW5zdGFuY2UgZXhpdGVkIChgRGF0ZS5ub3coKWAgZXBvY2ggbWlsbGlzZWNvbmRzKSwgd2hlbiBrbm93bi5cbiAgICovXG4gIHJlYWRvbmx5IGV4aXRlZEF0SW5NaWxsaXNlY29uZHM/OiBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSB0YWlsIG9mIHdoYXQgdGhlIGluc3RhbmNlIHdyb3RlIHRvIHN0ZG91dC9zdGRlcnIsIHdoZW4gYW55IHdhcyBjYXB0dXJlZC5cbiAgICovXG4gIHJlYWRvbmx5IG91dHB1dFRhaWw/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFBJRCBvZiB0aGUgZGVhZCBpbnN0YW5jZSwgd2hlbiBrbm93bi5cbiAgICovXG4gIHJlYWRvbmx5IHBpZD86IG51bWJlciB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgVGVybWluYXRpbmcgc2lnbmFsLCB3aGVuIGtub3duLlxuICAgKi9cbiAgcmVhZG9ubHkgc2lnbmFsPzogTm9kZUpTLlNpZ25hbHMgfCBudWxsIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBUaGUgc3Bhd24tZmFpbHVyZSBtZXNzYWdlIHdoZW4gdGhlIGluc3RhbmNlIG5ldmVyIHN0YXJ0ZWQsIG90aGVyd2lzZSBhYnNlbnQuXG4gICAqL1xuICByZWFkb25seSBzcGF3bkVycm9yPzogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFRocm93biB3aGVuIHRoZSBoYXJuZXNzLW93bmVkIE9ic2lkaWFuIGluc3RhbmNlIGhhcyBleGl0ZWQgYW5kIGl0cyBDRFBcbiAqIGVuZHBvaW50IGlzIHRoZXJlZm9yZSB1bnJlYWNoYWJsZS4gQ2FycmllcyB3aGF0ZXZlciBpcyBrbm93biBhYm91dCB0aGUgZGVhdGhcbiAqIFx1MjAxNCBleGl0IGNvZGUsIHNpZ25hbCwgd2hlbiBpdCBoYXBwZW5lZCwgYW5kIHRoZSBvdXRwdXQgdGFpbCBcdTIwMTQgc28gdGhlIGZhaWx1cmVcbiAqIG5hbWVzIGl0cyBvd24gY2F1c2UgaW5zdGVhZCBvZiBhIHJlZnVzZWQgY29ubmVjdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgLyoqXG4gIFRoZSBDRFAgVVJMIHRoZSBkZWFkIGluc3RhbmNlIHdhcyBzZXJ2aW5nLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNkcFVybDogc3RyaW5nO1xuXG4gIC8qKlxuICBFeGl0IGNvZGUsIHdoZW4ga25vd24uXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY29kZTogbnVsbCB8IG51bWJlciB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgV2hlbiB0aGUgaW5zdGFuY2UgZXhpdGVkIChgRGF0ZS5ub3coKWAgZXBvY2ggbWlsbGlzZWNvbmRzKSwgd2hlbiBrbm93bi5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBleGl0ZWRBdEluTWlsbGlzZWNvbmRzOiBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRlcm1pbmF0aW5nIHNpZ25hbCwgd2hlbiBrbm93bi5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBzaWduYWw6IE5vZGVKUy5TaWduYWxzIHwgbnVsbCB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgZXJyb3IgZnJvbSB3aGF0ZXZlciBpcyBrbm93biBhYm91dCB0aGUgaW5zdGFuY2UncyBkZWF0aC5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFRoZSBDRFAgVVJMLCBhbmQgdGhlIGV4aXQgZGV0YWlscyB3aGVuIHRoZXkgYXJlIGF2YWlsYWJsZS5cbiAgICovXG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihwYXJhbXM6IE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvckNvbnN0cnVjdG9yUGFyYW1zKSB7XG4gICAgc3VwZXIoYnVpbGRNZXNzYWdlKHBhcmFtcykpO1xuICAgIHRoaXMubmFtZSA9ICdPd25lZEluc3RhbmNlRXhpdGVkRXJyb3InO1xuICAgIHRoaXMuY2RwVXJsID0gcGFyYW1zLmNkcFVybDtcbiAgICB0aGlzLmNvZGUgPSBwYXJhbXMuY29kZTtcbiAgICB0aGlzLmV4aXRlZEF0SW5NaWxsaXNlY29uZHMgPSBwYXJhbXMuZXhpdGVkQXRJbk1pbGxpc2Vjb25kcztcbiAgICB0aGlzLnNpZ25hbCA9IHBhcmFtcy5zaWduYWw7XG4gIH1cbn1cblxuLyoqXG4gKiBCdWlsZHMgdGhlIGVycm9yIGZyb20gYW4gZXhpdCBtYXJrZXIsIGZvciBhIHByb2Nlc3MgdGhhdCBkaWQgbm90IGxhdW5jaCB0aGVcbiAqIGluc3RhbmNlIGFuZCBzbyBoYXMgbm90aGluZyBlbHNlIHRvIGdvIG9uLlxuICpcbiAqIEEgbWlzc2luZyBtYXJrZXIgaXMgZXhwZWN0ZWQgcmF0aGVyIHRoYW4gZXhjZXB0aW9uYWwgXHUyMDE0IGl0IGlzIGNsZWFyZWQgb24gZXZlcnlcbiAqIGRlbGliZXJhdGUga2lsbCwgYW5kIGEgaGFyZCBlbm91Z2gga2lsbCByZWNvcmRzIG5vdGhpbmcgXHUyMDE0IHNvIHRoZSBlcnJvciBpc1xuICogc3RpbGwgYnVpbHQsIG5hbWluZyB0aGUgaW5zdGFuY2Ugd2l0aG91dCBjbGFpbWluZyB0byBrbm93IGhvdyBpdCBkaWVkLlxuICpcbiAqIEBwYXJhbSBjZHBVcmwgLSBUaGUgQ0RQIFVSTCB0aGUgZGVhZCBpbnN0YW5jZSB3YXMgc2VydmluZy5cbiAqIEBwYXJhbSBtYXJrZXIgLSBUaGUgZXhpdCBtYXJrZXIgcmVhZCBmb3IgaXRzIHBvcnQsIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhlcmUgaXMgbm9uZS5cbiAqIEByZXR1cm5zIFRoZSBlcnJvciB0byB0aHJvdyBpbiBwbGFjZSBvZiBhIHJlZnVzZWQgY29ubmVjdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkT3duZWRJbnN0YW5jZUV4aXRlZEVycm9yRnJvbU1hcmtlcihjZHBVcmw6IHN0cmluZywgbWFya2VyOiBPd25lZEluc3RhbmNlRXhpdE1hcmtlciB8IHVuZGVmaW5lZCk6IE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvciB7XG4gIGlmICghbWFya2VyKSB7XG4gICAgcmV0dXJuIG5ldyBPd25lZEluc3RhbmNlRXhpdGVkRXJyb3IoeyBjZHBVcmwgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvcih7XG4gICAgY2RwVXJsLFxuICAgIGNvZGU6IG1hcmtlci5jb2RlLFxuICAgIGV4aXRlZEF0SW5NaWxsaXNlY29uZHM6IG1hcmtlci5leGl0ZWRBdEluTWlsbGlzZWNvbmRzLFxuICAgIG91dHB1dFRhaWw6IG1hcmtlci5vdXRwdXRUYWlsLFxuICAgIHBpZDogbWFya2VyLnBpZCxcbiAgICBzaWduYWw6IG1hcmtlci5zaWduYWwsXG4gICAgc3Bhd25FcnJvcjogbWFya2VyLnNwYXduRXJyb3JcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkTWVzc2FnZShwYXJhbXM6IE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvckNvbnN0cnVjdG9yUGFyYW1zKTogc3RyaW5nIHtcbiAgY29uc3QgbWVzc2FnZSA9IGBUaGUgaGFybmVzcy1vd25lZCBPYnNpZGlhbiBpbnN0YW5jZSBhdCAke3BhcmFtcy5jZHBVcmx9IGlzIGdvbmU6ICR7ZGVzY3JpYmVFeGl0KHBhcmFtcyl9LiBgXG4gICAgKyAnV2hhdGV2ZXIgcmFuIGFmdGVyIGl0IGhhZCBubyBhcHAgdG8gdGFsayB0bywgc28gdGhlc2UgZmFpbHVyZXMgYXJlIG5vdCB0ZXN0IHJlc3VsdHMgXHUyMDE0ICdcbiAgICArICdsb29rIGZvciB0aGUgYCEhISBPV05FRCBPQlNJRElBTiBFWElURURgIGxpbmUgaW4gdGhlIHJ1biBsb2cgZm9yIHRoZSBtb21lbnQgaXQgaGFwcGVuZWQuJztcblxuICByZXR1cm4gYXBwZW5kUHJvY2Vzc091dHB1dFRhaWwobWVzc2FnZSwgeyBvdXRwdXQ6IHBhcmFtcy5vdXRwdXRUYWlsID8/ICcnLCBvdXRwdXRMYWJlbDogJ09ic2lkaWFuIG91dHB1dCcgfSk7XG59XG5cbmZ1bmN0aW9uIGRlc2NyaWJlRXhpdChwYXJhbXM6IE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvckNvbnN0cnVjdG9yUGFyYW1zKTogc3RyaW5nIHtcbiAgaWYgKHBhcmFtcy5zcGF3bkVycm9yICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gYGl0IGZhaWxlZCB0byBzdGFydCAoJHtwYXJhbXMuc3Bhd25FcnJvcn0pYDtcbiAgfVxuXG4gIGlmIChwYXJhbXMuY29kZSA9PT0gdW5kZWZpbmVkICYmIHBhcmFtcy5zaWduYWwgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiAnaXQgZXhpdGVkIGF0IHNvbWUgcG9pbnQgZHVyaW5nIHRoaXMgcnVuLCBhbmQgdGhlIGhhcm5lc3MgcmVjb3JkZWQgbm90aGluZyBhYm91dCBob3cgJ1xuICAgICAgKyAnKHRoZSBydW4gdGhhdCBvd25zIGl0IGxvZ3MgdGhlIGV4aXQgY29kZTsgYSB3b3JrZXIgc2VlcyBvbmx5IHdoYXQgdGhlIGV4aXQgbWFya2VyIHByZXNlcnZlZCknO1xuICB9XG5cbiAgcmV0dXJuIGAke2Rlc2NyaWJlUHJvY2VzcyhwYXJhbXMpfSAke2Rlc2NyaWJlUmVhc29uKHBhcmFtcyl9JHtkZXNjcmliZVdoZW4ocGFyYW1zLmV4aXRlZEF0SW5NaWxsaXNlY29uZHMpfWA7XG59XG5cbmZ1bmN0aW9uIGRlc2NyaWJlUHJvY2VzcyhwYXJhbXM6IE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvckNvbnN0cnVjdG9yUGFyYW1zKTogc3RyaW5nIHtcbiAgcmV0dXJuIHBhcmFtcy5waWQgPT09IHVuZGVmaW5lZCA/ICdpdCcgOiBgaXRzIHByb2Nlc3MgKHBpZCAke1N0cmluZyhwYXJhbXMucGlkKX0pYDtcbn1cblxuZnVuY3Rpb24gZGVzY3JpYmVSZWFzb24ocGFyYW1zOiBPd25lZEluc3RhbmNlRXhpdGVkRXJyb3JDb25zdHJ1Y3RvclBhcmFtcyk6IHN0cmluZyB7XG4gIGlmIChwYXJhbXMuc2lnbmFsICE9PSB1bmRlZmluZWQgJiYgcGFyYW1zLnNpZ25hbCAhPT0gbnVsbCkge1xuICAgIHJldHVybiBgd2FzIHRlcm1pbmF0ZWQgYnkgc2lnbmFsICR7cGFyYW1zLnNpZ25hbH1gO1xuICB9XG5cbiAgcmV0dXJuIHBhcmFtcy5jb2RlID09PSB1bmRlZmluZWQgfHwgcGFyYW1zLmNvZGUgPT09IG51bGwgPyAnZXhpdGVkIHdpdGggbm8gZXhpdCBjb2RlJyA6IGBleGl0ZWQgd2l0aCBjb2RlICR7U3RyaW5nKHBhcmFtcy5jb2RlKX1gO1xufVxuXG5mdW5jdGlvbiBkZXNjcmliZVdoZW4oZXhpdGVkQXRJbk1pbGxpc2Vjb25kczogbnVtYmVyIHwgdW5kZWZpbmVkKTogc3RyaW5nIHtcbiAgaWYgKGV4aXRlZEF0SW5NaWxsaXNlY29uZHMgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIGNvbnN0IGVsYXBzZWRJblNlY29uZHMgPSBNYXRoLm1heCgwLCBNYXRoLnJvdW5kKChEYXRlLm5vdygpIC0gZXhpdGVkQXRJbk1pbGxpc2Vjb25kcykgLyBNSUxMSVNFQ09ORFNfUEVSX1NFQ09ORCkpO1xuICByZXR1cm4gYCAke1N0cmluZyhlbGFwc2VkSW5TZWNvbmRzKX1zIGFnbywgYXQgJHtuZXcgRGF0ZShleGl0ZWRBdEluTWlsbGlzZWNvbmRzKS50b0lTT1N0cmluZygpfWA7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiQUFvQkEsU0FBUywrQkFBK0I7QUFFeEMsTUFBTSwwQkFBMEI7QUFvRHpCLE1BQU0saUNBQWlDLE1BQU07QUFBQTtBQUFBO0FBQUE7QUFBQSxFQUlsQztBQUFBO0FBQUE7QUFBQTtBQUFBLEVBS0E7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQUtBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFLQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQU9ULFlBQVksUUFBbUQ7QUFDcEUsVUFBTSxhQUFhLE1BQU0sQ0FBQztBQUMxQixTQUFLLE9BQU87QUFDWixTQUFLLFNBQVMsT0FBTztBQUNyQixTQUFLLE9BQU8sT0FBTztBQUNuQixTQUFLLHlCQUF5QixPQUFPO0FBQ3JDLFNBQUssU0FBUyxPQUFPO0FBQUEsRUFDdkI7QUFDRjtBQWNPLFNBQVMsd0NBQXdDLFFBQWdCLFFBQXVFO0FBQzdJLE1BQUksQ0FBQyxRQUFRO0FBQ1gsV0FBTyxJQUFJLHlCQUF5QixFQUFFLE9BQU8sQ0FBQztBQUFBLEVBQ2hEO0FBRUEsU0FBTyxJQUFJLHlCQUF5QjtBQUFBLElBQ2xDO0FBQUEsSUFDQSxNQUFNLE9BQU87QUFBQSxJQUNiLHdCQUF3QixPQUFPO0FBQUEsSUFDL0IsWUFBWSxPQUFPO0FBQUEsSUFDbkIsS0FBSyxPQUFPO0FBQUEsSUFDWixRQUFRLE9BQU87QUFBQSxJQUNmLFlBQVksT0FBTztBQUFBLEVBQ3JCLENBQUM7QUFDSDtBQUVBLFNBQVMsYUFBYSxRQUEyRDtBQUMvRSxRQUFNLFVBQVUsMENBQTBDLE9BQU8sTUFBTSxhQUFhLGFBQWEsTUFBTSxDQUFDO0FBSXhHLFNBQU8sd0JBQXdCLFNBQVMsRUFBRSxRQUFRLE9BQU8sY0FBYyxJQUFJLGFBQWEsa0JBQWtCLENBQUM7QUFDN0c7QUFFQSxTQUFTLGFBQWEsUUFBMkQ7QUFDL0UsTUFBSSxPQUFPLGVBQWUsUUFBVztBQUNuQyxXQUFPLHVCQUF1QixPQUFPLFVBQVU7QUFBQSxFQUNqRDtBQUVBLE1BQUksT0FBTyxTQUFTLFVBQWEsT0FBTyxXQUFXLFFBQVc7QUFDNUQsV0FBTztBQUFBLEVBRVQ7QUFFQSxTQUFPLEdBQUcsZ0JBQWdCLE1BQU0sQ0FBQyxJQUFJLGVBQWUsTUFBTSxDQUFDLEdBQUcsYUFBYSxPQUFPLHNCQUFzQixDQUFDO0FBQzNHO0FBRUEsU0FBUyxnQkFBZ0IsUUFBMkQ7QUFDbEYsU0FBTyxPQUFPLFFBQVEsU0FBWSxPQUFPLG9CQUFvQixPQUFPLE9BQU8sR0FBRyxDQUFDO0FBQ2pGO0FBRUEsU0FBUyxlQUFlLFFBQTJEO0FBQ2pGLE1BQUksT0FBTyxXQUFXLFVBQWEsT0FBTyxXQUFXLE1BQU07QUFDekQsV0FBTyw0QkFBNEIsT0FBTyxNQUFNO0FBQUEsRUFDbEQ7QUFFQSxTQUFPLE9BQU8sU0FBUyxVQUFhLE9BQU8sU0FBUyxPQUFPLDZCQUE2QixvQkFBb0IsT0FBTyxPQUFPLElBQUksQ0FBQztBQUNqSTtBQUVBLFNBQVMsYUFBYSx3QkFBb0Q7QUFDeEUsTUFBSSwyQkFBMkIsUUFBVztBQUN4QyxXQUFPO0FBQUEsRUFDVDtBQUVBLFFBQU0sbUJBQW1CLEtBQUssSUFBSSxHQUFHLEtBQUssT0FBTyxLQUFLLElBQUksSUFBSSwwQkFBMEIsdUJBQXVCLENBQUM7QUFDaEgsU0FBTyxJQUFJLE9BQU8sZ0JBQWdCLENBQUMsYUFBYSxJQUFJLEtBQUssc0JBQXNCLEVBQUUsWUFBWSxDQUFDO0FBQ2hHOyIsCiAgIm5hbWVzIjogW10KfQo=