quickwin 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.en.md +8 -8
  2. package/README.md +6 -7
  3. package/examples/{exec_server.js → execd.js} +618 -228
  4. package/examples/execd.tsx +798 -0
  5. package/examples/execd_worker.js +122 -0
  6. package/examples/execd_worker.ts +127 -0
  7. package/examples/pdf_viewer.js +100 -111
  8. package/examples/test_gallery.js +100 -111
  9. package/examples/test_react_lazy.js +96 -109
  10. package/examples/test_react_listbox.js +96 -109
  11. package/examples/test_root_window.js +96 -109
  12. package/examples/test_tab.js +96 -109
  13. package/lib/ffi/ctype.ts +3 -1
  14. package/lib/ffi/struct.js +23 -7
  15. package/lib/ffi/struct.ts +50 -23
  16. package/lib/http-server.js +1 -1
  17. package/lib/http-server.ts +1 -1
  18. package/lib/windows/gdi32.js +1 -1
  19. package/lib/windows/gdi32.ts +1 -1
  20. package/lib/windows/structs.js +176 -92
  21. package/lib/windows/structs.ts +216 -92
  22. package/package.json +1 -1
  23. package/quickwin_const.d.ts +26 -0
  24. package/qwin-nowasm-x86.exe +0 -0
  25. package/qwin-nowasm.exe +0 -0
  26. package/qwin-x86.exe +0 -0
  27. package/qwin.exe +0 -0
  28. package/test/test_ffi_bind.js +5 -3
  29. package/test/test_ffi_bind.ts +6 -4
  30. package/test/test_ffi_struct.js +58 -24
  31. package/test/test_ffi_struct.ts +55 -25
  32. package/test/test_gdi_draw.js +1 -1
  33. package/test/test_gdi_draw.ts +1 -1
  34. package/test/test_react_complex.js +96 -109
  35. package/test/test_react_counter.js +96 -109
  36. package/test/test_react_flex.js +96 -109
  37. package/test/test_react_hidden.js +96 -109
  38. package/test/test_react_listview_link.js +96 -109
  39. package/test/test_react_notify.js +96 -109
  40. package/test/test_react_render.js +96 -109
  41. package/examples/exec_server.tsx +0 -489
  42. package/examples/exec_server_worker.js +0 -395
  43. package/examples/exec_server_worker.ts +0 -417
  44. package/examples/setres.js +0 -79
  45. package/examples/setres.ts +0 -86
@@ -15353,7 +15353,7 @@ var require_constants = __commonJS({
15353
15353
  }
15354
15354
  });
15355
15355
 
15356
- // _build/examples/exec_server.js
15356
+ // _build/examples/execd.js
15357
15357
  var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
15358
15358
 
15359
15359
  // _build/lib/polyfill.js
@@ -19044,7 +19044,7 @@ async function sendResponse(c2, method, res) {
19044
19044
  await writeStreamingBody(c2, res.body, chunked, chunked && trailerDeclared ? res.trailers : void 0);
19045
19045
  }
19046
19046
 
19047
- // _build/examples/exec_server.js
19047
+ // _build/examples/execd.js
19048
19048
  import * as os6 from "os";
19049
19049
  import * as std2 from "std";
19050
19050
  import * as gui18 from "gui";
