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.
- package/README.en.md +8 -8
- package/README.md +6 -7
- package/examples/{exec_server.js → execd.js} +618 -228
- package/examples/execd.tsx +798 -0
- package/examples/execd_worker.js +122 -0
- package/examples/execd_worker.ts +127 -0
- package/examples/pdf_viewer.js +100 -111
- package/examples/test_gallery.js +100 -111
- package/examples/test_react_lazy.js +96 -109
- package/examples/test_react_listbox.js +96 -109
- package/examples/test_root_window.js +96 -109
- package/examples/test_tab.js +96 -109
- package/lib/ffi/ctype.ts +3 -1
- package/lib/ffi/struct.js +23 -7
- package/lib/ffi/struct.ts +50 -23
- package/lib/http-server.js +1 -1
- package/lib/http-server.ts +1 -1
- package/lib/windows/gdi32.js +1 -1
- package/lib/windows/gdi32.ts +1 -1
- package/lib/windows/structs.js +176 -92
- package/lib/windows/structs.ts +216 -92
- package/package.json +1 -1
- package/quickwin_const.d.ts +26 -0
- package/qwin-nowasm-x86.exe +0 -0
- package/qwin-nowasm.exe +0 -0
- package/qwin-x86.exe +0 -0
- package/qwin.exe +0 -0
- package/test/test_ffi_bind.js +5 -3
- package/test/test_ffi_bind.ts +6 -4
- package/test/test_ffi_struct.js +58 -24
- package/test/test_ffi_struct.ts +55 -25
- package/test/test_gdi_draw.js +1 -1
- package/test/test_gdi_draw.ts +1 -1
- package/test/test_react_complex.js +96 -109
- package/test/test_react_counter.js +96 -109
- package/test/test_react_flex.js +96 -109
- package/test/test_react_hidden.js +96 -109
- package/test/test_react_listview_link.js +96 -109
- package/test/test_react_notify.js +96 -109
- package/test/test_react_render.js +96 -109
- package/examples/exec_server.tsx +0 -489
- package/examples/exec_server_worker.js +0 -395
- package/examples/exec_server_worker.ts +0 -417
- package/examples/setres.js +0 -79
- package/examples/setres.ts +0 -86
|
@@ -15353,7 +15353,7 @@ var require_constants = __commonJS({
|
|
|
15353
15353
|
}
|
|
15354
15354
|
});
|
|
15355
15355
|
|
|
15356
|
-
// _build/examples/
|
|
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/
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
19946
|
-
|
|
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:
|
|
19949
|
-
}
|
|
19950
|
-
var
|
|
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
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
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
|
|
19972
|
-
|
|
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
|
|
19985
|
-
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
20019
|
-
}
|
|
20020
|
-
var
|
|
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
|
|
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
|
|
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
|
|
20058
|
-
|
|
20059
|
-
|
|
20060
|
-
|
|
20061
|
-
|
|
20062
|
-
|
|
20063
|
-
|
|
20064
|
-
|
|
20065
|
-
|
|
20066
|
-
|
|
20067
|
-
|
|
20068
|
-
|
|
20069
|
-
|
|
20070
|
-
|
|
20071
|
-
|
|
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/
|
|
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
|
-
|
|
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: "
|
|
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("[
|
|
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("[
|
|
22092
|
+
console.error("[execd] taskkill spawn failed");
|
|
21958
22093
|
} catch (ex) {
|
|
21959
|
-
console.error("[
|
|
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
|
-
|
|
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
|
-
|
|
22084
|
-
|
|
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
|
-
|
|
22091
|
-
|
|
22092
|
-
|
|
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
|
|
22095
|
-
const
|
|
22096
|
-
|
|
22097
|
-
const
|
|
22098
|
-
|
|
22099
|
-
|
|
22100
|
-
|
|
22101
|
-
|
|
22102
|
-
|
|
22103
|
-
|
|
22104
|
-
|
|
22105
|
-
|
|
22106
|
-
}
|
|
22107
|
-
|
|
22108
|
-
|
|
22109
|
-
|
|
22110
|
-
|
|
22111
|
-
|
|
22112
|
-
|
|
22113
|
-
|
|
22114
|
-
|
|
22115
|
-
|
|
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
|
-
|
|
22118
|
-
|
|
22119
|
-
|
|
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
|
-
|
|
22127
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22136
|
-
|
|
22137
|
-
|
|
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
|
-
|
|
22522
|
+
logReq(t0, "GET /screenshot", 400, String(ex));
|
|
22145
22523
|
return jsonError(400, String(ex));
|
|
22146
22524
|
}
|
|
22147
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
22171
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
22196
|
-
return
|
|
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
|
-
|
|
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()));
|