@ai-ecoverse/slicc-kernel 1.90.0 → 1.91.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.md +2 -1
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +481 -70
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +117 -86
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +498 -87
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +79 -48
- package/dist/process-worker.js.map +3 -3
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
|
@@ -2305,34 +2305,40 @@ function readyEvents(subs, ready) {
|
|
|
2305
2305
|
hangup: ready.hangup?.includes(s.fd) === true
|
|
2306
2306
|
}));
|
|
2307
2307
|
}
|
|
2308
|
+
function selectOnce(deps, read2, write2, timeoutMs) {
|
|
2309
|
+
try {
|
|
2310
|
+
const ready = deps.kernel.call({ op: "fd-select", read: read2, write: write2, timeoutMs });
|
|
2311
|
+
return { ready, interrupted: false };
|
|
2312
|
+
} catch (e) {
|
|
2313
|
+
if (!deps.interruptWakes || e.code !== "EINTR") throw e;
|
|
2314
|
+
return { ready: { read: [], write: [] }, interrupted: true };
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
function waitEvents(deps, subs, { events, read: read2, write: write2 }, entered) {
|
|
2318
|
+
const earliest = subs.reduce((min, s) => Math.min(min, s.deadline), Infinity);
|
|
2319
|
+
const timeout = () => {
|
|
2320
|
+
if (events.length > 0 || entered) return 0;
|
|
2321
|
+
return earliest === Infinity ? -1 : Math.max(0, Math.ceil(earliest - performance.now()));
|
|
2322
|
+
};
|
|
2323
|
+
for (; ; ) {
|
|
2324
|
+
const { ready, interrupted } = selectOnce(deps, read2, write2, timeout());
|
|
2325
|
+
events.push(...readyEvents(subs, ready));
|
|
2326
|
+
if (interrupted) return true;
|
|
2327
|
+
if (events.length > 0 || entered || earliest === Infinity) return false;
|
|
2328
|
+
if (performance.now() >= earliest) return false;
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2308
2331
|
function pollOneoff(deps, inPtr, outPtr, nsubs, neventsPtr) {
|
|
2309
2332
|
if (nsubs === 0) return E.INVAL;
|
|
2310
|
-
const { mem
|
|
2333
|
+
const { mem } = deps;
|
|
2311
2334
|
const subs = readSubscriptions(mem, inPtr, nsubs, deps.now);
|
|
2312
|
-
const
|
|
2313
|
-
|
|
2314
|
-
const
|
|
2315
|
-
const
|
|
2316
|
-
|
|
2317
|
-
do {
|
|
2318
|
-
let timeoutMs = -1;
|
|
2319
|
-
if (events.length > 0) timeoutMs = 0;
|
|
2320
|
-
else if (earliest !== Infinity)
|
|
2321
|
-
timeoutMs = Math.max(0, Math.ceil(earliest - performance.now()));
|
|
2322
|
-
let ready;
|
|
2323
|
-
try {
|
|
2324
|
-
ready = kernel.call({ op: "fd-select", read: read2, write: write2, timeoutMs });
|
|
2325
|
-
} catch (e) {
|
|
2326
|
-
if (!deps.interruptWakes || e.code !== "EINTR") throw e;
|
|
2327
|
-
interrupted = true;
|
|
2328
|
-
ready = { read: [], write: [] };
|
|
2329
|
-
}
|
|
2330
|
-
events.push(
|
|
2331
|
-
...readyEvents(subs, ready)
|
|
2332
|
-
);
|
|
2333
|
-
} while (events.length === 0 && !interrupted && earliest !== Infinity && !expired());
|
|
2334
|
-
}
|
|
2335
|
+
const found = classify(deps.fds, subs);
|
|
2336
|
+
const { events, read: read2, write: write2 } = found;
|
|
2337
|
+
const entered = deps.entered === true && deps.interruptWakes !== true;
|
|
2338
|
+
const waits = read2.length > 0 || write2.length > 0 || events.length === 0;
|
|
2339
|
+
const interrupted = waits && waitEvents(deps, subs, found, entered);
|
|
2335
2340
|
const after = performance.now();
|
|
2341
|
+
if (entered && events.length === 0 && !subs.some((s) => s.deadline <= after)) return E.INTR;
|
|
2336
2342
|
for (const s of subs) {
|
|
2337
2343
|
if (s.type === EVENTTYPE.CLOCK && (interrupted || s.deadline <= after)) {
|
|
2338
2344
|
events.push({ userdata: s.userdata, error: E.SUCCESS, type: s.type });
|
|
@@ -2538,6 +2544,7 @@ var init_wasi_host = __esm({
|
|
|
2538
2544
|
cache;
|
|
2539
2545
|
startCwd;
|
|
2540
2546
|
interruptWakes = false;
|
|
2547
|
+
entered = false;
|
|
2541
2548
|
onRaise;
|
|
2542
2549
|
muted;
|
|
2543
2550
|
signals;
|
|
@@ -2761,7 +2768,8 @@ var init_wasi_host = __esm({
|
|
|
2761
2768
|
fds: this.fds,
|
|
2762
2769
|
kernel: this.o.kernel,
|
|
2763
2770
|
now: (id) => this.now(id),
|
|
2764
|
-
interruptWakes: this.interruptWakes
|
|
2771
|
+
interruptWakes: this.interruptWakes,
|
|
2772
|
+
entered: this.entered
|
|
2765
2773
|
},
|
|
2766
2774
|
inPtr,
|
|
2767
2775
|
outPtr,
|
|
@@ -2778,7 +2786,7 @@ var init_wasi_host = __esm({
|
|
|
2778
2786
|
this.mem.view().setUint32(nevents, 0, true);
|
|
2779
2787
|
if (mask.deliverUnblocked()) return E.INTR;
|
|
2780
2788
|
if (n > 0) return this.poll(inPtr, outPtr, n, nevents);
|
|
2781
|
-
return this.suspend();
|
|
2789
|
+
return this.entered ? E.INTR : this.suspend();
|
|
2782
2790
|
} finally {
|
|
2783
2791
|
mask.deliverUnblocked();
|
|
2784
2792
|
mask.restore(old);
|
|
@@ -3876,7 +3884,7 @@ var KERNEL_VERSION, OS_RELEASE;
|
|
|
3876
3884
|
var init_version = __esm({
|
|
3877
3885
|
"src/version.ts"() {
|
|
3878
3886
|
"use strict";
|
|
3879
|
-
KERNEL_VERSION = true ? "1.
|
|
3887
|
+
KERNEL_VERSION = true ? "1.91.0" : "0.0.0-dev";
|
|
3880
3888
|
OS_RELEASE = "6.0.0-slicc";
|
|
3881
3889
|
}
|
|
3882
3890
|
});
|
|
@@ -4812,6 +4820,52 @@ var init_js_exit = __esm({
|
|
|
4812
4820
|
}
|
|
4813
4821
|
});
|
|
4814
4822
|
|
|
4823
|
+
// src/kernel/net/loopback-names.ts
|
|
4824
|
+
function isKernelLoopbackHost(hostname) {
|
|
4825
|
+
const host = hostname.replace(/^\[(.*)\]$/, "$1").replace(/\.$/, "").toLowerCase();
|
|
4826
|
+
return host === "localhost" || host.endsWith(".localhost") || host === "0.0.0.0" || LOOPBACK_V4.test(host) || LOOPBACK_V6.has(host) || MAPPED_V4.test(host);
|
|
4827
|
+
}
|
|
4828
|
+
function reserved(name2) {
|
|
4829
|
+
const lower = name2.toLowerCase();
|
|
4830
|
+
return lower === "localhost" || lower.endsWith(".localhost") || lower === HOST_LOOPBACK || lower === "wasmer.sh" || /^\d+(\.\d+){3}$/.test(lower);
|
|
4831
|
+
}
|
|
4832
|
+
function isHostname(name2) {
|
|
4833
|
+
if (typeof name2 !== "string" || name2.length > 253 || reserved(name2)) return false;
|
|
4834
|
+
return name2.split(".").every((l) => LABEL.test(l));
|
|
4835
|
+
}
|
|
4836
|
+
function hostnameOf(env) {
|
|
4837
|
+
return isHostname(env.HOSTNAME) ? env.HOSTNAME : DEFAULT_HOSTNAME;
|
|
4838
|
+
}
|
|
4839
|
+
function ownNames(hostname) {
|
|
4840
|
+
return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
|
|
4841
|
+
}
|
|
4842
|
+
function hostsFile(hostname = DEFAULT_HOSTNAME) {
|
|
4843
|
+
return [
|
|
4844
|
+
"127.0.0.1 localhost localhost.localdomain",
|
|
4845
|
+
"::1 localhost ip6-localhost",
|
|
4846
|
+
`${HOSTNAME_ADDRESS} ${ownNames(hostname).join(" ")}`,
|
|
4847
|
+
`${HOST_LOOPBACK_ADDRESS.join(".")} ${HOST_LOOPBACK}`,
|
|
4848
|
+
""
|
|
4849
|
+
].join("\n");
|
|
4850
|
+
}
|
|
4851
|
+
var HOST_LOOPBACK, HOST_LOOPBACK_ADDRESS, PAGE_LOOPBACK, PAGE_LOOPBACK_URL, LOOPBACK_V4, LOOPBACK_V6, MAPPED_V4, DEFAULT_HOSTNAME, HOSTNAME_ADDRESS, LIBC_HOSTNAMES, LABEL;
|
|
4852
|
+
var init_loopback_names = __esm({
|
|
4853
|
+
"src/kernel/net/loopback-names.ts"() {
|
|
4854
|
+
"use strict";
|
|
4855
|
+
HOST_LOOPBACK = "host.slicc.internal";
|
|
4856
|
+
HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
|
|
4857
|
+
PAGE_LOOPBACK = "kernel.localhost";
|
|
4858
|
+
PAGE_LOOPBACK_URL = `http://{port}.${PAGE_LOOPBACK}`;
|
|
4859
|
+
LOOPBACK_V4 = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
4860
|
+
LOOPBACK_V6 = /* @__PURE__ */ new Set(["::1", "::", "0:0:0:0:0:0:0:1"]);
|
|
4861
|
+
MAPPED_V4 = /^::ffff:7f[0-9a-f]{2}:[0-9a-f]{1,4}$/;
|
|
4862
|
+
DEFAULT_HOSTNAME = "slicc";
|
|
4863
|
+
HOSTNAME_ADDRESS = "127.0.1.1";
|
|
4864
|
+
LIBC_HOSTNAMES = ["emscripten", "wasmer.sh"];
|
|
4865
|
+
LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
|
|
4866
|
+
}
|
|
4867
|
+
});
|
|
4868
|
+
|
|
4815
4869
|
// src/process/js/js-fetch.ts
|
|
4816
4870
|
function withoutFragment(url) {
|
|
4817
4871
|
url.hash = "";
|
|
@@ -4826,11 +4880,20 @@ function plain(status2, text) {
|
|
|
4826
4880
|
headers: { "content-type": "text/plain; charset=utf-8" }
|
|
4827
4881
|
});
|
|
4828
4882
|
}
|
|
4883
|
+
function local2(url) {
|
|
4884
|
+
return isKernelLoopbackHost(new URL(url).hostname);
|
|
4885
|
+
}
|
|
4829
4886
|
function rewrite(hop, status2, location) {
|
|
4830
4887
|
const next2 = new URL(location, hop.url);
|
|
4831
4888
|
if (next2.protocol !== "http:" && next2.protocol !== "https:") {
|
|
4832
4889
|
throw failed(new JsCallError("EPROTONOSUPPORT", next2.protocol));
|
|
4833
4890
|
}
|
|
4891
|
+
if (local2(next2.href) && !local2(hop.url)) {
|
|
4892
|
+
const from = new URL(hop.url).origin;
|
|
4893
|
+
throw failed(
|
|
4894
|
+
new JsCallError("EACCES", `a redirect from ${from} into the kernel's loopback: ${next2.href}`)
|
|
4895
|
+
);
|
|
4896
|
+
}
|
|
4834
4897
|
const toGet = (status2 === 301 || status2 === 302) && hop.method === "POST" || status2 === 303 && hop.method !== "GET" && hop.method !== "HEAD";
|
|
4835
4898
|
const crossOrigin = next2.origin !== new URL(hop.url).origin;
|
|
4836
4899
|
const headers = hop.headers.filter(
|
|
@@ -4999,13 +5062,15 @@ async function bodyOf(request, cap, signal) {
|
|
|
4999
5062
|
return out;
|
|
5000
5063
|
}
|
|
5001
5064
|
function fetchOp(kernel) {
|
|
5002
|
-
|
|
5003
|
-
const traitsOf = () => {
|
|
5004
|
-
|
|
5005
|
-
traits.
|
|
5006
|
-
|
|
5065
|
+
const traits = /* @__PURE__ */ new Map();
|
|
5066
|
+
const traitsOf = (url) => {
|
|
5067
|
+
const own = local2(url);
|
|
5068
|
+
const known = traits.get(own) ?? kernel.json({ op: "net-traits", url });
|
|
5069
|
+
traits.set(own, known);
|
|
5070
|
+
known.catch(() => {
|
|
5071
|
+
traits.delete(own);
|
|
5007
5072
|
});
|
|
5008
|
-
return
|
|
5073
|
+
return known;
|
|
5009
5074
|
};
|
|
5010
5075
|
const close = (handle) => kernel.raw({ op: "net-close", handle });
|
|
5011
5076
|
const send = async (hop, signal) => {
|
|
@@ -5092,6 +5157,13 @@ function fetchOp(kernel) {
|
|
|
5092
5157
|
});
|
|
5093
5158
|
return withMeta(response, head.url, redirected);
|
|
5094
5159
|
};
|
|
5160
|
+
const traitsAt = (at) => traitsOf(at).catch((err) => {
|
|
5161
|
+
throw failed(err);
|
|
5162
|
+
});
|
|
5163
|
+
const redirect = async (hop, status2, location, known) => {
|
|
5164
|
+
const next2 = rewrite(hop, status2, location);
|
|
5165
|
+
return [next2, local2(next2.url) === local2(hop.url) ? known : await traitsAt(next2.url)];
|
|
5166
|
+
};
|
|
5095
5167
|
return async (input, init) => {
|
|
5096
5168
|
const request = new Request(input, init);
|
|
5097
5169
|
const { signal } = request;
|
|
@@ -5101,9 +5173,7 @@ function fetchOp(kernel) {
|
|
|
5101
5173
|
if (protocol !== "http:" && protocol !== "https:") {
|
|
5102
5174
|
throw failed(new JsCallError("EPROTONOSUPPORT", protocol));
|
|
5103
5175
|
}
|
|
5104
|
-
|
|
5105
|
-
throw failed(err);
|
|
5106
|
-
});
|
|
5176
|
+
let known = await traitsAt(request.url);
|
|
5107
5177
|
if (!known.manualRedirects && request.redirect !== "follow") {
|
|
5108
5178
|
throw failed(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
|
|
5109
5179
|
}
|
|
@@ -5129,7 +5199,7 @@ function fetchOp(kernel) {
|
|
|
5129
5199
|
await close(head.handle);
|
|
5130
5200
|
if (request.redirect === "error") throw failed(new JsCallError("EREDIRECT", hop.url));
|
|
5131
5201
|
if (hops >= MAX_REDIRECTS) throw failed(new JsCallError("ELOOP", hop.url));
|
|
5132
|
-
hop =
|
|
5202
|
+
[hop, known] = await redirect(hop, head.status, location, known);
|
|
5133
5203
|
}
|
|
5134
5204
|
};
|
|
5135
5205
|
}
|
|
@@ -5137,6 +5207,7 @@ var CHUNK2, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTI
|
|
|
5137
5207
|
var init_js_fetch = __esm({
|
|
5138
5208
|
"src/process/js/js-fetch.ts"() {
|
|
5139
5209
|
"use strict";
|
|
5210
|
+
init_loopback_names();
|
|
5140
5211
|
init_js_kernel();
|
|
5141
5212
|
CHUNK2 = 64 * 1024;
|
|
5142
5213
|
MAX_REDIRECTS = 20;
|
|
@@ -5176,7 +5247,7 @@ function port(n) {
|
|
|
5176
5247
|
function netOps(kernel, io) {
|
|
5177
5248
|
const name2 = async (fd, peer) => addressOf(await kernel.json({ op: "sock-name", fd, peer }));
|
|
5178
5249
|
const connection = async (fd) => {
|
|
5179
|
-
const [
|
|
5250
|
+
const [local3, remote] = [await name2(fd, false), await name2(fd, true)];
|
|
5180
5251
|
const stop = new AbortController();
|
|
5181
5252
|
let closed;
|
|
5182
5253
|
const close = () => {
|
|
@@ -5201,7 +5272,7 @@ function netOps(kernel, io) {
|
|
|
5201
5272
|
close: async () => void await shut(SHUT_WR),
|
|
5202
5273
|
abort: () => close()
|
|
5203
5274
|
});
|
|
5204
|
-
return { fd, local:
|
|
5275
|
+
return { fd, local: local3, remote, readable: readable3, writable: writable2, close };
|
|
5205
5276
|
};
|
|
5206
5277
|
const resolve = async (host, signal) => {
|
|
5207
5278
|
if (IPV4.test(host)) return host;
|
|
@@ -5301,45 +5372,6 @@ var init_js_net = __esm({
|
|
|
5301
5372
|
}
|
|
5302
5373
|
});
|
|
5303
5374
|
|
|
5304
|
-
// src/kernel/net/loopback-names.ts
|
|
5305
|
-
function reserved(name2) {
|
|
5306
|
-
const lower = name2.toLowerCase();
|
|
5307
|
-
return lower === "localhost" || lower.endsWith(".localhost") || lower === HOST_LOOPBACK || lower === "wasmer.sh" || /^\d+(\.\d+){3}$/.test(lower);
|
|
5308
|
-
}
|
|
5309
|
-
function isHostname(name2) {
|
|
5310
|
-
if (typeof name2 !== "string" || name2.length > 253 || reserved(name2)) return false;
|
|
5311
|
-
return name2.split(".").every((l) => LABEL.test(l));
|
|
5312
|
-
}
|
|
5313
|
-
function hostnameOf(env) {
|
|
5314
|
-
return isHostname(env.HOSTNAME) ? env.HOSTNAME : DEFAULT_HOSTNAME;
|
|
5315
|
-
}
|
|
5316
|
-
function ownNames(hostname) {
|
|
5317
|
-
return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
|
|
5318
|
-
}
|
|
5319
|
-
function hostsFile(hostname = DEFAULT_HOSTNAME) {
|
|
5320
|
-
return [
|
|
5321
|
-
"127.0.0.1 localhost localhost.localdomain",
|
|
5322
|
-
"::1 localhost ip6-localhost",
|
|
5323
|
-
`${HOSTNAME_ADDRESS} ${ownNames(hostname).join(" ")}`,
|
|
5324
|
-
`${HOST_LOOPBACK_ADDRESS.join(".")} ${HOST_LOOPBACK}`,
|
|
5325
|
-
""
|
|
5326
|
-
].join("\n");
|
|
5327
|
-
}
|
|
5328
|
-
var HOST_LOOPBACK, HOST_LOOPBACK_ADDRESS, PAGE_LOOPBACK, PAGE_LOOPBACK_URL, DEFAULT_HOSTNAME, HOSTNAME_ADDRESS, LIBC_HOSTNAMES, LABEL;
|
|
5329
|
-
var init_loopback_names = __esm({
|
|
5330
|
-
"src/kernel/net/loopback-names.ts"() {
|
|
5331
|
-
"use strict";
|
|
5332
|
-
HOST_LOOPBACK = "host.slicc.internal";
|
|
5333
|
-
HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
|
|
5334
|
-
PAGE_LOOPBACK = "kernel.localhost";
|
|
5335
|
-
PAGE_LOOPBACK_URL = `http://{port}.${PAGE_LOOPBACK}`;
|
|
5336
|
-
DEFAULT_HOSTNAME = "slicc";
|
|
5337
|
-
HOSTNAME_ADDRESS = "127.0.1.1";
|
|
5338
|
-
LIBC_HOSTNAMES = ["emscripten", "wasmer.sh"];
|
|
5339
|
-
LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
|
|
5340
|
-
}
|
|
5341
|
-
});
|
|
5342
|
-
|
|
5343
5375
|
// src/process/wasi-errno.ts
|
|
5344
5376
|
function wasiErrno(code2) {
|
|
5345
5377
|
return WASI_ERRNO[code2] ?? E.IO;
|
|
@@ -10292,12 +10324,12 @@ function anySelect(Fs, transport, read2, write2, timeoutMs) {
|
|
|
10292
10324
|
const kernelRead = read2.filter((fd) => !own(fd));
|
|
10293
10325
|
const kernelWrite = write2.filter((fd) => !own(fd));
|
|
10294
10326
|
for (; ; ) {
|
|
10295
|
-
const
|
|
10296
|
-
const pending =
|
|
10327
|
+
const local3 = ownReady(Fs, read2.filter(own), write2.filter(own));
|
|
10328
|
+
const pending = local3.read.length > 0 || local3.write.length > 0;
|
|
10297
10329
|
const slice = pending ? 0 : Math.min(SELECT_SLICE_MS, Math.max(0, deadline - Date.now()));
|
|
10298
10330
|
const got = kernelSelect(Fs, transport, kernelRead, kernelWrite, slice);
|
|
10299
10331
|
if (typeof got === "number") return got;
|
|
10300
|
-
const ready = { read: [...
|
|
10332
|
+
const ready = { read: [...local3.read, ...got.read], write: [...local3.write, ...got.write] };
|
|
10301
10333
|
if (ready.read.length > 0 || ready.write.length > 0 || Date.now() >= deadline) {
|
|
10302
10334
|
return ready;
|
|
10303
10335
|
}
|
|
@@ -13393,10 +13425,8 @@ var init_wasix_host = __esm({
|
|
|
13393
13425
|
const v = mem.view();
|
|
13394
13426
|
const timed = timeoutPtr !== 0 && v.getUint8(timeoutPtr) === 1;
|
|
13395
13427
|
const ms = timed ? Number(v.getBigUint64(timeoutPtr + 8, true)) / 1e6 : Number.POSITIVE_INFINITY;
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
futexWait(i32(), ptr >> 2, expected | 0, ms, host.interrupted) ? 1 : 0
|
|
13399
|
-
);
|
|
13428
|
+
const woken = host.entered || futexWait(i32(), ptr >> 2, expected | 0, ms, host.interrupted);
|
|
13429
|
+
v.setUint8(wokenPtr, woken ? 1 : 0);
|
|
13400
13430
|
},
|
|
13401
13431
|
futex_wake: (ptr, wokenPtr) => {
|
|
13402
13432
|
Atomics.notify(i32(), ptr >> 2, 1);
|
|
@@ -13564,9 +13594,10 @@ function delivering(ns, table, host, driver, before) {
|
|
|
13564
13594
|
}
|
|
13565
13595
|
const fn = value2;
|
|
13566
13596
|
out[name2] = (...args) => {
|
|
13597
|
+
host.entered = false;
|
|
13567
13598
|
if (driver.idle) {
|
|
13568
13599
|
before?.();
|
|
13569
|
-
host.interrupted?.();
|
|
13600
|
+
host.entered = host.interrupted?.() === true;
|
|
13570
13601
|
}
|
|
13571
13602
|
return fn(...args);
|
|
13572
13603
|
};
|