quickwin 2.1.1 → 2.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 (117) hide show
  1. package/README.en.md +9 -9
  2. package/README.md +9 -9
  3. package/constants.ts +1063 -0
  4. package/enum_map.d.ts +129 -0
  5. package/examples/PdfCanvas.js +2 -2
  6. package/examples/PdfCanvas.tsx +3 -2
  7. package/examples/{exec_server.js → execd/main.js} +1114 -287
  8. package/examples/execd/tray.js +192 -0
  9. package/examples/execd/worker.js +122 -0
  10. package/examples/pdf_preview2.js +46 -46
  11. package/examples/pdf_preview2.ts +55 -54
  12. package/examples/pdf_viewer.js +134 -130
  13. package/examples/pdf_viewer.tsx +6 -5
  14. package/examples/test_gallery.js +135 -131
  15. package/examples/test_gallery.tsx +9 -8
  16. package/examples/test_react_lazy.js +130 -128
  17. package/examples/test_react_lazy.tsx +7 -6
  18. package/examples/test_react_listbox.js +130 -128
  19. package/examples/test_react_listbox.tsx +8 -7
  20. package/examples/test_root_window.js +130 -128
  21. package/examples/test_root_window.tsx +5 -5
  22. package/examples/test_tab.js +130 -128
  23. package/examples/test_tab.tsx +7 -6
  24. package/examples/tray_demo.js +8 -8
  25. package/examples/tray_demo.tsx +9 -8
  26. package/lib/dumpRects.js +2 -2
  27. package/lib/dumpRects.ts +3 -2
  28. package/lib/fetch.js +15 -15
  29. package/lib/fetch.ts +16 -15
  30. package/lib/ffi/bind.js +3 -3
  31. package/lib/ffi/bind.ts +3 -3
  32. package/lib/ffi/ctype.ts +3 -1
  33. package/lib/ffi/struct.js +23 -7
  34. package/lib/ffi/struct.ts +50 -23
  35. package/lib/http-server.js +5 -5
  36. package/lib/http-server.ts +6 -5
  37. package/lib/react-qw/components/Button.js +2 -2
  38. package/lib/react-qw/components/CheckBox.js +4 -4
  39. package/lib/react-qw/components/ComboBox.js +10 -10
  40. package/lib/react-qw/components/DateTimePicker.js +12 -12
  41. package/lib/react-qw/components/Input.js +7 -7
  42. package/lib/react-qw/components/Link.js +4 -4
  43. package/lib/react-qw/components/ListBox.js +12 -12
  44. package/lib/react-qw/components/ListView.js +35 -35
  45. package/lib/react-qw/components/PathPicker.js +3 -3
  46. package/lib/react-qw/components/ProgressBar.js +4 -4
  47. package/lib/react-qw/components/RadioButton.js +4 -4
  48. package/lib/react-qw/components/ScrollView.js +28 -28
  49. package/lib/react-qw/components/Slider.js +11 -11
  50. package/lib/react-qw/components/Tab.js +10 -10
  51. package/lib/react-qw/components/Tooltip.js +8 -8
  52. package/lib/react-qw/components/TreeView.js +20 -20
  53. package/lib/react-qw/index.js +5 -5
  54. package/lib/react-qw/index.ts +6 -5
  55. package/lib/react-qw/props.js +4 -4
  56. package/lib/react-qw/props.ts +5 -4
  57. package/lib/react-qw/reconciler.js +10 -10
  58. package/lib/react-qw/reconciler.ts +11 -10
  59. package/lib/text-measure.js +3 -3
  60. package/lib/text-measure.ts +4 -3
  61. package/lib/websocket.js +17 -17
  62. package/lib/websocket.ts +18 -17
  63. package/lib/windows/advapi32.js +7 -7
  64. package/lib/windows/advapi32.ts +7 -7
  65. package/lib/windows/gdi32.js +17 -17
  66. package/lib/windows/gdi32.ts +17 -17
  67. package/lib/windows/kernel32.js +41 -2
  68. package/lib/windows/kernel32.ts +45 -2
  69. package/lib/windows/shell32.js +24 -3
  70. package/lib/windows/shell32.ts +27 -4
  71. package/lib/windows/structs.js +230 -92
  72. package/lib/windows/structs.ts +278 -92
  73. package/lib/windows/user32.js +18 -6
  74. package/lib/windows/user32.ts +18 -6
  75. package/lib/windows/winspool.js +3 -3
  76. package/lib/windows/winspool.ts +3 -3
  77. package/package.json +4 -3
  78. package/quickwin.d.ts +32 -10
  79. package/qwin-nowasm-x86.exe +0 -0
  80. package/qwin-nowasm.exe +0 -0
  81. package/qwin-x86.exe +0 -0
  82. package/qwin.exe +0 -0
  83. package/test/test_ffi_bind.js +12 -10
  84. package/test/test_ffi_bind.ts +14 -12
  85. package/test/test_ffi_struct.js +60 -26
  86. package/test/test_ffi_struct.ts +58 -28
  87. package/test/test_ffi_windows.js +1 -1
  88. package/test/test_ffi_windows.ts +1 -1
  89. package/test/test_files.js +7 -7
  90. package/test/test_files.ts +8 -8
  91. package/test/test_gdi_draw.js +51 -51
  92. package/test/test_gdi_draw.ts +57 -57
  93. package/test/test_http_server.js +3 -3
  94. package/test/test_http_server.ts +4 -3
  95. package/test/test_ipv6.js +3 -3
  96. package/test/test_ipv6.ts +4 -3
  97. package/test/test_net_event.js +3 -3
  98. package/test/test_net_event.ts +4 -3
  99. package/test/test_printer.js +4 -4
  100. package/test/test_printer.ts +5 -5
  101. package/test/test_react_complex.js +132 -130
  102. package/test/test_react_counter.js +130 -128
  103. package/test/test_react_flex.js +132 -130
  104. package/test/test_react_hidden.js +130 -128
  105. package/test/test_react_listview_link.js +131 -129
  106. package/test/test_react_notify.js +148 -146
  107. package/test/test_react_render.js +130 -128
  108. package/test/test_registry.js +6 -6
  109. package/test/test_registry.ts +8 -8
  110. package/test/test_wolfssl_read.js +8 -8
  111. package/test/test_wolfssl_read.ts +9 -8
  112. package/examples/exec_server.tsx +0 -488
  113. package/examples/exec_server_worker.js +0 -395
  114. package/examples/exec_server_worker.ts +0 -417
  115. package/examples/setres.js +0 -79
  116. package/examples/setres.ts +0 -86
  117. package/quickwin_const.d.ts +0 -1037
@@ -1367,9 +1367,9 @@ var require_scheduler_development = __commonJS({
1367
1367
  }
1368
1368
  return first;
1369
1369
  }
1370
- function compare(a2, b7) {
1371
- var diff = a2.sortIndex - b7.sortIndex;
1372
- return 0 !== diff ? diff : a2.id - b7.id;
1370
+ function compare(a2, b8) {
1371
+ var diff = a2.sortIndex - b8.sortIndex;
1372
+ return 0 !== diff ? diff : a2.id - b8.id;
1373
1373
  }
1374
1374
  function advanceTimers(currentTime) {
1375
1375
  for (var timer = peek(timerQueue); null !== timer; ) {
@@ -1667,14 +1667,14 @@ var require_react_reconciler_development = __commonJS({
1667
1667
  throw Error("Unable to find node on an unmounted component.");
1668
1668
  return alternate !== fiber ? null : fiber;
1669
1669
  }
1670
- for (var a2 = fiber, b7 = alternate; ; ) {
1670
+ for (var a2 = fiber, b8 = alternate; ; ) {
1671
1671
  var parentA = a2.return;
1672
1672
  if (null === parentA) break;
1673
1673
  var parentB = parentA.alternate;
1674
1674
  if (null === parentB) {
1675
- b7 = parentA.return;
1676
- if (null !== b7) {
1677
- a2 = b7;
1675
+ b8 = parentA.return;
1676
+ if (null !== b8) {
1677
+ a2 = b8;
1678
1678
  continue;
1679
1679
  }
1680
1680
  break;
@@ -1682,23 +1682,23 @@ var require_react_reconciler_development = __commonJS({
1682
1682
  if (parentA.child === parentB.child) {
1683
1683
  for (parentB = parentA.child; parentB; ) {
1684
1684
  if (parentB === a2) return assertIsMounted(parentA), fiber;
1685
- if (parentB === b7) return assertIsMounted(parentA), alternate;
1685
+ if (parentB === b8) return assertIsMounted(parentA), alternate;
1686
1686
  parentB = parentB.sibling;
1687
1687
  }
1688
1688
  throw Error("Unable to find node on an unmounted component.");
1689
1689
  }
1690
- if (a2.return !== b7.return) a2 = parentA, b7 = parentB;
1690
+ if (a2.return !== b8.return) a2 = parentA, b8 = parentB;
1691
1691
  else {
1692
1692
  for (var didFindChild = false, _child = parentA.child; _child; ) {
1693
1693
  if (_child === a2) {
1694
1694
  didFindChild = true;
1695
1695
  a2 = parentA;
1696
- b7 = parentB;
1696
+ b8 = parentB;
1697
1697
  break;
1698
1698
  }
1699
- if (_child === b7) {
1699
+ if (_child === b8) {
1700
1700
  didFindChild = true;
1701
- b7 = parentA;
1701
+ b8 = parentA;
1702
1702
  a2 = parentB;
1703
1703
  break;
1704
1704
  }
@@ -1709,12 +1709,12 @@ var require_react_reconciler_development = __commonJS({
1709
1709
  if (_child === a2) {
1710
1710
  didFindChild = true;
1711
1711
  a2 = parentB;
1712
- b7 = parentA;
1712
+ b8 = parentA;
1713
1713
  break;
1714
1714
  }
1715
- if (_child === b7) {
1715
+ if (_child === b8) {
1716
1716
  didFindChild = true;
1717
- b7 = parentB;
1717
+ b8 = parentB;
1718
1718
  a2 = parentA;
1719
1719
  break;
1720
1720
  }
@@ -1726,7 +1726,7 @@ var require_react_reconciler_development = __commonJS({
1726
1726
  );
1727
1727
  }
1728
1728
  }
1729
- if (a2.alternate !== b7)
1729
+ if (a2.alternate !== b8)
1730
1730
  throw Error(
1731
1731
  "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue."
1732
1732
  );
@@ -15071,10 +15071,10 @@ var require_react_reconciler_development = __commonJS({
15071
15071
  setCurrentUpdatePriority(previousPriority), ReactSharedInternals.T = prevTransition;
15072
15072
  }
15073
15073
  };
15074
- exports2.discreteUpdates = function(fn, a2, b7, c2, d2) {
15074
+ exports2.discreteUpdates = function(fn, a2, b8, c2, d2) {
15075
15075
  var prevTransition = ReactSharedInternals.T, previousPriority = getCurrentUpdatePriority();
15076
15076
  try {
15077
- return setCurrentUpdatePriority(2), ReactSharedInternals.T = null, fn(a2, b7, c2, d2);
15077
+ return setCurrentUpdatePriority(2), ReactSharedInternals.T = null, fn(a2, b8, c2, d2);
15078
15078
  } finally {
15079
15079
  setCurrentUpdatePriority(previousPriority), ReactSharedInternals.T = prevTransition, executionContext === NoContext && (workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS);
15080
15080
  }
@@ -15353,7 +15353,7 @@ var require_constants = __commonJS({
15353
15353
  }
15354
15354
  });
15355
15355
 
15356
- // _build/examples/exec_server.js
15356
+ // _build/examples/execd/main.js
15357
15357
  var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
15358
15358
 
15359
15359
  // _build/lib/polyfill.js
@@ -15514,7 +15514,7 @@ var URLSearchParamsImpl = class {
15514
15514
  this._list.push([key, value]);
15515
15515
  }
15516
15516
  sort() {
15517
- this._list.sort(([a2], [b7]) => a2 < b7 ? -1 : a2 > b7 ? 1 : 0);
15517
+ this._list.sort(([a2], [b8]) => a2 < b8 ? -1 : a2 > b8 ? 1 : 0);
15518
15518
  }
15519
15519
  forEach(fn) {
15520
15520
  for (const [k2, v2] of this._list)
@@ -15564,43 +15564,43 @@ var URLImpl = class _URLImpl {
15564
15564
  }
15565
15565
  if (base === void 0)
15566
15566
  throw new TypeError("Invalid URL");
15567
- const b7 = new _URLImpl(base);
15567
+ const b8 = new _URLImpl(base);
15568
15568
  if (p2.host) {
15569
- p2.scheme = b7._scheme;
15569
+ p2.scheme = b8._scheme;
15570
15570
  this._apply(p2);
15571
15571
  return;
15572
15572
  }
15573
15573
  if (!p2.path && !p2.query) {
15574
15574
  this._apply({
15575
- scheme: b7._scheme,
15576
- user: b7._username,
15577
- pass: b7._password,
15578
- host: b7._hostname,
15579
- port: b7._port,
15580
- path: b7._pathname,
15581
- query: b7._query,
15575
+ scheme: b8._scheme,
15576
+ user: b8._username,
15577
+ pass: b8._password,
15578
+ host: b8._hostname,
15579
+ port: b8._port,
15580
+ path: b8._pathname,
15581
+ query: b8._query,
15582
15582
  fragment: p2.fragment || ""
15583
15583
  });
15584
15584
  return;
15585
15585
  }
15586
- p2.scheme = b7._scheme;
15586
+ p2.scheme = b8._scheme;
15587
15587
  if (!p2.user)
15588
- p2.user = b7._username;
15588
+ p2.user = b8._username;
15589
15589
  if (!p2.pass)
15590
- p2.pass = b7._password;
15590
+ p2.pass = b8._password;
15591
15591
  if (!p2.host)
15592
- p2.host = b7._hostname;
15592
+ p2.host = b8._hostname;
15593
15593
  if (!p2.port)
15594
- p2.port = b7._port;
15594
+ p2.port = b8._port;
15595
15595
  if (!p2.fragment)
15596
15596
  p2.fragment = "";
15597
15597
  if (p2.path && !p2.path.startsWith("/")) {
15598
- const bd = b7._pathname.substring(0, b7._pathname.lastIndexOf("/") + 1);
15598
+ const bd = b8._pathname.substring(0, b8._pathname.lastIndexOf("/") + 1);
15599
15599
  p2.path = _normalizePath(bd + p2.path);
15600
15600
  } else if (!p2.path) {
15601
- p2.path = b7._pathname;
15601
+ p2.path = b8._pathname;
15602
15602
  if (!p2.query)
15603
- p2.query = b7._query;
15603
+ p2.query = b8._query;
15604
15604
  }
15605
15605
  this._apply(p2);
15606
15606
  }
@@ -15705,19 +15705,19 @@ function _normalizeLabel(label) {
15705
15705
  function _decodeUTF8(buf, fatal) {
15706
15706
  let out = "";
15707
15707
  for (let i2 = 0; i2 < buf.length; ) {
15708
- const b7 = buf[i2++];
15709
- if (b7 < 128) {
15710
- out += String.fromCharCode(b7);
15708
+ const b8 = buf[i2++];
15709
+ if (b8 < 128) {
15710
+ out += String.fromCharCode(b8);
15711
15711
  continue;
15712
15712
  }
15713
- if (b7 < 192) {
15713
+ if (b8 < 192) {
15714
15714
  out += fatal ? (() => {
15715
15715
  throw new TypeError("unexpected continuation byte");
15716
15716
  })() : "\uFFFD";
15717
15717
  continue;
15718
15718
  }
15719
15719
  let c2, min;
15720
- if (b7 < 224) {
15720
+ if (b8 < 224) {
15721
15721
  if (i2 >= buf.length) {
15722
15722
  out += fatal ? (() => {
15723
15723
  throw new TypeError("incomplete utf-8");
@@ -15729,9 +15729,9 @@ function _decodeUTF8(buf, fatal) {
15729
15729
  out += "\uFFFD";
15730
15730
  continue;
15731
15731
  }
15732
- c2 = (b7 & 31) << 6 | b22 & 63;
15732
+ c2 = (b8 & 31) << 6 | b22 & 63;
15733
15733
  min = 128;
15734
- } else if (b7 < 240) {
15734
+ } else if (b8 < 240) {
15735
15735
  if (i2 + 1 >= buf.length) {
15736
15736
  out += fatal ? (() => {
15737
15737
  throw new TypeError("incomplete utf-8");
@@ -15744,9 +15744,9 @@ function _decodeUTF8(buf, fatal) {
15744
15744
  out += "\uFFFD";
15745
15745
  continue;
15746
15746
  }
15747
- c2 = (b7 & 15) << 12 | (b22 & 63) << 6 | b32 & 63;
15747
+ c2 = (b8 & 15) << 12 | (b22 & 63) << 6 | b32 & 63;
15748
15748
  min = 2048;
15749
- } else if (b7 < 248) {
15749
+ } else if (b8 < 248) {
15750
15750
  if (i2 + 2 >= buf.length) {
15751
15751
  out += fatal ? (() => {
15752
15752
  throw new TypeError("incomplete utf-8");
@@ -15760,7 +15760,7 @@ function _decodeUTF8(buf, fatal) {
15760
15760
  out += "\uFFFD";
15761
15761
  continue;
15762
15762
  }
15763
- c2 = (b7 & 7) << 18 | (b22 & 63) << 12 | (b32 & 63) << 6 | b42 & 63;
15763
+ c2 = (b8 & 7) << 18 | (b22 & 63) << 12 | (b32 & 63) << 6 | b42 & 63;
15764
15764
  min = 65536;
15765
15765
  } else {
15766
15766
  out += fatal ? (() => {
@@ -15940,31 +15940,31 @@ function sha1Bytes(bytes) {
15940
15940
  for (let t2 = 16; t2 < 80; t2++) {
15941
15941
  w2[t2] = rotl(w2[t2 - 3] ^ w2[t2 - 8] ^ w2[t2 - 14] ^ w2[t2 - 16], 1);
15942
15942
  }
15943
- let a2 = h0, b7 = h1, c2 = h2, d2 = h3, e2 = h4;
15943
+ let a2 = h0, b8 = h1, c2 = h2, d2 = h3, e2 = h4;
15944
15944
  for (let t2 = 0; t2 < 80; t2++) {
15945
15945
  let f2, k2;
15946
15946
  if (t2 < 20) {
15947
- f2 = b7 & c2 | ~b7 & d2;
15947
+ f2 = b8 & c2 | ~b8 & d2;
15948
15948
  k2 = 1518500249;
15949
15949
  } else if (t2 < 40) {
15950
- f2 = b7 ^ c2 ^ d2;
15950
+ f2 = b8 ^ c2 ^ d2;
15951
15951
  k2 = 1859775393;
15952
15952
  } else if (t2 < 60) {
15953
- f2 = b7 & c2 | b7 & d2 | c2 & d2;
15953
+ f2 = b8 & c2 | b8 & d2 | c2 & d2;
15954
15954
  k2 = 2400959708;
15955
15955
  } else {
15956
- f2 = b7 ^ c2 ^ d2;
15956
+ f2 = b8 ^ c2 ^ d2;
15957
15957
  k2 = 3395469782;
15958
15958
  }
15959
15959
  const temp = rotl(a2, 5) + f2 + e2 + k2 + w2[t2] >>> 0;
15960
15960
  e2 = d2;
15961
15961
  d2 = c2;
15962
- c2 = rotl(b7, 30);
15963
- b7 = a2;
15962
+ c2 = rotl(b8, 30);
15963
+ b8 = a2;
15964
15964
  a2 = temp;
15965
15965
  }
15966
15966
  h0 = h0 + a2 >>> 0;
15967
- h1 = h1 + b7 >>> 0;
15967
+ h1 = h1 + b8 >>> 0;
15968
15968
  h2 = h2 + c2 >>> 0;
15969
15969
  h3 = h3 + d2 >>> 0;
15970
15970
  h4 = h4 + e2 >>> 0;
@@ -17513,7 +17513,7 @@ function Er(e2) {
17513
17513
  function Wr(e2, t2) {
17514
17514
  return Oe(e2._readableStreamController) ? (function(e3) {
17515
17515
  let t3, r2, o2, n2, i2, a2 = V(e3), s2 = false, l2 = false, d2 = false, f2 = false, h2 = false;
17516
- const b7 = u((e4) => {
17516
+ const b8 = u((e4) => {
17517
17517
  i2 = e4;
17518
17518
  });
17519
17519
  function m2(e4) {
@@ -17583,14 +17583,14 @@ function Wr(e2, t2) {
17583
17583
  const o4 = le([t3, r2]), n3 = Mr(e3, o4);
17584
17584
  i2(n3);
17585
17585
  }
17586
- return b7;
17586
+ return b8;
17587
17587
  }
17588
17588
  function R2(o3) {
17589
17589
  if (h2 = true, r2 = o3, f2) {
17590
17590
  const o4 = le([t3, r2]), n3 = Mr(e3, o4);
17591
17591
  i2(n3);
17592
17592
  }
17593
- return b7;
17593
+ return b8;
17594
17594
  }
17595
17595
  function T2() {
17596
17596
  }
@@ -17601,14 +17601,14 @@ function Wr(e2, t2) {
17601
17601
  const h2 = u((e4) => {
17602
17602
  a2 = e4;
17603
17603
  });
17604
- function b7() {
17604
+ function b8() {
17605
17605
  if (s2) return l2 = true, c(void 0);
17606
17606
  s2 = true;
17607
17607
  return te(t3, { _chunkSteps: (e4) => {
17608
17608
  y(() => {
17609
17609
  l2 = false;
17610
17610
  const t4 = e4, r3 = e4;
17611
- d2 || Rr(n2._readableStreamController, t4), f2 || Rr(i2._readableStreamController, r3), s2 = false, l2 && b7();
17611
+ d2 || Rr(n2._readableStreamController, t4), f2 || Rr(i2._readableStreamController, r3), s2 = false, l2 && b8();
17612
17612
  });
17613
17613
  }, _closeSteps: () => {
17614
17614
  s2 = false, d2 || wr(n2._readableStreamController), f2 || wr(i2._readableStreamController), d2 && f2 || a2(void 0);
@@ -17632,7 +17632,7 @@ function Wr(e2, t2) {
17632
17632
  }
17633
17633
  function S2() {
17634
17634
  }
17635
- return n2 = Dr(S2, b7, m2), i2 = Dr(S2, b7, p2), _(t3._closedPromise, (e4) => (Tr(n2._readableStreamController, e4), Tr(i2._readableStreamController, e4), d2 && f2 || a2(void 0), null)), [n2, i2];
17635
+ return n2 = Dr(S2, b8, m2), i2 = Dr(S2, b8, p2), _(t3._closedPromise, (e4) => (Tr(n2._readableStreamController, e4), Tr(i2._readableStreamController, e4), d2 && f2 || a2(void 0), null)), [n2, i2];
17636
17636
  })(e2);
17637
17637
  }
17638
17638
  function Or(r2) {
@@ -17941,7 +17941,7 @@ var TransformStream = class {
17941
17941
  if (void 0 !== i2.readableType) throw new RangeError("Invalid readableType specified");
17942
17942
  if (void 0 !== i2.writableType) throw new RangeError("Invalid writableType specified");
17943
17943
  const a2 = mt(n2, 0), s2 = pt(n2), l2 = mt(o2, 1), f2 = pt(o2);
17944
- let b7;
17944
+ let b8;
17945
17945
  !(function(e3, t3, r3, o3, n3, i3) {
17946
17946
  function a3() {
17947
17947
  return t3;
@@ -18005,7 +18005,7 @@ var TransformStream = class {
18005
18005
  return Ct(a4), Nt(a4, Object.create(WritableStreamDefaultController.prototype), e4, t4, r4, o4, n4, i4), a4;
18006
18006
  })(a3, s3, c2, l3, r3, o3), e3._readable = Dr(a3, d2, f3, n3, i3), e3._backpressure = void 0, e3._backpressureChangePromise = void 0, e3._backpressureChangePromise_resolve = void 0, ao(e3, true), e3._transformStreamController = void 0;
18007
18007
  })(this, u((e3) => {
18008
- b7 = e3;
18008
+ b8 = e3;
18009
18009
  }), l2, f2, a2, s2), (function(e3, t3) {
18010
18010
  const r3 = Object.create(TransformStreamDefaultController.prototype);
18011
18011
  let o3, n3, i3;
@@ -18021,7 +18021,7 @@ var TransformStream = class {
18021
18021
  !(function(e4, t4, r4, o4, n4) {
18022
18022
  t4._controlledTransformStream = e4, e4._transformStreamController = t4, t4._transformAlgorithm = r4, t4._flushAlgorithm = o4, t4._cancelAlgorithm = n4, t4._finishPromise = void 0, t4._finishPromise_resolve = void 0, t4._finishPromise_reject = void 0;
18023
18023
  })(e3, r3, o3, n3, i3);
18024
- })(this, i2), void 0 !== i2.start ? b7(i2.start(this._transformStreamController)) : b7(void 0);
18024
+ })(this, i2), void 0 !== i2.start ? b8(i2.start(this._transformStreamController)) : b8(void 0);
18025
18025
  }
18026
18026
  get readable() {
18027
18027
  if (!ro(this)) throw _o("readable");
@@ -19044,10 +19044,10 @@ async function sendResponse(c2, method, res) {
19044
19044
  await writeStreamingBody(c2, res.body, chunked, chunked && trailerDeclared ? res.trailers : void 0);
19045
19045
  }
19046
19046
 
19047
- // _build/examples/exec_server.js
19048
- import * as os6 from "os";
19047
+ // _build/examples/execd/main.js
19048
+ import * as os7 from "os";
19049
19049
  import * as std2 from "std";
19050
- import * as gui18 from "gui";
19050
+ import * as gui19 from "gui";
19051
19051
 
19052
19052
  // _build/lib/exec-log.js
19053
19053
  var RequestLog = class {
@@ -19466,6 +19466,75 @@ function bind2(dll, name, sig, encoders, decoders) {
19466
19466
  var leakRegistry = new FinalizationRegistry((held) => {
19467
19467
  std.printf('[ffi] closure leaked (GCed without dispose): sig="%s" ptr=0x%x\n', held.sig, held.ptr);
19468
19468
  });
19469
+ function dispatchClosure(args, ret, fn, frameBuf, retBuf, sig) {
19470
+ const dv = new DataView(retBuf);
19471
+ const is64 = os3.arch === "x64";
19472
+ const fv = new DataView(frameBuf);
19473
+ const a2 = [];
19474
+ let off = 0;
19475
+ for (let i2 = 0; i2 < args.length; i2++) {
19476
+ const spec = args[i2];
19477
+ const k2 = spec.tok;
19478
+ let v2;
19479
+ if (is64) {
19480
+ const fp = k2 === "f32" || k2 === "f64";
19481
+ const base = fp ? i2 < 4 ? 128 + i2 * 8 : 32 + (i2 - 4) * 8 : i2 < 4 ? i2 * 8 : 32 + (i2 - 4) * 8;
19482
+ v2 = readScalar(fv, base, k2);
19483
+ } else {
19484
+ v2 = readScalar(fv, off, k2);
19485
+ off += IA32_ARG_SIZE[k2];
19486
+ }
19487
+ if (spec.nonnull && v2 === 0) {
19488
+ std.printf("[ffi] closure %s: arg#%d got 0 (! promise violated by caller), skipping callback\n", sig, i2 + 1);
19489
+ return;
19490
+ }
19491
+ a2.push(v2);
19492
+ }
19493
+ let r2;
19494
+ try {
19495
+ r2 = fn(...a2);
19496
+ } catch (err) {
19497
+ std.printf("[ffi] closure callback threw: %s\n", String(err));
19498
+ return;
19499
+ }
19500
+ if (ret.nonnull && r2 === 0) {
19501
+ std.printf("[ffi] closure %s: return got 0 (! promise violated by callback), leaving result slot 0\n", sig);
19502
+ return;
19503
+ }
19504
+ if (ret.tok !== "void") {
19505
+ writeSlot(dv, 0, { k: ret.tok, v: r2 });
19506
+ }
19507
+ }
19508
+ function closure(sig, fn, opts) {
19509
+ const { argTokens, retToken } = parseSig(sig);
19510
+ for (const t2 of argTokens)
19511
+ if (isCValToken(t2))
19512
+ throw new Error(`ffi-bind: closure signature cannot take a by-value struct (<${valName(t2)}>); by-value is bind-only \u2014 the C\u2192JS direction has no struct slot decoding (pass a pointer and decode on the JS side)`);
19513
+ const argSpecs = argTokens.map((t2) => ({ tok: cTokenToType(t2), nonnull: t2.endsWith("!") }));
19514
+ const retSpec = { tok: cTokenToType(retToken), nonnull: retToken.endsWith("!") };
19515
+ const is64 = os3.arch === "x64";
19516
+ const stackCapture = argSpecs.reduce((s2, x2) => s2 + IA32_ARG_SIZE[x2.tok], 0);
19517
+ if (is64 ? argSpecs.length > 16 : stackCapture > 64) {
19518
+ throw new Error(`ffi-bind: closure signature exceeds capture window (${is64 ? "max 16 params" : "max 64 stack bytes"}): ${sig}`);
19519
+ }
19520
+ const argBytes = opts?.stdcall === false || is64 ? 0 : stackCapture;
19521
+ const retKind = retSpec.tok === "f32" ? 1 : retSpec.tok === "f64" ? 2 : retSpec.tok === "u64" || retSpec.tok === "i64" ? 3 : 0;
19522
+ const wrapper = (frameBuf, retBuf) => {
19523
+ dispatchClosure(argSpecs, retSpec, fn, frameBuf, retBuf, sig);
19524
+ };
19525
+ const ptr = ffi.closureNew(argBytes, retKind, wrapper);
19526
+ let done = false;
19527
+ const dispose = () => {
19528
+ if (done)
19529
+ return;
19530
+ done = true;
19531
+ leakRegistry.unregister(dispose);
19532
+ ffi.closureFree(ptr);
19533
+ };
19534
+ const ret = { ptr, dispose };
19535
+ leakRegistry.register(dispose, { sig, ptr });
19536
+ return ret;
19537
+ }
19469
19538
 
19470
19539
  // _build/lib/ffi/struct.js
19471
19540
  import * as ffi2 from "ffi";
@@ -19497,13 +19566,13 @@ function lower(v2) {
19497
19566
  type: { tag: "array", elementType: el.type, elementSize: el.size }
19498
19567
  };
19499
19568
  }
19500
- const b7 = /^([A-Za-z_]\w*):(\d+)$/.exec(v2);
19501
- if (b7) {
19502
- const rawUnit = b7[1];
19569
+ const b8 = /^([A-Za-z_]\w*):(\d+)$/.exec(v2);
19570
+ if (b8) {
19571
+ const rawUnit = b8[1];
19503
19572
  const unit = normToken(rawUnit);
19504
19573
  if (!isCNumberToken(unit) || unit === "f32" || unit === "f64")
19505
19574
  throw new Error(`ffi-struct: bitfield unit must be an integer type, got "${rawUnit}"`);
19506
- const width = Number(b7[2]);
19575
+ const width = Number(b8[2]);
19507
19576
  const s3 = SizeAlign[unit];
19508
19577
  const cap = s3 * 8;
19509
19578
  if (!Number.isInteger(width) || width < 1)
@@ -19774,7 +19843,7 @@ function doEncode(dv, base, fields, v2) {
19774
19843
  function createStruct(t2) {
19775
19844
  const { fields, size, maxEffectiveAlign } = computeStructLayout(t2);
19776
19845
  return {
19777
- __struct: t2,
19846
+ fields,
19778
19847
  size,
19779
19848
  structAlign: maxEffectiveAlign,
19780
19849
  decode: (p2) => {
@@ -19803,6 +19872,14 @@ function createStruct(t2) {
19803
19872
  };
19804
19873
  }
19805
19874
  function buildDecl(kind, member, pack) {
19875
+ const declKind = member["#"];
19876
+ if (declKind !== void 0 && declKind !== kind)
19877
+ throw new Error(`ffi-struct: ${kind}() received a '${String(declKind)}' declaration (kind mismatch \u2014 use ${declKind}() for it)`);
19878
+ const declPack = member["#pack"];
19879
+ if (pack === void 0 && declPack !== void 0)
19880
+ pack = declPack;
19881
+ else if (pack !== void 0 && declPack !== void 0 && pack !== declPack)
19882
+ throw new Error(`ffi-struct: #pack conflict: opts.pack=${pack} vs declaration ${String(declPack)}`);
19806
19883
  const decl = { "#": kind };
19807
19884
  if (pack !== void 0)
19808
19885
  decl["#pack"] = pack;
@@ -19812,7 +19889,7 @@ function buildDecl(kind, member, pack) {
19812
19889
  return decl;
19813
19890
  }
19814
19891
  function structArray(def) {
19815
- const { fields, size } = computeStructLayout(def.__struct);
19892
+ const { fields, size } = def;
19816
19893
  const readN = (dv, n2) => {
19817
19894
  const out = [];
19818
19895
  for (let i2 = 0; i2 < n2; i2++)
@@ -19854,29 +19931,36 @@ function structArray(def) {
19854
19931
  })
19855
19932
  };
19856
19933
  }
19857
- function struct(a2, b7, c2) {
19934
+ function struct(a2, b8, c2) {
19858
19935
  const isNamed = typeof a2 === "string";
19859
- const raw = isNamed ? b7 : a2;
19860
- const opts = isNamed ? c2 : b7;
19936
+ const raw = isNamed ? b8 : a2;
19937
+ const opts = isNamed ? c2 : b8;
19861
19938
  return createStruct(buildDecl("struct", raw, opts?.pack));
19862
19939
  }
19863
19940
 
19864
19941
  // _build/lib/windows/structs.js
19865
- var RECT = /* @__PURE__ */ struct("RECT", {
19942
+ var RECT_DECL = {
19943
+ "#": "struct",
19866
19944
  left: "i32",
19867
19945
  top: "i32",
19868
19946
  right: "i32",
19869
19947
  bottom: "i32"
19870
- });
19871
- var POINT = /* @__PURE__ */ struct("POINT", {
19948
+ };
19949
+ var RECT = /* @__PURE__ */ struct("RECT", RECT_DECL);
19950
+ var POINT_DECL = {
19951
+ "#": "struct",
19872
19952
  x: "i32",
19873
19953
  y: "i32"
19874
- });
19875
- var SIZE = /* @__PURE__ */ struct("SIZE", {
19954
+ };
19955
+ var POINT = /* @__PURE__ */ struct("POINT", POINT_DECL);
19956
+ var SIZE_DECL = {
19957
+ "#": "struct",
19876
19958
  cx: "i32",
19877
19959
  cy: "i32"
19878
- });
19879
- var LOGFONTW = /* @__PURE__ */ struct("LOGFONTW", {
19960
+ };
19961
+ var SIZE = /* @__PURE__ */ struct("SIZE", SIZE_DECL);
19962
+ var LOGFONTW_DECL = {
19963
+ "#": "struct",
19880
19964
  lfHeight: "i32",
19881
19965
  lfWidth: "i32",
19882
19966
  lfEscapement: "i32",
@@ -19891,8 +19975,35 @@ var LOGFONTW = /* @__PURE__ */ struct("LOGFONTW", {
19891
19975
  lfQuality: "u8",
19892
19976
  lfPitchAndFamily: "u8",
19893
19977
  lfFaceName: "u16[32]@utf-16le"
19894
- });
19895
- var OPENFILENAMEW = /* @__PURE__ */ struct("OPENFILENAMEW", {
19978
+ };
19979
+ var LOGFONTW = /* @__PURE__ */ struct("LOGFONTW", LOGFONTW_DECL);
19980
+ var BITMAPINFOHEADER_DECL = {
19981
+ "#": "struct",
19982
+ biSize: "u32",
19983
+ biWidth: "i32",
19984
+ biHeight: "i32",
19985
+ biPlanes: "u16",
19986
+ biBitCount: "u16",
19987
+ biCompression: "u32",
19988
+ biSizeImage: "u32",
19989
+ biXPelsPerMeter: "i32",
19990
+ biYPelsPerMeter: "i32",
19991
+ biClrUsed: "u32",
19992
+ biClrImportant: "u32"
19993
+ };
19994
+ var BITMAPINFOHEADER = /* @__PURE__ */ struct("BITMAPINFOHEADER", BITMAPINFOHEADER_DECL);
19995
+ var BITMAPFILEHEADER_DECL = {
19996
+ "#": "struct",
19997
+ "#pack": 2,
19998
+ bfType: "u16",
19999
+ bfSize: "u32",
20000
+ bfReserved1: "u16",
20001
+ bfReserved2: "u16",
20002
+ bfOffBits: "u32"
20003
+ };
20004
+ var BITMAPFILEHEADER = /* @__PURE__ */ struct("BITMAPFILEHEADER", BITMAPFILEHEADER_DECL);
20005
+ var OPENFILENAMEW_DECL = {
20006
+ "#": "struct",
19896
20007
  lStructSize: "u32",
19897
20008
  hwndOwner: "<HWND>ptr",
19898
20009
  hInstance: "<HMODULE>ptr",
@@ -19916,8 +20027,10 @@ var OPENFILENAMEW = /* @__PURE__ */ struct("OPENFILENAMEW", {
19916
20027
  pvReserved: "<>ptr",
19917
20028
  dwReserved: "u32",
19918
20029
  FlagsEx: "u32"
19919
- });
19920
- var BROWSEINFOW = /* @__PURE__ */ struct("BROWSEINFOW", {
20030
+ };
20031
+ var OPENFILENAMEW = /* @__PURE__ */ struct("OPENFILENAMEW", OPENFILENAMEW_DECL);
20032
+ var BROWSEINFOW_DECL = {
20033
+ "#": "struct",
19921
20034
  hwndOwner: "<HWND>ptr",
19922
20035
  pidlRoot: "<>ptr",
19923
20036
  pszDisplayName: "<>ptr",
@@ -19926,13 +20039,17 @@ var BROWSEINFOW = /* @__PURE__ */ struct("BROWSEINFOW", {
19926
20039
  lpfn: "<>ptr",
19927
20040
  lParam: "<>ptr",
19928
20041
  iImage: "i32"
19929
- });
19930
- var NMHDR = /* @__PURE__ */ struct("NMHDR", {
20042
+ };
20043
+ var BROWSEINFOW = /* @__PURE__ */ struct("BROWSEINFOW", BROWSEINFOW_DECL);
20044
+ var NMHDR_DECL = {
20045
+ "#": "struct",
19931
20046
  hwndFrom: "<HWND>ptr",
19932
20047
  idFrom: "<>ptr",
19933
20048
  code: "i32"
19934
- });
19935
- var SYSTEMTIME = /* @__PURE__ */ struct("SYSTEMTIME", {
20049
+ };
20050
+ var NMHDR = /* @__PURE__ */ struct("NMHDR", NMHDR_DECL);
20051
+ var SYSTEMTIME_DECL = {
20052
+ "#": "struct",
19936
20053
  wYear: "u16",
19937
20054
  wMonth: "u16",
19938
20055
  wDayOfWeek: "u16",
@@ -19941,35 +20058,44 @@ var SYSTEMTIME = /* @__PURE__ */ struct("SYSTEMTIME", {
19941
20058
  wMinute: "u16",
19942
20059
  wSecond: "u16",
19943
20060
  wMilliseconds: "u16"
19944
- });
19945
- var NMDATETIMECHANGE = /* @__PURE__ */ struct("NMDATETIMECHANGE", {
19946
- hdr: NMHDR.__struct,
20061
+ };
20062
+ var SYSTEMTIME = /* @__PURE__ */ struct("SYSTEMTIME", SYSTEMTIME_DECL);
20063
+ var NMDATETIMECHANGE_DECL = {
20064
+ "#": "struct",
20065
+ hdr: NMHDR_DECL,
19947
20066
  dwFlags: "u32",
19948
- st: SYSTEMTIME.__struct
19949
- });
19950
- var LITEM = /* @__PURE__ */ struct("LITEM", {
20067
+ st: SYSTEMTIME_DECL
20068
+ };
20069
+ var NMDATETIMECHANGE = /* @__PURE__ */ struct("NMDATETIMECHANGE", NMDATETIMECHANGE_DECL);
20070
+ var LITEM_DECL = {
20071
+ "#": "struct",
19951
20072
  mask: "u32",
19952
20073
  iLink: "i32",
19953
20074
  state: "u32",
19954
20075
  stateMask: "u32",
19955
20076
  szID: "u16[48]@utf-16le",
19956
20077
  szUrl: "u16[2084]@utf-16le"
19957
- });
19958
- var NMLINK = /* @__PURE__ */ struct("NMLINK", {
19959
- hdr: NMHDR.__struct,
19960
- item: LITEM.__struct
19961
- });
19962
- var NMCUSTOMDRAW = /* @__PURE__ */ struct("NMCUSTOMDRAW", {
19963
- hdr: NMHDR.__struct,
20078
+ };
20079
+ var NMLINK_DECL = {
20080
+ "#": "struct",
20081
+ hdr: NMHDR_DECL,
20082
+ item: LITEM_DECL
20083
+ };
20084
+ var NMLINK = /* @__PURE__ */ struct("NMLINK", NMLINK_DECL);
20085
+ var NMCUSTOMDRAW_DECL = {
20086
+ "#": "struct",
20087
+ hdr: NMHDR_DECL,
19964
20088
  dwDrawStage: "u32",
19965
20089
  hdc: "<HDC>ptr",
19966
20090
  rc: "i32[4]",
19967
20091
  dwItemSpec: "<>ptr",
19968
20092
  uItemState: "u32",
19969
20093
  lItemlParam: "<>ptr"
19970
- });
19971
- var NMLVCUSTOMDRAW = /* @__PURE__ */ struct("NMLVCUSTOMDRAW", {
19972
- hdr: NMHDR.__struct,
20094
+ };
20095
+ var NMCUSTOMDRAW = /* @__PURE__ */ struct("NMCUSTOMDRAW", NMCUSTOMDRAW_DECL);
20096
+ var NMLVCUSTOMDRAW_DECL = {
20097
+ "#": "struct",
20098
+ hdr: NMHDR_DECL,
19973
20099
  dwDrawStage: "u32",
19974
20100
  hdc: "<HDC>ptr",
19975
20101
  rc: "i32[4]",
@@ -19980,9 +20106,11 @@ var NMLVCUSTOMDRAW = /* @__PURE__ */ struct("NMLVCUSTOMDRAW", {
19980
20106
  clrTextBk: "u32",
19981
20107
  iSubItem: "i32",
19982
20108
  dwItemType: "u32"
19983
- });
19984
- var NMLISTVIEW = /* @__PURE__ */ struct("NMLISTVIEW", {
19985
- hdr: NMHDR.__struct,
20109
+ };
20110
+ var NMLVCUSTOMDRAW = /* @__PURE__ */ struct("NMLVCUSTOMDRAW", NMLVCUSTOMDRAW_DECL);
20111
+ var NMLISTVIEW_DECL = {
20112
+ "#": "struct",
20113
+ hdr: NMHDR_DECL,
19986
20114
  iItem: "i32",
19987
20115
  iSubItem: "i32",
19988
20116
  uNewState: "u32",
@@ -19990,8 +20118,10 @@ var NMLISTVIEW = /* @__PURE__ */ struct("NMLISTVIEW", {
19990
20118
  uChanged: "u32",
19991
20119
  ptAction: "i32[2]",
19992
20120
  lParam: "<>ptr"
19993
- });
19994
- var TCITEMW = /* @__PURE__ */ struct("TCITEMW", {
20121
+ };
20122
+ var NMLISTVIEW = /* @__PURE__ */ struct("NMLISTVIEW", NMLISTVIEW_DECL);
20123
+ var TCITEMW_DECL = {
20124
+ "#": "struct",
19995
20125
  mask: "u32",
19996
20126
  dwState: "u32",
19997
20127
  dwStateMask: "u32",
@@ -19999,8 +20129,10 @@ var TCITEMW = /* @__PURE__ */ struct("TCITEMW", {
19999
20129
  cchTextMax: "i32",
20000
20130
  iImage: "i32",
20001
20131
  lParam: "<>ptr"
20002
- });
20003
- var TVITEM = /* @__PURE__ */ struct("TVITEM", {
20132
+ };
20133
+ var TCITEMW = /* @__PURE__ */ struct("TCITEMW", TCITEMW_DECL);
20134
+ var TVITEM_DECL = {
20135
+ "#": "struct",
20004
20136
  mask: "u32",
20005
20137
  hItem: "<>ptr",
20006
20138
  state: "u32",
@@ -20011,20 +20143,26 @@ var TVITEM = /* @__PURE__ */ struct("TVITEM", {
20011
20143
  iSelectedImage: "i32",
20012
20144
  cChildren: "i32",
20013
20145
  lParam: "<>ptr"
20014
- });
20015
- var TVINSERTSTRUCT = /* @__PURE__ */ struct("TVINSERTSTRUCT", {
20146
+ };
20147
+ var TVITEM = /* @__PURE__ */ struct("TVITEM", TVITEM_DECL);
20148
+ var TVINSERTSTRUCT_DECL = {
20149
+ "#": "struct",
20016
20150
  hParent: "<>ptr",
20017
20151
  hInsertAfter: "<>ptr",
20018
- item: TVITEM.__struct
20019
- });
20020
- var LVHITTESTINFO = /* @__PURE__ */ struct("LVHITTESTINFO", {
20152
+ item: TVITEM_DECL
20153
+ };
20154
+ var TVINSERTSTRUCT = /* @__PURE__ */ struct("TVINSERTSTRUCT", TVINSERTSTRUCT_DECL);
20155
+ var LVHITTESTINFO_DECL = {
20156
+ "#": "struct",
20021
20157
  pt: "i32[2]",
20022
20158
  flags: "u32",
20023
20159
  iItem: "i32",
20024
20160
  iSubItem: "i32",
20025
20161
  iGroup: "i32"
20026
- });
20027
- var LVITEMW = /* @__PURE__ */ struct("LVITEMW", {
20162
+ };
20163
+ var LVHITTESTINFO = /* @__PURE__ */ struct("LVHITTESTINFO", LVHITTESTINFO_DECL);
20164
+ var LVITEMW_DECL = {
20165
+ "#": "struct",
20028
20166
  mask: "u32",
20029
20167
  iItem: "i32",
20030
20168
  iSubItem: "i32",
@@ -20040,8 +20178,10 @@ var LVITEMW = /* @__PURE__ */ struct("LVITEMW", {
20040
20178
  puColumns: "<>ptr",
20041
20179
  piColFmt: "<>ptr",
20042
20180
  iGroup: "i32"
20043
- });
20044
- var LVCOLUMNW = /* @__PURE__ */ struct("LVCOLUMNW", {
20181
+ };
20182
+ var LVITEMW = /* @__PURE__ */ struct("LVITEMW", LVITEMW_DECL);
20183
+ var LVCOLUMNW_DECL = {
20184
+ "#": "struct",
20045
20185
  mask: "u32",
20046
20186
  fmt: "i32",
20047
20187
  cx: "i32",
@@ -20053,46 +20193,116 @@ var LVCOLUMNW = /* @__PURE__ */ struct("LVCOLUMNW", {
20053
20193
  cxMin: "i32",
20054
20194
  cxDefault: "i32",
20055
20195
  cxIdeal: "i32"
20056
- });
20057
- var MSG = /* @__PURE__ */ struct("MSG", {
20058
- hwnd: "<HWND>ptr",
20059
- message: "u32",
20060
- wParam: "<>ptr",
20061
- lParam: "<>ptr",
20196
+ };
20197
+ var LVCOLUMNW = /* @__PURE__ */ struct("LVCOLUMNW", LVCOLUMNW_DECL);
20198
+ var DEVMODEW_DECL = {
20199
+ "#": "struct",
20200
+ dmDeviceName: "u16[32]@utf-16le",
20201
+ dmSpecVersion: "u16",
20202
+ dmDriverVersion: "u16",
20203
+ dmSize: "u16",
20204
+ dmDriverExtra: "u16",
20205
+ dmFields: "u32",
20206
+ dmPosition: "i32[2]",
20207
+ dmDisplayOrientation: "u32",
20208
+ dmDisplayFixedOutput: "u32",
20209
+ dmColor: "i16",
20210
+ dmDuplex: "i16",
20211
+ dmYResolution: "i16",
20212
+ dmTTOption: "i16",
20213
+ dmCollate: "i16",
20214
+ dmFormName: "u16[32]@utf-16le",
20215
+ dmLogPixels: "u16",
20216
+ dmBitsPerPel: "u32",
20217
+ dmPelsWidth: "u32",
20218
+ dmPelsHeight: "u32",
20219
+ dmDisplayFlags: "u32",
20220
+ dmDisplayFrequency: "u32",
20221
+ dmICMMethod: "u32",
20222
+ dmICMIntent: "u32",
20223
+ dmMediaType: "u32",
20224
+ dmDitherType: "u32",
20225
+ dmReserved1: "u32",
20226
+ dmReserved2: "u32",
20227
+ dmPanningWidth: "u32",
20228
+ dmPanningHeight: "u32"
20229
+ };
20230
+ var DEVMODEW = /* @__PURE__ */ struct("DEVMODEW", DEVMODEW_DECL);
20231
+ var MOUSEINPUT_DECL = {
20232
+ "#": "struct",
20233
+ dx: "i32",
20234
+ dy: "i32",
20235
+ mouseData: "u32",
20236
+ dwFlags: "u32",
20062
20237
  time: "u32",
20063
- pt: POINT.__struct
20064
- });
20065
- var PAINTSTRUCT = /* @__PURE__ */ struct("PAINTSTRUCT", {
20066
- hdc: "<HDC>ptr",
20067
- fErase: "i32",
20068
- rcPaint: RECT.__struct,
20069
- fRestore: "i32",
20070
- fIncUpdate: "i32",
20071
- rgbReserved: "u8[32]"
20072
- });
20238
+ dwExtraInfo: "<>ptr"
20239
+ };
20240
+ var KEYBDINPUT_DECL = {
20241
+ "#": "struct",
20242
+ wVk: "u16",
20243
+ wScan: "u16",
20244
+ dwFlags: "u32",
20245
+ time: "u32",
20246
+ dwExtraInfo: "<>ptr"
20247
+ };
20248
+ var INPUT_DECL = {
20249
+ "#": "struct",
20250
+ type: "u32",
20251
+ data: {
20252
+ "#": "union",
20253
+ mi: MOUSEINPUT_DECL,
20254
+ ki: KEYBDINPUT_DECL
20255
+ }
20256
+ };
20257
+ var INPUT = /* @__PURE__ */ struct("INPUT", INPUT_DECL);
20258
+ var NOTIFYICONIDENTIFIER_DECL = {
20259
+ "#": "struct",
20260
+ cbSize: "u32",
20261
+ hWnd: "<HWND>ptr",
20262
+ uID: "u32",
20263
+ guidItem: "u32[4]"
20264
+ };
20265
+ var NOTIFYICONIDENTIFIER = /* @__PURE__ */ struct("NOTIFYICONIDENTIFIER", NOTIFYICONIDENTIFIER_DECL);
20073
20266
 
20074
20267
  // _build/lib/windows/user32.js
20075
20268
  var b2 = (name, sig, encoders) => bind2("user32.dll", name, sig, encoders);
20076
20269
  var _bProbe = b2("GetDesktopWindow", " -> <HWND>ptr");
20077
20270
  var LONG_PTR_SYM = os4.arch === "x64" ? "PtrW" : "W";
20078
20271
  var SetWindowPos = /* @__PURE__ */ b2("SetWindowPos", "<HWND>ptr <>ptr@SetWindowPosHwnd i32 i32 i32 i32 u32 -> i32");
20272
+ var GetWindowRect = /* @__PURE__ */ b2("GetWindowRect", "<HWND>ptr <RECT>ptr -> i32");
20273
+ var GetClientRect = /* @__PURE__ */ b2("GetClientRect", "<HWND>ptr <RECT>ptr -> i32");
20274
+ var IsWindow = /* @__PURE__ */ b2("IsWindow", "<HWND>ptr -> i32");
20275
+ var IsWindowVisible = /* @__PURE__ */ b2("IsWindowVisible", "<HWND>ptr -> i32");
20276
+ var IsIconic = /* @__PURE__ */ b2("IsIconic", "<HWND>ptr -> i32");
20277
+ var FindWindow = /* @__PURE__ */ b2("FindWindowW", "<WCHAR>ptr <WCHAR>ptr -> <HWND>ptr");
20278
+ var FindWindowEx = /* @__PURE__ */ b2("FindWindowExW", "<HWND>ptr <HWND>ptr <WCHAR>ptr <WCHAR>ptr -> <HWND>ptr");
20279
+ var GetWindowText = /* @__PURE__ */ b2("GetWindowTextW", "<HWND>ptr <BYTE>ptr i32 -> i32");
20079
20280
  var SetWindowText = /* @__PURE__ */ b2("SetWindowTextW", "<HWND>ptr <WCHAR>ptr -> i32");
20281
+ var GetClassName = /* @__PURE__ */ b2("GetClassNameW", "<HWND>ptr <BYTE>ptr i32 -> i32");
20080
20282
  var GetWindowLongPtr = /* @__PURE__ */ b2("GetWindowLong" + LONG_PTR_SYM, "<HWND>ptr i32@Gwlp -> <>ptr");
20081
20283
  var SetWindowLongPtr = /* @__PURE__ */ b2("SetWindowLong" + LONG_PTR_SYM, "<HWND>ptr i32@Gwlp <>ptr -> <>ptr");
20284
+ var GetWindowThreadProcessId = /* @__PURE__ */ b2("GetWindowThreadProcessId", "<HWND>ptr <BYTE>ptr -> u32");
20082
20285
  var EnableWindow = /* @__PURE__ */ b2("EnableWindow", "<HWND>ptr i32 -> i32");
20083
20286
  var SetParent = /* @__PURE__ */ b2("SetParent", "<HWND>ptr <HWND>ptr -> <HWND>ptr");
20084
20287
  var DefWindowProc = /* @__PURE__ */ b2("DefWindowProcW", "<HWND>ptr u32@AnyMsg <>ptr <>ptr -> <>ptr");
20085
20288
  var CallWindowProc = /* @__PURE__ */ b2("CallWindowProcW", "<>ptr <HWND>ptr u32@AnyMsg <>ptr <>ptr -> <>ptr");
20086
20289
  var GetDC = /* @__PURE__ */ b2("GetDC", "<HWND>ptr -> <HDC>ptr");
20087
20290
  var ReleaseDC = /* @__PURE__ */ b2("ReleaseDC", "<HWND>ptr <HDC>ptr! -> i32");
20291
+ var PrintWindow = /* @__PURE__ */ b2("PrintWindow", "<HWND>ptr <HDC>ptr! u32 -> i32");
20088
20292
  var DrawText = /* @__PURE__ */ b2("DrawTextW", "<HDC>ptr! <WCHAR>ptr i32 <RECT>ptr i32 -> i32");
20089
20293
  var InvalidateRect = /* @__PURE__ */ b2("InvalidateRect", "<HWND>ptr <RECT>ptr i32 -> i32", { RECT });
20090
20294
  var SetCursor = /* @__PURE__ */ b2("SetCursor", "<HCURSOR>ptr -> <HCURSOR>ptr");
20091
20295
  var LoadCursor = /* @__PURE__ */ b2("LoadCursorW", "<HMODULE>ptr <>ptr -> <HCURSOR>ptr");
20092
20296
  var GetCursorPos = /* @__PURE__ */ b2("GetCursorPos", "<POINT>ptr -> i32");
20093
20297
  var ScreenToClient = /* @__PURE__ */ b2("ScreenToClient", "<HWND>ptr <POINT>ptr -> i32");
20298
+ var ClientToScreen = /* @__PURE__ */ b2("ClientToScreen", "<HWND>ptr <POINT>ptr -> i32");
20299
+ var INPUTArr = /* @__PURE__ */ structArray(INPUT);
20300
+ var SendInput = /* @__PURE__ */ b2("SendInput", "u32 <INPUT>ptr i32 -> u32", { INPUT: INPUTArr });
20094
20301
  var ShowScrollBar = /* @__PURE__ */ b2("ShowScrollBar", "<HWND>ptr u32 i32 -> i32");
20095
20302
  var GetSystemMetrics = /* @__PURE__ */ b2("GetSystemMetrics", "i32 -> i32");
20303
+ var EnumWindows = /* @__PURE__ */ b2("EnumWindows", "<>ptr <>ptr -> i32");
20304
+ var EnumDisplaySettings = /* @__PURE__ */ b2("EnumDisplaySettingsW", "<WCHAR>ptr u32 <DEVMODEW>ptr -> i32");
20305
+ var ChangeDisplaySettings = /* @__PURE__ */ b2("ChangeDisplaySettingsW", "<DEVMODEW>ptr u32 -> i32");
20096
20306
 
20097
20307
  // _build/lib/react-qw/reconciler.js
20098
20308
  var import_react_reconciler = __toESM(require_react_reconciler(), 1);
@@ -20103,12 +20313,16 @@ import * as os5 from "os";
20103
20313
 
20104
20314
  // _build/lib/windows/gdi32.js
20105
20315
  var b3 = (name, sig, encoders) => bind2("gdi32.dll", name, sig, encoders);
20106
- var POINTArr = structArray(POINT);
20107
20316
  var DeleteObject = /* @__PURE__ */ b3("DeleteObject", "<HGDIOBJ>ptr -> i32");
20108
20317
  var GetDeviceCaps = /* @__PURE__ */ b3("GetDeviceCaps", "<HDC>ptr! i32@DeviceCap -> i32");
20109
20318
  var CreateFontIndirect = /* @__PURE__ */ b3("CreateFontIndirectW", "<LOGFONTW>ptr -> <HGDIOBJ>ptr", { LOGFONTW });
20319
+ var CreateCompatibleDC = /* @__PURE__ */ b3("CreateCompatibleDC", "<HDC>ptr -> <HDC>ptr");
20320
+ var CreateCompatibleBitmap = /* @__PURE__ */ b3("CreateCompatibleBitmap", "<HDC>ptr! i32 i32 -> <HGDIOBJ>ptr");
20110
20321
  var SelectObject = /* @__PURE__ */ b3("SelectObject", "<HDC>ptr! <HGDIOBJ>ptr -> <HGDIOBJ>ptr");
20322
+ var BitBlt = /* @__PURE__ */ b3("BitBlt", "<HDC>ptr! i32 i32 i32 i32 <HDC>ptr i32 i32 u32@RasterOp -> i32");
20323
+ var GetDIBits = /* @__PURE__ */ b3("GetDIBits", "<HDC>ptr! <HGDIOBJ>ptr u32 u32 <BYTE>ptr <>ptr u32 -> i32");
20111
20324
  var GetObject = /* @__PURE__ */ b3("GetObjectW", "<HGDIOBJ>ptr i32 <BYTE>ptr -> i32");
20325
+ var DeleteDC = /* @__PURE__ */ b3("DeleteDC", "<HDC>ptr! -> i32");
20112
20326
 
20113
20327
  // _build/lib/react-qw/props.js
20114
20328
  import * as gui from "gui";
@@ -20136,14 +20350,14 @@ function applyProps(instance, newProps, _oldProps) {
20136
20350
  gui.ShowWindow(
20137
20351
  hwnd,
20138
20352
  newProps.hidden ? 0 : 5
20139
- /* gui.ShowWindowCmd.SHOW */
20353
+ /* ShowWindowCmd.SHOW */
20140
20354
  );
20141
20355
  }
20142
20356
  if ("visible" in newProps) {
20143
20357
  gui.ShowWindow(
20144
20358
  hwnd,
20145
20359
  newProps.visible ? 5 : 0
20146
- /* gui.ShowWindowCmd.HIDE */
20360
+ /* ShowWindowCmd.HIDE */
20147
20361
  );
20148
20362
  }
20149
20363
  }
@@ -20239,7 +20453,7 @@ function measureText(hdc, text, maxWidth) {
20239
20453
  -1,
20240
20454
  r2.ptr,
20241
20455
  1024
20242
- /* gui.DrawTextFlag.CALCRECT */
20456
+ /* DrawTextFlag.CALCRECT */
20243
20457
  );
20244
20458
  const { right, bottom } = RECT.decode(r2);
20245
20459
  return { width: right, height: bottom };
@@ -20287,7 +20501,7 @@ function setupWindowProc(instance, hwnd) {
20287
20501
  const oldProc = GetWindowLongPtr(
20288
20502
  hwnd,
20289
20503
  -4
20290
- /* gui.Gwlp.WNDPROC */
20504
+ /* Gwlp.WNDPROC */
20291
20505
  );
20292
20506
  instancesByHwnd.set(hwnd, instance);
20293
20507
  gui3.SetWindowProc(hwnd, (hwnd2, msg, wParam, lParam) => {
@@ -20375,7 +20589,7 @@ function runFlexLayout(inst) {
20375
20589
  r2.width * scaleFactor,
20376
20590
  r2.height * scaleFactor,
20377
20591
  64
20378
- /* gui.SetWindowPosFlag.SWP_SHOWWINDOW */
20592
+ /* SetWindowPosFlag.SWP_SHOWWINDOW */
20379
20593
  );
20380
20594
  InvalidateRect(child.hwnd, NULL, 1);
20381
20595
  child.lastRect = { x: r2.x, y: r2.y, w: r2.width, h: r2.height };
@@ -20531,7 +20745,7 @@ var hostConfig = {
20531
20745
  gui3.ShowWindow(
20532
20746
  instance.hwnd,
20533
20747
  0
20534
- /* gui.ShowWindowCmd.HIDE */
20748
+ /* ShowWindowCmd.HIDE */
20535
20749
  );
20536
20750
  },
20537
20751
  hideTextInstance(instance) {
@@ -20539,7 +20753,7 @@ var hostConfig = {
20539
20753
  gui3.ShowWindow(
20540
20754
  instance.hwnd,
20541
20755
  0
20542
- /* gui.ShowWindowCmd.HIDE */
20756
+ /* ShowWindowCmd.HIDE */
20543
20757
  );
20544
20758
  },
20545
20759
  unhideInstance(instance, _props) {
@@ -20547,7 +20761,7 @@ var hostConfig = {
20547
20761
  gui3.ShowWindow(
20548
20762
  instance.hwnd,
20549
20763
  5
20550
- /* gui.ShowWindowCmd.SHOW */
20764
+ /* ShowWindowCmd.SHOW */
20551
20765
  );
20552
20766
  },
20553
20767
  unhideTextInstance(instance, _text) {
@@ -20555,7 +20769,7 @@ var hostConfig = {
20555
20769
  gui3.ShowWindow(
20556
20770
  instance.hwnd,
20557
20771
  5
20558
- /* gui.ShowWindowCmd.SHOW */
20772
+ /* ShowWindowCmd.SHOW */
20559
20773
  );
20560
20774
  },
20561
20775
  shouldSetTextContent(_type, props) {
@@ -20983,7 +21197,7 @@ function getCellFont(hwnd, style) {
20983
21197
  ...base,
20984
21198
  ...style.bold ? {
20985
21199
  lfWeight: 700
20986
- /* gui.FontWeight.BOLD */
21200
+ /* FontWeight.BOLD */
20987
21201
  } : {},
20988
21202
  ...style.italic ? { lfItalic: 1 } : {},
20989
21203
  ...style.underline ? { lfUnderline: 1 } : {}
@@ -21041,7 +21255,7 @@ function resolveCellStyle(columns, data, row, colIndex) {
21041
21255
  }
21042
21256
  function makeLVItem(i2, sub, text, image) {
21043
21257
  const textBuf = WCHAR.encode(text);
21044
- const b7 = LVITEMW.encode({
21258
+ const b8 = LVITEMW.encode({
21045
21259
  mask: 1 | (image !== void 0 ? 2 : 0),
21046
21260
  iItem: i2,
21047
21261
  iSubItem: sub,
@@ -21058,8 +21272,8 @@ function makeLVItem(i2, sub, text, image) {
21058
21272
  piColFmt: 0,
21059
21273
  iGroup: 0
21060
21274
  });
21061
- b7.__textBuf = textBuf;
21062
- return b7;
21275
+ b8.__textBuf = textBuf;
21276
+ return b8;
21063
21277
  }
21064
21278
  var ListView = (0, import_react9.forwardRef)(function ListViewInner({ columns, data, style, icons, iconSize, getIcon }, ref) {
21065
21279
  const lvRef = (0, import_react9.useRef)(null);
@@ -21105,7 +21319,7 @@ var ListView = (0, import_react9.forwardRef)(function ListViewInner({ columns, d
21105
21319
  4150,
21106
21320
  0,
21107
21321
  32 | 1 | 65536
21108
- /* gui.LvExStyle.DOUBLEBUFFER */
21322
+ /* LvExStyle.DOUBLEBUFFER */
21109
21323
  );
21110
21324
  const n2 = columns.length;
21111
21325
  for (let j2 = 0; j2 < n2; j2++) {
@@ -21150,7 +21364,7 @@ var ListView = (0, import_react9.forwardRef)(function ListViewInner({ columns, d
21150
21364
  4126,
21151
21365
  j2,
21152
21366
  -2
21153
- /* gui.LvColumnWidthCmd.AUTOSIZE_USEHEADER */
21367
+ /* LvColumnWidthCmd.AUTOSIZE_USEHEADER */
21154
21368
  );
21155
21369
  }
21156
21370
  }
@@ -21292,7 +21506,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21292
21506
  natW,
21293
21507
  natH,
21294
21508
  4
21295
- /* gui.SetWindowPosFlag.SWP_NOZORDER */
21509
+ /* SetWindowPosFlag.SWP_NOZORDER */
21296
21510
  );
21297
21511
  forceFlexLayout(content);
21298
21512
  if (natW > svW) {
@@ -21331,7 +21545,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21331
21545
  0,
21332
21546
  0,
21333
21547
  1 | 4
21334
- /* gui.SetWindowPosFlag.SWP_NOZORDER */
21548
+ /* SetWindowPosFlag.SWP_NOZORDER */
21335
21549
  );
21336
21550
  gui12.SetScrollInfo(sv, bar, { pos: newPos }, true);
21337
21551
  }
@@ -21397,7 +21611,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21397
21611
  handleScroll(
21398
21612
  e2,
21399
21613
  1
21400
- /* gui.ScrollBar.VERT */
21614
+ /* ScrollBar.VERT */
21401
21615
  );
21402
21616
  return 0;
21403
21617
  }
@@ -21405,7 +21619,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21405
21619
  handleScroll(
21406
21620
  e2,
21407
21621
  0
21408
- /* gui.ScrollBar.HORZ */
21622
+ /* ScrollBar.HORZ */
21409
21623
  );
21410
21624
  return 0;
21411
21625
  }
@@ -21569,7 +21783,7 @@ function deleteAllItems(hTree) {
21569
21783
  4353,
21570
21784
  1,
21571
21785
  -65536
21572
- /* gui.TvInsertAfter.ROOT */
21786
+ /* TvInsertAfter.ROOT */
21573
21787
  );
21574
21788
  }
21575
21789
  var TreeView = (0, import_react16.forwardRef)(function TreeViewInner({ data, onSelect, defaultSelectedKey, selectedKey: controlledKey, style }, ref) {
@@ -21601,7 +21815,7 @@ var TreeView = (0, import_react16.forwardRef)(function TreeViewInner({ data, onS
21601
21815
  4396,
21602
21816
  0,
21603
21817
  4
21604
- /* gui.TvExStyle.DOUBLEBUFFER */
21818
+ /* TvExStyle.DOUBLEBUFFER */
21605
21819
  );
21606
21820
  }, []);
21607
21821
  (0, import_react16.useEffect)(() => {
@@ -21643,9 +21857,16 @@ var b4 = (name, sig) => bind2("comdlg32.dll", name, sig);
21643
21857
  var GetOpenFileName = /* @__PURE__ */ b4("GetOpenFileNameW", "<OPENFILENAMEW>ptr -> u32");
21644
21858
 
21645
21859
  // _build/lib/windows/shell32.js
21646
- var b5 = (name, sig) => bind2("shell32.dll", name, sig);
21860
+ var b5 = (name, sig, encoders) => bind2("shell32.dll", name, sig, encoders);
21647
21861
  var SHBrowseForFolder = /* @__PURE__ */ b5("SHBrowseForFolderW", "<BROWSEINFOW>ptr -> <>ptr");
21648
21862
  var SHGetPathFromIDList = /* @__PURE__ */ b5("SHGetPathFromIDListW", "<>ptr <BYTE>ptr -> u32");
21863
+ var Shell_NotifyIconGetRect = (() => {
21864
+ try {
21865
+ return b5("Shell_NotifyIconGetRect", "<NOTIFYICONIDENTIFIER>ptr <RECT>ptr -> i32", { NOTIFYICONIDENTIFIER });
21866
+ } catch {
21867
+ return null;
21868
+ }
21869
+ })();
21649
21870
 
21650
21871
  // _build/lib/windows/ole32.js
21651
21872
  var b6 = (name, sig) => bind2("ole32.dll", name, sig);
@@ -21798,28 +22019,183 @@ function createRoot(container) {
21798
22019
  };
21799
22020
  }
21800
22021
 
21801
- // _build/examples/exec_server.js
22022
+ // _build/examples/execd/main.js
21802
22023
  var import_react18 = __toESM(require_react(), 1);
22024
+
22025
+ // _build/examples/execd/tray.js
22026
+ import * as os6 from "os";
22027
+ import * as gui18 from "gui";
22028
+
22029
+ // _build/lib/windows/kernel32.js
22030
+ var b7 = (name, sig, encoders) => bind2("kernel32.dll", name, sig, encoders);
22031
+ var CloseHandle = /* @__PURE__ */ b7("CloseHandle", "<>ptr -> i32");
22032
+ var OpenProcess = /* @__PURE__ */ b7("OpenProcess", "u32 i32 u32 -> <HPROCESS>ptr");
22033
+ var GetCurrentProcess = /* @__PURE__ */ b7("GetCurrentProcess", " -> <HPROCESS>ptr");
22034
+ var VirtualAllocEx = /* @__PURE__ */ b7("VirtualAllocEx", "<HPROCESS>ptr <>ptr <>ptr u32 u32 -> <>ptr");
22035
+ var VirtualFreeEx = /* @__PURE__ */ b7("VirtualFreeEx", "<HPROCESS>ptr <>ptr <>ptr u32 -> i32");
22036
+ var ReadProcessMemory = /* @__PURE__ */ b7("ReadProcessMemory", "<HPROCESS>ptr <>ptr <BYTE>ptr <>ptr <>ptr -> i32");
22037
+ var IsWow64Process = /* @__PURE__ */ b7("IsWow64Process", "<HPROCESS>ptr <BYTE>ptr -> i32");
22038
+
22039
+ // _build/examples/execd/tray.js
22040
+ var TB_GETBUTTON = 1047;
22041
+ var TB_BUTTONCOUNT = 1048;
22042
+ var TB_GETITEMRECT = 1053;
22043
+ var CLS_BUF = 512;
22044
+ var OS64 = os6.arch === "x64" || (() => {
22045
+ const wow = new PtrArrayBuffer(4);
22046
+ return IsWow64Process(GetCurrentProcess(), wow) !== 0 && new Uint32Array(wow)[0] !== 0;
22047
+ })();
22048
+ var TBBUTTON_DWDATA = OS64 ? 16 : 12;
22049
+ var TBBUTTON_ISTRING = OS64 ? 24 : 16;
22050
+ var TBBUTTON_SZ = OS64 ? 32 : 20;
22051
+ var TRAYDATA_UID = OS64 ? 8 : 4;
22052
+ var REMOTE_BUF = 256;
22053
+ function findToolbars(root) {
22054
+ const out = [];
22055
+ const cls = WCHAR.alloc(CLS_BUF);
22056
+ const walk = (parent) => {
22057
+ let child = FindWindowEx(parent, NULL, NULL, NULL);
22058
+ while (child) {
22059
+ const n2 = GetClassName(child, cls, CLS_BUF);
22060
+ if (n2 > 0 && WCHAR.decode(cls) === "ToolbarWindow32")
22061
+ out.push(child);
22062
+ walk(child);
22063
+ child = FindWindowEx(parent, child, NULL, NULL);
22064
+ }
22065
+ };
22066
+ walk(root);
22067
+ return out;
22068
+ }
22069
+ function readToolbar(tb, area, out) {
22070
+ const count = gui18.SendMessage(tb, TB_BUTTONCOUNT, 0, 0);
22071
+ if (!Number.isInteger(count) || count <= 0 || count > 512)
22072
+ return;
22073
+ const pidBuf = BYTE.alloc(4);
22074
+ if (GetWindowThreadProcessId(tb, pidBuf) === 0)
22075
+ return;
22076
+ const pid = new Uint32Array(pidBuf)[0];
22077
+ const proc = OpenProcess(56, 0, pid);
22078
+ if (!proc)
22079
+ throw new Error("OpenProcess(explorer " + pid + ") failed");
22080
+ const remote = VirtualAllocEx(proc, NULL, REMOTE_BUF, 12288, 4);
22081
+ if (!remote) {
22082
+ CloseHandle(proc);
22083
+ throw new Error("VirtualAllocEx failed");
22084
+ }
22085
+ try {
22086
+ const tbBuf = BYTE.alloc(REMOTE_BUF), trBuf = BYTE.alloc(REMOTE_BUF), tipBuf = BYTE.alloc(REMOTE_BUF);
22087
+ const dvTb = new DataView(tbBuf), dvTr = new DataView(trBuf);
22088
+ for (let i2 = 0; i2 < count; i2++) {
22089
+ if (!gui18.SendMessage(tb, TB_GETBUTTON, i2, remote))
22090
+ continue;
22091
+ if (!ReadProcessMemory(proc, remote, tbBuf, TBBUTTON_SZ, NULL))
22092
+ continue;
22093
+ const dwData = OS64 ? Number(dvTb.getBigUint64(TBBUTTON_DWDATA, true)) : dvTb.getUint32(TBBUTTON_DWDATA, true);
22094
+ if (dwData < 65536)
22095
+ continue;
22096
+ if (!ReadProcessMemory(proc, dwData, trBuf, TRAYDATA_UID + 4, NULL))
22097
+ continue;
22098
+ const hWnd = OS64 ? Number(dvTr.getBigUint64(0, true)) : dvTr.getUint32(0, true);
22099
+ const uID = dvTr.getUint32(TRAYDATA_UID, true);
22100
+ if (!hWnd || !IsWindow(hWnd))
22101
+ continue;
22102
+ let rect = null;
22103
+ if (gui18.SendMessage(tb, TB_GETITEMRECT, i2, remote) && ReadProcessMemory(proc, remote, trBuf, 16, NULL)) {
22104
+ const L2 = dvTr.getInt32(0, true), T2 = dvTr.getInt32(4, true);
22105
+ const R2 = dvTr.getInt32(8, true), B2 = dvTr.getInt32(12, true);
22106
+ if (!(L2 === 0 && T2 === 0 && R2 === 0 && B2 === 0)) {
22107
+ const tl = POINT.encode({ x: L2, y: T2 }), br2 = POINT.encode({ x: R2, y: B2 });
22108
+ if (ClientToScreen(tb, tl.ptr) && ClientToScreen(tb, br2.ptr)) {
22109
+ const a2 = POINT.decode(tl), b8 = POINT.decode(br2);
22110
+ rect = { left: a2.x, top: a2.y, right: b8.x, bottom: b8.y };
22111
+ }
22112
+ }
22113
+ }
22114
+ const iStr = OS64 ? Number(dvTb.getBigUint64(TBBUTTON_ISTRING, true)) : dvTb.getUint32(TBBUTTON_ISTRING, true);
22115
+ let tooltip = null;
22116
+ if (iStr >= 65536 && ReadProcessMemory(proc, iStr, tipBuf, 256, NULL)) {
22117
+ const dvTip = new DataView(tipBuf);
22118
+ let s2 = "";
22119
+ for (let off = 0; off < 256; off += 2) {
22120
+ const c2 = dvTip.getUint16(off, true);
22121
+ if (c2 === 0)
22122
+ break;
22123
+ s2 += String.fromCharCode(c2);
22124
+ }
22125
+ tooltip = s2 === "" ? null : s2;
22126
+ }
22127
+ out.push({ area, index: i2, hWnd, uID, tooltip, rect });
22128
+ }
22129
+ } finally {
22130
+ VirtualFreeEx(proc, remote, 0, 32768);
22131
+ CloseHandle(proc);
22132
+ }
22133
+ }
22134
+ function collectArea(root, area, out) {
22135
+ for (const tb of findToolbars(root))
22136
+ readToolbar(tb, area, out);
22137
+ }
22138
+ function collectVisible(root, out) {
22139
+ let main = null;
22140
+ let mainRight = -Infinity;
22141
+ for (const tb of findToolbars(root)) {
22142
+ const rc2 = RECT.alloc();
22143
+ if (!GetWindowRect(tb, rc2.ptr))
22144
+ continue;
22145
+ const right = RECT.decode(rc2).right;
22146
+ if (right > mainRight) {
22147
+ mainRight = right;
22148
+ main = tb;
22149
+ }
22150
+ }
22151
+ if (main)
22152
+ readToolbar(main, "visible", out);
22153
+ }
22154
+ function listTrayIcons() {
22155
+ const icons = [];
22156
+ const tray = FindWindow("Shell_TrayWnd", NULL);
22157
+ if (tray) {
22158
+ const notifyArea = FindWindowEx(tray, NULL, "TrayNotifyWnd", NULL);
22159
+ collectVisible(notifyArea ? notifyArea : tray, icons);
22160
+ }
22161
+ const overflow = FindWindow("NotifyIconOverflowWindow", NULL);
22162
+ if (overflow)
22163
+ collectArea(overflow, "overflow", icons);
22164
+ return icons;
22165
+ }
22166
+ function probeTrayIcon(hWnd, uID) {
22167
+ if (!Shell_NotifyIconGetRect)
22168
+ return { hr: -1, hrName: "unsupported", rect: null };
22169
+ const rc2 = RECT.alloc();
22170
+ const hr2 = Shell_NotifyIconGetRect({ cbSize: NOTIFYICONIDENTIFIER.size, hWnd, uID }, rc2.ptr);
22171
+ const hrName = hr2 === 0 ? "found" : hr2 === 1 ? "hidden" : hr2 === -2147467259 ? "not_found" : "hr=0x" + (hr2 >>> 0).toString(16);
22172
+ if (hr2 !== 0)
22173
+ return { hr: hr2, hrName, rect: null };
22174
+ const r2 = RECT.decode(rc2);
22175
+ return { hr: hr2, hrName, rect: { left: r2.left, top: r2.top, right: r2.right, bottom: r2.bottom } };
22176
+ }
22177
+
22178
+ // _build/examples/execd/main.js
21803
22179
  function parseArgs() {
21804
- let gui19 = true;
22180
+ let gui20 = true;
21805
22181
  let token = null;
21806
22182
  const args = typeof scriptArgs === "undefined" ? [] : scriptArgs;
21807
22183
  const normToken2 = (v2) => v2 === "" ? null : v2;
21808
22184
  for (let i2 = 0; i2 < args.length; i2++) {
21809
22185
  const a2 = args[i2] ?? "";
21810
22186
  if (a2 === "--nogui") {
21811
- gui19 = false;
22187
+ gui20 = false;
21812
22188
  } else if (a2 === "--gui") {
21813
- gui19 = (args[++i2] ?? "") !== "0";
22189
+ gui20 = (args[++i2] ?? "") !== "0";
21814
22190
  } else if (a2.startsWith("--gui=")) {
21815
- gui19 = a2.slice(6) !== "0";
22191
+ gui20 = a2.slice(6) !== "0";
21816
22192
  } else if (a2 === "--token") {
21817
22193
  token = normToken2(args[++i2] ?? "");
21818
22194
  } else if (a2.startsWith("--token=")) {
21819
22195
  token = normToken2(a2.slice(8));
21820
22196
  }
21821
22197
  }
21822
- return { gui: gui19, token };
22198
+ return { gui: gui20, token };
21823
22199
  }
21824
22200
  var cfg = parseArgs();
21825
22201
  var log = new RequestLog(100);
@@ -21840,8 +22216,6 @@ function formatLine(e2) {
21840
22216
  res = e2.exit === null ? "ok" : e2.exit === 0 ? "exit 0" : "exit " + e2.exit;
21841
22217
  } else if (e2.status === 401) {
21842
22218
  res = "unauthorized";
21843
- } else if (e2.status === 404) {
21844
- res = "404";
21845
22219
  } else if (e2.status === 504) {
21846
22220
  res = "timeout";
21847
22221
  } else {
@@ -21855,7 +22229,7 @@ function formatInfo() {
21855
22229
  function refreshGui() {
21856
22230
  if (!guiUpdater || guiTimer !== null)
21857
22231
  return;
21858
- guiTimer = os6.setTimeout(() => {
22232
+ guiTimer = os7.setTimeout(() => {
21859
22233
  guiTimer = null;
21860
22234
  const u2 = guiUpdater;
21861
22235
  if (u2)
@@ -21866,6 +22240,9 @@ function appendLog(e2) {
21866
22240
  log.push(e2);
21867
22241
  refreshGui();
21868
22242
  }
22243
+ function logReq(t0, cmd, status, note, exit = null) {
22244
+ appendLog({ ts: Date.now() / 1e3, cmd, status, exit, durMs: Date.now() - t0, note });
22245
+ }
21869
22246
  function bumpWorkers(d2) {
21870
22247
  activeWorkers += d2;
21871
22248
  refreshGui();
@@ -21875,20 +22252,20 @@ function initGui() {
21875
22252
  return;
21876
22253
  try {
21877
22254
  const root = createRoot({
21878
- text: "exec_server \xB7 :" + (boundPort || 8080),
22255
+ text: "execd \xB7 :" + (boundPort || 8080),
21879
22256
  x: 200,
21880
22257
  y: 200,
21881
22258
  width: 560,
21882
22259
  height: 420
21883
22260
  });
21884
22261
  root.render((0, import_jsx_runtime16.jsx)(LogPanel, {}));
21885
- gui18.ShowWindow(
22262
+ gui19.ShowWindow(
21886
22263
  root.hwnd,
21887
22264
  9
21888
- /* gui.ShowWindowCmd.RESTORE */
22265
+ /* ShowWindowCmd.RESTORE */
21889
22266
  );
21890
22267
  } catch (ex) {
21891
- console.error("[exec_server] gui init failed (fallback headless):", ex);
22268
+ console.error("[execd] gui init failed (fallback headless):", ex);
21892
22269
  }
21893
22270
  }
21894
22271
  function LogPanel() {
@@ -21914,7 +22291,7 @@ function authCheck(req) {
21914
22291
  }
21915
22292
  function runInWorker(cmd, signal, timeoutMs) {
21916
22293
  const spawnCmd = cmd;
21917
- const worker = new os6.Worker("data:text/javascript;base64,aW1wb3J0KmFzIGZlIGZyb20ib3MiO2ltcG9ydCphcyB4ZSBmcm9tInN0ZCI7aW1wb3J0KmFzIHkgZnJvbSJmZmkiO2ltcG9ydCphcyBldCBmcm9tIm9zIjtpbXBvcnQqYXMgSyBmcm9tInN0ZCI7aW1wb3J0KmFzIHJ0IGZyb20id2luIjt2YXIgZ2U9eyJ1dGYtOCI6InV0Zi04Iix1dGY4OiJ1dGYtOCIsInVuaWNvZGUtMS0xLXV0Zi04IjoidXRmLTgiLCJ1dGYtMTYiOiJ1dGYtMTZsZSIsInV0Zi0xNmxlIjoidXRmLTE2bGUiLCJ1dGYtMTZiZSI6InV0Zi0xNmJlIn07ZnVuY3Rpb24gT3QodCl7aWYoIXQpcmV0dXJuInV0Zi04IjtsZXQgZT1nZVt0LnRyaW0oKS50b0xvd2VyQ2FzZSgpXTtpZihlKXJldHVybiBlO3Rocm93IG5ldyBSYW5nZUVycm9yKGBUaGUgZW5jb2RpbmcgbGFiZWwgIiR7dH0iIGlzIG5vdCBzdXBwb3J0ZWRgKX1mdW5jdGlvbiBEZSh0LGUpe2xldCByPSIiO2ZvcihsZXQgbz0wO288dC5sZW5ndGg7KXtsZXQgbj10W28rK107aWYobjwxMjgpe3IrPVN0cmluZy5mcm9tQ2hhckNvZGUobik7Y29udGludWV9aWYobjwxOTIpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigidW5leHBlY3RlZCBjb250aW51YXRpb24gYnl0ZSIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1sZXQgaSxjO2lmKG48MjI0KXtpZihvPj10Lmxlbmd0aCl7cis9ZT8oKCk9Pnt0aHJvdyBuZXcgVHlwZUVycm9yKCJpbmNvbXBsZXRlIHV0Zi04Iil9KSgpOiJcdUZGRkQiO2JyZWFrfWxldCBzPXRbbysrXTtpZigocyYxOTIpIT09MTI4KXtyKz0iXHVGRkZEIjtjb250aW51ZX1pPShuJjMxKTw8NnxzJjYzLGM9MTI4fWVsc2UgaWYobjwyNDApe2lmKG8rMT49dC5sZW5ndGgpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW5jb21wbGV0ZSB1dGYtOCIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz10W28rK10scD10W28rK107aWYoKHMmMTkyKSE9PTEyOHx8KHAmMTkyKSE9PTEyOCl7cis9Ilx1RkZGRCI7Y29udGludWV9aT0obiYxNSk8PDEyfChzJjYzKTw8NnxwJjYzLGM9MjA0OH1lbHNlIGlmKG48MjQ4KXtpZihvKzI+PXQubGVuZ3RoKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImluY29tcGxldGUgdXRmLTgiKX0pKCk6Ilx1RkZGRCI7YnJlYWt9bGV0IHM9dFtvKytdLHA9dFtvKytdLGE9dFtvKytdO2lmKChzJjE5MikhPT0xMjh8fChwJjE5MikhPT0xMjh8fChhJjE5MikhPT0xMjgpe3IrPSJcdUZGRkQiO2NvbnRpbnVlfWk9KG4mNyk8PDE4fChzJjYzKTw8MTJ8KHAmNjMpPDw2fGEmNjMsYz02NTUzNn1lbHNle3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCB1dGYtOCBzdGFydCIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1pZihpPGN8fGk+PTU1Mjk2JiZpPD01NzM0M3x8aT4xMTE0MTExKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImludmFsaWQgdXRmLTggY29kZXBvaW50Iil9KSgpOiJcdUZGRkQiO2NvbnRpbnVlfWk8PTY1NTM1P3IrPVN0cmluZy5mcm9tQ2hhckNvZGUoaSk6KGktPTY1NTM2LHIrPVN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTZ8aT4+MTAsNTYzMjB8aSYxMDIzKSl9cmV0dXJuIHJ9ZnVuY3Rpb24gRWUodCxlLHIpe2xldCBvPW5ldyBEYXRhVmlldyh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQsdC5ieXRlTGVuZ3RoKSxuPSIiO2ZvcihsZXQgaT0wO2krMTx0Lmxlbmd0aDtpKz0yKXtsZXQgYz1vLmdldFVpbnQxNihpLGUpO2lmKGM+PTU1Mjk2JiZjPD01NjMxOSl7aWYoaSs9MixpKzE+PXQubGVuZ3RoKXtuKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInRydW5jYXRlZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz1vLmdldFVpbnQxNihpLGUpO3M+PTU2MzIwJiZzPD01NzM0Mz9uKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMscyk6KG4rPXI/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIixpLT0yKX1lbHNlIGM+PTU2MzIwJiZjPD01NzM0Mz9uKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInVuZXhwZWN0ZWQgdHJhaWxpbmcgc3Vycm9nYXRlIil9KSgpOiJcdUZGRkQiOm4rPVN0cmluZy5mcm9tQ2hhckNvZGUoYyl9cmV0dXJuIG59dmFyIHB0PWNsYXNze19lbmNvZGluZztfZmF0YWw7X2lnbm9yZUJPTTtjb25zdHJ1Y3RvcihlLHIpe3RoaXMuX2VuY29kaW5nPU90KGUpLHRoaXMuX2ZhdGFsPXI/LmZhdGFsPz8hMSx0aGlzLl9pZ25vcmVCT009cj8uaWdub3JlQk9NPz8hMX1nZXQgZW5jb2RpbmcoKXtyZXR1cm4gdGhpcy5fZW5jb2Rpbmd9Z2V0IGZhdGFsKCl7cmV0dXJuIHRoaXMuX2ZhdGFsfWdldCBpZ25vcmVCT00oKXtyZXR1cm4gdGhpcy5faWdub3JlQk9NfWRlY29kZShlKXtpZighZSlyZXR1cm4iIjtsZXQgcj1lIGluc3RhbmNlb2YgVWludDhBcnJheT9lOmUgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcj9uZXcgVWludDhBcnJheShlKTpuZXcgVWludDhBcnJheShlLmJ1ZmZlcixlLmJ5dGVPZmZzZXQsZS5ieXRlTGVuZ3RoKTtpZih0aGlzLl9lbmNvZGluZz09PSJ1dGYtOCIpcmV0dXJuIERlKHIsdGhpcy5fZmF0YWwpO2xldCBvPXRoaXMuX2VuY29kaW5nPT09InV0Zi0xNmxlIixuPTA7aWYoci5sZW5ndGg+PTImJiF0aGlzLl9pZ25vcmVCT00pe2xldCBpPW8/clswXTpyWzFdLHM9KG8/clsxXTpyWzBdKTw8OHxpOyhzPT09NjUyNzl8fHM9PT02NTUzNCkmJihuPTIpfXJldHVybiBFZShyLnNsaWNlKG4pLG8sdGhpcy5fZmF0YWwpfX0sYXQ9Y2xhc3N7X2VuY29kaW5nO2NvbnN0cnVjdG9yKGUpe3RoaXMuX2VuY29kaW5nPU90KGUpfWdldCBlbmNvZGluZygpe3JldHVybiB0aGlzLl9lbmNvZGluZ31lbmNvZGUoZSl7aWYoIWUpcmV0dXJuIG5ldyBVaW50OEFycmF5KDApO2lmKHRoaXMuX2VuY29kaW5nPT09InV0Zi04Iil7bGV0IGk9W107Zm9yKGxldCBjPTA7YzxlLmxlbmd0aDtjKyspe2xldCBzPWUuY2hhckNvZGVBdChjKTtpZihzPDEyOClpLnB1c2gocyk7ZWxzZSBpZihzPDIwNDgpaS5wdXNoKDE5MnxzPj42LDEyOHxzJjYzKTtlbHNlIGlmKHM8NTUyOTZ8fHM+PTU3MzQ0KWkucHVzaCgyMjR8cz4+MTIsMTI4fHM+PjYmNjMsMTI4fHMmNjMpO2Vsc2V7YysrO2xldCBwPWUuY2hhckNvZGVBdChjKTtzPTY1NTM2KygocyYxMDIzKTw8MTApfHAmMTAyMyxpLnB1c2goMjQwfHM+PjE4LDEyOHxzPj4xMiY2MywxMjh8cz4+NiY2MywxMjh8cyY2Myl9fXJldHVybiBuZXcgVWludDhBcnJheShpKX1sZXQgcj10aGlzLl9lbmNvZGluZz09PSJ1dGYtMTZsZSIsbz1uZXcgQXJyYXlCdWZmZXIoZS5sZW5ndGgqMiksbj1uZXcgRGF0YVZpZXcobyk7Zm9yKGxldCBpPTA7aTxlLmxlbmd0aDtpKyspbi5zZXRVaW50MTYoaSoyLGUuY2hhckNvZGVBdChpKSxyKTtyZXR1cm4gbmV3IFVpbnQ4QXJyYXkobyl9fTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RGVjb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHREZWNvZGVyPXB0KTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RW5jb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHRFbmNvZGVyPWF0KTtpbXBvcnR7YnVmZmVyUHRyIGFzIFdlfWZyb20iZmZpIjtpbXBvcnQqYXMgUnQgZnJvbSJvcyI7dmFyIFRlPVsidm9pZCIsInU4IiwiaTgiLCJ1MTYiLCJpMTYiLCJ1MzIiLCJpMzIiLCJ1NjQiLCJpNjQiLCJmMzIiLCJmNjQiLCJwdHIiXSx1dD0vXjwoW0EtWmEtel9dXHcqfCk+cHRyKCF8QFtBLVphLXpfXVx3Kik/JC87ZnVuY3Rpb24gUih0KXtyZXR1cm4gdXQudGVzdCh0KX12YXIgQXQ9L148KFtBLVphLXpfXVx3Kik+JC87ZnVuY3Rpb24gTSh0KXtyZXR1cm4gQXQudGVzdCh0KX1mdW5jdGlvbiBrKHQpe3JldHVybiBBdC5leGVjKHQpPy5bMV18fCIifWZ1bmN0aW9uIGx0KHQpe3JldHVybiB1dC5leGVjKHQpPy5bMV18fCIifXZhciB0dD10PT57aWYoUih0KSlyZXR1cm4icHRyIjtpZihNKHQpKXRocm93IG5ldyBFcnJvcihgZmZpOiBjVG9rZW5Ub1R5cGU6IGJ5LXZhbHVlIHRva2VuICIke3R9IiBoYXMgbm8gc2NhbGFyIHNsb3QgdHlwZWApO3JldHVybiB0fSxBPVJ0LmFyY2g9PT0ieDY0Ij84OjQsJD17dTg6MSxpODoxLHUxNjoyLGkxNjoyLHUzMjo0LGkzMjo0LHU2NDo4LGk2NDo4LGYzMjo0LGY2NDo4fSxJPTA7ZnVuY3Rpb24gWSh0KXtpZihSKHQpKXtsZXQgbj11dC5leGVjKHQpLGk9bj8uWzFdfHwiIjtyZXR1cm4gbj8uWzJdPy5zdGFydHNXaXRoKCJAIik/YDwke2l9PnB0cmA6dH1pZihNKHQpKXJldHVybiB0O2xldCBlPXQuaW5kZXhPZigiQCIpLHI9ZT49MD90LnNsaWNlKDAsZSk6dDtpZigoZTwwfHwvXltBLVphLXpfXVx3KiQvLnRlc3QodC5zbGljZShlKzEpKSkmJnIhPT0icHRyIiYmVGUuaW5jbHVkZXMocikpcmV0dXJuIHI7dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIHRva2VuOiAiK3QpfWZ1bmN0aW9uIFYodCxlLHIpe3N3aXRjaChyKXtjYXNlInU4IjpyZXR1cm4gdC5nZXRVaW50OChlKTtjYXNlImk4IjpyZXR1cm4gdC5nZXRJbnQ4KGUpO2Nhc2UidTE2IjpyZXR1cm4gdC5nZXRVaW50MTYoZSwhMCk7Y2FzZSJpMTYiOnJldHVybiB0LmdldEludDE2KGUsITApO2Nhc2UidTMyIjpyZXR1cm4gdC5nZXRVaW50MzIoZSwhMCk7Y2FzZSJpMzIiOnJldHVybiB0LmdldEludDMyKGUsITApO2Nhc2UidTY0IjpyZXR1cm4gdC5nZXRCaWdVaW50NjQoZSwhMCk7Y2FzZSJpNjQiOnJldHVybiB0LmdldEJpZ0ludDY0KGUsITApO2Nhc2UiZjMyIjpyZXR1cm4gdC5nZXRGbG9hdDMyKGUsITApO2Nhc2UiZjY0IjpyZXR1cm4gdC5nZXRGbG9hdDY0KGUsITApO2Nhc2UicHRyIjpyZXR1cm4gQT09PTg/TnVtYmVyKHQuZ2V0QmlnSW50NjQoZSwhMCkpOnQuZ2V0SW50MzIoZSwhMCl9fWZ1bmN0aW9uIGR0KHQsZSx7azpyLHY6b30pe3N3aXRjaChyKXtjYXNlInU4Ijp0LnNldFVpbnQ4KGUsTnVtYmVyKG8pKTticmVhaztjYXNlImk4Ijp0LnNldEludDgoZSxOdW1iZXIobykpO2JyZWFrO2Nhc2UidTE2Ijp0LnNldFVpbnQxNihlLE51bWJlcihvKSwhMCk7YnJlYWs7Y2FzZSJpMTYiOnQuc2V0SW50MTYoZSxOdW1iZXIobyksITApO2JyZWFrO2Nhc2UidTMyIjp0LnNldFVpbnQzMihlLG8+Pj4wLCEwKTticmVhaztjYXNlImkzMiI6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWs7Y2FzZSJ1NjQiOnQuc2V0QmlnVWludDY0KGUsbywhMCk7YnJlYWs7Y2FzZSJpNjQiOnQuc2V0QmlnSW50NjQoZSxvLCEwKTticmVhaztjYXNlImYzMiI6dC5zZXRGbG9hdDMyKGUsbywhMCk7YnJlYWs7Y2FzZSJmNjQiOnQuc2V0RmxvYXQ2NChlLG8sITApO2JyZWFrO2Nhc2UicHRyIjp7aWYobz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoImZmaTogZ290IG51bGwvdW5kZWZpbmVkIGZvciBhIHB0ciBzbG90OyBwYXNzIHRoZSBpbXBvcnRlZCBOVUxMIGNvbnN0YW50IGZvciBlbXB0eSIpO0E9PT04P3Quc2V0QmlnVWludDY0KGUsQmlnSW50LmFzVWludE4oNjQsQmlnSW50KG8pKSwhMCk6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWt9fX1mdW5jdGlvbiB2KHQsZSxyKXtsZXR7azpvLHY6bn09cjtpZihvPT09InU4Inx8bz09PSJpOCJ8fG89PT0idTE2Inx8bz09PSJpMTYiKXt0LnNldFVpbnQzMihlLE51bWJlcihuKT4+PjAsITApO3JldHVybn1kdCh0LGUscil9dmFyIGI9Y2xhc3MgZXh0ZW5kcyBBcnJheUJ1ZmZlcntwdHI7Y29uc3RydWN0b3IoZSl7c3VwZXIoZSksdGhpcy5wdHI9V2UodGhpcyl9fTtmdW5jdGlvbiBmdCh0LGUpe3JldHVybiBlW3RdfXZhciBCdD1uZXcgTWFwO2Z1bmN0aW9uIGJlKHQpe2xldCBlPUJ0LmdldCh0KTtpZihlIT09dm9pZCAwKXJldHVybiBlO2xldCByPXJ0LkxvYWRMaWJyYXJ5KHQpO2lmKCFyKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IExvYWRMaWJyYXJ5KCIke3R9IikgZmFpbGVkYCk7cmV0dXJuIEJ0LnNldCh0LHIpLHJ9ZnVuY3Rpb24gVXQodCl7bGV0IGU9dC5zcGxpdCgiIC0+ICIpO2lmKGUubGVuZ3RoIT09Mil0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBpbnZhbGlkIHNpZ25hdHVyZSAiJHt0fSIgKGV4cGVjdGVkICJhcmcxIGFyZzIgLT4gcmV0IilgKTtsZXQgcj1lWzBdLnNwbGl0KCIgIikuZmlsdGVyKGk9PmkhPT0iIiksbz1bXTtmb3IobGV0IGkgb2Ygcil7bGV0IGM9WShpKTtpZihjPT09InZvaWQiKXRocm93IG5ldyBFcnJvcigiVm9pZCBjYW4gbm90IGluIGFyZ3MiKTtvLnB1c2goYyl9bGV0IG49WShlWzFdKTtpZihNKG4pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICIke3R9IjogYnktdmFsdWUgc3RydWN0IGF0IHRoZSByZXR1cm4gcG9zaXRpb24gKDwke2sobil9PikgaXMgbm90IHN1cHBvcnRlZCBcdTIwMTQgYXJndW1lbnQgcG9zaXRpb25zIG9ubHk7IHBhc3MgYSBzdHJ1Y3Qgb3V0IHRocm91Z2ggYW4gb3V0LXBhcmFtIHNsb3QgaW5zdGVhZCAoPE4+cHRyICsgY2FsbGVyIGJ1ZmZlcilgKTtyZXR1cm57YXJnVG9rZW5zOm8scmV0VG9rZW46bixzaWc6dH19ZnVuY3Rpb24gTmUodCxlLHIsbyl7bGV0IG49VXQoZSk7Zm9yKGxldCBpIG9mIG4uYXJnVG9rZW5zKXtpZighTShpKSljb250aW51ZTtsZXQgYz1rKGkpLHM9ZnQoYyxyKTtpZighc3x8dHlwZW9mIHMuZW5jb2RlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7ZX06IGJ5LXZhbHVlIHBvc2l0aW9uIDwke2N9PiBoYXMgbm8gcmVnaXN0ZXJlZCBsYXlvdXQgKGF2YWlsYWJsZTogJHtPYmplY3Qua2V5cyhyKS5qb2luKCIsICIpfHwibm9uZSJ9KWApO2lmKHR5cGVvZiBzLnNpemUhPSJudW1iZXIifHxzLnNpemU8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke2V9OiBieS12YWx1ZSBwb3NpdGlvbiA8JHtjfT4gcmVxdWlyZXMgYSBzdHJ1Y3QgbGF5b3V0IHdpdGggc2l6ZSA+PSAxIChnb3QgJHtzLnNpemV9OyBub24tc3RydWN0IGNvZGVjcyBleHBvc2Ugbm8gc2l6ZSlgKX1yZXR1cm4oLi4uaSk9PkllKHQsbixpLHIsbyl9dmFyIHh0PXt1ODo0LGk4OjQsdTE2OjQsaTE2OjQsdTMyOjQsaTMyOjQsdTY0OjgsaTY0OjgsZjMyOjQsZjY0OjgscHRyOkF9LEd0PTQ7ZnVuY3Rpb24gSWUodCx7YXJnVG9rZW5zOmUscmV0VG9rZW46cixzaWc6b30sbixpLGMpe2xldCBzPWV0LmFyY2g9PT0ieDY0IixwPShsLEQpPT57aWYoTShsKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBnZXRXaWR0aDogYnktdmFsdWUgdG9rZW4gIiR7bH0iIChkaXNwYXRjaGVkIGJ5IHdpZHRoT2YpYCk7cmV0dXJuIEQ/ODpSKGwpP0E6eHRbbF19LGE9bD0+e2lmKE0obCkpe2lmKHMpcmV0dXJuIDg7bGV0IEQ9ZnQoayhsKSxpKTtpZighRCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtrKGwpfT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7bGV0IEU9RC5zaXplO3JldHVybiBFJTQ9PT0wP0U6RSs0LUUlNH1yZXR1cm4gcChsLHMpfSx1PTA7Zm9yKGxldCBsIG9mIGUpdSs9YShsKTtzJiZlLmxlbmd0aDxHdCYmKHU9R3QqOCk7bGV0IHg9bmV3IEFycmF5QnVmZmVyKHUpLGQ9bmV3IERhdGFWaWV3KHgpLHc9W10sZj0wO2ZvcihsZXQgbD0wO2w8ZS5sZW5ndGg7bCsrKXtsZXQgRD1lW2xdLEU9RC5lbmRzV2l0aCgiISIpLEM9bltsXTtpZihSKEQpKXtsZXQgaD1sdChEKTtpZih0eXBlb2YgQz09Im51bWJlciIpe2lmKEUmJkM9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IGFyZyMke2wrMX0gPCR7aH0+cHRyISBnb3QgMCAobnVsbCBwb2ludGVyIGZvcmJpZGRlbiBoZXJlOyB0aGUgdG9rZW4gbWFya3MgdGhpcyBwb3NpdGlvbiBub24tbnVsbClgKTt2KGQsZix7azoicHRyIix2OkN9KX1lbHNle2lmKEM9PW51bGwpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7aH0+cHRyIGdvdCAke1N0cmluZyhDKX07IHBhc3MgdGhlIGltcG9ydGVkIE5VTEwgY29uc3RhbnQgZm9yIGFuIGVtcHR5IHBvaW50ZXJgKTtsZXQgVD1pW2hdO2lmKCFUKXRocm93IG5ldyBFcnJvcihoPT09IiI/YGZmaS1iaW5kOiA8PnB0ciBleHBlY3RzIG51bWJlciAoTlVMTCB8IFB0ciksIGdvdCAke3R5cGVvZiBDfTsgdXNlIDxCWVRFPnB0ciB3aXRoIGEgUHRyQXJyYXlCdWZmZXIgKG5ldyBQdHJBcnJheUJ1ZmZlcihuKSksIG9yIGZmaS5idWZmZXJQdHIoYnVmKSBmb3IgYW4gYWRkcmVzc2A6YGZmaS1iaW5kOiB1bmtub3duIGxheW91dCAiPCR7aH0+cHRyIiAoYXZhaWxhYmxlOiAke09iamVjdC5rZXlzKGkpLmpvaW4oIiwgIil8fCJub25lIn0pYCk7aWYoIVQuZW5jb2RlKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IDwke2h9PnB0ciBoYXMgbm8gZW5jb2RlciAob3V0LW9ubHkgY29kZWMpYCk7bGV0IEg9VC5lbmNvZGUoQyk7dy5wdXNoKEgpO2xldCBMPUgucHRyO2lmKHR5cGVvZiBMIT0ibnVtYmVyIil0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiBjb2RlYy5lbmNvZGUgbXVzdCByZXR1cm4gYSBQdHJBcnJheUJ1ZmZlciwgZ290IHBsYWluIEFycmF5QnVmZmVyIik7aWYoRSYmTD09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT5wdHIhIGVuY29kZSBwcm9kdWNlZCAwIChudWxsIHBvaW50ZXIgZm9yYmlkZGVuIGhlcmUpYCk7dihkLGYse2s6InB0ciIsdjpMfSl9fWVsc2UgaWYoTShEKSl7bGV0IGg9ayhEKSxUPWZ0KGgsaSk7aWYoIVQpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7aWYoQz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtofT4gdmFsdWUgcG9zaXRpb24gZ290ICR7U3RyaW5nKEMpfTsgcGFzcyBhIHN0cnVjdCBvYmplY3QgKHVzZSA8JHtofT5wdHIgdG8gcGFzcyBhIHBvaW50ZXIpYCk7bGV0IEg9VC5zaXplO2lmKCFzfHxIPD04JiYoSCZILTEpPT09MClULmVuY29kZShDLHgsZik7ZWxzZXtsZXQgTD1uZXcgQXJyYXlCdWZmZXIoSCsxNSksUHQ9eS5idWZmZXJQdHIoTCksTXQ9KDE2LVB0JTE2KSUxNjtULmVuY29kZShDLEwsTXQpLHcucHVzaChMKSx2KGQsZix7azoicHRyIix2OlB0K010fSl9fWVsc2UgdihkLGYse2s6RCx2OkN9KTtmKz1hKEQpfWxldCBTPW5ldyBBcnJheUJ1ZmZlcig4KTt5LmZmaUNhbGwodCx4LFMscj09PSJmMzIifHxyPT09ImY2NCI/MTowKTtsZXQgVz15ZSh0dChyKSxTKTtpZihyLmVuZHNXaXRoKCIhIikmJlc9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IHJldHVybiAke3J9IGdvdCAwICh0aGUgdG9rZW4gcHJvbWlzZXMgQyBuZXZlciByZXR1cm5zIG51bGwgaGVyZSlgKTtpZihSKHIpJiZXIT09MCl7bGV0IGw9bHQocik7aWYobCE9PSIiKXtsZXQgRD1jW2xdO2lmKEQ/LmRlY29kZSlyZXR1cm4gRC5kZWNvZGUoVyl9fXJldHVybiBXfWZ1bmN0aW9uIHllKHQsZSl7aWYodCE9PSJ2b2lkIilyZXR1cm4gVihuZXcgRGF0YVZpZXcoZSksMCx0KX12YXIgQj17ZW5jb2RlOnQ9PntsZXQgZT1uZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIikuZW5jb2RlKHQrIlwwIikscj1uZXcgYihlLmJ5dGVMZW5ndGgpO3JldHVybiBuZXcgVWludDhBcnJheShyKS5zZXQoZSkscn0sZGVjb2RlOnQ9PntpZih0eXBlb2YgdD09Im51bWJlciIpe2xldCBuPSIiLGk9dCxjPWk7Zm9yKDs7KXtsZXQgcz15LnJlYWRCeXRlKGkpLHA9eS5yZWFkQnl0ZShpKzEpO2lmKHM9PT0wJiZwPT09MClyZXR1cm4gbjtpZihuKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHN8cDw8OCksaSs9MixpLWM+MTw8MjEpdGhyb3cgbmV3IEVycm9yKCJmZmktYmluZDogV0NIQVIgZGVjb2RlIGV4Y2VlZGVkIDRNaUIgd2l0aG91dCBOVUwiKX19bGV0IGU9bmV3IFVpbnQ4QXJyYXkodCkscj1lLmxlbmd0aCYtMixvPSIiO2ZvcihsZXQgbj0wO248cjtuKz0yKXtsZXQgaT1lW25dfGVbbisxXTw8ODtpZihpPT09MClyZXR1cm4gbztvKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGkpfXJldHVybiBvfSxhbGxvYzoodD0yNTYpPT5uZXcgYih0KjIpfSxGZT17ZW5jb2RlOnQ9PntpZighKHQgaW5zdGFuY2VvZiBiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiA8QllURT5wdHIgd2FudHMgYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pIC8gQllURS5hbGxvYyAvIHN0cnVjdC5lbmNvZGUpLCBub3QgYSBwbGFpbiBBcnJheUJ1ZmZlciIpO3JldHVybiB0fSxhbGxvYzp0PT5uZXcgYih0KX0sTHQ9e1dDSEFSOkIsQllURTpGZX07ZnVuY3Rpb24gRyh0LGUscixvLG4pe2xldCBpPXJ0LkdldFByb2NBZGRyZXNzKGJlKHQpLGUpO2lmKCFpKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IHByb2MgIiR7ZX0iIG5vdCBmb3VuZCBpbiAke3R9YCk7bGV0IGM9bj8/bztyZXR1cm4gTmUoaSxyLHsuLi5MdCwuLi5vfSx7Li4uTHQsLi4uYz8/e319KX12YXIga3Q9bmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KHQ9PntLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSBsZWFrZWQgKEdDZWQgd2l0aG91dCBkaXNwb3NlKTogc2lnPSIlcyIgcHRyPTB4JXgKYCx0LnNpZyx0LnB0cil9KTtmdW5jdGlvbiBIZSh0LGUscixvLG4saSl7bGV0IGM9bmV3IERhdGFWaWV3KG4pLHM9ZXQuYXJjaD09PSJ4NjQiLHA9bmV3IERhdGFWaWV3KG8pLGE9W10sdT0wO2ZvcihsZXQgZD0wO2Q8dC5sZW5ndGg7ZCsrKXtsZXQgdz10W2RdLGY9dy50b2ssUztpZihzKXtsZXQgVz1mPT09ImYzMiJ8fGY9PT0iZjY0Ij9kPDQ/MTI4K2QqODozMisoZC00KSo4OmQ8ND9kKjg6MzIrKGQtNCkqODtTPVYocCxXLGYpfWVsc2UgUz1WKHAsdSxmKSx1Kz14dFtmXTtpZih3Lm5vbm51bGwmJlM9PT0wKXtLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSAlczogYXJnIyVkIGdvdCAwICghIHByb21pc2UgdmlvbGF0ZWQgYnkgY2FsbGVyKSwgc2tpcHBpbmcgY2FsbGJhY2sKYCxpLGQrMSk7cmV0dXJufWEucHVzaChTKX1sZXQgeDt0cnl7eD1yKC4uLmEpfWNhdGNoKGQpe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlIGNhbGxiYWNrIHRocmV3OiAlcwpgLFN0cmluZyhkKSk7cmV0dXJufWlmKGUubm9ubnVsbCYmeD09PTApe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlICVzOiByZXR1cm4gZ290IDAgKCEgcHJvbWlzZSB2aW9sYXRlZCBieSBjYWxsYmFjayksIGxlYXZpbmcgcmVzdWx0IHNsb3QgMApgLGkpO3JldHVybn1lLnRvayE9PSJ2b2lkIiYmdihjLDAse2s6ZS50b2ssdjp4fSl9ZnVuY3Rpb24gX3QodCxlLHIpe2xldHthcmdUb2tlbnM6byxyZXRUb2tlbjpufT1VdCh0KTtmb3IobGV0IG0gb2YgbylpZihNKG0pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IGNsb3N1cmUgc2lnbmF0dXJlIGNhbm5vdCB0YWtlIGEgYnktdmFsdWUgc3RydWN0ICg8JHtrKG0pfT4pOyBieS12YWx1ZSBpcyBiaW5kLW9ubHkgXHUyMDE0IHRoZSBDXHUyMTkySlMgZGlyZWN0aW9uIGhhcyBubyBzdHJ1Y3Qgc2xvdCBkZWNvZGluZyAocGFzcyBhIHBvaW50ZXIgYW5kIGRlY29kZSBvbiB0aGUgSlMgc2lkZSlgKTtsZXQgaT1vLm1hcChtPT4oe3Rvazp0dChtKSxub25udWxsOm0uZW5kc1dpdGgoIiEiKX0pKSxjPXt0b2s6dHQobiksbm9ubnVsbDpuLmVuZHNXaXRoKCIhIil9LHM9ZXQuYXJjaD09PSJ4NjQiLHA9aS5yZWR1Y2UoKG0sVyk9Pm0reHRbVy50b2tdLDApO2lmKHM/aS5sZW5ndGg+MTY6cD42NCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBjbG9zdXJlIHNpZ25hdHVyZSBleGNlZWRzIGNhcHR1cmUgd2luZG93ICgke3M/Im1heCAxNiBwYXJhbXMiOiJtYXggNjQgc3RhY2sgYnl0ZXMifSk6ICR7dH1gKTtsZXQgYT1yPy5zdGRjYWxsPT09ITF8fHM/MDpwLHU9Yy50b2s9PT0iZjMyIj8xOmMudG9rPT09ImY2NCI/MjpjLnRvaz09PSJ1NjQifHxjLnRvaz09PSJpNjQiPzM6MCxkPXkuY2xvc3VyZU5ldyhhLHUsKG0sVyk9PntIZShpLGMsZSxtLFcsdCl9KSx3PSExLGY9KCk9Pnt3fHwodz0hMCxrdC51bnJlZ2lzdGVyKGYpLHkuY2xvc3VyZUZyZWUoZCkpfSxTPXtwdHI6ZCxkaXNwb3NlOmZ9O3JldHVybiBrdC5yZWdpc3RlcihmLHtzaWc6dCxwdHI6ZH0pLFN9aW1wb3J0KmFzIHd0IGZyb20iZmZpIjtmdW5jdGlvbiBYKHQsZSl7cmV0dXJuIHQrZS0xJn4oZS0xKX12YXIgenQ9dD0+JFt0XSE9PXZvaWQgMDtmdW5jdGlvbiBtdCh0KXtpZih0eXBlb2YgdD09InN0cmluZyIpe2xldCBlPS9eKHU4fHUxNilcWyhcZCspXF1AKHV0Zi04fHV0Zi0xNmxlKSQvLmV4ZWModCk7aWYoZSl7bGV0IGM9TnVtYmVyKGVbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJpbmcgbGVuZ3RoIG11c3QgYmUgYW4gaW50ZWdlciA+PSAxLCBnb3QgJHtjfWApO2xldCBzPWVbMV09PT0idTgiPzE6MjtyZXR1cm57c2l6ZTpzKmMsYWxpZ246cyx0eXBlOnt0YWc6InN0cmluZyIsZW5jb2Rpbmc6ZVszXX19fWxldCByPS9eKFteXFtcXV0rKVxbKFxkKylcXSQvLmV4ZWModCk7aWYocil7bGV0IGM9TnVtYmVyKHJbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke2N9YCk7bGV0IHM9bXQoclsxXSk7aWYocy50eXBlLnRhZz09PSJiaXRmaWVsZCIpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBiaXRmaWVsZHMgY2Fubm90IGJlIGFycmF5IGVsZW1lbnRzIik7cmV0dXJue3NpemU6cy5zaXplKmMsYWxpZ246cy5hbGlnbix0eXBlOnt0YWc6ImFycmF5IixlbGVtZW50VHlwZTpzLnR5cGUsZWxlbWVudFNpemU6cy5zaXplfX19bGV0IG89L14oW0EtWmEtel9dXHcqKTooXGQrKSQvLmV4ZWModCk7aWYobyl7bGV0IGM9b1sxXSxzPVkoYyk7aWYoIXp0KHMpfHxzPT09ImYzMiJ8fHM9PT0iZjY0Iil0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIHVuaXQgbXVzdCBiZSBhbiBpbnRlZ2VyIHR5cGUsIGdvdCAiJHtjfSJgKTtsZXQgcD1OdW1iZXIob1syXSksYT0kW3NdLHU9YSo4O2lmKCFOdW1iZXIuaXNJbnRlZ2VyKHApfHxwPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCBtdXN0IGJlIGFuIGludGVnZXIgPj0gMSwgZ290ICR7cH1gKTtpZihwPnUpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCAke3B9IGV4Y2VlZHMgdW5pdCB3aWR0aCAke3V9YCk7cmV0dXJue3NpemU6YSxhbGlnbjphLHR5cGU6e3RhZzoiYml0ZmllbGQiLHVuaXQ6cyxiaXQ6MCx3aWR0aDpwfX19bGV0IG49WSh0KTtpZihSKG4pKXJldHVybntzaXplOkEsYWxpZ246QSx0eXBlOnt0YWc6ImJhc2ljIixraW5kOiJwdHIifX07aWYoIXp0KG4pKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biBraW5kICIke3R9ImApO2xldCBpPSRbbl07cmV0dXJue3NpemU6aSxhbGlnbjppLHR5cGU6e3RhZzoiYmFzaWMiLGtpbmQ6bn19fWlmKHQmJnR5cGVvZiB0PT0ib2JqZWN0Iil7bGV0IGU9dCxyPWVbIiMiXTtpZihyPT09dm9pZCAwKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogbmVzdGVkIG9iamVjdCB2YWx1ZSByZXF1aXJlcyBhICcjJyBrZXkgKCdzdHJ1Y3QnIHwgJ3VuaW9uJyB8ICdhcnJheScpIik7aWYocj09PSJhcnJheSImJiIjcGFjayJpbiBlKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogJyNwYWNrJyBpcyBvbmx5IGFsbG93ZWQgb24gc3RydWN0L3VuaW9uLCBnb3QgJyR7cn0nYCk7aWYocj09PSJhcnJheSIpe2xldCBvPWUubGVuZ3RoO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKG8pfHxvPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke1N0cmluZyhvKX1gKTtsZXQgbj1tdChlLmVsZW1lbnQpO2lmKG4udHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOm4uc2l6ZSpvLGFsaWduOm4uYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6bi50eXBlLGVsZW1lbnRTaXplOm4uc2l6ZX19fWlmKHI9PT0ic3RydWN0Inx8cj09PSJ1bmlvbiIpe2xldCBvPWh0KHQpO3JldHVybntzaXplOm8uc2l6ZSxhbGlnbjpvLm1heEVmZmVjdGl2ZUFsaWduLHR5cGU6e3RhZzpyLGZpZWxkczpvLmZpZWxkc319fXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biAnIycgZGVjbGFyYXRpb24gJHtKU09OLnN0cmluZ2lmeShTdHJpbmcocikpfWApfXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogaW52YWxpZCBtZW1iZXIgdmFsdWU6ICR7U3RyaW5nKHQpfWApfWZ1bmN0aW9uIGh0KHQpe2xldCBlPXRbIiMiXT09PSJzdHJ1Y3QiLHI9dFsiI3BhY2siXT8/OCxvPTEsbj0wLGk9W10sYz0wLHM9LTEscD0wLGE9MCx1PSgpPT57czwwfHwoYz1YKHMrTWF0aC5jZWlsKHAvOCksYSkscz0tMSl9O2ZvcihsZXRbeCxkXW9mIE9iamVjdC5lbnRyaWVzKHQpKXtpZih4LnN0YXJ0c1dpdGgoIiMiKSljb250aW51ZTtsZXQgdz0vXihbXkBdKylAKFxkKykkLy5leGVjKHgpLGY9dz93WzFdOngsUz13P051bWJlcih3WzJdKTowLHtzaXplOm0sYWxpZ246Vyx0eXBlOmx9PW10KGQpLEQ9dHlwZW9mIGQ9PSJzdHJpbmciJiZkLmVuZHNXaXRoKCIhIiksRT1XO2lmKHI+MCYmKEU9TWF0aC5taW4ocixFKSksUyYmKEU9TWF0aC5tYXgoRSxTKSksbC50YWc9PT0iYml0ZmllbGQiKXtpZihmLnN0YXJ0c1dpdGgoIiQiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIG1lbWJlcnMgbXVzdCBiZSBuYW1lZCIpO2lmKCFlKXtpLnB1c2goe25hbWU6ZixvZmZzZXQ6MCxzaXplOm0sdHlwZTp7Li4ubCxiaXQ6MH19KSxvPU1hdGgubWF4KG8sRSksbj1NYXRoLm1heChuLG0pO2NvbnRpbnVlfWxldCBoPWwud2lkdGg7KHM8MHx8bSE9PWF8fHAraD5hKjgpJiYocz49MCYmdSgpLHM9WChjLEUpLHA9MCxhPW0pLGkucHVzaCh7bmFtZTpmLG9mZnNldDpzLHNpemU6bSx0eXBlOnsuLi5sLGJpdDpwfX0pLHArPWgsbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKTtjb250aW51ZX11KCk7bGV0IEM9WChjLEUpO2lmKCFmLnN0YXJ0c1dpdGgoIiQiKSlpLnB1c2goe25hbWU6ZixvZmZzZXQ6QyxzaXplOm0sdHlwZTpsLC4uLkQ/e25vbm51bGw6ITB9Ont9fSk7ZWxzZXtpZihsLnRhZyE9PSJzdHJ1Y3QiJiZsLnRhZyE9PSJ1bmlvbiIpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhbm9ueW1vdXMgbWVtYmVyICIke2Z9IiBtdXN0IGJlIGEgc3RydWN0L3VuaW9uYCk7Zm9yKGxldCBoIG9mIGwuZmllbGRzKWkucHVzaCh7Li4uaCxvZmZzZXQ6aC5vZmZzZXQrQ30pfWUmJihjPUMrbSksbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKX1yZXR1cm4gdSgpLHtzaXplOlgoZT9jOm4sbyksbWF4RWZmZWN0aXZlQWxpZ246byxmaWVsZHM6aX19ZnVuY3Rpb24gJHQodCxlLHIpe2xldCBvPSRbcl07cmV0dXJuIG89PT0xP0JpZ0ludCh0LmdldFVpbnQ4KGUpKTpvPT09Mj9CaWdJbnQodC5nZXRVaW50MTYoZSwhMCkpOm89PT00P0JpZ0ludCh0LmdldFVpbnQzMihlLCEwKSk6dC5nZXRCaWdVaW50NjQoZSwhMCl9ZnVuY3Rpb24gUGUodCxlLHIsbyl7bGV0IG49JFtyXTtpZihuPT09MSl7dC5zZXRVaW50OChlLE51bWJlcihvJjB4ZmZuKSk7cmV0dXJufWlmKG49PT0yKXt0LnNldFVpbnQxNihlLE51bWJlcihvJjB4ZmZmZm4pLCEwKTtyZXR1cm59aWYobj09PTQpe3Quc2V0VWludDMyKGUsTnVtYmVyKG8mMHhmZmZmZmZmZm4pLCEwKTtyZXR1cm59dC5zZXRCaWdVaW50NjQoZSxvJjB4ZmZmZmZmZmZmZmZmZmZmZm4sITApfWZ1bmN0aW9uIE1lKHQsZSxyKXtsZXQgbz1CaWdJbnQoci53aWR0aCksbj0kdCh0LGUsci51bml0KT4+QmlnSW50KHIuYml0KSYoMW48PG8pLTFuO3JldHVybiByLnVuaXRbMF09PT0iaSImJm4mMW48PG8tMW4mJihuLT0xbjw8byksci53aWR0aD41Mz9uOk51bWJlcihuKX1mdW5jdGlvbiBPZSh0LGUscixvKXtsZXQgbj1CaWdJbnQoci53aWR0aCksaT1CaWdJbnQoci5iaXQpLGM9KDFuPDxuKS0xbixzPWM8PGkscD0kdCh0LGUsci51bml0KSxhPSh0eXBlb2Ygbz09ImJpZ2ludCI/bzpCaWdJbnQoTWF0aC50cnVuYyhvKSkpJmM7UGUodCxlLHIudW5pdCxwJn5zfGE8PGkpfXZhciBSZT17InV0Zi04IjpuZXcgVGV4dEVuY29kZXIoInV0Zi04IiksInV0Zi0xNmxlIjpuZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIil9LEFlPXsidXRmLTgiOm5ldyBUZXh0RGVjb2RlcigidXRmLTgiLHtpZ25vcmVCT006ITB9KSwidXRmLTE2bGUiOm5ldyBUZXh0RGVjb2RlcigidXRmLTE2bGUiLHtpZ25vcmVCT006ITB9KX07ZnVuY3Rpb24gQmUodCxlLHIsbyl7bGV0IG49bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2UsciksaT1vPT09InV0Zi0xNmxlIj8yOjEsYz1yO2ZvcihsZXQgcz0wO3MraTw9cjtzKz1pKWlmKG5bc109PT0wJiYoaT09PTF8fG5bcysxXT09PTApKXtjPXM7YnJlYWt9cmV0dXJuIEFlW29dLmRlY29kZShuLnN1YmFycmF5KDAsYykpfWZ1bmN0aW9uIEdlKHQsZSxyLG8sbil7bGV0IGk9bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2Uscik7aS5maWxsKDApO2xldCBzPXItKG89PT0idXRmLTE2bGUiPzI6MSk7aWYoczw9MClyZXR1cm47bGV0IHA9UmVbb10uZW5jb2RlKFN0cmluZyhuPz8iIikpO2kuc2V0KHAuc3ViYXJyYXkoMCxNYXRoLm1pbihwLmxlbmd0aCxzKSkpfWZ1bmN0aW9uIExlKHQsZSxyLG8pe2xldCBuPW8uZWxlbWVudFNpemU+MD9yL28uZWxlbWVudFNpemU6MCxpPVtdO2ZvcihsZXQgYz0wO2M8bjtjKyspaS5wdXNoKFl0KHQsZStjKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplKSk7cmV0dXJuIGl9ZnVuY3Rpb24ga2UodCxlLHIsbyxuKXtsZXQgaT1vLmVsZW1lbnRTaXplPjA/ci9vLmVsZW1lbnRTaXplOjAsYz1uPz9bXTtmb3IobGV0IHM9MDtzPGk7cysrKVZ0KHQsZStzKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplLGNbc10pfWZ1bmN0aW9uIFl0KHQsZSxyLG8pe3N3aXRjaChyLnRhZyl7Y2FzZSJiYXNpYyI6cmV0dXJuIFYodCxlLHIua2luZCk7Y2FzZSJiaXRmaWVsZCI6cmV0dXJuIE1lKHQsZSxyKTtjYXNlInN0cmluZyI6cmV0dXJuIEJlKHQsZSxvLHIuZW5jb2RpbmcpO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjpyZXR1cm4gb3QodCxlLHIuZmllbGRzKTtjYXNlImFycmF5IjpyZXR1cm4gTGUodCxlLG8scil9fWZ1bmN0aW9uIFZ0KHQsZSxyLG8sbil7c3dpdGNoKHIudGFnKXtjYXNlImJhc2ljIjpkdCh0LGUse2s6ci5raW5kLHY6bn0pO2JyZWFrO2Nhc2UiYml0ZmllbGQiOk9lKHQsZSxyLG4/PzApO2JyZWFrO2Nhc2Uic3RyaW5nIjpHZSh0LGUsbyxyLmVuY29kaW5nLG4pO2JyZWFrO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjp2dCh0LGUsci5maWVsZHMsbj8/e30pO2JyZWFrO2Nhc2UiYXJyYXkiOmtlKHQsZSxvLHIsbik7YnJlYWt9fWZ1bmN0aW9uIG90KHQsZSxyKXtsZXQgbz17fTtmb3IobGV0IG4gb2Ygcil7bGV0IGk9WXQodCxlK24ub2Zmc2V0LG4udHlwZSxuLnNpemUpO2lmKG4ubm9ubnVsbCYmaT09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBkZWNvZGU6ICchJyBmaWVsZCAiJHtuLm5hbWV9IiBnb3QgMCAoQyBkaWQgbm90IGZpbGwgaXQsIG9yIGRlY29kZSB3YXMgY2FsbGVkIG9uIGFuIHVuZmlsbGVkIHNsb3QpYCk7b1tuLm5hbWVdPWl9cmV0dXJuIG99ZnVuY3Rpb24gdnQodCxlLHIsbyl7Zm9yKGxldCBuIG9mIHIpb1tuLm5hbWVdIT09dm9pZCAwJiZWdCh0LGUrbi5vZmZzZXQsbi50eXBlLG4uc2l6ZSxvW24ubmFtZV0pfWZ1bmN0aW9uIFVlKHQpe2xldHtmaWVsZHM6ZSxzaXplOnIsbWF4RWZmZWN0aXZlQWxpZ246b309aHQodCk7cmV0dXJue19fc3RydWN0OnQsc2l6ZTpyLHN0cnVjdEFsaWduOm8sZGVjb2RlOm49Pm90KHR5cGVvZiBuPT0ibnVtYmVyIj9uZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4scikpOm5ldyBEYXRhVmlldyhuKSwwLGUpLGFsbG9jOihuPT57aWYobiE9PXZvaWQgMCYmKCFOdW1iZXIuaXNJbnRlZ2VyKG4pfHxuPDEpKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYWxsb2MobikgcmVxdWlyZXMgYW4gaW50ZWdlciBuID49IDEgKFBBQigwKSBuZXZlciBlc2NhcGVzIFx1MjAxNCBwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7cmV0dXJuIG5ldyBiKHIqKG4/PzEpKX0pLGVuY29kZTooKG4saSxjKT0+e2lmKG49PW51bGwpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBlbmNvZGUodikgcmVxdWlyZXMgYW4gYXJndW1lbnQ7IHVzZSBhbGxvYygpIGZvciBhIHplcm9lZCBvdXQtcGFyYW0gc2xvdCIpO2xldCBzPWk/P25ldyBiKHIpO3JldHVybiB2dChuZXcgRGF0YVZpZXcocyksYz8/MCxlLG4pLHN9KSxvZmZzZXRPZjpuPT57Zm9yKGxldCBpIG9mIGUpaWYoaS5uYW1lPT09bilyZXR1cm4gaS5vZmZzZXQ7dGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBubyBmaWVsZCAiJHtufSJgKX19fWZ1bmN0aW9uIF9lKHQsZSxyKXtsZXQgbz17IiMiOnR9O3IhPT12b2lkIDAmJihvWyIjcGFjayJdPXIpO2ZvcihsZXRbbixpXW9mIE9iamVjdC5lbnRyaWVzKGUpKW4uc3RhcnRzV2l0aCgiIyIpfHwob1tuXT1pKTtyZXR1cm4gb31mdW5jdGlvbiBqdCh0KXtsZXR7ZmllbGRzOmUsc2l6ZTpyfT1odCh0Ll9fc3RydWN0KSxvPShuLGkpPT57bGV0IGM9W107Zm9yKGxldCBzPTA7czxpO3MrKyljLnB1c2gob3QobixzKnIsZSkpO3JldHVybiBjfTtyZXR1cm57ZW5jb2RlOm49PntpZighQXJyYXkuaXNBcnJheShuKXx8bi5sZW5ndGg9PT0wKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogc3RydWN0QXJyYXkoZGVmKS5lbmNvZGUoZWxzKSByZXF1aXJlcyBhIG5vbi1lbXB0eSBlbGVtZW50IGFycmF5IChwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7bGV0IGk9dC5hbGxvYyhuLmxlbmd0aCk7Zm9yKGxldCBjPTA7YzxuLmxlbmd0aDtjKyspdC5lbmNvZGUobltjXSxpLGMqdC5zaXplKTtyZXR1cm4gaX0sZGVjb2RlOigobixpKT0+e2lmKGkhPT12b2lkIDAmJighTnVtYmVyLmlzSW50ZWdlcihpKXx8aTwwKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZShwLCBjb3VudCkgcmVxdWlyZXMgYSBub24tbmVnYXRpdmUgaW50ZWdlciBjb3VudCwgZ290ICR7aX1gKTtpZih0eXBlb2Ygbj09Im51bWJlciIpe2lmKGk9PT12b2lkIDApdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGUoYWRkcmVzcywgY291bnQpIHJlcXVpcmVzIGFuIGV4cGxpY2l0IGNvdW50IChhIGJhcmUgYWRkcmVzcyBjYXJyaWVzIG5vIGxlbmd0aCkiKTtyZXR1cm4gaT09PTA/W106byhuZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4saSpyKSksaSl9bGV0IGM7aWYoaSE9PXZvaWQgMCl7aWYoYz1pLGMqcj5uLmJ5dGVMZW5ndGgpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGU6IGNvdW50ICR7Y30gXHhENyBzaXplICR7cn0gPSAke2Mqcn0gZXhjZWVkcyBidWZmZXIgYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH1gKX1lbHNle2lmKG4uYnl0ZUxlbmd0aCVyIT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZTogYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH0gaXMgbm90IGEgbXVsdGlwbGUgb2Ygc2l6ZSAke3J9IChtaXhlZCBidWZmZXI/IHBhc3MgY291bnQgZXhwbGljaXRseSlgKTtjPW4uYnl0ZUxlbmd0aC9yfXJldHVybiBjPT09MD9bXTpvKG5ldyBEYXRhVmlldyhuKSxjKX0pfX1mdW5jdGlvbiBnKHQsZSxyKXtsZXQgbz10eXBlb2YgdD09InN0cmluZyI7cmV0dXJuIFVlKF9lKCJzdHJ1Y3QiLG8/ZTp0LChvP3I6ZSk/LnBhY2spKX12YXIgUD1nKCJSRUNUIix7bGVmdDoiaTMyIix0b3A6ImkzMiIscmlnaHQ6ImkzMiIsYm90dG9tOiJpMzIifSksaj1nKCJQT0lOVCIse3g6ImkzMiIseToiaTMyIn0pO3ZhciBudD1nKCJTVEFSVFVQSU5GT1ciLHtjYjoidTMyIixscFJlc2VydmVkOiI8PnB0ciIsbHBEZXNrdG9wOiI8PnB0ciIsbHBUaXRsZToiPD5wdHIiLGR3WDoidTMyIixkd1k6InUzMiIsZHdYU2l6ZToidTMyIixkd1lTaXplOiJ1MzIiLGR3WENvdW50Q2hhcnM6InUzMiIsZHdZQ291bnRDaGFyczoidTMyIixkd0ZpbGxBdHRyaWJ1dGU6InUzMiIsZHdGbGFnczoidTMyIix3U2hvd1dpbmRvdzoidTE2QFNob3dXaW5kb3dDbWQiLGNiUmVzZXJ2ZWQyOiJ1MTYiLGxwUmVzZXJ2ZWQyOiI8PnB0ciIsaFN0ZElucHV0OiI8SEZJTEU+cHRyIixoU3RkT3V0cHV0OiI8SEZJTEU+cHRyIixoU3RkRXJyb3I6IjxIRklMRT5wdHIifSksQ3Q9ZygiUFJPQ0VTU19JTkZPUk1BVElPTiIse2hQcm9jZXNzOiI8SFBST0NFU1M+cHRyISIsaFRocmVhZDoiPEhUSFJFQUQ+cHRyISIsZHdQcm9jZXNzSWQ6InUzMiIsZHdUaHJlYWRJZDoidTMyIn0pLEo9ZygiQklUTUFQSU5GT0hFQURFUiIse2JpU2l6ZToidTMyIixiaVdpZHRoOiJpMzIiLGJpSGVpZ2h0OiJpMzIiLGJpUGxhbmVzOiJ1MTYiLGJpQml0Q291bnQ6InUxNiIsYmlDb21wcmVzc2lvbjoidTMyIixiaVNpemVJbWFnZToidTMyIixiaVhQZWxzUGVyTWV0ZXI6ImkzMiIsYmlZUGVsc1Blck1ldGVyOiJpMzIiLGJpQ2xyVXNlZDoidTMyIixiaUNsckltcG9ydGFudDoidTMyIn0pLGl0PWcoIkJJVE1BUEZJTEVIRUFERVIiLHtiZlR5cGU6InUxNiIsYmZTaXplOiJ1MzIiLGJmUmVzZXJ2ZWQxOiJ1MTYiLGJmUmVzZXJ2ZWQyOiJ1MTYiLGJmT2ZmQml0czoidTMyIn0se3BhY2s6Mn0pO3ZhciBaPWcoIk5NSERSIix7aHduZEZyb206IjxIV05EPnB0ciIsaWRGcm9tOiI8PnB0ciIsY29kZToiaTMyIn0pLHplPWcoIlNZU1RFTVRJTUUiLHt3WWVhcjoidTE2Iix3TW9udGg6InUxNiIsd0RheU9mV2VlazoidTE2Iix3RGF5OiJ1MTYiLHdIb3VyOiJ1MTYiLHdNaW51dGU6InUxNiIsd1NlY29uZDoidTE2Iix3TWlsbGlzZWNvbmRzOiJ1MTYifSksbXI9ZygiTk1EQVRFVElNRUNIQU5HRSIse2hkcjpaLl9fc3RydWN0LGR3RmxhZ3M6InUzMiIsc3Q6emUuX19zdHJ1Y3R9KSwkZT1nKCJMSVRFTSIse21hc2s6InUzMiIsaUxpbms6ImkzMiIsc3RhdGU6InUzMiIsc3RhdGVNYXNrOiJ1MzIiLHN6SUQ6InUxNls0OF1AdXRmLTE2bGUiLHN6VXJsOiJ1MTZbMjA4NF1AdXRmLTE2bGUifSksd3I9ZygiTk1MSU5LIix7aGRyOlouX19zdHJ1Y3QsaXRlbTokZS5fX3N0cnVjdH0pLGhyPWcoIk5NQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciJ9KSxDcj1nKCJOTUxWQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciIsY2xyVGV4dDoidTMyIixjbHJUZXh0Qms6InUzMiIsaVN1Ykl0ZW06ImkzMiIsZHdJdGVtVHlwZToidTMyIn0pLFNyPWcoIk5NTElTVFZJRVciLHtoZHI6Wi5fX3N0cnVjdCxpSXRlbToiaTMyIixpU3ViSXRlbToiaTMyIix1TmV3U3RhdGU6InUzMiIsdU9sZFN0YXRlOiJ1MzIiLHVDaGFuZ2VkOiJ1MzIiLHB0QWN0aW9uOiJpMzJbMl0iLGxQYXJhbToiPD5wdHIifSk7dmFyIFllPWcoIlRWSVRFTSIse21hc2s6InUzMiIsaEl0ZW06Ijw+cHRyIixzdGF0ZToidTMyIixzdGF0ZU1hc2s6InUzMiIscHN6VGV4dDoiPD5wdHIiLGNjaFRleHRNYXg6ImkzMiIsaUltYWdlOiJpMzIiLGlTZWxlY3RlZEltYWdlOiJpMzIiLGNDaGlsZHJlbjoiaTMyIixsUGFyYW06Ijw+cHRyIn0pLGdyPWcoIlRWSU5TRVJUU1RSVUNUIix7aFBhcmVudDoiPD5wdHIiLGhJbnNlcnRBZnRlcjoiPD5wdHIiLGl0ZW06WWUuX19zdHJ1Y3R9KTt2YXIgVmU9ZygiTVNHIix7aHduZDoiPEhXTkQ+cHRyIixtZXNzYWdlOiJ1MzIiLHdQYXJhbToiPD5wdHIiLGxQYXJhbToiPD5wdHIiLHRpbWU6InUzMiIscHQ6ai5fX3N0cnVjdH0pLERyPWcoIlBBSU5UU1RSVUNUIix7aGRjOiI8SERDPnB0ciIsZkVyYXNlOiJpMzIiLHJjUGFpbnQ6UC5fX3N0cnVjdCxmUmVzdG9yZToiaTMyIixmSW5jVXBkYXRlOiJpMzIiLHJnYlJlc2VydmVkOiJ1OFszMl0ifSk7dmFyIHN0PWcoIk9TVkVSU0lPTklORk9fMTQ4Iix7ZHdPU1ZlcnNpb25JbmZvU2l6ZToidTMyIixkd01ham9yVmVyc2lvbjoidTMyIixkd01pbm9yVmVyc2lvbjoidTMyIixkd0J1aWxkTnVtYmVyOiJ1MzIiLGR3UGxhdGZvcm1JZDoidTMyIixzekNTRFZlcnNpb246InU4WzEyOF0ifSk7dmFyIE89KHQsZSxyKT0+Rygia2VybmVsMzIuZGxsIix0LGUsciksSnQ9TygiQ3JlYXRlUGlwZSIsIjw+cHRyIDw+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKSxTdD1PKCJTZXRIYW5kbGVJbmZvcm1hdGlvbiIsIjxIRklMRT5wdHIhIHUzMiB1MzIgLT4gaTMyIiksS3Q9TygiQ3JlYXRlUHJvY2Vzc1ciLCI8V0NIQVI+cHRyIDxXQ0hBUj5wdHIgPD5wdHIgPD5wdHIgaTMyIHUzMiA8PnB0ciA8V0NIQVI+cHRyIDxTVEFSVFVQSU5GT1c+cHRyIDxQUk9DRVNTX0lORk9STUFUSU9OPnB0ciAtPiBpMzIiLHtTVEFSVFVQSU5GT1c6bnR9KSxYdD1PKCJXYWl0Rm9yU2luZ2xlT2JqZWN0IiwiPD5wdHIgdTMyIC0+IHUzMiIpLFp0PU8oIkdldEV4aXRDb2RlUHJvY2VzcyIsIjxIUFJPQ0VTUz5wdHIhIDxCWVRFPnB0ciAtPiBpMzIiKSxVPU8oIkNsb3NlSGFuZGxlIiwiPD5wdHIgLT4gaTMyIik7dmFyIHF0PU8oIlJlYWRGaWxlIiwiPEhGSUxFPnB0ciEgPEJZVEU+cHRyIHUzMiA8QllURT5wdHIgPD5wdHIgLT4gaTMyIik7dmFyIGd0PU8oIkdldExhc3RFcnJvciIsIiAtPiB1MzIiKSxRdD1PKCJHZXRTeXN0ZW1EaXJlY3RvcnlXIiwiPEJZVEU+cHRyIHUzMiAtPiB1MzIiKTtpbXBvcnQqYXMgdGUgZnJvbSJvcyI7dmFyIE49KHQsZSxyKT0+RygidXNlcjMyLmRsbCIsdCxlLHIpLEhyPU4oIkdldERlc2t0b3BXaW5kb3ciLCIgLT4gPEhXTkQ+cHRyIiksZWU9dGUuYXJjaD09PSJ4NjQiPyJQdHJXIjoiVyI7dmFyIER0PU4oIkdldFdpbmRvd1JlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpLHJlPU4oIkdldENsaWVudFJlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpO3ZhciBvZT1OKCJJc1dpbmRvd1Zpc2libGUiLCI8SFdORD5wdHIgLT4gaTMyIiksRXQ9TigiSXNJY29uaWMiLCI8SFdORD5wdHIgLT4gaTMyIik7dmFyIG5lPU4oIkdldFdpbmRvd1RleHRXIiwiPEhXTkQ+cHRyIDxCWVRFPnB0ciBpMzIgLT4gaTMyIik7dmFyIGllPU4oIkdldENsYXNzTmFtZVciLCI8SFdORD5wdHIgPEJZVEU+cHRyIGkzMiAtPiBpMzIiKSxQcj1OKCJHZXRXaW5kb3dMb25nIitlZSwiPEhXTkQ+cHRyIGkzMkBHd2xwIC0+IDw+cHRyIiksTXI9TigiU2V0V2luZG93TG9uZyIrZWUsIjxIV05EPnB0ciBpMzJAR3dscCA8PnB0ciAtPiA8PnB0ciIpO3ZhciBzZT1OKCJHZXREQyIsIjxIV05EPnB0ciAtPiA8SERDPnB0ciIpLFd0PU4oIlJlbGVhc2VEQyIsIjxIV05EPnB0ciA8SERDPnB0ciEgLT4gaTMyIiksY2U9TigiUHJpbnRXaW5kb3ciLCI8SFdORD5wdHIgPEhEQz5wdHIhIHUzMiAtPiBpMzIiKTt2YXIgcGU9TigiQ2xpZW50VG9TY3JlZW4iLCI8SFdORD5wdHIgPFBPSU5UPnB0ciAtPiBpMzIiKTt2YXIgXz1OKCJHZXRTeXN0ZW1NZXRyaWNzIiwiaTMyIC0+IGkzMiIpO3ZhciBhZT1OKCJFbnVtV2luZG93cyIsIjw+cHRyIDw+cHRyIC0+IGkzMiIpO3ZhciB6PSh0LGUscik9PkcoImdkaTMyLmRsbCIsdCxlLHIpLExyPWp0KGopO3ZhciBUdD16KCJEZWxldGVPYmplY3QiLCI8SEdESU9CSj5wdHIgLT4gaTMyIik7dmFyIGJ0PXooIkNyZWF0ZUNvbXBhdGlibGVEQyIsIjxIREM+cHRyIC0+IDxIREM+cHRyIiksTnQ9eigiQ3JlYXRlQ29tcGF0aWJsZUJpdG1hcCIsIjxIREM+cHRyISBpMzIgaTMyIC0+IDxIR0RJT0JKPnB0ciIpO3ZhciBxPXooIlNlbGVjdE9iamVjdCIsIjxIREM+cHRyISA8SEdESU9CSj5wdHIgLT4gPEhHRElPQko+cHRyIiksSXQ9eigiQml0Qmx0IiwiPEhEQz5wdHIhIGkzMiBpMzIgaTMyIGkzMiA8SERDPnB0ciBpMzIgaTMyIHUzMkBSYXN0ZXJPcCAtPiBpMzIiKSx1ZT16KCJHZXRESUJpdHMiLCI8SERDPnB0ciEgPEhHRElPQko+cHRyIHUzMiB1MzIgPEJZVEU+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKTt2YXIgUT16KCJEZWxldGVEQyIsIjxIREM+cHRyISAtPiBpMzIiKTt2YXIgdmU9KHQsZSk9PkcoIm50ZGxsLmRsbCIsdCxlKSxsZT12ZSgiUnRsR2V0VmVyc2lvbiIsIjxPU1ZFUlNJT05JTkZPXzE0OD5wdHIgLT4gaTMyIik7dmFyIG1lPXQ9Pnt0cnl7bGV0IGU9eGUub3BlbigiZGlhZy5sb2ciLCJhIik7ZSYmKGUucHV0cyhgJHtEYXRlLm5vdygpfSAke3R9CmApLGUuY2xvc2UoKSl9Y2F0Y2h7fX0seXQ9MSxqZT0yNTYsSmU9NDI5NDk2NzI5NSxGPWZlLldvcmtlci5wYXJlbnQsd2U9IkM6XFxXaW5kb3dzXFxTeXN0ZW0zMiI7dHJ5e2xldCB0PUIuYWxsb2MoMjU2KSxyPVF0KHQsMjU2KT4wP0IuZGVjb2RlKHQpOiIiO3ImJih3ZT1yKX1jYXRjaCh0KXttZSgiU1lTLURJUi1GQUlMOiAiK1N0cmluZyh0KSl9dmFyIGhlPSExO3RyeXtsZXQgdD1zdC5lbmNvZGUoe2R3T1NWZXJzaW9uSW5mb1NpemU6c3Quc2l6ZX0pO2xlKHQucHRyKT09PTAmJihoZT1zdC5kZWNvZGUodCkuZHdNYWpvclZlcnNpb24+PTEwKX1jYXRjaCh0KXttZSgiVkVSLUZBSUw6ICIrU3RyaW5nKHQpKX12YXIgRnQ9ZygiUElQRV9IQU5ETEVTIix7aFJlYWQ6IjxIRklMRT5wdHIhIixoV3JpdGU6IjxIRklMRT5wdHIhIn0pO2Z1bmN0aW9uIEtlKHQsZSl7bGV0IHI9RnQuYWxsb2MoKTtpZighSnQoci5wdHIsci5wdHIrRnQub2Zmc2V0T2YoImhXcml0ZSIpLEksMCkpdGhyb3cgbmV3IEVycm9yKCJDcmVhdGVQaXBlIGVycj0iK2d0KCkpO2xldHtoUmVhZDpvLGhXcml0ZTpufT1GdC5kZWNvZGUocik7U3Qobix5dCx5dCksU3Qobyx5dCwwKTtsZXQgaT1DdC5hbGxvYygpLHM9YCR7d2V9XFxjbWQuZXhlICR7aGU/Ii91ICI6IiJ9L2MgJHtlfWA7aWYoIUt0KEkscyxJLEksMSwwLEksSSx7Y2I6bnQuc2l6ZSxkd0ZsYWdzOmplLGhTdGRPdXRwdXQ6bixoU3RkRXJyb3I6bn0saS5wdHIpKXRocm93IFUobyksVShuKSxuZXcgRXJyb3IoIkNyZWF0ZVByb2Nlc3NXIGVycj0iK2d0KCkrIiBjbWQ9IitzKTtsZXR7aFByb2Nlc3M6cCxoVGhyZWFkOmEsZHdQcm9jZXNzSWQ6dX09Q3QuZGVjb2RlKGkpO1UoYSksVShuKSxGLnBvc3RNZXNzYWdlKHt0eXBlOiJpbmZvIixpZDp0LHBpZDp1fSk7bGV0IHg9bmV3IGIoNDA5NiksZD1uZXcgVWludDhBcnJheSh4KSx3PW5ldyBiKDQpLGY9bmV3IFVpbnQzMkFycmF5KHcpO2Zvcig7ZlswXT0wLCEhcXQobyx4LDQwOTYsdyxJKTspe2xldCBsPWZbMF07aWYobD09PTApYnJlYWs7Ri5wb3N0TWVzc2FnZSh7dHlwZToiZGF0YSIsaWQ6dCxjaHVuazpkLnNsaWNlKDAsbCl9KX1YdChwLEplKTtsZXQgUz1uZXcgYig0KSxtPW5ldyBJbnQzMkFycmF5KFMpO1p0KHAsUyk7bGV0IFc9bVswXTtyZXR1cm4gVShvKSxVKHApLFd9dmFyIENlPTEzMzY5Mzc2LFhlPTAsZGU9NjU1MzYsWmU9NGU3LGN0PTUxMixxZT0yZTQsSHQ9aXQuc2l6ZStKLnNpemU7ZnVuY3Rpb24gUWUodCxlLHIpe2xldCBvPWl0LmVuY29kZSh7YmZUeXBlOjE5Nzc4LGJmU2l6ZTpIdCt0LGJmT2ZmQml0czpIdH0pLG49Si5lbmNvZGUoe2JpU2l6ZTpKLnNpemUsYmlXaWR0aDplLGJpSGVpZ2h0Oi1yLGJpUGxhbmVzOjEsYmlCaXRDb3VudDozMixiaUNvbXByZXNzaW9uOjAsYmlTaXplSW1hZ2U6dCxiaVhQZWxzUGVyTWV0ZXI6MjgzNSxiaVlQZWxzUGVyTWV0ZXI6MjgzNX0pLGk9bmV3IFVpbnQ4QXJyYXkoSHQpO3JldHVybiBpLnNldChuZXcgVWludDhBcnJheShvKSwwKSxpLnNldChuZXcgVWludDhBcnJheShuKSxpdC5zaXplKSxpfWZ1bmN0aW9uIHRyKHQsZSxyLG8sbil7bGV0IGk9bmV3IGIobypuKjQpLGM9bmV3IFVpbnQ4QXJyYXkoaSkscz1KLmVuY29kZSh7YmlTaXplOkouc2l6ZSxiaVdpZHRoOm8sYmlIZWlnaHQ6LW4sYmlQbGFuZXM6MSxiaUJpdENvdW50OjMyLGJpU2l6ZUltYWdlOm8qbio0fSk7aWYodWUoZSxyLDAsbixpLHMucHRyLFhlKSE9PW4pcmV0dXJuITE7bGV0IGE9Yy5ieXRlTGVuZ3RoO0YucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6UWUoYSxvLG4pfSk7Zm9yKGxldCB1PTA7dTxhO3UrPWRlKUYucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6Yy5zbGljZSh1LE1hdGgubWluKHUrZGUsYSkpfSk7cmV0dXJuITB9ZnVuY3Rpb24gZXIodCxlLHIsbyxuLGksYyxzLHApe2xldCBhPWJ0KHQpLHU9YT9OdCh0LHIsbyk6MDtpZighYXx8IXUpcmV0dXJuIGEmJlEoYSksITE7bGV0IHg9cShhLHUpLHc9Y2UoZSxhLDApIT09MCYmSXQobiwwLDAscyxwLGEsaSxjLENlKSE9PTA7cmV0dXJuIHEoYSx4KSxUdCh1KSxRKGEpLHd9ZnVuY3Rpb24gU2UodCxlLHIsbyxuLGksYyxzLHAsYSl7aWYoIShzPjAmJnA+MCYmcypwPD1aZSkpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIHNpemUgaW52YWxpZCB3PSIrcysiIGg9IitwKTtpZihhIT09bnVsbCYmIShpPj0wJiZjPj0wJiZpK3M8PWUmJmMrcDw9cikpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGNyb3Agb3V0IG9mIHJhbmdlIGNyb3A9KCIraSsiLCIrYysiLCIrcysieCIrcCsiKSBmcmFtZT0iK2UrIngiK3IpO2xldCB1PXNlKEkpO2lmKCF1KXRocm93IG5ldyBFcnJvcigiR2V0REMoTlVMTCk9MFx1RkYxQVx1NjVFMFx1OEY5M1x1NTE2NVx1Njg0Q1x1OTc2Mlx1RkYwOFx1Nzg2RVx1OEJBNFx1NTcyOFx1NEVBNFx1NEU5MiBzZXNzaW9uIFx1NTQyRlx1NTJBOFx1RkYwQ1x1ODAwQ1x1OTc1RSBzc2hkL3NlcnZpY2VcdUZGMDkiKTtsZXQgeD1idCh1KSxkPXg/TnQodSxzLHApOjA7aWYoIXh8fCFkKXRocm93IHgmJlEoeCksV3QoSSx1KSxuZXcgRXJyb3IoIkNyZWF0ZUNvbXBhdGlibGVEQy9CaXRtYXAgZmFpbGVkIik7bGV0IHc9cSh4LGQpLGY9YT09PW51bGw/SXQoeCwwLDAscyxwLHUsbyxuLENlKSE9PTA6ZXIodSxhLGUscix4LGksYyxzLHApO3EoeCx3KTtsZXQgUz1mJiZ0cih0LHgsZCxzLHApO2lmKFR0KGQpLFEoeCksV3QoSSx1KSwhZil0aHJvdyBuZXcgRXJyb3IoImNhcHR1cmUgZmFpbGVkIG91dD0iK3MrIngiK3ArKGE9PT1udWxsPyIgYXQ9KCIrbysiLCIrbisiKSI6IiBod25kPSIrYSsiIGNyb3A9KCIraSsiLCIrYysiKSBmcmFtZT0iK2UrIngiK3IpKTtpZighUyl0aHJvdyBuZXcgRXJyb3IoIkdldERJQml0cyBzaG9ydCByZWFkIG91dD0iK3MrIngiK3ApO3JldHVybnt3aWR0aDpzLGhlaWdodDpwfX1mdW5jdGlvbiBycih0KXtsZXQgZT1fKDApLHI9XygxKTtpZihlPD0wfHxyPD0wKXRocm93IG5ldyBFcnJvcigiR2V0U3lzdGVtTWV0cmljcyB3PSIrZSsiIGg9IityKTtyZXR1cm4gU2UodCxlLHIsMCwwLDAsMCxlLHIsbnVsbCl9ZnVuY3Rpb24gb3IodCxlLHIsbyl7aWYobz09PSJzY3JlZW4iJiZFdChlKSE9PTApdGhyb3cgbmV3IEVycm9yKCJ3aW5kb3cgbWluaW1pemVkXHVGRjFBbW9kZT1zY3JlZW4gXHU1M0VBXHU0RjFBXHU2MjJBXHU1MjMwXHU1QjgzXHU0RTBCXHU2NUI5XHU3Njg0XHU2ODRDXHU5NzYyXHVGRjBDXHU2NTM5XHU3NTI4IG1vZGU9cHJpbnQiKTtsZXQgbj1QLmFsbG9jKCk7aWYoIUR0KGUsbi5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0V2luZG93UmVjdChod25kPSIrZSsiKT0wXHVGRjFBXHU3QTk3XHU1M0UzXHU0RTBEXHU1QjU4XHU1NzI4XHU2MjE2XHU1REYyXHU5NTAwXHU2QkMxIik7bGV0e2xlZnQ6aSx0b3A6YyxyaWdodDpzLGJvdHRvbTpwfT1QLmRlY29kZShuKSxhPXMtaSx1PXAtYyx4PTAsZD0wLHc9YSxmPXU7aWYocj09PSJjbGllbnQiKXtsZXQgVz1QLmFsbG9jKCk7aWYoIXJlKGUsVy5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0Q2xpZW50UmVjdChod25kPSIrZSsiKT0wIik7bGV0e2xlZnQ6bCx0b3A6RCxyaWdodDpFLGJvdHRvbTpDfT1QLmRlY29kZShXKTt3PUUtbCxmPUMtRDtsZXQgaD1qLmVuY29kZSh7eDowLHk6MH0pO2lmKCFwZShlLGgucHRyKSl0aHJvdyBuZXcgRXJyb3IoIkNsaWVudFRvU2NyZWVuKGh3bmQ9IitlKyIpPTAiKTtsZXQgVD1qLmRlY29kZShoKTt4PVQueC1pLGQ9VC55LWN9bGV0IFM9bz09PSJwcmludCI/MDppK3gsbT1vPT09InByaW50Ij8wOmMrZDtpZihvPT09InNjcmVlbiIpe2xldCBXPV8oNzYpLGw9Xyg3NyksRD1fKDc4KSxFPV8oNzkpLEM9TWF0aC5tYXgoUyxXKSxoPU1hdGgubWF4KG0sbCksVD1NYXRoLm1pbihTK3csVytEKSxIPU1hdGgubWluKG0rZixsK0UpO2lmKFQ8PUN8fEg8PWgpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGFyZWEgb3V0c2lkZSB2aXJ0dWFsIHNjcmVlbiBhdD0oIitTKyIsIittKyIsIit3KyJ4IitmKyIpIik7Uz1DLG09aCx3PVQtQyxmPUgtaH1yZXR1cm4gU2UodCxhLHUsUyxtLHgsZCx3LGYsbz09PSJwcmludCI/ZTpudWxsKX1mdW5jdGlvbiBucih0KXtsZXQgZT1bXSxyPV90KCI8SFdORD5wdHIgPD5wdHIgLT4gaTMyIixzPT4ocyYmZS5wdXNoKHMpLGUubGVuZ3RoPHFlPzE6MCkpO3RyeXthZShyLnB0cixJKX1maW5hbGx5e3IuZGlzcG9zZSgpfWxldCBvPVAuYWxsb2MoKSxuPUIuYWxsb2MoY3QpLGk9Qi5hbGxvYyhjdCksYz1bXTtmb3IobGV0IHMgb2YgZSlpZihEdChzLG8ucHRyKSl7bGV0IHA9UC5kZWNvZGUobyksYT1uZShzLG4sY3QpLHU9aWUocyxpLGN0KTtjLnB1c2goe2h3bmQ6cyx0aXRsZTphPjA/Qi5kZWNvZGUobik6IiIsY2xhc3NOYW1lOnU+MD9CLmRlY29kZShpKToiIixyZWN0OntsZWZ0OnAubGVmdCx0b3A6cC50b3AscmlnaHQ6cC5yaWdodCxib3R0b206cC5ib3R0b219LHZpc2libGU6b2UocykhPT0wLG1pbmltaXplZDpFdChzKSE9PTB9KX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQsY29kZTowLGVycm9yOm51bGwsd2luZG93czpjfSl9ZnVuY3Rpb24gaXIodCl7aWYodC50eXBlPT09InJ1biIpe2lmKHR5cGVvZiB0LmNtZCE9InN0cmluZyIpcmV0dXJuO2xldCBlPS0xLHI9bnVsbDt0cnl7ZT1LZSh0LmlkLHQuY21kKX1jYXRjaChvKXtyPVN0cmluZyhvKX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTplLGVycm9yOnJ9KTtyZXR1cm59aWYodC50eXBlPT09IndpbmRvd3MiKXt0cnl7bnIodC5pZCl9Y2F0Y2goZSl7Ri5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixpZDp0LmlkLGNvZGU6LTEsZXJyb3I6U3RyaW5nKGUpfSl9cmV0dXJufWlmKHQudHlwZT09PSJzY3JlZW5zaG90Iil0cnl7bGV0IGU9dC5od25kPz9udWxsLHt3aWR0aDpyLGhlaWdodDpvfT1lPT09bnVsbD9ycih0LmlkKTpvcih0LmlkLGUsdC5hcmVhPz8id2luZG93Iix0Lm1vZGU/PyJzY3JlZW4iKTtGLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTowLGVycm9yOm51bGwsd2lkdGg6cixoZWlnaHQ6b30pfWNhdGNoKGUpe0YucG9zdE1lc3NhZ2Uoe3R5cGU6InJlc3VsdCIsaWQ6dC5pZCxjb2RlOi0xLGVycm9yOlN0cmluZyhlKX0pfX1GLm9ubWVzc2FnZT10PT57aXIodC5kYXRhKSxGLm9ubWVzc2FnZT1udWxsfTsK");
22294
+ const worker = new os7.Worker("data:text/javascript;base64,aW1wb3J0KmFzIE90IGZyb20ib3MiO2ltcG9ydCphcyBQdCBmcm9tInN0ZCI7aW1wb3J0KmFzIEMgZnJvbSJmZmkiO2ltcG9ydCphcyBkdCBmcm9tIm9zIjtpbXBvcnQqYXMgbXQgZnJvbSJzdGQiO2ltcG9ydCphcyAkIGZyb20id2luIjt2YXIgQXQ9eyJ1dGYtOCI6InV0Zi04Iix1dGY4OiJ1dGYtOCIsInVuaWNvZGUtMS0xLXV0Zi04IjoidXRmLTgiLCJ1dGYtMTYiOiJ1dGYtMTZsZSIsInV0Zi0xNmxlIjoidXRmLTE2bGUiLCJ1dGYtMTZiZSI6InV0Zi0xNmJlIn07ZnVuY3Rpb24gc3QodCl7aWYoIXQpcmV0dXJuInV0Zi04IjtsZXQgZT1BdFt0LnRyaW0oKS50b0xvd2VyQ2FzZSgpXTtpZihlKXJldHVybiBlO3Rocm93IG5ldyBSYW5nZUVycm9yKGBUaGUgZW5jb2RpbmcgbGFiZWwgIiR7dH0iIGlzIG5vdCBzdXBwb3J0ZWRgKX1mdW5jdGlvbiBNdCh0LGUpe2xldCByPSIiO2ZvcihsZXQgbj0wO248dC5sZW5ndGg7KXtsZXQgbz10W24rK107aWYobzwxMjgpe3IrPVN0cmluZy5mcm9tQ2hhckNvZGUobyk7Y29udGludWV9aWYobzwxOTIpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigidW5leHBlY3RlZCBjb250aW51YXRpb24gYnl0ZSIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1sZXQgaSxjO2lmKG88MjI0KXtpZihuPj10Lmxlbmd0aCl7cis9ZT8oKCk9Pnt0aHJvdyBuZXcgVHlwZUVycm9yKCJpbmNvbXBsZXRlIHV0Zi04Iil9KSgpOiJcdUZGRkQiO2JyZWFrfWxldCBzPXRbbisrXTtpZigocyYxOTIpIT09MTI4KXtyKz0iXHVGRkZEIjtjb250aW51ZX1pPShvJjMxKTw8NnxzJjYzLGM9MTI4fWVsc2UgaWYobzwyNDApe2lmKG4rMT49dC5sZW5ndGgpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW5jb21wbGV0ZSB1dGYtOCIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz10W24rK10sdT10W24rK107aWYoKHMmMTkyKSE9PTEyOHx8KHUmMTkyKSE9PTEyOCl7cis9Ilx1RkZGRCI7Y29udGludWV9aT0obyYxNSk8PDEyfChzJjYzKTw8Nnx1JjYzLGM9MjA0OH1lbHNlIGlmKG88MjQ4KXtpZihuKzI+PXQubGVuZ3RoKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImluY29tcGxldGUgdXRmLTgiKX0pKCk6Ilx1RkZGRCI7YnJlYWt9bGV0IHM9dFtuKytdLHU9dFtuKytdLHA9dFtuKytdO2lmKChzJjE5MikhPT0xMjh8fCh1JjE5MikhPT0xMjh8fChwJjE5MikhPT0xMjgpe3IrPSJcdUZGRkQiO2NvbnRpbnVlfWk9KG8mNyk8PDE4fChzJjYzKTw8MTJ8KHUmNjMpPDw2fHAmNjMsYz02NTUzNn1lbHNle3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCB1dGYtOCBzdGFydCIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1pZihpPGN8fGk+PTU1Mjk2JiZpPD01NzM0M3x8aT4xMTE0MTExKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImludmFsaWQgdXRmLTggY29kZXBvaW50Iil9KSgpOiJcdUZGRkQiO2NvbnRpbnVlfWk8PTY1NTM1P3IrPVN0cmluZy5mcm9tQ2hhckNvZGUoaSk6KGktPTY1NTM2LHIrPVN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTZ8aT4+MTAsNTYzMjB8aSYxMDIzKSl9cmV0dXJuIHJ9ZnVuY3Rpb24gV3QodCxlLHIpe2xldCBuPW5ldyBEYXRhVmlldyh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQsdC5ieXRlTGVuZ3RoKSxvPSIiO2ZvcihsZXQgaT0wO2krMTx0Lmxlbmd0aDtpKz0yKXtsZXQgYz1uLmdldFVpbnQxNihpLGUpO2lmKGM+PTU1Mjk2JiZjPD01NjMxOSl7aWYoaSs9MixpKzE+PXQubGVuZ3RoKXtvKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInRydW5jYXRlZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz1uLmdldFVpbnQxNihpLGUpO3M+PTU2MzIwJiZzPD01NzM0Mz9vKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMscyk6KG8rPXI/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIixpLT0yKX1lbHNlIGM+PTU2MzIwJiZjPD01NzM0Mz9vKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInVuZXhwZWN0ZWQgdHJhaWxpbmcgc3Vycm9nYXRlIil9KSgpOiJcdUZGRkQiOm8rPVN0cmluZy5mcm9tQ2hhckNvZGUoYyl9cmV0dXJuIG99dmFyIFY9Y2xhc3N7X2VuY29kaW5nO19mYXRhbDtfaWdub3JlQk9NO2NvbnN0cnVjdG9yKGUscil7dGhpcy5fZW5jb2Rpbmc9c3QoZSksdGhpcy5fZmF0YWw9cj8uZmF0YWw/PyExLHRoaXMuX2lnbm9yZUJPTT1yPy5pZ25vcmVCT00/PyExfWdldCBlbmNvZGluZygpe3JldHVybiB0aGlzLl9lbmNvZGluZ31nZXQgZmF0YWwoKXtyZXR1cm4gdGhpcy5fZmF0YWx9Z2V0IGlnbm9yZUJPTSgpe3JldHVybiB0aGlzLl9pZ25vcmVCT019ZGVjb2RlKGUpe2lmKCFlKXJldHVybiIiO2xldCByPWUgaW5zdGFuY2VvZiBVaW50OEFycmF5P2U6ZSBpbnN0YW5jZW9mIEFycmF5QnVmZmVyP25ldyBVaW50OEFycmF5KGUpOm5ldyBVaW50OEFycmF5KGUuYnVmZmVyLGUuYnl0ZU9mZnNldCxlLmJ5dGVMZW5ndGgpO2lmKHRoaXMuX2VuY29kaW5nPT09InV0Zi04IilyZXR1cm4gTXQocix0aGlzLl9mYXRhbCk7bGV0IG49dGhpcy5fZW5jb2Rpbmc9PT0idXRmLTE2bGUiLG89MDtpZihyLmxlbmd0aD49MiYmIXRoaXMuX2lnbm9yZUJPTSl7bGV0IGk9bj9yWzBdOnJbMV0scz0obj9yWzFdOnJbMF0pPDw4fGk7KHM9PT02NTI3OXx8cz09PTY1NTM0KSYmKG89Mil9cmV0dXJuIFd0KHIuc2xpY2Uobyksbix0aGlzLl9mYXRhbCl9fSx2PWNsYXNze19lbmNvZGluZztjb25zdHJ1Y3RvcihlKXt0aGlzLl9lbmNvZGluZz1zdChlKX1nZXQgZW5jb2RpbmcoKXtyZXR1cm4gdGhpcy5fZW5jb2Rpbmd9ZW5jb2RlKGUpe2lmKCFlKXJldHVybiBuZXcgVWludDhBcnJheSgwKTtpZih0aGlzLl9lbmNvZGluZz09PSJ1dGYtOCIpe2xldCBpPVtdO2ZvcihsZXQgYz0wO2M8ZS5sZW5ndGg7YysrKXtsZXQgcz1lLmNoYXJDb2RlQXQoYyk7aWYoczwxMjgpaS5wdXNoKHMpO2Vsc2UgaWYoczwyMDQ4KWkucHVzaCgxOTJ8cz4+NiwxMjh8cyY2Myk7ZWxzZSBpZihzPDU1Mjk2fHxzPj01NzM0NClpLnB1c2goMjI0fHM+PjEyLDEyOHxzPj42JjYzLDEyOHxzJjYzKTtlbHNle2MrKztsZXQgdT1lLmNoYXJDb2RlQXQoYyk7cz02NTUzNisoKHMmMTAyMyk8PDEwKXx1JjEwMjMsaS5wdXNoKDI0MHxzPj4xOCwxMjh8cz4+MTImNjMsMTI4fHM+PjYmNjMsMTI4fHMmNjMpfX1yZXR1cm4gbmV3IFVpbnQ4QXJyYXkoaSl9bGV0IHI9dGhpcy5fZW5jb2Rpbmc9PT0idXRmLTE2bGUiLG49bmV3IEFycmF5QnVmZmVyKGUubGVuZ3RoKjIpLG89bmV3IERhdGFWaWV3KG4pO2ZvcihsZXQgaT0wO2k8ZS5sZW5ndGg7aSsrKW8uc2V0VWludDE2KGkqMixlLmNoYXJDb2RlQXQoaSkscik7cmV0dXJuIG5ldyBVaW50OEFycmF5KG4pfX07dHlwZW9mIGdsb2JhbFRoaXMuVGV4dERlY29kZXI+InUiJiYoZ2xvYmFsVGhpcy5UZXh0RGVjb2Rlcj1WKTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RW5jb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHRFbmNvZGVyPXYpO2ltcG9ydHtidWZmZXJQdHIgYXMgUnR9ZnJvbSJmZmkiO2ltcG9ydCphcyBjdCBmcm9tIm9zIjt2YXIga3Q9WyJ2b2lkIiwidTgiLCJpOCIsInUxNiIsImkxNiIsInUzMiIsImkzMiIsInU2NCIsImk2NCIsImYzMiIsImY2NCIsInB0ciJdLGo9L148KFtBLVphLXpfXVx3KnwpPnB0cighfEBbQS1aYS16X11cdyopPyQvO2Z1bmN0aW9uIE4odCl7cmV0dXJuIGoudGVzdCh0KX12YXIgdXQ9L148KFtBLVphLXpfXVx3Kik+JC87ZnVuY3Rpb24geSh0KXtyZXR1cm4gdXQudGVzdCh0KX1mdW5jdGlvbiBXKHQpe3JldHVybiB1dC5leGVjKHQpPy5bMV18fCIifWZ1bmN0aW9uIFgodCl7cmV0dXJuIGouZXhlYyh0KT8uWzFdfHwiIn12YXIgYXQ9dD0+e2lmKE4odCkpcmV0dXJuInB0ciI7aWYoeSh0KSl0aHJvdyBuZXcgRXJyb3IoYGZmaTogY1Rva2VuVG9UeXBlOiBieS12YWx1ZSB0b2tlbiAiJHt0fSIgaGFzIG5vIHNjYWxhciBzbG90IHR5cGVgKTtyZXR1cm4gdH0sRD1jdC5hcmNoPT09Ing2NCI/ODo0LFI9e3U4OjEsaTg6MSx1MTY6MixpMTY6Mix1MzI6NCxpMzI6NCx1NjQ6OCxpNjQ6OCxmMzI6NCxmNjQ6OH0sTz0wO2Z1bmN0aW9uIGsodCl7aWYoTih0KSl7bGV0IG89ai5leGVjKHQpLGk9bz8uWzFdfHwiIjtyZXR1cm4gbz8uWzJdPy5zdGFydHNXaXRoKCJAIik/YDwke2l9PnB0cmA6dH1pZih5KHQpKXJldHVybiB0O2xldCBlPXQuaW5kZXhPZigiQCIpLHI9ZT49MD90LnNsaWNlKDAsZSk6dDtpZigoZTwwfHwvXltBLVphLXpfXVx3KiQvLnRlc3QodC5zbGljZShlKzEpKSkmJnIhPT0icHRyIiYma3QuaW5jbHVkZXMocikpcmV0dXJuIHI7dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIHRva2VuOiAiK3QpfWZ1bmN0aW9uIHoodCxlLHIpe3N3aXRjaChyKXtjYXNlInU4IjpyZXR1cm4gdC5nZXRVaW50OChlKTtjYXNlImk4IjpyZXR1cm4gdC5nZXRJbnQ4KGUpO2Nhc2UidTE2IjpyZXR1cm4gdC5nZXRVaW50MTYoZSwhMCk7Y2FzZSJpMTYiOnJldHVybiB0LmdldEludDE2KGUsITApO2Nhc2UidTMyIjpyZXR1cm4gdC5nZXRVaW50MzIoZSwhMCk7Y2FzZSJpMzIiOnJldHVybiB0LmdldEludDMyKGUsITApO2Nhc2UidTY0IjpyZXR1cm4gdC5nZXRCaWdVaW50NjQoZSwhMCk7Y2FzZSJpNjQiOnJldHVybiB0LmdldEJpZ0ludDY0KGUsITApO2Nhc2UiZjMyIjpyZXR1cm4gdC5nZXRGbG9hdDMyKGUsITApO2Nhc2UiZjY0IjpyZXR1cm4gdC5nZXRGbG9hdDY0KGUsITApO2Nhc2UicHRyIjpyZXR1cm4gRD09PTg/TnVtYmVyKHQuZ2V0QmlnSW50NjQoZSwhMCkpOnQuZ2V0SW50MzIoZSwhMCl9fWZ1bmN0aW9uIFoodCxlLHtrOnIsdjpufSl7c3dpdGNoKHIpe2Nhc2UidTgiOnQuc2V0VWludDgoZSxOdW1iZXIobikpO2JyZWFrO2Nhc2UiaTgiOnQuc2V0SW50OChlLE51bWJlcihuKSk7YnJlYWs7Y2FzZSJ1MTYiOnQuc2V0VWludDE2KGUsTnVtYmVyKG4pLCEwKTticmVhaztjYXNlImkxNiI6dC5zZXRJbnQxNihlLE51bWJlcihuKSwhMCk7YnJlYWs7Y2FzZSJ1MzIiOnQuc2V0VWludDMyKGUsbj4+PjAsITApO2JyZWFrO2Nhc2UiaTMyIjp0LnNldFVpbnQzMihlLG4+Pj4wLCEwKTticmVhaztjYXNlInU2NCI6dC5zZXRCaWdVaW50NjQoZSxuLCEwKTticmVhaztjYXNlImk2NCI6dC5zZXRCaWdJbnQ2NChlLG4sITApO2JyZWFrO2Nhc2UiZjMyIjp0LnNldEZsb2F0MzIoZSxuLCEwKTticmVhaztjYXNlImY2NCI6dC5zZXRGbG9hdDY0KGUsbiwhMCk7YnJlYWs7Y2FzZSJwdHIiOntpZihuPT1udWxsKXRocm93IG5ldyBFcnJvcigiZmZpOiBnb3QgbnVsbC91bmRlZmluZWQgZm9yIGEgcHRyIHNsb3Q7IHBhc3MgdGhlIGltcG9ydGVkIE5VTEwgY29uc3RhbnQgZm9yIGVtcHR5Iik7RD09PTg/dC5zZXRCaWdVaW50NjQoZSxCaWdJbnQuYXNVaW50Tig2NCxCaWdJbnQobikpLCEwKTp0LnNldFVpbnQzMihlLG4+Pj4wLCEwKTticmVha319fWZ1bmN0aW9uIF8odCxlLHIpe2xldHtrOm4sdjpvfT1yO2lmKG49PT0idTgifHxuPT09Imk4Inx8bj09PSJ1MTYifHxuPT09ImkxNiIpe3Quc2V0VWludDMyKGUsTnVtYmVyKG8pPj4+MCwhMCk7cmV0dXJufVoodCxlLHIpfXZhciB4PWNsYXNzIGV4dGVuZHMgQXJyYXlCdWZmZXJ7cHRyO2NvbnN0cnVjdG9yKGUpe3N1cGVyKGUpLHRoaXMucHRyPVJ0KHRoaXMpfX07ZnVuY3Rpb24gcSh0LGUpe3JldHVybiBlW3RdfXZhciBwdD1uZXcgTWFwO2Z1bmN0aW9uIF90KHQpe2xldCBlPXB0LmdldCh0KTtpZihlIT09dm9pZCAwKXJldHVybiBlO2xldCByPSQuTG9hZExpYnJhcnkodCk7aWYoIXIpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogTG9hZExpYnJhcnkoIiR7dH0iKSBmYWlsZWRgKTtyZXR1cm4gcHQuc2V0KHQscikscn1mdW5jdGlvbiBVdCh0KXtsZXQgZT10LnNwbGl0KCIgLT4gIik7aWYoZS5sZW5ndGghPT0yKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IGludmFsaWQgc2lnbmF0dXJlICIke3R9IiAoZXhwZWN0ZWQgImFyZzEgYXJnMiAtPiByZXQiKWApO2xldCByPWVbMF0uc3BsaXQoIiAiKS5maWx0ZXIoaT0+aSE9PSIiKSxuPVtdO2ZvcihsZXQgaSBvZiByKXtsZXQgYz1rKGkpO2lmKGM9PT0idm9pZCIpdGhyb3cgbmV3IEVycm9yKCJWb2lkIGNhbiBub3QgaW4gYXJncyIpO24ucHVzaChjKX1sZXQgbz1rKGVbMV0pO2lmKHkobykpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogIiR7dH0iOiBieS12YWx1ZSBzdHJ1Y3QgYXQgdGhlIHJldHVybiBwb3NpdGlvbiAoPCR7VyhvKX0+KSBpcyBub3Qgc3VwcG9ydGVkIFx1MjAxNCBhcmd1bWVudCBwb3NpdGlvbnMgb25seTsgcGFzcyBhIHN0cnVjdCBvdXQgdGhyb3VnaCBhbiBvdXQtcGFyYW0gc2xvdCBpbnN0ZWFkICg8Tj5wdHIgKyBjYWxsZXIgYnVmZmVyKWApO3JldHVybnthcmdUb2tlbnM6bixyZXRUb2tlbjpvLHNpZzp0fX1mdW5jdGlvbiBCdCh0LGUscixuKXtsZXQgbz1VdChlKTtmb3IobGV0IGkgb2Ygby5hcmdUb2tlbnMpe2lmKCF5KGkpKWNvbnRpbnVlO2xldCBjPVcoaSkscz1xKGMscik7aWYoIXN8fHR5cGVvZiBzLmVuY29kZSE9ImZ1bmN0aW9uIil0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke2V9OiBieS12YWx1ZSBwb3NpdGlvbiA8JHtjfT4gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0IChhdmFpbGFibGU6ICR7T2JqZWN0LmtleXMocikuam9pbigiLCAiKXx8Im5vbmUifSlgKTtpZih0eXBlb2Ygcy5zaXplIT0ibnVtYmVyInx8cy5zaXplPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtlfTogYnktdmFsdWUgcG9zaXRpb24gPCR7Y30+IHJlcXVpcmVzIGEgc3RydWN0IGxheW91dCB3aXRoIHNpemUgPj0gMSAoZ290ICR7cy5zaXplfTsgbm9uLXN0cnVjdCBjb2RlY3MgZXhwb3NlIG5vIHNpemUpYCl9cmV0dXJuKC4uLmkpPT56dCh0LG8saSxyLG4pfXZhciBIdD17dTg6NCxpODo0LHUxNjo0LGkxNjo0LHUzMjo0LGkzMjo0LHU2NDo4LGk2NDo4LGYzMjo0LGY2NDo4LHB0cjpEfSxmdD00O2Z1bmN0aW9uIHp0KHQse2FyZ1Rva2VuczplLHJldFRva2VuOnIsc2lnOm59LG8saSxjKXtsZXQgcz1kdC5hcmNoPT09Ing2NCIsdT0oYSxkKT0+e2lmKHkoYSkpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogZ2V0V2lkdGg6IGJ5LXZhbHVlIHRva2VuICIke2F9IiAoZGlzcGF0Y2hlZCBieSB3aWR0aE9mKWApO3JldHVybiBkPzg6TihhKT9EOkh0W2FdfSxwPWE9PntpZih5KGEpKXtpZihzKXJldHVybiA4O2xldCBkPXEoVyhhKSxpKTtpZighZCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtXKGEpfT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7bGV0IG09ZC5zaXplO3JldHVybiBtJTQ9PT0wP206bSs0LW0lNH1yZXR1cm4gdShhLHMpfSxoPTA7Zm9yKGxldCBhIG9mIGUpaCs9cChhKTtzJiZlLmxlbmd0aDxmdCYmKGg9ZnQqOCk7bGV0IEY9bmV3IEFycmF5QnVmZmVyKGgpLGc9bmV3IERhdGFWaWV3KEYpLFQ9W10sRT0wO2ZvcihsZXQgYT0wO2E8ZS5sZW5ndGg7YSsrKXtsZXQgZD1lW2FdLG09ZC5lbmRzV2l0aCgiISIpLGY9b1thXTtpZihOKGQpKXtsZXQgbD1YKGQpO2lmKHR5cGVvZiBmPT0ibnVtYmVyIil7aWYobSYmZj09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtufTogYXJnIyR7YSsxfSA8JHtsfT5wdHIhIGdvdCAwIChudWxsIHBvaW50ZXIgZm9yYmlkZGVuIGhlcmU7IHRoZSB0b2tlbiBtYXJrcyB0aGlzIHBvc2l0aW9uIG5vbi1udWxsKWApO18oZyxFLHtrOiJwdHIiLHY6Zn0pfWVsc2V7aWYoZj09bnVsbCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtsfT5wdHIgZ290ICR7U3RyaW5nKGYpfTsgcGFzcyB0aGUgaW1wb3J0ZWQgTlVMTCBjb25zdGFudCBmb3IgYW4gZW1wdHkgcG9pbnRlcmApO2xldCBJPWlbbF07aWYoIUkpdGhyb3cgbmV3IEVycm9yKGw9PT0iIj9gZmZpLWJpbmQ6IDw+cHRyIGV4cGVjdHMgbnVtYmVyIChOVUxMIHwgUHRyKSwgZ290ICR7dHlwZW9mIGZ9OyB1c2UgPEJZVEU+cHRyIHdpdGggYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pKSwgb3IgZmZpLmJ1ZmZlclB0cihidWYpIGZvciBhbiBhZGRyZXNzYDpgZmZpLWJpbmQ6IHVua25vd24gbGF5b3V0ICI8JHtsfT5wdHIiIChhdmFpbGFibGU6ICR7T2JqZWN0LmtleXMoaSkuam9pbigiLCAiKXx8Im5vbmUifSlgKTtpZighSS5lbmNvZGUpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7bH0+cHRyIGhhcyBubyBlbmNvZGVyIChvdXQtb25seSBjb2RlYylgKTtsZXQgTD1JLmVuY29kZShmKTtULnB1c2goTCk7bGV0IEE9TC5wdHI7aWYodHlwZW9mIEEhPSJudW1iZXIiKXRocm93IG5ldyBFcnJvcigiZmZpLWJpbmQ6IGNvZGVjLmVuY29kZSBtdXN0IHJldHVybiBhIFB0ckFycmF5QnVmZmVyLCBnb3QgcGxhaW4gQXJyYXlCdWZmZXIiKTtpZihtJiZBPT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke259OiBhcmcjJHthKzF9IDwke2x9PnB0ciEgZW5jb2RlIHByb2R1Y2VkIDAgKG51bGwgcG9pbnRlciBmb3JiaWRkZW4gaGVyZSlgKTtfKGcsRSx7azoicHRyIix2OkF9KX19ZWxzZSBpZih5KGQpKXtsZXQgbD1XKGQpLEk9cShsLGkpO2lmKCFJKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7bn06IGFyZyMke2ErMX0gPCR7bH0+IGJ5LXZhbHVlIHBvc2l0aW9uIGhhcyBubyByZWdpc3RlcmVkIGxheW91dGApO2lmKGY9PW51bGwpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7bH0+IHZhbHVlIHBvc2l0aW9uIGdvdCAke1N0cmluZyhmKX07IHBhc3MgYSBzdHJ1Y3Qgb2JqZWN0ICh1c2UgPCR7bH0+cHRyIHRvIHBhc3MgYSBwb2ludGVyKWApO2xldCBMPUkuc2l6ZTtpZighc3x8TDw9OCYmKEwmTC0xKT09PTApSS5lbmNvZGUoZixGLEUpO2Vsc2V7bGV0IEE9bmV3IEFycmF5QnVmZmVyKEwrMTUpLG90PUMuYnVmZmVyUHRyKEEpLGl0PSgxNi1vdCUxNiklMTY7SS5lbmNvZGUoZixBLGl0KSxULnB1c2goQSksXyhnLEUse2s6InB0ciIsdjpvdCtpdH0pfX1lbHNlIF8oZyxFLHtrOmQsdjpmfSk7RSs9cChkKX1sZXQgUD1uZXcgQXJyYXlCdWZmZXIoOCk7Qy5mZmlDYWxsKHQsRixQLHI9PT0iZjMyInx8cj09PSJmNjQiPzE6MCk7bGV0IFM9JHQoYXQociksUCk7aWYoci5lbmRzV2l0aCgiISIpJiZTPT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke259OiByZXR1cm4gJHtyfSBnb3QgMCAodGhlIHRva2VuIHByb21pc2VzIEMgbmV2ZXIgcmV0dXJucyBudWxsIGhlcmUpYCk7aWYoTihyKSYmUyE9PTApe2xldCBhPVgocik7aWYoYSE9PSIiKXtsZXQgZD1jW2FdO2lmKGQ/LmRlY29kZSlyZXR1cm4gZC5kZWNvZGUoUyl9fXJldHVybiBTfWZ1bmN0aW9uICR0KHQsZSl7aWYodCE9PSJ2b2lkIilyZXR1cm4geihuZXcgRGF0YVZpZXcoZSksMCx0KX12YXIgRz17ZW5jb2RlOnQ9PntsZXQgZT1uZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIikuZW5jb2RlKHQrIlwwIikscj1uZXcgeChlLmJ5dGVMZW5ndGgpO3JldHVybiBuZXcgVWludDhBcnJheShyKS5zZXQoZSkscn0sZGVjb2RlOnQ9PntpZih0eXBlb2YgdD09Im51bWJlciIpe2xldCBvPSIiLGk9dCxjPWk7Zm9yKDs7KXtsZXQgcz1DLnJlYWRCeXRlKGkpLHU9Qy5yZWFkQnl0ZShpKzEpO2lmKHM9PT0wJiZ1PT09MClyZXR1cm4gbztpZihvKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHN8dTw8OCksaSs9MixpLWM+MTw8MjEpdGhyb3cgbmV3IEVycm9yKCJmZmktYmluZDogV0NIQVIgZGVjb2RlIGV4Y2VlZGVkIDRNaUIgd2l0aG91dCBOVUwiKX19bGV0IGU9bmV3IFVpbnQ4QXJyYXkodCkscj1lLmxlbmd0aCYtMixuPSIiO2ZvcihsZXQgbz0wO288cjtvKz0yKXtsZXQgaT1lW29dfGVbbysxXTw8ODtpZihpPT09MClyZXR1cm4gbjtuKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGkpfXJldHVybiBufSxhbGxvYzoodD0yNTYpPT5uZXcgeCh0KjIpfSxHdD17ZW5jb2RlOnQ9PntpZighKHQgaW5zdGFuY2VvZiB4KSl0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiA8QllURT5wdHIgd2FudHMgYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pIC8gQllURS5hbGxvYyAvIHN0cnVjdC5lbmNvZGUpLCBub3QgYSBwbGFpbiBBcnJheUJ1ZmZlciIpO3JldHVybiB0fSxhbGxvYzp0PT5uZXcgeCh0KX0sbHQ9e1dDSEFSOkcsQllURTpHdH07ZnVuY3Rpb24gRXQodCxlLHIsbixvKXtsZXQgaT0kLkdldFByb2NBZGRyZXNzKF90KHQpLGUpO2lmKCFpKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IHByb2MgIiR7ZX0iIG5vdCBmb3VuZCBpbiAke3R9YCk7bGV0IGM9bz8/bjtyZXR1cm4gQnQoaSxyLHsuLi5sdCwuLi5ufSx7Li4ubHQsLi4uYz8/e319KX12YXIgZmU9bmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KHQ9PnttdC5wcmludGYoYFtmZmldIGNsb3N1cmUgbGVha2VkIChHQ2VkIHdpdGhvdXQgZGlzcG9zZSk6IHNpZz0iJXMiIHB0cj0weCV4CmAsdC5zaWcsdC5wdHIpfSk7aW1wb3J0KmFzIGh0IGZyb20iZmZpIjtmdW5jdGlvbiBVKHQsZSl7cmV0dXJuIHQrZS0xJn4oZS0xKX12YXIgeHQ9dD0+Ult0XSE9PXZvaWQgMDtmdW5jdGlvbiBLKHQpe2lmKHR5cGVvZiB0PT0ic3RyaW5nIil7bGV0IGU9L14odTh8dTE2KVxbKFxkKylcXUAodXRmLTh8dXRmLTE2bGUpJC8uZXhlYyh0KTtpZihlKXtsZXQgYz1OdW1iZXIoZVsyXSk7aWYoIU51bWJlci5pc0ludGVnZXIoYyl8fGM8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cmluZyBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke2N9YCk7bGV0IHM9ZVsxXT09PSJ1OCI/MToyO3JldHVybntzaXplOnMqYyxhbGlnbjpzLHR5cGU6e3RhZzoic3RyaW5nIixlbmNvZGluZzplWzNdfX19bGV0IHI9L14oW15cW1xdXSspXFsoXGQrKVxdJC8uZXhlYyh0KTtpZihyKXtsZXQgYz1OdW1iZXIoclsyXSk7aWYoIU51bWJlci5pc0ludGVnZXIoYyl8fGM8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGFycmF5IGxlbmd0aCBtdXN0IGJlIGFuIGludGVnZXIgPj0gMSwgZ290ICR7Y31gKTtsZXQgcz1LKHJbMV0pO2lmKHMudHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOnMuc2l6ZSpjLGFsaWduOnMuYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6cy50eXBlLGVsZW1lbnRTaXplOnMuc2l6ZX19fWxldCBuPS9eKFtBLVphLXpfXVx3Kik6KFxkKykkLy5leGVjKHQpO2lmKG4pe2xldCBjPW5bMV0scz1rKGMpO2lmKCF4dChzKXx8cz09PSJmMzIifHxzPT09ImY2NCIpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB1bml0IG11c3QgYmUgYW4gaW50ZWdlciB0eXBlLCBnb3QgIiR7Y30iYCk7bGV0IHU9TnVtYmVyKG5bMl0pLHA9UltzXSxoPXAqODtpZighTnVtYmVyLmlzSW50ZWdlcih1KXx8dTwxKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogYml0ZmllbGQgd2lkdGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke3V9YCk7aWYodT5oKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogYml0ZmllbGQgd2lkdGggJHt1fSBleGNlZWRzIHVuaXQgd2lkdGggJHtofWApO3JldHVybntzaXplOnAsYWxpZ246cCx0eXBlOnt0YWc6ImJpdGZpZWxkIix1bml0OnMsYml0OjAsd2lkdGg6dX19fWxldCBvPWsodCk7aWYoTihvKSlyZXR1cm57c2l6ZTpELGFsaWduOkQsdHlwZTp7dGFnOiJiYXNpYyIsa2luZDoicHRyIn19O2lmKCF4dChvKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHVua25vd24ga2luZCAiJHt0fSJgKTtsZXQgaT1SW29dO3JldHVybntzaXplOmksYWxpZ246aSx0eXBlOnt0YWc6ImJhc2ljIixraW5kOm99fX1pZih0JiZ0eXBlb2YgdD09Im9iamVjdCIpe2xldCBlPXQscj1lWyIjIl07aWYocj09PXZvaWQgMCl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IG5lc3RlZCBvYmplY3QgdmFsdWUgcmVxdWlyZXMgYSAnIycga2V5ICgnc3RydWN0JyB8ICd1bmlvbicgfCAnYXJyYXknKSIpO2lmKHI9PT0iYXJyYXkiJiYiI3BhY2siaW4gZSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6ICcjcGFjaycgaXMgb25seSBhbGxvd2VkIG9uIHN0cnVjdC91bmlvbiwgZ290ICcke3J9J2ApO2lmKHI9PT0iYXJyYXkiKXtsZXQgbj1lLmxlbmd0aDtpZighTnVtYmVyLmlzSW50ZWdlcihuKXx8bjwxKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogYXJyYXkgbGVuZ3RoIG11c3QgYmUgYW4gaW50ZWdlciA+PSAxLCBnb3QgJHtTdHJpbmcobil9YCk7bGV0IG89SyhlLmVsZW1lbnQpO2lmKG8udHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOm8uc2l6ZSpuLGFsaWduOm8uYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6by50eXBlLGVsZW1lbnRTaXplOm8uc2l6ZX19fWlmKHI9PT0ic3RydWN0Inx8cj09PSJ1bmlvbiIpe2xldCBuPXd0KHQpO3JldHVybntzaXplOm4uc2l6ZSxhbGlnbjpuLm1heEVmZmVjdGl2ZUFsaWduLHR5cGU6e3RhZzpyLGZpZWxkczpuLmZpZWxkc319fXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biAnIycgZGVjbGFyYXRpb24gJHtKU09OLnN0cmluZ2lmeShTdHJpbmcocikpfWApfXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogaW52YWxpZCBtZW1iZXIgdmFsdWU6ICR7U3RyaW5nKHQpfWApfWZ1bmN0aW9uIHd0KHQpe2xldCBlPXRbIiMiXT09PSJzdHJ1Y3QiLHI9dFsiI3BhY2siXT8/OCxuPTEsbz0wLGk9W10sYz0wLHM9LTEsdT0wLHA9MCxoPSgpPT57czwwfHwoYz1VKHMrTWF0aC5jZWlsKHUvOCkscCkscz0tMSl9O2ZvcihsZXRbRixnXW9mIE9iamVjdC5lbnRyaWVzKHQpKXtpZihGLnN0YXJ0c1dpdGgoIiMiKSljb250aW51ZTtsZXQgVD0vXihbXkBdKylAKFxkKykkLy5leGVjKEYpLEU9VD9UWzFdOkYsUD1UP051bWJlcihUWzJdKTowLHtzaXplOncsYWxpZ246Uyx0eXBlOmF9PUsoZyksZD10eXBlb2YgZz09InN0cmluZyImJmcuZW5kc1dpdGgoIiEiKSxtPVM7aWYocj4wJiYobT1NYXRoLm1pbihyLG0pKSxQJiYobT1NYXRoLm1heChtLFApKSxhLnRhZz09PSJiaXRmaWVsZCIpe2lmKEUuc3RhcnRzV2l0aCgiJCIpKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGQgbWVtYmVycyBtdXN0IGJlIG5hbWVkIik7aWYoIWUpe2kucHVzaCh7bmFtZTpFLG9mZnNldDowLHNpemU6dyx0eXBlOnsuLi5hLGJpdDowfX0pLG49TWF0aC5tYXgobixtKSxvPU1hdGgubWF4KG8sdyk7Y29udGludWV9bGV0IGw9YS53aWR0aDsoczwwfHx3IT09cHx8dStsPnAqOCkmJihzPj0wJiZoKCkscz1VKGMsbSksdT0wLHA9dyksaS5wdXNoKHtuYW1lOkUsb2Zmc2V0OnMsc2l6ZTp3LHR5cGU6ey4uLmEsYml0OnV9fSksdSs9bCxuPU1hdGgubWF4KG4sbSksbz1NYXRoLm1heChvLHcpO2NvbnRpbnVlfWgoKTtsZXQgZj1VKGMsbSk7aWYoIUUuc3RhcnRzV2l0aCgiJCIpKWkucHVzaCh7bmFtZTpFLG9mZnNldDpmLHNpemU6dyx0eXBlOmEsLi4uZD97bm9ubnVsbDohMH06e319KTtlbHNle2lmKGEudGFnIT09InN0cnVjdCImJmEudGFnIT09InVuaW9uIil0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGFub255bW91cyBtZW1iZXIgIiR7RX0iIG11c3QgYmUgYSBzdHJ1Y3QvdW5pb25gKTtmb3IobGV0IGwgb2YgYS5maWVsZHMpaS5wdXNoKHsuLi5sLG9mZnNldDpsLm9mZnNldCtmfSl9ZSYmKGM9Zit3KSxuPU1hdGgubWF4KG4sbSksbz1NYXRoLm1heChvLHcpfXJldHVybiBoKCkse3NpemU6VShlP2M6byxuKSxtYXhFZmZlY3RpdmVBbGlnbjpuLGZpZWxkczppfX1mdW5jdGlvbiBndCh0LGUscil7bGV0IG49UltyXTtyZXR1cm4gbj09PTE/QmlnSW50KHQuZ2V0VWludDgoZSkpOm49PT0yP0JpZ0ludCh0LmdldFVpbnQxNihlLCEwKSk6bj09PTQ/QmlnSW50KHQuZ2V0VWludDMyKGUsITApKTp0LmdldEJpZ1VpbnQ2NChlLCEwKX1mdW5jdGlvbiBZdCh0LGUscixuKXtsZXQgbz1SW3JdO2lmKG89PT0xKXt0LnNldFVpbnQ4KGUsTnVtYmVyKG4mMHhmZm4pKTtyZXR1cm59aWYobz09PTIpe3Quc2V0VWludDE2KGUsTnVtYmVyKG4mMHhmZmZmbiksITApO3JldHVybn1pZihvPT09NCl7dC5zZXRVaW50MzIoZSxOdW1iZXIobiYweGZmZmZmZmZmbiksITApO3JldHVybn10LnNldEJpZ1VpbnQ2NChlLG4mMHhmZmZmZmZmZmZmZmZmZmZmbiwhMCl9ZnVuY3Rpb24gVnQodCxlLHIpe2xldCBuPUJpZ0ludChyLndpZHRoKSxvPWd0KHQsZSxyLnVuaXQpPj5CaWdJbnQoci5iaXQpJigxbjw8biktMW47cmV0dXJuIHIudW5pdFswXT09PSJpIiYmbyYxbjw8bi0xbiYmKG8tPTFuPDxuKSxyLndpZHRoPjUzP286TnVtYmVyKG8pfWZ1bmN0aW9uIHZ0KHQsZSxyLG4pe2xldCBvPUJpZ0ludChyLndpZHRoKSxpPUJpZ0ludChyLmJpdCksYz0oMW48PG8pLTFuLHM9Yzw8aSx1PWd0KHQsZSxyLnVuaXQpLHA9KHR5cGVvZiBuPT0iYmlnaW50Ij9uOkJpZ0ludChNYXRoLnRydW5jKG4pKSkmYztZdCh0LGUsci51bml0LHUmfnN8cDw8aSl9dmFyIGp0PXsidXRmLTgiOm5ldyBUZXh0RW5jb2RlcigidXRmLTgiKSwidXRmLTE2bGUiOm5ldyBUZXh0RW5jb2RlcigidXRmLTE2bGUiKX0sWHQ9eyJ1dGYtOCI6bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIse2lnbm9yZUJPTTohMH0pLCJ1dGYtMTZsZSI6bmV3IFRleHREZWNvZGVyKCJ1dGYtMTZsZSIse2lnbm9yZUJPTTohMH0pfTtmdW5jdGlvbiBadCh0LGUscixuKXtsZXQgbz1uZXcgVWludDhBcnJheSh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQrZSxyKSxpPW49PT0idXRmLTE2bGUiPzI6MSxjPXI7Zm9yKGxldCBzPTA7cytpPD1yO3MrPWkpaWYob1tzXT09PTAmJihpPT09MXx8b1tzKzFdPT09MCkpe2M9czticmVha31yZXR1cm4gWHRbbl0uZGVjb2RlKG8uc3ViYXJyYXkoMCxjKSl9ZnVuY3Rpb24gcXQodCxlLHIsbixvKXtsZXQgaT1uZXcgVWludDhBcnJheSh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQrZSxyKTtpLmZpbGwoMCk7bGV0IHM9ci0obj09PSJ1dGYtMTZsZSI/MjoxKTtpZihzPD0wKXJldHVybjtsZXQgdT1qdFtuXS5lbmNvZGUoU3RyaW5nKG8/PyIiKSk7aS5zZXQodS5zdWJhcnJheSgwLE1hdGgubWluKHUubGVuZ3RoLHMpKSl9ZnVuY3Rpb24gS3QodCxlLHIsbil7bGV0IG89bi5lbGVtZW50U2l6ZT4wP3Ivbi5lbGVtZW50U2l6ZTowLGk9W107Zm9yKGxldCBjPTA7YzxvO2MrKylpLnB1c2goVHQodCxlK2Mqbi5lbGVtZW50U2l6ZSxuLmVsZW1lbnRUeXBlLG4uZWxlbWVudFNpemUpKTtyZXR1cm4gaX1mdW5jdGlvbiBRdCh0LGUscixuLG8pe2xldCBpPW4uZWxlbWVudFNpemU+MD9yL24uZWxlbWVudFNpemU6MCxjPW8/P1tdO2ZvcihsZXQgcz0wO3M8aTtzKyspRnQodCxlK3Mqbi5lbGVtZW50U2l6ZSxuLmVsZW1lbnRUeXBlLG4uZWxlbWVudFNpemUsY1tzXSl9ZnVuY3Rpb24gVHQodCxlLHIsbil7c3dpdGNoKHIudGFnKXtjYXNlImJhc2ljIjpyZXR1cm4geih0LGUsci5raW5kKTtjYXNlImJpdGZpZWxkIjpyZXR1cm4gVnQodCxlLHIpO2Nhc2Uic3RyaW5nIjpyZXR1cm4gWnQodCxlLG4sci5lbmNvZGluZyk7Y2FzZSJzdHJ1Y3QiOmNhc2UidW5pb24iOnJldHVybiBRKHQsZSxyLmZpZWxkcyk7Y2FzZSJhcnJheSI6cmV0dXJuIEt0KHQsZSxuLHIpfX1mdW5jdGlvbiBGdCh0LGUscixuLG8pe3N3aXRjaChyLnRhZyl7Y2FzZSJiYXNpYyI6Wih0LGUse2s6ci5raW5kLHY6b30pO2JyZWFrO2Nhc2UiYml0ZmllbGQiOnZ0KHQsZSxyLG8/PzApO2JyZWFrO2Nhc2Uic3RyaW5nIjpxdCh0LGUsbixyLmVuY29kaW5nLG8pO2JyZWFrO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjpTdCh0LGUsci5maWVsZHMsbz8/e30pO2JyZWFrO2Nhc2UiYXJyYXkiOlF0KHQsZSxuLHIsbyk7YnJlYWt9fWZ1bmN0aW9uIFEodCxlLHIpe2xldCBuPXt9O2ZvcihsZXQgbyBvZiByKXtsZXQgaT1UdCh0LGUrby5vZmZzZXQsby50eXBlLG8uc2l6ZSk7aWYoby5ub25udWxsJiZpPT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGRlY29kZTogJyEnIGZpZWxkICIke28ubmFtZX0iIGdvdCAwIChDIGRpZCBub3QgZmlsbCBpdCwgb3IgZGVjb2RlIHdhcyBjYWxsZWQgb24gYW4gdW5maWxsZWQgc2xvdClgKTtuW28ubmFtZV09aX1yZXR1cm4gbn1mdW5jdGlvbiBTdCh0LGUscixuKXtmb3IobGV0IG8gb2YgciluW28ubmFtZV0hPT12b2lkIDAmJkZ0KHQsZStvLm9mZnNldCxvLnR5cGUsby5zaXplLG5bby5uYW1lXSl9ZnVuY3Rpb24gSnQodCl7bGV0e2ZpZWxkczplLHNpemU6cixtYXhFZmZlY3RpdmVBbGlnbjpufT13dCh0KTtyZXR1cm57ZmllbGRzOmUsc2l6ZTpyLHN0cnVjdEFsaWduOm4sZGVjb2RlOm89PlEodHlwZW9mIG89PSJudW1iZXIiP25ldyBEYXRhVmlldyhodC5yZWFkQnl0ZXMobyxyKSk6bmV3IERhdGFWaWV3KG8pLDAsZSksYWxsb2M6KG89PntpZihvIT09dm9pZCAwJiYoIU51bWJlci5pc0ludGVnZXIobyl8fG88MSkpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBhbGxvYyhuKSByZXF1aXJlcyBhbiBpbnRlZ2VyIG4gPj0gMSAoUEFCKDApIG5ldmVyIGVzY2FwZXMgXHUyMDE0IHBhc3MgTlVMTCBmb3IgYW4gZW1wdHkgcG9pbnRlciBwb3NpdGlvbikiKTtyZXR1cm4gbmV3IHgocioobz8/MSkpfSksZW5jb2RlOigobyxpLGMpPT57aWYobz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IGVuY29kZSh2KSByZXF1aXJlcyBhbiBhcmd1bWVudDsgdXNlIGFsbG9jKCkgZm9yIGEgemVyb2VkIG91dC1wYXJhbSBzbG90Iik7bGV0IHM9aT8/bmV3IHgocik7cmV0dXJuIFN0KG5ldyBEYXRhVmlldyhzKSxjPz8wLGUsbyksc30pLG9mZnNldE9mOm89Pntmb3IobGV0IGkgb2YgZSlpZihpLm5hbWU9PT1vKXJldHVybiBpLm9mZnNldDt0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IG5vIGZpZWxkICIke299ImApfX19ZnVuY3Rpb24gdGUodCxlLHIpe2xldCBuPWVbIiMiXTtpZihuIT09dm9pZCAwJiZuIT09dCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6ICR7dH0oKSByZWNlaXZlZCBhICcke1N0cmluZyhuKX0nIGRlY2xhcmF0aW9uIChraW5kIG1pc21hdGNoIFx1MjAxNCB1c2UgJHtufSgpIGZvciBpdClgKTtsZXQgbz1lWyIjcGFjayJdO2lmKHI9PT12b2lkIDAmJm8hPT12b2lkIDApcj1vO2Vsc2UgaWYociE9PXZvaWQgMCYmbyE9PXZvaWQgMCYmciE9PW8pdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiAjcGFjayBjb25mbGljdDogb3B0cy5wYWNrPSR7cn0gdnMgZGVjbGFyYXRpb24gJHtTdHJpbmcobyl9YCk7bGV0IGk9eyIjIjp0fTtyIT09dm9pZCAwJiYoaVsiI3BhY2siXT1yKTtmb3IobGV0W2Msc11vZiBPYmplY3QuZW50cmllcyhlKSljLnN0YXJ0c1dpdGgoIiMiKXx8KGlbY109cyk7cmV0dXJuIGl9ZnVuY3Rpb24gQih0LGUscil7bGV0IG49dHlwZW9mIHQ9PSJzdHJpbmciO3JldHVybiBKdCh0ZSgic3RydWN0IixuP2U6dCwobj9yOmUpPy5wYWNrKSl9dmFyIGVlPXsiIyI6InN0cnVjdCIsY2I6InUzMiIsbHBSZXNlcnZlZDoiPD5wdHIiLGxwRGVza3RvcDoiPD5wdHIiLGxwVGl0bGU6Ijw+cHRyIixkd1g6InUzMiIsZHdZOiJ1MzIiLGR3WFNpemU6InUzMiIsZHdZU2l6ZToidTMyIixkd1hDb3VudENoYXJzOiJ1MzIiLGR3WUNvdW50Q2hhcnM6InUzMiIsZHdGaWxsQXR0cmlidXRlOiJ1MzIiLGR3RmxhZ3M6InUzMiIsd1Nob3dXaW5kb3c6InUxNkBTaG93V2luZG93Q21kIixjYlJlc2VydmVkMjoidTE2IixscFJlc2VydmVkMjoiPD5wdHIiLGhTdGRJbnB1dDoiPEhGSUxFPnB0ciIsaFN0ZE91dHB1dDoiPEhGSUxFPnB0ciIsaFN0ZEVycm9yOiI8SEZJTEU+cHRyIn0sWT1CKCJTVEFSVFVQSU5GT1ciLGVlKSxyZT17IiMiOiJzdHJ1Y3QiLGhQcm9jZXNzOiI8SFBST0NFU1M+cHRyISIsaFRocmVhZDoiPEhUSFJFQUQ+cHRyISIsZHdQcm9jZXNzSWQ6InUzMiIsZHdUaHJlYWRJZDoidTMyIn0sSj1CKCJQUk9DRVNTX0lORk9STUFUSU9OIixyZSk7dmFyIGI9KHQsZSxyKT0+RXQoImtlcm5lbDMyLmRsbCIsdCxlLHIpLEl0PWIoIkNyZWF0ZVBpcGUiLCI8PnB0ciA8PnB0ciA8PnB0ciB1MzIgLT4gaTMyIiksdHQ9YigiU2V0SGFuZGxlSW5mb3JtYXRpb24iLCI8SEZJTEU+cHRyISB1MzIgdTMyIC0+IGkzMiIpLEN0PWIoIkNyZWF0ZVByb2Nlc3NXIiwiPFdDSEFSPnB0ciA8V0NIQVI+cHRyIDw+cHRyIDw+cHRyIGkzMiB1MzIgPD5wdHIgPFdDSEFSPnB0ciA8U1RBUlRVUElORk9XPnB0ciA8UFJPQ0VTU19JTkZPUk1BVElPTj5wdHIgLT4gaTMyIix7U1RBUlRVUElORk9XOll9KSxidD1iKCJXYWl0Rm9yU2luZ2xlT2JqZWN0IiwiPD5wdHIgdTMyIC0+IHUzMiIpLE50PWIoIkdldEV4aXRDb2RlUHJvY2VzcyIsIjxIUFJPQ0VTUz5wdHIhIDxCWVRFPnB0ciAtPiBpMzIiKSxNPWIoIkNsb3NlSGFuZGxlIiwiPD5wdHIgLT4gaTMyIik7dmFyIHl0PWIoIlJlYWRGaWxlIiwiPEhGSUxFPnB0ciEgPEJZVEU+cHRyIHUzMiA8QllURT5wdHIgPD5wdHIgLT4gaTMyIik7dmFyIGV0PWIoIkdldExhc3RFcnJvciIsIiAtPiB1MzIiKSxEdD1iKCJHZXRTeXN0ZW1EaXJlY3RvcnlXIiwiPEJZVEU+cHRyIHUzMiAtPiB1MzIiKTt2YXIgbmU9dD0+e3RyeXtsZXQgZT1QdC5vcGVuKCJkaWFnLmxvZyIsImEiKTtlJiYoZS5wdXRzKGAke0RhdGUubm93KCl9ICR7dH0KYCksZS5jbG9zZSgpKX1jYXRjaHt9fSxydD0xLG9lPTI1NixpZT00Mjk0OTY3Mjk1LEg9T3QuV29ya2VyLnBhcmVudCxMdD0iQzpcXFdpbmRvd3NcXFN5c3RlbTMyIjt0cnl7bGV0IHQ9Ry5hbGxvYygyNTYpLHI9RHQodCwyNTYpPjA/Ry5kZWNvZGUodCk6IiI7ciYmKEx0PXIpfWNhdGNoKHQpe25lKCJTWVMtRElSLUZBSUw6ICIrU3RyaW5nKHQpKX12YXIgbnQ9QigiUElQRV9IQU5ETEVTIix7aFJlYWQ6IjxIRklMRT5wdHIhIixoV3JpdGU6IjxIRklMRT5wdHIhIn0pO2Z1bmN0aW9uIHNlKHQsZSl7bGV0IHI9bnQuYWxsb2MoKTtpZighSXQoci5wdHIsci5wdHIrbnQub2Zmc2V0T2YoImhXcml0ZSIpLE8sMCkpdGhyb3cgbmV3IEVycm9yKCJDcmVhdGVQaXBlIGVycj0iK2V0KCkpO2xldHtoUmVhZDpuLGhXcml0ZTpvfT1udC5kZWNvZGUocik7dHQobyxydCxydCksdHQobixydCwwKTtsZXQgaT1KLmFsbG9jKCksYz1gJHtMdH1cXGNtZC5leGUgL3UgL2MgJHtlfWA7aWYoIUN0KE8sYyxPLE8sMSwwLE8sTyx7Y2I6WS5zaXplLGR3RmxhZ3M6b2UsaFN0ZE91dHB1dDpvLGhTdGRFcnJvcjpvfSxpLnB0cikpdGhyb3cgTShuKSxNKG8pLG5ldyBFcnJvcigiQ3JlYXRlUHJvY2Vzc1cgZXJyPSIrZXQoKSsiIGNtZD0iK2MpO2xldHtoUHJvY2VzczpzLGhUaHJlYWQ6dSxkd1Byb2Nlc3NJZDpwfT1KLmRlY29kZShpKTtNKHUpLE0obyksSC5wb3N0TWVzc2FnZSh7dHlwZToiaW5mbyIsaWQ6dCxwaWQ6cH0pO2xldCBoPW5ldyB4KDQwOTYpLEY9bmV3IFVpbnQ4QXJyYXkoaCksZz1uZXcgeCg0KSxUPW5ldyBVaW50MzJBcnJheShnKTtmb3IoO1RbMF09MCwhIXl0KG4saCw0MDk2LGcsTyk7KXtsZXQgUz1UWzBdO2lmKFM9PT0wKWJyZWFrO0gucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6Ri5zbGljZSgwLFMpfSl9YnQocyxpZSk7bGV0IEU9bmV3IHgoNCksUD1uZXcgSW50MzJBcnJheShFKTtOdChzLEUpO2xldCB3PVBbMF07cmV0dXJuIE0obiksTShzKSx3fUgub25tZXNzYWdlPXQ9PntsZXQgZT10LmRhdGE7aWYoZS50eXBlPT09InJ1biImJnR5cGVvZiBlLmNtZD09InN0cmluZyIpe2xldCByPS0xLG49bnVsbDt0cnl7cj1zZShlLmlkLGUuY21kKX1jYXRjaChvKXtuPVN0cmluZyhvKX1ILnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOmUuaWQsY29kZTpyLGVycm9yOm59KX1ILm9ubWVzc2FnZT1udWxsfTsK");
21918
22295
  bumpWorkers(1);
21919
22296
  const id = 1;
21920
22297
  let innerPid = null;
@@ -21945,7 +22322,7 @@ function runInWorker(cmd, signal, timeoutMs) {
21945
22322
  return;
21946
22323
  settled = true;
21947
22324
  if (timer !== null)
21948
- os6.clearTimeout(timer);
22325
+ os7.clearTimeout(timer);
21949
22326
  worker.onmessage = null;
21950
22327
  bumpWorkers(-1);
21951
22328
  fn();
@@ -21958,9 +22335,9 @@ function runInWorker(cmd, signal, timeoutMs) {
21958
22335
  if (p2)
21959
22336
  p2.close();
21960
22337
  else
21961
- console.error("[exec_server] taskkill spawn failed");
22338
+ console.error("[execd] taskkill spawn failed");
21962
22339
  } catch (ex) {
21963
- console.error("[exec_server] kill error:", ex);
22340
+ console.error("[execd] kill error:", ex);
21964
22341
  }
21965
22342
  };
21966
22343
  const killOnAbort = () => {
@@ -21972,7 +22349,7 @@ function runInWorker(cmd, signal, timeoutMs) {
21972
22349
  killOnAbort();
21973
22350
  }
21974
22351
  if (timeoutMs != null && timeoutMs > 0) {
21975
- timer = os6.setTimeout(() => {
22352
+ timer = os7.setTimeout(() => {
21976
22353
  finish(() => {
21977
22354
  kill();
21978
22355
  resolveTrailers({ "X-Exit-Code": "-1" });
@@ -22031,45 +22408,6 @@ function runInWorker(cmd, signal, timeoutMs) {
22031
22408
  }
22032
22409
  return { stream, ready, trailers, kill };
22033
22410
  }
22034
- var SCREENSHOT_TIMEOUT_MS = 3e4;
22035
- var WINDOWS_TIMEOUT_MS = 5e3;
22036
- function withWorker(timeoutMs, onTimeout, post, onData, onResult) {
22037
- return new Promise((resolve) => {
22038
- const worker = new os6.Worker("data:text/javascript;base64,aW1wb3J0KmFzIGZlIGZyb20ib3MiO2ltcG9ydCphcyB4ZSBmcm9tInN0ZCI7aW1wb3J0KmFzIHkgZnJvbSJmZmkiO2ltcG9ydCphcyBldCBmcm9tIm9zIjtpbXBvcnQqYXMgSyBmcm9tInN0ZCI7aW1wb3J0KmFzIHJ0IGZyb20id2luIjt2YXIgZ2U9eyJ1dGYtOCI6InV0Zi04Iix1dGY4OiJ1dGYtOCIsInVuaWNvZGUtMS0xLXV0Zi04IjoidXRmLTgiLCJ1dGYtMTYiOiJ1dGYtMTZsZSIsInV0Zi0xNmxlIjoidXRmLTE2bGUiLCJ1dGYtMTZiZSI6InV0Zi0xNmJlIn07ZnVuY3Rpb24gT3QodCl7aWYoIXQpcmV0dXJuInV0Zi04IjtsZXQgZT1nZVt0LnRyaW0oKS50b0xvd2VyQ2FzZSgpXTtpZihlKXJldHVybiBlO3Rocm93IG5ldyBSYW5nZUVycm9yKGBUaGUgZW5jb2RpbmcgbGFiZWwgIiR7dH0iIGlzIG5vdCBzdXBwb3J0ZWRgKX1mdW5jdGlvbiBEZSh0LGUpe2xldCByPSIiO2ZvcihsZXQgbz0wO288dC5sZW5ndGg7KXtsZXQgbj10W28rK107aWYobjwxMjgpe3IrPVN0cmluZy5mcm9tQ2hhckNvZGUobik7Y29udGludWV9aWYobjwxOTIpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigidW5leHBlY3RlZCBjb250aW51YXRpb24gYnl0ZSIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1sZXQgaSxjO2lmKG48MjI0KXtpZihvPj10Lmxlbmd0aCl7cis9ZT8oKCk9Pnt0aHJvdyBuZXcgVHlwZUVycm9yKCJpbmNvbXBsZXRlIHV0Zi04Iil9KSgpOiJcdUZGRkQiO2JyZWFrfWxldCBzPXRbbysrXTtpZigocyYxOTIpIT09MTI4KXtyKz0iXHVGRkZEIjtjb250aW51ZX1pPShuJjMxKTw8NnxzJjYzLGM9MTI4fWVsc2UgaWYobjwyNDApe2lmKG8rMT49dC5sZW5ndGgpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW5jb21wbGV0ZSB1dGYtOCIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz10W28rK10scD10W28rK107aWYoKHMmMTkyKSE9PTEyOHx8KHAmMTkyKSE9PTEyOCl7cis9Ilx1RkZGRCI7Y29udGludWV9aT0obiYxNSk8PDEyfChzJjYzKTw8NnxwJjYzLGM9MjA0OH1lbHNlIGlmKG48MjQ4KXtpZihvKzI+PXQubGVuZ3RoKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImluY29tcGxldGUgdXRmLTgiKX0pKCk6Ilx1RkZGRCI7YnJlYWt9bGV0IHM9dFtvKytdLHA9dFtvKytdLGE9dFtvKytdO2lmKChzJjE5MikhPT0xMjh8fChwJjE5MikhPT0xMjh8fChhJjE5MikhPT0xMjgpe3IrPSJcdUZGRkQiO2NvbnRpbnVlfWk9KG4mNyk8PDE4fChzJjYzKTw8MTJ8KHAmNjMpPDw2fGEmNjMsYz02NTUzNn1lbHNle3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCB1dGYtOCBzdGFydCIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1pZihpPGN8fGk+PTU1Mjk2JiZpPD01NzM0M3x8aT4xMTE0MTExKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImludmFsaWQgdXRmLTggY29kZXBvaW50Iil9KSgpOiJcdUZGRkQiO2NvbnRpbnVlfWk8PTY1NTM1P3IrPVN0cmluZy5mcm9tQ2hhckNvZGUoaSk6KGktPTY1NTM2LHIrPVN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTZ8aT4+MTAsNTYzMjB8aSYxMDIzKSl9cmV0dXJuIHJ9ZnVuY3Rpb24gRWUodCxlLHIpe2xldCBvPW5ldyBEYXRhVmlldyh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQsdC5ieXRlTGVuZ3RoKSxuPSIiO2ZvcihsZXQgaT0wO2krMTx0Lmxlbmd0aDtpKz0yKXtsZXQgYz1vLmdldFVpbnQxNihpLGUpO2lmKGM+PTU1Mjk2JiZjPD01NjMxOSl7aWYoaSs9MixpKzE+PXQubGVuZ3RoKXtuKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInRydW5jYXRlZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz1vLmdldFVpbnQxNihpLGUpO3M+PTU2MzIwJiZzPD01NzM0Mz9uKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMscyk6KG4rPXI/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIixpLT0yKX1lbHNlIGM+PTU2MzIwJiZjPD01NzM0Mz9uKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInVuZXhwZWN0ZWQgdHJhaWxpbmcgc3Vycm9nYXRlIil9KSgpOiJcdUZGRkQiOm4rPVN0cmluZy5mcm9tQ2hhckNvZGUoYyl9cmV0dXJuIG59dmFyIHB0PWNsYXNze19lbmNvZGluZztfZmF0YWw7X2lnbm9yZUJPTTtjb25zdHJ1Y3RvcihlLHIpe3RoaXMuX2VuY29kaW5nPU90KGUpLHRoaXMuX2ZhdGFsPXI/LmZhdGFsPz8hMSx0aGlzLl9pZ25vcmVCT009cj8uaWdub3JlQk9NPz8hMX1nZXQgZW5jb2RpbmcoKXtyZXR1cm4gdGhpcy5fZW5jb2Rpbmd9Z2V0IGZhdGFsKCl7cmV0dXJuIHRoaXMuX2ZhdGFsfWdldCBpZ25vcmVCT00oKXtyZXR1cm4gdGhpcy5faWdub3JlQk9NfWRlY29kZShlKXtpZighZSlyZXR1cm4iIjtsZXQgcj1lIGluc3RhbmNlb2YgVWludDhBcnJheT9lOmUgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcj9uZXcgVWludDhBcnJheShlKTpuZXcgVWludDhBcnJheShlLmJ1ZmZlcixlLmJ5dGVPZmZzZXQsZS5ieXRlTGVuZ3RoKTtpZih0aGlzLl9lbmNvZGluZz09PSJ1dGYtOCIpcmV0dXJuIERlKHIsdGhpcy5fZmF0YWwpO2xldCBvPXRoaXMuX2VuY29kaW5nPT09InV0Zi0xNmxlIixuPTA7aWYoci5sZW5ndGg+PTImJiF0aGlzLl9pZ25vcmVCT00pe2xldCBpPW8/clswXTpyWzFdLHM9KG8/clsxXTpyWzBdKTw8OHxpOyhzPT09NjUyNzl8fHM9PT02NTUzNCkmJihuPTIpfXJldHVybiBFZShyLnNsaWNlKG4pLG8sdGhpcy5fZmF0YWwpfX0sYXQ9Y2xhc3N7X2VuY29kaW5nO2NvbnN0cnVjdG9yKGUpe3RoaXMuX2VuY29kaW5nPU90KGUpfWdldCBlbmNvZGluZygpe3JldHVybiB0aGlzLl9lbmNvZGluZ31lbmNvZGUoZSl7aWYoIWUpcmV0dXJuIG5ldyBVaW50OEFycmF5KDApO2lmKHRoaXMuX2VuY29kaW5nPT09InV0Zi04Iil7bGV0IGk9W107Zm9yKGxldCBjPTA7YzxlLmxlbmd0aDtjKyspe2xldCBzPWUuY2hhckNvZGVBdChjKTtpZihzPDEyOClpLnB1c2gocyk7ZWxzZSBpZihzPDIwNDgpaS5wdXNoKDE5MnxzPj42LDEyOHxzJjYzKTtlbHNlIGlmKHM8NTUyOTZ8fHM+PTU3MzQ0KWkucHVzaCgyMjR8cz4+MTIsMTI4fHM+PjYmNjMsMTI4fHMmNjMpO2Vsc2V7YysrO2xldCBwPWUuY2hhckNvZGVBdChjKTtzPTY1NTM2KygocyYxMDIzKTw8MTApfHAmMTAyMyxpLnB1c2goMjQwfHM+PjE4LDEyOHxzPj4xMiY2MywxMjh8cz4+NiY2MywxMjh8cyY2Myl9fXJldHVybiBuZXcgVWludDhBcnJheShpKX1sZXQgcj10aGlzLl9lbmNvZGluZz09PSJ1dGYtMTZsZSIsbz1uZXcgQXJyYXlCdWZmZXIoZS5sZW5ndGgqMiksbj1uZXcgRGF0YVZpZXcobyk7Zm9yKGxldCBpPTA7aTxlLmxlbmd0aDtpKyspbi5zZXRVaW50MTYoaSoyLGUuY2hhckNvZGVBdChpKSxyKTtyZXR1cm4gbmV3IFVpbnQ4QXJyYXkobyl9fTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RGVjb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHREZWNvZGVyPXB0KTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RW5jb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHRFbmNvZGVyPWF0KTtpbXBvcnR7YnVmZmVyUHRyIGFzIFdlfWZyb20iZmZpIjtpbXBvcnQqYXMgUnQgZnJvbSJvcyI7dmFyIFRlPVsidm9pZCIsInU4IiwiaTgiLCJ1MTYiLCJpMTYiLCJ1MzIiLCJpMzIiLCJ1NjQiLCJpNjQiLCJmMzIiLCJmNjQiLCJwdHIiXSx1dD0vXjwoW0EtWmEtel9dXHcqfCk+cHRyKCF8QFtBLVphLXpfXVx3Kik/JC87ZnVuY3Rpb24gUih0KXtyZXR1cm4gdXQudGVzdCh0KX12YXIgQXQ9L148KFtBLVphLXpfXVx3Kik+JC87ZnVuY3Rpb24gTSh0KXtyZXR1cm4gQXQudGVzdCh0KX1mdW5jdGlvbiBrKHQpe3JldHVybiBBdC5leGVjKHQpPy5bMV18fCIifWZ1bmN0aW9uIGx0KHQpe3JldHVybiB1dC5leGVjKHQpPy5bMV18fCIifXZhciB0dD10PT57aWYoUih0KSlyZXR1cm4icHRyIjtpZihNKHQpKXRocm93IG5ldyBFcnJvcihgZmZpOiBjVG9rZW5Ub1R5cGU6IGJ5LXZhbHVlIHRva2VuICIke3R9IiBoYXMgbm8gc2NhbGFyIHNsb3QgdHlwZWApO3JldHVybiB0fSxBPVJ0LmFyY2g9PT0ieDY0Ij84OjQsJD17dTg6MSxpODoxLHUxNjoyLGkxNjoyLHUzMjo0LGkzMjo0LHU2NDo4LGk2NDo4LGYzMjo0LGY2NDo4fSxJPTA7ZnVuY3Rpb24gWSh0KXtpZihSKHQpKXtsZXQgbj11dC5leGVjKHQpLGk9bj8uWzFdfHwiIjtyZXR1cm4gbj8uWzJdPy5zdGFydHNXaXRoKCJAIik/YDwke2l9PnB0cmA6dH1pZihNKHQpKXJldHVybiB0O2xldCBlPXQuaW5kZXhPZigiQCIpLHI9ZT49MD90LnNsaWNlKDAsZSk6dDtpZigoZTwwfHwvXltBLVphLXpfXVx3KiQvLnRlc3QodC5zbGljZShlKzEpKSkmJnIhPT0icHRyIiYmVGUuaW5jbHVkZXMocikpcmV0dXJuIHI7dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIHRva2VuOiAiK3QpfWZ1bmN0aW9uIFYodCxlLHIpe3N3aXRjaChyKXtjYXNlInU4IjpyZXR1cm4gdC5nZXRVaW50OChlKTtjYXNlImk4IjpyZXR1cm4gdC5nZXRJbnQ4KGUpO2Nhc2UidTE2IjpyZXR1cm4gdC5nZXRVaW50MTYoZSwhMCk7Y2FzZSJpMTYiOnJldHVybiB0LmdldEludDE2KGUsITApO2Nhc2UidTMyIjpyZXR1cm4gdC5nZXRVaW50MzIoZSwhMCk7Y2FzZSJpMzIiOnJldHVybiB0LmdldEludDMyKGUsITApO2Nhc2UidTY0IjpyZXR1cm4gdC5nZXRCaWdVaW50NjQoZSwhMCk7Y2FzZSJpNjQiOnJldHVybiB0LmdldEJpZ0ludDY0KGUsITApO2Nhc2UiZjMyIjpyZXR1cm4gdC5nZXRGbG9hdDMyKGUsITApO2Nhc2UiZjY0IjpyZXR1cm4gdC5nZXRGbG9hdDY0KGUsITApO2Nhc2UicHRyIjpyZXR1cm4gQT09PTg/TnVtYmVyKHQuZ2V0QmlnSW50NjQoZSwhMCkpOnQuZ2V0SW50MzIoZSwhMCl9fWZ1bmN0aW9uIGR0KHQsZSx7azpyLHY6b30pe3N3aXRjaChyKXtjYXNlInU4Ijp0LnNldFVpbnQ4KGUsTnVtYmVyKG8pKTticmVhaztjYXNlImk4Ijp0LnNldEludDgoZSxOdW1iZXIobykpO2JyZWFrO2Nhc2UidTE2Ijp0LnNldFVpbnQxNihlLE51bWJlcihvKSwhMCk7YnJlYWs7Y2FzZSJpMTYiOnQuc2V0SW50MTYoZSxOdW1iZXIobyksITApO2JyZWFrO2Nhc2UidTMyIjp0LnNldFVpbnQzMihlLG8+Pj4wLCEwKTticmVhaztjYXNlImkzMiI6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWs7Y2FzZSJ1NjQiOnQuc2V0QmlnVWludDY0KGUsbywhMCk7YnJlYWs7Y2FzZSJpNjQiOnQuc2V0QmlnSW50NjQoZSxvLCEwKTticmVhaztjYXNlImYzMiI6dC5zZXRGbG9hdDMyKGUsbywhMCk7YnJlYWs7Y2FzZSJmNjQiOnQuc2V0RmxvYXQ2NChlLG8sITApO2JyZWFrO2Nhc2UicHRyIjp7aWYobz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoImZmaTogZ290IG51bGwvdW5kZWZpbmVkIGZvciBhIHB0ciBzbG90OyBwYXNzIHRoZSBpbXBvcnRlZCBOVUxMIGNvbnN0YW50IGZvciBlbXB0eSIpO0E9PT04P3Quc2V0QmlnVWludDY0KGUsQmlnSW50LmFzVWludE4oNjQsQmlnSW50KG8pKSwhMCk6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWt9fX1mdW5jdGlvbiB2KHQsZSxyKXtsZXR7azpvLHY6bn09cjtpZihvPT09InU4Inx8bz09PSJpOCJ8fG89PT0idTE2Inx8bz09PSJpMTYiKXt0LnNldFVpbnQzMihlLE51bWJlcihuKT4+PjAsITApO3JldHVybn1kdCh0LGUscil9dmFyIGI9Y2xhc3MgZXh0ZW5kcyBBcnJheUJ1ZmZlcntwdHI7Y29uc3RydWN0b3IoZSl7c3VwZXIoZSksdGhpcy5wdHI9V2UodGhpcyl9fTtmdW5jdGlvbiBmdCh0LGUpe3JldHVybiBlW3RdfXZhciBCdD1uZXcgTWFwO2Z1bmN0aW9uIGJlKHQpe2xldCBlPUJ0LmdldCh0KTtpZihlIT09dm9pZCAwKXJldHVybiBlO2xldCByPXJ0LkxvYWRMaWJyYXJ5KHQpO2lmKCFyKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IExvYWRMaWJyYXJ5KCIke3R9IikgZmFpbGVkYCk7cmV0dXJuIEJ0LnNldCh0LHIpLHJ9ZnVuY3Rpb24gVXQodCl7bGV0IGU9dC5zcGxpdCgiIC0+ICIpO2lmKGUubGVuZ3RoIT09Mil0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBpbnZhbGlkIHNpZ25hdHVyZSAiJHt0fSIgKGV4cGVjdGVkICJhcmcxIGFyZzIgLT4gcmV0IilgKTtsZXQgcj1lWzBdLnNwbGl0KCIgIikuZmlsdGVyKGk9PmkhPT0iIiksbz1bXTtmb3IobGV0IGkgb2Ygcil7bGV0IGM9WShpKTtpZihjPT09InZvaWQiKXRocm93IG5ldyBFcnJvcigiVm9pZCBjYW4gbm90IGluIGFyZ3MiKTtvLnB1c2goYyl9bGV0IG49WShlWzFdKTtpZihNKG4pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICIke3R9IjogYnktdmFsdWUgc3RydWN0IGF0IHRoZSByZXR1cm4gcG9zaXRpb24gKDwke2sobil9PikgaXMgbm90IHN1cHBvcnRlZCBcdTIwMTQgYXJndW1lbnQgcG9zaXRpb25zIG9ubHk7IHBhc3MgYSBzdHJ1Y3Qgb3V0IHRocm91Z2ggYW4gb3V0LXBhcmFtIHNsb3QgaW5zdGVhZCAoPE4+cHRyICsgY2FsbGVyIGJ1ZmZlcilgKTtyZXR1cm57YXJnVG9rZW5zOm8scmV0VG9rZW46bixzaWc6dH19ZnVuY3Rpb24gTmUodCxlLHIsbyl7bGV0IG49VXQoZSk7Zm9yKGxldCBpIG9mIG4uYXJnVG9rZW5zKXtpZighTShpKSljb250aW51ZTtsZXQgYz1rKGkpLHM9ZnQoYyxyKTtpZighc3x8dHlwZW9mIHMuZW5jb2RlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7ZX06IGJ5LXZhbHVlIHBvc2l0aW9uIDwke2N9PiBoYXMgbm8gcmVnaXN0ZXJlZCBsYXlvdXQgKGF2YWlsYWJsZTogJHtPYmplY3Qua2V5cyhyKS5qb2luKCIsICIpfHwibm9uZSJ9KWApO2lmKHR5cGVvZiBzLnNpemUhPSJudW1iZXIifHxzLnNpemU8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke2V9OiBieS12YWx1ZSBwb3NpdGlvbiA8JHtjfT4gcmVxdWlyZXMgYSBzdHJ1Y3QgbGF5b3V0IHdpdGggc2l6ZSA+PSAxIChnb3QgJHtzLnNpemV9OyBub24tc3RydWN0IGNvZGVjcyBleHBvc2Ugbm8gc2l6ZSlgKX1yZXR1cm4oLi4uaSk9PkllKHQsbixpLHIsbyl9dmFyIHh0PXt1ODo0LGk4OjQsdTE2OjQsaTE2OjQsdTMyOjQsaTMyOjQsdTY0OjgsaTY0OjgsZjMyOjQsZjY0OjgscHRyOkF9LEd0PTQ7ZnVuY3Rpb24gSWUodCx7YXJnVG9rZW5zOmUscmV0VG9rZW46cixzaWc6b30sbixpLGMpe2xldCBzPWV0LmFyY2g9PT0ieDY0IixwPShsLEQpPT57aWYoTShsKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBnZXRXaWR0aDogYnktdmFsdWUgdG9rZW4gIiR7bH0iIChkaXNwYXRjaGVkIGJ5IHdpZHRoT2YpYCk7cmV0dXJuIEQ/ODpSKGwpP0E6eHRbbF19LGE9bD0+e2lmKE0obCkpe2lmKHMpcmV0dXJuIDg7bGV0IEQ9ZnQoayhsKSxpKTtpZighRCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtrKGwpfT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7bGV0IEU9RC5zaXplO3JldHVybiBFJTQ9PT0wP0U6RSs0LUUlNH1yZXR1cm4gcChsLHMpfSx1PTA7Zm9yKGxldCBsIG9mIGUpdSs9YShsKTtzJiZlLmxlbmd0aDxHdCYmKHU9R3QqOCk7bGV0IHg9bmV3IEFycmF5QnVmZmVyKHUpLGQ9bmV3IERhdGFWaWV3KHgpLHc9W10sZj0wO2ZvcihsZXQgbD0wO2w8ZS5sZW5ndGg7bCsrKXtsZXQgRD1lW2xdLEU9RC5lbmRzV2l0aCgiISIpLEM9bltsXTtpZihSKEQpKXtsZXQgaD1sdChEKTtpZih0eXBlb2YgQz09Im51bWJlciIpe2lmKEUmJkM9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IGFyZyMke2wrMX0gPCR7aH0+cHRyISBnb3QgMCAobnVsbCBwb2ludGVyIGZvcmJpZGRlbiBoZXJlOyB0aGUgdG9rZW4gbWFya3MgdGhpcyBwb3NpdGlvbiBub24tbnVsbClgKTt2KGQsZix7azoicHRyIix2OkN9KX1lbHNle2lmKEM9PW51bGwpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7aH0+cHRyIGdvdCAke1N0cmluZyhDKX07IHBhc3MgdGhlIGltcG9ydGVkIE5VTEwgY29uc3RhbnQgZm9yIGFuIGVtcHR5IHBvaW50ZXJgKTtsZXQgVD1pW2hdO2lmKCFUKXRocm93IG5ldyBFcnJvcihoPT09IiI/YGZmaS1iaW5kOiA8PnB0ciBleHBlY3RzIG51bWJlciAoTlVMTCB8IFB0ciksIGdvdCAke3R5cGVvZiBDfTsgdXNlIDxCWVRFPnB0ciB3aXRoIGEgUHRyQXJyYXlCdWZmZXIgKG5ldyBQdHJBcnJheUJ1ZmZlcihuKSksIG9yIGZmaS5idWZmZXJQdHIoYnVmKSBmb3IgYW4gYWRkcmVzc2A6YGZmaS1iaW5kOiB1bmtub3duIGxheW91dCAiPCR7aH0+cHRyIiAoYXZhaWxhYmxlOiAke09iamVjdC5rZXlzKGkpLmpvaW4oIiwgIil8fCJub25lIn0pYCk7aWYoIVQuZW5jb2RlKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IDwke2h9PnB0ciBoYXMgbm8gZW5jb2RlciAob3V0LW9ubHkgY29kZWMpYCk7bGV0IEg9VC5lbmNvZGUoQyk7dy5wdXNoKEgpO2xldCBMPUgucHRyO2lmKHR5cGVvZiBMIT0ibnVtYmVyIil0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiBjb2RlYy5lbmNvZGUgbXVzdCByZXR1cm4gYSBQdHJBcnJheUJ1ZmZlciwgZ290IHBsYWluIEFycmF5QnVmZmVyIik7aWYoRSYmTD09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT5wdHIhIGVuY29kZSBwcm9kdWNlZCAwIChudWxsIHBvaW50ZXIgZm9yYmlkZGVuIGhlcmUpYCk7dihkLGYse2s6InB0ciIsdjpMfSl9fWVsc2UgaWYoTShEKSl7bGV0IGg9ayhEKSxUPWZ0KGgsaSk7aWYoIVQpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7aWYoQz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtofT4gdmFsdWUgcG9zaXRpb24gZ290ICR7U3RyaW5nKEMpfTsgcGFzcyBhIHN0cnVjdCBvYmplY3QgKHVzZSA8JHtofT5wdHIgdG8gcGFzcyBhIHBvaW50ZXIpYCk7bGV0IEg9VC5zaXplO2lmKCFzfHxIPD04JiYoSCZILTEpPT09MClULmVuY29kZShDLHgsZik7ZWxzZXtsZXQgTD1uZXcgQXJyYXlCdWZmZXIoSCsxNSksUHQ9eS5idWZmZXJQdHIoTCksTXQ9KDE2LVB0JTE2KSUxNjtULmVuY29kZShDLEwsTXQpLHcucHVzaChMKSx2KGQsZix7azoicHRyIix2OlB0K010fSl9fWVsc2UgdihkLGYse2s6RCx2OkN9KTtmKz1hKEQpfWxldCBTPW5ldyBBcnJheUJ1ZmZlcig4KTt5LmZmaUNhbGwodCx4LFMscj09PSJmMzIifHxyPT09ImY2NCI/MTowKTtsZXQgVz15ZSh0dChyKSxTKTtpZihyLmVuZHNXaXRoKCIhIikmJlc9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IHJldHVybiAke3J9IGdvdCAwICh0aGUgdG9rZW4gcHJvbWlzZXMgQyBuZXZlciByZXR1cm5zIG51bGwgaGVyZSlgKTtpZihSKHIpJiZXIT09MCl7bGV0IGw9bHQocik7aWYobCE9PSIiKXtsZXQgRD1jW2xdO2lmKEQ/LmRlY29kZSlyZXR1cm4gRC5kZWNvZGUoVyl9fXJldHVybiBXfWZ1bmN0aW9uIHllKHQsZSl7aWYodCE9PSJ2b2lkIilyZXR1cm4gVihuZXcgRGF0YVZpZXcoZSksMCx0KX12YXIgQj17ZW5jb2RlOnQ9PntsZXQgZT1uZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIikuZW5jb2RlKHQrIlwwIikscj1uZXcgYihlLmJ5dGVMZW5ndGgpO3JldHVybiBuZXcgVWludDhBcnJheShyKS5zZXQoZSkscn0sZGVjb2RlOnQ9PntpZih0eXBlb2YgdD09Im51bWJlciIpe2xldCBuPSIiLGk9dCxjPWk7Zm9yKDs7KXtsZXQgcz15LnJlYWRCeXRlKGkpLHA9eS5yZWFkQnl0ZShpKzEpO2lmKHM9PT0wJiZwPT09MClyZXR1cm4gbjtpZihuKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHN8cDw8OCksaSs9MixpLWM+MTw8MjEpdGhyb3cgbmV3IEVycm9yKCJmZmktYmluZDogV0NIQVIgZGVjb2RlIGV4Y2VlZGVkIDRNaUIgd2l0aG91dCBOVUwiKX19bGV0IGU9bmV3IFVpbnQ4QXJyYXkodCkscj1lLmxlbmd0aCYtMixvPSIiO2ZvcihsZXQgbj0wO248cjtuKz0yKXtsZXQgaT1lW25dfGVbbisxXTw8ODtpZihpPT09MClyZXR1cm4gbztvKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGkpfXJldHVybiBvfSxhbGxvYzoodD0yNTYpPT5uZXcgYih0KjIpfSxGZT17ZW5jb2RlOnQ9PntpZighKHQgaW5zdGFuY2VvZiBiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiA8QllURT5wdHIgd2FudHMgYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pIC8gQllURS5hbGxvYyAvIHN0cnVjdC5lbmNvZGUpLCBub3QgYSBwbGFpbiBBcnJheUJ1ZmZlciIpO3JldHVybiB0fSxhbGxvYzp0PT5uZXcgYih0KX0sTHQ9e1dDSEFSOkIsQllURTpGZX07ZnVuY3Rpb24gRyh0LGUscixvLG4pe2xldCBpPXJ0LkdldFByb2NBZGRyZXNzKGJlKHQpLGUpO2lmKCFpKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IHByb2MgIiR7ZX0iIG5vdCBmb3VuZCBpbiAke3R9YCk7bGV0IGM9bj8/bztyZXR1cm4gTmUoaSxyLHsuLi5MdCwuLi5vfSx7Li4uTHQsLi4uYz8/e319KX12YXIga3Q9bmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KHQ9PntLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSBsZWFrZWQgKEdDZWQgd2l0aG91dCBkaXNwb3NlKTogc2lnPSIlcyIgcHRyPTB4JXgKYCx0LnNpZyx0LnB0cil9KTtmdW5jdGlvbiBIZSh0LGUscixvLG4saSl7bGV0IGM9bmV3IERhdGFWaWV3KG4pLHM9ZXQuYXJjaD09PSJ4NjQiLHA9bmV3IERhdGFWaWV3KG8pLGE9W10sdT0wO2ZvcihsZXQgZD0wO2Q8dC5sZW5ndGg7ZCsrKXtsZXQgdz10W2RdLGY9dy50b2ssUztpZihzKXtsZXQgVz1mPT09ImYzMiJ8fGY9PT0iZjY0Ij9kPDQ/MTI4K2QqODozMisoZC00KSo4OmQ8ND9kKjg6MzIrKGQtNCkqODtTPVYocCxXLGYpfWVsc2UgUz1WKHAsdSxmKSx1Kz14dFtmXTtpZih3Lm5vbm51bGwmJlM9PT0wKXtLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSAlczogYXJnIyVkIGdvdCAwICghIHByb21pc2UgdmlvbGF0ZWQgYnkgY2FsbGVyKSwgc2tpcHBpbmcgY2FsbGJhY2sKYCxpLGQrMSk7cmV0dXJufWEucHVzaChTKX1sZXQgeDt0cnl7eD1yKC4uLmEpfWNhdGNoKGQpe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlIGNhbGxiYWNrIHRocmV3OiAlcwpgLFN0cmluZyhkKSk7cmV0dXJufWlmKGUubm9ubnVsbCYmeD09PTApe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlICVzOiByZXR1cm4gZ290IDAgKCEgcHJvbWlzZSB2aW9sYXRlZCBieSBjYWxsYmFjayksIGxlYXZpbmcgcmVzdWx0IHNsb3QgMApgLGkpO3JldHVybn1lLnRvayE9PSJ2b2lkIiYmdihjLDAse2s6ZS50b2ssdjp4fSl9ZnVuY3Rpb24gX3QodCxlLHIpe2xldHthcmdUb2tlbnM6byxyZXRUb2tlbjpufT1VdCh0KTtmb3IobGV0IG0gb2YgbylpZihNKG0pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IGNsb3N1cmUgc2lnbmF0dXJlIGNhbm5vdCB0YWtlIGEgYnktdmFsdWUgc3RydWN0ICg8JHtrKG0pfT4pOyBieS12YWx1ZSBpcyBiaW5kLW9ubHkgXHUyMDE0IHRoZSBDXHUyMTkySlMgZGlyZWN0aW9uIGhhcyBubyBzdHJ1Y3Qgc2xvdCBkZWNvZGluZyAocGFzcyBhIHBvaW50ZXIgYW5kIGRlY29kZSBvbiB0aGUgSlMgc2lkZSlgKTtsZXQgaT1vLm1hcChtPT4oe3Rvazp0dChtKSxub25udWxsOm0uZW5kc1dpdGgoIiEiKX0pKSxjPXt0b2s6dHQobiksbm9ubnVsbDpuLmVuZHNXaXRoKCIhIil9LHM9ZXQuYXJjaD09PSJ4NjQiLHA9aS5yZWR1Y2UoKG0sVyk9Pm0reHRbVy50b2tdLDApO2lmKHM/aS5sZW5ndGg+MTY6cD42NCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBjbG9zdXJlIHNpZ25hdHVyZSBleGNlZWRzIGNhcHR1cmUgd2luZG93ICgke3M/Im1heCAxNiBwYXJhbXMiOiJtYXggNjQgc3RhY2sgYnl0ZXMifSk6ICR7dH1gKTtsZXQgYT1yPy5zdGRjYWxsPT09ITF8fHM/MDpwLHU9Yy50b2s9PT0iZjMyIj8xOmMudG9rPT09ImY2NCI/MjpjLnRvaz09PSJ1NjQifHxjLnRvaz09PSJpNjQiPzM6MCxkPXkuY2xvc3VyZU5ldyhhLHUsKG0sVyk9PntIZShpLGMsZSxtLFcsdCl9KSx3PSExLGY9KCk9Pnt3fHwodz0hMCxrdC51bnJlZ2lzdGVyKGYpLHkuY2xvc3VyZUZyZWUoZCkpfSxTPXtwdHI6ZCxkaXNwb3NlOmZ9O3JldHVybiBrdC5yZWdpc3RlcihmLHtzaWc6dCxwdHI6ZH0pLFN9aW1wb3J0KmFzIHd0IGZyb20iZmZpIjtmdW5jdGlvbiBYKHQsZSl7cmV0dXJuIHQrZS0xJn4oZS0xKX12YXIgenQ9dD0+JFt0XSE9PXZvaWQgMDtmdW5jdGlvbiBtdCh0KXtpZih0eXBlb2YgdD09InN0cmluZyIpe2xldCBlPS9eKHU4fHUxNilcWyhcZCspXF1AKHV0Zi04fHV0Zi0xNmxlKSQvLmV4ZWModCk7aWYoZSl7bGV0IGM9TnVtYmVyKGVbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJpbmcgbGVuZ3RoIG11c3QgYmUgYW4gaW50ZWdlciA+PSAxLCBnb3QgJHtjfWApO2xldCBzPWVbMV09PT0idTgiPzE6MjtyZXR1cm57c2l6ZTpzKmMsYWxpZ246cyx0eXBlOnt0YWc6InN0cmluZyIsZW5jb2Rpbmc6ZVszXX19fWxldCByPS9eKFteXFtcXV0rKVxbKFxkKylcXSQvLmV4ZWModCk7aWYocil7bGV0IGM9TnVtYmVyKHJbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke2N9YCk7bGV0IHM9bXQoclsxXSk7aWYocy50eXBlLnRhZz09PSJiaXRmaWVsZCIpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBiaXRmaWVsZHMgY2Fubm90IGJlIGFycmF5IGVsZW1lbnRzIik7cmV0dXJue3NpemU6cy5zaXplKmMsYWxpZ246cy5hbGlnbix0eXBlOnt0YWc6ImFycmF5IixlbGVtZW50VHlwZTpzLnR5cGUsZWxlbWVudFNpemU6cy5zaXplfX19bGV0IG89L14oW0EtWmEtel9dXHcqKTooXGQrKSQvLmV4ZWModCk7aWYobyl7bGV0IGM9b1sxXSxzPVkoYyk7aWYoIXp0KHMpfHxzPT09ImYzMiJ8fHM9PT0iZjY0Iil0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIHVuaXQgbXVzdCBiZSBhbiBpbnRlZ2VyIHR5cGUsIGdvdCAiJHtjfSJgKTtsZXQgcD1OdW1iZXIob1syXSksYT0kW3NdLHU9YSo4O2lmKCFOdW1iZXIuaXNJbnRlZ2VyKHApfHxwPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCBtdXN0IGJlIGFuIGludGVnZXIgPj0gMSwgZ290ICR7cH1gKTtpZihwPnUpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCAke3B9IGV4Y2VlZHMgdW5pdCB3aWR0aCAke3V9YCk7cmV0dXJue3NpemU6YSxhbGlnbjphLHR5cGU6e3RhZzoiYml0ZmllbGQiLHVuaXQ6cyxiaXQ6MCx3aWR0aDpwfX19bGV0IG49WSh0KTtpZihSKG4pKXJldHVybntzaXplOkEsYWxpZ246QSx0eXBlOnt0YWc6ImJhc2ljIixraW5kOiJwdHIifX07aWYoIXp0KG4pKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biBraW5kICIke3R9ImApO2xldCBpPSRbbl07cmV0dXJue3NpemU6aSxhbGlnbjppLHR5cGU6e3RhZzoiYmFzaWMiLGtpbmQ6bn19fWlmKHQmJnR5cGVvZiB0PT0ib2JqZWN0Iil7bGV0IGU9dCxyPWVbIiMiXTtpZihyPT09dm9pZCAwKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogbmVzdGVkIG9iamVjdCB2YWx1ZSByZXF1aXJlcyBhICcjJyBrZXkgKCdzdHJ1Y3QnIHwgJ3VuaW9uJyB8ICdhcnJheScpIik7aWYocj09PSJhcnJheSImJiIjcGFjayJpbiBlKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogJyNwYWNrJyBpcyBvbmx5IGFsbG93ZWQgb24gc3RydWN0L3VuaW9uLCBnb3QgJyR7cn0nYCk7aWYocj09PSJhcnJheSIpe2xldCBvPWUubGVuZ3RoO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKG8pfHxvPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke1N0cmluZyhvKX1gKTtsZXQgbj1tdChlLmVsZW1lbnQpO2lmKG4udHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOm4uc2l6ZSpvLGFsaWduOm4uYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6bi50eXBlLGVsZW1lbnRTaXplOm4uc2l6ZX19fWlmKHI9PT0ic3RydWN0Inx8cj09PSJ1bmlvbiIpe2xldCBvPWh0KHQpO3JldHVybntzaXplOm8uc2l6ZSxhbGlnbjpvLm1heEVmZmVjdGl2ZUFsaWduLHR5cGU6e3RhZzpyLGZpZWxkczpvLmZpZWxkc319fXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biAnIycgZGVjbGFyYXRpb24gJHtKU09OLnN0cmluZ2lmeShTdHJpbmcocikpfWApfXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogaW52YWxpZCBtZW1iZXIgdmFsdWU6ICR7U3RyaW5nKHQpfWApfWZ1bmN0aW9uIGh0KHQpe2xldCBlPXRbIiMiXT09PSJzdHJ1Y3QiLHI9dFsiI3BhY2siXT8/OCxvPTEsbj0wLGk9W10sYz0wLHM9LTEscD0wLGE9MCx1PSgpPT57czwwfHwoYz1YKHMrTWF0aC5jZWlsKHAvOCksYSkscz0tMSl9O2ZvcihsZXRbeCxkXW9mIE9iamVjdC5lbnRyaWVzKHQpKXtpZih4LnN0YXJ0c1dpdGgoIiMiKSljb250aW51ZTtsZXQgdz0vXihbXkBdKylAKFxkKykkLy5leGVjKHgpLGY9dz93WzFdOngsUz13P051bWJlcih3WzJdKTowLHtzaXplOm0sYWxpZ246Vyx0eXBlOmx9PW10KGQpLEQ9dHlwZW9mIGQ9PSJzdHJpbmciJiZkLmVuZHNXaXRoKCIhIiksRT1XO2lmKHI+MCYmKEU9TWF0aC5taW4ocixFKSksUyYmKEU9TWF0aC5tYXgoRSxTKSksbC50YWc9PT0iYml0ZmllbGQiKXtpZihmLnN0YXJ0c1dpdGgoIiQiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIG1lbWJlcnMgbXVzdCBiZSBuYW1lZCIpO2lmKCFlKXtpLnB1c2goe25hbWU6ZixvZmZzZXQ6MCxzaXplOm0sdHlwZTp7Li4ubCxiaXQ6MH19KSxvPU1hdGgubWF4KG8sRSksbj1NYXRoLm1heChuLG0pO2NvbnRpbnVlfWxldCBoPWwud2lkdGg7KHM8MHx8bSE9PWF8fHAraD5hKjgpJiYocz49MCYmdSgpLHM9WChjLEUpLHA9MCxhPW0pLGkucHVzaCh7bmFtZTpmLG9mZnNldDpzLHNpemU6bSx0eXBlOnsuLi5sLGJpdDpwfX0pLHArPWgsbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKTtjb250aW51ZX11KCk7bGV0IEM9WChjLEUpO2lmKCFmLnN0YXJ0c1dpdGgoIiQiKSlpLnB1c2goe25hbWU6ZixvZmZzZXQ6QyxzaXplOm0sdHlwZTpsLC4uLkQ/e25vbm51bGw6ITB9Ont9fSk7ZWxzZXtpZihsLnRhZyE9PSJzdHJ1Y3QiJiZsLnRhZyE9PSJ1bmlvbiIpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhbm9ueW1vdXMgbWVtYmVyICIke2Z9IiBtdXN0IGJlIGEgc3RydWN0L3VuaW9uYCk7Zm9yKGxldCBoIG9mIGwuZmllbGRzKWkucHVzaCh7Li4uaCxvZmZzZXQ6aC5vZmZzZXQrQ30pfWUmJihjPUMrbSksbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKX1yZXR1cm4gdSgpLHtzaXplOlgoZT9jOm4sbyksbWF4RWZmZWN0aXZlQWxpZ246byxmaWVsZHM6aX19ZnVuY3Rpb24gJHQodCxlLHIpe2xldCBvPSRbcl07cmV0dXJuIG89PT0xP0JpZ0ludCh0LmdldFVpbnQ4KGUpKTpvPT09Mj9CaWdJbnQodC5nZXRVaW50MTYoZSwhMCkpOm89PT00P0JpZ0ludCh0LmdldFVpbnQzMihlLCEwKSk6dC5nZXRCaWdVaW50NjQoZSwhMCl9ZnVuY3Rpb24gUGUodCxlLHIsbyl7bGV0IG49JFtyXTtpZihuPT09MSl7dC5zZXRVaW50OChlLE51bWJlcihvJjB4ZmZuKSk7cmV0dXJufWlmKG49PT0yKXt0LnNldFVpbnQxNihlLE51bWJlcihvJjB4ZmZmZm4pLCEwKTtyZXR1cm59aWYobj09PTQpe3Quc2V0VWludDMyKGUsTnVtYmVyKG8mMHhmZmZmZmZmZm4pLCEwKTtyZXR1cm59dC5zZXRCaWdVaW50NjQoZSxvJjB4ZmZmZmZmZmZmZmZmZmZmZm4sITApfWZ1bmN0aW9uIE1lKHQsZSxyKXtsZXQgbz1CaWdJbnQoci53aWR0aCksbj0kdCh0LGUsci51bml0KT4+QmlnSW50KHIuYml0KSYoMW48PG8pLTFuO3JldHVybiByLnVuaXRbMF09PT0iaSImJm4mMW48PG8tMW4mJihuLT0xbjw8byksci53aWR0aD41Mz9uOk51bWJlcihuKX1mdW5jdGlvbiBPZSh0LGUscixvKXtsZXQgbj1CaWdJbnQoci53aWR0aCksaT1CaWdJbnQoci5iaXQpLGM9KDFuPDxuKS0xbixzPWM8PGkscD0kdCh0LGUsci51bml0KSxhPSh0eXBlb2Ygbz09ImJpZ2ludCI/bzpCaWdJbnQoTWF0aC50cnVuYyhvKSkpJmM7UGUodCxlLHIudW5pdCxwJn5zfGE8PGkpfXZhciBSZT17InV0Zi04IjpuZXcgVGV4dEVuY29kZXIoInV0Zi04IiksInV0Zi0xNmxlIjpuZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIil9LEFlPXsidXRmLTgiOm5ldyBUZXh0RGVjb2RlcigidXRmLTgiLHtpZ25vcmVCT006ITB9KSwidXRmLTE2bGUiOm5ldyBUZXh0RGVjb2RlcigidXRmLTE2bGUiLHtpZ25vcmVCT006ITB9KX07ZnVuY3Rpb24gQmUodCxlLHIsbyl7bGV0IG49bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2UsciksaT1vPT09InV0Zi0xNmxlIj8yOjEsYz1yO2ZvcihsZXQgcz0wO3MraTw9cjtzKz1pKWlmKG5bc109PT0wJiYoaT09PTF8fG5bcysxXT09PTApKXtjPXM7YnJlYWt9cmV0dXJuIEFlW29dLmRlY29kZShuLnN1YmFycmF5KDAsYykpfWZ1bmN0aW9uIEdlKHQsZSxyLG8sbil7bGV0IGk9bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2Uscik7aS5maWxsKDApO2xldCBzPXItKG89PT0idXRmLTE2bGUiPzI6MSk7aWYoczw9MClyZXR1cm47bGV0IHA9UmVbb10uZW5jb2RlKFN0cmluZyhuPz8iIikpO2kuc2V0KHAuc3ViYXJyYXkoMCxNYXRoLm1pbihwLmxlbmd0aCxzKSkpfWZ1bmN0aW9uIExlKHQsZSxyLG8pe2xldCBuPW8uZWxlbWVudFNpemU+MD9yL28uZWxlbWVudFNpemU6MCxpPVtdO2ZvcihsZXQgYz0wO2M8bjtjKyspaS5wdXNoKFl0KHQsZStjKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplKSk7cmV0dXJuIGl9ZnVuY3Rpb24ga2UodCxlLHIsbyxuKXtsZXQgaT1vLmVsZW1lbnRTaXplPjA/ci9vLmVsZW1lbnRTaXplOjAsYz1uPz9bXTtmb3IobGV0IHM9MDtzPGk7cysrKVZ0KHQsZStzKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplLGNbc10pfWZ1bmN0aW9uIFl0KHQsZSxyLG8pe3N3aXRjaChyLnRhZyl7Y2FzZSJiYXNpYyI6cmV0dXJuIFYodCxlLHIua2luZCk7Y2FzZSJiaXRmaWVsZCI6cmV0dXJuIE1lKHQsZSxyKTtjYXNlInN0cmluZyI6cmV0dXJuIEJlKHQsZSxvLHIuZW5jb2RpbmcpO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjpyZXR1cm4gb3QodCxlLHIuZmllbGRzKTtjYXNlImFycmF5IjpyZXR1cm4gTGUodCxlLG8scil9fWZ1bmN0aW9uIFZ0KHQsZSxyLG8sbil7c3dpdGNoKHIudGFnKXtjYXNlImJhc2ljIjpkdCh0LGUse2s6ci5raW5kLHY6bn0pO2JyZWFrO2Nhc2UiYml0ZmllbGQiOk9lKHQsZSxyLG4/PzApO2JyZWFrO2Nhc2Uic3RyaW5nIjpHZSh0LGUsbyxyLmVuY29kaW5nLG4pO2JyZWFrO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjp2dCh0LGUsci5maWVsZHMsbj8/e30pO2JyZWFrO2Nhc2UiYXJyYXkiOmtlKHQsZSxvLHIsbik7YnJlYWt9fWZ1bmN0aW9uIG90KHQsZSxyKXtsZXQgbz17fTtmb3IobGV0IG4gb2Ygcil7bGV0IGk9WXQodCxlK24ub2Zmc2V0LG4udHlwZSxuLnNpemUpO2lmKG4ubm9ubnVsbCYmaT09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBkZWNvZGU6ICchJyBmaWVsZCAiJHtuLm5hbWV9IiBnb3QgMCAoQyBkaWQgbm90IGZpbGwgaXQsIG9yIGRlY29kZSB3YXMgY2FsbGVkIG9uIGFuIHVuZmlsbGVkIHNsb3QpYCk7b1tuLm5hbWVdPWl9cmV0dXJuIG99ZnVuY3Rpb24gdnQodCxlLHIsbyl7Zm9yKGxldCBuIG9mIHIpb1tuLm5hbWVdIT09dm9pZCAwJiZWdCh0LGUrbi5vZmZzZXQsbi50eXBlLG4uc2l6ZSxvW24ubmFtZV0pfWZ1bmN0aW9uIFVlKHQpe2xldHtmaWVsZHM6ZSxzaXplOnIsbWF4RWZmZWN0aXZlQWxpZ246b309aHQodCk7cmV0dXJue19fc3RydWN0OnQsc2l6ZTpyLHN0cnVjdEFsaWduOm8sZGVjb2RlOm49Pm90KHR5cGVvZiBuPT0ibnVtYmVyIj9uZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4scikpOm5ldyBEYXRhVmlldyhuKSwwLGUpLGFsbG9jOihuPT57aWYobiE9PXZvaWQgMCYmKCFOdW1iZXIuaXNJbnRlZ2VyKG4pfHxuPDEpKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYWxsb2MobikgcmVxdWlyZXMgYW4gaW50ZWdlciBuID49IDEgKFBBQigwKSBuZXZlciBlc2NhcGVzIFx1MjAxNCBwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7cmV0dXJuIG5ldyBiKHIqKG4/PzEpKX0pLGVuY29kZTooKG4saSxjKT0+e2lmKG49PW51bGwpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBlbmNvZGUodikgcmVxdWlyZXMgYW4gYXJndW1lbnQ7IHVzZSBhbGxvYygpIGZvciBhIHplcm9lZCBvdXQtcGFyYW0gc2xvdCIpO2xldCBzPWk/P25ldyBiKHIpO3JldHVybiB2dChuZXcgRGF0YVZpZXcocyksYz8/MCxlLG4pLHN9KSxvZmZzZXRPZjpuPT57Zm9yKGxldCBpIG9mIGUpaWYoaS5uYW1lPT09bilyZXR1cm4gaS5vZmZzZXQ7dGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBubyBmaWVsZCAiJHtufSJgKX19fWZ1bmN0aW9uIF9lKHQsZSxyKXtsZXQgbz17IiMiOnR9O3IhPT12b2lkIDAmJihvWyIjcGFjayJdPXIpO2ZvcihsZXRbbixpXW9mIE9iamVjdC5lbnRyaWVzKGUpKW4uc3RhcnRzV2l0aCgiIyIpfHwob1tuXT1pKTtyZXR1cm4gb31mdW5jdGlvbiBqdCh0KXtsZXR7ZmllbGRzOmUsc2l6ZTpyfT1odCh0Ll9fc3RydWN0KSxvPShuLGkpPT57bGV0IGM9W107Zm9yKGxldCBzPTA7czxpO3MrKyljLnB1c2gob3QobixzKnIsZSkpO3JldHVybiBjfTtyZXR1cm57ZW5jb2RlOm49PntpZighQXJyYXkuaXNBcnJheShuKXx8bi5sZW5ndGg9PT0wKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogc3RydWN0QXJyYXkoZGVmKS5lbmNvZGUoZWxzKSByZXF1aXJlcyBhIG5vbi1lbXB0eSBlbGVtZW50IGFycmF5IChwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7bGV0IGk9dC5hbGxvYyhuLmxlbmd0aCk7Zm9yKGxldCBjPTA7YzxuLmxlbmd0aDtjKyspdC5lbmNvZGUobltjXSxpLGMqdC5zaXplKTtyZXR1cm4gaX0sZGVjb2RlOigobixpKT0+e2lmKGkhPT12b2lkIDAmJighTnVtYmVyLmlzSW50ZWdlcihpKXx8aTwwKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZShwLCBjb3VudCkgcmVxdWlyZXMgYSBub24tbmVnYXRpdmUgaW50ZWdlciBjb3VudCwgZ290ICR7aX1gKTtpZih0eXBlb2Ygbj09Im51bWJlciIpe2lmKGk9PT12b2lkIDApdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGUoYWRkcmVzcywgY291bnQpIHJlcXVpcmVzIGFuIGV4cGxpY2l0IGNvdW50IChhIGJhcmUgYWRkcmVzcyBjYXJyaWVzIG5vIGxlbmd0aCkiKTtyZXR1cm4gaT09PTA/W106byhuZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4saSpyKSksaSl9bGV0IGM7aWYoaSE9PXZvaWQgMCl7aWYoYz1pLGMqcj5uLmJ5dGVMZW5ndGgpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGU6IGNvdW50ICR7Y30gXHhENyBzaXplICR7cn0gPSAke2Mqcn0gZXhjZWVkcyBidWZmZXIgYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH1gKX1lbHNle2lmKG4uYnl0ZUxlbmd0aCVyIT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZTogYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH0gaXMgbm90IGEgbXVsdGlwbGUgb2Ygc2l6ZSAke3J9IChtaXhlZCBidWZmZXI/IHBhc3MgY291bnQgZXhwbGljaXRseSlgKTtjPW4uYnl0ZUxlbmd0aC9yfXJldHVybiBjPT09MD9bXTpvKG5ldyBEYXRhVmlldyhuKSxjKX0pfX1mdW5jdGlvbiBnKHQsZSxyKXtsZXQgbz10eXBlb2YgdD09InN0cmluZyI7cmV0dXJuIFVlKF9lKCJzdHJ1Y3QiLG8/ZTp0LChvP3I6ZSk/LnBhY2spKX12YXIgUD1nKCJSRUNUIix7bGVmdDoiaTMyIix0b3A6ImkzMiIscmlnaHQ6ImkzMiIsYm90dG9tOiJpMzIifSksaj1nKCJQT0lOVCIse3g6ImkzMiIseToiaTMyIn0pO3ZhciBudD1nKCJTVEFSVFVQSU5GT1ciLHtjYjoidTMyIixscFJlc2VydmVkOiI8PnB0ciIsbHBEZXNrdG9wOiI8PnB0ciIsbHBUaXRsZToiPD5wdHIiLGR3WDoidTMyIixkd1k6InUzMiIsZHdYU2l6ZToidTMyIixkd1lTaXplOiJ1MzIiLGR3WENvdW50Q2hhcnM6InUzMiIsZHdZQ291bnRDaGFyczoidTMyIixkd0ZpbGxBdHRyaWJ1dGU6InUzMiIsZHdGbGFnczoidTMyIix3U2hvd1dpbmRvdzoidTE2QFNob3dXaW5kb3dDbWQiLGNiUmVzZXJ2ZWQyOiJ1MTYiLGxwUmVzZXJ2ZWQyOiI8PnB0ciIsaFN0ZElucHV0OiI8SEZJTEU+cHRyIixoU3RkT3V0cHV0OiI8SEZJTEU+cHRyIixoU3RkRXJyb3I6IjxIRklMRT5wdHIifSksQ3Q9ZygiUFJPQ0VTU19JTkZPUk1BVElPTiIse2hQcm9jZXNzOiI8SFBST0NFU1M+cHRyISIsaFRocmVhZDoiPEhUSFJFQUQ+cHRyISIsZHdQcm9jZXNzSWQ6InUzMiIsZHdUaHJlYWRJZDoidTMyIn0pLEo9ZygiQklUTUFQSU5GT0hFQURFUiIse2JpU2l6ZToidTMyIixiaVdpZHRoOiJpMzIiLGJpSGVpZ2h0OiJpMzIiLGJpUGxhbmVzOiJ1MTYiLGJpQml0Q291bnQ6InUxNiIsYmlDb21wcmVzc2lvbjoidTMyIixiaVNpemVJbWFnZToidTMyIixiaVhQZWxzUGVyTWV0ZXI6ImkzMiIsYmlZUGVsc1Blck1ldGVyOiJpMzIiLGJpQ2xyVXNlZDoidTMyIixiaUNsckltcG9ydGFudDoidTMyIn0pLGl0PWcoIkJJVE1BUEZJTEVIRUFERVIiLHtiZlR5cGU6InUxNiIsYmZTaXplOiJ1MzIiLGJmUmVzZXJ2ZWQxOiJ1MTYiLGJmUmVzZXJ2ZWQyOiJ1MTYiLGJmT2ZmQml0czoidTMyIn0se3BhY2s6Mn0pO3ZhciBaPWcoIk5NSERSIix7aHduZEZyb206IjxIV05EPnB0ciIsaWRGcm9tOiI8PnB0ciIsY29kZToiaTMyIn0pLHplPWcoIlNZU1RFTVRJTUUiLHt3WWVhcjoidTE2Iix3TW9udGg6InUxNiIsd0RheU9mV2VlazoidTE2Iix3RGF5OiJ1MTYiLHdIb3VyOiJ1MTYiLHdNaW51dGU6InUxNiIsd1NlY29uZDoidTE2Iix3TWlsbGlzZWNvbmRzOiJ1MTYifSksbXI9ZygiTk1EQVRFVElNRUNIQU5HRSIse2hkcjpaLl9fc3RydWN0LGR3RmxhZ3M6InUzMiIsc3Q6emUuX19zdHJ1Y3R9KSwkZT1nKCJMSVRFTSIse21hc2s6InUzMiIsaUxpbms6ImkzMiIsc3RhdGU6InUzMiIsc3RhdGVNYXNrOiJ1MzIiLHN6SUQ6InUxNls0OF1AdXRmLTE2bGUiLHN6VXJsOiJ1MTZbMjA4NF1AdXRmLTE2bGUifSksd3I9ZygiTk1MSU5LIix7aGRyOlouX19zdHJ1Y3QsaXRlbTokZS5fX3N0cnVjdH0pLGhyPWcoIk5NQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciJ9KSxDcj1nKCJOTUxWQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciIsY2xyVGV4dDoidTMyIixjbHJUZXh0Qms6InUzMiIsaVN1Ykl0ZW06ImkzMiIsZHdJdGVtVHlwZToidTMyIn0pLFNyPWcoIk5NTElTVFZJRVciLHtoZHI6Wi5fX3N0cnVjdCxpSXRlbToiaTMyIixpU3ViSXRlbToiaTMyIix1TmV3U3RhdGU6InUzMiIsdU9sZFN0YXRlOiJ1MzIiLHVDaGFuZ2VkOiJ1MzIiLHB0QWN0aW9uOiJpMzJbMl0iLGxQYXJhbToiPD5wdHIifSk7dmFyIFllPWcoIlRWSVRFTSIse21hc2s6InUzMiIsaEl0ZW06Ijw+cHRyIixzdGF0ZToidTMyIixzdGF0ZU1hc2s6InUzMiIscHN6VGV4dDoiPD5wdHIiLGNjaFRleHRNYXg6ImkzMiIsaUltYWdlOiJpMzIiLGlTZWxlY3RlZEltYWdlOiJpMzIiLGNDaGlsZHJlbjoiaTMyIixsUGFyYW06Ijw+cHRyIn0pLGdyPWcoIlRWSU5TRVJUU1RSVUNUIix7aFBhcmVudDoiPD5wdHIiLGhJbnNlcnRBZnRlcjoiPD5wdHIiLGl0ZW06WWUuX19zdHJ1Y3R9KTt2YXIgVmU9ZygiTVNHIix7aHduZDoiPEhXTkQ+cHRyIixtZXNzYWdlOiJ1MzIiLHdQYXJhbToiPD5wdHIiLGxQYXJhbToiPD5wdHIiLHRpbWU6InUzMiIscHQ6ai5fX3N0cnVjdH0pLERyPWcoIlBBSU5UU1RSVUNUIix7aGRjOiI8SERDPnB0ciIsZkVyYXNlOiJpMzIiLHJjUGFpbnQ6UC5fX3N0cnVjdCxmUmVzdG9yZToiaTMyIixmSW5jVXBkYXRlOiJpMzIiLHJnYlJlc2VydmVkOiJ1OFszMl0ifSk7dmFyIHN0PWcoIk9TVkVSU0lPTklORk9fMTQ4Iix7ZHdPU1ZlcnNpb25JbmZvU2l6ZToidTMyIixkd01ham9yVmVyc2lvbjoidTMyIixkd01pbm9yVmVyc2lvbjoidTMyIixkd0J1aWxkTnVtYmVyOiJ1MzIiLGR3UGxhdGZvcm1JZDoidTMyIixzekNTRFZlcnNpb246InU4WzEyOF0ifSk7dmFyIE89KHQsZSxyKT0+Rygia2VybmVsMzIuZGxsIix0LGUsciksSnQ9TygiQ3JlYXRlUGlwZSIsIjw+cHRyIDw+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKSxTdD1PKCJTZXRIYW5kbGVJbmZvcm1hdGlvbiIsIjxIRklMRT5wdHIhIHUzMiB1MzIgLT4gaTMyIiksS3Q9TygiQ3JlYXRlUHJvY2Vzc1ciLCI8V0NIQVI+cHRyIDxXQ0hBUj5wdHIgPD5wdHIgPD5wdHIgaTMyIHUzMiA8PnB0ciA8V0NIQVI+cHRyIDxTVEFSVFVQSU5GT1c+cHRyIDxQUk9DRVNTX0lORk9STUFUSU9OPnB0ciAtPiBpMzIiLHtTVEFSVFVQSU5GT1c6bnR9KSxYdD1PKCJXYWl0Rm9yU2luZ2xlT2JqZWN0IiwiPD5wdHIgdTMyIC0+IHUzMiIpLFp0PU8oIkdldEV4aXRDb2RlUHJvY2VzcyIsIjxIUFJPQ0VTUz5wdHIhIDxCWVRFPnB0ciAtPiBpMzIiKSxVPU8oIkNsb3NlSGFuZGxlIiwiPD5wdHIgLT4gaTMyIik7dmFyIHF0PU8oIlJlYWRGaWxlIiwiPEhGSUxFPnB0ciEgPEJZVEU+cHRyIHUzMiA8QllURT5wdHIgPD5wdHIgLT4gaTMyIik7dmFyIGd0PU8oIkdldExhc3RFcnJvciIsIiAtPiB1MzIiKSxRdD1PKCJHZXRTeXN0ZW1EaXJlY3RvcnlXIiwiPEJZVEU+cHRyIHUzMiAtPiB1MzIiKTtpbXBvcnQqYXMgdGUgZnJvbSJvcyI7dmFyIE49KHQsZSxyKT0+RygidXNlcjMyLmRsbCIsdCxlLHIpLEhyPU4oIkdldERlc2t0b3BXaW5kb3ciLCIgLT4gPEhXTkQ+cHRyIiksZWU9dGUuYXJjaD09PSJ4NjQiPyJQdHJXIjoiVyI7dmFyIER0PU4oIkdldFdpbmRvd1JlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpLHJlPU4oIkdldENsaWVudFJlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpO3ZhciBvZT1OKCJJc1dpbmRvd1Zpc2libGUiLCI8SFdORD5wdHIgLT4gaTMyIiksRXQ9TigiSXNJY29uaWMiLCI8SFdORD5wdHIgLT4gaTMyIik7dmFyIG5lPU4oIkdldFdpbmRvd1RleHRXIiwiPEhXTkQ+cHRyIDxCWVRFPnB0ciBpMzIgLT4gaTMyIik7dmFyIGllPU4oIkdldENsYXNzTmFtZVciLCI8SFdORD5wdHIgPEJZVEU+cHRyIGkzMiAtPiBpMzIiKSxQcj1OKCJHZXRXaW5kb3dMb25nIitlZSwiPEhXTkQ+cHRyIGkzMkBHd2xwIC0+IDw+cHRyIiksTXI9TigiU2V0V2luZG93TG9uZyIrZWUsIjxIV05EPnB0ciBpMzJAR3dscCA8PnB0ciAtPiA8PnB0ciIpO3ZhciBzZT1OKCJHZXREQyIsIjxIV05EPnB0ciAtPiA8SERDPnB0ciIpLFd0PU4oIlJlbGVhc2VEQyIsIjxIV05EPnB0ciA8SERDPnB0ciEgLT4gaTMyIiksY2U9TigiUHJpbnRXaW5kb3ciLCI8SFdORD5wdHIgPEhEQz5wdHIhIHUzMiAtPiBpMzIiKTt2YXIgcGU9TigiQ2xpZW50VG9TY3JlZW4iLCI8SFdORD5wdHIgPFBPSU5UPnB0ciAtPiBpMzIiKTt2YXIgXz1OKCJHZXRTeXN0ZW1NZXRyaWNzIiwiaTMyIC0+IGkzMiIpO3ZhciBhZT1OKCJFbnVtV2luZG93cyIsIjw+cHRyIDw+cHRyIC0+IGkzMiIpO3ZhciB6PSh0LGUscik9PkcoImdkaTMyLmRsbCIsdCxlLHIpLExyPWp0KGopO3ZhciBUdD16KCJEZWxldGVPYmplY3QiLCI8SEdESU9CSj5wdHIgLT4gaTMyIik7dmFyIGJ0PXooIkNyZWF0ZUNvbXBhdGlibGVEQyIsIjxIREM+cHRyIC0+IDxIREM+cHRyIiksTnQ9eigiQ3JlYXRlQ29tcGF0aWJsZUJpdG1hcCIsIjxIREM+cHRyISBpMzIgaTMyIC0+IDxIR0RJT0JKPnB0ciIpO3ZhciBxPXooIlNlbGVjdE9iamVjdCIsIjxIREM+cHRyISA8SEdESU9CSj5wdHIgLT4gPEhHRElPQko+cHRyIiksSXQ9eigiQml0Qmx0IiwiPEhEQz5wdHIhIGkzMiBpMzIgaTMyIGkzMiA8SERDPnB0ciBpMzIgaTMyIHUzMkBSYXN0ZXJPcCAtPiBpMzIiKSx1ZT16KCJHZXRESUJpdHMiLCI8SERDPnB0ciEgPEhHRElPQko+cHRyIHUzMiB1MzIgPEJZVEU+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKTt2YXIgUT16KCJEZWxldGVEQyIsIjxIREM+cHRyISAtPiBpMzIiKTt2YXIgdmU9KHQsZSk9PkcoIm50ZGxsLmRsbCIsdCxlKSxsZT12ZSgiUnRsR2V0VmVyc2lvbiIsIjxPU1ZFUlNJT05JTkZPXzE0OD5wdHIgLT4gaTMyIik7dmFyIG1lPXQ9Pnt0cnl7bGV0IGU9eGUub3BlbigiZGlhZy5sb2ciLCJhIik7ZSYmKGUucHV0cyhgJHtEYXRlLm5vdygpfSAke3R9CmApLGUuY2xvc2UoKSl9Y2F0Y2h7fX0seXQ9MSxqZT0yNTYsSmU9NDI5NDk2NzI5NSxGPWZlLldvcmtlci5wYXJlbnQsd2U9IkM6XFxXaW5kb3dzXFxTeXN0ZW0zMiI7dHJ5e2xldCB0PUIuYWxsb2MoMjU2KSxyPVF0KHQsMjU2KT4wP0IuZGVjb2RlKHQpOiIiO3ImJih3ZT1yKX1jYXRjaCh0KXttZSgiU1lTLURJUi1GQUlMOiAiK1N0cmluZyh0KSl9dmFyIGhlPSExO3RyeXtsZXQgdD1zdC5lbmNvZGUoe2R3T1NWZXJzaW9uSW5mb1NpemU6c3Quc2l6ZX0pO2xlKHQucHRyKT09PTAmJihoZT1zdC5kZWNvZGUodCkuZHdNYWpvclZlcnNpb24+PTEwKX1jYXRjaCh0KXttZSgiVkVSLUZBSUw6ICIrU3RyaW5nKHQpKX12YXIgRnQ9ZygiUElQRV9IQU5ETEVTIix7aFJlYWQ6IjxIRklMRT5wdHIhIixoV3JpdGU6IjxIRklMRT5wdHIhIn0pO2Z1bmN0aW9uIEtlKHQsZSl7bGV0IHI9RnQuYWxsb2MoKTtpZighSnQoci5wdHIsci5wdHIrRnQub2Zmc2V0T2YoImhXcml0ZSIpLEksMCkpdGhyb3cgbmV3IEVycm9yKCJDcmVhdGVQaXBlIGVycj0iK2d0KCkpO2xldHtoUmVhZDpvLGhXcml0ZTpufT1GdC5kZWNvZGUocik7U3Qobix5dCx5dCksU3Qobyx5dCwwKTtsZXQgaT1DdC5hbGxvYygpLHM9YCR7d2V9XFxjbWQuZXhlICR7aGU/Ii91ICI6IiJ9L2MgJHtlfWA7aWYoIUt0KEkscyxJLEksMSwwLEksSSx7Y2I6bnQuc2l6ZSxkd0ZsYWdzOmplLGhTdGRPdXRwdXQ6bixoU3RkRXJyb3I6bn0saS5wdHIpKXRocm93IFUobyksVShuKSxuZXcgRXJyb3IoIkNyZWF0ZVByb2Nlc3NXIGVycj0iK2d0KCkrIiBjbWQ9IitzKTtsZXR7aFByb2Nlc3M6cCxoVGhyZWFkOmEsZHdQcm9jZXNzSWQ6dX09Q3QuZGVjb2RlKGkpO1UoYSksVShuKSxGLnBvc3RNZXNzYWdlKHt0eXBlOiJpbmZvIixpZDp0LHBpZDp1fSk7bGV0IHg9bmV3IGIoNDA5NiksZD1uZXcgVWludDhBcnJheSh4KSx3PW5ldyBiKDQpLGY9bmV3IFVpbnQzMkFycmF5KHcpO2Zvcig7ZlswXT0wLCEhcXQobyx4LDQwOTYsdyxJKTspe2xldCBsPWZbMF07aWYobD09PTApYnJlYWs7Ri5wb3N0TWVzc2FnZSh7dHlwZToiZGF0YSIsaWQ6dCxjaHVuazpkLnNsaWNlKDAsbCl9KX1YdChwLEplKTtsZXQgUz1uZXcgYig0KSxtPW5ldyBJbnQzMkFycmF5KFMpO1p0KHAsUyk7bGV0IFc9bVswXTtyZXR1cm4gVShvKSxVKHApLFd9dmFyIENlPTEzMzY5Mzc2LFhlPTAsZGU9NjU1MzYsWmU9NGU3LGN0PTUxMixxZT0yZTQsSHQ9aXQuc2l6ZStKLnNpemU7ZnVuY3Rpb24gUWUodCxlLHIpe2xldCBvPWl0LmVuY29kZSh7YmZUeXBlOjE5Nzc4LGJmU2l6ZTpIdCt0LGJmT2ZmQml0czpIdH0pLG49Si5lbmNvZGUoe2JpU2l6ZTpKLnNpemUsYmlXaWR0aDplLGJpSGVpZ2h0Oi1yLGJpUGxhbmVzOjEsYmlCaXRDb3VudDozMixiaUNvbXByZXNzaW9uOjAsYmlTaXplSW1hZ2U6dCxiaVhQZWxzUGVyTWV0ZXI6MjgzNSxiaVlQZWxzUGVyTWV0ZXI6MjgzNX0pLGk9bmV3IFVpbnQ4QXJyYXkoSHQpO3JldHVybiBpLnNldChuZXcgVWludDhBcnJheShvKSwwKSxpLnNldChuZXcgVWludDhBcnJheShuKSxpdC5zaXplKSxpfWZ1bmN0aW9uIHRyKHQsZSxyLG8sbil7bGV0IGk9bmV3IGIobypuKjQpLGM9bmV3IFVpbnQ4QXJyYXkoaSkscz1KLmVuY29kZSh7YmlTaXplOkouc2l6ZSxiaVdpZHRoOm8sYmlIZWlnaHQ6LW4sYmlQbGFuZXM6MSxiaUJpdENvdW50OjMyLGJpU2l6ZUltYWdlOm8qbio0fSk7aWYodWUoZSxyLDAsbixpLHMucHRyLFhlKSE9PW4pcmV0dXJuITE7bGV0IGE9Yy5ieXRlTGVuZ3RoO0YucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6UWUoYSxvLG4pfSk7Zm9yKGxldCB1PTA7dTxhO3UrPWRlKUYucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6Yy5zbGljZSh1LE1hdGgubWluKHUrZGUsYSkpfSk7cmV0dXJuITB9ZnVuY3Rpb24gZXIodCxlLHIsbyxuLGksYyxzLHApe2xldCBhPWJ0KHQpLHU9YT9OdCh0LHIsbyk6MDtpZighYXx8IXUpcmV0dXJuIGEmJlEoYSksITE7bGV0IHg9cShhLHUpLHc9Y2UoZSxhLDApIT09MCYmSXQobiwwLDAscyxwLGEsaSxjLENlKSE9PTA7cmV0dXJuIHEoYSx4KSxUdCh1KSxRKGEpLHd9ZnVuY3Rpb24gU2UodCxlLHIsbyxuLGksYyxzLHAsYSl7aWYoIShzPjAmJnA+MCYmcypwPD1aZSkpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIHNpemUgaW52YWxpZCB3PSIrcysiIGg9IitwKTtpZihhIT09bnVsbCYmIShpPj0wJiZjPj0wJiZpK3M8PWUmJmMrcDw9cikpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGNyb3Agb3V0IG9mIHJhbmdlIGNyb3A9KCIraSsiLCIrYysiLCIrcysieCIrcCsiKSBmcmFtZT0iK2UrIngiK3IpO2xldCB1PXNlKEkpO2lmKCF1KXRocm93IG5ldyBFcnJvcigiR2V0REMoTlVMTCk9MFx1RkYxQVx1NjVFMFx1OEY5M1x1NTE2NVx1Njg0Q1x1OTc2Mlx1RkYwOFx1Nzg2RVx1OEJBNFx1NTcyOFx1NEVBNFx1NEU5MiBzZXNzaW9uIFx1NTQyRlx1NTJBOFx1RkYwQ1x1ODAwQ1x1OTc1RSBzc2hkL3NlcnZpY2VcdUZGMDkiKTtsZXQgeD1idCh1KSxkPXg/TnQodSxzLHApOjA7aWYoIXh8fCFkKXRocm93IHgmJlEoeCksV3QoSSx1KSxuZXcgRXJyb3IoIkNyZWF0ZUNvbXBhdGlibGVEQy9CaXRtYXAgZmFpbGVkIik7bGV0IHc9cSh4LGQpLGY9YT09PW51bGw/SXQoeCwwLDAscyxwLHUsbyxuLENlKSE9PTA6ZXIodSxhLGUscix4LGksYyxzLHApO3EoeCx3KTtsZXQgUz1mJiZ0cih0LHgsZCxzLHApO2lmKFR0KGQpLFEoeCksV3QoSSx1KSwhZil0aHJvdyBuZXcgRXJyb3IoImNhcHR1cmUgZmFpbGVkIG91dD0iK3MrIngiK3ArKGE9PT1udWxsPyIgYXQ9KCIrbysiLCIrbisiKSI6IiBod25kPSIrYSsiIGNyb3A9KCIraSsiLCIrYysiKSBmcmFtZT0iK2UrIngiK3IpKTtpZighUyl0aHJvdyBuZXcgRXJyb3IoIkdldERJQml0cyBzaG9ydCByZWFkIG91dD0iK3MrIngiK3ApO3JldHVybnt3aWR0aDpzLGhlaWdodDpwfX1mdW5jdGlvbiBycih0KXtsZXQgZT1fKDApLHI9XygxKTtpZihlPD0wfHxyPD0wKXRocm93IG5ldyBFcnJvcigiR2V0U3lzdGVtTWV0cmljcyB3PSIrZSsiIGg9IityKTtyZXR1cm4gU2UodCxlLHIsMCwwLDAsMCxlLHIsbnVsbCl9ZnVuY3Rpb24gb3IodCxlLHIsbyl7aWYobz09PSJzY3JlZW4iJiZFdChlKSE9PTApdGhyb3cgbmV3IEVycm9yKCJ3aW5kb3cgbWluaW1pemVkXHVGRjFBbW9kZT1zY3JlZW4gXHU1M0VBXHU0RjFBXHU2MjJBXHU1MjMwXHU1QjgzXHU0RTBCXHU2NUI5XHU3Njg0XHU2ODRDXHU5NzYyXHVGRjBDXHU2NTM5XHU3NTI4IG1vZGU9cHJpbnQiKTtsZXQgbj1QLmFsbG9jKCk7aWYoIUR0KGUsbi5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0V2luZG93UmVjdChod25kPSIrZSsiKT0wXHVGRjFBXHU3QTk3XHU1M0UzXHU0RTBEXHU1QjU4XHU1NzI4XHU2MjE2XHU1REYyXHU5NTAwXHU2QkMxIik7bGV0e2xlZnQ6aSx0b3A6YyxyaWdodDpzLGJvdHRvbTpwfT1QLmRlY29kZShuKSxhPXMtaSx1PXAtYyx4PTAsZD0wLHc9YSxmPXU7aWYocj09PSJjbGllbnQiKXtsZXQgVz1QLmFsbG9jKCk7aWYoIXJlKGUsVy5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0Q2xpZW50UmVjdChod25kPSIrZSsiKT0wIik7bGV0e2xlZnQ6bCx0b3A6RCxyaWdodDpFLGJvdHRvbTpDfT1QLmRlY29kZShXKTt3PUUtbCxmPUMtRDtsZXQgaD1qLmVuY29kZSh7eDowLHk6MH0pO2lmKCFwZShlLGgucHRyKSl0aHJvdyBuZXcgRXJyb3IoIkNsaWVudFRvU2NyZWVuKGh3bmQ9IitlKyIpPTAiKTtsZXQgVD1qLmRlY29kZShoKTt4PVQueC1pLGQ9VC55LWN9bGV0IFM9bz09PSJwcmludCI/MDppK3gsbT1vPT09InByaW50Ij8wOmMrZDtpZihvPT09InNjcmVlbiIpe2xldCBXPV8oNzYpLGw9Xyg3NyksRD1fKDc4KSxFPV8oNzkpLEM9TWF0aC5tYXgoUyxXKSxoPU1hdGgubWF4KG0sbCksVD1NYXRoLm1pbihTK3csVytEKSxIPU1hdGgubWluKG0rZixsK0UpO2lmKFQ8PUN8fEg8PWgpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGFyZWEgb3V0c2lkZSB2aXJ0dWFsIHNjcmVlbiBhdD0oIitTKyIsIittKyIsIit3KyJ4IitmKyIpIik7Uz1DLG09aCx3PVQtQyxmPUgtaH1yZXR1cm4gU2UodCxhLHUsUyxtLHgsZCx3LGYsbz09PSJwcmludCI/ZTpudWxsKX1mdW5jdGlvbiBucih0KXtsZXQgZT1bXSxyPV90KCI8SFdORD5wdHIgPD5wdHIgLT4gaTMyIixzPT4ocyYmZS5wdXNoKHMpLGUubGVuZ3RoPHFlPzE6MCkpO3RyeXthZShyLnB0cixJKX1maW5hbGx5e3IuZGlzcG9zZSgpfWxldCBvPVAuYWxsb2MoKSxuPUIuYWxsb2MoY3QpLGk9Qi5hbGxvYyhjdCksYz1bXTtmb3IobGV0IHMgb2YgZSlpZihEdChzLG8ucHRyKSl7bGV0IHA9UC5kZWNvZGUobyksYT1uZShzLG4sY3QpLHU9aWUocyxpLGN0KTtjLnB1c2goe2h3bmQ6cyx0aXRsZTphPjA/Qi5kZWNvZGUobik6IiIsY2xhc3NOYW1lOnU+MD9CLmRlY29kZShpKToiIixyZWN0OntsZWZ0OnAubGVmdCx0b3A6cC50b3AscmlnaHQ6cC5yaWdodCxib3R0b206cC5ib3R0b219LHZpc2libGU6b2UocykhPT0wLG1pbmltaXplZDpFdChzKSE9PTB9KX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQsY29kZTowLGVycm9yOm51bGwsd2luZG93czpjfSl9ZnVuY3Rpb24gaXIodCl7aWYodC50eXBlPT09InJ1biIpe2lmKHR5cGVvZiB0LmNtZCE9InN0cmluZyIpcmV0dXJuO2xldCBlPS0xLHI9bnVsbDt0cnl7ZT1LZSh0LmlkLHQuY21kKX1jYXRjaChvKXtyPVN0cmluZyhvKX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTplLGVycm9yOnJ9KTtyZXR1cm59aWYodC50eXBlPT09IndpbmRvd3MiKXt0cnl7bnIodC5pZCl9Y2F0Y2goZSl7Ri5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixpZDp0LmlkLGNvZGU6LTEsZXJyb3I6U3RyaW5nKGUpfSl9cmV0dXJufWlmKHQudHlwZT09PSJzY3JlZW5zaG90Iil0cnl7bGV0IGU9dC5od25kPz9udWxsLHt3aWR0aDpyLGhlaWdodDpvfT1lPT09bnVsbD9ycih0LmlkKTpvcih0LmlkLGUsdC5hcmVhPz8id2luZG93Iix0Lm1vZGU/PyJzY3JlZW4iKTtGLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTowLGVycm9yOm51bGwsd2lkdGg6cixoZWlnaHQ6b30pfWNhdGNoKGUpe0YucG9zdE1lc3NhZ2Uoe3R5cGU6InJlc3VsdCIsaWQ6dC5pZCxjb2RlOi0xLGVycm9yOlN0cmluZyhlKX0pfX1GLm9ubWVzc2FnZT10PT57aXIodC5kYXRhKSxGLm9ubWVzc2FnZT1udWxsfTsK");
22039
- bumpWorkers(1);
22040
- const id = 1;
22041
- let settled = false;
22042
- let timer = null;
22043
- const settle = (r2) => {
22044
- if (settled)
22045
- return;
22046
- settled = true;
22047
- if (timer !== null)
22048
- os6.clearTimeout(timer);
22049
- worker.onmessage = null;
22050
- bumpWorkers(-1);
22051
- resolve(r2);
22052
- };
22053
- timer = os6.setTimeout(() => settle(onTimeout()), timeoutMs);
22054
- worker.onmessage = (e2) => {
22055
- const msg = e2.data;
22056
- if (msg.id !== void 0 && msg.id !== id)
22057
- return;
22058
- if (msg.type === "data") {
22059
- onData(msg.chunk);
22060
- return;
22061
- }
22062
- if (msg.type !== "result")
22063
- return;
22064
- settle(onResult(msg));
22065
- };
22066
- try {
22067
- worker.postMessage(post);
22068
- } catch (ex) {
22069
- settle(onResult({ type: "error", error: "spawn: " + String(ex) }));
22070
- }
22071
- });
22072
- }
22073
22411
  function jsonError(status, msg) {
22074
22412
  return new Response(JSON.stringify({ error: msg }), {
22075
22413
  status,
@@ -22078,81 +22416,586 @@ function jsonError(status, msg) {
22078
22416
  }
22079
22417
  function parseShotOpts(params) {
22080
22418
  const area = params.get("area") ?? "window";
22081
- const mode = params.get("mode") ?? "screen";
22082
22419
  if (area !== "window" && area !== "client")
22083
22420
  throw new Error('area must be "window" or "client"');
22084
- if (mode !== "screen" && mode !== "print")
22421
+ const rawMode = params.get("mode");
22422
+ if (rawMode !== null && rawMode !== "screen" && rawMode !== "print") {
22085
22423
  throw new Error('mode must be "screen" or "print"');
22424
+ }
22086
22425
  const raw = params.get("hwnd");
22087
- if (raw === null || raw === "")
22088
- return { hwnd: null, area, mode };
22089
- const hwnd = Number(raw);
22090
- if (!Number.isInteger(hwnd) || hwnd <= 0)
22426
+ const hwnd = raw === null || raw === "" ? null : Number(raw);
22427
+ if (hwnd !== null && (!Number.isInteger(hwnd) || hwnd <= 0)) {
22091
22428
  throw new Error("hwnd must be a positive integer");
22429
+ }
22430
+ const mode = rawMode ?? (hwnd === null ? "screen" : "print");
22092
22431
  return { hwnd, area, mode };
22093
22432
  }
22094
- function windowsResponse() {
22095
- return withWorker(WINDOWS_TIMEOUT_MS, () => jsonError(504, "windows timeout"), { type: "windows", id: 1 }, () => {
22096
- }, (msg) => msg.error ? jsonError(500, msg.error) : new Response(JSON.stringify(msg.windows ?? []), { headers: { "Content-Type": "application/json" } }));
22433
+ var SRCCOPY = 13369376;
22434
+ var DIB_RGB_COLORS = 0;
22435
+ var MAX_CAPTURE_PX = 4e7;
22436
+ var WIDE_BUF_CHARS = 512;
22437
+ var MAX_WINDOWS = 2e4;
22438
+ var BMP_HEADERS_SIZE = BITMAPFILEHEADER.size + BITMAPINFOHEADER.size;
22439
+ function bmpHeader(size, w2, h2) {
22440
+ const fileHdr = BITMAPFILEHEADER.encode({
22441
+ bfType: 19778,
22442
+ // 'BM'
22443
+ bfSize: BMP_HEADERS_SIZE + size,
22444
+ // 文件总长 = 头 + 像素
22445
+ bfOffBits: BMP_HEADERS_SIZE
22446
+ // 像素数据偏移
22447
+ });
22448
+ const infoHdr = BITMAPINFOHEADER.encode({
22449
+ biSize: BITMAPINFOHEADER.size,
22450
+ biWidth: w2,
22451
+ biHeight: -h2,
22452
+ // 负 = 顶向下
22453
+ biPlanes: 1,
22454
+ biBitCount: 32,
22455
+ biCompression: 0,
22456
+ // BI_RGB
22457
+ biSizeImage: size,
22458
+ biXPelsPerMeter: 2835,
22459
+ // 72dpi
22460
+ biYPelsPerMeter: 2835
22461
+ });
22462
+ const out = new Uint8Array(BMP_HEADERS_SIZE);
22463
+ out.set(new Uint8Array(fileHdr), 0);
22464
+ out.set(new Uint8Array(infoHdr), BITMAPFILEHEADER.size);
22465
+ return out;
22097
22466
  }
22098
- function screenshotResponse(opts) {
22099
- const parts = [];
22100
- let total = 0;
22101
- const post = { type: "screenshot", id: 1 };
22102
- if (opts.hwnd !== null) {
22103
- post.hwnd = opts.hwnd;
22104
- post.area = opts.area;
22105
- post.mode = opts.mode;
22106
- }
22107
- return withWorker(SCREENSHOT_TIMEOUT_MS, () => jsonError(504, "screenshot timeout"), post, (c2) => {
22108
- parts.push(c2);
22109
- total += c2.byteLength;
22110
- }, (msg) => {
22111
- if (msg.error)
22112
- return jsonError(500, msg.error);
22113
- if (total === 0)
22114
- return jsonError(500, "empty capture");
22115
- const buf = new Uint8Array(total);
22116
- let off = 0;
22117
- for (const p2 of parts) {
22118
- buf.set(p2, off);
22119
- off += p2.byteLength;
22467
+ function emitDib(hdc, hbm, w2, h2) {
22468
+ const pxB = new PtrArrayBuffer(w2 * h2 * 4);
22469
+ const px = new Uint8Array(pxB);
22470
+ const bmi = BITMAPINFOHEADER.encode({
22471
+ biSize: BITMAPINFOHEADER.size,
22472
+ biWidth: w2,
22473
+ biHeight: -h2,
22474
+ // 负 = 顶向下
22475
+ biPlanes: 1,
22476
+ biBitCount: 32,
22477
+ // biCompression 缺省 0 = BI_RGB
22478
+ biSizeImage: w2 * h2 * 4
22479
+ });
22480
+ const got = GetDIBits(hdc, hbm, 0, h2, pxB, bmi.ptr, DIB_RGB_COLORS);
22481
+ if (got !== h2)
22482
+ return null;
22483
+ const out = new Uint8Array(BMP_HEADERS_SIZE + px.byteLength);
22484
+ out.set(bmpHeader(px.byteLength, w2, h2), 0);
22485
+ out.set(px, BMP_HEADERS_SIZE);
22486
+ return out;
22487
+ }
22488
+ function printAndCrop(hdcScreen, hwnd, frameW, frameH, hdcOut, cropX, cropY, outW, outH) {
22489
+ const hdcTmp = CreateCompatibleDC(hdcScreen);
22490
+ const hbmTmp = hdcTmp ? CreateCompatibleBitmap(hdcScreen, frameW, frameH) : 0;
22491
+ if (!hdcTmp || !hbmTmp) {
22492
+ if (hdcTmp)
22493
+ DeleteDC(hdcTmp);
22494
+ return false;
22495
+ }
22496
+ const oldTmp = SelectObject(hdcTmp, hbmTmp);
22497
+ const printed = PrintWindow(hwnd, hdcTmp, 0) !== 0;
22498
+ const cropped = printed && BitBlt(hdcOut, 0, 0, outW, outH, hdcTmp, cropX, cropY, SRCCOPY) !== 0;
22499
+ SelectObject(hdcTmp, oldTmp);
22500
+ DeleteObject(hbmTmp);
22501
+ DeleteDC(hdcTmp);
22502
+ return cropped;
22503
+ }
22504
+ function captureRect(frameW, frameH, srcX, srcY, cropX, cropY, outW, outH, hwnd) {
22505
+ if (!(outW > 0 && outH > 0 && outW * outH <= MAX_CAPTURE_PX)) {
22506
+ throw new Error("capture size invalid w=" + outW + " h=" + outH);
22507
+ }
22508
+ if (hwnd !== null && !(cropX >= 0 && cropY >= 0 && cropX + outW <= frameW && cropY + outH <= frameH)) {
22509
+ throw new Error("capture crop out of range crop=(" + cropX + "," + cropY + "," + outW + "x" + outH + ") frame=" + frameW + "x" + frameH);
22510
+ }
22511
+ const hdcScreen = GetDC(NULL);
22512
+ if (!hdcScreen) {
22513
+ throw new Error("GetDC(NULL)=0\uFF1A\u65E0\u8F93\u5165\u684C\u9762\uFF08\u786E\u8BA4\u5728\u4EA4\u4E92 session \u542F\u52A8\uFF0C\u800C\u975E sshd/service\uFF09");
22514
+ }
22515
+ const hdcOut = CreateCompatibleDC(hdcScreen);
22516
+ const hbmOut = hdcOut ? CreateCompatibleBitmap(hdcScreen, outW, outH) : 0;
22517
+ if (!hdcOut || !hbmOut) {
22518
+ if (hdcOut)
22519
+ DeleteDC(hdcOut);
22520
+ ReleaseDC(NULL, hdcScreen);
22521
+ throw new Error("CreateCompatibleDC/Bitmap failed");
22522
+ }
22523
+ const oldOut = SelectObject(hdcOut, hbmOut);
22524
+ const ok = hwnd === null ? BitBlt(hdcOut, 0, 0, outW, outH, hdcScreen, srcX, srcY, SRCCOPY) !== 0 : printAndCrop(hdcScreen, hwnd, frameW, frameH, hdcOut, cropX, cropY, outW, outH);
22525
+ SelectObject(hdcOut, oldOut);
22526
+ const bmp = ok ? emitDib(hdcOut, hbmOut, outW, outH) : null;
22527
+ DeleteObject(hbmOut);
22528
+ DeleteDC(hdcOut);
22529
+ ReleaseDC(NULL, hdcScreen);
22530
+ if (!ok) {
22531
+ throw new Error("capture failed out=" + outW + "x" + outH + (hwnd === null ? " at=(" + srcX + "," + srcY + ")" : " hwnd=" + hwnd + " crop=(" + cropX + "," + cropY + ") frame=" + frameW + "x" + frameH));
22532
+ }
22533
+ if (!bmp)
22534
+ throw new Error("GetDIBits short read out=" + outW + "x" + outH);
22535
+ return { bmp, width: outW, height: outH };
22536
+ }
22537
+ function captureScreen() {
22538
+ const w2 = GetSystemMetrics(0);
22539
+ const h2 = GetSystemMetrics(1);
22540
+ if (w2 <= 0 || h2 <= 0)
22541
+ throw new Error("GetSystemMetrics w=" + w2 + " h=" + h2);
22542
+ return captureRect(w2, h2, 0, 0, 0, 0, w2, h2, null);
22543
+ }
22544
+ function captureWindow(hwnd, area, mode) {
22545
+ if (mode === "screen" && IsIconic(hwnd) !== 0) {
22546
+ throw new Error("window minimized\uFF1Amode=screen \u53EA\u4F1A\u622A\u5230\u5B83\u4E0B\u65B9\u7684\u684C\u9762\uFF0C\u53BB\u6389 mode=screen \u8BA9\u9ED8\u8BA4 print \u751F\u6548");
22547
+ }
22548
+ const wRect = RECT.alloc();
22549
+ if (!GetWindowRect(hwnd, wRect.ptr)) {
22550
+ throw new Error("GetWindowRect(hwnd=" + hwnd + ")=0\uFF1A\u7A97\u53E3\u4E0D\u5B58\u5728\u6216\u5DF2\u9500\u6BC1");
22551
+ }
22552
+ const { left: wl, top: wt2, right: wr2, bottom: wbot } = RECT.decode(wRect);
22553
+ const ww = wr2 - wl;
22554
+ const wh = wbot - wt2;
22555
+ let cropX = 0;
22556
+ let cropY = 0;
22557
+ let cw = ww;
22558
+ let ch = wh;
22559
+ if (area === "client") {
22560
+ const cRect = RECT.alloc();
22561
+ if (!GetClientRect(hwnd, cRect.ptr))
22562
+ throw new Error("GetClientRect(hwnd=" + hwnd + ")=0");
22563
+ const { left: cl, top: ct2, right: cr2, bottom: cbot } = RECT.decode(cRect);
22564
+ cw = cr2 - cl;
22565
+ ch = cbot - ct2;
22566
+ const origin = POINT.encode({ x: 0, y: 0 });
22567
+ if (!ClientToScreen(hwnd, origin.ptr))
22568
+ throw new Error("ClientToScreen(hwnd=" + hwnd + ")=0");
22569
+ const org = POINT.decode(origin);
22570
+ cropX = org.x - wl;
22571
+ cropY = org.y - wt2;
22572
+ }
22573
+ let sx = mode === "print" ? 0 : wl + cropX;
22574
+ let sy = mode === "print" ? 0 : wt2 + cropY;
22575
+ if (mode === "screen") {
22576
+ const vsX = GetSystemMetrics(76);
22577
+ const vsY = GetSystemMetrics(77);
22578
+ const vsW = GetSystemMetrics(78);
22579
+ const vsH = GetSystemMetrics(79);
22580
+ const ax = Math.max(sx, vsX);
22581
+ const ay = Math.max(sy, vsY);
22582
+ const ax2 = Math.min(sx + cw, vsX + vsW);
22583
+ const ay2 = Math.min(sy + ch, vsY + vsH);
22584
+ if (ax2 <= ax || ay2 <= ay) {
22585
+ throw new Error("capture area outside virtual screen at=(" + sx + "," + sy + "," + cw + "x" + ch + ")");
22120
22586
  }
22121
- const dims = msg.width !== void 0 && msg.height !== void 0 ? msg.width + "x" + msg.height : "";
22122
- return new Response(buf, {
22123
- headers: { "Content-Type": "image/bmp", "X-Dimensions": dims }
22124
- });
22587
+ sx = ax;
22588
+ sy = ay;
22589
+ cw = ax2 - ax;
22590
+ ch = ay2 - ay;
22591
+ }
22592
+ return captureRect(ww, wh, sx, sy, cropX, cropY, cw, ch, mode === "print" ? hwnd : null);
22593
+ }
22594
+ function listWindows() {
22595
+ const handles = [];
22596
+ const collect = closure("<HWND>ptr <>ptr -> i32", (h2) => {
22597
+ if (h2)
22598
+ handles.push(h2);
22599
+ return handles.length < MAX_WINDOWS ? 1 : 0;
22125
22600
  });
22601
+ try {
22602
+ EnumWindows(collect.ptr, NULL);
22603
+ } finally {
22604
+ collect.dispose();
22605
+ }
22606
+ const wRect = RECT.alloc();
22607
+ const tb = WCHAR.alloc(WIDE_BUF_CHARS);
22608
+ const cb = WCHAR.alloc(WIDE_BUF_CHARS);
22609
+ const out = [];
22610
+ for (const hwnd of handles) {
22611
+ if (GetWindowRect(hwnd, wRect.ptr)) {
22612
+ const rc2 = RECT.decode(wRect);
22613
+ const tl = GetWindowText(hwnd, tb, WIDE_BUF_CHARS);
22614
+ const cl = GetClassName(hwnd, cb, WIDE_BUF_CHARS);
22615
+ out.push({
22616
+ hwnd,
22617
+ // 缓冲跨窗口复用:长度 0 时 API 不保证写回终止符,不能 decode 残留内容
22618
+ title: tl > 0 ? WCHAR.decode(tb) : "",
22619
+ className: cl > 0 ? WCHAR.decode(cb) : "",
22620
+ rect: { left: rc2.left, top: rc2.top, right: rc2.right, bottom: rc2.bottom },
22621
+ visible: IsWindowVisible(hwnd) !== 0,
22622
+ minimized: IsIconic(hwnd) !== 0
22623
+ });
22624
+ }
22625
+ }
22626
+ return out;
22627
+ }
22628
+ var DISP_CHANGE_NAME = {
22629
+ [
22630
+ 0
22631
+ /* DisplayChangeResult.SUCCESSFUL */
22632
+ ]: "SUCCESSFUL",
22633
+ [
22634
+ 1
22635
+ /* DisplayChangeResult.RESTART */
22636
+ ]: "RESTART",
22637
+ [
22638
+ -1
22639
+ /* DisplayChangeResult.FAILED */
22640
+ ]: "FAILED",
22641
+ [
22642
+ -2
22643
+ /* DisplayChangeResult.BADMODE */
22644
+ ]: "BADMODE",
22645
+ [
22646
+ -3
22647
+ /* DisplayChangeResult.NOTUPDATED */
22648
+ ]: "NOTUPDATED",
22649
+ [
22650
+ -4
22651
+ /* DisplayChangeResult.BADFLAGS */
22652
+ ]: "BADFLAGS",
22653
+ [
22654
+ -5
22655
+ /* DisplayChangeResult.BADPARAM */
22656
+ ]: "BADPARAM",
22657
+ [
22658
+ -6
22659
+ /* DisplayChangeResult.BADDUALVIEW */
22660
+ ]: "BADDUALVIEW"
22661
+ };
22662
+ function dispChangeName(ret) {
22663
+ return DISP_CHANGE_NAME[ret] ?? "?";
22664
+ }
22665
+ function currentScreen() {
22666
+ return GetSystemMetrics(
22667
+ 0
22668
+ /* SysMetrics.CXSCREEN */
22669
+ ) + "x" + GetSystemMetrics(
22670
+ 1
22671
+ /* SysMetrics.CYSCREEN */
22672
+ );
22673
+ }
22674
+ function listModes32() {
22675
+ const probe = DEVMODEW.encode({ dmSize: DEVMODEW.size });
22676
+ const out = [];
22677
+ for (let i2 = 0; i2 < 200; i2++) {
22678
+ if (!EnumDisplaySettings(NULL, i2, probe.ptr))
22679
+ break;
22680
+ const dm = DEVMODEW.decode(probe);
22681
+ if (dm.dmBitsPerPel !== 32)
22682
+ continue;
22683
+ out.push(dm.dmPelsWidth + "x" + dm.dmPelsHeight + "@" + dm.dmDisplayFrequency);
22684
+ }
22685
+ return out;
22686
+ }
22687
+ function applyDisplayMode(w2, h2, persist) {
22688
+ if (!Number.isInteger(w2) || w2 <= 0 || !Number.isInteger(h2) || h2 <= 0) {
22689
+ throw new Error("applyDisplayMode: w/h must be positive integers, got " + w2 + "x" + h2);
22690
+ }
22691
+ const dm = DEVMODEW.encode({ dmSize: DEVMODEW.size });
22692
+ if (!EnumDisplaySettings(NULL, -1, dm.ptr)) {
22693
+ throw new Error("applyDisplayMode: EnumDisplaySettings CURRENT failed");
22694
+ }
22695
+ const cur = DEVMODEW.decode(dm);
22696
+ const before = cur.dmPelsWidth + "x" + cur.dmPelsHeight;
22697
+ DEVMODEW.encode({
22698
+ dmFields: cur.dmFields | 524288 | 1048576,
22699
+ dmPelsWidth: w2,
22700
+ dmPelsHeight: h2
22701
+ }, dm);
22702
+ const testRet = ChangeDisplaySettings(
22703
+ dm.ptr,
22704
+ 2
22705
+ /* ChangeDisplayFlag.TEST */
22706
+ );
22707
+ if (testRet !== 0) {
22708
+ return {
22709
+ before,
22710
+ after: currentScreen(),
22711
+ testRet,
22712
+ ret: testRet,
22713
+ retName: dispChangeName(testRet),
22714
+ modes32: listModes32()
22715
+ };
22716
+ }
22717
+ let ret = ChangeDisplaySettings(dm.ptr, 0);
22718
+ if (ret === 0 && persist) {
22719
+ ret = ChangeDisplaySettings(
22720
+ dm.ptr,
22721
+ 1
22722
+ /* ChangeDisplayFlag.UPDATEREGISTRY */
22723
+ );
22724
+ }
22725
+ return { before, after: currentScreen(), testRet, ret, retName: dispChangeName(ret), modes32: listModes32() };
22726
+ }
22727
+ var USAGE = `quickwin execd \u2014\u2014 \u672C\u9875\u5373\u7528\u6CD5\uFF08API \u4E4B\u5916\u4EFB\u610F\u8DEF\u5F84\u5747\u8FD4\u56DE\uFF0CHTTP 200\uFF09
22728
+
22729
+ API\uFF08\u914D\u7F6E token \u540E\u9700 Authorization: Bearer <token>\uFF0C\u672A\u914D\u7F6E\u5219\u653E\u884C\uFF09\uFF1A
22730
+ POST /exec JSON {"cmd":"\u547D\u4EE4","timeout":\u6BEB\u79D2?} \u2192 \u6D41\u5F0F\u8F93\u51FA\uFF0CTrailer X-Exit-Code
22731
+ GET /screenshot ?hwnd=<\u5341\u8FDB\u5236>&area=window|client&mode=screen|print \u2192 image/bmp
22732
+ \uFF08X-Dimensions\uFF1B\u4E0D\u5E26 hwnd = \u6574\u5C4F BitBlt\uFF1B\u5E26 hwnd \u9ED8\u8BA4 mode=print
22733
+ \u8BA9\u7A97\u53E3\u81EA\u7ED8\u2014\u2014\u906E\u6321/\u6700\u5C0F\u5316/\u8D85\u5C4F\u4E5F\u62FF\u5B8C\u6574\u50CF\u7D20\uFF0Cscreen \u53EA\u622A\u53EF\u89C1\u90E8\u5206\uFF09
22734
+ GET /window_list \u2192 JSON \u7A97\u53E3\u5217\u8868 [{hwnd,title,className,...}]
22735
+ GET /tray_list \u2192 JSON {icons:[{area,index,hWnd,uID,tooltip,rect}]}\uFF08\u8DE8\u8FDB\u7A0B\u679A\u4E3E
22736
+ explorer toolbar\uFF1A\u53EF\u89C1\u533A Shell_TrayWnd + \u6298\u53E0\u533A NotifyIconOverflowWindow\uFF1B
22737
+ rect \u5C4F\u5E55\u7269\u7406\u50CF\u7D20\uFF0C\u5168 0 \u2192 null\uFF1B\u6298\u53E0\u9762\u677F\u672A\u5C55\u5F00\u65F6 overflow \u533A rect
22738
+ \u4EC5\u5F53\u5C55\u5F00\u540E\u53EF\u9760\uFF09\uFF1B?probe=<hwnd>&uid=<n> \u2192 \u9644 probe {hr,hrName,rect}
22739
+ \uFF08\u5355\u56FE\u6807 Shell_NotifyIconGetRect\uFF0CWin7+\uFF1A0=found \u9644\u5BB9\u5668 rect / 1=hidden
22740
+ / E_FAIL=\u4E0D\u5B58\u5728\u6216 GUID \u56FE\u6807\uFF1BXP \u65E0\u6B64 API \u2192 unsupported\uFF09
22741
+ POST /set_resolution ?w=<px>&h=<px>&persist=0|1\uFF08\u9ED8\u8BA4 1 = \u5199\u6CE8\u518C\u8868\u8DE8\u91CD\u542F\uFF09\u2192 JSON
22742
+ {before,after,testRet,ret,retName,modes32}\uFF1Bmodes32 \u6052\u5E26 32bpp
22743
+ \u53EF\u7528\u6A21\u5F0F\uFF08\u975E\u6CD5\u5BBD\u9AD8\u4F1A\u4EE5 BADMODE \u62D2\u7EDD\u5E76\u7ED9\u672C\u5217\u8868\uFF09
22744
+ POST /input body = JSON \u6570\u7EC4\uFF08\u6279\u91CF\u6CE8\u5165\uFF1Bx/y \u7269\u7406\u50CF\u7D20\uFF09\uFF1A
22745
+ {"t":"move","x":,"y":} | {"t":"down|up","btn":"left|right|middle|x1|x2","x":,"y":?} |
22746
+ {"t":"key","key":"a|enter|0x41","up":true?} | {"t":"sleep","ms":0..5000}
22747
+ \u2192 JSON {sent,expected}\uFF1B\u6309 sleep \u5207\u6BB5\uFF0C\u6BB5\u5185\u4E00\u6B21 SendInput \u539F\u5B50\u6CE8\u5165`;
22748
+ function usageResponse() {
22749
+ return new Response(USAGE, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
22750
+ }
22751
+ var INPUT_MOUSE = 0;
22752
+ var INPUT_KEYBOARD = 1;
22753
+ var MOUSEEVENTF_MOVE = 1;
22754
+ var MOUSEEVENTF_ABSOLUTE = 32768;
22755
+ var KEYEVENTF_KEYUP = 2;
22756
+ var MOUSE_BTNS = {
22757
+ left: [2, 4, 0],
22758
+ right: [8, 16, 0],
22759
+ middle: [32, 64, 0],
22760
+ x1: [128, 256, 1],
22761
+ x2: [128, 256, 2]
22762
+ };
22763
+ var VK_NAMES = {
22764
+ backspace: 8,
22765
+ tab: 9,
22766
+ enter: 13,
22767
+ shift: 16,
22768
+ ctrl: 17,
22769
+ alt: 18,
22770
+ caps: 20,
22771
+ esc: 27,
22772
+ space: 32,
22773
+ pageup: 33,
22774
+ pagedown: 34,
22775
+ end: 35,
22776
+ home: 36,
22777
+ left: 37,
22778
+ up: 38,
22779
+ right: 39,
22780
+ down: 40,
22781
+ insert: 45,
22782
+ delete: 46,
22783
+ win: 91,
22784
+ f1: 112,
22785
+ f2: 113,
22786
+ f3: 114,
22787
+ f4: 115,
22788
+ f5: 116,
22789
+ f6: 117,
22790
+ f7: 118,
22791
+ f8: 119,
22792
+ f9: 120,
22793
+ f10: 121,
22794
+ f11: 122,
22795
+ f12: 123
22796
+ };
22797
+ function vkOf(key) {
22798
+ if (typeof key === "number" && Number.isInteger(key) && key >= 0 && key <= 65535)
22799
+ return key;
22800
+ if (typeof key === "string") {
22801
+ if (key.length === 1) {
22802
+ const c2 = key.toUpperCase().charCodeAt(0);
22803
+ if (c2 >= 48 && c2 <= 57 || c2 >= 65 && c2 <= 90)
22804
+ return c2;
22805
+ }
22806
+ const vk = VK_NAMES[key.toLowerCase()];
22807
+ if (vk !== void 0)
22808
+ return vk;
22809
+ }
22810
+ throw new Error("bad key: " + JSON.stringify(key) + " (a-z/0-9|name|0..0xFFFF)");
22126
22811
  }
22127
22812
  var server = createServer(async (req) => {
22128
22813
  const t0 = Date.now();
22129
22814
  const path = new URL(req.url).pathname;
22130
- if (req.method === "GET" && (path === "/" || path === "/health")) {
22131
- return new Response("ok", { headers: { "Content-Type": "text/plain" } });
22132
- }
22815
+ const isApi = req.method === "POST" && (path === "/exec" || path === "/set_resolution" || path === "/input") || req.method === "GET" && (path === "/window_list" || path === "/screenshot" || path === "/tray_list");
22816
+ if (!isApi)
22817
+ return usageResponse();
22133
22818
  const denied = authCheck(req);
22134
22819
  if (denied !== null) {
22135
- appendLog({ ts: Date.now() / 1e3, cmd: req.method + " " + path, status: 401, exit: null, durMs: Date.now() - t0, note: "missing/invalid token" });
22820
+ logReq(t0, req.method + " " + path, 401, "missing/invalid token");
22136
22821
  return denied;
22137
22822
  }
22138
22823
  if (req.method === "GET" && path === "/window_list") {
22139
- const resp = await windowsResponse();
22140
- appendLog({ ts: Date.now() / 1e3, cmd: "GET /window_list", status: resp.status, exit: null, durMs: Date.now() - t0 });
22141
- return resp;
22824
+ try {
22825
+ const wins = listWindows();
22826
+ const resp = new Response(JSON.stringify(wins), { headers: { "Content-Type": "application/json" } });
22827
+ logReq(t0, "GET /window_list", 200);
22828
+ return resp;
22829
+ } catch (ex) {
22830
+ logReq(t0, "GET /window_list", 500, String(ex));
22831
+ return jsonError(500, String(ex));
22832
+ }
22833
+ }
22834
+ if (req.method === "GET" && path === "/tray_list") {
22835
+ const params = new URL(req.url).searchParams;
22836
+ let probe = null;
22837
+ const ph = params.get("probe");
22838
+ if (ph !== null) {
22839
+ const hh = Number(ph), uid = Number(params.get("uid") ?? "");
22840
+ if (!Number.isInteger(hh) || hh <= 0 || !Number.isInteger(uid) || uid < 0) {
22841
+ logReq(t0, "GET /tray_list", 400, "probe=<hwnd>&uid=<n>");
22842
+ return jsonError(400, "probe needs integer hwnd>0 and uid>=0");
22843
+ }
22844
+ probe = { hWnd: hh, uID: uid };
22845
+ }
22846
+ try {
22847
+ const icons = listTrayIcons();
22848
+ const body = { icons };
22849
+ if (probe)
22850
+ body.probe = probeTrayIcon(probe.hWnd, probe.uID);
22851
+ const nOv = icons.reduce((n2, e2) => n2 + (e2.area === "overflow" ? 1 : 0), 0);
22852
+ logReq(t0, "GET /tray_list", 200, icons.length + " icons \xB7 overflow " + nOv);
22853
+ return new Response(JSON.stringify(body), { headers: { "Content-Type": "application/json" } });
22854
+ } catch (ex) {
22855
+ logReq(t0, "GET /tray_list", 500, String(ex));
22856
+ return jsonError(500, String(ex));
22857
+ }
22142
22858
  }
22143
22859
  if (req.method === "GET" && path === "/screenshot") {
22144
22860
  let opts;
22145
22861
  try {
22146
22862
  opts = parseShotOpts(new URL(req.url).searchParams);
22147
22863
  } catch (ex) {
22148
- appendLog({ ts: Date.now() / 1e3, cmd: "GET /screenshot", status: 400, exit: null, durMs: Date.now() - t0, note: String(ex) });
22864
+ logReq(t0, "GET /screenshot", 400, String(ex));
22149
22865
  return jsonError(400, String(ex));
22150
22866
  }
22151
- const resp = await screenshotResponse(opts);
22867
+ let cap;
22868
+ try {
22869
+ cap = opts.hwnd === null ? captureScreen() : captureWindow(opts.hwnd, opts.area, opts.mode);
22870
+ } catch (ex) {
22871
+ logReq(t0, "GET /screenshot", 500, String(ex));
22872
+ return jsonError(500, String(ex));
22873
+ }
22152
22874
  const target = opts.hwnd !== null ? " hwnd=" + opts.hwnd + " " + opts.area + "/" + opts.mode : " screen";
22153
- appendLog({ ts: Date.now() / 1e3, cmd: "GET /screenshot" + target, status: resp.status, exit: null, durMs: Date.now() - t0 });
22875
+ logReq(t0, "GET /screenshot" + target, 200);
22876
+ return new Response(cap.bmp, {
22877
+ headers: { "Content-Type": "image/bmp", "X-Dimensions": cap.width + "x" + cap.height }
22878
+ });
22879
+ }
22880
+ if (req.method === "POST" && path === "/set_resolution") {
22881
+ let result;
22882
+ let w2 = 0, h2 = 0, persist = true;
22883
+ try {
22884
+ const params = new URL(req.url).searchParams;
22885
+ w2 = Number(params.get("w"));
22886
+ h2 = Number(params.get("h"));
22887
+ if (!Number.isInteger(w2) || w2 <= 0 || !Number.isInteger(h2) || h2 <= 0) {
22888
+ throw new Error("w/h must be positive integers");
22889
+ }
22890
+ persist = params.get("persist") !== "0";
22891
+ result = applyDisplayMode(w2, h2, persist);
22892
+ } catch (ex) {
22893
+ logReq(t0, "POST /set_resolution", 400, String(ex));
22894
+ return jsonError(400, String(ex));
22895
+ }
22896
+ const resp = new Response(JSON.stringify(result), { headers: { "Content-Type": "application/json" } });
22897
+ logReq(t0, "POST /set_resolution " + w2 + "x" + h2 + (persist ? "" : " persist=0"), 200, result.ret !== 0 ? result.retName : void 0);
22154
22898
  return resp;
22155
22899
  }
22900
+ if (req.method === "POST" && path === "/input") {
22901
+ const bad = (msg) => {
22902
+ logReq(t0, "POST /input", 400, msg);
22903
+ return jsonError(400, msg);
22904
+ };
22905
+ let raw;
22906
+ try {
22907
+ raw = await req.json();
22908
+ } catch (ex) {
22909
+ return bad("bad json: " + String(ex));
22910
+ }
22911
+ if (!Array.isArray(raw) || raw.length === 0)
22912
+ return bad("body must be a non-empty JSON array");
22913
+ if (raw.length > 1e3)
22914
+ return bad("too many events: " + raw.length + " (max 1000)");
22915
+ const sw = GetSystemMetrics(0), sh = GetSystemMetrics(1);
22916
+ const segs = [{ els: [], sleep: 0 }];
22917
+ const cur = () => segs[segs.length - 1];
22918
+ try {
22919
+ for (const e2 of raw) {
22920
+ if (typeof e2 !== "object" || e2 === null || Array.isArray(e2))
22921
+ throw new Error("event must be an object: " + JSON.stringify(e2));
22922
+ const ev = e2;
22923
+ const abs = (required) => {
22924
+ if (ev.x === void 0 && ev.y === void 0) {
22925
+ if (required)
22926
+ throw new Error("x/y required for move");
22927
+ return [0, 0, 0];
22928
+ }
22929
+ const x2 = ev.x, y2 = ev.y;
22930
+ if (typeof x2 !== "number" || typeof y2 !== "number" || !Number.isInteger(x2) || !Number.isInteger(y2))
22931
+ throw new Error("x/y must be integers (physical px)");
22932
+ if (x2 < 0 || x2 >= sw || y2 < 0 || y2 >= sh)
22933
+ throw new Error("x/y out of screen: 0.." + (sw - 1) + " / 0.." + (sh - 1));
22934
+ return [
22935
+ Math.round(x2 * 65535 / (sw - 1)),
22936
+ Math.round(y2 * 65535 / (sh - 1)),
22937
+ MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE
22938
+ ];
22939
+ };
22940
+ switch (ev.t) {
22941
+ case "move": {
22942
+ const [dx, dy, f2] = abs(true);
22943
+ cur().els.push({ type: INPUT_MOUSE, data: { mi: { dx, dy, dwFlags: f2 } } });
22944
+ break;
22945
+ }
22946
+ case "down":
22947
+ case "up": {
22948
+ const btn = typeof ev.btn === "string" ? MOUSE_BTNS[ev.btn] : void 0;
22949
+ if (!btn)
22950
+ throw new Error("bad btn: " + JSON.stringify(ev.btn) + " (left|right|middle|x1|x2)");
22951
+ const [downF, upF, mData] = btn;
22952
+ const [dx, dy, f2] = abs(false);
22953
+ const flag = ev.t === "down" ? downF : upF;
22954
+ cur().els.push({ type: INPUT_MOUSE, data: { mi: { dx, dy, mouseData: mData, dwFlags: f2 | flag } } });
22955
+ break;
22956
+ }
22957
+ case "key": {
22958
+ const up = ev.up === true;
22959
+ cur().els.push({ type: INPUT_KEYBOARD, data: { ki: { wVk: vkOf(ev.key), dwFlags: up ? KEYEVENTF_KEYUP : 0 } } });
22960
+ break;
22961
+ }
22962
+ case "sleep": {
22963
+ const ms = ev.ms;
22964
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0 || ms > 5e3)
22965
+ throw new Error("sleep ms must be a number in 0..5000");
22966
+ segs.push({ els: [], sleep: ms });
22967
+ break;
22968
+ }
22969
+ default:
22970
+ throw new Error("bad t: " + JSON.stringify(ev.t) + " (move|down|up|key|sleep)");
22971
+ }
22972
+ }
22973
+ } catch (ex) {
22974
+ return bad(ex instanceof Error ? ex.message : String(ex));
22975
+ }
22976
+ let expected = 0, sent = 0;
22977
+ for (const s2 of segs)
22978
+ expected += s2.els.length;
22979
+ try {
22980
+ for (const seg of segs) {
22981
+ if (seg.sleep > 0)
22982
+ await new Promise((r2) => {
22983
+ os7.setTimeout(r2, seg.sleep);
22984
+ });
22985
+ if (seg.els.length === 0)
22986
+ continue;
22987
+ const n2 = SendInput(seg.els.length, seg.els, INPUT.size);
22988
+ sent += n2;
22989
+ if (n2 < seg.els.length)
22990
+ break;
22991
+ }
22992
+ } catch (ex) {
22993
+ logReq(t0, "POST /input", 500, String(ex));
22994
+ return jsonError(500, String(ex));
22995
+ }
22996
+ logReq(t0, "POST /input " + raw.length + "ev", 200, sent < expected ? "sent " + sent + "/" + expected : void 0);
22997
+ return new Response(JSON.stringify({ sent, expected }), { headers: { "Content-Type": "application/json" } });
22998
+ }
22156
22999
  if (req.method === "POST" && path === "/exec") {
22157
23000
  let out;
22158
23001
  let cmd;
@@ -22163,29 +23006,17 @@ var server = createServer(async (req) => {
22163
23006
  cmd = body.cmd;
22164
23007
  out = runInWorker(body.cmd, req.signal, timeoutMs);
22165
23008
  } catch (ex) {
22166
- return new Response(JSON.stringify({ error: "setup: " + String(ex) }), {
22167
- status: 500,
22168
- headers: { "Content-Type": "application/json" }
22169
- });
23009
+ return jsonError(500, "setup: " + String(ex));
22170
23010
  }
22171
23011
  try {
22172
23012
  const rd = await out.ready;
22173
23013
  if (!rd.ok) {
22174
- appendLog({ ts: Date.now() / 1e3, cmd, status: 500, exit: null, durMs: Date.now() - t0, note: rd.error });
22175
- return new Response(JSON.stringify({ error: rd.error }), {
22176
- status: 500,
22177
- headers: { "Content-Type": "application/json" }
22178
- });
23014
+ logReq(t0, cmd, 500, rd.error);
23015
+ return jsonError(500, rd.error ?? "exec failed");
22179
23016
  }
22180
23017
  out.trailers.then((h2) => {
22181
23018
  const code = h2["X-Exit-Code"];
22182
- appendLog({
22183
- ts: Date.now() / 1e3,
22184
- cmd,
22185
- status: 200,
22186
- exit: code === void 0 ? null : Number(code),
22187
- durMs: Date.now() - t0
22188
- });
23019
+ logReq(t0, cmd, 200, void 0, code === void 0 ? null : Number(code));
22189
23020
  }).catch(() => {
22190
23021
  });
22191
23022
  return new Response(out.stream, {
@@ -22196,15 +23027,11 @@ var server = createServer(async (req) => {
22196
23027
  trailers: out.trailers
22197
23028
  });
22198
23029
  } catch (ex) {
22199
- appendLog({ ts: Date.now() / 1e3, cmd, status: 504, exit: null, durMs: Date.now() - t0, note: "exec timeout" });
22200
- return new Response(JSON.stringify({ error: String(ex) }), {
22201
- status: 504,
22202
- headers: { "Content-Type": "application/json" }
22203
- });
23030
+ logReq(t0, cmd, 504, "exec timeout");
23031
+ return jsonError(504, String(ex));
22204
23032
  }
22205
23033
  }
22206
- appendLog({ ts: Date.now() / 1e3, cmd: req.method + " " + path, status: 404, exit: null, durMs: Date.now() - t0 });
22207
- return new Response("Not Found", { status: 404 });
23034
+ return usageResponse();
22208
23035
  });
22209
23036
  var rc = server.listen(8080, "0.0.0.0");
22210
23037
  console.log("listen rc=" + rc + " addr=" + JSON.stringify(server.address()));