@@ -19466,6 +19466,75 @@ function bind2(dll, name, sig, encoders, decoders) {
19466
19466
  var leakRegistry = new FinalizationRegistry((held) => {
19467
19467
  std.printf('[ffi] closure leaked (GCed without dispose): sig="%s" ptr=0x%x\n', held.sig, held.ptr);
19468
19468
  });
19469
+ function dispatchClosure(args, ret, fn, frameBuf, retBuf, sig) {
19470
+ const dv = new DataView(retBuf);
19471
+ const is64 = os3.arch === "x64";
19472
+ const fv = new DataView(frameBuf);
19473
+ const a2 = [];
19474
+ let off = 0;
19475
+ for (let i2 = 0; i2 < args.length; i2++) {
19476
+ const spec = args[i2];
19477
+ const k2 = spec.tok;
19478
+ let v2;
19479
+ if (is64) {
19480
+ const fp = k2 === "f32" || k2 === "f64";
19481
+ const base = fp ? i2 < 4 ? 128 + i2 * 8 : 32 + (i2 - 4) * 8 : i2 < 4 ? i2 * 8 : 32 + (i2 - 4) * 8;
19482
+ v2 = readScalar(fv, base, k2);
19483
+ } else {
19484
+ v2 = readScalar(fv, off, k2);
19485
+ off += IA32_ARG_SIZE[k2];
19486
+ }
19487
+ if (spec.nonnull && v2 === 0) {
19488
+ std.printf("[ffi] closure %s: arg#%d got 0 (! promise violated by caller), skipping callback\n", sig, i2 + 1);
19489
+ return;
19490
+ }
19491
+ a2.push(v2);
19492
+ }
19493
+ let r2;
19494
+ try {
19495
+ r2 = fn(...a2);
19496
+ } catch (err) {
19497
+ std.printf("[ffi] closure callback threw: %s\n", String(err));
19498
+ return;
19499
+ }
19500
+ if (ret.nonnull && r2 === 0) {
19501
+ std.printf("[ffi] closure %s: return got 0 (! promise violated by callback), leaving result slot 0\n", sig);
19502
+ return;
19503
+ }
19504
+ if (ret.tok !== "void") {
19505
+ writeSlot(dv, 0, { k: ret.tok, v: r2 });
19506
+ }
19507
+ }
19508
+ function closure(sig, fn, opts) {
19509
+ const { argTokens, retToken } = parseSig(sig);
19510
+ for (const t2 of argTokens)
19511
+ if (isCValToken(t2))
19512
+ throw new Error(`ffi-bind: closure signature cannot take a by-value struct (<${valName(t2)}>); by-value is bind-only \u2014 the C\u2192JS direction has no struct slot decoding (pass a pointer and decode on the JS side)`);
19513
+ const argSpecs = argTokens.map((t2) => ({ tok: cTokenToType(t2), nonnull: t2.endsWith("!") }));
19514
+ const retSpec = { tok: cTokenToType(retToken), nonnull: retToken.endsWith("!") };
19515
+ const is64 = os3.arch === "x64";
19516
+ const stackCapture = argSpecs.reduce((s2, x2) => s2 + IA32_ARG_SIZE[x2.tok], 0);
19517
+ if (is64 ? argSpecs.length > 16 : stackCapture > 64) {
19518
+ throw new Error(`ffi-bind: closure signature exceeds capture window (${is64 ? "max 16 params" : "max 64 stack bytes"}): ${sig}`);
19519
+ }
19520
+ const argBytes = opts?.stdcall === false || is64 ? 0 : stackCapture;
19521
+ const retKind = retSpec.tok === "f32" ? 1 : retSpec.tok === "f64" ? 2 : retSpec.tok === "u64" || retSpec.tok === "i64" ? 3 : 0;
19522
+ const wrapper = (frameBuf, retBuf) => {
19523
+ dispatchClosure(argSpecs, retSpec, fn, frameBuf, retBuf, sig);
19524
+ };
19525
+ const ptr = ffi.closureNew(argBytes, retKind, wrapper);
19526
+ let done = false;
19527
+ const dispose = () => {
19528
+ if (done)
19529
+ return;
19530
+ done = true;
19531
+ leakRegistry.unregister(dispose);
19532
+ ffi.closureFree(ptr);
19533
+ };
19534
+ const ret = { ptr, dispose };
19535
+ leakRegistry.register(dispose, { sig, ptr });
19536
+ return ret;
19537
+ }
19469
19538
 
19470
19539
  // _build/lib/ffi/struct.js
19471
19540
  import * as ffi2 from "ffi";
@@ -19774,7 +19843,7 @@ function doEncode(dv, base, fields, v2) {
19774
19843
  function createStruct(t2) {
19775
19844
  const { fields, size, maxEffectiveAlign } = computeStructLayout(t2);
19776
19845
  return {
19777
- __struct: t2,
19846
+ fields,
19778
19847
  size,
19779
19848
  structAlign: maxEffectiveAlign,
19780
19849
  decode: (p2) => {
@@ -19803,6 +19872,14 @@ function createStruct(t2) {
19803
19872
  };
19804
19873
  }
19805
19874
  function buildDecl(kind, member, pack) {
19875
+ const declKind = member["#"];
19876
+ if (declKind !== void 0 && declKind !== kind)
19877
+ throw new Error(`ffi-struct: ${kind}() received a '${String(declKind)}' declaration (kind mismatch \u2014 use ${declKind}() for it)`);
19878
+ const declPack = member["#pack"];
19879
+ if (pack === void 0 && declPack !== void 0)
19880
+ pack = declPack;
19881
+ else if (pack !== void 0 && declPack !== void 0 && pack !== declPack)
19882
+ throw new Error(`ffi-struct: #pack conflict: opts.pack=${pack} vs declaration ${String(declPack)}`);
19806
19883
  const decl = { "#": kind };
19807
19884
  if (pack !== void 0)
19808
19885
  decl["#pack"] = pack;
@@ -19811,49 +19888,6 @@ function buildDecl(kind, member, pack) {
19811
19888
  decl[k2] = v2;
19812
19889
  return decl;
19813
19890
  }
19814
- function structArray(def) {
19815
- const { fields, size } = computeStructLayout(def.__struct);
19816
- const readN = (dv, n2) => {
19817
- const out = [];
19818
- for (let i2 = 0; i2 < n2; i2++)
19819
- out.push(doDecode(dv, i2 * size, fields));
19820
- return out;
19821
- };
19822
- return {
19823
- encode: (els) => {
19824
- if (!Array.isArray(els) || els.length === 0)
19825
- throw new Error(`ffi-struct: structArray(def).encode(els) requires a non-empty element array (pass NULL for an empty pointer position)`);
19826
- const out = def.alloc(els.length);
19827
- for (let i2 = 0; i2 < els.length; i2++)
19828
- def.encode(els[i2], out, i2 * def.size);
19829
- return out;
19830
- },
19831
- decode: ((p2, count) => {
19832
- if (count !== void 0 && (!Number.isInteger(count) || count < 0))
19833
- throw new Error(`ffi-struct: structArray.decode(p, count) requires a non-negative integer count, got ${count}`);
19834
- if (typeof p2 === "number") {
19835
- if (count === void 0)
19836
- throw new Error(`ffi-struct: structArray.decode(address, count) requires an explicit count (a bare address carries no length)`);
19837
- if (count === 0)
19838
- return [];
19839
- return readN(new DataView(ffi2.readBytes(p2, count * size)), count);
19840
- }
19841
- let n2;
19842
- if (count !== void 0) {
19843
- n2 = count;
19844
- if (n2 * size > p2.byteLength)
19845
- throw new Error(`ffi-struct: structArray.decode: count ${n2} \xD7 size ${size} = ${n2 * size} exceeds buffer byteLength ${p2.byteLength}`);
19846
- } else {
19847
- if (p2.byteLength % size !== 0)
19848
- throw new Error(`ffi-struct: structArray.decode: byteLength ${p2.byteLength} is not a multiple of size ${size} (mixed buffer? pass count explicitly)`);
19849
- n2 = p2.byteLength / size;
19850
- }
19851
- if (n2 === 0)
19852
- return [];
19853
- return readN(new DataView(p2), n2);
19854
- })
19855
- };
19856
- }
19857
19891
  function struct(a2, b7, c2) {
19858
19892
  const isNamed = typeof a2 === "string";
19859
19893
  const raw = isNamed ? b7 : a2;
@@ -19862,21 +19896,28 @@ function struct(a2, b7, c2) {
19862
19896
  }
19863
19897
 
19864
19898
  // _build/lib/windows/structs.js
19865
- var RECT = /* @__PURE__ */ struct("RECT", {
19899
+ var RECT_DECL = {
19900
+ "#": "struct",
19866
19901
  left: "i32",
19867
19902
  top: "i32",
19868
19903
  right: "i32",
19869
19904
  bottom: "i32"
19870
- });
19871
- var POINT = /* @__PURE__ */ struct("POINT", {
19905
+ };
19906
+ var RECT = /* @__PURE__ */ struct("RECT", RECT_DECL);
19907
+ var POINT_DECL = {
19908
+ "#": "struct",
19872
19909
  x: "i32",
19873
19910
  y: "i32"
19874
- });
19875
- var SIZE = /* @__PURE__ */ struct("SIZE", {
19911
+ };
19912
+ var POINT = /* @__PURE__ */ struct("POINT", POINT_DECL);
19913
+ var SIZE_DECL = {
19914
+ "#": "struct",
19876
19915
  cx: "i32",
19877
19916
  cy: "i32"
19878
- });
19879
- var LOGFONTW = /* @__PURE__ */ struct("LOGFONTW", {
19917
+ };
19918
+ var SIZE = /* @__PURE__ */ struct("SIZE", SIZE_DECL);
19919
+ var LOGFONTW_DECL = {
19920
+ "#": "struct",
19880
19921
  lfHeight: "i32",
19881
19922
  lfWidth: "i32",
19882
19923
  lfEscapement: "i32",
@@ -19891,8 +19932,35 @@ var LOGFONTW = /* @__PURE__ */ struct("LOGFONTW", {
19891
19932
  lfQuality: "u8",
19892
19933
  lfPitchAndFamily: "u8",
19893
19934
  lfFaceName: "u16[32]@utf-16le"
19894
- });
19895
- var OPENFILENAMEW = /* @__PURE__ */ struct("OPENFILENAMEW", {
19935
+ };
19936
+ var LOGFONTW = /* @__PURE__ */ struct("LOGFONTW", LOGFONTW_DECL);
19937
+ var BITMAPINFOHEADER_DECL = {
19938
+ "#": "struct",
19939
+ biSize: "u32",
19940
+ biWidth: "i32",
19941
+ biHeight: "i32",
19942
+ biPlanes: "u16",
19943
+ biBitCount: "u16",
19944
+ biCompression: "u32",
19945
+ biSizeImage: "u32",
19946
+ biXPelsPerMeter: "i32",
19947
+ biYPelsPerMeter: "i32",
19948
+ biClrUsed: "u32",
19949
+ biClrImportant: "u32"
19950
+ };
19951
+ var BITMAPINFOHEADER = /* @__PURE__ */ struct("BITMAPINFOHEADER", BITMAPINFOHEADER_DECL);
19952
+ var BITMAPFILEHEADER_DECL = {
19953
+ "#": "struct",
19954
+ "#pack": 2,
19955
+ bfType: "u16",
19956
+ bfSize: "u32",
19957
+ bfReserved1: "u16",
19958
+ bfReserved2: "u16",
19959
+ bfOffBits: "u32"
19960
+ };
19961
+ var BITMAPFILEHEADER = /* @__PURE__ */ struct("BITMAPFILEHEADER", BITMAPFILEHEADER_DECL);
19962
+ var OPENFILENAMEW_DECL = {
19963
+ "#": "struct",
19896
19964
  lStructSize: "u32",
19897
19965
  hwndOwner: "<HWND>ptr",
19898
19966
  hInstance: "<HMODULE>ptr",
@@ -19916,8 +19984,10 @@ var OPENFILENAMEW = /* @__PURE__ */ struct("OPENFILENAMEW", {
19916
19984
  pvReserved: "<>ptr",
19917
19985
  dwReserved: "u32",
19918
19986
  FlagsEx: "u32"
19919
- });
19920
- var BROWSEINFOW = /* @__PURE__ */ struct("BROWSEINFOW", {
19987
+ };
19988
+ var OPENFILENAMEW = /* @__PURE__ */ struct("OPENFILENAMEW", OPENFILENAMEW_DECL);
19989
+ var BROWSEINFOW_DECL = {
19990
+ "#": "struct",
19921
19991
  hwndOwner: "<HWND>ptr",
19922
19992
  pidlRoot: "<>ptr",
19923
19993
  pszDisplayName: "<>ptr",
@@ -19926,13 +19996,17 @@ var BROWSEINFOW = /* @__PURE__ */ struct("BROWSEINFOW", {
19926
19996
  lpfn: "<>ptr",
19927
19997
  lParam: "<>ptr",
19928
19998
  iImage: "i32"
19929
- });
19930
- var NMHDR = /* @__PURE__ */ struct("NMHDR", {
19999
+ };
20000
+ var BROWSEINFOW = /* @__PURE__ */ struct("BROWSEINFOW", BROWSEINFOW_DECL);
20001
+ var NMHDR_DECL = {
20002
+ "#": "struct",
19931
20003
  hwndFrom: "<HWND>ptr",
19932
20004
  idFrom: "<>ptr",
19933
20005
  code: "i32"
19934
- });
19935
- var SYSTEMTIME = /* @__PURE__ */ struct("SYSTEMTIME", {
20006
+ };
20007
+ var NMHDR = /* @__PURE__ */ struct("NMHDR", NMHDR_DECL);
20008
+ var SYSTEMTIME_DECL = {
20009
+ "#": "struct",
19936
20010
  wYear: "u16",
19937
20011
  wMonth: "u16",
19938
20012
  wDayOfWeek: "u16",
@@ -19941,35 +20015,44 @@ var SYSTEMTIME = /* @__PURE__ */ struct("SYSTEMTIME", {
19941
20015
  wMinute: "u16",
19942
20016
  wSecond: "u16",
19943
20017
  wMilliseconds: "u16"
19944
- });
19945
- var NMDATETIMECHANGE = /* @__PURE__ */ struct("NMDATETIMECHANGE", {
19946
- hdr: NMHDR.__struct,
20018
+ };
20019
+ var SYSTEMTIME = /* @__PURE__ */ struct("SYSTEMTIME", SYSTEMTIME_DECL);
20020
+ var NMDATETIMECHANGE_DECL = {
20021
+ "#": "struct",
20022
+ hdr: NMHDR_DECL,
19947
20023
  dwFlags: "u32",
19948
- st: SYSTEMTIME.__struct
19949
- });
19950
- var LITEM = /* @__PURE__ */ struct("LITEM", {
20024
+ st: SYSTEMTIME_DECL
20025
+ };
20026
+ var NMDATETIMECHANGE = /* @__PURE__ */ struct("NMDATETIMECHANGE", NMDATETIMECHANGE_DECL);
20027
+ var LITEM_DECL = {
20028
+ "#": "struct",
19951
20029
  mask: "u32",
19952
20030
  iLink: "i32",
19953
20031
  state: "u32",
19954
20032
  stateMask: "u32",
19955
20033
  szID: "u16[48]@utf-16le",
19956
20034
  szUrl: "u16[2084]@utf-16le"
19957
- });
19958
- var NMLINK = /* @__PURE__ */ struct("NMLINK", {
19959
- hdr: NMHDR.__struct,
19960
- item: LITEM.__struct
19961
- });
19962
- var NMCUSTOMDRAW = /* @__PURE__ */ struct("NMCUSTOMDRAW", {
19963
- hdr: NMHDR.__struct,
20035
+ };
20036
+ var NMLINK_DECL = {
20037
+ "#": "struct",
20038
+ hdr: NMHDR_DECL,
20039
+ item: LITEM_DECL
20040
+ };
20041
+ var NMLINK = /* @__PURE__ */ struct("NMLINK", NMLINK_DECL);
20042
+ var NMCUSTOMDRAW_DECL = {
20043
+ "#": "struct",
20044
+ hdr: NMHDR_DECL,
19964
20045
  dwDrawStage: "u32",
19965
20046
  hdc: "<HDC>ptr",
19966
20047
  rc: "i32[4]",
19967
20048
  dwItemSpec: "<>ptr",
19968
20049
  uItemState: "u32",
19969
20050
  lItemlParam: "<>ptr"
19970
- });
19971
- var NMLVCUSTOMDRAW = /* @__PURE__ */ struct("NMLVCUSTOMDRAW", {
19972
- hdr: NMHDR.__struct,
20051
+ };
20052
+ var NMCUSTOMDRAW = /* @__PURE__ */ struct("NMCUSTOMDRAW", NMCUSTOMDRAW_DECL);
20053
+ var NMLVCUSTOMDRAW_DECL = {
20054
+ "#": "struct",
20055
+ hdr: NMHDR_DECL,
19973
20056
  dwDrawStage: "u32",
19974
20057
  hdc: "<HDC>ptr",
19975
20058
  rc: "i32[4]",
@@ -19980,9 +20063,11 @@ var NMLVCUSTOMDRAW = /* @__PURE__ */ struct("NMLVCUSTOMDRAW", {
19980
20063
  clrTextBk: "u32",
19981
20064
  iSubItem: "i32",
19982
20065
  dwItemType: "u32"
19983
- });
19984
- var NMLISTVIEW = /* @__PURE__ */ struct("NMLISTVIEW", {
19985
- hdr: NMHDR.__struct,
20066
+ };
20067
+ var NMLVCUSTOMDRAW = /* @__PURE__ */ struct("NMLVCUSTOMDRAW", NMLVCUSTOMDRAW_DECL);
20068
+ var NMLISTVIEW_DECL = {
20069
+ "#": "struct",
20070
+ hdr: NMHDR_DECL,
19986
20071
  iItem: "i32",
19987
20072
  iSubItem: "i32",
19988
20073
  uNewState: "u32",
@@ -19990,8 +20075,10 @@ var NMLISTVIEW = /* @__PURE__ */ struct("NMLISTVIEW", {
19990
20075
  uChanged: "u32",
19991
20076
  ptAction: "i32[2]",
19992
20077
  lParam: "<>ptr"
19993
- });
19994
- var TCITEMW = /* @__PURE__ */ struct("TCITEMW", {
20078
+ };
20079
+ var NMLISTVIEW = /* @__PURE__ */ struct("NMLISTVIEW", NMLISTVIEW_DECL);
20080
+ var TCITEMW_DECL = {
20081
+ "#": "struct",
19995
20082
  mask: "u32",
19996
20083
  dwState: "u32",
19997
20084
  dwStateMask: "u32",
@@ -19999,8 +20086,10 @@ var TCITEMW = /* @__PURE__ */ struct("TCITEMW", {
19999
20086
  cchTextMax: "i32",
20000
20087
  iImage: "i32",
20001
20088
  lParam: "<>ptr"
20002
- });
20003
- var TVITEM = /* @__PURE__ */ struct("TVITEM", {
20089
+ };
20090
+ var TCITEMW = /* @__PURE__ */ struct("TCITEMW", TCITEMW_DECL);
20091
+ var TVITEM_DECL = {
20092
+ "#": "struct",
20004
20093
  mask: "u32",
20005
20094
  hItem: "<>ptr",
20006
20095
  state: "u32",
@@ -20011,20 +20100,26 @@ var TVITEM = /* @__PURE__ */ struct("TVITEM", {
20011
20100
  iSelectedImage: "i32",
20012
20101
  cChildren: "i32",
20013
20102
  lParam: "<>ptr"
20014
- });
20015
- var TVINSERTSTRUCT = /* @__PURE__ */ struct("TVINSERTSTRUCT", {
20103
+ };
20104
+ var TVITEM = /* @__PURE__ */ struct("TVITEM", TVITEM_DECL);
20105
+ var TVINSERTSTRUCT_DECL = {
20106
+ "#": "struct",
20016
20107
  hParent: "<>ptr",
20017
20108
  hInsertAfter: "<>ptr",
20018
- item: TVITEM.__struct
20019
- });
20020
- var LVHITTESTINFO = /* @__PURE__ */ struct("LVHITTESTINFO", {
20109
+ item: TVITEM_DECL
20110
+ };
20111
+ var TVINSERTSTRUCT = /* @__PURE__ */ struct("TVINSERTSTRUCT", TVINSERTSTRUCT_DECL);
20112
+ var LVHITTESTINFO_DECL = {
20113
+ "#": "struct",
20021
20114
  pt: "i32[2]",
20022
20115
  flags: "u32",
20023
20116
  iItem: "i32",
20024
20117
  iSubItem: "i32",
20025
20118
  iGroup: "i32"
20026
- });
20027
- var LVITEMW = /* @__PURE__ */ struct("LVITEMW", {
20119
+ };
20120
+ var LVHITTESTINFO = /* @__PURE__ */ struct("LVHITTESTINFO", LVHITTESTINFO_DECL);
20121
+ var LVITEMW_DECL = {
20122
+ "#": "struct",
20028
20123
  mask: "u32",
20029
20124
  iItem: "i32",
20030
20125
  iSubItem: "i32",
@@ -20040,8 +20135,10 @@ var LVITEMW = /* @__PURE__ */ struct("LVITEMW", {
20040
20135
  puColumns: "<>ptr",
20041
20136
  piColFmt: "<>ptr",
20042
20137
  iGroup: "i32"
20043
- });
20044
- var LVCOLUMNW = /* @__PURE__ */ struct("LVCOLUMNW", {
20138
+ };
20139
+ var LVITEMW = /* @__PURE__ */ struct("LVITEMW", LVITEMW_DECL);
20140
+ var LVCOLUMNW_DECL = {
20141
+ "#": "struct",
20045
20142
  mask: "u32",
20046
20143
  fmt: "i32",
20047
20144
  cx: "i32",
@@ -20053,30 +20150,54 @@ var LVCOLUMNW = /* @__PURE__ */ struct("LVCOLUMNW", {
20053
20150
  cxMin: "i32",
20054
20151
  cxDefault: "i32",
20055
20152
  cxIdeal: "i32"
20056
- });
20057
- var MSG = /* @__PURE__ */ struct("MSG", {
20058
- hwnd: "<HWND>ptr",
20059
- message: "u32",
20060
- wParam: "<>ptr",
20061
- lParam: "<>ptr",
20062
- time: "u32",
20063
- pt: POINT.__struct
20064
- });
20065
- var PAINTSTRUCT = /* @__PURE__ */ struct("PAINTSTRUCT", {
20066
- hdc: "<HDC>ptr",
20067
- fErase: "i32",
20068
- rcPaint: RECT.__struct,
20069
- fRestore: "i32",
20070
- fIncUpdate: "i32",
20071
- rgbReserved: "u8[32]"
20072
- });
20153
+ };
20154
+ var LVCOLUMNW = /* @__PURE__ */ struct("LVCOLUMNW", LVCOLUMNW_DECL);
20155
+ var DEVMODEW_DECL = {
20156
+ "#": "struct",
20157
+ dmDeviceName: "u16[32]@utf-16le",
20158
+ dmSpecVersion: "u16",
20159
+ dmDriverVersion: "u16",
20160
+ dmSize: "u16",
20161
+ dmDriverExtra: "u16",
20162
+ dmFields: "u32",
20163
+ dmPosition: "i32[2]",
20164
+ dmDisplayOrientation: "u32",
20165
+ dmDisplayFixedOutput: "u32",
20166
+ dmColor: "i16",
20167
+ dmDuplex: "i16",
20168
+ dmYResolution: "i16",
20169
+ dmTTOption: "i16",
20170
+ dmCollate: "i16",
20171
+ dmFormName: "u16[32]@utf-16le",
20172
+ dmLogPixels: "u16",
20173
+ dmBitsPerPel: "u32",
20174
+ dmPelsWidth: "u32",
20175
+ dmPelsHeight: "u32",
20176
+ dmDisplayFlags: "u32",
20177
+ dmDisplayFrequency: "u32",
20178
+ dmICMMethod: "u32",
20179
+ dmICMIntent: "u32",
20180
+ dmMediaType: "u32",
20181
+ dmDitherType: "u32",
20182
+ dmReserved1: "u32",
20183
+ dmReserved2: "u32",
20184
+ dmPanningWidth: "u32",
20185
+ dmPanningHeight: "u32"
20186
+ };
20187
+ var DEVMODEW = /* @__PURE__ */ struct("DEVMODEW", DEVMODEW_DECL);
20073
20188
 
20074
20189
  // _build/lib/windows/user32.js
20075
20190
  var b2 = (name, sig, encoders) => bind2("user32.dll", name, sig, encoders);
20076
20191
  var _bProbe = b2("GetDesktopWindow", " -> <HWND>ptr");
20077
20192
  var LONG_PTR_SYM = os4.arch === "x64" ? "PtrW" : "W";
20078
20193
  var SetWindowPos = /* @__PURE__ */ b2("SetWindowPos", "<HWND>ptr <>ptr@SetWindowPosHwnd i32 i32 i32 i32 u32 -> i32");
20194
+ var GetWindowRect = /* @__PURE__ */ b2("GetWindowRect", "<HWND>ptr <RECT>ptr -> i32");
20195
+ var GetClientRect = /* @__PURE__ */ b2("GetClientRect", "<HWND>ptr <RECT>ptr -> i32");
20196
+ var IsWindowVisible = /* @__PURE__ */ b2("IsWindowVisible", "<HWND>ptr -> i32");
20197
+ var IsIconic = /* @__PURE__ */ b2("IsIconic", "<HWND>ptr -> i32");
20198
+ var GetWindowText = /* @__PURE__ */ b2("GetWindowTextW", "<HWND>ptr <BYTE>ptr i32 -> i32");
20079
20199
  var SetWindowText = /* @__PURE__ */ b2("SetWindowTextW", "<HWND>ptr <WCHAR>ptr -> i32");
20200
+ var GetClassName = /* @__PURE__ */ b2("GetClassNameW", "<HWND>ptr <BYTE>ptr i32 -> i32");
20080
20201
  var GetWindowLongPtr = /* @__PURE__ */ b2("GetWindowLong" + LONG_PTR_SYM, "<HWND>ptr i32@Gwlp -> <>ptr");
20081
20202
  var SetWindowLongPtr = /* @__PURE__ */ b2("SetWindowLong" + LONG_PTR_SYM, "<HWND>ptr i32@Gwlp <>ptr -> <>ptr");
20082
20203
  var EnableWindow = /* @__PURE__ */ b2("EnableWindow", "<HWND>ptr i32 -> i32");
@@ -20085,14 +20206,19 @@ var DefWindowProc = /* @__PURE__ */ b2("DefWindowProcW", "<HWND>ptr u32@AnyMsg <
20085
20206
  var CallWindowProc = /* @__PURE__ */ b2("CallWindowProcW", "<>ptr <HWND>ptr u32@AnyMsg <>ptr <>ptr -> <>ptr");
20086
20207
  var GetDC = /* @__PURE__ */ b2("GetDC", "<HWND>ptr -> <HDC>ptr");
20087
20208
  var ReleaseDC = /* @__PURE__ */ b2("ReleaseDC", "<HWND>ptr <HDC>ptr! -> i32");
20209
+ var PrintWindow = /* @__PURE__ */ b2("PrintWindow", "<HWND>ptr <HDC>ptr! u32 -> i32");
20088
20210
  var DrawText = /* @__PURE__ */ b2("DrawTextW", "<HDC>ptr! <WCHAR>ptr i32 <RECT>ptr i32 -> i32");
20089
20211
  var InvalidateRect = /* @__PURE__ */ b2("InvalidateRect", "<HWND>ptr <RECT>ptr i32 -> i32", { RECT });
20090
20212
  var SetCursor = /* @__PURE__ */ b2("SetCursor", "<HCURSOR>ptr -> <HCURSOR>ptr");
20091
20213
  var LoadCursor = /* @__PURE__ */ b2("LoadCursorW", "<HMODULE>ptr <>ptr -> <HCURSOR>ptr");
20092
20214
  var GetCursorPos = /* @__PURE__ */ b2("GetCursorPos", "<POINT>ptr -> i32");
20093
20215
  var ScreenToClient = /* @__PURE__ */ b2("ScreenToClient", "<HWND>ptr <POINT>ptr -> i32");
20216
+ var ClientToScreen = /* @__PURE__ */ b2("ClientToScreen", "<HWND>ptr <POINT>ptr -> i32");
20094
20217
  var ShowScrollBar = /* @__PURE__ */ b2("ShowScrollBar", "<HWND>ptr u32 i32 -> i32");
20095
20218
  var GetSystemMetrics = /* @__PURE__ */ b2("GetSystemMetrics", "i32 -> i32");
20219
+ var EnumWindows = /* @__PURE__ */ b2("EnumWindows", "<>ptr <>ptr -> i32");
20220
+ var EnumDisplaySettings = /* @__PURE__ */ b2("EnumDisplaySettingsW", "<WCHAR>ptr u32 <DEVMODEW>ptr -> i32");
20221
+ var ChangeDisplaySettings = /* @__PURE__ */ b2("ChangeDisplaySettingsW", "<DEVMODEW>ptr u32 -> i32");
20096
20222
 
20097
20223
  // _build/lib/react-qw/reconciler.js
20098
20224
  var import_react_reconciler = __toESM(require_react_reconciler(), 1);
@@ -20103,12 +20229,16 @@ import * as os5 from "os";
20103
20229
 
20104
20230
  // _build/lib/windows/gdi32.js
20105
20231
  var b3 = (name, sig, encoders) => bind2("gdi32.dll", name, sig, encoders);
20106
- var POINTArr = structArray(POINT);
20107
20232
  var DeleteObject = /* @__PURE__ */ b3("DeleteObject", "<HGDIOBJ>ptr -> i32");
20108
20233
  var GetDeviceCaps = /* @__PURE__ */ b3("GetDeviceCaps", "<HDC>ptr! i32@DeviceCap -> i32");
20109
20234
  var CreateFontIndirect = /* @__PURE__ */ b3("CreateFontIndirectW", "<LOGFONTW>ptr -> <HGDIOBJ>ptr", { LOGFONTW });
20235
+ var CreateCompatibleDC = /* @__PURE__ */ b3("CreateCompatibleDC", "<HDC>ptr -> <HDC>ptr");
20236
+ var CreateCompatibleBitmap = /* @__PURE__ */ b3("CreateCompatibleBitmap", "<HDC>ptr! i32 i32 -> <HGDIOBJ>ptr");
20110
20237
  var SelectObject = /* @__PURE__ */ b3("SelectObject", "<HDC>ptr! <HGDIOBJ>ptr -> <HGDIOBJ>ptr");
20238
+ var BitBlt = /* @__PURE__ */ b3("BitBlt", "<HDC>ptr! i32 i32 i32 i32 <HDC>ptr i32 i32 u32@RasterOp -> i32");
20239
+ var GetDIBits = /* @__PURE__ */ b3("GetDIBits", "<HDC>ptr! <HGDIOBJ>ptr u32 u32 <BYTE>ptr <>ptr u32 -> i32");
20111
20240
  var GetObject = /* @__PURE__ */ b3("GetObjectW", "<HGDIOBJ>ptr i32 <BYTE>ptr -> i32");
20241
+ var DeleteDC = /* @__PURE__ */ b3("DeleteDC", "<HDC>ptr! -> i32");
20112
20242
 
20113
20243
  // _build/lib/react-qw/props.js
20114
20244
  import * as gui from "gui";
@@ -21798,21 +21928,25 @@ function createRoot(container) {
21798
21928
  };
21799
21929
  }
21800
21930
 
21801
- // _build/examples/exec_server.js
21931
+ // _build/examples/execd.js
21802
21932
  var import_react18 = __toESM(require_react(), 1);
21803
21933
  function parseArgs() {
21804
21934
  let gui19 = true;
21805
21935
  let token = null;
21806
21936
  const args = typeof scriptArgs === "undefined" ? [] : scriptArgs;
21937
+ const normToken2 = (v2) => v2 === "" ? null : v2;
21807
21938
  for (let i2 = 0; i2 < args.length; i2++) {
21808
21939
  const a2 = args[i2] ?? "";
21809
21940
  if (a2 === "--nogui") {
21810
21941
  gui19 = false;
21942
+ } else if (a2 === "--gui") {
21943
+ gui19 = (args[++i2] ?? "") !== "0";
21811
21944
  } else if (a2.startsWith("--gui=")) {
21812
21945
  gui19 = a2.slice(6) !== "0";
21946
+ } else if (a2 === "--token") {
21947
+ token = normToken2(args[++i2] ?? "");
21813
21948
  } else if (a2.startsWith("--token=")) {
21814
- const v2 = a2.slice(8);
21815
- token = v2 === "" ? null : v2;
21949
+ token = normToken2(a2.slice(8));
21816
21950
  }
21817
21951
  }
21818
21952
  return { gui: gui19, token };
@@ -21836,8 +21970,6 @@ function formatLine(e2) {
21836
21970
  res = e2.exit === null ? "ok" : e2.exit === 0 ? "exit 0" : "exit " + e2.exit;
21837
21971
  } else if (e2.status === 401) {
21838
21972
  res = "unauthorized";
21839
- } else if (e2.status === 404) {
21840
- res = "404";
21841
21973
  } else if (e2.status === 504) {
21842
21974
  res = "timeout";
21843
21975
  } else {
@@ -21862,6 +21994,9 @@ function appendLog(e2) {
21862
21994
  log.push(e2);
21863
21995
  refreshGui();
21864
21996
  }
21997
+ function logReq(t0, cmd, status, note, exit = null) {
21998
+ appendLog({ ts: Date.now() / 1e3, cmd, status, exit, durMs: Date.now() - t0, note });
21999
+ }
21865
22000
  function bumpWorkers(d2) {
21866
22001
  activeWorkers += d2;
21867
22002
  refreshGui();
@@ -21871,7 +22006,7 @@ function initGui() {
21871
22006
  return;
21872
22007
  try {
21873
22008
  const root = createRoot({
21874
- text: "exec_server \xB7 :" + (boundPort || 8080),
22009
+ text: "execd \xB7 :" + (boundPort || 8080),
21875
22010
  x: 200,
21876
22011
  y: 200,
21877
22012
  width: 560,
@@ -21884,7 +22019,7 @@ function initGui() {
21884
22019
  /* gui.ShowWindowCmd.RESTORE */
21885
22020
  );
21886
22021
  } catch (ex) {
21887
- console.error("[exec_server] gui init failed (fallback headless):", ex);
22022
+ console.error("[execd] gui init failed (fallback headless):", ex);
21888
22023
  }
21889
22024
  }
21890
22025
  function LogPanel() {
@@ -21910,7 +22045,7 @@ function authCheck(req) {
21910
22045
  }
21911
22046
  function runInWorker(cmd, signal, timeoutMs) {
21912
22047
  const spawnCmd = cmd;
21913
- const worker = new os6.Worker("data:text/javascript;base64,aW1wb3J0KmFzIGZlIGZyb20ib3MiO2ltcG9ydCphcyB4ZSBmcm9tInN0ZCI7aW1wb3J0KmFzIHkgZnJvbSJmZmkiO2ltcG9ydCphcyBldCBmcm9tIm9zIjtpbXBvcnQqYXMgSyBmcm9tInN0ZCI7aW1wb3J0KmFzIHJ0IGZyb20id2luIjt2YXIgZ2U9eyJ1dGYtOCI6InV0Zi04Iix1dGY4OiJ1dGYtOCIsInVuaWNvZGUtMS0xLXV0Zi04IjoidXRmLTgiLCJ1dGYtMTYiOiJ1dGYtMTZsZSIsInV0Zi0xNmxlIjoidXRmLTE2bGUiLCJ1dGYtMTZiZSI6InV0Zi0xNmJlIn07ZnVuY3Rpb24gT3QodCl7aWYoIXQpcmV0dXJuInV0Zi04IjtsZXQgZT1nZVt0LnRyaW0oKS50b0xvd2VyQ2FzZSgpXTtpZihlKXJldHVybiBlO3Rocm93IG5ldyBSYW5nZUVycm9yKGBUaGUgZW5jb2RpbmcgbGFiZWwgIiR7dH0iIGlzIG5vdCBzdXBwb3J0ZWRgKX1mdW5jdGlvbiBEZSh0LGUpe2xldCByPSIiO2ZvcihsZXQgbz0wO288dC5sZW5ndGg7KXtsZXQgbj10W28rK107aWYobjwxMjgpe3IrPVN0cmluZy5mcm9tQ2hhckNvZGUobik7Y29udGludWV9aWYobjwxOTIpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigidW5leHBlY3RlZCBjb250aW51YXRpb24gYnl0ZSIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1sZXQgaSxjO2lmKG48MjI0KXtpZihvPj10Lmxlbmd0aCl7cis9ZT8oKCk9Pnt0aHJvdyBuZXcgVHlwZUVycm9yKCJpbmNvbXBsZXRlIHV0Zi04Iil9KSgpOiJcdUZGRkQiO2JyZWFrfWxldCBzPXRbbysrXTtpZigocyYxOTIpIT09MTI4KXtyKz0iXHVGRkZEIjtjb250aW51ZX1pPShuJjMxKTw8NnxzJjYzLGM9MTI4fWVsc2UgaWYobjwyNDApe2lmKG8rMT49dC5sZW5ndGgpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW5jb21wbGV0ZSB1dGYtOCIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz10W28rK10scD10W28rK107aWYoKHMmMTkyKSE9PTEyOHx8KHAmMTkyKSE9PTEyOCl7cis9Ilx1RkZGRCI7Y29udGludWV9aT0obiYxNSk8PDEyfChzJjYzKTw8NnxwJjYzLGM9MjA0OH1lbHNlIGlmKG48MjQ4KXtpZihvKzI+PXQubGVuZ3RoKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImluY29tcGxldGUgdXRmLTgiKX0pKCk6Ilx1RkZGRCI7YnJlYWt9bGV0IHM9dFtvKytdLHA9dFtvKytdLGE9dFtvKytdO2lmKChzJjE5MikhPT0xMjh8fChwJjE5MikhPT0xMjh8fChhJjE5MikhPT0xMjgpe3IrPSJcdUZGRkQiO2NvbnRpbnVlfWk9KG4mNyk8PDE4fChzJjYzKTw8MTJ8KHAmNjMpPDw2fGEmNjMsYz02NTUzNn1lbHNle3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCB1dGYtOCBzdGFydCIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1pZihpPGN8fGk+PTU1Mjk2JiZpPD01NzM0M3x8aT4xMTE0MTExKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImludmFsaWQgdXRmLTggY29kZXBvaW50Iil9KSgpOiJcdUZGRkQiO2NvbnRpbnVlfWk8PTY1NTM1P3IrPVN0cmluZy5mcm9tQ2hhckNvZGUoaSk6KGktPTY1NTM2LHIrPVN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTZ8aT4+MTAsNTYzMjB8aSYxMDIzKSl9cmV0dXJuIHJ9ZnVuY3Rpb24gRWUodCxlLHIpe2xldCBvPW5ldyBEYXRhVmlldyh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQsdC5ieXRlTGVuZ3RoKSxuPSIiO2ZvcihsZXQgaT0wO2krMTx0Lmxlbmd0aDtpKz0yKXtsZXQgYz1vLmdldFVpbnQxNihpLGUpO2lmKGM+PTU1Mjk2JiZjPD01NjMxOSl7aWYoaSs9MixpKzE+PXQubGVuZ3RoKXtuKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInRydW5jYXRlZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz1vLmdldFVpbnQxNihpLGUpO3M+PTU2MzIwJiZzPD01NzM0Mz9uKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMscyk6KG4rPXI/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIixpLT0yKX1lbHNlIGM+PTU2MzIwJiZjPD01NzM0Mz9uKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInVuZXhwZWN0ZWQgdHJhaWxpbmcgc3Vycm9nYXRlIil9KSgpOiJcdUZGRkQiOm4rPVN0cmluZy5mcm9tQ2hhckNvZGUoYyl9cmV0dXJuIG59dmFyIHB0PWNsYXNze19lbmNvZGluZztfZmF0YWw7X2lnbm9yZUJPTTtjb25zdHJ1Y3RvcihlLHIpe3RoaXMuX2VuY29kaW5nPU90KGUpLHRoaXMuX2ZhdGFsPXI/LmZhdGFsPz8hMSx0aGlzLl9pZ25vcmVCT009cj8uaWdub3JlQk9NPz8hMX1nZXQgZW5jb2RpbmcoKXtyZXR1cm4gdGhpcy5fZW5jb2Rpbmd9Z2V0IGZhdGFsKCl7cmV0dXJuIHRoaXMuX2ZhdGFsfWdldCBpZ25vcmVCT00oKXtyZXR1cm4gdGhpcy5faWdub3JlQk9NfWRlY29kZShlKXtpZighZSlyZXR1cm4iIjtsZXQgcj1lIGluc3RhbmNlb2YgVWludDhBcnJheT9lOmUgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcj9uZXcgVWludDhBcnJheShlKTpuZXcgVWludDhBcnJheShlLmJ1ZmZlcixlLmJ5dGVPZmZzZXQsZS5ieXRlTGVuZ3RoKTtpZih0aGlzLl9lbmNvZGluZz09PSJ1dGYtOCIpcmV0dXJuIERlKHIsdGhpcy5fZmF0YWwpO2xldCBvPXRoaXMuX2VuY29kaW5nPT09InV0Zi0xNmxlIixuPTA7aWYoci5sZW5ndGg+PTImJiF0aGlzLl9pZ25vcmVCT00pe2xldCBpPW8/clswXTpyWzFdLHM9KG8/clsxXTpyWzBdKTw8OHxpOyhzPT09NjUyNzl8fHM9PT02NTUzNCkmJihuPTIpfXJldHVybiBFZShyLnNsaWNlKG4pLG8sdGhpcy5fZmF0YWwpfX0sYXQ9Y2xhc3N7X2VuY29kaW5nO2NvbnN0cnVjdG9yKGUpe3RoaXMuX2VuY29kaW5nPU90KGUpfWdldCBlbmNvZGluZygpe3JldHVybiB0aGlzLl9lbmNvZGluZ31lbmNvZGUoZSl7aWYoIWUpcmV0dXJuIG5ldyBVaW50OEFycmF5KDApO2lmKHRoaXMuX2VuY29kaW5nPT09InV0Zi04Iil7bGV0IGk9W107Zm9yKGxldCBjPTA7YzxlLmxlbmd0aDtjKyspe2xldCBzPWUuY2hhckNvZGVBdChjKTtpZihzPDEyOClpLnB1c2gocyk7ZWxzZSBpZihzPDIwNDgpaS5wdXNoKDE5MnxzPj42LDEyOHxzJjYzKTtlbHNlIGlmKHM8NTUyOTZ8fHM+PTU3MzQ0KWkucHVzaCgyMjR8cz4+MTIsMTI4fHM+PjYmNjMsMTI4fHMmNjMpO2Vsc2V7YysrO2xldCBwPWUuY2hhckNvZGVBdChjKTtzPTY1NTM2KygocyYxMDIzKTw8MTApfHAmMTAyMyxpLnB1c2goMjQwfHM+PjE4LDEyOHxzPj4xMiY2MywxMjh8cz4+NiY2MywxMjh8cyY2Myl9fXJldHVybiBuZXcgVWludDhBcnJheShpKX1sZXQgcj10aGlzLl9lbmNvZGluZz09PSJ1dGYtMTZsZSIsbz1uZXcgQXJyYXlCdWZmZXIoZS5sZW5ndGgqMiksbj1uZXcgRGF0YVZpZXcobyk7Zm9yKGxldCBpPTA7aTxlLmxlbmd0aDtpKyspbi5zZXRVaW50MTYoaSoyLGUuY2hhckNvZGVBdChpKSxyKTtyZXR1cm4gbmV3IFVpbnQ4QXJyYXkobyl9fTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RGVjb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHREZWNvZGVyPXB0KTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RW5jb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHRFbmNvZGVyPWF0KTtpbXBvcnR7YnVmZmVyUHRyIGFzIFdlfWZyb20iZmZpIjtpbXBvcnQqYXMgUnQgZnJvbSJvcyI7dmFyIFRlPVsidm9pZCIsInU4IiwiaTgiLCJ1MTYiLCJpMTYiLCJ1MzIiLCJpMzIiLCJ1NjQiLCJpNjQiLCJmMzIiLCJmNjQiLCJwdHIiXSx1dD0vXjwoW0EtWmEtel9dXHcqfCk+cHRyKCF8QFtBLVphLXpfXVx3Kik/JC87ZnVuY3Rpb24gUih0KXtyZXR1cm4gdXQudGVzdCh0KX12YXIgQXQ9L148KFtBLVphLXpfXVx3Kik+JC87ZnVuY3Rpb24gTSh0KXtyZXR1cm4gQXQudGVzdCh0KX1mdW5jdGlvbiBrKHQpe3JldHVybiBBdC5leGVjKHQpPy5bMV18fCIifWZ1bmN0aW9uIGx0KHQpe3JldHVybiB1dC5leGVjKHQpPy5bMV18fCIifXZhciB0dD10PT57aWYoUih0KSlyZXR1cm4icHRyIjtpZihNKHQpKXRocm93IG5ldyBFcnJvcihgZmZpOiBjVG9rZW5Ub1R5cGU6IGJ5LXZhbHVlIHRva2VuICIke3R9IiBoYXMgbm8gc2NhbGFyIHNsb3QgdHlwZWApO3JldHVybiB0fSxBPVJ0LmFyY2g9PT0ieDY0Ij84OjQsJD17dTg6MSxpODoxLHUxNjoyLGkxNjoyLHUzMjo0LGkzMjo0LHU2NDo4LGk2NDo4LGYzMjo0LGY2NDo4fSxJPTA7ZnVuY3Rpb24gWSh0KXtpZihSKHQpKXtsZXQgbj11dC5leGVjKHQpLGk9bj8uWzFdfHwiIjtyZXR1cm4gbj8uWzJdPy5zdGFydHNXaXRoKCJAIik/YDwke2l9PnB0cmA6dH1pZihNKHQpKXJldHVybiB0O2xldCBlPXQuaW5kZXhPZigiQCIpLHI9ZT49MD90LnNsaWNlKDAsZSk6dDtpZigoZTwwfHwvXltBLVphLXpfXVx3KiQvLnRlc3QodC5zbGljZShlKzEpKSkmJnIhPT0icHRyIiYmVGUuaW5jbHVkZXMocikpcmV0dXJuIHI7dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIHRva2VuOiAiK3QpfWZ1bmN0aW9uIFYodCxlLHIpe3N3aXRjaChyKXtjYXNlInU4IjpyZXR1cm4gdC5nZXRVaW50OChlKTtjYXNlImk4IjpyZXR1cm4gdC5nZXRJbnQ4KGUpO2Nhc2UidTE2IjpyZXR1cm4gdC5nZXRVaW50MTYoZSwhMCk7Y2FzZSJpMTYiOnJldHVybiB0LmdldEludDE2KGUsITApO2Nhc2UidTMyIjpyZXR1cm4gdC5nZXRVaW50MzIoZSwhMCk7Y2FzZSJpMzIiOnJldHVybiB0LmdldEludDMyKGUsITApO2Nhc2UidTY0IjpyZXR1cm4gdC5nZXRCaWdVaW50NjQoZSwhMCk7Y2FzZSJpNjQiOnJldHVybiB0LmdldEJpZ0ludDY0KGUsITApO2Nhc2UiZjMyIjpyZXR1cm4gdC5nZXRGbG9hdDMyKGUsITApO2Nhc2UiZjY0IjpyZXR1cm4gdC5nZXRGbG9hdDY0KGUsITApO2Nhc2UicHRyIjpyZXR1cm4gQT09PTg/TnVtYmVyKHQuZ2V0QmlnSW50NjQoZSwhMCkpOnQuZ2V0SW50MzIoZSwhMCl9fWZ1bmN0aW9uIGR0KHQsZSx7azpyLHY6b30pe3N3aXRjaChyKXtjYXNlInU4Ijp0LnNldFVpbnQ4KGUsTnVtYmVyKG8pKTticmVhaztjYXNlImk4Ijp0LnNldEludDgoZSxOdW1iZXIobykpO2JyZWFrO2Nhc2UidTE2Ijp0LnNldFVpbnQxNihlLE51bWJlcihvKSwhMCk7YnJlYWs7Y2FzZSJpMTYiOnQuc2V0SW50MTYoZSxOdW1iZXIobyksITApO2JyZWFrO2Nhc2UidTMyIjp0LnNldFVpbnQzMihlLG8+Pj4wLCEwKTticmVhaztjYXNlImkzMiI6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWs7Y2FzZSJ1NjQiOnQuc2V0QmlnVWludDY0KGUsbywhMCk7YnJlYWs7Y2FzZSJpNjQiOnQuc2V0QmlnSW50NjQoZSxvLCEwKTticmVhaztjYXNlImYzMiI6dC5zZXRGbG9hdDMyKGUsbywhMCk7YnJlYWs7Y2FzZSJmNjQiOnQuc2V0RmxvYXQ2NChlLG8sITApO2JyZWFrO2Nhc2UicHRyIjp7aWYobz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoImZmaTogZ290IG51bGwvdW5kZWZpbmVkIGZvciBhIHB0ciBzbG90OyBwYXNzIHRoZSBpbXBvcnRlZCBOVUxMIGNvbnN0YW50IGZvciBlbXB0eSIpO0E9PT04P3Quc2V0QmlnVWludDY0KGUsQmlnSW50LmFzVWludE4oNjQsQmlnSW50KG8pKSwhMCk6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWt9fX1mdW5jdGlvbiB2KHQsZSxyKXtsZXR7azpvLHY6bn09cjtpZihvPT09InU4Inx8bz09PSJpOCJ8fG89PT0idTE2Inx8bz09PSJpMTYiKXt0LnNldFVpbnQzMihlLE51bWJlcihuKT4+PjAsITApO3JldHVybn1kdCh0LGUscil9dmFyIGI9Y2xhc3MgZXh0ZW5kcyBBcnJheUJ1ZmZlcntwdHI7Y29uc3RydWN0b3IoZSl7c3VwZXIoZSksdGhpcy5wdHI9V2UodGhpcyl9fTtmdW5jdGlvbiBmdCh0LGUpe3JldHVybiBlW3RdfXZhciBCdD1uZXcgTWFwO2Z1bmN0aW9uIGJlKHQpe2xldCBlPUJ0LmdldCh0KTtpZihlIT09dm9pZCAwKXJldHVybiBlO2xldCByPXJ0LkxvYWRMaWJyYXJ5KHQpO2lmKCFyKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IExvYWRMaWJyYXJ5KCIke3R9IikgZmFpbGVkYCk7cmV0dXJuIEJ0LnNldCh0LHIpLHJ9ZnVuY3Rpb24gVXQodCl7bGV0IGU9dC5zcGxpdCgiIC0+ICIpO2lmKGUubGVuZ3RoIT09Mil0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBpbnZhbGlkIHNpZ25hdHVyZSAiJHt0fSIgKGV4cGVjdGVkICJhcmcxIGFyZzIgLT4gcmV0IilgKTtsZXQgcj1lWzBdLnNwbGl0KCIgIikuZmlsdGVyKGk9PmkhPT0iIiksbz1bXTtmb3IobGV0IGkgb2Ygcil7bGV0IGM9WShpKTtpZihjPT09InZvaWQiKXRocm93IG5ldyBFcnJvcigiVm9pZCBjYW4gbm90IGluIGFyZ3MiKTtvLnB1c2goYyl9bGV0IG49WShlWzFdKTtpZihNKG4pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICIke3R9IjogYnktdmFsdWUgc3RydWN0IGF0IHRoZSByZXR1cm4gcG9zaXRpb24gKDwke2sobil9PikgaXMgbm90IHN1cHBvcnRlZCBcdTIwMTQgYXJndW1lbnQgcG9zaXRpb25zIG9ubHk7IHBhc3MgYSBzdHJ1Y3Qgb3V0IHRocm91Z2ggYW4gb3V0LXBhcmFtIHNsb3QgaW5zdGVhZCAoPE4+cHRyICsgY2FsbGVyIGJ1ZmZlcilgKTtyZXR1cm57YXJnVG9rZW5zOm8scmV0VG9rZW46bixzaWc6dH19ZnVuY3Rpb24gTmUodCxlLHIsbyl7bGV0IG49VXQoZSk7Zm9yKGxldCBpIG9mIG4uYXJnVG9rZW5zKXtpZighTShpKSljb250aW51ZTtsZXQgYz1rKGkpLHM9ZnQoYyxyKTtpZighc3x8dHlwZW9mIHMuZW5jb2RlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7ZX06IGJ5LXZhbHVlIHBvc2l0aW9uIDwke2N9PiBoYXMgbm8gcmVnaXN0ZXJlZCBsYXlvdXQgKGF2YWlsYWJsZTogJHtPYmplY3Qua2V5cyhyKS5qb2luKCIsICIpfHwibm9uZSJ9KWApO2lmKHR5cGVvZiBzLnNpemUhPSJudW1iZXIifHxzLnNpemU8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke2V9OiBieS12YWx1ZSBwb3NpdGlvbiA8JHtjfT4gcmVxdWlyZXMgYSBzdHJ1Y3QgbGF5b3V0IHdpdGggc2l6ZSA+PSAxIChnb3QgJHtzLnNpemV9OyBub24tc3RydWN0IGNvZGVjcyBleHBvc2Ugbm8gc2l6ZSlgKX1yZXR1cm4oLi4uaSk9PkllKHQsbixpLHIsbyl9dmFyIHh0PXt1ODo0LGk4OjQsdTE2OjQsaTE2OjQsdTMyOjQsaTMyOjQsdTY0OjgsaTY0OjgsZjMyOjQsZjY0OjgscHRyOkF9LEd0PTQ7ZnVuY3Rpb24gSWUodCx7YXJnVG9rZW5zOmUscmV0VG9rZW46cixzaWc6b30sbixpLGMpe2xldCBzPWV0LmFyY2g9PT0ieDY0IixwPShsLEQpPT57aWYoTShsKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBnZXRXaWR0aDogYnktdmFsdWUgdG9rZW4gIiR7bH0iIChkaXNwYXRjaGVkIGJ5IHdpZHRoT2YpYCk7cmV0dXJuIEQ/ODpSKGwpP0E6eHRbbF19LGE9bD0+e2lmKE0obCkpe2lmKHMpcmV0dXJuIDg7bGV0IEQ9ZnQoayhsKSxpKTtpZighRCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtrKGwpfT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7bGV0IEU9RC5zaXplO3JldHVybiBFJTQ9PT0wP0U6RSs0LUUlNH1yZXR1cm4gcChsLHMpfSx1PTA7Zm9yKGxldCBsIG9mIGUpdSs9YShsKTtzJiZlLmxlbmd0aDxHdCYmKHU9R3QqOCk7bGV0IHg9bmV3IEFycmF5QnVmZmVyKHUpLGQ9bmV3IERhdGFWaWV3KHgpLHc9W10sZj0wO2ZvcihsZXQgbD0wO2w8ZS5sZW5ndGg7bCsrKXtsZXQgRD1lW2xdLEU9RC5lbmRzV2l0aCgiISIpLEM9bltsXTtpZihSKEQpKXtsZXQgaD1sdChEKTtpZih0eXBlb2YgQz09Im51bWJlciIpe2lmKEUmJkM9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IGFyZyMke2wrMX0gPCR7aH0+cHRyISBnb3QgMCAobnVsbCBwb2ludGVyIGZvcmJpZGRlbiBoZXJlOyB0aGUgdG9rZW4gbWFya3MgdGhpcyBwb3NpdGlvbiBub24tbnVsbClgKTt2KGQsZix7azoicHRyIix2OkN9KX1lbHNle2lmKEM9PW51bGwpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7aH0+cHRyIGdvdCAke1N0cmluZyhDKX07IHBhc3MgdGhlIGltcG9ydGVkIE5VTEwgY29uc3RhbnQgZm9yIGFuIGVtcHR5IHBvaW50ZXJgKTtsZXQgVD1pW2hdO2lmKCFUKXRocm93IG5ldyBFcnJvcihoPT09IiI/YGZmaS1iaW5kOiA8PnB0ciBleHBlY3RzIG51bWJlciAoTlVMTCB8IFB0ciksIGdvdCAke3R5cGVvZiBDfTsgdXNlIDxCWVRFPnB0ciB3aXRoIGEgUHRyQXJyYXlCdWZmZXIgKG5ldyBQdHJBcnJheUJ1ZmZlcihuKSksIG9yIGZmaS5idWZmZXJQdHIoYnVmKSBmb3IgYW4gYWRkcmVzc2A6YGZmaS1iaW5kOiB1bmtub3duIGxheW91dCAiPCR7aH0+cHRyIiAoYXZhaWxhYmxlOiAke09iamVjdC5rZXlzKGkpLmpvaW4oIiwgIil8fCJub25lIn0pYCk7aWYoIVQuZW5jb2RlKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IDwke2h9PnB0ciBoYXMgbm8gZW5jb2RlciAob3V0LW9ubHkgY29kZWMpYCk7bGV0IEg9VC5lbmNvZGUoQyk7dy5wdXNoKEgpO2xldCBMPUgucHRyO2lmKHR5cGVvZiBMIT0ibnVtYmVyIil0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiBjb2RlYy5lbmNvZGUgbXVzdCByZXR1cm4gYSBQdHJBcnJheUJ1ZmZlciwgZ290IHBsYWluIEFycmF5QnVmZmVyIik7aWYoRSYmTD09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT5wdHIhIGVuY29kZSBwcm9kdWNlZCAwIChudWxsIHBvaW50ZXIgZm9yYmlkZGVuIGhlcmUpYCk7dihkLGYse2s6InB0ciIsdjpMfSl9fWVsc2UgaWYoTShEKSl7bGV0IGg9ayhEKSxUPWZ0KGgsaSk7aWYoIVQpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7aWYoQz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtofT4gdmFsdWUgcG9zaXRpb24gZ290ICR7U3RyaW5nKEMpfTsgcGFzcyBhIHN0cnVjdCBvYmplY3QgKHVzZSA8JHtofT5wdHIgdG8gcGFzcyBhIHBvaW50ZXIpYCk7bGV0IEg9VC5zaXplO2lmKCFzfHxIPD04JiYoSCZILTEpPT09MClULmVuY29kZShDLHgsZik7ZWxzZXtsZXQgTD1uZXcgQXJyYXlCdWZmZXIoSCsxNSksUHQ9eS5idWZmZXJQdHIoTCksTXQ9KDE2LVB0JTE2KSUxNjtULmVuY29kZShDLEwsTXQpLHcucHVzaChMKSx2KGQsZix7azoicHRyIix2OlB0K010fSl9fWVsc2UgdihkLGYse2s6RCx2OkN9KTtmKz1hKEQpfWxldCBTPW5ldyBBcnJheUJ1ZmZlcig4KTt5LmZmaUNhbGwodCx4LFMscj09PSJmMzIifHxyPT09ImY2NCI/MTowKTtsZXQgVz15ZSh0dChyKSxTKTtpZihyLmVuZHNXaXRoKCIhIikmJlc9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IHJldHVybiAke3J9IGdvdCAwICh0aGUgdG9rZW4gcHJvbWlzZXMgQyBuZXZlciByZXR1cm5zIG51bGwgaGVyZSlgKTtpZihSKHIpJiZXIT09MCl7bGV0IGw9bHQocik7aWYobCE9PSIiKXtsZXQgRD1jW2xdO2lmKEQ/LmRlY29kZSlyZXR1cm4gRC5kZWNvZGUoVyl9fXJldHVybiBXfWZ1bmN0aW9uIHllKHQsZSl7aWYodCE9PSJ2b2lkIilyZXR1cm4gVihuZXcgRGF0YVZpZXcoZSksMCx0KX12YXIgQj17ZW5jb2RlOnQ9PntsZXQgZT1uZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIikuZW5jb2RlKHQrIlwwIikscj1uZXcgYihlLmJ5dGVMZW5ndGgpO3JldHVybiBuZXcgVWludDhBcnJheShyKS5zZXQoZSkscn0sZGVjb2RlOnQ9PntpZih0eXBlb2YgdD09Im51bWJlciIpe2xldCBuPSIiLGk9dCxjPWk7Zm9yKDs7KXtsZXQgcz15LnJlYWRCeXRlKGkpLHA9eS5yZWFkQnl0ZShpKzEpO2lmKHM9PT0wJiZwPT09MClyZXR1cm4gbjtpZihuKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHN8cDw8OCksaSs9MixpLWM+MTw8MjEpdGhyb3cgbmV3IEVycm9yKCJmZmktYmluZDogV0NIQVIgZGVjb2RlIGV4Y2VlZGVkIDRNaUIgd2l0aG91dCBOVUwiKX19bGV0IGU9bmV3IFVpbnQ4QXJyYXkodCkscj1lLmxlbmd0aCYtMixvPSIiO2ZvcihsZXQgbj0wO248cjtuKz0yKXtsZXQgaT1lW25dfGVbbisxXTw8ODtpZihpPT09MClyZXR1cm4gbztvKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGkpfXJldHVybiBvfSxhbGxvYzoodD0yNTYpPT5uZXcgYih0KjIpfSxGZT17ZW5jb2RlOnQ9PntpZighKHQgaW5zdGFuY2VvZiBiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiA8QllURT5wdHIgd2FudHMgYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pIC8gQllURS5hbGxvYyAvIHN0cnVjdC5lbmNvZGUpLCBub3QgYSBwbGFpbiBBcnJheUJ1ZmZlciIpO3JldHVybiB0fSxhbGxvYzp0PT5uZXcgYih0KX0sTHQ9e1dDSEFSOkIsQllURTpGZX07ZnVuY3Rpb24gRyh0LGUscixvLG4pe2xldCBpPXJ0LkdldFByb2NBZGRyZXNzKGJlKHQpLGUpO2lmKCFpKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IHByb2MgIiR7ZX0iIG5vdCBmb3VuZCBpbiAke3R9YCk7bGV0IGM9bj8/bztyZXR1cm4gTmUoaSxyLHsuLi5MdCwuLi5vfSx7Li4uTHQsLi4uYz8/e319KX12YXIga3Q9bmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KHQ9PntLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSBsZWFrZWQgKEdDZWQgd2l0aG91dCBkaXNwb3NlKTogc2lnPSIlcyIgcHRyPTB4JXgKYCx0LnNpZyx0LnB0cil9KTtmdW5jdGlvbiBIZSh0LGUscixvLG4saSl7bGV0IGM9bmV3IERhdGFWaWV3KG4pLHM9ZXQuYXJjaD09PSJ4NjQiLHA9bmV3IERhdGFWaWV3KG8pLGE9W10sdT0wO2ZvcihsZXQgZD0wO2Q8dC5sZW5ndGg7ZCsrKXtsZXQgdz10W2RdLGY9dy50b2ssUztpZihzKXtsZXQgVz1mPT09ImYzMiJ8fGY9PT0iZjY0Ij9kPDQ/MTI4K2QqODozMisoZC00KSo4OmQ8ND9kKjg6MzIrKGQtNCkqODtTPVYocCxXLGYpfWVsc2UgUz1WKHAsdSxmKSx1Kz14dFtmXTtpZih3Lm5vbm51bGwmJlM9PT0wKXtLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSAlczogYXJnIyVkIGdvdCAwICghIHByb21pc2UgdmlvbGF0ZWQgYnkgY2FsbGVyKSwgc2tpcHBpbmcgY2FsbGJhY2sKYCxpLGQrMSk7cmV0dXJufWEucHVzaChTKX1sZXQgeDt0cnl7eD1yKC4uLmEpfWNhdGNoKGQpe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlIGNhbGxiYWNrIHRocmV3OiAlcwpgLFN0cmluZyhkKSk7cmV0dXJufWlmKGUubm9ubnVsbCYmeD09PTApe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlICVzOiByZXR1cm4gZ290IDAgKCEgcHJvbWlzZSB2aW9sYXRlZCBieSBjYWxsYmFjayksIGxlYXZpbmcgcmVzdWx0IHNsb3QgMApgLGkpO3JldHVybn1lLnRvayE9PSJ2b2lkIiYmdihjLDAse2s6ZS50b2ssdjp4fSl9ZnVuY3Rpb24gX3QodCxlLHIpe2xldHthcmdUb2tlbnM6byxyZXRUb2tlbjpufT1VdCh0KTtmb3IobGV0IG0gb2YgbylpZihNKG0pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IGNsb3N1cmUgc2lnbmF0dXJlIGNhbm5vdCB0YWtlIGEgYnktdmFsdWUgc3RydWN0ICg8JHtrKG0pfT4pOyBieS12YWx1ZSBpcyBiaW5kLW9ubHkgXHUyMDE0IHRoZSBDXHUyMTkySlMgZGlyZWN0aW9uIGhhcyBubyBzdHJ1Y3Qgc2xvdCBkZWNvZGluZyAocGFzcyBhIHBvaW50ZXIgYW5kIGRlY29kZSBvbiB0aGUgSlMgc2lkZSlgKTtsZXQgaT1vLm1hcChtPT4oe3Rvazp0dChtKSxub25udWxsOm0uZW5kc1dpdGgoIiEiKX0pKSxjPXt0b2s6dHQobiksbm9ubnVsbDpuLmVuZHNXaXRoKCIhIil9LHM9ZXQuYXJjaD09PSJ4NjQiLHA9aS5yZWR1Y2UoKG0sVyk9Pm0reHRbVy50b2tdLDApO2lmKHM/aS5sZW5ndGg+MTY6cD42NCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBjbG9zdXJlIHNpZ25hdHVyZSBleGNlZWRzIGNhcHR1cmUgd2luZG93ICgke3M/Im1heCAxNiBwYXJhbXMiOiJtYXggNjQgc3RhY2sgYnl0ZXMifSk6ICR7dH1gKTtsZXQgYT1yPy5zdGRjYWxsPT09ITF8fHM/MDpwLHU9Yy50b2s9PT0iZjMyIj8xOmMudG9rPT09ImY2NCI/MjpjLnRvaz09PSJ1NjQifHxjLnRvaz09PSJpNjQiPzM6MCxkPXkuY2xvc3VyZU5ldyhhLHUsKG0sVyk9PntIZShpLGMsZSxtLFcsdCl9KSx3PSExLGY9KCk9Pnt3fHwodz0hMCxrdC51bnJlZ2lzdGVyKGYpLHkuY2xvc3VyZUZyZWUoZCkpfSxTPXtwdHI6ZCxkaXNwb3NlOmZ9O3JldHVybiBrdC5yZWdpc3RlcihmLHtzaWc6dCxwdHI6ZH0pLFN9aW1wb3J0KmFzIHd0IGZyb20iZmZpIjtmdW5jdGlvbiBYKHQsZSl7cmV0dXJuIHQrZS0xJn4oZS0xKX12YXIgenQ9dD0+JFt0XSE9PXZvaWQgMDtmdW5jdGlvbiBtdCh0KXtpZih0eXBlb2YgdD09InN0cmluZyIpe2xldCBlPS9eKHU4fHUxNilcWyhcZCspXF1AKHV0Zi04fHV0Zi0xNmxlKSQvLmV4ZWModCk7aWYoZSl7bGV0IGM9TnVtYmVyKGVbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJpbmcgbGVuZ3RoIG11c3QgYmUgYW4gaW50ZWdlciA+PSAxLCBnb3QgJHtjfWApO2xldCBzPWVbMV09PT0idTgiPzE6MjtyZXR1cm57c2l6ZTpzKmMsYWxpZ246cyx0eXBlOnt0YWc6InN0cmluZyIsZW5jb2Rpbmc6ZVszXX19fWxldCByPS9eKFteXFtcXV0rKVxbKFxkKylcXSQvLmV4ZWModCk7aWYocil7bGV0IGM9TnVtYmVyKHJbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke2N9YCk7bGV0IHM9bXQoclsxXSk7aWYocy50eXBlLnRhZz09PSJiaXRmaWVsZCIpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBiaXRmaWVsZHMgY2Fubm90IGJlIGFycmF5IGVsZW1lbnRzIik7cmV0dXJue3NpemU6cy5zaXplKmMsYWxpZ246cy5hbGlnbix0eXBlOnt0YWc6ImFycmF5IixlbGVtZW50VHlwZTpzLnR5cGUsZWxlbWVudFNpemU6cy5zaXplfX19bGV0IG89L14oW0EtWmEtel9dXHcqKTooXGQrKSQvLmV4ZWModCk7aWYobyl7bGV0IGM9b1sxXSxzPVkoYyk7aWYoIXp0KHMpfHxzPT09ImYzMiJ8fHM9PT0iZjY0Iil0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIHVuaXQgbXVzdCBiZSBhbiBpbnRlZ2VyIHR5cGUsIGdvdCAiJHtjfSJgKTtsZXQgcD1OdW1iZXIob1syXSksYT0kW3NdLHU9YSo4O2lmKCFOdW1iZXIuaXNJbnRlZ2VyKHApfHxwPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCBtdXN0IGJlIGFuIGludGVnZXIgPj0gMSwgZ290ICR7cH1gKTtpZihwPnUpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCAke3B9IGV4Y2VlZHMgdW5pdCB3aWR0aCAke3V9YCk7cmV0dXJue3NpemU6YSxhbGlnbjphLHR5cGU6e3RhZzoiYml0ZmllbGQiLHVuaXQ6cyxiaXQ6MCx3aWR0aDpwfX19bGV0IG49WSh0KTtpZihSKG4pKXJldHVybntzaXplOkEsYWxpZ246QSx0eXBlOnt0YWc6ImJhc2ljIixraW5kOiJwdHIifX07aWYoIXp0KG4pKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biBraW5kICIke3R9ImApO2xldCBpPSRbbl07cmV0dXJue3NpemU6aSxhbGlnbjppLHR5cGU6e3RhZzoiYmFzaWMiLGtpbmQ6bn19fWlmKHQmJnR5cGVvZiB0PT0ib2JqZWN0Iil7bGV0IGU9dCxyPWVbIiMiXTtpZihyPT09dm9pZCAwKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogbmVzdGVkIG9iamVjdCB2YWx1ZSByZXF1aXJlcyBhICcjJyBrZXkgKCdzdHJ1Y3QnIHwgJ3VuaW9uJyB8ICdhcnJheScpIik7aWYocj09PSJhcnJheSImJiIjcGFjayJpbiBlKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogJyNwYWNrJyBpcyBvbmx5IGFsbG93ZWQgb24gc3RydWN0L3VuaW9uLCBnb3QgJyR7cn0nYCk7aWYocj09PSJhcnJheSIpe2xldCBvPWUubGVuZ3RoO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKG8pfHxvPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke1N0cmluZyhvKX1gKTtsZXQgbj1tdChlLmVsZW1lbnQpO2lmKG4udHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOm4uc2l6ZSpvLGFsaWduOm4uYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6bi50eXBlLGVsZW1lbnRTaXplOm4uc2l6ZX19fWlmKHI9PT0ic3RydWN0Inx8cj09PSJ1bmlvbiIpe2xldCBvPWh0KHQpO3JldHVybntzaXplOm8uc2l6ZSxhbGlnbjpvLm1heEVmZmVjdGl2ZUFsaWduLHR5cGU6e3RhZzpyLGZpZWxkczpvLmZpZWxkc319fXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biAnIycgZGVjbGFyYXRpb24gJHtKU09OLnN0cmluZ2lmeShTdHJpbmcocikpfWApfXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogaW52YWxpZCBtZW1iZXIgdmFsdWU6ICR7U3RyaW5nKHQpfWApfWZ1bmN0aW9uIGh0KHQpe2xldCBlPXRbIiMiXT09PSJzdHJ1Y3QiLHI9dFsiI3BhY2siXT8/OCxvPTEsbj0wLGk9W10sYz0wLHM9LTEscD0wLGE9MCx1PSgpPT57czwwfHwoYz1YKHMrTWF0aC5jZWlsKHAvOCksYSkscz0tMSl9O2ZvcihsZXRbeCxkXW9mIE9iamVjdC5lbnRyaWVzKHQpKXtpZih4LnN0YXJ0c1dpdGgoIiMiKSljb250aW51ZTtsZXQgdz0vXihbXkBdKylAKFxkKykkLy5leGVjKHgpLGY9dz93WzFdOngsUz13P051bWJlcih3WzJdKTowLHtzaXplOm0sYWxpZ246Vyx0eXBlOmx9PW10KGQpLEQ9dHlwZW9mIGQ9PSJzdHJpbmciJiZkLmVuZHNXaXRoKCIhIiksRT1XO2lmKHI+MCYmKEU9TWF0aC5taW4ocixFKSksUyYmKEU9TWF0aC5tYXgoRSxTKSksbC50YWc9PT0iYml0ZmllbGQiKXtpZihmLnN0YXJ0c1dpdGgoIiQiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIG1lbWJlcnMgbXVzdCBiZSBuYW1lZCIpO2lmKCFlKXtpLnB1c2goe25hbWU6ZixvZmZzZXQ6MCxzaXplOm0sdHlwZTp7Li4ubCxiaXQ6MH19KSxvPU1hdGgubWF4KG8sRSksbj1NYXRoLm1heChuLG0pO2NvbnRpbnVlfWxldCBoPWwud2lkdGg7KHM8MHx8bSE9PWF8fHAraD5hKjgpJiYocz49MCYmdSgpLHM9WChjLEUpLHA9MCxhPW0pLGkucHVzaCh7bmFtZTpmLG9mZnNldDpzLHNpemU6bSx0eXBlOnsuLi5sLGJpdDpwfX0pLHArPWgsbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKTtjb250aW51ZX11KCk7bGV0IEM9WChjLEUpO2lmKCFmLnN0YXJ0c1dpdGgoIiQiKSlpLnB1c2goe25hbWU6ZixvZmZzZXQ6QyxzaXplOm0sdHlwZTpsLC4uLkQ/e25vbm51bGw6ITB9Ont9fSk7ZWxzZXtpZihsLnRhZyE9PSJzdHJ1Y3QiJiZsLnRhZyE9PSJ1bmlvbiIpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhbm9ueW1vdXMgbWVtYmVyICIke2Z9IiBtdXN0IGJlIGEgc3RydWN0L3VuaW9uYCk7Zm9yKGxldCBoIG9mIGwuZmllbGRzKWkucHVzaCh7Li4uaCxvZmZzZXQ6aC5vZmZzZXQrQ30pfWUmJihjPUMrbSksbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKX1yZXR1cm4gdSgpLHtzaXplOlgoZT9jOm4sbyksbWF4RWZmZWN0aXZlQWxpZ246byxmaWVsZHM6aX19ZnVuY3Rpb24gJHQodCxlLHIpe2xldCBvPSRbcl07cmV0dXJuIG89PT0xP0JpZ0ludCh0LmdldFVpbnQ4KGUpKTpvPT09Mj9CaWdJbnQodC5nZXRVaW50MTYoZSwhMCkpOm89PT00P0JpZ0ludCh0LmdldFVpbnQzMihlLCEwKSk6dC5nZXRCaWdVaW50NjQoZSwhMCl9ZnVuY3Rpb24gUGUodCxlLHIsbyl7bGV0IG49JFtyXTtpZihuPT09MSl7dC5zZXRVaW50OChlLE51bWJlcihvJjB4ZmZuKSk7cmV0dXJufWlmKG49PT0yKXt0LnNldFVpbnQxNihlLE51bWJlcihvJjB4ZmZmZm4pLCEwKTtyZXR1cm59aWYobj09PTQpe3Quc2V0VWludDMyKGUsTnVtYmVyKG8mMHhmZmZmZmZmZm4pLCEwKTtyZXR1cm59dC5zZXRCaWdVaW50NjQoZSxvJjB4ZmZmZmZmZmZmZmZmZmZmZm4sITApfWZ1bmN0aW9uIE1lKHQsZSxyKXtsZXQgbz1CaWdJbnQoci53aWR0aCksbj0kdCh0LGUsci51bml0KT4+QmlnSW50KHIuYml0KSYoMW48PG8pLTFuO3JldHVybiByLnVuaXRbMF09PT0iaSImJm4mMW48PG8tMW4mJihuLT0xbjw8byksci53aWR0aD41Mz9uOk51bWJlcihuKX1mdW5jdGlvbiBPZSh0LGUscixvKXtsZXQgbj1CaWdJbnQoci53aWR0aCksaT1CaWdJbnQoci5iaXQpLGM9KDFuPDxuKS0xbixzPWM8PGkscD0kdCh0LGUsci51bml0KSxhPSh0eXBlb2Ygbz09ImJpZ2ludCI/bzpCaWdJbnQoTWF0aC50cnVuYyhvKSkpJmM7UGUodCxlLHIudW5pdCxwJn5zfGE8PGkpfXZhciBSZT17InV0Zi04IjpuZXcgVGV4dEVuY29kZXIoInV0Zi04IiksInV0Zi0xNmxlIjpuZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIil9LEFlPXsidXRmLTgiOm5ldyBUZXh0RGVjb2RlcigidXRmLTgiLHtpZ25vcmVCT006ITB9KSwidXRmLTE2bGUiOm5ldyBUZXh0RGVjb2RlcigidXRmLTE2bGUiLHtpZ25vcmVCT006ITB9KX07ZnVuY3Rpb24gQmUodCxlLHIsbyl7bGV0IG49bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2UsciksaT1vPT09InV0Zi0xNmxlIj8yOjEsYz1yO2ZvcihsZXQgcz0wO3MraTw9cjtzKz1pKWlmKG5bc109PT0wJiYoaT09PTF8fG5bcysxXT09PTApKXtjPXM7YnJlYWt9cmV0dXJuIEFlW29dLmRlY29kZShuLnN1YmFycmF5KDAsYykpfWZ1bmN0aW9uIEdlKHQsZSxyLG8sbil7bGV0IGk9bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2Uscik7aS5maWxsKDApO2xldCBzPXItKG89PT0idXRmLTE2bGUiPzI6MSk7aWYoczw9MClyZXR1cm47bGV0IHA9UmVbb10uZW5jb2RlKFN0cmluZyhuPz8iIikpO2kuc2V0KHAuc3ViYXJyYXkoMCxNYXRoLm1pbihwLmxlbmd0aCxzKSkpfWZ1bmN0aW9uIExlKHQsZSxyLG8pe2xldCBuPW8uZWxlbWVudFNpemU+MD9yL28uZWxlbWVudFNpemU6MCxpPVtdO2ZvcihsZXQgYz0wO2M8bjtjKyspaS5wdXNoKFl0KHQsZStjKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplKSk7cmV0dXJuIGl9ZnVuY3Rpb24ga2UodCxlLHIsbyxuKXtsZXQgaT1vLmVsZW1lbnRTaXplPjA/ci9vLmVsZW1lbnRTaXplOjAsYz1uPz9bXTtmb3IobGV0IHM9MDtzPGk7cysrKVZ0KHQsZStzKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplLGNbc10pfWZ1bmN0aW9uIFl0KHQsZSxyLG8pe3N3aXRjaChyLnRhZyl7Y2FzZSJiYXNpYyI6cmV0dXJuIFYodCxlLHIua2luZCk7Y2FzZSJiaXRmaWVsZCI6cmV0dXJuIE1lKHQsZSxyKTtjYXNlInN0cmluZyI6cmV0dXJuIEJlKHQsZSxvLHIuZW5jb2RpbmcpO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjpyZXR1cm4gb3QodCxlLHIuZmllbGRzKTtjYXNlImFycmF5IjpyZXR1cm4gTGUodCxlLG8scil9fWZ1bmN0aW9uIFZ0KHQsZSxyLG8sbil7c3dpdGNoKHIudGFnKXtjYXNlImJhc2ljIjpkdCh0LGUse2s6ci5raW5kLHY6bn0pO2JyZWFrO2Nhc2UiYml0ZmllbGQiOk9lKHQsZSxyLG4/PzApO2JyZWFrO2Nhc2Uic3RyaW5nIjpHZSh0LGUsbyxyLmVuY29kaW5nLG4pO2JyZWFrO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjp2dCh0LGUsci5maWVsZHMsbj8/e30pO2JyZWFrO2Nhc2UiYXJyYXkiOmtlKHQsZSxvLHIsbik7YnJlYWt9fWZ1bmN0aW9uIG90KHQsZSxyKXtsZXQgbz17fTtmb3IobGV0IG4gb2Ygcil7bGV0IGk9WXQodCxlK24ub2Zmc2V0LG4udHlwZSxuLnNpemUpO2lmKG4ubm9ubnVsbCYmaT09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBkZWNvZGU6ICchJyBmaWVsZCAiJHtuLm5hbWV9IiBnb3QgMCAoQyBkaWQgbm90IGZpbGwgaXQsIG9yIGRlY29kZSB3YXMgY2FsbGVkIG9uIGFuIHVuZmlsbGVkIHNsb3QpYCk7b1tuLm5hbWVdPWl9cmV0dXJuIG99ZnVuY3Rpb24gdnQodCxlLHIsbyl7Zm9yKGxldCBuIG9mIHIpb1tuLm5hbWVdIT09dm9pZCAwJiZWdCh0LGUrbi5vZmZzZXQsbi50eXBlLG4uc2l6ZSxvW24ubmFtZV0pfWZ1bmN0aW9uIFVlKHQpe2xldHtmaWVsZHM6ZSxzaXplOnIsbWF4RWZmZWN0aXZlQWxpZ246b309aHQodCk7cmV0dXJue19fc3RydWN0OnQsc2l6ZTpyLHN0cnVjdEFsaWduOm8sZGVjb2RlOm49Pm90KHR5cGVvZiBuPT0ibnVtYmVyIj9uZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4scikpOm5ldyBEYXRhVmlldyhuKSwwLGUpLGFsbG9jOihuPT57aWYobiE9PXZvaWQgMCYmKCFOdW1iZXIuaXNJbnRlZ2VyKG4pfHxuPDEpKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYWxsb2MobikgcmVxdWlyZXMgYW4gaW50ZWdlciBuID49IDEgKFBBQigwKSBuZXZlciBlc2NhcGVzIFx1MjAxNCBwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7cmV0dXJuIG5ldyBiKHIqKG4/PzEpKX0pLGVuY29kZTooKG4saSxjKT0+e2lmKG49PW51bGwpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBlbmNvZGUodikgcmVxdWlyZXMgYW4gYXJndW1lbnQ7IHVzZSBhbGxvYygpIGZvciBhIHplcm9lZCBvdXQtcGFyYW0gc2xvdCIpO2xldCBzPWk/P25ldyBiKHIpO3JldHVybiB2dChuZXcgRGF0YVZpZXcocyksYz8/MCxlLG4pLHN9KSxvZmZzZXRPZjpuPT57Zm9yKGxldCBpIG9mIGUpaWYoaS5uYW1lPT09bilyZXR1cm4gaS5vZmZzZXQ7dGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBubyBmaWVsZCAiJHtufSJgKX19fWZ1bmN0aW9uIF9lKHQsZSxyKXtsZXQgbz17IiMiOnR9O3IhPT12b2lkIDAmJihvWyIjcGFjayJdPXIpO2ZvcihsZXRbbixpXW9mIE9iamVjdC5lbnRyaWVzKGUpKW4uc3RhcnRzV2l0aCgiIyIpfHwob1tuXT1pKTtyZXR1cm4gb31mdW5jdGlvbiBqdCh0KXtsZXR7ZmllbGRzOmUsc2l6ZTpyfT1odCh0Ll9fc3RydWN0KSxvPShuLGkpPT57bGV0IGM9W107Zm9yKGxldCBzPTA7czxpO3MrKyljLnB1c2gob3QobixzKnIsZSkpO3JldHVybiBjfTtyZXR1cm57ZW5jb2RlOm49PntpZighQXJyYXkuaXNBcnJheShuKXx8bi5sZW5ndGg9PT0wKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogc3RydWN0QXJyYXkoZGVmKS5lbmNvZGUoZWxzKSByZXF1aXJlcyBhIG5vbi1lbXB0eSBlbGVtZW50IGFycmF5IChwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7bGV0IGk9dC5hbGxvYyhuLmxlbmd0aCk7Zm9yKGxldCBjPTA7YzxuLmxlbmd0aDtjKyspdC5lbmNvZGUobltjXSxpLGMqdC5zaXplKTtyZXR1cm4gaX0sZGVjb2RlOigobixpKT0+e2lmKGkhPT12b2lkIDAmJighTnVtYmVyLmlzSW50ZWdlcihpKXx8aTwwKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZShwLCBjb3VudCkgcmVxdWlyZXMgYSBub24tbmVnYXRpdmUgaW50ZWdlciBjb3VudCwgZ290ICR7aX1gKTtpZih0eXBlb2Ygbj09Im51bWJlciIpe2lmKGk9PT12b2lkIDApdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGUoYWRkcmVzcywgY291bnQpIHJlcXVpcmVzIGFuIGV4cGxpY2l0IGNvdW50IChhIGJhcmUgYWRkcmVzcyBjYXJyaWVzIG5vIGxlbmd0aCkiKTtyZXR1cm4gaT09PTA/W106byhuZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4saSpyKSksaSl9bGV0IGM7aWYoaSE9PXZvaWQgMCl7aWYoYz1pLGMqcj5uLmJ5dGVMZW5ndGgpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGU6IGNvdW50ICR7Y30gXHhENyBzaXplICR7cn0gPSAke2Mqcn0gZXhjZWVkcyBidWZmZXIgYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH1gKX1lbHNle2lmKG4uYnl0ZUxlbmd0aCVyIT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZTogYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH0gaXMgbm90IGEgbXVsdGlwbGUgb2Ygc2l6ZSAke3J9IChtaXhlZCBidWZmZXI/IHBhc3MgY291bnQgZXhwbGljaXRseSlgKTtjPW4uYnl0ZUxlbmd0aC9yfXJldHVybiBjPT09MD9bXTpvKG5ldyBEYXRhVmlldyhuKSxjKX0pfX1mdW5jdGlvbiBnKHQsZSxyKXtsZXQgbz10eXBlb2YgdD09InN0cmluZyI7cmV0dXJuIFVlKF9lKCJzdHJ1Y3QiLG8/ZTp0LChvP3I6ZSk/LnBhY2spKX12YXIgUD1nKCJSRUNUIix7bGVmdDoiaTMyIix0b3A6ImkzMiIscmlnaHQ6ImkzMiIsYm90dG9tOiJpMzIifSksaj1nKCJQT0lOVCIse3g6ImkzMiIseToiaTMyIn0pO3ZhciBudD1nKCJTVEFSVFVQSU5GT1ciLHtjYjoidTMyIixscFJlc2VydmVkOiI8PnB0ciIsbHBEZXNrdG9wOiI8PnB0ciIsbHBUaXRsZToiPD5wdHIiLGR3WDoidTMyIixkd1k6InUzMiIsZHdYU2l6ZToidTMyIixkd1lTaXplOiJ1MzIiLGR3WENvdW50Q2hhcnM6InUzMiIsZHdZQ291bnRDaGFyczoidTMyIixkd0ZpbGxBdHRyaWJ1dGU6InUzMiIsZHdGbGFnczoidTMyIix3U2hvd1dpbmRvdzoidTE2QFNob3dXaW5kb3dDbWQiLGNiUmVzZXJ2ZWQyOiJ1MTYiLGxwUmVzZXJ2ZWQyOiI8PnB0ciIsaFN0ZElucHV0OiI8SEZJTEU+cHRyIixoU3RkT3V0cHV0OiI8SEZJTEU+cHRyIixoU3RkRXJyb3I6IjxIRklMRT5wdHIifSksQ3Q9ZygiUFJPQ0VTU19JTkZPUk1BVElPTiIse2hQcm9jZXNzOiI8SFBST0NFU1M+cHRyISIsaFRocmVhZDoiPEhUSFJFQUQ+cHRyISIsZHdQcm9jZXNzSWQ6InUzMiIsZHdUaHJlYWRJZDoidTMyIn0pLEo9ZygiQklUTUFQSU5GT0hFQURFUiIse2JpU2l6ZToidTMyIixiaVdpZHRoOiJpMzIiLGJpSGVpZ2h0OiJpMzIiLGJpUGxhbmVzOiJ1MTYiLGJpQml0Q291bnQ6InUxNiIsYmlDb21wcmVzc2lvbjoidTMyIixiaVNpemVJbWFnZToidTMyIixiaVhQZWxzUGVyTWV0ZXI6ImkzMiIsYmlZUGVsc1Blck1ldGVyOiJpMzIiLGJpQ2xyVXNlZDoidTMyIixiaUNsckltcG9ydGFudDoidTMyIn0pLGl0PWcoIkJJVE1BUEZJTEVIRUFERVIiLHtiZlR5cGU6InUxNiIsYmZTaXplOiJ1MzIiLGJmUmVzZXJ2ZWQxOiJ1MTYiLGJmUmVzZXJ2ZWQyOiJ1MTYiLGJmT2ZmQml0czoidTMyIn0se3BhY2s6Mn0pO3ZhciBaPWcoIk5NSERSIix7aHduZEZyb206IjxIV05EPnB0ciIsaWRGcm9tOiI8PnB0ciIsY29kZToiaTMyIn0pLHplPWcoIlNZU1RFTVRJTUUiLHt3WWVhcjoidTE2Iix3TW9udGg6InUxNiIsd0RheU9mV2VlazoidTE2Iix3RGF5OiJ1MTYiLHdIb3VyOiJ1MTYiLHdNaW51dGU6InUxNiIsd1NlY29uZDoidTE2Iix3TWlsbGlzZWNvbmRzOiJ1MTYifSksbXI9ZygiTk1EQVRFVElNRUNIQU5HRSIse2hkcjpaLl9fc3RydWN0LGR3RmxhZ3M6InUzMiIsc3Q6emUuX19zdHJ1Y3R9KSwkZT1nKCJMSVRFTSIse21hc2s6InUzMiIsaUxpbms6ImkzMiIsc3RhdGU6InUzMiIsc3RhdGVNYXNrOiJ1MzIiLHN6SUQ6InUxNls0OF1AdXRmLTE2bGUiLHN6VXJsOiJ1MTZbMjA4NF1AdXRmLTE2bGUifSksd3I9ZygiTk1MSU5LIix7aGRyOlouX19zdHJ1Y3QsaXRlbTokZS5fX3N0cnVjdH0pLGhyPWcoIk5NQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciJ9KSxDcj1nKCJOTUxWQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciIsY2xyVGV4dDoidTMyIixjbHJUZXh0Qms6InUzMiIsaVN1Ykl0ZW06ImkzMiIsZHdJdGVtVHlwZToidTMyIn0pLFNyPWcoIk5NTElTVFZJRVciLHtoZHI6Wi5fX3N0cnVjdCxpSXRlbToiaTMyIixpU3ViSXRlbToiaTMyIix1TmV3U3RhdGU6InUzMiIsdU9sZFN0YXRlOiJ1MzIiLHVDaGFuZ2VkOiJ1MzIiLHB0QWN0aW9uOiJpMzJbMl0iLGxQYXJhbToiPD5wdHIifSk7dmFyIFllPWcoIlRWSVRFTSIse21hc2s6InUzMiIsaEl0ZW06Ijw+cHRyIixzdGF0ZToidTMyIixzdGF0ZU1hc2s6InUzMiIscHN6VGV4dDoiPD5wdHIiLGNjaFRleHRNYXg6ImkzMiIsaUltYWdlOiJpMzIiLGlTZWxlY3RlZEltYWdlOiJpMzIiLGNDaGlsZHJlbjoiaTMyIixsUGFyYW06Ijw+cHRyIn0pLGdyPWcoIlRWSU5TRVJUU1RSVUNUIix7aFBhcmVudDoiPD5wdHIiLGhJbnNlcnRBZnRlcjoiPD5wdHIiLGl0ZW06WWUuX19zdHJ1Y3R9KTt2YXIgVmU9ZygiTVNHIix7aHduZDoiPEhXTkQ+cHRyIixtZXNzYWdlOiJ1MzIiLHdQYXJhbToiPD5wdHIiLGxQYXJhbToiPD5wdHIiLHRpbWU6InUzMiIscHQ6ai5fX3N0cnVjdH0pLERyPWcoIlBBSU5UU1RSVUNUIix7aGRjOiI8SERDPnB0ciIsZkVyYXNlOiJpMzIiLHJjUGFpbnQ6UC5fX3N0cnVjdCxmUmVzdG9yZToiaTMyIixmSW5jVXBkYXRlOiJpMzIiLHJnYlJlc2VydmVkOiJ1OFszMl0ifSk7dmFyIHN0PWcoIk9TVkVSU0lPTklORk9fMTQ4Iix7ZHdPU1ZlcnNpb25JbmZvU2l6ZToidTMyIixkd01ham9yVmVyc2lvbjoidTMyIixkd01pbm9yVmVyc2lvbjoidTMyIixkd0J1aWxkTnVtYmVyOiJ1MzIiLGR3UGxhdGZvcm1JZDoidTMyIixzekNTRFZlcnNpb246InU4WzEyOF0ifSk7dmFyIE89KHQsZSxyKT0+Rygia2VybmVsMzIuZGxsIix0LGUsciksSnQ9TygiQ3JlYXRlUGlwZSIsIjw+cHRyIDw+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKSxTdD1PKCJTZXRIYW5kbGVJbmZvcm1hdGlvbiIsIjxIRklMRT5wdHIhIHUzMiB1MzIgLT4gaTMyIiksS3Q9TygiQ3JlYXRlUHJvY2Vzc1ciLCI8V0NIQVI+cHRyIDxXQ0hBUj5wdHIgPD5wdHIgPD5wdHIgaTMyIHUzMiA8PnB0ciA8V0NIQVI+cHRyIDxTVEFSVFVQSU5GT1c+cHRyIDxQUk9DRVNTX0lORk9STUFUSU9OPnB0ciAtPiBpMzIiLHtTVEFSVFVQSU5GT1c6bnR9KSxYdD1PKCJXYWl0Rm9yU2luZ2xlT2JqZWN0IiwiPD5wdHIgdTMyIC0+IHUzMiIpLFp0PU8oIkdldEV4aXRDb2RlUHJvY2VzcyIsIjxIUFJPQ0VTUz5wdHIhIDxCWVRFPnB0ciAtPiBpMzIiKSxVPU8oIkNsb3NlSGFuZGxlIiwiPD5wdHIgLT4gaTMyIik7dmFyIHF0PU8oIlJlYWRGaWxlIiwiPEhGSUxFPnB0ciEgPEJZVEU+cHRyIHUzMiA8QllURT5wdHIgPD5wdHIgLT4gaTMyIik7dmFyIGd0PU8oIkdldExhc3RFcnJvciIsIiAtPiB1MzIiKSxRdD1PKCJHZXRTeXN0ZW1EaXJlY3RvcnlXIiwiPEJZVEU+cHRyIHUzMiAtPiB1MzIiKTtpbXBvcnQqYXMgdGUgZnJvbSJvcyI7dmFyIE49KHQsZSxyKT0+RygidXNlcjMyLmRsbCIsdCxlLHIpLEhyPU4oIkdldERlc2t0b3BXaW5kb3ciLCIgLT4gPEhXTkQ+cHRyIiksZWU9dGUuYXJjaD09PSJ4NjQiPyJQdHJXIjoiVyI7dmFyIER0PU4oIkdldFdpbmRvd1JlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpLHJlPU4oIkdldENsaWVudFJlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpO3ZhciBvZT1OKCJJc1dpbmRvd1Zpc2libGUiLCI8SFdORD5wdHIgLT4gaTMyIiksRXQ9TigiSXNJY29uaWMiLCI8SFdORD5wdHIgLT4gaTMyIik7dmFyIG5lPU4oIkdldFdpbmRvd1RleHRXIiwiPEhXTkQ+cHRyIDxCWVRFPnB0ciBpMzIgLT4gaTMyIik7dmFyIGllPU4oIkdldENsYXNzTmFtZVciLCI8SFdORD5wdHIgPEJZVEU+cHRyIGkzMiAtPiBpMzIiKSxQcj1OKCJHZXRXaW5kb3dMb25nIitlZSwiPEhXTkQ+cHRyIGkzMkBHd2xwIC0+IDw+cHRyIiksTXI9TigiU2V0V2luZG93TG9uZyIrZWUsIjxIV05EPnB0ciBpMzJAR3dscCA8PnB0ciAtPiA8PnB0ciIpO3ZhciBzZT1OKCJHZXREQyIsIjxIV05EPnB0ciAtPiA8SERDPnB0ciIpLFd0PU4oIlJlbGVhc2VEQyIsIjxIV05EPnB0ciA8SERDPnB0ciEgLT4gaTMyIiksY2U9TigiUHJpbnRXaW5kb3ciLCI8SFdORD5wdHIgPEhEQz5wdHIhIHUzMiAtPiBpMzIiKTt2YXIgcGU9TigiQ2xpZW50VG9TY3JlZW4iLCI8SFdORD5wdHIgPFBPSU5UPnB0ciAtPiBpMzIiKTt2YXIgXz1OKCJHZXRTeXN0ZW1NZXRyaWNzIiwiaTMyIC0+IGkzMiIpO3ZhciBhZT1OKCJFbnVtV2luZG93cyIsIjw+cHRyIDw+cHRyIC0+IGkzMiIpO3ZhciB6PSh0LGUscik9PkcoImdkaTMyLmRsbCIsdCxlLHIpLExyPWp0KGopO3ZhciBUdD16KCJEZWxldGVPYmplY3QiLCI8SEdESU9CSj5wdHIgLT4gaTMyIik7dmFyIGJ0PXooIkNyZWF0ZUNvbXBhdGlibGVEQyIsIjxIREM+cHRyIC0+IDxIREM+cHRyIiksTnQ9eigiQ3JlYXRlQ29tcGF0aWJsZUJpdG1hcCIsIjxIREM+cHRyISBpMzIgaTMyIC0+IDxIR0RJT0JKPnB0ciIpO3ZhciBxPXooIlNlbGVjdE9iamVjdCIsIjxIREM+cHRyISA8SEdESU9CSj5wdHIgLT4gPEhHRElPQko+cHRyIiksSXQ9eigiQml0Qmx0IiwiPEhEQz5wdHIhIGkzMiBpMzIgaTMyIGkzMiA8SERDPnB0ciBpMzIgaTMyIHUzMkBSYXN0ZXJPcCAtPiBpMzIiKSx1ZT16KCJHZXRESUJpdHMiLCI8SERDPnB0ciEgPEhHRElPQko+cHRyIHUzMiB1MzIgPEJZVEU+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKTt2YXIgUT16KCJEZWxldGVEQyIsIjxIREM+cHRyISAtPiBpMzIiKTt2YXIgdmU9KHQsZSk9PkcoIm50ZGxsLmRsbCIsdCxlKSxsZT12ZSgiUnRsR2V0VmVyc2lvbiIsIjxPU1ZFUlNJT05JTkZPXzE0OD5wdHIgLT4gaTMyIik7dmFyIG1lPXQ9Pnt0cnl7bGV0IGU9eGUub3BlbigiZGlhZy5sb2ciLCJhIik7ZSYmKGUucHV0cyhgJHtEYXRlLm5vdygpfSAke3R9CmApLGUuY2xvc2UoKSl9Y2F0Y2h7fX0seXQ9MSxqZT0yNTYsSmU9NDI5NDk2NzI5NSxGPWZlLldvcmtlci5wYXJlbnQsd2U9IkM6XFxXaW5kb3dzXFxTeXN0ZW0zMiI7dHJ5e2xldCB0PUIuYWxsb2MoMjU2KSxyPVF0KHQsMjU2KT4wP0IuZGVjb2RlKHQpOiIiO3ImJih3ZT1yKX1jYXRjaCh0KXttZSgiU1lTLURJUi1GQUlMOiAiK1N0cmluZyh0KSl9dmFyIGhlPSExO3RyeXtsZXQgdD1zdC5lbmNvZGUoe2R3T1NWZXJzaW9uSW5mb1NpemU6c3Quc2l6ZX0pO2xlKHQucHRyKT09PTAmJihoZT1zdC5kZWNvZGUodCkuZHdNYWpvclZlcnNpb24+PTEwKX1jYXRjaCh0KXttZSgiVkVSLUZBSUw6ICIrU3RyaW5nKHQpKX12YXIgRnQ9ZygiUElQRV9IQU5ETEVTIix7aFJlYWQ6IjxIRklMRT5wdHIhIixoV3JpdGU6IjxIRklMRT5wdHIhIn0pO2Z1bmN0aW9uIEtlKHQsZSl7bGV0IHI9RnQuYWxsb2MoKTtpZighSnQoci5wdHIsci5wdHIrRnQub2Zmc2V0T2YoImhXcml0ZSIpLEksMCkpdGhyb3cgbmV3IEVycm9yKCJDcmVhdGVQaXBlIGVycj0iK2d0KCkpO2xldHtoUmVhZDpvLGhXcml0ZTpufT1GdC5kZWNvZGUocik7U3Qobix5dCx5dCksU3Qobyx5dCwwKTtsZXQgaT1DdC5hbGxvYygpLHM9YCR7d2V9XFxjbWQuZXhlICR7aGU/Ii91ICI6IiJ9L2MgJHtlfWA7aWYoIUt0KEkscyxJLEksMSwwLEksSSx7Y2I6bnQuc2l6ZSxkd0ZsYWdzOmplLGhTdGRPdXRwdXQ6bixoU3RkRXJyb3I6bn0saS5wdHIpKXRocm93IFUobyksVShuKSxuZXcgRXJyb3IoIkNyZWF0ZVByb2Nlc3NXIGVycj0iK2d0KCkrIiBjbWQ9IitzKTtsZXR7aFByb2Nlc3M6cCxoVGhyZWFkOmEsZHdQcm9jZXNzSWQ6dX09Q3QuZGVjb2RlKGkpO1UoYSksVShuKSxGLnBvc3RNZXNzYWdlKHt0eXBlOiJpbmZvIixpZDp0LHBpZDp1fSk7bGV0IHg9bmV3IGIoNDA5NiksZD1uZXcgVWludDhBcnJheSh4KSx3PW5ldyBiKDQpLGY9bmV3IFVpbnQzMkFycmF5KHcpO2Zvcig7ZlswXT0wLCEhcXQobyx4LDQwOTYsdyxJKTspe2xldCBsPWZbMF07aWYobD09PTApYnJlYWs7Ri5wb3N0TWVzc2FnZSh7dHlwZToiZGF0YSIsaWQ6dCxjaHVuazpkLnNsaWNlKDAsbCl9KX1YdChwLEplKTtsZXQgUz1uZXcgYig0KSxtPW5ldyBJbnQzMkFycmF5KFMpO1p0KHAsUyk7bGV0IFc9bVswXTtyZXR1cm4gVShvKSxVKHApLFd9dmFyIENlPTEzMzY5Mzc2LFhlPTAsZGU9NjU1MzYsWmU9NGU3LGN0PTUxMixxZT0yZTQsSHQ9aXQuc2l6ZStKLnNpemU7ZnVuY3Rpb24gUWUodCxlLHIpe2xldCBvPWl0LmVuY29kZSh7YmZUeXBlOjE5Nzc4LGJmU2l6ZTpIdCt0LGJmT2ZmQml0czpIdH0pLG49Si5lbmNvZGUoe2JpU2l6ZTpKLnNpemUsYmlXaWR0aDplLGJpSGVpZ2h0Oi1yLGJpUGxhbmVzOjEsYmlCaXRDb3VudDozMixiaUNvbXByZXNzaW9uOjAsYmlTaXplSW1hZ2U6dCxiaVhQZWxzUGVyTWV0ZXI6MjgzNSxiaVlQZWxzUGVyTWV0ZXI6MjgzNX0pLGk9bmV3IFVpbnQ4QXJyYXkoSHQpO3JldHVybiBpLnNldChuZXcgVWludDhBcnJheShvKSwwKSxpLnNldChuZXcgVWludDhBcnJheShuKSxpdC5zaXplKSxpfWZ1bmN0aW9uIHRyKHQsZSxyLG8sbil7bGV0IGk9bmV3IGIobypuKjQpLGM9bmV3IFVpbnQ4QXJyYXkoaSkscz1KLmVuY29kZSh7YmlTaXplOkouc2l6ZSxiaVdpZHRoOm8sYmlIZWlnaHQ6LW4sYmlQbGFuZXM6MSxiaUJpdENvdW50OjMyLGJpU2l6ZUltYWdlOm8qbio0fSk7aWYodWUoZSxyLDAsbixpLHMucHRyLFhlKSE9PW4pcmV0dXJuITE7bGV0IGE9Yy5ieXRlTGVuZ3RoO0YucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6UWUoYSxvLG4pfSk7Zm9yKGxldCB1PTA7dTxhO3UrPWRlKUYucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6Yy5zbGljZSh1LE1hdGgubWluKHUrZGUsYSkpfSk7cmV0dXJuITB9ZnVuY3Rpb24gZXIodCxlLHIsbyxuLGksYyxzLHApe2xldCBhPWJ0KHQpLHU9YT9OdCh0LHIsbyk6MDtpZighYXx8IXUpcmV0dXJuIGEmJlEoYSksITE7bGV0IHg9cShhLHUpLHc9Y2UoZSxhLDApIT09MCYmSXQobiwwLDAscyxwLGEsaSxjLENlKSE9PTA7cmV0dXJuIHEoYSx4KSxUdCh1KSxRKGEpLHd9ZnVuY3Rpb24gU2UodCxlLHIsbyxuLGksYyxzLHAsYSl7aWYoIShzPjAmJnA+MCYmcypwPD1aZSkpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIHNpemUgaW52YWxpZCB3PSIrcysiIGg9IitwKTtpZihhIT09bnVsbCYmIShpPj0wJiZjPj0wJiZpK3M8PWUmJmMrcDw9cikpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGNyb3Agb3V0IG9mIHJhbmdlIGNyb3A9KCIraSsiLCIrYysiLCIrcysieCIrcCsiKSBmcmFtZT0iK2UrIngiK3IpO2xldCB1PXNlKEkpO2lmKCF1KXRocm93IG5ldyBFcnJvcigiR2V0REMoTlVMTCk9MFx1RkYxQVx1NjVFMFx1OEY5M1x1NTE2NVx1Njg0Q1x1OTc2Mlx1RkYwOFx1Nzg2RVx1OEJBNFx1NTcyOFx1NEVBNFx1NEU5MiBzZXNzaW9uIFx1NTQyRlx1NTJBOFx1RkYwQ1x1ODAwQ1x1OTc1RSBzc2hkL3NlcnZpY2VcdUZGMDkiKTtsZXQgeD1idCh1KSxkPXg/TnQodSxzLHApOjA7aWYoIXh8fCFkKXRocm93IHgmJlEoeCksV3QoSSx1KSxuZXcgRXJyb3IoIkNyZWF0ZUNvbXBhdGlibGVEQy9CaXRtYXAgZmFpbGVkIik7bGV0IHc9cSh4LGQpLGY9YT09PW51bGw/SXQoeCwwLDAscyxwLHUsbyxuLENlKSE9PTA6ZXIodSxhLGUscix4LGksYyxzLHApO3EoeCx3KTtsZXQgUz1mJiZ0cih0LHgsZCxzLHApO2lmKFR0KGQpLFEoeCksV3QoSSx1KSwhZil0aHJvdyBuZXcgRXJyb3IoImNhcHR1cmUgZmFpbGVkIG91dD0iK3MrIngiK3ArKGE9PT1udWxsPyIgYXQ9KCIrbysiLCIrbisiKSI6IiBod25kPSIrYSsiIGNyb3A9KCIraSsiLCIrYysiKSBmcmFtZT0iK2UrIngiK3IpKTtpZighUyl0aHJvdyBuZXcgRXJyb3IoIkdldERJQml0cyBzaG9ydCByZWFkIG91dD0iK3MrIngiK3ApO3JldHVybnt3aWR0aDpzLGhlaWdodDpwfX1mdW5jdGlvbiBycih0KXtsZXQgZT1fKDApLHI9XygxKTtpZihlPD0wfHxyPD0wKXRocm93IG5ldyBFcnJvcigiR2V0U3lzdGVtTWV0cmljcyB3PSIrZSsiIGg9IityKTtyZXR1cm4gU2UodCxlLHIsMCwwLDAsMCxlLHIsbnVsbCl9ZnVuY3Rpb24gb3IodCxlLHIsbyl7aWYobz09PSJzY3JlZW4iJiZFdChlKSE9PTApdGhyb3cgbmV3IEVycm9yKCJ3aW5kb3cgbWluaW1pemVkXHVGRjFBbW9kZT1zY3JlZW4gXHU1M0VBXHU0RjFBXHU2MjJBXHU1MjMwXHU1QjgzXHU0RTBCXHU2NUI5XHU3Njg0XHU2ODRDXHU5NzYyXHVGRjBDXHU2NTM5XHU3NTI4IG1vZGU9cHJpbnQiKTtsZXQgbj1QLmFsbG9jKCk7aWYoIUR0KGUsbi5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0V2luZG93UmVjdChod25kPSIrZSsiKT0wXHVGRjFBXHU3QTk3XHU1M0UzXHU0RTBEXHU1QjU4XHU1NzI4XHU2MjE2XHU1REYyXHU5NTAwXHU2QkMxIik7bGV0e2xlZnQ6aSx0b3A6YyxyaWdodDpzLGJvdHRvbTpwfT1QLmRlY29kZShuKSxhPXMtaSx1PXAtYyx4PTAsZD0wLHc9YSxmPXU7aWYocj09PSJjbGllbnQiKXtsZXQgVz1QLmFsbG9jKCk7aWYoIXJlKGUsVy5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0Q2xpZW50UmVjdChod25kPSIrZSsiKT0wIik7bGV0e2xlZnQ6bCx0b3A6RCxyaWdodDpFLGJvdHRvbTpDfT1QLmRlY29kZShXKTt3PUUtbCxmPUMtRDtsZXQgaD1qLmVuY29kZSh7eDowLHk6MH0pO2lmKCFwZShlLGgucHRyKSl0aHJvdyBuZXcgRXJyb3IoIkNsaWVudFRvU2NyZWVuKGh3bmQ9IitlKyIpPTAiKTtsZXQgVD1qLmRlY29kZShoKTt4PVQueC1pLGQ9VC55LWN9bGV0IFM9bz09PSJwcmludCI/MDppK3gsbT1vPT09InByaW50Ij8wOmMrZDtpZihvPT09InNjcmVlbiIpe2xldCBXPV8oNzYpLGw9Xyg3NyksRD1fKDc4KSxFPV8oNzkpLEM9TWF0aC5tYXgoUyxXKSxoPU1hdGgubWF4KG0sbCksVD1NYXRoLm1pbihTK3csVytEKSxIPU1hdGgubWluKG0rZixsK0UpO2lmKFQ8PUN8fEg8PWgpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGFyZWEgb3V0c2lkZSB2aXJ0dWFsIHNjcmVlbiBhdD0oIitTKyIsIittKyIsIit3KyJ4IitmKyIpIik7Uz1DLG09aCx3PVQtQyxmPUgtaH1yZXR1cm4gU2UodCxhLHUsUyxtLHgsZCx3LGYsbz09PSJwcmludCI/ZTpudWxsKX1mdW5jdGlvbiBucih0KXtsZXQgZT1bXSxyPV90KCI8SFdORD5wdHIgPD5wdHIgLT4gaTMyIixzPT4ocyYmZS5wdXNoKHMpLGUubGVuZ3RoPHFlPzE6MCkpO3RyeXthZShyLnB0cixJKX1maW5hbGx5e3IuZGlzcG9zZSgpfWxldCBvPVAuYWxsb2MoKSxuPUIuYWxsb2MoY3QpLGk9Qi5hbGxvYyhjdCksYz1bXTtmb3IobGV0IHMgb2YgZSlpZihEdChzLG8ucHRyKSl7bGV0IHA9UC5kZWNvZGUobyksYT1uZShzLG4sY3QpLHU9aWUocyxpLGN0KTtjLnB1c2goe2h3bmQ6cyx0aXRsZTphPjA/Qi5kZWNvZGUobik6IiIsY2xhc3NOYW1lOnU+MD9CLmRlY29kZShpKToiIixyZWN0OntsZWZ0OnAubGVmdCx0b3A6cC50b3AscmlnaHQ6cC5yaWdodCxib3R0b206cC5ib3R0b219LHZpc2libGU6b2UocykhPT0wLG1pbmltaXplZDpFdChzKSE9PTB9KX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQsY29kZTowLGVycm9yOm51bGwsd2luZG93czpjfSl9ZnVuY3Rpb24gaXIodCl7aWYodC50eXBlPT09InJ1biIpe2lmKHR5cGVvZiB0LmNtZCE9InN0cmluZyIpcmV0dXJuO2xldCBlPS0xLHI9bnVsbDt0cnl7ZT1LZSh0LmlkLHQuY21kKX1jYXRjaChvKXtyPVN0cmluZyhvKX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTplLGVycm9yOnJ9KTtyZXR1cm59aWYodC50eXBlPT09IndpbmRvd3MiKXt0cnl7bnIodC5pZCl9Y2F0Y2goZSl7Ri5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixpZDp0LmlkLGNvZGU6LTEsZXJyb3I6U3RyaW5nKGUpfSl9cmV0dXJufWlmKHQudHlwZT09PSJzY3JlZW5zaG90Iil0cnl7bGV0IGU9dC5od25kPz9udWxsLHt3aWR0aDpyLGhlaWdodDpvfT1lPT09bnVsbD9ycih0LmlkKTpvcih0LmlkLGUsdC5hcmVhPz8id2luZG93Iix0Lm1vZGU/PyJzY3JlZW4iKTtGLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTowLGVycm9yOm51bGwsd2lkdGg6cixoZWlnaHQ6b30pfWNhdGNoKGUpe0YucG9zdE1lc3NhZ2Uoe3R5cGU6InJlc3VsdCIsaWQ6dC5pZCxjb2RlOi0xLGVycm9yOlN0cmluZyhlKX0pfX1GLm9ubWVzc2FnZT10PT57aXIodC5kYXRhKSxGLm9ubWVzc2FnZT1udWxsfTsK");
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");
21914
22049
  bumpWorkers(1);
21915
22050
  const id = 1;
21916
22051
  let innerPid = null;
@@ -21954,9 +22089,9 @@ function runInWorker(cmd, signal, timeoutMs) {
21954
22089
  if (p2)
21955
22090
  p2.close();
21956
22091
  else
21957
- console.error("[exec_server] taskkill spawn failed");
22092
+ console.error("[execd] taskkill spawn failed");
21958
22093
  } catch (ex) {
21959
- console.error("[exec_server] kill error:", ex);
22094
+ console.error("[execd] kill error:", ex);
21960
22095
  }
21961
22096
  };
21962
22097
  const killOnAbort = () => {
@@ -22027,45 +22162,6 @@ function runInWorker(cmd, signal, timeoutMs) {
22027
22162
  }
22028
22163
  return { stream, ready, trailers, kill };
22029
22164
  }
22030
- var SCREENSHOT_TIMEOUT_MS = 3e4;
22031
- var WINDOWS_TIMEOUT_MS = 5e3;
22032
- function withWorker(timeoutMs, onTimeout, post, onData, onResult) {
22033
- return new Promise((resolve) => {
22034
- const worker = new os6.Worker("data:text/javascript;base64,aW1wb3J0KmFzIGZlIGZyb20ib3MiO2ltcG9ydCphcyB4ZSBmcm9tInN0ZCI7aW1wb3J0KmFzIHkgZnJvbSJmZmkiO2ltcG9ydCphcyBldCBmcm9tIm9zIjtpbXBvcnQqYXMgSyBmcm9tInN0ZCI7aW1wb3J0KmFzIHJ0IGZyb20id2luIjt2YXIgZ2U9eyJ1dGYtOCI6InV0Zi04Iix1dGY4OiJ1dGYtOCIsInVuaWNvZGUtMS0xLXV0Zi04IjoidXRmLTgiLCJ1dGYtMTYiOiJ1dGYtMTZsZSIsInV0Zi0xNmxlIjoidXRmLTE2bGUiLCJ1dGYtMTZiZSI6InV0Zi0xNmJlIn07ZnVuY3Rpb24gT3QodCl7aWYoIXQpcmV0dXJuInV0Zi04IjtsZXQgZT1nZVt0LnRyaW0oKS50b0xvd2VyQ2FzZSgpXTtpZihlKXJldHVybiBlO3Rocm93IG5ldyBSYW5nZUVycm9yKGBUaGUgZW5jb2RpbmcgbGFiZWwgIiR7dH0iIGlzIG5vdCBzdXBwb3J0ZWRgKX1mdW5jdGlvbiBEZSh0LGUpe2xldCByPSIiO2ZvcihsZXQgbz0wO288dC5sZW5ndGg7KXtsZXQgbj10W28rK107aWYobjwxMjgpe3IrPVN0cmluZy5mcm9tQ2hhckNvZGUobik7Y29udGludWV9aWYobjwxOTIpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigidW5leHBlY3RlZCBjb250aW51YXRpb24gYnl0ZSIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1sZXQgaSxjO2lmKG48MjI0KXtpZihvPj10Lmxlbmd0aCl7cis9ZT8oKCk9Pnt0aHJvdyBuZXcgVHlwZUVycm9yKCJpbmNvbXBsZXRlIHV0Zi04Iil9KSgpOiJcdUZGRkQiO2JyZWFrfWxldCBzPXRbbysrXTtpZigocyYxOTIpIT09MTI4KXtyKz0iXHVGRkZEIjtjb250aW51ZX1pPShuJjMxKTw8NnxzJjYzLGM9MTI4fWVsc2UgaWYobjwyNDApe2lmKG8rMT49dC5sZW5ndGgpe3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW5jb21wbGV0ZSB1dGYtOCIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz10W28rK10scD10W28rK107aWYoKHMmMTkyKSE9PTEyOHx8KHAmMTkyKSE9PTEyOCl7cis9Ilx1RkZGRCI7Y29udGludWV9aT0obiYxNSk8PDEyfChzJjYzKTw8NnxwJjYzLGM9MjA0OH1lbHNlIGlmKG48MjQ4KXtpZihvKzI+PXQubGVuZ3RoKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImluY29tcGxldGUgdXRmLTgiKX0pKCk6Ilx1RkZGRCI7YnJlYWt9bGV0IHM9dFtvKytdLHA9dFtvKytdLGE9dFtvKytdO2lmKChzJjE5MikhPT0xMjh8fChwJjE5MikhPT0xMjh8fChhJjE5MikhPT0xMjgpe3IrPSJcdUZGRkQiO2NvbnRpbnVlfWk9KG4mNyk8PDE4fChzJjYzKTw8MTJ8KHAmNjMpPDw2fGEmNjMsYz02NTUzNn1lbHNle3IrPWU/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCB1dGYtOCBzdGFydCIpfSkoKToiXHVGRkZEIjtjb250aW51ZX1pZihpPGN8fGk+PTU1Mjk2JiZpPD01NzM0M3x8aT4xMTE0MTExKXtyKz1lPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoImludmFsaWQgdXRmLTggY29kZXBvaW50Iil9KSgpOiJcdUZGRkQiO2NvbnRpbnVlfWk8PTY1NTM1P3IrPVN0cmluZy5mcm9tQ2hhckNvZGUoaSk6KGktPTY1NTM2LHIrPVN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTZ8aT4+MTAsNTYzMjB8aSYxMDIzKSl9cmV0dXJuIHJ9ZnVuY3Rpb24gRWUodCxlLHIpe2xldCBvPW5ldyBEYXRhVmlldyh0LmJ1ZmZlcix0LmJ5dGVPZmZzZXQsdC5ieXRlTGVuZ3RoKSxuPSIiO2ZvcihsZXQgaT0wO2krMTx0Lmxlbmd0aDtpKz0yKXtsZXQgYz1vLmdldFVpbnQxNihpLGUpO2lmKGM+PTU1Mjk2JiZjPD01NjMxOSl7aWYoaSs9MixpKzE+PXQubGVuZ3RoKXtuKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInRydW5jYXRlZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIjticmVha31sZXQgcz1vLmdldFVpbnQxNihpLGUpO3M+PTU2MzIwJiZzPD01NzM0Mz9uKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMscyk6KG4rPXI/KCgpPT57dGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCBzdXJyb2dhdGUgcGFpciIpfSkoKToiXHVGRkZEIixpLT0yKX1lbHNlIGM+PTU2MzIwJiZjPD01NzM0Mz9uKz1yPygoKT0+e3Rocm93IG5ldyBUeXBlRXJyb3IoInVuZXhwZWN0ZWQgdHJhaWxpbmcgc3Vycm9nYXRlIil9KSgpOiJcdUZGRkQiOm4rPVN0cmluZy5mcm9tQ2hhckNvZGUoYyl9cmV0dXJuIG59dmFyIHB0PWNsYXNze19lbmNvZGluZztfZmF0YWw7X2lnbm9yZUJPTTtjb25zdHJ1Y3RvcihlLHIpe3RoaXMuX2VuY29kaW5nPU90KGUpLHRoaXMuX2ZhdGFsPXI/LmZhdGFsPz8hMSx0aGlzLl9pZ25vcmVCT009cj8uaWdub3JlQk9NPz8hMX1nZXQgZW5jb2RpbmcoKXtyZXR1cm4gdGhpcy5fZW5jb2Rpbmd9Z2V0IGZhdGFsKCl7cmV0dXJuIHRoaXMuX2ZhdGFsfWdldCBpZ25vcmVCT00oKXtyZXR1cm4gdGhpcy5faWdub3JlQk9NfWRlY29kZShlKXtpZighZSlyZXR1cm4iIjtsZXQgcj1lIGluc3RhbmNlb2YgVWludDhBcnJheT9lOmUgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcj9uZXcgVWludDhBcnJheShlKTpuZXcgVWludDhBcnJheShlLmJ1ZmZlcixlLmJ5dGVPZmZzZXQsZS5ieXRlTGVuZ3RoKTtpZih0aGlzLl9lbmNvZGluZz09PSJ1dGYtOCIpcmV0dXJuIERlKHIsdGhpcy5fZmF0YWwpO2xldCBvPXRoaXMuX2VuY29kaW5nPT09InV0Zi0xNmxlIixuPTA7aWYoci5sZW5ndGg+PTImJiF0aGlzLl9pZ25vcmVCT00pe2xldCBpPW8/clswXTpyWzFdLHM9KG8/clsxXTpyWzBdKTw8OHxpOyhzPT09NjUyNzl8fHM9PT02NTUzNCkmJihuPTIpfXJldHVybiBFZShyLnNsaWNlKG4pLG8sdGhpcy5fZmF0YWwpfX0sYXQ9Y2xhc3N7X2VuY29kaW5nO2NvbnN0cnVjdG9yKGUpe3RoaXMuX2VuY29kaW5nPU90KGUpfWdldCBlbmNvZGluZygpe3JldHVybiB0aGlzLl9lbmNvZGluZ31lbmNvZGUoZSl7aWYoIWUpcmV0dXJuIG5ldyBVaW50OEFycmF5KDApO2lmKHRoaXMuX2VuY29kaW5nPT09InV0Zi04Iil7bGV0IGk9W107Zm9yKGxldCBjPTA7YzxlLmxlbmd0aDtjKyspe2xldCBzPWUuY2hhckNvZGVBdChjKTtpZihzPDEyOClpLnB1c2gocyk7ZWxzZSBpZihzPDIwNDgpaS5wdXNoKDE5MnxzPj42LDEyOHxzJjYzKTtlbHNlIGlmKHM8NTUyOTZ8fHM+PTU3MzQ0KWkucHVzaCgyMjR8cz4+MTIsMTI4fHM+PjYmNjMsMTI4fHMmNjMpO2Vsc2V7YysrO2xldCBwPWUuY2hhckNvZGVBdChjKTtzPTY1NTM2KygocyYxMDIzKTw8MTApfHAmMTAyMyxpLnB1c2goMjQwfHM+PjE4LDEyOHxzPj4xMiY2MywxMjh8cz4+NiY2MywxMjh8cyY2Myl9fXJldHVybiBuZXcgVWludDhBcnJheShpKX1sZXQgcj10aGlzLl9lbmNvZGluZz09PSJ1dGYtMTZsZSIsbz1uZXcgQXJyYXlCdWZmZXIoZS5sZW5ndGgqMiksbj1uZXcgRGF0YVZpZXcobyk7Zm9yKGxldCBpPTA7aTxlLmxlbmd0aDtpKyspbi5zZXRVaW50MTYoaSoyLGUuY2hhckNvZGVBdChpKSxyKTtyZXR1cm4gbmV3IFVpbnQ4QXJyYXkobyl9fTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RGVjb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHREZWNvZGVyPXB0KTt0eXBlb2YgZ2xvYmFsVGhpcy5UZXh0RW5jb2Rlcj4idSImJihnbG9iYWxUaGlzLlRleHRFbmNvZGVyPWF0KTtpbXBvcnR7YnVmZmVyUHRyIGFzIFdlfWZyb20iZmZpIjtpbXBvcnQqYXMgUnQgZnJvbSJvcyI7dmFyIFRlPVsidm9pZCIsInU4IiwiaTgiLCJ1MTYiLCJpMTYiLCJ1MzIiLCJpMzIiLCJ1NjQiLCJpNjQiLCJmMzIiLCJmNjQiLCJwdHIiXSx1dD0vXjwoW0EtWmEtel9dXHcqfCk+cHRyKCF8QFtBLVphLXpfXVx3Kik/JC87ZnVuY3Rpb24gUih0KXtyZXR1cm4gdXQudGVzdCh0KX12YXIgQXQ9L148KFtBLVphLXpfXVx3Kik+JC87ZnVuY3Rpb24gTSh0KXtyZXR1cm4gQXQudGVzdCh0KX1mdW5jdGlvbiBrKHQpe3JldHVybiBBdC5leGVjKHQpPy5bMV18fCIifWZ1bmN0aW9uIGx0KHQpe3JldHVybiB1dC5leGVjKHQpPy5bMV18fCIifXZhciB0dD10PT57aWYoUih0KSlyZXR1cm4icHRyIjtpZihNKHQpKXRocm93IG5ldyBFcnJvcihgZmZpOiBjVG9rZW5Ub1R5cGU6IGJ5LXZhbHVlIHRva2VuICIke3R9IiBoYXMgbm8gc2NhbGFyIHNsb3QgdHlwZWApO3JldHVybiB0fSxBPVJ0LmFyY2g9PT0ieDY0Ij84OjQsJD17dTg6MSxpODoxLHUxNjoyLGkxNjoyLHUzMjo0LGkzMjo0LHU2NDo4LGk2NDo4LGYzMjo0LGY2NDo4fSxJPTA7ZnVuY3Rpb24gWSh0KXtpZihSKHQpKXtsZXQgbj11dC5leGVjKHQpLGk9bj8uWzFdfHwiIjtyZXR1cm4gbj8uWzJdPy5zdGFydHNXaXRoKCJAIik/YDwke2l9PnB0cmA6dH1pZihNKHQpKXJldHVybiB0O2xldCBlPXQuaW5kZXhPZigiQCIpLHI9ZT49MD90LnNsaWNlKDAsZSk6dDtpZigoZTwwfHwvXltBLVphLXpfXVx3KiQvLnRlc3QodC5zbGljZShlKzEpKSkmJnIhPT0icHRyIiYmVGUuaW5jbHVkZXMocikpcmV0dXJuIHI7dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIHRva2VuOiAiK3QpfWZ1bmN0aW9uIFYodCxlLHIpe3N3aXRjaChyKXtjYXNlInU4IjpyZXR1cm4gdC5nZXRVaW50OChlKTtjYXNlImk4IjpyZXR1cm4gdC5nZXRJbnQ4KGUpO2Nhc2UidTE2IjpyZXR1cm4gdC5nZXRVaW50MTYoZSwhMCk7Y2FzZSJpMTYiOnJldHVybiB0LmdldEludDE2KGUsITApO2Nhc2UidTMyIjpyZXR1cm4gdC5nZXRVaW50MzIoZSwhMCk7Y2FzZSJpMzIiOnJldHVybiB0LmdldEludDMyKGUsITApO2Nhc2UidTY0IjpyZXR1cm4gdC5nZXRCaWdVaW50NjQoZSwhMCk7Y2FzZSJpNjQiOnJldHVybiB0LmdldEJpZ0ludDY0KGUsITApO2Nhc2UiZjMyIjpyZXR1cm4gdC5nZXRGbG9hdDMyKGUsITApO2Nhc2UiZjY0IjpyZXR1cm4gdC5nZXRGbG9hdDY0KGUsITApO2Nhc2UicHRyIjpyZXR1cm4gQT09PTg/TnVtYmVyKHQuZ2V0QmlnSW50NjQoZSwhMCkpOnQuZ2V0SW50MzIoZSwhMCl9fWZ1bmN0aW9uIGR0KHQsZSx7azpyLHY6b30pe3N3aXRjaChyKXtjYXNlInU4Ijp0LnNldFVpbnQ4KGUsTnVtYmVyKG8pKTticmVhaztjYXNlImk4Ijp0LnNldEludDgoZSxOdW1iZXIobykpO2JyZWFrO2Nhc2UidTE2Ijp0LnNldFVpbnQxNihlLE51bWJlcihvKSwhMCk7YnJlYWs7Y2FzZSJpMTYiOnQuc2V0SW50MTYoZSxOdW1iZXIobyksITApO2JyZWFrO2Nhc2UidTMyIjp0LnNldFVpbnQzMihlLG8+Pj4wLCEwKTticmVhaztjYXNlImkzMiI6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWs7Y2FzZSJ1NjQiOnQuc2V0QmlnVWludDY0KGUsbywhMCk7YnJlYWs7Y2FzZSJpNjQiOnQuc2V0QmlnSW50NjQoZSxvLCEwKTticmVhaztjYXNlImYzMiI6dC5zZXRGbG9hdDMyKGUsbywhMCk7YnJlYWs7Y2FzZSJmNjQiOnQuc2V0RmxvYXQ2NChlLG8sITApO2JyZWFrO2Nhc2UicHRyIjp7aWYobz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoImZmaTogZ290IG51bGwvdW5kZWZpbmVkIGZvciBhIHB0ciBzbG90OyBwYXNzIHRoZSBpbXBvcnRlZCBOVUxMIGNvbnN0YW50IGZvciBlbXB0eSIpO0E9PT04P3Quc2V0QmlnVWludDY0KGUsQmlnSW50LmFzVWludE4oNjQsQmlnSW50KG8pKSwhMCk6dC5zZXRVaW50MzIoZSxvPj4+MCwhMCk7YnJlYWt9fX1mdW5jdGlvbiB2KHQsZSxyKXtsZXR7azpvLHY6bn09cjtpZihvPT09InU4Inx8bz09PSJpOCJ8fG89PT0idTE2Inx8bz09PSJpMTYiKXt0LnNldFVpbnQzMihlLE51bWJlcihuKT4+PjAsITApO3JldHVybn1kdCh0LGUscil9dmFyIGI9Y2xhc3MgZXh0ZW5kcyBBcnJheUJ1ZmZlcntwdHI7Y29uc3RydWN0b3IoZSl7c3VwZXIoZSksdGhpcy5wdHI9V2UodGhpcyl9fTtmdW5jdGlvbiBmdCh0LGUpe3JldHVybiBlW3RdfXZhciBCdD1uZXcgTWFwO2Z1bmN0aW9uIGJlKHQpe2xldCBlPUJ0LmdldCh0KTtpZihlIT09dm9pZCAwKXJldHVybiBlO2xldCByPXJ0LkxvYWRMaWJyYXJ5KHQpO2lmKCFyKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IExvYWRMaWJyYXJ5KCIke3R9IikgZmFpbGVkYCk7cmV0dXJuIEJ0LnNldCh0LHIpLHJ9ZnVuY3Rpb24gVXQodCl7bGV0IGU9dC5zcGxpdCgiIC0+ICIpO2lmKGUubGVuZ3RoIT09Mil0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBpbnZhbGlkIHNpZ25hdHVyZSAiJHt0fSIgKGV4cGVjdGVkICJhcmcxIGFyZzIgLT4gcmV0IilgKTtsZXQgcj1lWzBdLnNwbGl0KCIgIikuZmlsdGVyKGk9PmkhPT0iIiksbz1bXTtmb3IobGV0IGkgb2Ygcil7bGV0IGM9WShpKTtpZihjPT09InZvaWQiKXRocm93IG5ldyBFcnJvcigiVm9pZCBjYW4gbm90IGluIGFyZ3MiKTtvLnB1c2goYyl9bGV0IG49WShlWzFdKTtpZihNKG4pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICIke3R9IjogYnktdmFsdWUgc3RydWN0IGF0IHRoZSByZXR1cm4gcG9zaXRpb24gKDwke2sobil9PikgaXMgbm90IHN1cHBvcnRlZCBcdTIwMTQgYXJndW1lbnQgcG9zaXRpb25zIG9ubHk7IHBhc3MgYSBzdHJ1Y3Qgb3V0IHRocm91Z2ggYW4gb3V0LXBhcmFtIHNsb3QgaW5zdGVhZCAoPE4+cHRyICsgY2FsbGVyIGJ1ZmZlcilgKTtyZXR1cm57YXJnVG9rZW5zOm8scmV0VG9rZW46bixzaWc6dH19ZnVuY3Rpb24gTmUodCxlLHIsbyl7bGV0IG49VXQoZSk7Zm9yKGxldCBpIG9mIG4uYXJnVG9rZW5zKXtpZighTShpKSljb250aW51ZTtsZXQgYz1rKGkpLHM9ZnQoYyxyKTtpZighc3x8dHlwZW9mIHMuZW5jb2RlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7ZX06IGJ5LXZhbHVlIHBvc2l0aW9uIDwke2N9PiBoYXMgbm8gcmVnaXN0ZXJlZCBsYXlvdXQgKGF2YWlsYWJsZTogJHtPYmplY3Qua2V5cyhyKS5qb2luKCIsICIpfHwibm9uZSJ9KWApO2lmKHR5cGVvZiBzLnNpemUhPSJudW1iZXIifHxzLnNpemU8MSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiAke2V9OiBieS12YWx1ZSBwb3NpdGlvbiA8JHtjfT4gcmVxdWlyZXMgYSBzdHJ1Y3QgbGF5b3V0IHdpdGggc2l6ZSA+PSAxIChnb3QgJHtzLnNpemV9OyBub24tc3RydWN0IGNvZGVjcyBleHBvc2Ugbm8gc2l6ZSlgKX1yZXR1cm4oLi4uaSk9PkllKHQsbixpLHIsbyl9dmFyIHh0PXt1ODo0LGk4OjQsdTE2OjQsaTE2OjQsdTMyOjQsaTMyOjQsdTY0OjgsaTY0OjgsZjMyOjQsZjY0OjgscHRyOkF9LEd0PTQ7ZnVuY3Rpb24gSWUodCx7YXJnVG9rZW5zOmUscmV0VG9rZW46cixzaWc6b30sbixpLGMpe2xldCBzPWV0LmFyY2g9PT0ieDY0IixwPShsLEQpPT57aWYoTShsKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBnZXRXaWR0aDogYnktdmFsdWUgdG9rZW4gIiR7bH0iIChkaXNwYXRjaGVkIGJ5IHdpZHRoT2YpYCk7cmV0dXJuIEQ/ODpSKGwpP0E6eHRbbF19LGE9bD0+e2lmKE0obCkpe2lmKHMpcmV0dXJuIDg7bGV0IEQ9ZnQoayhsKSxpKTtpZighRCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtrKGwpfT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7bGV0IEU9RC5zaXplO3JldHVybiBFJTQ9PT0wP0U6RSs0LUUlNH1yZXR1cm4gcChsLHMpfSx1PTA7Zm9yKGxldCBsIG9mIGUpdSs9YShsKTtzJiZlLmxlbmd0aDxHdCYmKHU9R3QqOCk7bGV0IHg9bmV3IEFycmF5QnVmZmVyKHUpLGQ9bmV3IERhdGFWaWV3KHgpLHc9W10sZj0wO2ZvcihsZXQgbD0wO2w8ZS5sZW5ndGg7bCsrKXtsZXQgRD1lW2xdLEU9RC5lbmRzV2l0aCgiISIpLEM9bltsXTtpZihSKEQpKXtsZXQgaD1sdChEKTtpZih0eXBlb2YgQz09Im51bWJlciIpe2lmKEUmJkM9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IGFyZyMke2wrMX0gPCR7aH0+cHRyISBnb3QgMCAobnVsbCBwb2ludGVyIGZvcmJpZGRlbiBoZXJlOyB0aGUgdG9rZW4gbWFya3MgdGhpcyBwb3NpdGlvbiBub24tbnVsbClgKTt2KGQsZix7azoicHRyIix2OkN9KX1lbHNle2lmKEM9PW51bGwpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogPCR7aH0+cHRyIGdvdCAke1N0cmluZyhDKX07IHBhc3MgdGhlIGltcG9ydGVkIE5VTEwgY29uc3RhbnQgZm9yIGFuIGVtcHR5IHBvaW50ZXJgKTtsZXQgVD1pW2hdO2lmKCFUKXRocm93IG5ldyBFcnJvcihoPT09IiI/YGZmaS1iaW5kOiA8PnB0ciBleHBlY3RzIG51bWJlciAoTlVMTCB8IFB0ciksIGdvdCAke3R5cGVvZiBDfTsgdXNlIDxCWVRFPnB0ciB3aXRoIGEgUHRyQXJyYXlCdWZmZXIgKG5ldyBQdHJBcnJheUJ1ZmZlcihuKSksIG9yIGZmaS5idWZmZXJQdHIoYnVmKSBmb3IgYW4gYWRkcmVzc2A6YGZmaS1iaW5kOiB1bmtub3duIGxheW91dCAiPCR7aH0+cHRyIiAoYXZhaWxhYmxlOiAke09iamVjdC5rZXlzKGkpLmpvaW4oIiwgIil8fCJub25lIn0pYCk7aWYoIVQuZW5jb2RlKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IDwke2h9PnB0ciBoYXMgbm8gZW5jb2RlciAob3V0LW9ubHkgY29kZWMpYCk7bGV0IEg9VC5lbmNvZGUoQyk7dy5wdXNoKEgpO2xldCBMPUgucHRyO2lmKHR5cGVvZiBMIT0ibnVtYmVyIil0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiBjb2RlYy5lbmNvZGUgbXVzdCByZXR1cm4gYSBQdHJBcnJheUJ1ZmZlciwgZ290IHBsYWluIEFycmF5QnVmZmVyIik7aWYoRSYmTD09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT5wdHIhIGVuY29kZSBwcm9kdWNlZCAwIChudWxsIHBvaW50ZXIgZm9yYmlkZGVuIGhlcmUpYCk7dihkLGYse2s6InB0ciIsdjpMfSl9fWVsc2UgaWYoTShEKSl7bGV0IGg9ayhEKSxUPWZ0KGgsaSk7aWYoIVQpdGhyb3cgbmV3IEVycm9yKGBmZmktYmluZDogJHtvfTogYXJnIyR7bCsxfSA8JHtofT4gYnktdmFsdWUgcG9zaXRpb24gaGFzIG5vIHJlZ2lzdGVyZWQgbGF5b3V0YCk7aWYoQz09bnVsbCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiA8JHtofT4gdmFsdWUgcG9zaXRpb24gZ290ICR7U3RyaW5nKEMpfTsgcGFzcyBhIHN0cnVjdCBvYmplY3QgKHVzZSA8JHtofT5wdHIgdG8gcGFzcyBhIHBvaW50ZXIpYCk7bGV0IEg9VC5zaXplO2lmKCFzfHxIPD04JiYoSCZILTEpPT09MClULmVuY29kZShDLHgsZik7ZWxzZXtsZXQgTD1uZXcgQXJyYXlCdWZmZXIoSCsxNSksUHQ9eS5idWZmZXJQdHIoTCksTXQ9KDE2LVB0JTE2KSUxNjtULmVuY29kZShDLEwsTXQpLHcucHVzaChMKSx2KGQsZix7azoicHRyIix2OlB0K010fSl9fWVsc2UgdihkLGYse2s6RCx2OkN9KTtmKz1hKEQpfWxldCBTPW5ldyBBcnJheUJ1ZmZlcig4KTt5LmZmaUNhbGwodCx4LFMscj09PSJmMzIifHxyPT09ImY2NCI/MTowKTtsZXQgVz15ZSh0dChyKSxTKTtpZihyLmVuZHNXaXRoKCIhIikmJlc9PT0wKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6ICR7b306IHJldHVybiAke3J9IGdvdCAwICh0aGUgdG9rZW4gcHJvbWlzZXMgQyBuZXZlciByZXR1cm5zIG51bGwgaGVyZSlgKTtpZihSKHIpJiZXIT09MCl7bGV0IGw9bHQocik7aWYobCE9PSIiKXtsZXQgRD1jW2xdO2lmKEQ/LmRlY29kZSlyZXR1cm4gRC5kZWNvZGUoVyl9fXJldHVybiBXfWZ1bmN0aW9uIHllKHQsZSl7aWYodCE9PSJ2b2lkIilyZXR1cm4gVihuZXcgRGF0YVZpZXcoZSksMCx0KX12YXIgQj17ZW5jb2RlOnQ9PntsZXQgZT1uZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIikuZW5jb2RlKHQrIlwwIikscj1uZXcgYihlLmJ5dGVMZW5ndGgpO3JldHVybiBuZXcgVWludDhBcnJheShyKS5zZXQoZSkscn0sZGVjb2RlOnQ9PntpZih0eXBlb2YgdD09Im51bWJlciIpe2xldCBuPSIiLGk9dCxjPWk7Zm9yKDs7KXtsZXQgcz15LnJlYWRCeXRlKGkpLHA9eS5yZWFkQnl0ZShpKzEpO2lmKHM9PT0wJiZwPT09MClyZXR1cm4gbjtpZihuKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHN8cDw8OCksaSs9MixpLWM+MTw8MjEpdGhyb3cgbmV3IEVycm9yKCJmZmktYmluZDogV0NIQVIgZGVjb2RlIGV4Y2VlZGVkIDRNaUIgd2l0aG91dCBOVUwiKX19bGV0IGU9bmV3IFVpbnQ4QXJyYXkodCkscj1lLmxlbmd0aCYtMixvPSIiO2ZvcihsZXQgbj0wO248cjtuKz0yKXtsZXQgaT1lW25dfGVbbisxXTw8ODtpZihpPT09MClyZXR1cm4gbztvKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGkpfXJldHVybiBvfSxhbGxvYzoodD0yNTYpPT5uZXcgYih0KjIpfSxGZT17ZW5jb2RlOnQ9PntpZighKHQgaW5zdGFuY2VvZiBiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1iaW5kOiA8QllURT5wdHIgd2FudHMgYSBQdHJBcnJheUJ1ZmZlciAobmV3IFB0ckFycmF5QnVmZmVyKG4pIC8gQllURS5hbGxvYyAvIHN0cnVjdC5lbmNvZGUpLCBub3QgYSBwbGFpbiBBcnJheUJ1ZmZlciIpO3JldHVybiB0fSxhbGxvYzp0PT5uZXcgYih0KX0sTHQ9e1dDSEFSOkIsQllURTpGZX07ZnVuY3Rpb24gRyh0LGUscixvLG4pe2xldCBpPXJ0LkdldFByb2NBZGRyZXNzKGJlKHQpLGUpO2lmKCFpKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IHByb2MgIiR7ZX0iIG5vdCBmb3VuZCBpbiAke3R9YCk7bGV0IGM9bj8/bztyZXR1cm4gTmUoaSxyLHsuLi5MdCwuLi5vfSx7Li4uTHQsLi4uYz8/e319KX12YXIga3Q9bmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KHQ9PntLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSBsZWFrZWQgKEdDZWQgd2l0aG91dCBkaXNwb3NlKTogc2lnPSIlcyIgcHRyPTB4JXgKYCx0LnNpZyx0LnB0cil9KTtmdW5jdGlvbiBIZSh0LGUscixvLG4saSl7bGV0IGM9bmV3IERhdGFWaWV3KG4pLHM9ZXQuYXJjaD09PSJ4NjQiLHA9bmV3IERhdGFWaWV3KG8pLGE9W10sdT0wO2ZvcihsZXQgZD0wO2Q8dC5sZW5ndGg7ZCsrKXtsZXQgdz10W2RdLGY9dy50b2ssUztpZihzKXtsZXQgVz1mPT09ImYzMiJ8fGY9PT0iZjY0Ij9kPDQ/MTI4K2QqODozMisoZC00KSo4OmQ8ND9kKjg6MzIrKGQtNCkqODtTPVYocCxXLGYpfWVsc2UgUz1WKHAsdSxmKSx1Kz14dFtmXTtpZih3Lm5vbm51bGwmJlM9PT0wKXtLLnByaW50ZihgW2ZmaV0gY2xvc3VyZSAlczogYXJnIyVkIGdvdCAwICghIHByb21pc2UgdmlvbGF0ZWQgYnkgY2FsbGVyKSwgc2tpcHBpbmcgY2FsbGJhY2sKYCxpLGQrMSk7cmV0dXJufWEucHVzaChTKX1sZXQgeDt0cnl7eD1yKC4uLmEpfWNhdGNoKGQpe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlIGNhbGxiYWNrIHRocmV3OiAlcwpgLFN0cmluZyhkKSk7cmV0dXJufWlmKGUubm9ubnVsbCYmeD09PTApe0sucHJpbnRmKGBbZmZpXSBjbG9zdXJlICVzOiByZXR1cm4gZ290IDAgKCEgcHJvbWlzZSB2aW9sYXRlZCBieSBjYWxsYmFjayksIGxlYXZpbmcgcmVzdWx0IHNsb3QgMApgLGkpO3JldHVybn1lLnRvayE9PSJ2b2lkIiYmdihjLDAse2s6ZS50b2ssdjp4fSl9ZnVuY3Rpb24gX3QodCxlLHIpe2xldHthcmdUb2tlbnM6byxyZXRUb2tlbjpufT1VdCh0KTtmb3IobGV0IG0gb2YgbylpZihNKG0pKXRocm93IG5ldyBFcnJvcihgZmZpLWJpbmQ6IGNsb3N1cmUgc2lnbmF0dXJlIGNhbm5vdCB0YWtlIGEgYnktdmFsdWUgc3RydWN0ICg8JHtrKG0pfT4pOyBieS12YWx1ZSBpcyBiaW5kLW9ubHkgXHUyMDE0IHRoZSBDXHUyMTkySlMgZGlyZWN0aW9uIGhhcyBubyBzdHJ1Y3Qgc2xvdCBkZWNvZGluZyAocGFzcyBhIHBvaW50ZXIgYW5kIGRlY29kZSBvbiB0aGUgSlMgc2lkZSlgKTtsZXQgaT1vLm1hcChtPT4oe3Rvazp0dChtKSxub25udWxsOm0uZW5kc1dpdGgoIiEiKX0pKSxjPXt0b2s6dHQobiksbm9ubnVsbDpuLmVuZHNXaXRoKCIhIil9LHM9ZXQuYXJjaD09PSJ4NjQiLHA9aS5yZWR1Y2UoKG0sVyk9Pm0reHRbVy50b2tdLDApO2lmKHM/aS5sZW5ndGg+MTY6cD42NCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1iaW5kOiBjbG9zdXJlIHNpZ25hdHVyZSBleGNlZWRzIGNhcHR1cmUgd2luZG93ICgke3M/Im1heCAxNiBwYXJhbXMiOiJtYXggNjQgc3RhY2sgYnl0ZXMifSk6ICR7dH1gKTtsZXQgYT1yPy5zdGRjYWxsPT09ITF8fHM/MDpwLHU9Yy50b2s9PT0iZjMyIj8xOmMudG9rPT09ImY2NCI/MjpjLnRvaz09PSJ1NjQifHxjLnRvaz09PSJpNjQiPzM6MCxkPXkuY2xvc3VyZU5ldyhhLHUsKG0sVyk9PntIZShpLGMsZSxtLFcsdCl9KSx3PSExLGY9KCk9Pnt3fHwodz0hMCxrdC51bnJlZ2lzdGVyKGYpLHkuY2xvc3VyZUZyZWUoZCkpfSxTPXtwdHI6ZCxkaXNwb3NlOmZ9O3JldHVybiBrdC5yZWdpc3RlcihmLHtzaWc6dCxwdHI6ZH0pLFN9aW1wb3J0KmFzIHd0IGZyb20iZmZpIjtmdW5jdGlvbiBYKHQsZSl7cmV0dXJuIHQrZS0xJn4oZS0xKX12YXIgenQ9dD0+JFt0XSE9PXZvaWQgMDtmdW5jdGlvbiBtdCh0KXtpZih0eXBlb2YgdD09InN0cmluZyIpe2xldCBlPS9eKHU4fHUxNilcWyhcZCspXF1AKHV0Zi04fHV0Zi0xNmxlKSQvLmV4ZWModCk7aWYoZSl7bGV0IGM9TnVtYmVyKGVbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJpbmcgbGVuZ3RoIG11c3QgYmUgYW4gaW50ZWdlciA+PSAxLCBnb3QgJHtjfWApO2xldCBzPWVbMV09PT0idTgiPzE6MjtyZXR1cm57c2l6ZTpzKmMsYWxpZ246cyx0eXBlOnt0YWc6InN0cmluZyIsZW5jb2Rpbmc6ZVszXX19fWxldCByPS9eKFteXFtcXV0rKVxbKFxkKylcXSQvLmV4ZWModCk7aWYocil7bGV0IGM9TnVtYmVyKHJbMl0pO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKGMpfHxjPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke2N9YCk7bGV0IHM9bXQoclsxXSk7aWYocy50eXBlLnRhZz09PSJiaXRmaWVsZCIpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBiaXRmaWVsZHMgY2Fubm90IGJlIGFycmF5IGVsZW1lbnRzIik7cmV0dXJue3NpemU6cy5zaXplKmMsYWxpZ246cy5hbGlnbix0eXBlOnt0YWc6ImFycmF5IixlbGVtZW50VHlwZTpzLnR5cGUsZWxlbWVudFNpemU6cy5zaXplfX19bGV0IG89L14oW0EtWmEtel9dXHcqKTooXGQrKSQvLmV4ZWModCk7aWYobyl7bGV0IGM9b1sxXSxzPVkoYyk7aWYoIXp0KHMpfHxzPT09ImYzMiJ8fHM9PT0iZjY0Iil0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIHVuaXQgbXVzdCBiZSBhbiBpbnRlZ2VyIHR5cGUsIGdvdCAiJHtjfSJgKTtsZXQgcD1OdW1iZXIob1syXSksYT0kW3NdLHU9YSo4O2lmKCFOdW1iZXIuaXNJbnRlZ2VyKHApfHxwPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCBtdXN0IGJlIGFuIGludGVnZXIgPj0gMSwgZ290ICR7cH1gKTtpZihwPnUpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBiaXRmaWVsZCB3aWR0aCAke3B9IGV4Y2VlZHMgdW5pdCB3aWR0aCAke3V9YCk7cmV0dXJue3NpemU6YSxhbGlnbjphLHR5cGU6e3RhZzoiYml0ZmllbGQiLHVuaXQ6cyxiaXQ6MCx3aWR0aDpwfX19bGV0IG49WSh0KTtpZihSKG4pKXJldHVybntzaXplOkEsYWxpZ246QSx0eXBlOnt0YWc6ImJhc2ljIixraW5kOiJwdHIifX07aWYoIXp0KG4pKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biBraW5kICIke3R9ImApO2xldCBpPSRbbl07cmV0dXJue3NpemU6aSxhbGlnbjppLHR5cGU6e3RhZzoiYmFzaWMiLGtpbmQ6bn19fWlmKHQmJnR5cGVvZiB0PT0ib2JqZWN0Iil7bGV0IGU9dCxyPWVbIiMiXTtpZihyPT09dm9pZCAwKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogbmVzdGVkIG9iamVjdCB2YWx1ZSByZXF1aXJlcyBhICcjJyBrZXkgKCdzdHJ1Y3QnIHwgJ3VuaW9uJyB8ICdhcnJheScpIik7aWYocj09PSJhcnJheSImJiIjcGFjayJpbiBlKXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogJyNwYWNrJyBpcyBvbmx5IGFsbG93ZWQgb24gc3RydWN0L3VuaW9uLCBnb3QgJyR7cn0nYCk7aWYocj09PSJhcnJheSIpe2xldCBvPWUubGVuZ3RoO2lmKCFOdW1iZXIuaXNJbnRlZ2VyKG8pfHxvPDEpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhcnJheSBsZW5ndGggbXVzdCBiZSBhbiBpbnRlZ2VyID49IDEsIGdvdCAke1N0cmluZyhvKX1gKTtsZXQgbj1tdChlLmVsZW1lbnQpO2lmKG4udHlwZS50YWc9PT0iYml0ZmllbGQiKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYml0ZmllbGRzIGNhbm5vdCBiZSBhcnJheSBlbGVtZW50cyIpO3JldHVybntzaXplOm4uc2l6ZSpvLGFsaWduOm4uYWxpZ24sdHlwZTp7dGFnOiJhcnJheSIsZWxlbWVudFR5cGU6bi50eXBlLGVsZW1lbnRTaXplOm4uc2l6ZX19fWlmKHI9PT0ic3RydWN0Inx8cj09PSJ1bmlvbiIpe2xldCBvPWh0KHQpO3JldHVybntzaXplOm8uc2l6ZSxhbGlnbjpvLm1heEVmZmVjdGl2ZUFsaWduLHR5cGU6e3RhZzpyLGZpZWxkczpvLmZpZWxkc319fXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogdW5rbm93biAnIycgZGVjbGFyYXRpb24gJHtKU09OLnN0cmluZ2lmeShTdHJpbmcocikpfWApfXRocm93IG5ldyBFcnJvcihgZmZpLXN0cnVjdDogaW52YWxpZCBtZW1iZXIgdmFsdWU6ICR7U3RyaW5nKHQpfWApfWZ1bmN0aW9uIGh0KHQpe2xldCBlPXRbIiMiXT09PSJzdHJ1Y3QiLHI9dFsiI3BhY2siXT8/OCxvPTEsbj0wLGk9W10sYz0wLHM9LTEscD0wLGE9MCx1PSgpPT57czwwfHwoYz1YKHMrTWF0aC5jZWlsKHAvOCksYSkscz0tMSl9O2ZvcihsZXRbeCxkXW9mIE9iamVjdC5lbnRyaWVzKHQpKXtpZih4LnN0YXJ0c1dpdGgoIiMiKSljb250aW51ZTtsZXQgdz0vXihbXkBdKylAKFxkKykkLy5leGVjKHgpLGY9dz93WzFdOngsUz13P051bWJlcih3WzJdKTowLHtzaXplOm0sYWxpZ246Vyx0eXBlOmx9PW10KGQpLEQ9dHlwZW9mIGQ9PSJzdHJpbmciJiZkLmVuZHNXaXRoKCIhIiksRT1XO2lmKHI+MCYmKEU9TWF0aC5taW4ocixFKSksUyYmKEU9TWF0aC5tYXgoRSxTKSksbC50YWc9PT0iYml0ZmllbGQiKXtpZihmLnN0YXJ0c1dpdGgoIiQiKSl0aHJvdyBuZXcgRXJyb3IoImZmaS1zdHJ1Y3Q6IGJpdGZpZWxkIG1lbWJlcnMgbXVzdCBiZSBuYW1lZCIpO2lmKCFlKXtpLnB1c2goe25hbWU6ZixvZmZzZXQ6MCxzaXplOm0sdHlwZTp7Li4ubCxiaXQ6MH19KSxvPU1hdGgubWF4KG8sRSksbj1NYXRoLm1heChuLG0pO2NvbnRpbnVlfWxldCBoPWwud2lkdGg7KHM8MHx8bSE9PWF8fHAraD5hKjgpJiYocz49MCYmdSgpLHM9WChjLEUpLHA9MCxhPW0pLGkucHVzaCh7bmFtZTpmLG9mZnNldDpzLHNpemU6bSx0eXBlOnsuLi5sLGJpdDpwfX0pLHArPWgsbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKTtjb250aW51ZX11KCk7bGV0IEM9WChjLEUpO2lmKCFmLnN0YXJ0c1dpdGgoIiQiKSlpLnB1c2goe25hbWU6ZixvZmZzZXQ6QyxzaXplOm0sdHlwZTpsLC4uLkQ/e25vbm51bGw6ITB9Ont9fSk7ZWxzZXtpZihsLnRhZyE9PSJzdHJ1Y3QiJiZsLnRhZyE9PSJ1bmlvbiIpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBhbm9ueW1vdXMgbWVtYmVyICIke2Z9IiBtdXN0IGJlIGEgc3RydWN0L3VuaW9uYCk7Zm9yKGxldCBoIG9mIGwuZmllbGRzKWkucHVzaCh7Li4uaCxvZmZzZXQ6aC5vZmZzZXQrQ30pfWUmJihjPUMrbSksbz1NYXRoLm1heChvLEUpLG49TWF0aC5tYXgobixtKX1yZXR1cm4gdSgpLHtzaXplOlgoZT9jOm4sbyksbWF4RWZmZWN0aXZlQWxpZ246byxmaWVsZHM6aX19ZnVuY3Rpb24gJHQodCxlLHIpe2xldCBvPSRbcl07cmV0dXJuIG89PT0xP0JpZ0ludCh0LmdldFVpbnQ4KGUpKTpvPT09Mj9CaWdJbnQodC5nZXRVaW50MTYoZSwhMCkpOm89PT00P0JpZ0ludCh0LmdldFVpbnQzMihlLCEwKSk6dC5nZXRCaWdVaW50NjQoZSwhMCl9ZnVuY3Rpb24gUGUodCxlLHIsbyl7bGV0IG49JFtyXTtpZihuPT09MSl7dC5zZXRVaW50OChlLE51bWJlcihvJjB4ZmZuKSk7cmV0dXJufWlmKG49PT0yKXt0LnNldFVpbnQxNihlLE51bWJlcihvJjB4ZmZmZm4pLCEwKTtyZXR1cm59aWYobj09PTQpe3Quc2V0VWludDMyKGUsTnVtYmVyKG8mMHhmZmZmZmZmZm4pLCEwKTtyZXR1cm59dC5zZXRCaWdVaW50NjQoZSxvJjB4ZmZmZmZmZmZmZmZmZmZmZm4sITApfWZ1bmN0aW9uIE1lKHQsZSxyKXtsZXQgbz1CaWdJbnQoci53aWR0aCksbj0kdCh0LGUsci51bml0KT4+QmlnSW50KHIuYml0KSYoMW48PG8pLTFuO3JldHVybiByLnVuaXRbMF09PT0iaSImJm4mMW48PG8tMW4mJihuLT0xbjw8byksci53aWR0aD41Mz9uOk51bWJlcihuKX1mdW5jdGlvbiBPZSh0LGUscixvKXtsZXQgbj1CaWdJbnQoci53aWR0aCksaT1CaWdJbnQoci5iaXQpLGM9KDFuPDxuKS0xbixzPWM8PGkscD0kdCh0LGUsci51bml0KSxhPSh0eXBlb2Ygbz09ImJpZ2ludCI/bzpCaWdJbnQoTWF0aC50cnVuYyhvKSkpJmM7UGUodCxlLHIudW5pdCxwJn5zfGE8PGkpfXZhciBSZT17InV0Zi04IjpuZXcgVGV4dEVuY29kZXIoInV0Zi04IiksInV0Zi0xNmxlIjpuZXcgVGV4dEVuY29kZXIoInV0Zi0xNmxlIil9LEFlPXsidXRmLTgiOm5ldyBUZXh0RGVjb2RlcigidXRmLTgiLHtpZ25vcmVCT006ITB9KSwidXRmLTE2bGUiOm5ldyBUZXh0RGVjb2RlcigidXRmLTE2bGUiLHtpZ25vcmVCT006ITB9KX07ZnVuY3Rpb24gQmUodCxlLHIsbyl7bGV0IG49bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2UsciksaT1vPT09InV0Zi0xNmxlIj8yOjEsYz1yO2ZvcihsZXQgcz0wO3MraTw9cjtzKz1pKWlmKG5bc109PT0wJiYoaT09PTF8fG5bcysxXT09PTApKXtjPXM7YnJlYWt9cmV0dXJuIEFlW29dLmRlY29kZShuLnN1YmFycmF5KDAsYykpfWZ1bmN0aW9uIEdlKHQsZSxyLG8sbil7bGV0IGk9bmV3IFVpbnQ4QXJyYXkodC5idWZmZXIsdC5ieXRlT2Zmc2V0K2Uscik7aS5maWxsKDApO2xldCBzPXItKG89PT0idXRmLTE2bGUiPzI6MSk7aWYoczw9MClyZXR1cm47bGV0IHA9UmVbb10uZW5jb2RlKFN0cmluZyhuPz8iIikpO2kuc2V0KHAuc3ViYXJyYXkoMCxNYXRoLm1pbihwLmxlbmd0aCxzKSkpfWZ1bmN0aW9uIExlKHQsZSxyLG8pe2xldCBuPW8uZWxlbWVudFNpemU+MD9yL28uZWxlbWVudFNpemU6MCxpPVtdO2ZvcihsZXQgYz0wO2M8bjtjKyspaS5wdXNoKFl0KHQsZStjKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplKSk7cmV0dXJuIGl9ZnVuY3Rpb24ga2UodCxlLHIsbyxuKXtsZXQgaT1vLmVsZW1lbnRTaXplPjA/ci9vLmVsZW1lbnRTaXplOjAsYz1uPz9bXTtmb3IobGV0IHM9MDtzPGk7cysrKVZ0KHQsZStzKm8uZWxlbWVudFNpemUsby5lbGVtZW50VHlwZSxvLmVsZW1lbnRTaXplLGNbc10pfWZ1bmN0aW9uIFl0KHQsZSxyLG8pe3N3aXRjaChyLnRhZyl7Y2FzZSJiYXNpYyI6cmV0dXJuIFYodCxlLHIua2luZCk7Y2FzZSJiaXRmaWVsZCI6cmV0dXJuIE1lKHQsZSxyKTtjYXNlInN0cmluZyI6cmV0dXJuIEJlKHQsZSxvLHIuZW5jb2RpbmcpO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjpyZXR1cm4gb3QodCxlLHIuZmllbGRzKTtjYXNlImFycmF5IjpyZXR1cm4gTGUodCxlLG8scil9fWZ1bmN0aW9uIFZ0KHQsZSxyLG8sbil7c3dpdGNoKHIudGFnKXtjYXNlImJhc2ljIjpkdCh0LGUse2s6ci5raW5kLHY6bn0pO2JyZWFrO2Nhc2UiYml0ZmllbGQiOk9lKHQsZSxyLG4/PzApO2JyZWFrO2Nhc2Uic3RyaW5nIjpHZSh0LGUsbyxyLmVuY29kaW5nLG4pO2JyZWFrO2Nhc2Uic3RydWN0IjpjYXNlInVuaW9uIjp2dCh0LGUsci5maWVsZHMsbj8/e30pO2JyZWFrO2Nhc2UiYXJyYXkiOmtlKHQsZSxvLHIsbik7YnJlYWt9fWZ1bmN0aW9uIG90KHQsZSxyKXtsZXQgbz17fTtmb3IobGV0IG4gb2Ygcil7bGV0IGk9WXQodCxlK24ub2Zmc2V0LG4udHlwZSxuLnNpemUpO2lmKG4ubm9ubnVsbCYmaT09PTApdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBkZWNvZGU6ICchJyBmaWVsZCAiJHtuLm5hbWV9IiBnb3QgMCAoQyBkaWQgbm90IGZpbGwgaXQsIG9yIGRlY29kZSB3YXMgY2FsbGVkIG9uIGFuIHVuZmlsbGVkIHNsb3QpYCk7b1tuLm5hbWVdPWl9cmV0dXJuIG99ZnVuY3Rpb24gdnQodCxlLHIsbyl7Zm9yKGxldCBuIG9mIHIpb1tuLm5hbWVdIT09dm9pZCAwJiZWdCh0LGUrbi5vZmZzZXQsbi50eXBlLG4uc2l6ZSxvW24ubmFtZV0pfWZ1bmN0aW9uIFVlKHQpe2xldHtmaWVsZHM6ZSxzaXplOnIsbWF4RWZmZWN0aXZlQWxpZ246b309aHQodCk7cmV0dXJue19fc3RydWN0OnQsc2l6ZTpyLHN0cnVjdEFsaWduOm8sZGVjb2RlOm49Pm90KHR5cGVvZiBuPT0ibnVtYmVyIj9uZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4scikpOm5ldyBEYXRhVmlldyhuKSwwLGUpLGFsbG9jOihuPT57aWYobiE9PXZvaWQgMCYmKCFOdW1iZXIuaXNJbnRlZ2VyKG4pfHxuPDEpKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogYWxsb2MobikgcmVxdWlyZXMgYW4gaW50ZWdlciBuID49IDEgKFBBQigwKSBuZXZlciBlc2NhcGVzIFx1MjAxNCBwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7cmV0dXJuIG5ldyBiKHIqKG4/PzEpKX0pLGVuY29kZTooKG4saSxjKT0+e2lmKG49PW51bGwpdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBlbmNvZGUodikgcmVxdWlyZXMgYW4gYXJndW1lbnQ7IHVzZSBhbGxvYygpIGZvciBhIHplcm9lZCBvdXQtcGFyYW0gc2xvdCIpO2xldCBzPWk/P25ldyBiKHIpO3JldHVybiB2dChuZXcgRGF0YVZpZXcocyksYz8/MCxlLG4pLHN9KSxvZmZzZXRPZjpuPT57Zm9yKGxldCBpIG9mIGUpaWYoaS5uYW1lPT09bilyZXR1cm4gaS5vZmZzZXQ7dGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBubyBmaWVsZCAiJHtufSJgKX19fWZ1bmN0aW9uIF9lKHQsZSxyKXtsZXQgbz17IiMiOnR9O3IhPT12b2lkIDAmJihvWyIjcGFjayJdPXIpO2ZvcihsZXRbbixpXW9mIE9iamVjdC5lbnRyaWVzKGUpKW4uc3RhcnRzV2l0aCgiIyIpfHwob1tuXT1pKTtyZXR1cm4gb31mdW5jdGlvbiBqdCh0KXtsZXR7ZmllbGRzOmUsc2l6ZTpyfT1odCh0Ll9fc3RydWN0KSxvPShuLGkpPT57bGV0IGM9W107Zm9yKGxldCBzPTA7czxpO3MrKyljLnB1c2gob3QobixzKnIsZSkpO3JldHVybiBjfTtyZXR1cm57ZW5jb2RlOm49PntpZighQXJyYXkuaXNBcnJheShuKXx8bi5sZW5ndGg9PT0wKXRocm93IG5ldyBFcnJvcigiZmZpLXN0cnVjdDogc3RydWN0QXJyYXkoZGVmKS5lbmNvZGUoZWxzKSByZXF1aXJlcyBhIG5vbi1lbXB0eSBlbGVtZW50IGFycmF5IChwYXNzIE5VTEwgZm9yIGFuIGVtcHR5IHBvaW50ZXIgcG9zaXRpb24pIik7bGV0IGk9dC5hbGxvYyhuLmxlbmd0aCk7Zm9yKGxldCBjPTA7YzxuLmxlbmd0aDtjKyspdC5lbmNvZGUobltjXSxpLGMqdC5zaXplKTtyZXR1cm4gaX0sZGVjb2RlOigobixpKT0+e2lmKGkhPT12b2lkIDAmJighTnVtYmVyLmlzSW50ZWdlcihpKXx8aTwwKSl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZShwLCBjb3VudCkgcmVxdWlyZXMgYSBub24tbmVnYXRpdmUgaW50ZWdlciBjb3VudCwgZ290ICR7aX1gKTtpZih0eXBlb2Ygbj09Im51bWJlciIpe2lmKGk9PT12b2lkIDApdGhyb3cgbmV3IEVycm9yKCJmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGUoYWRkcmVzcywgY291bnQpIHJlcXVpcmVzIGFuIGV4cGxpY2l0IGNvdW50IChhIGJhcmUgYWRkcmVzcyBjYXJyaWVzIG5vIGxlbmd0aCkiKTtyZXR1cm4gaT09PTA/W106byhuZXcgRGF0YVZpZXcod3QucmVhZEJ5dGVzKG4saSpyKSksaSl9bGV0IGM7aWYoaSE9PXZvaWQgMCl7aWYoYz1pLGMqcj5uLmJ5dGVMZW5ndGgpdGhyb3cgbmV3IEVycm9yKGBmZmktc3RydWN0OiBzdHJ1Y3RBcnJheS5kZWNvZGU6IGNvdW50ICR7Y30gXHhENyBzaXplICR7cn0gPSAke2Mqcn0gZXhjZWVkcyBidWZmZXIgYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH1gKX1lbHNle2lmKG4uYnl0ZUxlbmd0aCVyIT09MCl0aHJvdyBuZXcgRXJyb3IoYGZmaS1zdHJ1Y3Q6IHN0cnVjdEFycmF5LmRlY29kZTogYnl0ZUxlbmd0aCAke24uYnl0ZUxlbmd0aH0gaXMgbm90IGEgbXVsdGlwbGUgb2Ygc2l6ZSAke3J9IChtaXhlZCBidWZmZXI/IHBhc3MgY291bnQgZXhwbGljaXRseSlgKTtjPW4uYnl0ZUxlbmd0aC9yfXJldHVybiBjPT09MD9bXTpvKG5ldyBEYXRhVmlldyhuKSxjKX0pfX1mdW5jdGlvbiBnKHQsZSxyKXtsZXQgbz10eXBlb2YgdD09InN0cmluZyI7cmV0dXJuIFVlKF9lKCJzdHJ1Y3QiLG8/ZTp0LChvP3I6ZSk/LnBhY2spKX12YXIgUD1nKCJSRUNUIix7bGVmdDoiaTMyIix0b3A6ImkzMiIscmlnaHQ6ImkzMiIsYm90dG9tOiJpMzIifSksaj1nKCJQT0lOVCIse3g6ImkzMiIseToiaTMyIn0pO3ZhciBudD1nKCJTVEFSVFVQSU5GT1ciLHtjYjoidTMyIixscFJlc2VydmVkOiI8PnB0ciIsbHBEZXNrdG9wOiI8PnB0ciIsbHBUaXRsZToiPD5wdHIiLGR3WDoidTMyIixkd1k6InUzMiIsZHdYU2l6ZToidTMyIixkd1lTaXplOiJ1MzIiLGR3WENvdW50Q2hhcnM6InUzMiIsZHdZQ291bnRDaGFyczoidTMyIixkd0ZpbGxBdHRyaWJ1dGU6InUzMiIsZHdGbGFnczoidTMyIix3U2hvd1dpbmRvdzoidTE2QFNob3dXaW5kb3dDbWQiLGNiUmVzZXJ2ZWQyOiJ1MTYiLGxwUmVzZXJ2ZWQyOiI8PnB0ciIsaFN0ZElucHV0OiI8SEZJTEU+cHRyIixoU3RkT3V0cHV0OiI8SEZJTEU+cHRyIixoU3RkRXJyb3I6IjxIRklMRT5wdHIifSksQ3Q9ZygiUFJPQ0VTU19JTkZPUk1BVElPTiIse2hQcm9jZXNzOiI8SFBST0NFU1M+cHRyISIsaFRocmVhZDoiPEhUSFJFQUQ+cHRyISIsZHdQcm9jZXNzSWQ6InUzMiIsZHdUaHJlYWRJZDoidTMyIn0pLEo9ZygiQklUTUFQSU5GT0hFQURFUiIse2JpU2l6ZToidTMyIixiaVdpZHRoOiJpMzIiLGJpSGVpZ2h0OiJpMzIiLGJpUGxhbmVzOiJ1MTYiLGJpQml0Q291bnQ6InUxNiIsYmlDb21wcmVzc2lvbjoidTMyIixiaVNpemVJbWFnZToidTMyIixiaVhQZWxzUGVyTWV0ZXI6ImkzMiIsYmlZUGVsc1Blck1ldGVyOiJpMzIiLGJpQ2xyVXNlZDoidTMyIixiaUNsckltcG9ydGFudDoidTMyIn0pLGl0PWcoIkJJVE1BUEZJTEVIRUFERVIiLHtiZlR5cGU6InUxNiIsYmZTaXplOiJ1MzIiLGJmUmVzZXJ2ZWQxOiJ1MTYiLGJmUmVzZXJ2ZWQyOiJ1MTYiLGJmT2ZmQml0czoidTMyIn0se3BhY2s6Mn0pO3ZhciBaPWcoIk5NSERSIix7aHduZEZyb206IjxIV05EPnB0ciIsaWRGcm9tOiI8PnB0ciIsY29kZToiaTMyIn0pLHplPWcoIlNZU1RFTVRJTUUiLHt3WWVhcjoidTE2Iix3TW9udGg6InUxNiIsd0RheU9mV2VlazoidTE2Iix3RGF5OiJ1MTYiLHdIb3VyOiJ1MTYiLHdNaW51dGU6InUxNiIsd1NlY29uZDoidTE2Iix3TWlsbGlzZWNvbmRzOiJ1MTYifSksbXI9ZygiTk1EQVRFVElNRUNIQU5HRSIse2hkcjpaLl9fc3RydWN0LGR3RmxhZ3M6InUzMiIsc3Q6emUuX19zdHJ1Y3R9KSwkZT1nKCJMSVRFTSIse21hc2s6InUzMiIsaUxpbms6ImkzMiIsc3RhdGU6InUzMiIsc3RhdGVNYXNrOiJ1MzIiLHN6SUQ6InUxNls0OF1AdXRmLTE2bGUiLHN6VXJsOiJ1MTZbMjA4NF1AdXRmLTE2bGUifSksd3I9ZygiTk1MSU5LIix7aGRyOlouX19zdHJ1Y3QsaXRlbTokZS5fX3N0cnVjdH0pLGhyPWcoIk5NQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciJ9KSxDcj1nKCJOTUxWQ1VTVE9NRFJBVyIse2hkcjpaLl9fc3RydWN0LGR3RHJhd1N0YWdlOiJ1MzIiLGhkYzoiPEhEQz5wdHIiLHJjOiJpMzJbNF0iLGR3SXRlbVNwZWM6Ijw+cHRyIix1SXRlbVN0YXRlOiJ1MzIiLGxJdGVtbFBhcmFtOiI8PnB0ciIsY2xyVGV4dDoidTMyIixjbHJUZXh0Qms6InUzMiIsaVN1Ykl0ZW06ImkzMiIsZHdJdGVtVHlwZToidTMyIn0pLFNyPWcoIk5NTElTVFZJRVciLHtoZHI6Wi5fX3N0cnVjdCxpSXRlbToiaTMyIixpU3ViSXRlbToiaTMyIix1TmV3U3RhdGU6InUzMiIsdU9sZFN0YXRlOiJ1MzIiLHVDaGFuZ2VkOiJ1MzIiLHB0QWN0aW9uOiJpMzJbMl0iLGxQYXJhbToiPD5wdHIifSk7dmFyIFllPWcoIlRWSVRFTSIse21hc2s6InUzMiIsaEl0ZW06Ijw+cHRyIixzdGF0ZToidTMyIixzdGF0ZU1hc2s6InUzMiIscHN6VGV4dDoiPD5wdHIiLGNjaFRleHRNYXg6ImkzMiIsaUltYWdlOiJpMzIiLGlTZWxlY3RlZEltYWdlOiJpMzIiLGNDaGlsZHJlbjoiaTMyIixsUGFyYW06Ijw+cHRyIn0pLGdyPWcoIlRWSU5TRVJUU1RSVUNUIix7aFBhcmVudDoiPD5wdHIiLGhJbnNlcnRBZnRlcjoiPD5wdHIiLGl0ZW06WWUuX19zdHJ1Y3R9KTt2YXIgVmU9ZygiTVNHIix7aHduZDoiPEhXTkQ+cHRyIixtZXNzYWdlOiJ1MzIiLHdQYXJhbToiPD5wdHIiLGxQYXJhbToiPD5wdHIiLHRpbWU6InUzMiIscHQ6ai5fX3N0cnVjdH0pLERyPWcoIlBBSU5UU1RSVUNUIix7aGRjOiI8SERDPnB0ciIsZkVyYXNlOiJpMzIiLHJjUGFpbnQ6UC5fX3N0cnVjdCxmUmVzdG9yZToiaTMyIixmSW5jVXBkYXRlOiJpMzIiLHJnYlJlc2VydmVkOiJ1OFszMl0ifSk7dmFyIHN0PWcoIk9TVkVSU0lPTklORk9fMTQ4Iix7ZHdPU1ZlcnNpb25JbmZvU2l6ZToidTMyIixkd01ham9yVmVyc2lvbjoidTMyIixkd01pbm9yVmVyc2lvbjoidTMyIixkd0J1aWxkTnVtYmVyOiJ1MzIiLGR3UGxhdGZvcm1JZDoidTMyIixzekNTRFZlcnNpb246InU4WzEyOF0ifSk7dmFyIE89KHQsZSxyKT0+Rygia2VybmVsMzIuZGxsIix0LGUsciksSnQ9TygiQ3JlYXRlUGlwZSIsIjw+cHRyIDw+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKSxTdD1PKCJTZXRIYW5kbGVJbmZvcm1hdGlvbiIsIjxIRklMRT5wdHIhIHUzMiB1MzIgLT4gaTMyIiksS3Q9TygiQ3JlYXRlUHJvY2Vzc1ciLCI8V0NIQVI+cHRyIDxXQ0hBUj5wdHIgPD5wdHIgPD5wdHIgaTMyIHUzMiA8PnB0ciA8V0NIQVI+cHRyIDxTVEFSVFVQSU5GT1c+cHRyIDxQUk9DRVNTX0lORk9STUFUSU9OPnB0ciAtPiBpMzIiLHtTVEFSVFVQSU5GT1c6bnR9KSxYdD1PKCJXYWl0Rm9yU2luZ2xlT2JqZWN0IiwiPD5wdHIgdTMyIC0+IHUzMiIpLFp0PU8oIkdldEV4aXRDb2RlUHJvY2VzcyIsIjxIUFJPQ0VTUz5wdHIhIDxCWVRFPnB0ciAtPiBpMzIiKSxVPU8oIkNsb3NlSGFuZGxlIiwiPD5wdHIgLT4gaTMyIik7dmFyIHF0PU8oIlJlYWRGaWxlIiwiPEhGSUxFPnB0ciEgPEJZVEU+cHRyIHUzMiA8QllURT5wdHIgPD5wdHIgLT4gaTMyIik7dmFyIGd0PU8oIkdldExhc3RFcnJvciIsIiAtPiB1MzIiKSxRdD1PKCJHZXRTeXN0ZW1EaXJlY3RvcnlXIiwiPEJZVEU+cHRyIHUzMiAtPiB1MzIiKTtpbXBvcnQqYXMgdGUgZnJvbSJvcyI7dmFyIE49KHQsZSxyKT0+RygidXNlcjMyLmRsbCIsdCxlLHIpLEhyPU4oIkdldERlc2t0b3BXaW5kb3ciLCIgLT4gPEhXTkQ+cHRyIiksZWU9dGUuYXJjaD09PSJ4NjQiPyJQdHJXIjoiVyI7dmFyIER0PU4oIkdldFdpbmRvd1JlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpLHJlPU4oIkdldENsaWVudFJlY3QiLCI8SFdORD5wdHIgPFJFQ1Q+cHRyIC0+IGkzMiIpO3ZhciBvZT1OKCJJc1dpbmRvd1Zpc2libGUiLCI8SFdORD5wdHIgLT4gaTMyIiksRXQ9TigiSXNJY29uaWMiLCI8SFdORD5wdHIgLT4gaTMyIik7dmFyIG5lPU4oIkdldFdpbmRvd1RleHRXIiwiPEhXTkQ+cHRyIDxCWVRFPnB0ciBpMzIgLT4gaTMyIik7dmFyIGllPU4oIkdldENsYXNzTmFtZVciLCI8SFdORD5wdHIgPEJZVEU+cHRyIGkzMiAtPiBpMzIiKSxQcj1OKCJHZXRXaW5kb3dMb25nIitlZSwiPEhXTkQ+cHRyIGkzMkBHd2xwIC0+IDw+cHRyIiksTXI9TigiU2V0V2luZG93TG9uZyIrZWUsIjxIV05EPnB0ciBpMzJAR3dscCA8PnB0ciAtPiA8PnB0ciIpO3ZhciBzZT1OKCJHZXREQyIsIjxIV05EPnB0ciAtPiA8SERDPnB0ciIpLFd0PU4oIlJlbGVhc2VEQyIsIjxIV05EPnB0ciA8SERDPnB0ciEgLT4gaTMyIiksY2U9TigiUHJpbnRXaW5kb3ciLCI8SFdORD5wdHIgPEhEQz5wdHIhIHUzMiAtPiBpMzIiKTt2YXIgcGU9TigiQ2xpZW50VG9TY3JlZW4iLCI8SFdORD5wdHIgPFBPSU5UPnB0ciAtPiBpMzIiKTt2YXIgXz1OKCJHZXRTeXN0ZW1NZXRyaWNzIiwiaTMyIC0+IGkzMiIpO3ZhciBhZT1OKCJFbnVtV2luZG93cyIsIjw+cHRyIDw+cHRyIC0+IGkzMiIpO3ZhciB6PSh0LGUscik9PkcoImdkaTMyLmRsbCIsdCxlLHIpLExyPWp0KGopO3ZhciBUdD16KCJEZWxldGVPYmplY3QiLCI8SEdESU9CSj5wdHIgLT4gaTMyIik7dmFyIGJ0PXooIkNyZWF0ZUNvbXBhdGlibGVEQyIsIjxIREM+cHRyIC0+IDxIREM+cHRyIiksTnQ9eigiQ3JlYXRlQ29tcGF0aWJsZUJpdG1hcCIsIjxIREM+cHRyISBpMzIgaTMyIC0+IDxIR0RJT0JKPnB0ciIpO3ZhciBxPXooIlNlbGVjdE9iamVjdCIsIjxIREM+cHRyISA8SEdESU9CSj5wdHIgLT4gPEhHRElPQko+cHRyIiksSXQ9eigiQml0Qmx0IiwiPEhEQz5wdHIhIGkzMiBpMzIgaTMyIGkzMiA8SERDPnB0ciBpMzIgaTMyIHUzMkBSYXN0ZXJPcCAtPiBpMzIiKSx1ZT16KCJHZXRESUJpdHMiLCI8SERDPnB0ciEgPEhHRElPQko+cHRyIHUzMiB1MzIgPEJZVEU+cHRyIDw+cHRyIHUzMiAtPiBpMzIiKTt2YXIgUT16KCJEZWxldGVEQyIsIjxIREM+cHRyISAtPiBpMzIiKTt2YXIgdmU9KHQsZSk9PkcoIm50ZGxsLmRsbCIsdCxlKSxsZT12ZSgiUnRsR2V0VmVyc2lvbiIsIjxPU1ZFUlNJT05JTkZPXzE0OD5wdHIgLT4gaTMyIik7dmFyIG1lPXQ9Pnt0cnl7bGV0IGU9eGUub3BlbigiZGlhZy5sb2ciLCJhIik7ZSYmKGUucHV0cyhgJHtEYXRlLm5vdygpfSAke3R9CmApLGUuY2xvc2UoKSl9Y2F0Y2h7fX0seXQ9MSxqZT0yNTYsSmU9NDI5NDk2NzI5NSxGPWZlLldvcmtlci5wYXJlbnQsd2U9IkM6XFxXaW5kb3dzXFxTeXN0ZW0zMiI7dHJ5e2xldCB0PUIuYWxsb2MoMjU2KSxyPVF0KHQsMjU2KT4wP0IuZGVjb2RlKHQpOiIiO3ImJih3ZT1yKX1jYXRjaCh0KXttZSgiU1lTLURJUi1GQUlMOiAiK1N0cmluZyh0KSl9dmFyIGhlPSExO3RyeXtsZXQgdD1zdC5lbmNvZGUoe2R3T1NWZXJzaW9uSW5mb1NpemU6c3Quc2l6ZX0pO2xlKHQucHRyKT09PTAmJihoZT1zdC5kZWNvZGUodCkuZHdNYWpvclZlcnNpb24+PTEwKX1jYXRjaCh0KXttZSgiVkVSLUZBSUw6ICIrU3RyaW5nKHQpKX12YXIgRnQ9ZygiUElQRV9IQU5ETEVTIix7aFJlYWQ6IjxIRklMRT5wdHIhIixoV3JpdGU6IjxIRklMRT5wdHIhIn0pO2Z1bmN0aW9uIEtlKHQsZSl7bGV0IHI9RnQuYWxsb2MoKTtpZighSnQoci5wdHIsci5wdHIrRnQub2Zmc2V0T2YoImhXcml0ZSIpLEksMCkpdGhyb3cgbmV3IEVycm9yKCJDcmVhdGVQaXBlIGVycj0iK2d0KCkpO2xldHtoUmVhZDpvLGhXcml0ZTpufT1GdC5kZWNvZGUocik7U3Qobix5dCx5dCksU3Qobyx5dCwwKTtsZXQgaT1DdC5hbGxvYygpLHM9YCR7d2V9XFxjbWQuZXhlICR7aGU/Ii91ICI6IiJ9L2MgJHtlfWA7aWYoIUt0KEkscyxJLEksMSwwLEksSSx7Y2I6bnQuc2l6ZSxkd0ZsYWdzOmplLGhTdGRPdXRwdXQ6bixoU3RkRXJyb3I6bn0saS5wdHIpKXRocm93IFUobyksVShuKSxuZXcgRXJyb3IoIkNyZWF0ZVByb2Nlc3NXIGVycj0iK2d0KCkrIiBjbWQ9IitzKTtsZXR7aFByb2Nlc3M6cCxoVGhyZWFkOmEsZHdQcm9jZXNzSWQ6dX09Q3QuZGVjb2RlKGkpO1UoYSksVShuKSxGLnBvc3RNZXNzYWdlKHt0eXBlOiJpbmZvIixpZDp0LHBpZDp1fSk7bGV0IHg9bmV3IGIoNDA5NiksZD1uZXcgVWludDhBcnJheSh4KSx3PW5ldyBiKDQpLGY9bmV3IFVpbnQzMkFycmF5KHcpO2Zvcig7ZlswXT0wLCEhcXQobyx4LDQwOTYsdyxJKTspe2xldCBsPWZbMF07aWYobD09PTApYnJlYWs7Ri5wb3N0TWVzc2FnZSh7dHlwZToiZGF0YSIsaWQ6dCxjaHVuazpkLnNsaWNlKDAsbCl9KX1YdChwLEplKTtsZXQgUz1uZXcgYig0KSxtPW5ldyBJbnQzMkFycmF5KFMpO1p0KHAsUyk7bGV0IFc9bVswXTtyZXR1cm4gVShvKSxVKHApLFd9dmFyIENlPTEzMzY5Mzc2LFhlPTAsZGU9NjU1MzYsWmU9NGU3LGN0PTUxMixxZT0yZTQsSHQ9aXQuc2l6ZStKLnNpemU7ZnVuY3Rpb24gUWUodCxlLHIpe2xldCBvPWl0LmVuY29kZSh7YmZUeXBlOjE5Nzc4LGJmU2l6ZTpIdCt0LGJmT2ZmQml0czpIdH0pLG49Si5lbmNvZGUoe2JpU2l6ZTpKLnNpemUsYmlXaWR0aDplLGJpSGVpZ2h0Oi1yLGJpUGxhbmVzOjEsYmlCaXRDb3VudDozMixiaUNvbXByZXNzaW9uOjAsYmlTaXplSW1hZ2U6dCxiaVhQZWxzUGVyTWV0ZXI6MjgzNSxiaVlQZWxzUGVyTWV0ZXI6MjgzNX0pLGk9bmV3IFVpbnQ4QXJyYXkoSHQpO3JldHVybiBpLnNldChuZXcgVWludDhBcnJheShvKSwwKSxpLnNldChuZXcgVWludDhBcnJheShuKSxpdC5zaXplKSxpfWZ1bmN0aW9uIHRyKHQsZSxyLG8sbil7bGV0IGk9bmV3IGIobypuKjQpLGM9bmV3IFVpbnQ4QXJyYXkoaSkscz1KLmVuY29kZSh7YmlTaXplOkouc2l6ZSxiaVdpZHRoOm8sYmlIZWlnaHQ6LW4sYmlQbGFuZXM6MSxiaUJpdENvdW50OjMyLGJpU2l6ZUltYWdlOm8qbio0fSk7aWYodWUoZSxyLDAsbixpLHMucHRyLFhlKSE9PW4pcmV0dXJuITE7bGV0IGE9Yy5ieXRlTGVuZ3RoO0YucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6UWUoYSxvLG4pfSk7Zm9yKGxldCB1PTA7dTxhO3UrPWRlKUYucG9zdE1lc3NhZ2Uoe3R5cGU6ImRhdGEiLGlkOnQsY2h1bms6Yy5zbGljZSh1LE1hdGgubWluKHUrZGUsYSkpfSk7cmV0dXJuITB9ZnVuY3Rpb24gZXIodCxlLHIsbyxuLGksYyxzLHApe2xldCBhPWJ0KHQpLHU9YT9OdCh0LHIsbyk6MDtpZighYXx8IXUpcmV0dXJuIGEmJlEoYSksITE7bGV0IHg9cShhLHUpLHc9Y2UoZSxhLDApIT09MCYmSXQobiwwLDAscyxwLGEsaSxjLENlKSE9PTA7cmV0dXJuIHEoYSx4KSxUdCh1KSxRKGEpLHd9ZnVuY3Rpb24gU2UodCxlLHIsbyxuLGksYyxzLHAsYSl7aWYoIShzPjAmJnA+MCYmcypwPD1aZSkpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIHNpemUgaW52YWxpZCB3PSIrcysiIGg9IitwKTtpZihhIT09bnVsbCYmIShpPj0wJiZjPj0wJiZpK3M8PWUmJmMrcDw9cikpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGNyb3Agb3V0IG9mIHJhbmdlIGNyb3A9KCIraSsiLCIrYysiLCIrcysieCIrcCsiKSBmcmFtZT0iK2UrIngiK3IpO2xldCB1PXNlKEkpO2lmKCF1KXRocm93IG5ldyBFcnJvcigiR2V0REMoTlVMTCk9MFx1RkYxQVx1NjVFMFx1OEY5M1x1NTE2NVx1Njg0Q1x1OTc2Mlx1RkYwOFx1Nzg2RVx1OEJBNFx1NTcyOFx1NEVBNFx1NEU5MiBzZXNzaW9uIFx1NTQyRlx1NTJBOFx1RkYwQ1x1ODAwQ1x1OTc1RSBzc2hkL3NlcnZpY2VcdUZGMDkiKTtsZXQgeD1idCh1KSxkPXg/TnQodSxzLHApOjA7aWYoIXh8fCFkKXRocm93IHgmJlEoeCksV3QoSSx1KSxuZXcgRXJyb3IoIkNyZWF0ZUNvbXBhdGlibGVEQy9CaXRtYXAgZmFpbGVkIik7bGV0IHc9cSh4LGQpLGY9YT09PW51bGw/SXQoeCwwLDAscyxwLHUsbyxuLENlKSE9PTA6ZXIodSxhLGUscix4LGksYyxzLHApO3EoeCx3KTtsZXQgUz1mJiZ0cih0LHgsZCxzLHApO2lmKFR0KGQpLFEoeCksV3QoSSx1KSwhZil0aHJvdyBuZXcgRXJyb3IoImNhcHR1cmUgZmFpbGVkIG91dD0iK3MrIngiK3ArKGE9PT1udWxsPyIgYXQ9KCIrbysiLCIrbisiKSI6IiBod25kPSIrYSsiIGNyb3A9KCIraSsiLCIrYysiKSBmcmFtZT0iK2UrIngiK3IpKTtpZighUyl0aHJvdyBuZXcgRXJyb3IoIkdldERJQml0cyBzaG9ydCByZWFkIG91dD0iK3MrIngiK3ApO3JldHVybnt3aWR0aDpzLGhlaWdodDpwfX1mdW5jdGlvbiBycih0KXtsZXQgZT1fKDApLHI9XygxKTtpZihlPD0wfHxyPD0wKXRocm93IG5ldyBFcnJvcigiR2V0U3lzdGVtTWV0cmljcyB3PSIrZSsiIGg9IityKTtyZXR1cm4gU2UodCxlLHIsMCwwLDAsMCxlLHIsbnVsbCl9ZnVuY3Rpb24gb3IodCxlLHIsbyl7aWYobz09PSJzY3JlZW4iJiZFdChlKSE9PTApdGhyb3cgbmV3IEVycm9yKCJ3aW5kb3cgbWluaW1pemVkXHVGRjFBbW9kZT1zY3JlZW4gXHU1M0VBXHU0RjFBXHU2MjJBXHU1MjMwXHU1QjgzXHU0RTBCXHU2NUI5XHU3Njg0XHU2ODRDXHU5NzYyXHVGRjBDXHU2NTM5XHU3NTI4IG1vZGU9cHJpbnQiKTtsZXQgbj1QLmFsbG9jKCk7aWYoIUR0KGUsbi5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0V2luZG93UmVjdChod25kPSIrZSsiKT0wXHVGRjFBXHU3QTk3XHU1M0UzXHU0RTBEXHU1QjU4XHU1NzI4XHU2MjE2XHU1REYyXHU5NTAwXHU2QkMxIik7bGV0e2xlZnQ6aSx0b3A6YyxyaWdodDpzLGJvdHRvbTpwfT1QLmRlY29kZShuKSxhPXMtaSx1PXAtYyx4PTAsZD0wLHc9YSxmPXU7aWYocj09PSJjbGllbnQiKXtsZXQgVz1QLmFsbG9jKCk7aWYoIXJlKGUsVy5wdHIpKXRocm93IG5ldyBFcnJvcigiR2V0Q2xpZW50UmVjdChod25kPSIrZSsiKT0wIik7bGV0e2xlZnQ6bCx0b3A6RCxyaWdodDpFLGJvdHRvbTpDfT1QLmRlY29kZShXKTt3PUUtbCxmPUMtRDtsZXQgaD1qLmVuY29kZSh7eDowLHk6MH0pO2lmKCFwZShlLGgucHRyKSl0aHJvdyBuZXcgRXJyb3IoIkNsaWVudFRvU2NyZWVuKGh3bmQ9IitlKyIpPTAiKTtsZXQgVD1qLmRlY29kZShoKTt4PVQueC1pLGQ9VC55LWN9bGV0IFM9bz09PSJwcmludCI/MDppK3gsbT1vPT09InByaW50Ij8wOmMrZDtpZihvPT09InNjcmVlbiIpe2xldCBXPV8oNzYpLGw9Xyg3NyksRD1fKDc4KSxFPV8oNzkpLEM9TWF0aC5tYXgoUyxXKSxoPU1hdGgubWF4KG0sbCksVD1NYXRoLm1pbihTK3csVytEKSxIPU1hdGgubWluKG0rZixsK0UpO2lmKFQ8PUN8fEg8PWgpdGhyb3cgbmV3IEVycm9yKCJjYXB0dXJlIGFyZWEgb3V0c2lkZSB2aXJ0dWFsIHNjcmVlbiBhdD0oIitTKyIsIittKyIsIit3KyJ4IitmKyIpIik7Uz1DLG09aCx3PVQtQyxmPUgtaH1yZXR1cm4gU2UodCxhLHUsUyxtLHgsZCx3LGYsbz09PSJwcmludCI/ZTpudWxsKX1mdW5jdGlvbiBucih0KXtsZXQgZT1bXSxyPV90KCI8SFdORD5wdHIgPD5wdHIgLT4gaTMyIixzPT4ocyYmZS5wdXNoKHMpLGUubGVuZ3RoPHFlPzE6MCkpO3RyeXthZShyLnB0cixJKX1maW5hbGx5e3IuZGlzcG9zZSgpfWxldCBvPVAuYWxsb2MoKSxuPUIuYWxsb2MoY3QpLGk9Qi5hbGxvYyhjdCksYz1bXTtmb3IobGV0IHMgb2YgZSlpZihEdChzLG8ucHRyKSl7bGV0IHA9UC5kZWNvZGUobyksYT1uZShzLG4sY3QpLHU9aWUocyxpLGN0KTtjLnB1c2goe2h3bmQ6cyx0aXRsZTphPjA/Qi5kZWNvZGUobik6IiIsY2xhc3NOYW1lOnU+MD9CLmRlY29kZShpKToiIixyZWN0OntsZWZ0OnAubGVmdCx0b3A6cC50b3AscmlnaHQ6cC5yaWdodCxib3R0b206cC5ib3R0b219LHZpc2libGU6b2UocykhPT0wLG1pbmltaXplZDpFdChzKSE9PTB9KX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQsY29kZTowLGVycm9yOm51bGwsd2luZG93czpjfSl9ZnVuY3Rpb24gaXIodCl7aWYodC50eXBlPT09InJ1biIpe2lmKHR5cGVvZiB0LmNtZCE9InN0cmluZyIpcmV0dXJuO2xldCBlPS0xLHI9bnVsbDt0cnl7ZT1LZSh0LmlkLHQuY21kKX1jYXRjaChvKXtyPVN0cmluZyhvKX1GLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTplLGVycm9yOnJ9KTtyZXR1cm59aWYodC50eXBlPT09IndpbmRvd3MiKXt0cnl7bnIodC5pZCl9Y2F0Y2goZSl7Ri5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixpZDp0LmlkLGNvZGU6LTEsZXJyb3I6U3RyaW5nKGUpfSl9cmV0dXJufWlmKHQudHlwZT09PSJzY3JlZW5zaG90Iil0cnl7bGV0IGU9dC5od25kPz9udWxsLHt3aWR0aDpyLGhlaWdodDpvfT1lPT09bnVsbD9ycih0LmlkKTpvcih0LmlkLGUsdC5hcmVhPz8id2luZG93Iix0Lm1vZGU/PyJzY3JlZW4iKTtGLnBvc3RNZXNzYWdlKHt0eXBlOiJyZXN1bHQiLGlkOnQuaWQsY29kZTowLGVycm9yOm51bGwsd2lkdGg6cixoZWlnaHQ6b30pfWNhdGNoKGUpe0YucG9zdE1lc3NhZ2Uoe3R5cGU6InJlc3VsdCIsaWQ6dC5pZCxjb2RlOi0xLGVycm9yOlN0cmluZyhlKX0pfX1GLm9ubWVzc2FnZT10PT57aXIodC5kYXRhKSxGLm9ubWVzc2FnZT1udWxsfTsK");
22035
- bumpWorkers(1);
22036
- const id = 1;
22037
- let settled = false;
22038
- let timer = null;
22039
- const settle = (r2) => {
22040
- if (settled)
22041
- return;
22042
- settled = true;
22043
- if (timer !== null)
22044
- os6.clearTimeout(timer);
22045
- worker.onmessage = null;
22046
- bumpWorkers(-1);
22047
- resolve(r2);
22048
- };
22049
- timer = os6.setTimeout(() => settle(onTimeout()), timeoutMs);
22050
- worker.onmessage = (e2) => {
22051
- const msg = e2.data;
22052
- if (msg.id !== void 0 && msg.id !== id)
22053
- return;
22054
- if (msg.type === "data") {
22055
- onData(msg.chunk);
22056
- return;
22057
- }
22058
- if (msg.type !== "result")
22059
- return;
22060
- settle(onResult(msg));
22061
- };
22062
- try {
22063
- worker.postMessage(post);
22064
- } catch (ex) {
22065
- settle(onResult({ type: "error", error: "spawn: " + String(ex) }));
22066
- }
22067
- });
22068
- }
22069
22165
  function jsonError(status, msg) {
22070
22166
  return new Response(JSON.stringify({ error: msg }), {
22071
22167
  status,
@@ -22074,79 +22170,389 @@ function jsonError(status, msg) {
22074
22170
  }
22075
22171
  function parseShotOpts(params) {
22076
22172
  const area = params.get("area") ?? "window";
22077
- const mode = params.get("mode") ?? "screen";
22078
22173
  if (area !== "window" && area !== "client")
22079
22174
  throw new Error('area must be "window" or "client"');
22080
- if (mode !== "screen" && mode !== "print")
22175
+ const rawMode = params.get("mode");
22176
+ if (rawMode !== null && rawMode !== "screen" && rawMode !== "print") {
22081
22177
  throw new Error('mode must be "screen" or "print"');
22178
+ }
22082
22179
  const raw = params.get("hwnd");
22083
- if (raw === null || raw === "")
22084
- return { hwnd: null, area, mode };
22085
- const hwnd = Number(raw);
22086
- if (!Number.isInteger(hwnd) || hwnd <= 0)
22180
+ const hwnd = raw === null || raw === "" ? null : Number(raw);
22181
+ if (hwnd !== null && (!Number.isInteger(hwnd) || hwnd <= 0)) {
22087
22182
  throw new Error("hwnd must be a positive integer");
22183
+ }
22184
+ const mode = rawMode ?? (hwnd === null ? "screen" : "print");
22088
22185
  return { hwnd, area, mode };
22089
22186
  }
22090
- function windowsResponse() {
22091
- return withWorker(WINDOWS_TIMEOUT_MS, () => jsonError(504, "windows timeout"), { type: "windows", id: 1 }, () => {
22092
- }, (msg) => msg.error ? jsonError(500, msg.error) : new Response(JSON.stringify(msg.windows ?? []), { headers: { "Content-Type": "application/json" } }));
22187
+ var SRCCOPY = 13369376;
22188
+ var DIB_RGB_COLORS = 0;
22189
+ var MAX_CAPTURE_PX = 4e7;
22190
+ var WIDE_BUF_CHARS = 512;
22191
+ var MAX_WINDOWS = 2e4;
22192
+ var BMP_HEADERS_SIZE = BITMAPFILEHEADER.size + BITMAPINFOHEADER.size;
22193
+ function bmpHeader(size, w2, h2) {
22194
+ const fileHdr = BITMAPFILEHEADER.encode({
22195
+ bfType: 19778,
22196
+ // 'BM'
22197
+ bfSize: BMP_HEADERS_SIZE + size,
22198
+ // 文件总长 = 头 + 像素
22199
+ bfOffBits: BMP_HEADERS_SIZE
22200
+ // 像素数据偏移
22201
+ });
22202
+ const infoHdr = BITMAPINFOHEADER.encode({
22203
+ biSize: BITMAPINFOHEADER.size,
22204
+ biWidth: w2,
22205
+ biHeight: -h2,
22206
+ // 负 = 顶向下
22207
+ biPlanes: 1,
22208
+ biBitCount: 32,
22209
+ biCompression: 0,
22210
+ // BI_RGB
22211
+ biSizeImage: size,
22212
+ biXPelsPerMeter: 2835,
22213
+ // 72dpi
22214
+ biYPelsPerMeter: 2835
22215
+ });
22216
+ const out = new Uint8Array(BMP_HEADERS_SIZE);
22217
+ out.set(new Uint8Array(fileHdr), 0);
22218
+ out.set(new Uint8Array(infoHdr), BITMAPFILEHEADER.size);
22219
+ return out;
22093
22220
  }
22094
- function screenshotResponse(opts) {
22095
- const parts = [];
22096
- let total = 0;
22097
- const post = { type: "screenshot", id: 1 };
22098
- if (opts.hwnd !== null) {
22099
- post.hwnd = opts.hwnd;
22100
- post.area = opts.area;
22101
- post.mode = opts.mode;
22102
- }
22103
- return withWorker(SCREENSHOT_TIMEOUT_MS, () => jsonError(504, "screenshot timeout"), post, (c2) => {
22104
- parts.push(c2);
22105
- total += c2.byteLength;
22106
- }, (msg) => {
22107
- if (msg.error)
22108
- return jsonError(500, msg.error);
22109
- if (total === 0)
22110
- return jsonError(500, "empty capture");
22111
- const buf = new Uint8Array(total);
22112
- let off = 0;
22113
- for (const p2 of parts) {
22114
- buf.set(p2, off);
22115
- off += p2.byteLength;
22221
+ function emitDib(hdc, hbm, w2, h2) {
22222
+ const pxB = new PtrArrayBuffer(w2 * h2 * 4);
22223
+ const px = new Uint8Array(pxB);
22224
+ const bmi = BITMAPINFOHEADER.encode({
22225
+ biSize: BITMAPINFOHEADER.size,
22226
+ biWidth: w2,
22227
+ biHeight: -h2,
22228
+ // 负 = 顶向下
22229
+ biPlanes: 1,
22230
+ biBitCount: 32,
22231
+ // biCompression 缺省 0 = BI_RGB
22232
+ biSizeImage: w2 * h2 * 4
22233
+ });
22234
+ const got = GetDIBits(hdc, hbm, 0, h2, pxB, bmi.ptr, DIB_RGB_COLORS);
22235
+ if (got !== h2)
22236
+ return null;
22237
+ const out = new Uint8Array(BMP_HEADERS_SIZE + px.byteLength);
22238
+ out.set(bmpHeader(px.byteLength, w2, h2), 0);
22239
+ out.set(px, BMP_HEADERS_SIZE);
22240
+ return out;
22241
+ }
22242
+ function printAndCrop(hdcScreen, hwnd, frameW, frameH, hdcOut, cropX, cropY, outW, outH) {
22243
+ const hdcTmp = CreateCompatibleDC(hdcScreen);
22244
+ const hbmTmp = hdcTmp ? CreateCompatibleBitmap(hdcScreen, frameW, frameH) : 0;
22245
+ if (!hdcTmp || !hbmTmp) {
22246
+ if (hdcTmp)
22247
+ DeleteDC(hdcTmp);
22248
+ return false;
22249
+ }
22250
+ const oldTmp = SelectObject(hdcTmp, hbmTmp);
22251
+ const printed = PrintWindow(hwnd, hdcTmp, 0) !== 0;
22252
+ const cropped = printed && BitBlt(hdcOut, 0, 0, outW, outH, hdcTmp, cropX, cropY, SRCCOPY) !== 0;
22253
+ SelectObject(hdcTmp, oldTmp);
22254
+ DeleteObject(hbmTmp);
22255
+ DeleteDC(hdcTmp);
22256
+ return cropped;
22257
+ }
22258
+ function captureRect(frameW, frameH, srcX, srcY, cropX, cropY, outW, outH, hwnd) {
22259
+ if (!(outW > 0 && outH > 0 && outW * outH <= MAX_CAPTURE_PX)) {
22260
+ throw new Error("capture size invalid w=" + outW + " h=" + outH);
22261
+ }
22262
+ if (hwnd !== null && !(cropX >= 0 && cropY >= 0 && cropX + outW <= frameW && cropY + outH <= frameH)) {
22263
+ throw new Error("capture crop out of range crop=(" + cropX + "," + cropY + "," + outW + "x" + outH + ") frame=" + frameW + "x" + frameH);
22264
+ }
22265
+ const hdcScreen = GetDC(NULL);
22266
+ if (!hdcScreen) {
22267
+ throw new Error("GetDC(NULL)=0\uFF1A\u65E0\u8F93\u5165\u684C\u9762\uFF08\u786E\u8BA4\u5728\u4EA4\u4E92 session \u542F\u52A8\uFF0C\u800C\u975E sshd/service\uFF09");
22268
+ }
22269
+ const hdcOut = CreateCompatibleDC(hdcScreen);
22270
+ const hbmOut = hdcOut ? CreateCompatibleBitmap(hdcScreen, outW, outH) : 0;
22271
+ if (!hdcOut || !hbmOut) {
22272
+ if (hdcOut)
22273
+ DeleteDC(hdcOut);
22274
+ ReleaseDC(NULL, hdcScreen);
22275
+ throw new Error("CreateCompatibleDC/Bitmap failed");
22276
+ }
22277
+ const oldOut = SelectObject(hdcOut, hbmOut);
22278
+ const ok = hwnd === null ? BitBlt(hdcOut, 0, 0, outW, outH, hdcScreen, srcX, srcY, SRCCOPY) !== 0 : printAndCrop(hdcScreen, hwnd, frameW, frameH, hdcOut, cropX, cropY, outW, outH);
22279
+ SelectObject(hdcOut, oldOut);
22280
+ const bmp = ok ? emitDib(hdcOut, hbmOut, outW, outH) : null;
22281
+ DeleteObject(hbmOut);
22282
+ DeleteDC(hdcOut);
22283
+ ReleaseDC(NULL, hdcScreen);
22284
+ if (!ok) {
22285
+ throw new Error("capture failed out=" + outW + "x" + outH + (hwnd === null ? " at=(" + srcX + "," + srcY + ")" : " hwnd=" + hwnd + " crop=(" + cropX + "," + cropY + ") frame=" + frameW + "x" + frameH));
22286
+ }
22287
+ if (!bmp)
22288
+ throw new Error("GetDIBits short read out=" + outW + "x" + outH);
22289
+ return { bmp, width: outW, height: outH };
22290
+ }
22291
+ function captureScreen() {
22292
+ const w2 = GetSystemMetrics(0);
22293
+ const h2 = GetSystemMetrics(1);
22294
+ if (w2 <= 0 || h2 <= 0)
22295
+ throw new Error("GetSystemMetrics w=" + w2 + " h=" + h2);
22296
+ return captureRect(w2, h2, 0, 0, 0, 0, w2, h2, null);
22297
+ }
22298
+ function captureWindow(hwnd, area, mode) {
22299
+ if (mode === "screen" && IsIconic(hwnd) !== 0) {
22300
+ throw new Error("window minimized\uFF1Amode=screen \u53EA\u4F1A\u622A\u5230\u5B83\u4E0B\u65B9\u7684\u684C\u9762\uFF0C\u53BB\u6389 mode=screen \u8BA9\u9ED8\u8BA4 print \u751F\u6548");
22301
+ }
22302
+ const wRect = RECT.alloc();
22303
+ if (!GetWindowRect(hwnd, wRect.ptr)) {
22304
+ throw new Error("GetWindowRect(hwnd=" + hwnd + ")=0\uFF1A\u7A97\u53E3\u4E0D\u5B58\u5728\u6216\u5DF2\u9500\u6BC1");
22305
+ }
22306
+ const { left: wl, top: wt2, right: wr2, bottom: wbot } = RECT.decode(wRect);
22307
+ const ww = wr2 - wl;
22308
+ const wh = wbot - wt2;
22309
+ let cropX = 0;
22310
+ let cropY = 0;
22311
+ let cw = ww;
22312
+ let ch = wh;
22313
+ if (area === "client") {
22314
+ const cRect = RECT.alloc();
22315
+ if (!GetClientRect(hwnd, cRect.ptr))
22316
+ throw new Error("GetClientRect(hwnd=" + hwnd + ")=0");
22317
+ const { left: cl, top: ct2, right: cr2, bottom: cbot } = RECT.decode(cRect);
22318
+ cw = cr2 - cl;
22319
+ ch = cbot - ct2;
22320
+ const origin = POINT.encode({ x: 0, y: 0 });
22321
+ if (!ClientToScreen(hwnd, origin.ptr))
22322
+ throw new Error("ClientToScreen(hwnd=" + hwnd + ")=0");
22323
+ const org = POINT.decode(origin);
22324
+ cropX = org.x - wl;
22325
+ cropY = org.y - wt2;
22326
+ }
22327
+ let sx = mode === "print" ? 0 : wl + cropX;
22328
+ let sy = mode === "print" ? 0 : wt2 + cropY;
22329
+ if (mode === "screen") {
22330
+ const vsX = GetSystemMetrics(76);
22331
+ const vsY = GetSystemMetrics(77);
22332
+ const vsW = GetSystemMetrics(78);
22333
+ const vsH = GetSystemMetrics(79);
22334
+ const ax = Math.max(sx, vsX);
22335
+ const ay = Math.max(sy, vsY);
22336
+ const ax2 = Math.min(sx + cw, vsX + vsW);
22337
+ const ay2 = Math.min(sy + ch, vsY + vsH);
22338
+ if (ax2 <= ax || ay2 <= ay) {
22339
+ throw new Error("capture area outside virtual screen at=(" + sx + "," + sy + "," + cw + "x" + ch + ")");
22116
22340
  }
22117
- const dims = msg.width !== void 0 && msg.height !== void 0 ? msg.width + "x" + msg.height : "";
22118
- return new Response(buf, {
22119
- headers: { "Content-Type": "image/bmp", "X-Dimensions": dims }
22120
- });
22341
+ sx = ax;
22342
+ sy = ay;
22343
+ cw = ax2 - ax;
22344
+ ch = ay2 - ay;
22345
+ }
22346
+ return captureRect(ww, wh, sx, sy, cropX, cropY, cw, ch, mode === "print" ? hwnd : null);
22347
+ }
22348
+ function listWindows() {
22349
+ const handles = [];
22350
+ const collect = closure("<HWND>ptr <>ptr -> i32", (h2) => {
22351
+ if (h2)
22352
+ handles.push(h2);
22353
+ return handles.length < MAX_WINDOWS ? 1 : 0;
22121
22354
  });
22355
+ try {
22356
+ EnumWindows(collect.ptr, NULL);
22357
+ } finally {
22358
+ collect.dispose();
22359
+ }
22360
+ const wRect = RECT.alloc();
22361
+ const tb = WCHAR.alloc(WIDE_BUF_CHARS);
22362
+ const cb = WCHAR.alloc(WIDE_BUF_CHARS);
22363
+ const out = [];
22364
+ for (const hwnd of handles) {
22365
+ if (GetWindowRect(hwnd, wRect.ptr)) {
22366
+ const rc2 = RECT.decode(wRect);
22367
+ const tl = GetWindowText(hwnd, tb, WIDE_BUF_CHARS);
22368
+ const cl = GetClassName(hwnd, cb, WIDE_BUF_CHARS);
22369
+ out.push({
22370
+ hwnd,
22371
+ // 缓冲跨窗口复用:长度 0 时 API 不保证写回终止符,不能 decode 残留内容
22372
+ title: tl > 0 ? WCHAR.decode(tb) : "",
22373
+ className: cl > 0 ? WCHAR.decode(cb) : "",
22374
+ rect: { left: rc2.left, top: rc2.top, right: rc2.right, bottom: rc2.bottom },
22375
+ visible: IsWindowVisible(hwnd) !== 0,
22376
+ minimized: IsIconic(hwnd) !== 0
22377
+ });
22378
+ }
22379
+ }
22380
+ return out;
22381
+ }
22382
+ var DISP_CHANGE_NAME = {
22383
+ [
22384
+ 0
22385
+ /* gui.DisplayChangeResult.SUCCESSFUL */
22386
+ ]: "SUCCESSFUL",
22387
+ [
22388
+ 1
22389
+ /* gui.DisplayChangeResult.RESTART */
22390
+ ]: "RESTART",
22391
+ [
22392
+ -1
22393
+ /* gui.DisplayChangeResult.FAILED */
22394
+ ]: "FAILED",
22395
+ [
22396
+ -2
22397
+ /* gui.DisplayChangeResult.BADMODE */
22398
+ ]: "BADMODE",
22399
+ [
22400
+ -3
22401
+ /* gui.DisplayChangeResult.NOTUPDATED */
22402
+ ]: "NOTUPDATED",
22403
+ [
22404
+ -4
22405
+ /* gui.DisplayChangeResult.BADFLAGS */
22406
+ ]: "BADFLAGS",
22407
+ [
22408
+ -5
22409
+ /* gui.DisplayChangeResult.BADPARAM */
22410
+ ]: "BADPARAM",
22411
+ [
22412
+ -6
22413
+ /* gui.DisplayChangeResult.BADDUALVIEW */
22414
+ ]: "BADDUALVIEW"
22415
+ };
22416
+ function dispChangeName(ret) {
22417
+ return DISP_CHANGE_NAME[ret] ?? "?";
22418
+ }
22419
+ function currentScreen() {
22420
+ return GetSystemMetrics(
22421
+ 0
22422
+ /* gui.SysMetrics.CXSCREEN */
22423
+ ) + "x" + GetSystemMetrics(
22424
+ 1
22425
+ /* gui.SysMetrics.CYSCREEN */
22426
+ );
22427
+ }
22428
+ function listModes32() {
22429
+ const probe = DEVMODEW.encode({ dmSize: DEVMODEW.size });
22430
+ const out = [];
22431
+ for (let i2 = 0; i2 < 200; i2++) {
22432
+ if (!EnumDisplaySettings(NULL, i2, probe.ptr))
22433
+ break;
22434
+ const dm = DEVMODEW.decode(probe);
22435
+ if (dm.dmBitsPerPel !== 32)
22436
+ continue;
22437
+ out.push(dm.dmPelsWidth + "x" + dm.dmPelsHeight + "@" + dm.dmDisplayFrequency);
22438
+ }
22439
+ return out;
22440
+ }
22441
+ function applyDisplayMode(w2, h2, persist) {
22442
+ if (!Number.isInteger(w2) || w2 <= 0 || !Number.isInteger(h2) || h2 <= 0) {
22443
+ throw new Error("applyDisplayMode: w/h must be positive integers, got " + w2 + "x" + h2);
22444
+ }
22445
+ const dm = DEVMODEW.encode({ dmSize: DEVMODEW.size });
22446
+ if (!EnumDisplaySettings(NULL, -1, dm.ptr)) {
22447
+ throw new Error("applyDisplayMode: EnumDisplaySettings CURRENT failed");
22448
+ }
22449
+ const cur = DEVMODEW.decode(dm);
22450
+ const before = cur.dmPelsWidth + "x" + cur.dmPelsHeight;
22451
+ DEVMODEW.encode({
22452
+ dmFields: cur.dmFields | 524288 | 1048576,
22453
+ dmPelsWidth: w2,
22454
+ dmPelsHeight: h2
22455
+ }, dm);
22456
+ const testRet = ChangeDisplaySettings(
22457
+ dm.ptr,
22458
+ 2
22459
+ /* gui.ChangeDisplayFlag.TEST */
22460
+ );
22461
+ if (testRet !== 0) {
22462
+ return {
22463
+ before,
22464
+ after: currentScreen(),
22465
+ testRet,
22466
+ ret: testRet,
22467
+ retName: dispChangeName(testRet),
22468
+ modes32: listModes32()
22469
+ };
22470
+ }
22471
+ let ret = ChangeDisplaySettings(dm.ptr, 0);
22472
+ if (ret === 0 && persist) {
22473
+ ret = ChangeDisplaySettings(
22474
+ dm.ptr,
22475
+ 1
22476
+ /* gui.ChangeDisplayFlag.UPDATEREGISTRY */
22477
+ );
22478
+ }
22479
+ return { before, after: currentScreen(), testRet, ret, retName: dispChangeName(ret), modes32: listModes32() };
22480
+ }
22481
+ var USAGE = `quickwin execd \u2014\u2014 \u672C\u9875\u5373\u7528\u6CD5\uFF08API \u4E4B\u5916\u4EFB\u610F\u8DEF\u5F84\u5747\u8FD4\u56DE\uFF0CHTTP 200\uFF09
22482
+
22483
+ API\uFF08\u914D\u7F6E token \u540E\u9700 Authorization: Bearer <token>\uFF0C\u672A\u914D\u7F6E\u5219\u653E\u884C\uFF09\uFF1A
22484
+ POST /exec JSON {"cmd":"\u547D\u4EE4","timeout":\u6BEB\u79D2?} \u2192 \u6D41\u5F0F\u8F93\u51FA\uFF0CTrailer X-Exit-Code
22485
+ GET /screenshot ?hwnd=<\u5341\u8FDB\u5236>&area=window|client&mode=screen|print \u2192 image/bmp
22486
+ \uFF08X-Dimensions\uFF1B\u4E0D\u5E26 hwnd = \u6574\u5C4F BitBlt\uFF1B\u5E26 hwnd \u9ED8\u8BA4 mode=print
22487
+ \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
+ GET /window_list \u2192 JSON \u7A97\u53E3\u5217\u8868 [{hwnd,title,className,...}]
22489
+ 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
+ {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`;
22492
+ function usageResponse() {
22493
+ return new Response(USAGE, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
22122
22494
  }
22123
22495
  var server = createServer(async (req) => {
22124
22496
  const t0 = Date.now();
22125
22497
  const path = new URL(req.url).pathname;
22126
- if (req.method === "GET" && (path === "/" || path === "/health")) {
22127
- return new Response("ok", { headers: { "Content-Type": "text/plain" } });
22128
- }
22498
+ const isApi = req.method === "POST" && (path === "/exec" || path === "/set_resolution") || req.method === "GET" && (path === "/window_list" || path === "/screenshot");
22499
+ if (!isApi)
22500
+ return usageResponse();
22129
22501
  const denied = authCheck(req);
22130
22502
  if (denied !== null) {
22131
- appendLog({ ts: Date.now() / 1e3, cmd: req.method + " " + path, status: 401, exit: null, durMs: Date.now() - t0, note: "missing/invalid token" });
22503
+ logReq(t0, req.method + " " + path, 401, "missing/invalid token");
22132
22504
  return denied;
22133
22505
  }
22134
22506
  if (req.method === "GET" && path === "/window_list") {
22135
- const resp = await windowsResponse();
22136
- appendLog({ ts: Date.now() / 1e3, cmd: "GET /window_list", status: resp.status, exit: null, durMs: Date.now() - t0 });
22137
- return resp;
22507
+ try {
22508
+ const wins = listWindows();
22509
+ const resp = new Response(JSON.stringify(wins), { headers: { "Content-Type": "application/json" } });
22510
+ logReq(t0, "GET /window_list", 200);
22511
+ return resp;
22512
+ } catch (ex) {
22513
+ logReq(t0, "GET /window_list", 500, String(ex));
22514
+ return jsonError(500, String(ex));
22515
+ }
22138
22516
  }
22139
22517
  if (req.method === "GET" && path === "/screenshot") {
22140
22518
  let opts;
22141
22519
  try {
22142
22520
  opts = parseShotOpts(new URL(req.url).searchParams);
22143
22521
  } catch (ex) {
22144
- appendLog({ ts: Date.now() / 1e3, cmd: "GET /screenshot", status: 400, exit: null, durMs: Date.now() - t0, note: String(ex) });
22522
+ logReq(t0, "GET /screenshot", 400, String(ex));
22145
22523
  return jsonError(400, String(ex));
22146
22524
  }
22147
- const resp = await screenshotResponse(opts);
22525
+ let cap;
22526
+ try {
22527
+ cap = opts.hwnd === null ? captureScreen() : captureWindow(opts.hwnd, opts.area, opts.mode);
22528
+ } catch (ex) {
22529
+ logReq(t0, "GET /screenshot", 500, String(ex));
22530
+ return jsonError(500, String(ex));
22531
+ }
22148
22532
  const target = opts.hwnd !== null ? " hwnd=" + opts.hwnd + " " + opts.area + "/" + opts.mode : " screen";
22149
- appendLog({ ts: Date.now() / 1e3, cmd: "GET /screenshot" + target, status: resp.status, exit: null, durMs: Date.now() - t0 });
22533
+ logReq(t0, "GET /screenshot" + target, 200);
22534
+ return new Response(cap.bmp, {
22535
+ headers: { "Content-Type": "image/bmp", "X-Dimensions": cap.width + "x" + cap.height }
22536
+ });
22537
+ }
22538
+ if (req.method === "POST" && path === "/set_resolution") {
22539
+ let result;
22540
+ let w2 = 0, h2 = 0, persist = true;
22541
+ try {
22542
+ const params = new URL(req.url).searchParams;
22543
+ w2 = Number(params.get("w"));
22544
+ h2 = Number(params.get("h"));
22545
+ if (!Number.isInteger(w2) || w2 <= 0 || !Number.isInteger(h2) || h2 <= 0) {
22546
+ throw new Error("w/h must be positive integers");
22547
+ }
22548
+ persist = params.get("persist") !== "0";
22549
+ result = applyDisplayMode(w2, h2, persist);
22550
+ } catch (ex) {
22551
+ logReq(t0, "POST /set_resolution", 400, String(ex));
22552
+ return jsonError(400, String(ex));
22553
+ }
22554
+ const resp = new Response(JSON.stringify(result), { headers: { "Content-Type": "application/json" } });
22555
+ logReq(t0, "POST /set_resolution " + w2 + "x" + h2 + (persist ? "" : " persist=0"), 200, result.ret !== 0 ? result.retName : void 0);
22150
22556
  return resp;
22151
22557
  }
22152
22558
  if (req.method === "POST" && path === "/exec") {
@@ -22159,29 +22565,17 @@ var server = createServer(async (req) => {
22159
22565
  cmd = body.cmd;
22160
22566
  out = runInWorker(body.cmd, req.signal, timeoutMs);
22161
22567
  } catch (ex) {
22162
- return new Response(JSON.stringify({ error: "setup: " + String(ex) }), {
22163
- status: 500,
22164
- headers: { "Content-Type": "application/json" }
22165
- });
22568
+ return jsonError(500, "setup: " + String(ex));
22166
22569
  }
22167
22570
  try {
22168
22571
  const rd = await out.ready;
22169
22572
  if (!rd.ok) {
22170
- appendLog({ ts: Date.now() / 1e3, cmd, status: 500, exit: null, durMs: Date.now() - t0, note: rd.error });
22171
- return new Response(JSON.stringify({ error: rd.error }), {
22172
- status: 500,
22173
- headers: { "Content-Type": "application/json" }
22174
- });
22573
+ logReq(t0, cmd, 500, rd.error);
22574
+ return jsonError(500, rd.error ?? "exec failed");
22175
22575
  }
22176
22576
  out.trailers.then((h2) => {
22177
22577
  const code = h2["X-Exit-Code"];
22178
- appendLog({
22179
- ts: Date.now() / 1e3,
22180
- cmd,
22181
- status: 200,
22182
- exit: code === void 0 ? null : Number(code),
22183
- durMs: Date.now() - t0
22184
- });
22578
+ logReq(t0, cmd, 200, void 0, code === void 0 ? null : Number(code));
22185
22579
  }).catch(() => {
22186
22580
  });
22187
22581
  return new Response(out.stream, {
@@ -22192,15 +22586,11 @@ var server = createServer(async (req) => {
22192
22586
  trailers: out.trailers
22193
22587
  });
22194
22588
  } catch (ex) {
22195
- appendLog({ ts: Date.now() / 1e3, cmd, status: 504, exit: null, durMs: Date.now() - t0, note: "exec timeout" });
22196
- return new Response(JSON.stringify({ error: String(ex) }), {
22197
- status: 504,
22198
- headers: { "Content-Type": "application/json" }
22199
- });
22589
+ logReq(t0, cmd, 504, "exec timeout");
22590
+ return jsonError(504, String(ex));
22200
22591
  }
22201
22592
  }
22202
- appendLog({ ts: Date.now() / 1e3, cmd: req.method + " " + path, status: 404, exit: null, durMs: Date.now() - t0 });
22203
- return new Response("Not Found", { status: 404 });
22593
+ return usageResponse();
22204
22594
  });
22205
22595
  var rc = server.listen(8080, "0.0.0.0");
22206
22596
  console.log("listen rc=" + rc + " addr=" + JSON.stringify(server.address()));