quickwin 2.2.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.en.md +7 -7
  2. package/README.md +7 -7
  3. package/constants.ts +1070 -0
  4. package/enum_map.d.ts +130 -0
  5. package/examples/PdfCanvas.js +2 -2
  6. package/examples/PdfCanvas.tsx +3 -2
  7. package/examples/{execd.js → execd/main.js} +717 -148
  8. package/examples/execd/tray.js +192 -0
  9. package/examples/{execd_worker.js → execd/worker.js} +7 -7
  10. package/examples/pdf_preview2.js +46 -46
  11. package/examples/pdf_preview2.ts +55 -54
  12. package/examples/pdf_viewer.js +34 -19
  13. package/examples/pdf_viewer.tsx +6 -5
  14. package/examples/test_gallery.js +35 -20
  15. package/examples/test_gallery.tsx +9 -8
  16. package/examples/test_react_lazy.js +34 -19
  17. package/examples/test_react_lazy.tsx +7 -6
  18. package/examples/test_react_listbox.js +34 -19
  19. package/examples/test_react_listbox.tsx +8 -7
  20. package/examples/test_root_window.js +34 -19
  21. package/examples/test_root_window.tsx +5 -5
  22. package/examples/test_tab.js +34 -19
  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/http-server.js +54 -29
  33. package/lib/http-server.ts +56 -27
  34. package/lib/react-qw/components/Button.js +2 -2
  35. package/lib/react-qw/components/CheckBox.js +4 -4
  36. package/lib/react-qw/components/ComboBox.js +10 -10
  37. package/lib/react-qw/components/DateTimePicker.js +12 -12
  38. package/lib/react-qw/components/Input.js +7 -7
  39. package/lib/react-qw/components/Link.js +4 -4
  40. package/lib/react-qw/components/ListBox.js +12 -12
  41. package/lib/react-qw/components/ListView.js +35 -35
  42. package/lib/react-qw/components/PathPicker.js +3 -3
  43. package/lib/react-qw/components/ProgressBar.js +4 -4
  44. package/lib/react-qw/components/RadioButton.js +4 -4
  45. package/lib/react-qw/components/ScrollView.js +28 -28
  46. package/lib/react-qw/components/Slider.js +11 -11
  47. package/lib/react-qw/components/Tab.js +10 -10
  48. package/lib/react-qw/components/Tooltip.js +8 -8
  49. package/lib/react-qw/components/TreeView.js +20 -20
  50. package/lib/react-qw/index.js +5 -5
  51. package/lib/react-qw/index.ts +6 -5
  52. package/lib/react-qw/props.js +4 -4
  53. package/lib/react-qw/props.ts +5 -4
  54. package/lib/react-qw/reconciler.js +10 -10
  55. package/lib/react-qw/reconciler.ts +11 -10
  56. package/lib/text-measure.js +3 -3
  57. package/lib/text-measure.ts +4 -3
  58. package/lib/websocket.js +17 -17
  59. package/lib/websocket.ts +18 -17
  60. package/lib/windows/advapi32.js +7 -7
  61. package/lib/windows/advapi32.ts +7 -7
  62. package/lib/windows/gdi32.js +16 -16
  63. package/lib/windows/gdi32.ts +16 -16
  64. package/lib/windows/kernel32.js +41 -2
  65. package/lib/windows/kernel32.ts +45 -2
  66. package/lib/windows/shell32.js +24 -3
  67. package/lib/windows/shell32.ts +27 -4
  68. package/lib/windows/structs.js +54 -0
  69. package/lib/windows/structs.ts +63 -1
  70. package/lib/windows/user32.js +18 -6
  71. package/lib/windows/user32.ts +18 -6
  72. package/lib/windows/winspool.js +3 -3
  73. package/lib/windows/winspool.ts +3 -3
  74. package/package.json +4 -3
  75. package/quickwin.d.ts +32 -10
  76. package/qwin-nowasm-x86.exe +0 -0
  77. package/qwin-nowasm.exe +0 -0
  78. package/qwin-x86.exe +0 -0
  79. package/qwin.exe +0 -0
  80. package/test/test_ffi_bind.js +7 -7
  81. package/test/test_ffi_bind.ts +8 -8
  82. package/test/test_ffi_struct.js +2 -2
  83. package/test/test_ffi_struct.ts +3 -3
  84. package/test/test_ffi_windows.js +1 -1
  85. package/test/test_ffi_windows.ts +1 -1
  86. package/test/test_files.js +7 -7
  87. package/test/test_files.ts +8 -8
  88. package/test/test_gdi_draw.js +51 -51
  89. package/test/test_gdi_draw.ts +57 -57
  90. package/test/test_http_server.js +3 -3
  91. package/test/test_http_server.ts +4 -3
  92. package/test/test_ipv6.js +3 -3
  93. package/test/test_ipv6.ts +4 -3
  94. package/test/test_net_event.js +3 -3
  95. package/test/test_net_event.ts +4 -3
  96. package/test/test_printer.js +4 -4
  97. package/test/test_printer.ts +5 -5
  98. package/test/test_react_complex.js +36 -21
  99. package/test/test_react_counter.js +34 -19
  100. package/test/test_react_flex.js +36 -21
  101. package/test/test_react_hidden.js +34 -19
  102. package/test/test_react_listview_link.js +35 -20
  103. package/test/test_react_notify.js +52 -37
  104. package/test/test_react_render.js +34 -19
  105. package/test/test_registry.js +6 -6
  106. package/test/test_registry.ts +8 -8
  107. package/test/test_wolfssl_read.js +8 -8
  108. package/test/test_wolfssl_read.ts +9 -8
  109. package/examples/execd.tsx +0 -798
  110. package/examples/execd_worker.ts +0 -127
  111. package/quickwin_const.d.ts +0 -1063
@@ -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/execd.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");
@@ -18535,6 +18535,8 @@ function concatU8(parts) {
18535
18535
  return out;
18536
18536
  }
18537
18537
  function toArrayBuffer(u8) {
18538
+ if (u8.byteOffset === 0 && u8.byteLength === u8.buffer.byteLength)
18539
+ return u8.buffer;
18538
18540
  return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength);
18539
18541
  }
18540
18542
  function findCrLfCrLf(buf) {
@@ -18694,6 +18696,7 @@ var HttpServer = class {
18694
18696
  const c2 = {
18695
18697
  sock: ac.handle,
18696
18698
  parts: [],
18699
+ partsLen: 0,
18697
18700
  pending: null,
18698
18701
  current: null,
18699
18702
  outQueue: null,
@@ -18732,7 +18735,9 @@ function onRead(c2) {
18732
18735
  const d2 = sock.recv(c2.sock, 8192);
18733
18736
  if (!d2)
18734
18737
  break;
18735
- c2.parts.push(new Uint8Array(d2));
18738
+ const u8 = new Uint8Array(d2);
18739
+ c2.parts.push(u8);
18740
+ c2.partsLen += u8.length;
18736
18741
  }
18737
18742
  if (!c2.closed)
18738
18743
  tryProcess(c2);
@@ -18822,11 +18827,17 @@ async function writeStreamingBody(c2, body, chunked, trailer) {
18822
18827
  if (done)
18823
18828
  break;
18824
18829
  if (value && value.byteLength > 0) {
18825
- const frame = chunked ? encodeChunkFrame(value, enc) : value;
18826
- if (!queueSend(c2, frame)) {
18827
- await new Promise((resolve) => {
18828
- c2.resumeRead = resolve;
18829
- });
18830
+ const MAX_SEND = 65536;
18831
+ for (let off = 0; off < value.byteLength; off += MAX_SEND) {
18832
+ const piece = value.byteLength <= MAX_SEND ? value : value.subarray(off, Math.min(off + MAX_SEND, value.byteLength));
18833
+ const frame = chunked ? encodeChunkFrame(piece, enc) : piece;
18834
+ if (!queueSend(c2, frame)) {
18835
+ await new Promise((resolve) => {
18836
+ c2.resumeRead = resolve;
18837
+ });
18838
+ }
18839
+ if (c2.closed)
18840
+ break;
18830
18841
  }
18831
18842
  }
18832
18843
  }
@@ -18867,36 +18878,36 @@ function whole(c2) {
18867
18878
  function trimParts(c2, buf, consumed) {
18868
18879
  if (consumed >= buf.length) {
18869
18880
  c2.parts = [];
18881
+ c2.partsLen = 0;
18870
18882
  } else {
18871
18883
  c2.parts = [buf.subarray(consumed)];
18884
+ c2.partsLen = buf.length - consumed;
18872
18885
  }
18873
18886
  }
18874
18887
  function tryProcess(c2) {
18875
18888
  if (c2.closed || c2.current)
18876
18889
  return;
18877
- const buf = whole(c2);
18878
18890
  if (c2.pending) {
18879
18891
  const bodyStart2 = c2.pending.bodyStart;
18880
18892
  const parsed2 = c2.pending.parsed;
18881
- let body;
18882
- let end;
18883
- if (parsed2.chunked) {
18884
- const dec = decodeChunked(buf, bodyStart2);
18885
- if (!dec)
18893
+ if (!parsed2.chunked) {
18894
+ const end = bodyStart2 + parsed2.contentLength;
18895
+ if (end > c2.partsLen)
18886
18896
  return;
18887
- body = dec.data;
18888
- end = dec.end;
18889
- } else {
18890
- const needed = parsed2.contentLength;
18891
- if (bodyStart2 + needed > buf.length)
18892
- return;
18893
- body = buf.subarray(bodyStart2, bodyStart2 + needed);
18894
- end = bodyStart2 + needed;
18897
+ const buf3 = whole(c2);
18898
+ c2.pending = null;
18899
+ dispatchRequest(c2, parsed2, buf3.subarray(bodyStart2, end), end, buf3);
18900
+ return;
18895
18901
  }
18902
+ const buf2 = whole(c2);
18903
+ const dec = decodeChunked(buf2, bodyStart2);
18904
+ if (!dec)
18905
+ return;
18896
18906
  c2.pending = null;
18897
- dispatchRequest(c2, parsed2, body, end);
18907
+ dispatchRequest(c2, parsed2, dec.data, dec.end, buf2);
18898
18908
  return;
18899
18909
  }
18910
+ const buf = whole(c2);
18900
18911
  const headerEnd = findCrLfCrLf(buf);
18901
18912
  if (headerEnd < 0)
18902
18913
  return;
@@ -18914,18 +18925,18 @@ function tryProcess(c2) {
18914
18925
  c2.pending = { parsed, bodyStart };
18915
18926
  return;
18916
18927
  }
18917
- dispatchRequest(c2, parsed, dec.data, dec.end);
18928
+ dispatchRequest(c2, parsed, dec.data, dec.end, buf);
18918
18929
  } else if (parsed.contentLength > 0) {
18919
18930
  if (bodyStart + parsed.contentLength > buf.length) {
18920
18931
  c2.pending = { parsed, bodyStart };
18921
18932
  return;
18922
18933
  }
18923
- dispatchRequest(c2, parsed, buf.subarray(bodyStart, bodyStart + parsed.contentLength), bodyStart + parsed.contentLength);
18934
+ dispatchRequest(c2, parsed, buf.subarray(bodyStart, bodyStart + parsed.contentLength), bodyStart + parsed.contentLength, buf);
18924
18935
  } else {
18925
- dispatchRequest(c2, parsed, new Uint8Array(0), bodyStart);
18936
+ dispatchRequest(c2, parsed, new Uint8Array(0), bodyStart, buf);
18926
18937
  }
18927
18938
  }
18928
- function dispatchRequest(c2, parsed, body, end) {
18939
+ function dispatchRequest(c2, parsed, body, end, wholeBuf) {
18929
18940
  const connHeader = (parsed.headers["connection"] || "").toLowerCase();
18930
18941
  if (parsed.version === "HTTP/1.1")
18931
18942
  c2.keepAlive = connHeader.indexOf("close") < 0;
@@ -18948,7 +18959,7 @@ function dispatchRequest(c2, parsed, body, end) {
18948
18959
  });
18949
18960
  c2.ac = ac;
18950
18961
  c2.current = { req };
18951
- trimParts(c2, whole(c2), end);
18962
+ trimParts(c2, wholeBuf ?? whole(c2), end);
18952
18963
  void handleRequest(c2);
18953
18964
  }
18954
18965
  async function handleRequest(c2) {
@@ -19044,10 +19055,10 @@ async function sendResponse(c2, method, res) {
19044
19055
  await writeStreamingBody(c2, res.body, chunked, chunked && trailerDeclared ? res.trailers : void 0);
19045
19056
  }
19046
19057
 
19047
- // _build/examples/execd.js
19048
- import * as os6 from "os";
19058
+ // _build/examples/execd/main.js
19059
+ import * as os7 from "os";
19049
19060
  import * as std2 from "std";
19050
- import * as gui18 from "gui";
19061
+ import * as gui19 from "gui";
19051
19062
 
19052
19063
  // _build/lib/exec-log.js
19053
19064
  var RequestLog = class {
@@ -19566,13 +19577,13 @@ function lower(v2) {
19566
19577
  type: { tag: "array", elementType: el.type, elementSize: el.size }
19567
19578
  };
19568
19579
  }
19569
- const b7 = /^([A-Za-z_]\w*):(\d+)$/.exec(v2);
19570
- if (b7) {
19571
- const rawUnit = b7[1];
19580
+ const b8 = /^([A-Za-z_]\w*):(\d+)$/.exec(v2);
19581
+ if (b8) {
19582
+ const rawUnit = b8[1];
19572
19583
  const unit = normToken(rawUnit);
19573
19584
  if (!isCNumberToken(unit) || unit === "f32" || unit === "f64")
19574
19585
  throw new Error(`ffi-struct: bitfield unit must be an integer type, got "${rawUnit}"`);
19575
- const width = Number(b7[2]);
19586
+ const width = Number(b8[2]);
19576
19587
  const s3 = SizeAlign[unit];
19577
19588
  const cap = s3 * 8;
19578
19589
  if (!Number.isInteger(width) || width < 1)
@@ -19888,10 +19899,53 @@ function buildDecl(kind, member, pack) {
19888
19899
  decl[k2] = v2;
19889
19900
  return decl;
19890
19901
  }
19891
- function struct(a2, b7, c2) {
19902
+ function structArray(def) {
19903
+ const { fields, size } = def;
19904
+ const readN = (dv, n2) => {
19905
+ const out = [];
19906
+ for (let i2 = 0; i2 < n2; i2++)
19907
+ out.push(doDecode(dv, i2 * size, fields));
19908
+ return out;
19909
+ };
19910
+ return {
19911
+ encode: (els) => {
19912
+ if (!Array.isArray(els) || els.length === 0)
19913
+ throw new Error(`ffi-struct: structArray(def).encode(els) requires a non-empty element array (pass NULL for an empty pointer position)`);
19914
+ const out = def.alloc(els.length);
19915
+ for (let i2 = 0; i2 < els.length; i2++)
19916
+ def.encode(els[i2], out, i2 * def.size);
19917
+ return out;
19918
+ },
19919
+ decode: ((p2, count) => {
19920
+ if (count !== void 0 && (!Number.isInteger(count) || count < 0))
19921
+ throw new Error(`ffi-struct: structArray.decode(p, count) requires a non-negative integer count, got ${count}`);
19922
+ if (typeof p2 === "number") {
19923
+ if (count === void 0)
19924
+ throw new Error(`ffi-struct: structArray.decode(address, count) requires an explicit count (a bare address carries no length)`);
19925
+ if (count === 0)
19926
+ return [];
19927
+ return readN(new DataView(ffi2.readBytes(p2, count * size)), count);
19928
+ }
19929
+ let n2;
19930
+ if (count !== void 0) {
19931
+ n2 = count;
19932
+ if (n2 * size > p2.byteLength)
19933
+ throw new Error(`ffi-struct: structArray.decode: count ${n2} \xD7 size ${size} = ${n2 * size} exceeds buffer byteLength ${p2.byteLength}`);
19934
+ } else {
19935
+ if (p2.byteLength % size !== 0)
19936
+ throw new Error(`ffi-struct: structArray.decode: byteLength ${p2.byteLength} is not a multiple of size ${size} (mixed buffer? pass count explicitly)`);
19937
+ n2 = p2.byteLength / size;
19938
+ }
19939
+ if (n2 === 0)
19940
+ return [];
19941
+ return readN(new DataView(p2), n2);
19942
+ })
19943
+ };
19944
+ }
19945
+ function struct(a2, b8, c2) {
19892
19946
  const isNamed = typeof a2 === "string";
19893
- const raw = isNamed ? b7 : a2;
19894
- const opts = isNamed ? c2 : b7;
19947
+ const raw = isNamed ? b8 : a2;
19948
+ const opts = isNamed ? c2 : b8;
19895
19949
  return createStruct(buildDecl("struct", raw, opts?.pack));
19896
19950
  }
19897
19951
 
@@ -20185,6 +20239,41 @@ var DEVMODEW_DECL = {
20185
20239
  dmPanningHeight: "u32"
20186
20240
  };
20187
20241
  var DEVMODEW = /* @__PURE__ */ struct("DEVMODEW", DEVMODEW_DECL);
20242
+ var MOUSEINPUT_DECL = {
20243
+ "#": "struct",
20244
+ dx: "i32",
20245
+ dy: "i32",
20246
+ mouseData: "u32",
20247
+ dwFlags: "u32",
20248
+ time: "u32",
20249
+ dwExtraInfo: "<>ptr"
20250
+ };
20251
+ var KEYBDINPUT_DECL = {
20252
+ "#": "struct",
20253
+ wVk: "u16",
20254
+ wScan: "u16",
20255
+ dwFlags: "u32",
20256
+ time: "u32",
20257
+ dwExtraInfo: "<>ptr"
20258
+ };
20259
+ var INPUT_DECL = {
20260
+ "#": "struct",
20261
+ type: "u32",
20262
+ data: {
20263
+ "#": "union",
20264
+ mi: MOUSEINPUT_DECL,
20265
+ ki: KEYBDINPUT_DECL
20266
+ }
20267
+ };
20268
+ var INPUT = /* @__PURE__ */ struct("INPUT", INPUT_DECL);
20269
+ var NOTIFYICONIDENTIFIER_DECL = {
20270
+ "#": "struct",
20271
+ cbSize: "u32",
20272
+ hWnd: "<HWND>ptr",
20273
+ uID: "u32",
20274
+ guidItem: "u32[4]"
20275
+ };
20276
+ var NOTIFYICONIDENTIFIER = /* @__PURE__ */ struct("NOTIFYICONIDENTIFIER", NOTIFYICONIDENTIFIER_DECL);
20188
20277
 
20189
20278
  // _build/lib/windows/user32.js
20190
20279
  var b2 = (name, sig, encoders) => bind2("user32.dll", name, sig, encoders);
@@ -20193,13 +20282,17 @@ var LONG_PTR_SYM = os4.arch === "x64" ? "PtrW" : "W";
20193
20282
  var SetWindowPos = /* @__PURE__ */ b2("SetWindowPos", "<HWND>ptr <>ptr@SetWindowPosHwnd i32 i32 i32 i32 u32 -> i32");
20194
20283
  var GetWindowRect = /* @__PURE__ */ b2("GetWindowRect", "<HWND>ptr <RECT>ptr -> i32");
20195
20284
  var GetClientRect = /* @__PURE__ */ b2("GetClientRect", "<HWND>ptr <RECT>ptr -> i32");
20285
+ var IsWindow = /* @__PURE__ */ b2("IsWindow", "<HWND>ptr -> i32");
20196
20286
  var IsWindowVisible = /* @__PURE__ */ b2("IsWindowVisible", "<HWND>ptr -> i32");
20197
20287
  var IsIconic = /* @__PURE__ */ b2("IsIconic", "<HWND>ptr -> i32");
20288
+ var FindWindow = /* @__PURE__ */ b2("FindWindowW", "<WCHAR>ptr <WCHAR>ptr -> <HWND>ptr");
20289
+ var FindWindowEx = /* @__PURE__ */ b2("FindWindowExW", "<HWND>ptr <HWND>ptr <WCHAR>ptr <WCHAR>ptr -> <HWND>ptr");
20198
20290
  var GetWindowText = /* @__PURE__ */ b2("GetWindowTextW", "<HWND>ptr <BYTE>ptr i32 -> i32");
20199
20291
  var SetWindowText = /* @__PURE__ */ b2("SetWindowTextW", "<HWND>ptr <WCHAR>ptr -> i32");
20200
20292
  var GetClassName = /* @__PURE__ */ b2("GetClassNameW", "<HWND>ptr <BYTE>ptr i32 -> i32");
20201
20293
  var GetWindowLongPtr = /* @__PURE__ */ b2("GetWindowLong" + LONG_PTR_SYM, "<HWND>ptr i32@Gwlp -> <>ptr");
20202
20294
  var SetWindowLongPtr = /* @__PURE__ */ b2("SetWindowLong" + LONG_PTR_SYM, "<HWND>ptr i32@Gwlp <>ptr -> <>ptr");
20295
+ var GetWindowThreadProcessId = /* @__PURE__ */ b2("GetWindowThreadProcessId", "<HWND>ptr <BYTE>ptr -> u32");
20203
20296
  var EnableWindow = /* @__PURE__ */ b2("EnableWindow", "<HWND>ptr i32 -> i32");
20204
20297
  var SetParent = /* @__PURE__ */ b2("SetParent", "<HWND>ptr <HWND>ptr -> <HWND>ptr");
20205
20298
  var DefWindowProc = /* @__PURE__ */ b2("DefWindowProcW", "<HWND>ptr u32@AnyMsg <>ptr <>ptr -> <>ptr");
@@ -20214,6 +20307,8 @@ var LoadCursor = /* @__PURE__ */ b2("LoadCursorW", "<HMODULE>ptr <>ptr -> <HCURS
20214
20307
  var GetCursorPos = /* @__PURE__ */ b2("GetCursorPos", "<POINT>ptr -> i32");
20215
20308
  var ScreenToClient = /* @__PURE__ */ b2("ScreenToClient", "<HWND>ptr <POINT>ptr -> i32");
20216
20309
  var ClientToScreen = /* @__PURE__ */ b2("ClientToScreen", "<HWND>ptr <POINT>ptr -> i32");
20310
+ var INPUTArr = /* @__PURE__ */ structArray(INPUT);
20311
+ var SendInput = /* @__PURE__ */ b2("SendInput", "u32 <INPUT>ptr i32 -> u32", { INPUT: INPUTArr });
20217
20312
  var ShowScrollBar = /* @__PURE__ */ b2("ShowScrollBar", "<HWND>ptr u32 i32 -> i32");
20218
20313
  var GetSystemMetrics = /* @__PURE__ */ b2("GetSystemMetrics", "i32 -> i32");
20219
20314
  var EnumWindows = /* @__PURE__ */ b2("EnumWindows", "<>ptr <>ptr -> i32");
@@ -20266,14 +20361,14 @@ function applyProps(instance, newProps, _oldProps) {
20266
20361
  gui.ShowWindow(
20267
20362
  hwnd,
20268
20363
  newProps.hidden ? 0 : 5
20269
- /* gui.ShowWindowCmd.SHOW */
20364
+ /* ShowWindowCmd.SHOW */
20270
20365
  );
20271
20366
  }
20272
20367
  if ("visible" in newProps) {
20273
20368
  gui.ShowWindow(
20274
20369
  hwnd,
20275
20370
  newProps.visible ? 5 : 0
20276
- /* gui.ShowWindowCmd.HIDE */
20371
+ /* ShowWindowCmd.HIDE */
20277
20372
  );
20278
20373
  }
20279
20374
  }
@@ -20369,7 +20464,7 @@ function measureText(hdc, text, maxWidth) {
20369
20464
  -1,
20370
20465
  r2.ptr,
20371
20466
  1024
20372
- /* gui.DrawTextFlag.CALCRECT */
20467
+ /* DrawTextFlag.CALCRECT */
20373
20468
  );
20374
20469
  const { right, bottom } = RECT.decode(r2);
20375
20470
  return { width: right, height: bottom };
@@ -20417,7 +20512,7 @@ function setupWindowProc(instance, hwnd) {
20417
20512
  const oldProc = GetWindowLongPtr(
20418
20513
  hwnd,
20419
20514
  -4
20420
- /* gui.Gwlp.WNDPROC */
20515
+ /* Gwlp.WNDPROC */
20421
20516
  );
20422
20517
  instancesByHwnd.set(hwnd, instance);
20423
20518
  gui3.SetWindowProc(hwnd, (hwnd2, msg, wParam, lParam) => {
@@ -20505,7 +20600,7 @@ function runFlexLayout(inst) {
20505
20600
  r2.width * scaleFactor,
20506
20601
  r2.height * scaleFactor,
20507
20602
  64
20508
- /* gui.SetWindowPosFlag.SWP_SHOWWINDOW */
20603
+ /* SetWindowPosFlag.SWP_SHOWWINDOW */
20509
20604
  );
20510
20605
  InvalidateRect(child.hwnd, NULL, 1);
20511
20606
  child.lastRect = { x: r2.x, y: r2.y, w: r2.width, h: r2.height };
@@ -20661,7 +20756,7 @@ var hostConfig = {
20661
20756
  gui3.ShowWindow(
20662
20757
  instance.hwnd,
20663
20758
  0
20664
- /* gui.ShowWindowCmd.HIDE */
20759
+ /* ShowWindowCmd.HIDE */
20665
20760
  );
20666
20761
  },
20667
20762
  hideTextInstance(instance) {
@@ -20669,7 +20764,7 @@ var hostConfig = {
20669
20764
  gui3.ShowWindow(
20670
20765
  instance.hwnd,
20671
20766
  0
20672
- /* gui.ShowWindowCmd.HIDE */
20767
+ /* ShowWindowCmd.HIDE */
20673
20768
  );
20674
20769
  },
20675
20770
  unhideInstance(instance, _props) {
@@ -20677,7 +20772,7 @@ var hostConfig = {
20677
20772
  gui3.ShowWindow(
20678
20773
  instance.hwnd,
20679
20774
  5
20680
- /* gui.ShowWindowCmd.SHOW */
20775
+ /* ShowWindowCmd.SHOW */
20681
20776
  );
20682
20777
  },
20683
20778
  unhideTextInstance(instance, _text) {
@@ -20685,7 +20780,7 @@ var hostConfig = {
20685
20780
  gui3.ShowWindow(
20686
20781
  instance.hwnd,
20687
20782
  5
20688
- /* gui.ShowWindowCmd.SHOW */
20783
+ /* ShowWindowCmd.SHOW */
20689
20784
  );
20690
20785
  },
20691
20786
  shouldSetTextContent(_type, props) {
@@ -21113,7 +21208,7 @@ function getCellFont(hwnd, style) {
21113
21208
  ...base,
21114
21209
  ...style.bold ? {
21115
21210
  lfWeight: 700
21116
- /* gui.FontWeight.BOLD */
21211
+ /* FontWeight.BOLD */
21117
21212
  } : {},
21118
21213
  ...style.italic ? { lfItalic: 1 } : {},
21119
21214
  ...style.underline ? { lfUnderline: 1 } : {}
@@ -21171,7 +21266,7 @@ function resolveCellStyle(columns, data, row, colIndex) {
21171
21266
  }
21172
21267
  function makeLVItem(i2, sub, text, image) {
21173
21268
  const textBuf = WCHAR.encode(text);
21174
- const b7 = LVITEMW.encode({
21269
+ const b8 = LVITEMW.encode({
21175
21270
  mask: 1 | (image !== void 0 ? 2 : 0),
21176
21271
  iItem: i2,
21177
21272
  iSubItem: sub,
@@ -21188,8 +21283,8 @@ function makeLVItem(i2, sub, text, image) {
21188
21283
  piColFmt: 0,
21189
21284
  iGroup: 0
21190
21285
  });
21191
- b7.__textBuf = textBuf;
21192
- return b7;
21286
+ b8.__textBuf = textBuf;
21287
+ return b8;
21193
21288
  }
21194
21289
  var ListView = (0, import_react9.forwardRef)(function ListViewInner({ columns, data, style, icons, iconSize, getIcon }, ref) {
21195
21290
  const lvRef = (0, import_react9.useRef)(null);
@@ -21235,7 +21330,7 @@ var ListView = (0, import_react9.forwardRef)(function ListViewInner({ columns, d
21235
21330
  4150,
21236
21331
  0,
21237
21332
  32 | 1 | 65536
21238
- /* gui.LvExStyle.DOUBLEBUFFER */
21333
+ /* LvExStyle.DOUBLEBUFFER */
21239
21334
  );
21240
21335
  const n2 = columns.length;
21241
21336
  for (let j2 = 0; j2 < n2; j2++) {
@@ -21280,7 +21375,7 @@ var ListView = (0, import_react9.forwardRef)(function ListViewInner({ columns, d
21280
21375
  4126,
21281
21376
  j2,
21282
21377
  -2
21283
- /* gui.LvColumnWidthCmd.AUTOSIZE_USEHEADER */
21378
+ /* LvColumnWidthCmd.AUTOSIZE_USEHEADER */
21284
21379
  );
21285
21380
  }
21286
21381
  }
@@ -21422,7 +21517,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21422
21517
  natW,
21423
21518
  natH,
21424
21519
  4
21425
- /* gui.SetWindowPosFlag.SWP_NOZORDER */
21520
+ /* SetWindowPosFlag.SWP_NOZORDER */
21426
21521
  );
21427
21522
  forceFlexLayout(content);
21428
21523
  if (natW > svW) {
@@ -21461,7 +21556,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21461
21556
  0,
21462
21557
  0,
21463
21558
  1 | 4
21464
- /* gui.SetWindowPosFlag.SWP_NOZORDER */
21559
+ /* SetWindowPosFlag.SWP_NOZORDER */
21465
21560
  );
21466
21561
  gui12.SetScrollInfo(sv, bar, { pos: newPos }, true);
21467
21562
  }
@@ -21527,7 +21622,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21527
21622
  handleScroll(
21528
21623
  e2,
21529
21624
  1
21530
- /* gui.ScrollBar.VERT */
21625
+ /* ScrollBar.VERT */
21531
21626
  );
21532
21627
  return 0;
21533
21628
  }
@@ -21535,7 +21630,7 @@ var ScrollView = (0, import_react12.forwardRef)(({ children, style, contentWidth
21535
21630
  handleScroll(
21536
21631
  e2,
21537
21632
  0
21538
- /* gui.ScrollBar.HORZ */
21633
+ /* ScrollBar.HORZ */
21539
21634
  );
21540
21635
  return 0;
21541
21636
  }
@@ -21699,7 +21794,7 @@ function deleteAllItems(hTree) {
21699
21794
  4353,
21700
21795
  1,
21701
21796
  -65536
21702
- /* gui.TvInsertAfter.ROOT */
21797
+ /* TvInsertAfter.ROOT */
21703
21798
  );
21704
21799
  }
21705
21800
  var TreeView = (0, import_react16.forwardRef)(function TreeViewInner({ data, onSelect, defaultSelectedKey, selectedKey: controlledKey, style }, ref) {
@@ -21731,7 +21826,7 @@ var TreeView = (0, import_react16.forwardRef)(function TreeViewInner({ data, onS
21731
21826
  4396,
21732
21827
  0,
21733
21828
  4
21734
- /* gui.TvExStyle.DOUBLEBUFFER */
21829
+ /* TvExStyle.DOUBLEBUFFER */
21735
21830
  );
21736
21831
  }, []);
21737
21832
  (0, import_react16.useEffect)(() => {
@@ -21773,9 +21868,16 @@ var b4 = (name, sig) => bind2("comdlg32.dll", name, sig);
21773
21868
  var GetOpenFileName = /* @__PURE__ */ b4("GetOpenFileNameW", "<OPENFILENAMEW>ptr -> u32");
21774
21869
 
21775
21870
  // _build/lib/windows/shell32.js
21776
- var b5 = (name, sig) => bind2("shell32.dll", name, sig);
21871
+ var b5 = (name, sig, encoders) => bind2("shell32.dll", name, sig, encoders);
21777
21872
  var SHBrowseForFolder = /* @__PURE__ */ b5("SHBrowseForFolderW", "<BROWSEINFOW>ptr -> <>ptr");
21778
21873
  var SHGetPathFromIDList = /* @__PURE__ */ b5("SHGetPathFromIDListW", "<>ptr <BYTE>ptr -> u32");
21874
+ var Shell_NotifyIconGetRect = (() => {
21875
+ try {
21876
+ return b5("Shell_NotifyIconGetRect", "<NOTIFYICONIDENTIFIER>ptr <RECT>ptr -> i32", { NOTIFYICONIDENTIFIER });
21877
+ } catch {
21878
+ return null;
21879
+ }
21880
+ })();
21779
21881
 
21780
21882
  // _build/lib/windows/ole32.js
21781
21883
  var b6 = (name, sig) => bind2("ole32.dll", name, sig);
@@ -21928,28 +22030,183 @@ function createRoot(container) {
21928
22030
  };
21929
22031
  }
21930
22032
 
21931
- // _build/examples/execd.js
22033
+ // _build/examples/execd/main.js
21932
22034
  var import_react18 = __toESM(require_react(), 1);
22035
+
22036
+ // _build/lib/windows/kernel32.js
22037
+ var b7 = (name, sig, encoders) => bind2("kernel32.dll", name, sig, encoders);
22038
+ var CloseHandle = /* @__PURE__ */ b7("CloseHandle", "<>ptr -> i32");
22039
+ var OpenProcess = /* @__PURE__ */ b7("OpenProcess", "u32 i32 u32 -> <HPROCESS>ptr");
22040
+ var GetCurrentProcess = /* @__PURE__ */ b7("GetCurrentProcess", " -> <HPROCESS>ptr");
22041
+ var VirtualAllocEx = /* @__PURE__ */ b7("VirtualAllocEx", "<HPROCESS>ptr <>ptr <>ptr u32 u32 -> <>ptr");
22042
+ var VirtualFreeEx = /* @__PURE__ */ b7("VirtualFreeEx", "<HPROCESS>ptr <>ptr <>ptr u32 -> i32");
22043
+ var ReadProcessMemory = /* @__PURE__ */ b7("ReadProcessMemory", "<HPROCESS>ptr <>ptr <BYTE>ptr <>ptr <>ptr -> i32");
22044
+ var MoveFileEx = /* @__PURE__ */ b7("MoveFileExW", "<WCHAR>ptr! <WCHAR>ptr! u32 -> i32");
22045
+ var GetLastError = /* @__PURE__ */ b7("GetLastError", " -> u32");
22046
+ var IsWow64Process = /* @__PURE__ */ b7("IsWow64Process", "<HPROCESS>ptr <BYTE>ptr -> i32");
22047
+
22048
+ // _build/examples/execd/tray.js
22049
+ import * as os6 from "os";
22050
+ import * as gui18 from "gui";
22051
+ var TB_GETBUTTON = 1047;
22052
+ var TB_BUTTONCOUNT = 1048;
22053
+ var TB_GETITEMRECT = 1053;
22054
+ var CLS_BUF = 512;
22055
+ var OS64 = os6.arch === "x64" || (() => {
22056
+ const wow = new PtrArrayBuffer(4);
22057
+ return IsWow64Process(GetCurrentProcess(), wow) !== 0 && new Uint32Array(wow)[0] !== 0;
22058
+ })();
22059
+ var TBBUTTON_DWDATA = OS64 ? 16 : 12;
22060
+ var TBBUTTON_ISTRING = OS64 ? 24 : 16;
22061
+ var TBBUTTON_SZ = OS64 ? 32 : 20;
22062
+ var TRAYDATA_UID = OS64 ? 8 : 4;
22063
+ var REMOTE_BUF = 256;
22064
+ function findToolbars(root) {
22065
+ const out = [];
22066
+ const cls = WCHAR.alloc(CLS_BUF);
22067
+ const walk = (parent) => {
22068
+ let child = FindWindowEx(parent, NULL, NULL, NULL);
22069
+ while (child) {
22070
+ const n2 = GetClassName(child, cls, CLS_BUF);
22071
+ if (n2 > 0 && WCHAR.decode(cls) === "ToolbarWindow32")
22072
+ out.push(child);
22073
+ walk(child);
22074
+ child = FindWindowEx(parent, child, NULL, NULL);
22075
+ }
22076
+ };
22077
+ walk(root);
22078
+ return out;
22079
+ }
22080
+ function readToolbar(tb, area, out) {
22081
+ const count = gui18.SendMessage(tb, TB_BUTTONCOUNT, 0, 0);
22082
+ if (!Number.isInteger(count) || count <= 0 || count > 512)
22083
+ return;
22084
+ const pidBuf = BYTE.alloc(4);
22085
+ if (GetWindowThreadProcessId(tb, pidBuf) === 0)
22086
+ return;
22087
+ const pid = new Uint32Array(pidBuf)[0];
22088
+ const proc = OpenProcess(56, 0, pid);
22089
+ if (!proc)
22090
+ throw new Error("OpenProcess(explorer " + pid + ") failed");
22091
+ const remote = VirtualAllocEx(proc, NULL, REMOTE_BUF, 12288, 4);
22092
+ if (!remote) {
22093
+ CloseHandle(proc);
22094
+ throw new Error("VirtualAllocEx failed");
22095
+ }
22096
+ try {
22097
+ const tbBuf = BYTE.alloc(REMOTE_BUF), trBuf = BYTE.alloc(REMOTE_BUF), tipBuf = BYTE.alloc(REMOTE_BUF);
22098
+ const dvTb = new DataView(tbBuf), dvTr = new DataView(trBuf);
22099
+ for (let i2 = 0; i2 < count; i2++) {
22100
+ if (!gui18.SendMessage(tb, TB_GETBUTTON, i2, remote))
22101
+ continue;
22102
+ if (!ReadProcessMemory(proc, remote, tbBuf, TBBUTTON_SZ, NULL))
22103
+ continue;
22104
+ const dwData = OS64 ? Number(dvTb.getBigUint64(TBBUTTON_DWDATA, true)) : dvTb.getUint32(TBBUTTON_DWDATA, true);
22105
+ if (dwData < 65536)
22106
+ continue;
22107
+ if (!ReadProcessMemory(proc, dwData, trBuf, TRAYDATA_UID + 4, NULL))
22108
+ continue;
22109
+ const hWnd = OS64 ? Number(dvTr.getBigUint64(0, true)) : dvTr.getUint32(0, true);
22110
+ const uID = dvTr.getUint32(TRAYDATA_UID, true);
22111
+ if (!hWnd || !IsWindow(hWnd))
22112
+ continue;
22113
+ let rect = null;
22114
+ if (gui18.SendMessage(tb, TB_GETITEMRECT, i2, remote) && ReadProcessMemory(proc, remote, trBuf, 16, NULL)) {
22115
+ const L2 = dvTr.getInt32(0, true), T2 = dvTr.getInt32(4, true);
22116
+ const R2 = dvTr.getInt32(8, true), B2 = dvTr.getInt32(12, true);
22117
+ if (!(L2 === 0 && T2 === 0 && R2 === 0 && B2 === 0)) {
22118
+ const tl = POINT.encode({ x: L2, y: T2 }), br2 = POINT.encode({ x: R2, y: B2 });
22119
+ if (ClientToScreen(tb, tl.ptr) && ClientToScreen(tb, br2.ptr)) {
22120
+ const a2 = POINT.decode(tl), b8 = POINT.decode(br2);
22121
+ rect = { left: a2.x, top: a2.y, right: b8.x, bottom: b8.y };
22122
+ }
22123
+ }
22124
+ }
22125
+ const iStr = OS64 ? Number(dvTb.getBigUint64(TBBUTTON_ISTRING, true)) : dvTb.getUint32(TBBUTTON_ISTRING, true);
22126
+ let tooltip = null;
22127
+ if (iStr >= 65536 && ReadProcessMemory(proc, iStr, tipBuf, 256, NULL)) {
22128
+ const dvTip = new DataView(tipBuf);
22129
+ let s2 = "";
22130
+ for (let off = 0; off < 256; off += 2) {
22131
+ const c2 = dvTip.getUint16(off, true);
22132
+ if (c2 === 0)
22133
+ break;
22134
+ s2 += String.fromCharCode(c2);
22135
+ }
22136
+ tooltip = s2 === "" ? null : s2;
22137
+ }
22138
+ out.push({ area, index: i2, hWnd, uID, tooltip, rect });
22139
+ }
22140
+ } finally {
22141
+ VirtualFreeEx(proc, remote, 0, 32768);
22142
+ CloseHandle(proc);
22143
+ }
22144
+ }
22145
+ function collectArea(root, area, out) {
22146
+ for (const tb of findToolbars(root))
22147
+ readToolbar(tb, area, out);
22148
+ }
22149
+ function collectVisible(root, out) {
22150
+ let main = null;
22151
+ let mainRight = -Infinity;
22152
+ for (const tb of findToolbars(root)) {
22153
+ const rc2 = RECT.alloc();
22154
+ if (!GetWindowRect(tb, rc2.ptr))
22155
+ continue;
22156
+ const right = RECT.decode(rc2).right;
22157
+ if (right > mainRight) {
22158
+ mainRight = right;
22159
+ main = tb;
22160
+ }
22161
+ }
22162
+ if (main)
22163
+ readToolbar(main, "visible", out);
22164
+ }
22165
+ function listTrayIcons() {
22166
+ const icons = [];
22167
+ const tray = FindWindow("Shell_TrayWnd", NULL);
22168
+ if (tray) {
22169
+ const notifyArea = FindWindowEx(tray, NULL, "TrayNotifyWnd", NULL);
22170
+ collectVisible(notifyArea ? notifyArea : tray, icons);
22171
+ }
22172
+ const overflow = FindWindow("NotifyIconOverflowWindow", NULL);
22173
+ if (overflow)
22174
+ collectArea(overflow, "overflow", icons);
22175
+ return icons;
22176
+ }
22177
+ function probeTrayIcon(hWnd, uID) {
22178
+ if (!Shell_NotifyIconGetRect)
22179
+ return { hr: -1, hrName: "unsupported", rect: null };
22180
+ const rc2 = RECT.alloc();
22181
+ const hr2 = Shell_NotifyIconGetRect({ cbSize: NOTIFYICONIDENTIFIER.size, hWnd, uID }, rc2.ptr);
22182
+ const hrName = hr2 === 0 ? "found" : hr2 === 1 ? "hidden" : hr2 === -2147467259 ? "not_found" : "hr=0x" + (hr2 >>> 0).toString(16);
22183
+ if (hr2 !== 0)
22184
+ return { hr: hr2, hrName, rect: null };
22185
+ const r2 = RECT.decode(rc2);
22186
+ return { hr: hr2, hrName, rect: { left: r2.left, top: r2.top, right: r2.right, bottom: r2.bottom } };
22187
+ }
22188
+
22189
+ // _build/examples/execd/main.js
21933
22190
  function parseArgs() {
21934
- let gui19 = true;
22191
+ let gui20 = true;
21935
22192
  let token = null;
21936
22193
  const args = typeof scriptArgs === "undefined" ? [] : scriptArgs;
21937
22194
  const normToken2 = (v2) => v2 === "" ? null : v2;
21938
22195
  for (let i2 = 0; i2 < args.length; i2++) {
21939
22196
  const a2 = args[i2] ?? "";
21940
22197
  if (a2 === "--nogui") {
21941
- gui19 = false;
22198
+ gui20 = false;
21942
22199
  } else if (a2 === "--gui") {
21943
- gui19 = (args[++i2] ?? "") !== "0";
22200
+ gui20 = (args[++i2] ?? "") !== "0";
21944
22201
  } else if (a2.startsWith("--gui=")) {
21945
- gui19 = a2.slice(6) !== "0";
22202
+ gui20 = a2.slice(6) !== "0";
21946
22203
  } else if (a2 === "--token") {
21947
22204
  token = normToken2(args[++i2] ?? "");
21948
22205
  } else if (a2.startsWith("--token=")) {
21949
22206
  token = normToken2(a2.slice(8));
21950
22207
  }
21951
22208
  }
21952
- return { gui: gui19, token };
22209
+ return { gui: gui20, token };
21953
22210
  }
21954
22211
  var cfg = parseArgs();
21955
22212
  var log = new RequestLog(100);
@@ -21983,7 +22240,7 @@ function formatInfo() {
21983
22240
  function refreshGui() {
21984
22241
  if (!guiUpdater || guiTimer !== null)
21985
22242
  return;
21986
- guiTimer = os6.setTimeout(() => {
22243
+ guiTimer = os7.setTimeout(() => {
21987
22244
  guiTimer = null;
21988
22245
  const u2 = guiUpdater;
21989
22246
  if (u2)
@@ -22013,10 +22270,10 @@ function initGui() {
22013
22270
  height: 420
22014
22271
  });
22015
22272
  root.render((0, import_jsx_runtime16.jsx)(LogPanel, {}));
22016
- gui18.ShowWindow(
22273
+ gui19.ShowWindow(
22017
22274
  root.hwnd,
22018
22275
  9
22019
- /* gui.ShowWindowCmd.RESTORE */
22276
+ /* ShowWindowCmd.RESTORE */
22020
22277
  );
22021
22278
  } catch (ex) {
22022
22279
  console.error("[execd] gui init failed (fallback headless):", ex);
@@ -22045,7 +22302,7 @@ function authCheck(req) {
22045
22302
  }
22046
22303
  function runInWorker(cmd, signal, timeoutMs) {
22047
22304
  const spawnCmd = cmd;
22048
- const worker = new os6.Worker("data:text/javascript;base64,aW1wb3J0KmFzIE90IGZyb20ib3MiO2ltcG9ydCphcyBMdCBmcm9tInN0ZCI7aW1wb3J0KmFzIGIgZnJvbSJmZmkiO2ltcG9ydCphcyBkdCBmcm9tIm9zIjtpbXBvcnQqYXMgbXQgZnJvbSJzdGQiO2ltcG9ydCphcyAkIGZyb20id2luIjt2YXIgUHQ9eyJ1dGYtOCI6InV0Zi04Iix1dGY4OiJ1dGYtOCIsInVuaWNvZGUtMS0xLXV0Zi04IjoidXRmLTgiLCJ1dGYtMTYiOiJ1dGYtMTZsZSIsInV0Zi0xNmxlIjoidXRmLTE2bGUiLCJ1dGYtMTZiZSI6InV0Zi0xNmJlIn07ZnVuY3Rpb24gc3QodCl7aWYoIXQpcmV0dXJuInV0Zi04IjtsZXQgZT1QdFt0LnRyaW0oKS50b0xvd2VyQ2FzZSgpXTtpZihlKXJldHVybiBlO3Rocm93IG5ldyBSYW5nZUVycm9yKGBUaGUgZW5jb2RpbmcgbGFiZWwgIiR7dH0iIGlzIG5vdCBzdXBwb3J0ZWRgKX1mdW5jdGlvbiBNdCh0LGUpe2xldCByPSIiO2ZvcihsZXQgbj0wO248dC5sZW5ndGg7KXtsZXQgbz10W24rK107aWYobzwxMjgpe3IrPVN0cmluZy5mcm9tQ2hhckNvZGUobyk7Y29udGludWV9aWYobzwxOTIpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigidW5leHBlY3RlZCBjb250aW51YXRpb24gYnl0ZSIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1sZXQgaSxjO2lmKG88MjI0KXtpZihuPj10Lmxlbmd0aCl7cis9ZT8oKCk9Pnt0aHJvdyBuZXcgVHlwZUVycm9yKCJpbmNvbXBsZXRlIHV0Zi04Iil9KSgpOiJcdUZGRkQiO2JyZWFrfWxldCBzPXRbbisrXTtpZigocyYxOTIpIT09MTI4KXtyKz0iXHVGRkZEIjtjb250aW51ZX1pPShvJjMxKTw8NnxzJjYzLGM9MTI4fWVsc2UgaWYobzwyNDApe2lmKG4rMT49dC5sZW5ndGgpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW5jb21wbGV0ZSB1dGYtOCIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz10W24rK10sdT10W24rK107aWYoKHMmMTkyKSE9PTEyOHx8KHUmMTkyKSE9PTEyOCl7cis9Ilx1RkZGRCI7Y29udGludWV9aT0obyYxNSk8PDEyfChzJjYzKTw8Nnx1JjYzLGM9MjA0OH1lbHNlIGlmKG88MjQ4KXtpZihuKzI+PXQubGVuZ3RoKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImluY29tcGxldGUgdXRmLTgiKX0pKCk6Ilx1RkZGRCI7YnJlYWt9bGV0IHM9dFtuKytdLHU9dFtuKytdLHA9dFtuKytdO2lmKChzJjE5MikhPT0xMjh8fCh1JjE5MikhPT0xMjh8fChwJjE5MikhPT0xMjgpe3IrPSJcdUZGRkQiO2NvbnRpbnVlfWk9KG8mNyk8PDE4fChzJjYzKTw8MTJ8KHUmNjMpPDw2fHAmNjMsYz02NTUzNn1lbHNle3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCB1dGYtOCBzdGFydCIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1pZihpPGN8fGk+PTU1Mjk2JiZpPD01NzM0M3x8aT4xMTE0MTExKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImludmFsaWQgdXRmLTggY29kZXBvaW50Iil9KSgpOiJcdUZGRkQiO2NvbnRpbnVlfWk8PTY1NTM1P3IrPVN0cmluZy5mcm9tQ2hhckNvZGUoaSk6KGktPTY1NTM2LHIrPVN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTZ8aT4+MTAsNTYzMjB8aSYxMDIzKSl9cmV0dXJuIHJ9ZnVuY3Rpb24gV3QodCxlLHIpe2xldCBuPW5ldyBEYXRhVmlldyh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQsdC5ieXRlTGVuZ3RoKSxvPSIiO2ZvcihsZXQgaT0wO2krMTx0Lmxlbmd0aDtpKz0yKXtsZXQgYz1uLmdldFVpbnQxNihpLGUpO2lmKGM+PTU1Mjk2JiZjPD01NjMxOSl7aWYoaSs9MixpKzE+PXQubGVuZ3RoKXtvKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInRydW5jYXRlZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz1uLmdldFVpbnQxNihpLGUpO3M+PTU2MzIwJiZzPD01NzM0Mz9vKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMscyk6KG8rPXI/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIixpLT0yKX1lbHNlIGM+PTU2MzIwJiZjPD01NzM0Mz9vKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInVuZXhwZWN0ZWQgdHJhaWxpbmcgc3Vycm9nYXRlIil9KSgpOiJcdUZGRkQiOm8rPVN0cmluZy5mcm9tQ2hhckNvZGUoYyl9cmV0dXJuIG99dmFyIFk9Y2xhc3N7X2VuY29kaW5nO19mYXRhbDtfaWdub3JlQk9NO2NvbnN0cnVjdG9yKGUscil7dGhpcy5fZW5jb2Rpbmc9c3QoZSksdGhpcy5fZmF0YWw9cj8uZmF0YWw/PyExLHRoaXMuX2lnbm9yZUJPTT1yPy5pZ25vcmVCT00/PyExfWdldCBlbmNvZGluZygpe3JldHVybiB0aGlzLl9lbmNvZGluZ31nZXQgZmF0YWwoKXtyZXR1cm4gdGhpcy5fZmF0YWx9Z2V0IGlnbm9yZUJPTSgpe3JldHVybiB0aGlzLl9pZ25vcmVCT019ZGVjb2RlKGUpe2lmKCFlKXJldHVybiIiO2xldCByPWUgaW5zdGFuY2VvZiBVaW50OEFycmF5P2U6ZSBpbnN0YW5jZW9mIEFycmF5QnVmZmVyP25ldyBVaW50OEFycmF5KGUpOm5ldyBVaW50OEFycmF5KGUuYnVmZmVyLGUuYnl0ZU9mZnNldCxlLmJ5dGVMZW5ndGgpO2lmKHRoaXMuX2VuY29kaW5nPT09InV0Zi04IilyZXR1cm4gTXQocix0aGlzLl9mYXRhbCk7bGV0IG49dGhpcy5fZW5jb2Rpbmc9PT0idXRmLTE2bGUiLG89MDtpZihyLmxlbmd0aD49MiYmIXRoaXMuX2lnbm9yZUJPTSl7bGV0IGk9bj9yWzBdOnJbMV0scz0obj9yWzFdOnJbMF0pPDw4fGk7KHM9PT02NTI3OXx8cz09PTY1NTM0KSYmKG89Mil9cmV0dXJuIFd0KHIuc2xpY2Uobyksbix0aGlzLl9mYXRhbCl9fSx2PWNsYXNze19lbmNvZGluZztjb25zdHJ1Y3RvcihlKXt0aGlzLl9lbmNvZGluZz1zdChlKX1nZXQgZW5jb2RpbmcoKXtyZXR1cm4gdGhpcy5fZW5jb2Rpbmd9ZW5jb2RlKGUpe2lmKCFlKXJldHVybiBuZXcgVWludDhBcnJheSgwKTtpZih0aGlzLl9lbmNvZGluZz09PSJ1dGYtOCIpe2xldCBpPVtdO2ZvcihsZXQgYz0wO2M8ZS5sZW5ndGg7YysrKXtsZXQgcz1lLmNoYXJDb2RlQXQoYyk7aWYoczwxMjgpaS5wdXNoKHMpO2Vsc2UgaWYoczwyMDQ4KWkucHVzaCgxOTJ8cz4+NiwxMjh8cyY2Myk7ZWxzZSBpZihzPDU1Mjk2fHxzPj01NzM0NClpLnB1c2goMjI0fHM+PjEyLDEyOHxzPj42JjYzLDEyOHxzJjYzKTtlbHNle2MrKztsZXQgdT1lLmNoYXJDb2RlQXQoYyk7cz02NTUzNisoKHMmMTAyMyk8PDEwKXx1JjEwMjMsaS5wdXNoKDI0MHxzPj4xOCwxMjh8cz4+MTImNjMsMTI4fHM+PjYmNjMsMTI4fHMmNjMpfX1yZXR1cm4gbmV3IFVpbnQ4QXJyYXkoaSl9bGV0IHI9dGhpcy5fZW5jb2Rpbmc9PT0idXRmLTE2bGUiLG49bmV3IEFycmF5QnVmZmVyKGUubGVuZ3RoKjIpLG89bmV3IERhdGFWaWV3KG4pO2ZvcihsZXQgaT0wO2k8ZS5sZW5ndGg7aSsrKW8uc2V0VWludDE2KGkqMixlLmNoYXJDb2RlQXQoaSkscik7cmV0dXJuIG5ldyBVaW50OEFycmF5KG4pfX07dHlwZW9mIGdsb2JhbFRoaXMuVGV4dERlY29kZXI+InUiJiYoZ2xvYmFsVGhpcy5UZXh0RGVjb2Rlcj1ZKTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RW5jb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHRFbmNvZGVyPXYpO2ltcG9ydHtidWZmZXJQdHIgYXMgUnR9ZnJvbSJmZmkiO2ltcG9ydCphcyBjdCBmcm9tIm9zIjt2YXIga3Q9WyJ2b2lkIiwidTgiLCJpOCIsInUxNiIsImkxNiIsInUzMiIsImkzMiIsInU2NCIsImk2NCIsImYzMiIsImY2NCIsInB0ciJdLGo9L148KFtBLVphLXpfXVx3KnwpPnB0cighfEBbQS1aYS16X11cdyopPyQvO2Z1bmN0aW9uIHkodCl7cmV0dXJuIGoudGVzdCh0KX12YXIgdXQ9L148KFtBLVphLXpfXVx3Kik+JC87ZnVuY3Rpb24gTih0KXtyZXR1cm4gdXQudGVzdCh0KX1mdW5jdGlvbiBXKHQpe3JldHVybiB1dC5leGVjKHQpPy5bMV18fCIifWZ1bmN0aW9uIFgodCl7cmV0dXJuIGouZXhlYyh0KT8uWzFdfHwiIn12YXIgYXQ9dD0+e2lmKHkodCkpcmV0dXJuInB0ciI7aWYoTih0KSl0aHJvdyBuZXcgRXJyb3IoYGZmaTogY1Rva2VuVG9UeXBlOiBieS12YWx1ZSB0b2tlbiAiJHt0fSIgaGFzIG5vIHNjYWxhciBzbG90IHR5cGVgKTtyZXR1cm4gdH0sRD1jdC5hcmNoPT09Ing2NCI/ODo0LFI9e3U4OjEsaTg6MSx1MTY6MixpMTY6Mix1MzI6NCxpMzI6NCx1NjQ6OCxpNjQ6OCxmMzI6NCxmNjQ6OH0sTz0wO2Z1bmN0aW9uIGsodCl7aWYoeSh0KSl7bGV0IG89ai5leGVjKHQpLGk9bz8uWzFdfHwiIjtyZXR1cm4gbz8uWzJdPy5zdGFydHNXaXRoKCJAIik/YDwke2l9PnB0cmA6dH1pZihOKHQpKXJldHVybiB0O2xldCBlPXQuaW5kZXhPZigiQCIpLHI9ZT49MD90LnNsaWNlKDAsZSk6dDtpZigoZTwwfHwvXltBLVphLXpfXVx3KiQvLnRlc3QodC5zbGljZShlKzEpKSkmJnIhPT0icHRyIiYma3QuaW5jbHVkZXMocikpcmV0dXJuIHI7dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIHRva2VuOiAiK3QpfWZ1bmN0aW9uIHoodCxlLHIpe3N3aXRjaChyKXtjYXNlInU4IjpyZXR1cm4gdC5nZXRVaW50OChlKTtjYXNlImk4IjpyZXR1cm4gdC5nZXRJbnQ4KGUpO2Nhc2UidTE2IjpyZXR1cm4gdC5nZXRVaW50MTYoZSwhMCk7Y2FzZSJpMTYiOnJldHVybiB0LmdldEludDE2KGUsITApO2Nhc2UidTMyIjpyZXR1cm4gdC5nZXRVaW50MzIoZSwhMCk7Y2FzZSJpMzIiOnJldHVybiB0LmdldEludDMyKGUsITApO2Nhc2UidTY0IjpyZXR1cm4gdC5nZXRCaWdVaW50NjQoZSwhMCk7Y2FzZSJpNjQiOnJldHVybiB0LmdldEJpZ0ludDY0KGUsITApO2Nhc2UiZjMyIjpyZXR1cm4gdC5nZXRGbG9hdDMyKGUsITApO2Nhc2UiZjY0IjpyZXR1cm4gdC5nZXRGbG9hdDY0KGUsITApO2Nhc2UicHRyIjpyZXR1cm4gRD09PTg/TnVtYmVyKHQuZ2V0QmlnSW50NjQoZSwhMCkpOnQuZ2V0SW50MzIoZSwhMCl9fWZ1bmN0aW9uIFoodCxlLHtrOnIsdjpufSl7c3dpdGNoKHIpe2Nhc2UidTgiOnQuc2V0VWludDgoZSxOdW1iZXIobikpO2JyZWFrO2Nhc2UiaTgiOnQuc2V0SW50OChlLE51bWJlcihuKSk7YnJlYWs7Y2FzZSJ1MTYiOnQuc2V0VWludDE2KGUsTnVtYmVyKG4pLCEwKTticmVhaztjYXNlImkxNiI6dC5zZXRJbnQxNihlLE51bWJlcihuKSwhMCk7YnJlYWs7Y2FzZSJ1MzIiOnQuc2V0VWludDMyKGUsbj4+PjAsITApO2JyZWFrO2Nhc2UiaTMyIjp0LnNldFVpbnQzMihlLG4+Pj4wLCEwKTticmVhaztjYXNlInU2NCI6dC5zZXRCaWdVaW50NjQoZSxuLCEwKTticmVhaztjYXNlImk2NCI6dC5zZXRCaWdJbnQ2NChlLG4sITApO2JyZWFrO2Nhc2UiZjMyIjp0LnNldEZsb2F0MzIoZSxuLCEwKTticmVhaztjYXNlImY2NCI6dC5zZXRGbG9hdDY0KGUsbiwhMCk7YnJlYWs7Y2FzZSJwdHIiOntpZihuPT1udWxsKXRocm93IG5ldyBFcnJvcigiZmZpOiBnb3QgbnVsbC91bmRlZmluZWQgZm9yIGEgcHRyIHNsb3Q7IHBhc3MgdGhlIGltcG9ydGVkIE5VTEwgY29uc3RhbnQgZm9yIGVtcHR5Iik7RD09PTg/dC5zZXRCaWdVaW50NjQoZSxCaWdJbnQuYXNVaW50Tig2NCxCaWdJbnQobikpLCEwKTp0LnNldFVpbnQzMihlLG4+Pj4wLCEwKTticmVha319fWZ1bmN0aW9uIF8odCxlLHIpe2xldHtrOm4sdjpvfT1yO2lmKG49PT0idTgifHxuPT09Imk4Inx8bj09PSJ1MTYifHxuPT09ImkxNiIpe3Quc2V0VWludDMyKGUsTnVtYmVyKG8pPj4+MCwhMCk7cmV0dXJufVoodCxlLHIpfXZhciBoPWNsYXNzIGV4dGVuZHMgQXJyYXlCdWZmZXJ7cHRyO2NvbnN0cnVjdG9yKGUpe3N1cGVyKGUpLHRoaXMucHRyPVJ0KHRoaXMpfX07ZnVuY3Rpb24gcSh0LGUpe3JldHVybiBlW3RdfXZhciBwdD1uZXcgTWFwO2Z1bmN0aW9uIF90KHQpe2xldCBlPXB0LmdldCh0KTtpZihlIT09dm9pZCAwKXJldHVybiBlO2xldCByPSQuTG9hZExpYnJhcnkodCk7aWYoIXIpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogTG9hZExpYnJhcnkoIiR7dH0iKSBmYWlsZWRgKTtyZXR1cm4gcHQuc2V0KHQscikscn1mdW5jdGlvbiBCdCh0KXtsZXQgZT10LnNwbGl0KCIgLT4gIik7aWYoZS5sZW5ndGghPT0yKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IGludmFsaWQgc2lnbmF0dXJlICIke3R9IiAoZXhwZWN0ZWQgImFyZzEgYXJnMiAtPiByZXQiKWApO2xldCByPWVbMF0uc3BsaXQoIiAiKS5maWx0ZXIoaT0+aSE9PSIiKSxuPVtdO2ZvcihsZXQgaSBvZiByKXtsZXQgYz1rKGkpO2lmKGM9PT0idm9pZCIpdGhyb3cgbmV3IEVycm9yKCJWb2lkIGNhbiBub3QgaW4gYXJncyIpO24ucHVzaChjKX1sZXQgbz1rKGVbMV0pO2lmKE4obykpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogIiR7dH0iOiBieS12YWx1ZSBzdHJ1Y3QgYXQgdGhlIHJldHVybiBwb3NpdGlvbiAoPCR7VyhvKX0+KSBpcyBub3Qgc3VwcG9ydGVkIFx1MjAxNCBhcmd1bWVudCBwb3NpdGlvbnMgb25seTsgcGFzcyBhIHN0cnVjdCBvdXQgdGhyb3VnaCBhbiBvdXQtcGFyYW0gc2xvdCBpbnN0ZWFkICg8Tj5wdHIgKyBjYWxsZXIgYnVmZmVyKWApO3JldHVybnthcmdUb2tlbnM6bixyZXRUb2tlbjpvLHNpZzp0fX1mdW5jdGlvbiBVdCh0LGUscixuKXtsZXQgbz1CdChlKTtmb3IobGV0IGkgb2Ygby5hcmdUb2tlbnMpe2lmKCFOKGkpKWNvbnRpbnVlO2xldCBjPVcoaSkscz1xKGMscik7aWYoIXN8fHR5cGVvZiBzLmVuY29kZSE9ImZ1bmN0aW9uIil0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke2V9OiBieS12YWx1ZSBwb3NpdGlvbiA8JHtjfT4gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0IChhdmFpbGFibGU6ICR7T2JqZWN0LmtleXMocikuam9pbigiLCAiKXx8Im5vbmUifSlgKTtpZih0eXBlb2Ygcy5zaXplIT0ibnVtYmVyInx8cy5zaXplPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtlfTogYnktdmFsdWUgcG9zaXRpb24gPCR7Y30+IHJlcXVpcmVzIGEgc3RydWN0IGxheW91dCB3aXRoIHNpemUgPj0gMSAoZ290ICR7cy5zaXplfTsgbm9uLXN0cnVjdCBjb2RlY3MgZXhwb3NlIG5vIHNpemUpYCl9cmV0dXJuKC4uLmkpPT56dCh0LG8saSxyLG4pfXZhciBIdD17dTg6NCxpODo0LHUxNjo0LGkxNjo0LHUzMjo0LGkzMjo0LHU2NDo4LGk2NDo4LGYzMjo0LGY2NDo4LHB0cjpEfSxmdD00O2Z1bmN0aW9uIHp0KHQse2FyZ1Rva2VuczplLHJldFRva2VuOnIsc2lnOm59LG8saSxjKXtsZXQgcz1kdC5hcmNoPT09Ing2NCIsdT0oYSxkKT0+e2lmKE4oYSkpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogZ2V0V2lkdGg6IGJ5LXZhbHVlIHRva2VuICIke2F9IiAoZGlzcGF0Y2hlZCBieSB3aWR0aE9mKWApO3JldHVybiBkPzg6eShhKT9EOkh0W2FdfSxwPWE9PntpZihOKGEpKXtpZihzKXJldHVybiA4O2xldCBkPXEoVyhhKSxpKTtpZighZCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtXKGEpfT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7bGV0IG09ZC5zaXplO3JldHVybiBtJTQ9PT0wP206bSs0LW0lNH1yZXR1cm4gdShhLHMpfSx4PTA7Zm9yKGxldCBhIG9mIGUpeCs9cChhKTtzJiZlLmxlbmd0aDxmdCYmKHg9ZnQqOCk7bGV0IEY9bmV3IEFycmF5QnVmZmVyKHgpLGc9bmV3IERhdGFWaWV3KEYpLFQ9W10sRT0wO2ZvcihsZXQgYT0wO2E8ZS5sZW5ndGg7YSsrKXtsZXQgZD1lW2FdLG09ZC5lbmRzV2l0aCgiISIpLGY9b1thXTtpZih5KGQpKXtsZXQgbD1YKGQpO2lmKHR5cGVvZiBmPT0ibnVtYmVyIil7aWYobSYmZj09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtufTogYXJnIyR7YSsxfSA8JHtsfT5wdHIhIGdvdCAwIChudWxsIHBvaW50ZXIgZm9yYmlkZGVuIGhlcmU7IHRoZSB0b2tlbiBtYXJrcyB0aGlzIHBvc2l0aW9uIG5vbi1udWxsKWApO18oZyxFLHtrOiJwdHIiLHY6Zn0pfWVsc2V7aWYoZj09bnVsbCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtsfT5wdHIgZ290ICR7U3RyaW5nKGYpfTsgcGFzcyB0aGUgaW1wb3J0ZWQgTlVMTCBjb25zdGFudCBmb3IgYW4gZW1wdHkgcG9pbnRlcmApO2xldCBDPWlbbF07aWYoIUMpdGhyb3cgbmV3IEVycm9yKGw9PT0iIj9gZmZpLWJpbmQ6IDw+cHRyIGV4cGVjdHMgbnVtYmVyIChOVUxMIHwgUHRyKSwgZ290ICR7dHlwZW9mIGZ9OyB1c2UgPEJZVEU+cHRyIHdpdGggYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pKSwgb3IgZmZpLmJ1ZmZlclB0cihidWYpIGZvciBhbiBhZGRyZXNzYDpgZmZpLWJpbmQ6IHVua25vd24gbGF5b3V0ICI8JHtsfT5wdHIiIChhdmFpbGFibGU6ICR7T2JqZWN0LmtleXMoaSkuam9pbigiLCAiKXx8Im5vbmUifSlgKTtpZighQy5lbmNvZGUpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7bH0+cHRyIGhhcyBubyBlbmNvZGVyIChvdXQtb25seSBjb2RlYylgKTtsZXQgQT1DLmVuY29kZShmKTtULnB1c2goQSk7bGV0IFA9QS5wdHI7aWYodHlwZW9mIFAhPSJudW1iZXIiKXRocm93IG5ldyBFcnJvcigiZmZpLWJpbmQ6IGNvZGVjLmVuY29kZSBtdXN0IHJldHVybiBhIFB0ckFycmF5QnVmZmVyLCBnb3QgcGxhaW4gQXJyYXlCdWZmZXIiKTtpZihtJiZQPT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke259OiBhcmcjJHthKzF9IDwke2x9PnB0ciEgZW5jb2RlIHByb2R1Y2VkIDAgKG51bGwgcG9pbnRlciBmb3JiaWRkZW4gaGVyZSlgKTtfKGcsRSx7azoicHRyIix2OlB9KX19ZWxzZSBpZihOKGQpKXtsZXQgbD1XKGQpLEM9cShsLGkpO2lmKCFDKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7bn06IGFyZyMke2ErMX0gPCR7bH0+IGJ5LXZhbHVlIHBvc2l0aW9uIGhhcyBubyByZWdpc3RlcmVkIGxheW91dGApO2lmKGY9PW51bGwpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7bH0+IHZhbHVlIHBvc2l0aW9uIGdvdCAke1N0cmluZyhmKX07IHBhc3MgYSBzdHJ1Y3Qgb2JqZWN0ICh1c2UgPCR7bH0+cHRyIHRvIHBhc3MgYSBwb2ludGVyKWApO2xldCBBPUMuc2l6ZTtpZighc3x8QTw9OCYmKEEmQS0xKT09PTApQy5lbmNvZGUoZixGLEUpO2Vsc2V7bGV0IFA9bmV3IEFycmF5QnVmZmVyKEErMTUpLG90PWIuYnVmZmVyUHRyKFApLGl0PSgxNi1vdCUxNiklMTY7Qy5lbmNvZGUoZixQLGl0KSxULnB1c2goUCksXyhnLEUse2s6InB0ciIsdjpvdCtpdH0pfX1lbHNlIF8oZyxFLHtrOmQsdjpmfSk7RSs9cChkKX1sZXQgTD1uZXcgQXJyYXlCdWZmZXIoOCk7Yi5mZmlDYWxsKHQsRixMLHI9PT0iZjMyInx8cj09PSJmNjQiPzE6MCk7bGV0IFM9JHQoYXQociksTCk7aWYoci5lbmRzV2l0aCgiISIpJiZTPT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke259OiByZXR1cm4gJHtyfSBnb3QgMCAodGhlIHRva2VuIHByb21pc2VzIEMgbmV2ZXIgcmV0dXJucyBudWxsIGhlcmUpYCk7aWYoeShyKSYmUyE9PTApe2xldCBhPVgocik7aWYoYSE9PSIiKXtsZXQgZD1jW2FdO2lmKGQ/LmRlY29kZSlyZXR1cm4gZC5kZWNvZGUoUyl9fXJldHVybiBTfWZ1bmN0aW9uICR0KHQsZSl7aWYodCE9PSJ2b2lkIilyZXR1cm4geihuZXcgRGF0YVZpZXcoZSksMCx0KX12YXIgRz17ZW5jb2RlOnQ9PntsZXQgZT1uZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIikuZW5jb2RlKHQrIlwwIikscj1uZXcgaChlLmJ5dGVMZW5ndGgpO3JldHVybiBuZXcgVWludDhBcnJheShyKS5zZXQoZSkscn0sZGVjb2RlOnQ9PntpZih0eXBlb2YgdD09Im51bWJlciIpe2xldCBvPSIiLGk9dCxjPWk7Zm9yKDs7KXtsZXQgcz1iLnJlYWRCeXRlKGkpLHU9Yi5yZWFkQnl0ZShpKzEpO2lmKHM9PT0wJiZ1PT09MClyZXR1cm4gbztpZihvKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHN8dTw8OCksaSs9MixpLWM+MTw8MjEpdGhyb3cgbmV3IEVycm9yKCJmZmktYmluZDogV0NIQVIgZGVjb2RlIGV4Y2VlZGVkIDRNaUIgd2l0aG91dCBOVUwiKX19bGV0IGU9bmV3IFVpbnQ4QXJyYXkodCkscj1lLmxlbmd0aCYtMixuPSIiO2ZvcihsZXQgbz0wO288cjtvKz0yKXtsZXQgaT1lW29dfGVbbysxXTw8ODtpZihpPT09MClyZXR1cm4gbjtuKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGkpfXJldHVybiBufSxhbGxvYzoodD0yNTYpPT5uZXcgaCh0KjIpfSxHdD17ZW5jb2RlOnQ9PntpZighKHQgaW5zdGFuY2VvZiBoKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiA8QllURT5wdHIgd2FudHMgYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pIC8gQllURS5hbGxvYyAvIHN0cnVjdC5lbmNvZGUpLCBub3QgYSBwbGFpbiBBcnJheUJ1ZmZlciIpO3JldHVybiB0fSxhbGxvYzp0PT5uZXcgaCh0KX0sbHQ9e1dDSEFSOkcsQllURTpHdH07ZnVuY3Rpb24gRXQodCxlLHIsbixvKXtsZXQgaT0kLkdldFByb2NBZGRyZXNzKF90KHQpLGUpO2lmKCFpKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IHByb2MgIiR7ZX0iIG5vdCBmb3VuZCBpbiAke3R9YCk7bGV0IGM9bz8/bjtyZXR1cm4gVXQoaSxyLHsuLi5sdCwuLi5ufSx7Li4ubHQsLi4uYz8/e319KX12YXIgZmU9bmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KHQ9PnttdC5wcmludGYoYFtmZmldIGNsb3N1cmUgbGVha2VkIChHQ2VkIHdpdGhvdXQgZGlzcG9zZSk6IHNpZz0iJXMiIHB0cj0weCV4CmAsdC5zaWcsdC5wdHIpfSk7aW1wb3J0KmFzIHh0IGZyb20iZmZpIjtmdW5jdGlvbiBCKHQsZSl7cmV0dXJuIHQrZS0xJn4oZS0xKX12YXIgaHQ9dD0+Ult0XSE9PXZvaWQgMDtmdW5jdGlvbiBRKHQpe2lmKHR5cGVvZiB0PT0ic3RyaW5nIil7bGV0IGU9L14odTh8dTE2KVxbKFxkKylcXUAodXRmLTh8dXRmLTE2bGUpJC8uZXhlYyh0KTtpZihlKXtsZXQgYz1OdW1iZXIoZVsyXSk7aWYoIU51bWJlci5pc0ludGVnZXIoYyl8fGM8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cmluZyBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke2N9YCk7bGV0IHM9ZVsxXT09PSJ1OCI/MToyO3JldHVybntzaXplOnMqYyxhbGlnbjpzLHR5cGU6e3RhZzoic3RyaW5nIixlbmNvZGluZzplWzNdfX19bGV0IHI9L14oW15cW1xdXSspXFsoXGQrKVxdJC8uZXhlYyh0KTtpZihyKXtsZXQgYz1OdW1iZXIoclsyXSk7aWYoIU51bWJlci5pc0ludGVnZXIoYyl8fGM8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGFycmF5IGxlbmd0aCBtdXN0IGJlIGFuIGludGVnZXIgPj0gMSwgZ290ICR7Y31gKTtsZXQgcz1RKHJbMV0pO2lmKHMudHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOnMuc2l6ZSpjLGFsaWduOnMuYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6cy50eXBlLGVsZW1lbnRTaXplOnMuc2l6ZX19fWxldCBuPS9eKFtBLVphLXpfXVx3Kik6KFxkKykkLy5leGVjKHQpO2lmKG4pe2xldCBjPW5bMV0scz1rKGMpO2lmKCFodChzKXx8cz09PSJmMzIifHxzPT09ImY2NCIpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB1bml0IG11c3QgYmUgYW4gaW50ZWdlciB0eXBlLCBnb3QgIiR7Y30iYCk7bGV0IHU9TnVtYmVyKG5bMl0pLHA9UltzXSx4PXAqODtpZighTnVtYmVyLmlzSW50ZWdlcih1KXx8dTwxKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogYml0ZmllbGQgd2lkdGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke3V9YCk7aWYodT54KXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogYml0ZmllbGQgd2lkdGggJHt1fSBleGNlZWRzIHVuaXQgd2lkdGggJHt4fWApO3JldHVybntzaXplOnAsYWxpZ246cCx0eXBlOnt0YWc6ImJpdGZpZWxkIix1bml0OnMsYml0OjAsd2lkdGg6dX19fWxldCBvPWsodCk7aWYoeShvKSlyZXR1cm57c2l6ZTpELGFsaWduOkQsdHlwZTp7dGFnOiJiYXNpYyIsa2luZDoicHRyIn19O2lmKCFodChvKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHVua25vd24ga2luZCAiJHt0fSJgKTtsZXQgaT1SW29dO3JldHVybntzaXplOmksYWxpZ246aSx0eXBlOnt0YWc6ImJhc2ljIixraW5kOm99fX1pZih0JiZ0eXBlb2YgdD09Im9iamVjdCIpe2xldCBlPXQscj1lWyIjIl07aWYocj09PXZvaWQgMCl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IG5lc3RlZCBvYmplY3QgdmFsdWUgcmVxdWlyZXMgYSAnIycga2V5ICgnc3RydWN0JyB8ICd1bmlvbicgfCAnYXJyYXknKSIpO2lmKHI9PT0iYXJyYXkiJiYiI3BhY2siaW4gZSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6ICcjcGFjaycgaXMgb25seSBhbGxvd2VkIG9uIHN0cnVjdC91bmlvbiwgZ290ICcke3J9J2ApO2lmKHI9PT0iYXJyYXkiKXtsZXQgbj1lLmxlbmd0aDtpZighTnVtYmVyLmlzSW50ZWdlcihuKXx8bjwxKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogYXJyYXkgbGVuZ3RoIG11c3QgYmUgYW4gaW50ZWdlciA+PSAxLCBnb3QgJHtTdHJpbmcobil9YCk7bGV0IG89UShlLmVsZW1lbnQpO2lmKG8udHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOm8uc2l6ZSpuLGFsaWduOm8uYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6by50eXBlLGVsZW1lbnRTaXplOm8uc2l6ZX19fWlmKHI9PT0ic3RydWN0Inx8cj09PSJ1bmlvbiIpe2xldCBuPXd0KHQpO3JldHVybntzaXplOm4uc2l6ZSxhbGlnbjpuLm1heEVmZmVjdGl2ZUFsaWduLHR5cGU6e3RhZzpyLGZpZWxkczpuLmZpZWxkc319fXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biAnIycgZGVjbGFyYXRpb24gJHtKU09OLnN0cmluZ2lmeShTdHJpbmcocikpfWApfXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogaW52YWxpZCBtZW1iZXIgdmFsdWU6ICR7U3RyaW5nKHQpfWApfWZ1bmN0aW9uIHd0KHQpe2xldCBlPXRbIiMiXT09PSJzdHJ1Y3QiLHI9dFsiI3BhY2siXT8/OCxuPTEsbz0wLGk9W10sYz0wLHM9LTEsdT0wLHA9MCx4PSgpPT57czwwfHwoYz1CKHMrTWF0aC5jZWlsKHUvOCkscCkscz0tMSl9O2ZvcihsZXRbRixnXW9mIE9iamVjdC5lbnRyaWVzKHQpKXtpZihGLnN0YXJ0c1dpdGgoIiMiKSljb250aW51ZTtsZXQgVD0vXihbXkBdKylAKFxkKykkLy5leGVjKEYpLEU9VD9UWzFdOkYsTD1UP051bWJlcihUWzJdKTowLHtzaXplOncsYWxpZ246Uyx0eXBlOmF9PVEoZyksZD10eXBlb2YgZz09InN0cmluZyImJmcuZW5kc1dpdGgoIiEiKSxtPVM7aWYocj4wJiYobT1NYXRoLm1pbihyLG0pKSxMJiYobT1NYXRoLm1heChtLEwpKSxhLnRhZz09PSJiaXRmaWVsZCIpe2lmKEUuc3RhcnRzV2l0aCgiJCIpKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGQgbWVtYmVycyBtdXN0IGJlIG5hbWVkIik7aWYoIWUpe2kucHVzaCh7bmFtZTpFLG9mZnNldDowLHNpemU6dyx0eXBlOnsuLi5hLGJpdDowfX0pLG49TWF0aC5tYXgobixtKSxvPU1hdGgubWF4KG8sdyk7Y29udGludWV9bGV0IGw9YS53aWR0aDsoczwwfHx3IT09cHx8dStsPnAqOCkmJihzPj0wJiZ4KCkscz1CKGMsbSksdT0wLHA9dyksaS5wdXNoKHtuYW1lOkUsb2Zmc2V0OnMsc2l6ZTp3LHR5cGU6ey4uLmEsYml0OnV9fSksdSs9bCxuPU1hdGgubWF4KG4sbSksbz1NYXRoLm1heChvLHcpO2NvbnRpbnVlfXgoKTtsZXQgZj1CKGMsbSk7aWYoIUUuc3RhcnRzV2l0aCgiJCIpKWkucHVzaCh7bmFtZTpFLG9mZnNldDpmLHNpemU6dyx0eXBlOmEsLi4uZD97bm9ubnVsbDohMH06e319KTtlbHNle2lmKGEudGFnIT09InN0cnVjdCImJmEudGFnIT09InVuaW9uIil0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGFub255bW91cyBtZW1iZXIgIiR7RX0iIG11c3QgYmUgYSBzdHJ1Y3QvdW5pb25gKTtmb3IobGV0IGwgb2YgYS5maWVsZHMpaS5wdXNoKHsuLi5sLG9mZnNldDpsLm9mZnNldCtmfSl9ZSYmKGM9Zit3KSxuPU1hdGgubWF4KG4sbSksbz1NYXRoLm1heChvLHcpfXJldHVybiB4KCkse3NpemU6QihlP2M6byxuKSxtYXhFZmZlY3RpdmVBbGlnbjpuLGZpZWxkczppfX1mdW5jdGlvbiBndCh0LGUscil7bGV0IG49UltyXTtyZXR1cm4gbj09PTE/QmlnSW50KHQuZ2V0VWludDgoZSkpOm49PT0yP0JpZ0ludCh0LmdldFVpbnQxNihlLCEwKSk6bj09PTQ/QmlnSW50KHQuZ2V0VWludDMyKGUsITApKTp0LmdldEJpZ1VpbnQ2NChlLCEwKX1mdW5jdGlvbiBWdCh0LGUscixuKXtsZXQgbz1SW3JdO2lmKG89PT0xKXt0LnNldFVpbnQ4KGUsTnVtYmVyKG4mMHhmZm4pKTtyZXR1cm59aWYobz09PTIpe3Quc2V0VWludDE2KGUsTnVtYmVyKG4mMHhmZmZmbiksITApO3JldHVybn1pZihvPT09NCl7dC5zZXRVaW50MzIoZSxOdW1iZXIobiYweGZmZmZmZmZmbiksITApO3JldHVybn10LnNldEJpZ1VpbnQ2NChlLG4mMHhmZmZmZmZmZmZmZmZmZmZmbiwhMCl9ZnVuY3Rpb24gWXQodCxlLHIpe2xldCBuPUJpZ0ludChyLndpZHRoKSxvPWd0KHQsZSxyLnVuaXQpPj5CaWdJbnQoci5iaXQpJigxbjw8biktMW47cmV0dXJuIHIudW5pdFswXT09PSJpIiYmbyYxbjw8bi0xbiYmKG8tPTFuPDxuKSxyLndpZHRoPjUzP286TnVtYmVyKG8pfWZ1bmN0aW9uIHZ0KHQsZSxyLG4pe2xldCBvPUJpZ0ludChyLndpZHRoKSxpPUJpZ0ludChyLmJpdCksYz0oMW48PG8pLTFuLHM9Yzw8aSx1PWd0KHQsZSxyLnVuaXQpLHA9KHR5cGVvZiBuPT0iYmlnaW50Ij9uOkJpZ0ludChNYXRoLnRydW5jKG4pKSkmYztWdCh0LGUsci51bml0LHUmfnN8cDw8aSl9dmFyIGp0PXsidXRmLTgiOm5ldyBUZXh0RW5jb2RlcigidXRmLTgiKSwidXRmLTE2bGUiOm5ldyBUZXh0RW5jb2RlcigidXRmLTE2bGUiKX0sWHQ9eyJ1dGYtOCI6bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIse2lnbm9yZUJPTTohMH0pLCJ1dGYtMTZsZSI6bmV3IFRleHREZWNvZGVyKCJ1dGYtMTZsZSIse2lnbm9yZUJPTTohMH0pfTtmdW5jdGlvbiBadCh0LGUscixuKXtsZXQgbz1uZXcgVWludDhBcnJheSh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQrZSxyKSxpPW49PT0idXRmLTE2bGUiPzI6MSxjPXI7Zm9yKGxldCBzPTA7cytpPD1yO3MrPWkpaWYob1tzXT09PTAmJihpPT09MXx8b1tzKzFdPT09MCkpe2M9czticmVha31yZXR1cm4gWHRbbl0uZGVjb2RlKG8uc3ViYXJyYXkoMCxjKSl9ZnVuY3Rpb24gcXQodCxlLHIsbixvKXtsZXQgaT1uZXcgVWludDhBcnJheSh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQrZSxyKTtpLmZpbGwoMCk7bGV0IHM9ci0obj09PSJ1dGYtMTZsZSI/MjoxKTtpZihzPD0wKXJldHVybjtsZXQgdT1qdFtuXS5lbmNvZGUoU3RyaW5nKG8/PyIiKSk7aS5zZXQodS5zdWJhcnJheSgwLE1hdGgubWluKHUubGVuZ3RoLHMpKSl9ZnVuY3Rpb24gUXQodCxlLHIsbil7bGV0IG89bi5lbGVtZW50U2l6ZT4wP3Ivbi5lbGVtZW50U2l6ZTowLGk9W107Zm9yKGxldCBjPTA7YzxvO2MrKylpLnB1c2goVHQodCxlK2Mqbi5lbGVtZW50U2l6ZSxuLmVsZW1lbnRUeXBlLG4uZWxlbWVudFNpemUpKTtyZXR1cm4gaX1mdW5jdGlvbiBLdCh0LGUscixuLG8pe2xldCBpPW4uZWxlbWVudFNpemU+MD9yL24uZWxlbWVudFNpemU6MCxjPW8/P1tdO2ZvcihsZXQgcz0wO3M8aTtzKyspRnQodCxlK3Mqbi5lbGVtZW50U2l6ZSxuLmVsZW1lbnRUeXBlLG4uZWxlbWVudFNpemUsY1tzXSl9ZnVuY3Rpb24gVHQodCxlLHIsbil7c3dpdGNoKHIudGFnKXtjYXNlImJhc2ljIjpyZXR1cm4geih0LGUsci5raW5kKTtjYXNlImJpdGZpZWxkIjpyZXR1cm4gWXQodCxlLHIpO2Nhc2Uic3RyaW5nIjpyZXR1cm4gWnQodCxlLG4sci5lbmNvZGluZyk7Y2FzZSJzdHJ1Y3QiOmNhc2UidW5pb24iOnJldHVybiBLKHQsZSxyLmZpZWxkcyk7Y2FzZSJhcnJheSI6cmV0dXJuIFF0KHQsZSxuLHIpfX1mdW5jdGlvbiBGdCh0LGUscixuLG8pe3N3aXRjaChyLnRhZyl7Y2FzZSJiYXNpYyI6Wih0LGUse2s6ci5raW5kLHY6b30pO2JyZWFrO2Nhc2UiYml0ZmllbGQiOnZ0KHQsZSxyLG8/PzApO2JyZWFrO2Nhc2Uic3RyaW5nIjpxdCh0LGUsbixyLmVuY29kaW5nLG8pO2JyZWFrO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjpTdCh0LGUsci5maWVsZHMsbz8/e30pO2JyZWFrO2Nhc2UiYXJyYXkiOkt0KHQsZSxuLHIsbyk7YnJlYWt9fWZ1bmN0aW9uIEsodCxlLHIpe2xldCBuPXt9O2ZvcihsZXQgbyBvZiByKXtsZXQgaT1UdCh0LGUrby5vZmZzZXQsby50eXBlLG8uc2l6ZSk7aWYoby5ub25udWxsJiZpPT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGRlY29kZTogJyEnIGZpZWxkICIke28ubmFtZX0iIGdvdCAwIChDIGRpZCBub3QgZmlsbCBpdCwgb3IgZGVjb2RlIHdhcyBjYWxsZWQgb24gYW4gdW5maWxsZWQgc2xvdClgKTtuW28ubmFtZV09aX1yZXR1cm4gbn1mdW5jdGlvbiBTdCh0LGUscixuKXtmb3IobGV0IG8gb2YgciluW28ubmFtZV0hPT12b2lkIDAmJkZ0KHQsZStvLm9mZnNldCxvLnR5cGUsby5zaXplLG5bby5uYW1lXSl9ZnVuY3Rpb24gSnQodCl7bGV0e2ZpZWxkczplLHNpemU6cixtYXhFZmZlY3RpdmVBbGlnbjpufT13dCh0KTtyZXR1cm57ZmllbGRzOmUsc2l6ZTpyLHN0cnVjdEFsaWduOm4sZGVjb2RlOm89PksodHlwZW9mIG89PSJudW1iZXIiP25ldyBEYXRhVmlldyh4dC5yZWFkQnl0ZXMobyxyKSk6bmV3IERhdGFWaWV3KG8pLDAsZSksYWxsb2M6KG89PntpZihvIT09dm9pZCAwJiYoIU51bWJlci5pc0ludGVnZXIobyl8fG88MSkpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBhbGxvYyhuKSByZXF1aXJlcyBhbiBpbnRlZ2VyIG4gPj0gMSAoUEFCKDApIG5ldmVyIGVzY2FwZXMgXHUyMDE0IHBhc3MgTlVMTCBmb3IgYW4gZW1wdHkgcG9pbnRlciBwb3NpdGlvbikiKTtyZXR1cm4gbmV3IGgocioobz8/MSkpfSksZW5jb2RlOigobyxpLGMpPT57aWYobz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IGVuY29kZSh2KSByZXF1aXJlcyBhbiBhcmd1bWVudDsgdXNlIGFsbG9jKCkgZm9yIGEgemVyb2VkIG91dC1wYXJhbSBzbG90Iik7bGV0IHM9aT8/bmV3IGgocik7cmV0dXJuIFN0KG5ldyBEYXRhVmlldyhzKSxjPz8wLGUsbyksc30pLG9mZnNldE9mOm89Pntmb3IobGV0IGkgb2YgZSlpZihpLm5hbWU9PT1vKXJldHVybiBpLm9mZnNldDt0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IG5vIGZpZWxkICIke299ImApfX19ZnVuY3Rpb24gdGUodCxlLHIpe2xldCBuPWVbIiMiXTtpZihuIT09dm9pZCAwJiZuIT09dCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6ICR7dH0oKSByZWNlaXZlZCBhICcke1N0cmluZyhuKX0nIGRlY2xhcmF0aW9uIChraW5kIG1pc21hdGNoIFx1MjAxNCB1c2UgJHtufSgpIGZvciBpdClgKTtsZXQgbz1lWyIjcGFjayJdO2lmKHI9PT12b2lkIDAmJm8hPT12b2lkIDApcj1vO2Vsc2UgaWYociE9PXZvaWQgMCYmbyE9PXZvaWQgMCYmciE9PW8pdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiAjcGFjayBjb25mbGljdDogb3B0cy5wYWNrPSR7cn0gdnMgZGVjbGFyYXRpb24gJHtTdHJpbmcobyl9YCk7bGV0IGk9eyIjIjp0fTtyIT09dm9pZCAwJiYoaVsiI3BhY2siXT1yKTtmb3IobGV0W2Msc11vZiBPYmplY3QuZW50cmllcyhlKSljLnN0YXJ0c1dpdGgoIiMiKXx8KGlbY109cyk7cmV0dXJuIGl9ZnVuY3Rpb24gVSh0LGUscil7bGV0IG49dHlwZW9mIHQ9PSJzdHJpbmciO3JldHVybiBKdCh0ZSgic3RydWN0IixuP2U6dCwobj9yOmUpPy5wYWNrKSl9dmFyIGVlPXsiIyI6InN0cnVjdCIsY2I6InUzMiIsbHBSZXNlcnZlZDoiPD5wdHIiLGxwRGVza3RvcDoiPD5wdHIiLGxwVGl0bGU6Ijw+cHRyIixkd1g6InUzMiIsZHdZOiJ1MzIiLGR3WFNpemU6InUzMiIsZHdZU2l6ZToidTMyIixkd1hDb3VudENoYXJzOiJ1MzIiLGR3WUNvdW50Q2hhcnM6InUzMiIsZHdGaWxsQXR0cmlidXRlOiJ1MzIiLGR3RmxhZ3M6InUzMiIsd1Nob3dXaW5kb3c6InUxNkBTaG93V2luZG93Q21kIixjYlJlc2VydmVkMjoidTE2IixscFJlc2VydmVkMjoiPD5wdHIiLGhTdGRJbnB1dDoiPEhGSUxFPnB0ciIsaFN0ZE91dHB1dDoiPEhGSUxFPnB0ciIsaFN0ZEVycm9yOiI8SEZJTEU+cHRyIn0sVj1VKCJTVEFSVFVQSU5GT1ciLGVlKSxyZT17IiMiOiJzdHJ1Y3QiLGhQcm9jZXNzOiI8SFBST0NFU1M+cHRyISIsaFRocmVhZDoiPEhUSFJFQUQ+cHRyISIsZHdQcm9jZXNzSWQ6InUzMiIsZHdUaHJlYWRJZDoidTMyIn0sSj1VKCJQUk9DRVNTX0lORk9STUFUSU9OIixyZSk7dmFyIEk9KHQsZSxyKT0+RXQoImtlcm5lbDMyLmRsbCIsdCxlLHIpLEN0PUkoIkNyZWF0ZVBpcGUiLCI8PnB0ciA8PnB0ciA8PnB0ciB1MzIgLT4gaTMyIiksdHQ9SSgiU2V0SGFuZGxlSW5mb3JtYXRpb24iLCI8SEZJTEU+cHRyISB1MzIgdTMyIC0+IGkzMiIpLGJ0PUkoIkNyZWF0ZVByb2Nlc3NXIiwiPFdDSEFSPnB0ciA8V0NIQVI+cHRyIDw+cHRyIDw+cHRyIGkzMiB1MzIgPD5wdHIgPFdDSEFSPnB0ciA8U1RBUlRVUElORk9XPnB0ciA8UFJPQ0VTU19JTkZPUk1BVElPTj5wdHIgLT4gaTMyIix7U1RBUlRVUElORk9XOlZ9KSxJdD1JKCJXYWl0Rm9yU2luZ2xlT2JqZWN0IiwiPD5wdHIgdTMyIC0+IHUzMiIpLHl0PUkoIkdldEV4aXRDb2RlUHJvY2VzcyIsIjxIUFJPQ0VTUz5wdHIhIDxCWVRFPnB0ciAtPiBpMzIiKSxNPUkoIkNsb3NlSGFuZGxlIiwiPD5wdHIgLT4gaTMyIik7dmFyIE50PUkoIlJlYWRGaWxlIiwiPEhGSUxFPnB0ciEgPEJZVEU+cHRyIHUzMiA8QllURT5wdHIgPD5wdHIgLT4gaTMyIik7dmFyIGV0PUkoIkdldExhc3RFcnJvciIsIiAtPiB1MzIiKSxEdD1JKCJHZXRTeXN0ZW1EaXJlY3RvcnlXIiwiPEJZVEU+cHRyIHUzMiAtPiB1MzIiKTt2YXIgbmU9dD0+e3RyeXtsZXQgZT1MdC5vcGVuKCJkaWFnLmxvZyIsImEiKTtlJiYoZS5wdXRzKGAke0RhdGUubm93KCl9ICR7dH0KYCksZS5jbG9zZSgpKX1jYXRjaHt9fSxydD0xLG9lPTI1NixpZT00Mjk0OTY3Mjk1LEg9T3QuV29ya2VyLnBhcmVudCxBdD0iQzpcXFdpbmRvd3NcXFN5c3RlbTMyIjt0cnl7bGV0IHQ9Ry5hbGxvYygyNTYpLHI9RHQodCwyNTYpPjA/Ry5kZWNvZGUodCk6IiI7ciYmKEF0PXIpfWNhdGNoKHQpe25lKCJTWVMtRElSLUZBSUw6ICIrU3RyaW5nKHQpKX12YXIgbnQ9VSgiUElQRV9IQU5ETEVTIix7aFJlYWQ6IjxIRklMRT5wdHIhIixoV3JpdGU6IjxIRklMRT5wdHIhIn0pO2Z1bmN0aW9uIHNlKHQsZSl7bGV0IHI9bnQuYWxsb2MoKTtpZighQ3Qoci5wdHIsci5wdHIrbnQub2Zmc2V0T2YoImhXcml0ZSIpLE8sMCkpdGhyb3cgbmV3IEVycm9yKCJDcmVhdGVQaXBlIGVycj0iK2V0KCkpO2xldHtoUmVhZDpuLGhXcml0ZTpvfT1udC5kZWNvZGUocik7dHQobyxydCxydCksdHQobixydCwwKTtsZXQgaT1KLmFsbG9jKCksYz1gJHtBdH1cXGNtZC5leGUgL3UgL2MgJHtlfWA7aWYoIWJ0KE8sYyxPLE8sMSwwLE8sTyx7Y2I6Vi5zaXplLGR3RmxhZ3M6b2UsaFN0ZE91dHB1dDpvLGhTdGRFcnJvcjpvfSxpLnB0cikpdGhyb3cgTShuKSxNKG8pLG5ldyBFcnJvcigiQ3JlYXRlUHJvY2Vzc1cgZXJyPSIrZXQoKSsiIGNtZD0iK2MpO2xldHtoUHJvY2VzczpzLGhUaHJlYWQ6dSxkd1Byb2Nlc3NJZDpwfT1KLmRlY29kZShpKTtNKHUpLE0obyksSC5wb3N0TWVzc2FnZSh7dHlwZToiaW5mbyIsaWQ6dCxwaWQ6cH0pO2xldCB4PW5ldyBoKDQwOTYpLEY9bmV3IFVpbnQ4QXJyYXkoeCksZz1uZXcgaCg0KSxUPW5ldyBVaW50MzJBcnJheShnKTtmb3IoO1RbMF09MCwhIU50KG4seCw0MDk2LGcsTyk7KXtsZXQgUz1UWzBdO2lmKFM9PT0wKWJyZWFrO0gucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6Ri5zbGljZSgwLFMpfSl9SXQocyxpZSk7bGV0IEU9bmV3IGgoNCksTD1uZXcgSW50MzJBcnJheShFKTt5dChzLEUpO2xldCB3PUxbMF07cmV0dXJuIE0obiksTShzKSx3fUgub25tZXNzYWdlPXQ9PntsZXQgZT10LmRhdGE7aWYoZS50eXBlPT09InJ1biImJnR5cGVvZiBlLmNtZD09InN0cmluZyIpe2xldCByPS0xLG49bnVsbDt0cnl7cj1zZShlLmlkLGUuY21kKX1jYXRjaChvKXtuPVN0cmluZyhvKX1ILnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOmUuaWQsY29kZTpyLGVycm9yOm59KX1ILm9ubWVzc2FnZT1udWxsfTsK");
22305
+ 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");
22049
22306
  bumpWorkers(1);
22050
22307
  const id = 1;
22051
22308
  let innerPid = null;
@@ -22076,7 +22333,7 @@ function runInWorker(cmd, signal, timeoutMs) {
22076
22333
  return;
22077
22334
  settled = true;
22078
22335
  if (timer !== null)
22079
- os6.clearTimeout(timer);
22336
+ os7.clearTimeout(timer);
22080
22337
  worker.onmessage = null;
22081
22338
  bumpWorkers(-1);
22082
22339
  fn();
@@ -22103,7 +22360,7 @@ function runInWorker(cmd, signal, timeoutMs) {
22103
22360
  killOnAbort();
22104
22361
  }
22105
22362
  if (timeoutMs != null && timeoutMs > 0) {
22106
- timer = os6.setTimeout(() => {
22363
+ timer = os7.setTimeout(() => {
22107
22364
  finish(() => {
22108
22365
  kill();
22109
22366
  resolveTrailers({ "X-Exit-Code": "-1" });
@@ -22382,35 +22639,35 @@ function listWindows() {
22382
22639
  var DISP_CHANGE_NAME = {
22383
22640
  [
22384
22641
  0
22385
- /* gui.DisplayChangeResult.SUCCESSFUL */
22642
+ /* DisplayChangeResult.SUCCESSFUL */
22386
22643
  ]: "SUCCESSFUL",
22387
22644
  [
22388
22645
  1
22389
- /* gui.DisplayChangeResult.RESTART */
22646
+ /* DisplayChangeResult.RESTART */
22390
22647
  ]: "RESTART",
22391
22648
  [
22392
22649
  -1
22393
- /* gui.DisplayChangeResult.FAILED */
22650
+ /* DisplayChangeResult.FAILED */
22394
22651
  ]: "FAILED",
22395
22652
  [
22396
22653
  -2
22397
- /* gui.DisplayChangeResult.BADMODE */
22654
+ /* DisplayChangeResult.BADMODE */
22398
22655
  ]: "BADMODE",
22399
22656
  [
22400
22657
  -3
22401
- /* gui.DisplayChangeResult.NOTUPDATED */
22658
+ /* DisplayChangeResult.NOTUPDATED */
22402
22659
  ]: "NOTUPDATED",
22403
22660
  [
22404
22661
  -4
22405
- /* gui.DisplayChangeResult.BADFLAGS */
22662
+ /* DisplayChangeResult.BADFLAGS */
22406
22663
  ]: "BADFLAGS",
22407
22664
  [
22408
22665
  -5
22409
- /* gui.DisplayChangeResult.BADPARAM */
22666
+ /* DisplayChangeResult.BADPARAM */
22410
22667
  ]: "BADPARAM",
22411
22668
  [
22412
22669
  -6
22413
- /* gui.DisplayChangeResult.BADDUALVIEW */
22670
+ /* DisplayChangeResult.BADDUALVIEW */
22414
22671
  ]: "BADDUALVIEW"
22415
22672
  };
22416
22673
  function dispChangeName(ret) {
@@ -22419,10 +22676,10 @@ function dispChangeName(ret) {
22419
22676
  function currentScreen() {
22420
22677
  return GetSystemMetrics(
22421
22678
  0
22422
- /* gui.SysMetrics.CXSCREEN */
22679
+ /* SysMetrics.CXSCREEN */
22423
22680
  ) + "x" + GetSystemMetrics(
22424
22681
  1
22425
- /* gui.SysMetrics.CYSCREEN */
22682
+ /* SysMetrics.CYSCREEN */
22426
22683
  );
22427
22684
  }
22428
22685
  function listModes32() {
@@ -22456,7 +22713,7 @@ function applyDisplayMode(w2, h2, persist) {
22456
22713
  const testRet = ChangeDisplaySettings(
22457
22714
  dm.ptr,
22458
22715
  2
22459
- /* gui.ChangeDisplayFlag.TEST */
22716
+ /* ChangeDisplayFlag.TEST */
22460
22717
  );
22461
22718
  if (testRet !== 0) {
22462
22719
  return {
@@ -22473,7 +22730,7 @@ function applyDisplayMode(w2, h2, persist) {
22473
22730
  ret = ChangeDisplaySettings(
22474
22731
  dm.ptr,
22475
22732
  1
22476
- /* gui.ChangeDisplayFlag.UPDATEREGISTRY */
22733
+ /* ChangeDisplayFlag.UPDATEREGISTRY */
22477
22734
  );
22478
22735
  }
22479
22736
  return { before, after: currentScreen(), testRet, ret, retName: dispChangeName(ret), modes32: listModes32() };
@@ -22486,16 +22743,107 @@ API\uFF08\u914D\u7F6E token \u540E\u9700 Authorization: Bearer <token>\uFF0C\u67
22486
22743
  \uFF08X-Dimensions\uFF1B\u4E0D\u5E26 hwnd = \u6574\u5C4F BitBlt\uFF1B\u5E26 hwnd \u9ED8\u8BA4 mode=print
22487
22744
  \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
22488
22745
  GET /window_list \u2192 JSON \u7A97\u53E3\u5217\u8868 [{hwnd,title,className,...}]
22746
+ GET /tray_list \u2192 JSON {icons:[{area,index,hWnd,uID,tooltip,rect}]}\uFF08\u8DE8\u8FDB\u7A0B\u679A\u4E3E
22747
+ explorer toolbar\uFF1A\u53EF\u89C1\u533A Shell_TrayWnd + \u6298\u53E0\u533A NotifyIconOverflowWindow\uFF1B
22748
+ rect \u5C4F\u5E55\u7269\u7406\u50CF\u7D20\uFF0C\u5168 0 \u2192 null\uFF1B\u6298\u53E0\u9762\u677F\u672A\u5C55\u5F00\u65F6 overflow \u533A rect
22749
+ \u4EC5\u5F53\u5C55\u5F00\u540E\u53EF\u9760\uFF09\uFF1B?probe=<hwnd>&uid=<n> \u2192 \u9644 probe {hr,hrName,rect}
22750
+ \uFF08\u5355\u56FE\u6807 Shell_NotifyIconGetRect\uFF0CWin7+\uFF1A0=found \u9644\u5BB9\u5668 rect / 1=hidden
22751
+ / E_FAIL=\u4E0D\u5B58\u5728\u6216 GUID \u56FE\u6807\uFF1BXP \u65E0\u6B64 API \u2192 unsupported\uFF09
22489
22752
  POST /set_resolution ?w=<px>&h=<px>&persist=0|1\uFF08\u9ED8\u8BA4 1 = \u5199\u6CE8\u518C\u8868\u8DE8\u91CD\u542F\uFF09\u2192 JSON
22490
22753
  {before,after,testRet,ret,retName,modes32}\uFF1Bmodes32 \u6052\u5E26 32bpp
22491
- \u53EF\u7528\u6A21\u5F0F\uFF08\u975E\u6CD5\u5BBD\u9AD8\u4F1A\u4EE5 BADMODE \u62D2\u7EDD\u5E76\u7ED9\u672C\u5217\u8868\uFF09`;
22754
+ \u53EF\u7528\u6A21\u5F0F\uFF08\u975E\u6CD5\u5BBD\u9AD8\u4F1A\u4EE5 BADMODE \u62D2\u7EDD\u5E76\u7ED9\u672C\u5217\u8868\uFF09
22755
+ POST /input body = JSON \u6570\u7EC4\uFF08\u6279\u91CF\u6CE8\u5165\uFF1Bx/y \u7269\u7406\u50CF\u7D20\uFF09\uFF1A
22756
+ {"t":"move","x":,"y":} | {"t":"down|up","btn":"left|right|middle|x1|x2","x":,"y":?} |
22757
+ {"t":"key","key":"a|enter|0x41","up":true?} | {"t":"sleep","ms":0..5000}
22758
+ \u2192 JSON {sent,expected}\uFF1B\u6309 sleep \u5207\u6BB5\uFF0C\u6BB5\u5185\u4E00\u6B21 SendInput \u539F\u5B50\u6CE8\u5165
22759
+ POST /upload ?path=<\u76EE\u6807\u8DEF\u5F84>&mkdir=0 body=\u539F\u59CB\u5B57\u8282\uFF08\u975E\u7A7A\uFF09\u2192 JSON {bytes,path}
22760
+ \u9ED8\u8BA4\u9010\u5C42\u5EFA\u7236\u76EE\u5F55\uFF08mkdir=0 \u4E25\u683C\u8981\u6C42\u7236\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u9632\u8DEF\u5F84 typo\uFF09\uFF1B
22761
+ \u539F\u5B50\u5199\uFF1A\u5148\u5199 <path>.uploading \u518D MoveFileEx \u8986\u76D6\uFF0C\u770B\u4E0D\u5230\u534A\u622A\u6587\u4EF6\u3002
22762
+ \u65E0 SMB \u73AF\u5883\u7684\u4F20\u6587\u4EF6\u901A\u9053\uFF0C\u8DEF\u5F84\u5168\u653E\u5F00\u30028MB \u5206\u5757\u5199\u76D8\uFF08CRT \u5355\u5757\u5927\u5199
22763
+ \u5728 XP \u7F51\u7EDC\u76D8 ~64MiB \u8FB9\u754C\u4F1A\u88AB\u6574\u5757\u62D2\u7EDD\uFF09\uFF0CXP/win7 \u5B9E\u6D4B 100MB+ OK
22764
+ GET /download ?path=<\u6587\u4EF6\u8DEF\u5F84> \u2192 \u539F\u59CB\u5B57\u8282\u6D41\uFF08application/octet-stream\uFF0CX-Bytes \u5934\uFF1B
22765
+ \u5206\u5757\u8BFB\u5230 EOF \u65E0\u5927\u5C0F\u4E0A\u9650\uFF09\u2014\u2014type \u547D\u4EE4\u7684\u4E8C\u8FDB\u5236\u5B89\u5168\u7248`;
22492
22766
  function usageResponse() {
22493
22767
  return new Response(USAGE, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
22494
22768
  }
22769
+ var INPUT_MOUSE = 0;
22770
+ var INPUT_KEYBOARD = 1;
22771
+ var MOUSEEVENTF_MOVE = 1;
22772
+ var MOUSEEVENTF_ABSOLUTE = 32768;
22773
+ var KEYEVENTF_KEYUP = 2;
22774
+ var MOUSE_BTNS = {
22775
+ left: [2, 4, 0],
22776
+ right: [8, 16, 0],
22777
+ middle: [32, 64, 0],
22778
+ x1: [128, 256, 1],
22779
+ x2: [128, 256, 2]
22780
+ };
22781
+ var VK_NAMES = {
22782
+ backspace: 8,
22783
+ tab: 9,
22784
+ enter: 13,
22785
+ shift: 16,
22786
+ ctrl: 17,
22787
+ alt: 18,
22788
+ caps: 20,
22789
+ esc: 27,
22790
+ space: 32,
22791
+ pageup: 33,
22792
+ pagedown: 34,
22793
+ end: 35,
22794
+ home: 36,
22795
+ left: 37,
22796
+ up: 38,
22797
+ right: 39,
22798
+ down: 40,
22799
+ insert: 45,
22800
+ delete: 46,
22801
+ win: 91,
22802
+ f1: 112,
22803
+ f2: 113,
22804
+ f3: 114,
22805
+ f4: 115,
22806
+ f5: 116,
22807
+ f6: 117,
22808
+ f7: 118,
22809
+ f8: 119,
22810
+ f9: 120,
22811
+ f10: 121,
22812
+ f11: 122,
22813
+ f12: 123
22814
+ };
22815
+ function vkOf(key) {
22816
+ if (typeof key === "number" && Number.isInteger(key) && key >= 0 && key <= 65535)
22817
+ return key;
22818
+ if (typeof key === "string") {
22819
+ if (key.length === 1) {
22820
+ const c2 = key.toUpperCase().charCodeAt(0);
22821
+ if (c2 >= 48 && c2 <= 57 || c2 >= 65 && c2 <= 90)
22822
+ return c2;
22823
+ }
22824
+ const vk = VK_NAMES[key.toLowerCase()];
22825
+ if (vk !== void 0)
22826
+ return vk;
22827
+ }
22828
+ throw new Error("bad key: " + JSON.stringify(key) + " (a-z/0-9|name|0..0xFFFF)");
22829
+ }
22830
+ function mkdirParents(dest) {
22831
+ const segs = dest.replace(/\//g, "\\").split("\\");
22832
+ let acc = "";
22833
+ for (let i2 = 0; i2 < segs.length - 1; i2++) {
22834
+ acc = acc === "" ? segs[i2] : acc + "\\" + segs[i2];
22835
+ if (acc === "" || /^[A-Za-z]:$/.test(acc))
22836
+ continue;
22837
+ try {
22838
+ os7.mkdir(acc);
22839
+ } catch {
22840
+ }
22841
+ }
22842
+ }
22495
22843
  var server = createServer(async (req) => {
22496
22844
  const t0 = Date.now();
22497
22845
  const path = new URL(req.url).pathname;
22498
- const isApi = req.method === "POST" && (path === "/exec" || path === "/set_resolution") || req.method === "GET" && (path === "/window_list" || path === "/screenshot");
22846
+ const isApi = req.method === "POST" && (path === "/exec" || path === "/set_resolution" || path === "/input" || path === "/upload") || req.method === "GET" && (path === "/window_list" || path === "/screenshot" || path === "/tray_list" || path === "/download");
22499
22847
  if (!isApi)
22500
22848
  return usageResponse();
22501
22849
  const denied = authCheck(req);
@@ -22514,6 +22862,31 @@ var server = createServer(async (req) => {
22514
22862
  return jsonError(500, String(ex));
22515
22863
  }
22516
22864
  }
22865
+ if (req.method === "GET" && path === "/tray_list") {
22866
+ const params = new URL(req.url).searchParams;
22867
+ let probe = null;
22868
+ const ph = params.get("probe");
22869
+ if (ph !== null) {
22870
+ const hh = Number(ph), uid = Number(params.get("uid") ?? "");
22871
+ if (!Number.isInteger(hh) || hh <= 0 || !Number.isInteger(uid) || uid < 0) {
22872
+ logReq(t0, "GET /tray_list", 400, "probe=<hwnd>&uid=<n>");
22873
+ return jsonError(400, "probe needs integer hwnd>0 and uid>=0");
22874
+ }
22875
+ probe = { hWnd: hh, uID: uid };
22876
+ }
22877
+ try {
22878
+ const icons = listTrayIcons();
22879
+ const body = { icons };
22880
+ if (probe)
22881
+ body.probe = probeTrayIcon(probe.hWnd, probe.uID);
22882
+ const nOv = icons.reduce((n2, e2) => n2 + (e2.area === "overflow" ? 1 : 0), 0);
22883
+ logReq(t0, "GET /tray_list", 200, icons.length + " icons \xB7 overflow " + nOv);
22884
+ return new Response(JSON.stringify(body), { headers: { "Content-Type": "application/json" } });
22885
+ } catch (ex) {
22886
+ logReq(t0, "GET /tray_list", 500, String(ex));
22887
+ return jsonError(500, String(ex));
22888
+ }
22889
+ }
22517
22890
  if (req.method === "GET" && path === "/screenshot") {
22518
22891
  let opts;
22519
22892
  try {
@@ -22555,6 +22928,105 @@ var server = createServer(async (req) => {
22555
22928
  logReq(t0, "POST /set_resolution " + w2 + "x" + h2 + (persist ? "" : " persist=0"), 200, result.ret !== 0 ? result.retName : void 0);
22556
22929
  return resp;
22557
22930
  }
22931
+ if (req.method === "POST" && path === "/input") {
22932
+ const bad = (msg) => {
22933
+ logReq(t0, "POST /input", 400, msg);
22934
+ return jsonError(400, msg);
22935
+ };
22936
+ let raw;
22937
+ try {
22938
+ raw = await req.json();
22939
+ } catch (ex) {
22940
+ return bad("bad json: " + String(ex));
22941
+ }
22942
+ if (!Array.isArray(raw) || raw.length === 0)
22943
+ return bad("body must be a non-empty JSON array");
22944
+ if (raw.length > 1e3)
22945
+ return bad("too many events: " + raw.length + " (max 1000)");
22946
+ const sw = GetSystemMetrics(0), sh = GetSystemMetrics(1);
22947
+ const segs = [{ els: [], sleep: 0 }];
22948
+ const cur = () => segs[segs.length - 1];
22949
+ try {
22950
+ for (const e2 of raw) {
22951
+ if (typeof e2 !== "object" || e2 === null || Array.isArray(e2))
22952
+ throw new Error("event must be an object: " + JSON.stringify(e2));
22953
+ const ev = e2;
22954
+ const abs = (required) => {
22955
+ if (ev.x === void 0 && ev.y === void 0) {
22956
+ if (required)
22957
+ throw new Error("x/y required for move");
22958
+ return [0, 0, 0];
22959
+ }
22960
+ const x2 = ev.x, y2 = ev.y;
22961
+ if (typeof x2 !== "number" || typeof y2 !== "number" || !Number.isInteger(x2) || !Number.isInteger(y2))
22962
+ throw new Error("x/y must be integers (physical px)");
22963
+ if (x2 < 0 || x2 >= sw || y2 < 0 || y2 >= sh)
22964
+ throw new Error("x/y out of screen: 0.." + (sw - 1) + " / 0.." + (sh - 1));
22965
+ return [
22966
+ Math.round(x2 * 65535 / (sw - 1)),
22967
+ Math.round(y2 * 65535 / (sh - 1)),
22968
+ MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE
22969
+ ];
22970
+ };
22971
+ switch (ev.t) {
22972
+ case "move": {
22973
+ const [dx, dy, f2] = abs(true);
22974
+ cur().els.push({ type: INPUT_MOUSE, data: { mi: { dx, dy, dwFlags: f2 } } });
22975
+ break;
22976
+ }
22977
+ case "down":
22978
+ case "up": {
22979
+ const btn = typeof ev.btn === "string" ? MOUSE_BTNS[ev.btn] : void 0;
22980
+ if (!btn)
22981
+ throw new Error("bad btn: " + JSON.stringify(ev.btn) + " (left|right|middle|x1|x2)");
22982
+ const [downF, upF, mData] = btn;
22983
+ const [dx, dy, f2] = abs(false);
22984
+ const flag = ev.t === "down" ? downF : upF;
22985
+ cur().els.push({ type: INPUT_MOUSE, data: { mi: { dx, dy, mouseData: mData, dwFlags: f2 | flag } } });
22986
+ break;
22987
+ }
22988
+ case "key": {
22989
+ const up = ev.up === true;
22990
+ cur().els.push({ type: INPUT_KEYBOARD, data: { ki: { wVk: vkOf(ev.key), dwFlags: up ? KEYEVENTF_KEYUP : 0 } } });
22991
+ break;
22992
+ }
22993
+ case "sleep": {
22994
+ const ms = ev.ms;
22995
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0 || ms > 5e3)
22996
+ throw new Error("sleep ms must be a number in 0..5000");
22997
+ segs.push({ els: [], sleep: ms });
22998
+ break;
22999
+ }
23000
+ default:
23001
+ throw new Error("bad t: " + JSON.stringify(ev.t) + " (move|down|up|key|sleep)");
23002
+ }
23003
+ }
23004
+ } catch (ex) {
23005
+ return bad(ex instanceof Error ? ex.message : String(ex));
23006
+ }
23007
+ let expected = 0, sent = 0;
23008
+ for (const s2 of segs)
23009
+ expected += s2.els.length;
23010
+ try {
23011
+ for (const seg of segs) {
23012
+ if (seg.sleep > 0)
23013
+ await new Promise((r2) => {
23014
+ os7.setTimeout(r2, seg.sleep);
23015
+ });
23016
+ if (seg.els.length === 0)
23017
+ continue;
23018
+ const n2 = SendInput(seg.els.length, seg.els, INPUT.size);
23019
+ sent += n2;
23020
+ if (n2 < seg.els.length)
23021
+ break;
23022
+ }
23023
+ } catch (ex) {
23024
+ logReq(t0, "POST /input", 500, String(ex));
23025
+ return jsonError(500, String(ex));
23026
+ }
23027
+ logReq(t0, "POST /input " + raw.length + "ev", 200, sent < expected ? "sent " + sent + "/" + expected : void 0);
23028
+ return new Response(JSON.stringify({ sent, expected }), { headers: { "Content-Type": "application/json" } });
23029
+ }
22558
23030
  if (req.method === "POST" && path === "/exec") {
22559
23031
  let out;
22560
23032
  let cmd;
@@ -22590,6 +23062,103 @@ var server = createServer(async (req) => {
22590
23062
  return jsonError(504, String(ex));
22591
23063
  }
22592
23064
  }
23065
+ if (req.method === "POST" && path === "/upload") {
23066
+ const bad = (msg) => {
23067
+ logReq(t0, "POST /upload", 400, msg);
23068
+ return jsonError(400, msg);
23069
+ };
23070
+ const params = new URL(req.url).searchParams;
23071
+ const dest = params.get("path");
23072
+ if (!dest)
23073
+ return bad("path=<\u76EE\u6807\u8DEF\u5F84>");
23074
+ let bytes;
23075
+ try {
23076
+ bytes = new Uint8Array(await req.arrayBuffer());
23077
+ } catch (ex) {
23078
+ return bad("bad body: " + String(ex));
23079
+ }
23080
+ if (bytes.length === 0)
23081
+ return bad("empty body");
23082
+ try {
23083
+ if (params.get("mkdir") !== "0")
23084
+ mkdirParents(dest);
23085
+ const tmp = dest + ".uploading";
23086
+ const f2 = std2.open(tmp, "wb");
23087
+ if (!f2)
23088
+ throw new Error("open for write failed: " + tmp);
23089
+ let w2 = 0;
23090
+ try {
23091
+ const CHUNK = 8 * 1024 * 1024;
23092
+ for (let off = 0; off < bytes.length; off += CHUNK) {
23093
+ const n2 = f2.write(bytes.buffer, off, Math.min(CHUNK, bytes.length - off));
23094
+ if (n2 <= 0)
23095
+ break;
23096
+ w2 += n2;
23097
+ }
23098
+ } finally {
23099
+ f2.close();
23100
+ }
23101
+ if (w2 !== bytes.length)
23102
+ throw new Error("short write: " + w2 + "/" + bytes.length);
23103
+ if (!MoveFileEx(
23104
+ tmp,
23105
+ dest,
23106
+ 1
23107
+ /* MoveFileFlag.REPLACE_EXISTING */
23108
+ ))
23109
+ throw new Error("MoveFileEx failed (GetLastError " + GetLastError() + "): " + tmp + " -> " + dest);
23110
+ } catch (ex) {
23111
+ logReq(t0, "POST /upload", 500, String(ex));
23112
+ return jsonError(500, String(ex));
23113
+ }
23114
+ logReq(t0, "POST /upload", 200, bytes.length + "B -> " + dest);
23115
+ return new Response(JSON.stringify({ bytes: bytes.length, path: dest }), { headers: { "Content-Type": "application/json" } });
23116
+ }
23117
+ if (req.method === "GET" && path === "/download") {
23118
+ const p2 = new URL(req.url).searchParams.get("path");
23119
+ if (!p2) {
23120
+ logReq(t0, "GET /download", 400, "path=<\u6587\u4EF6\u8DEF\u5F84>");
23121
+ return jsonError(400, "path=<\u6587\u4EF6\u8DEF\u5F84>");
23122
+ }
23123
+ let f2 = null;
23124
+ try {
23125
+ f2 = std2.open(p2, "rb");
23126
+ } catch (ex) {
23127
+ logReq(t0, "GET /download", 500, String(ex));
23128
+ return jsonError(500, String(ex));
23129
+ }
23130
+ if (f2 === null) {
23131
+ logReq(t0, "GET /download", 404, p2);
23132
+ return jsonError(404, "cannot open: " + p2);
23133
+ }
23134
+ try {
23135
+ const chunks = [];
23136
+ const buf = new Uint8Array(64 * 1024);
23137
+ let total = 0;
23138
+ for (; ; ) {
23139
+ const n2 = f2.read(buf.buffer, 0, buf.length);
23140
+ if (n2 <= 0)
23141
+ break;
23142
+ chunks.push(n2 === buf.length ? buf.slice() : buf.slice(0, n2));
23143
+ total += n2;
23144
+ }
23145
+ const all = new Uint8Array(total);
23146
+ let off = 0;
23147
+ for (const c2 of chunks) {
23148
+ all.set(c2, off);
23149
+ off += c2.length;
23150
+ }
23151
+ logReq(t0, "GET /download", 200, total + "B <- " + p2);
23152
+ return new Response(all, {
23153
+ headers: { "Content-Type": "application/octet-stream", "X-Bytes": String(total) }
23154
+ });
23155
+ } catch (ex) {
23156
+ logReq(t0, "GET /download", 500, String(ex));
23157
+ return jsonError(500, String(ex));
23158
+ } finally {
23159
+ f2.close();
23160
+ }
23161
+ }
22593
23162
  return usageResponse();
22594
23163
  });
22595
23164
  var rc = server.listen(8080, "0.0.0.0");