@formant/data-sdk 1.47.0 → 1.49.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/dist/data-sdk.cjs.js +2 -2
- package/dist/data-sdk.cjs.js.map +1 -1
- package/dist/data-sdk.es.js +153 -106
- package/dist/data-sdk.es.js.map +1 -1
- package/dist/data-sdk.es6.js +153 -106
- package/dist/data-sdk.umd.js +2 -2
- package/dist/types/data-sdk/src/config/whichFormantApiUrl.d.ts +1 -1
- package/dist/types/data-sdk/src/connector/data/BaseUniverseDataConnector.d.ts +2 -0
- package/dist/types/data-sdk/src/connector/data/LiveUniverseData.d.ts +1 -1
- package/dist/types/data-sdk/src/connector/data/TelemetryUniverseData.d.ts +3 -2
- package/dist/types/data-sdk/src/connector/model/IUniverseData.d.ts +3 -1
- package/dist/types/data-sdk/src/connector/model/IUniverseOdometry.d.ts +1 -0
- package/package.json +1 -1
package/dist/data-sdk.es.js
CHANGED
|
@@ -2,8 +2,16 @@ var Rn = Object.defineProperty;
|
|
|
2
2
|
var Bn = (e, t, n) => t in e ? Rn(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
|
|
3
3
|
var he = (e, t, n) => (Bn(e, typeof t != "symbol" ? t + "" : t, n), n);
|
|
4
4
|
const DEFAULT_FORMANT_API_URL = "https://api.formant.io";
|
|
5
|
-
function whichFormantApiUrl(e, t) {
|
|
5
|
+
function whichFormantApiUrl(e, t, n) {
|
|
6
6
|
try {
|
|
7
|
+
if (n) {
|
|
8
|
+
if (n.includes("app-dev.formant.io") || n.includes("localhost"))
|
|
9
|
+
return "https://api-dev.formant.io";
|
|
10
|
+
if (n.includes("app-stage.formant.io"))
|
|
11
|
+
return "https://api-stage.formant.io";
|
|
12
|
+
if (n.includes("app.formant.io"))
|
|
13
|
+
return "https://api.formant.local";
|
|
14
|
+
}
|
|
7
15
|
if (t.get("formant_stage"))
|
|
8
16
|
return "https://api-stage.formant.io";
|
|
9
17
|
if (t.get("formant_dev"))
|
|
@@ -11,13 +19,13 @@ function whichFormantApiUrl(e, t) {
|
|
|
11
19
|
if (t.get("formant_local"))
|
|
12
20
|
return "https://api.formant.local";
|
|
13
21
|
if (t.get("formant_url")) {
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
22
|
+
const r = t.get("formant_url");
|
|
23
|
+
if (r !== null)
|
|
16
24
|
try {
|
|
17
|
-
return new URL(
|
|
25
|
+
return new URL(r).origin;
|
|
18
26
|
} catch {
|
|
19
27
|
console.warn(
|
|
20
|
-
`Ignoring malformed \`formant_url\` url parameter: ${
|
|
28
|
+
`Ignoring malformed \`formant_url\` url parameter: ${r}`
|
|
21
29
|
);
|
|
22
30
|
}
|
|
23
31
|
}
|
|
@@ -29,7 +37,8 @@ const FORMANT_API_URL = whichFormantApiUrl(
|
|
|
29
37
|
typeof window != "undefined" ? window : globalThis,
|
|
30
38
|
new URLSearchParams(
|
|
31
39
|
typeof window != "undefined" && window.location ? window.location.search : void 0
|
|
32
|
-
)
|
|
40
|
+
),
|
|
41
|
+
typeof window != "undefined" && window.location ? window.location.host : void 0
|
|
33
42
|
);
|
|
34
43
|
var commonjsGlobal = typeof globalThis != "undefined" ? globalThis : typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : {};
|
|
35
44
|
function getDefaultExportFromCjs(e) {
|
|
@@ -31642,6 +31651,12 @@ class BasicUniverseDataConnector {
|
|
|
31642
31651
|
setTime(t) {
|
|
31643
31652
|
t !== "live" && (this.time = t), this.timeChangeListeners.forEach((n) => n(t));
|
|
31644
31653
|
}
|
|
31654
|
+
getTime() {
|
|
31655
|
+
return this.time;
|
|
31656
|
+
}
|
|
31657
|
+
getTimeMs() {
|
|
31658
|
+
return this.time === "live" ? (/* @__PURE__ */ new Date()).getTime() : this.time.getTime();
|
|
31659
|
+
}
|
|
31645
31660
|
getAvailablePCDWorker() {
|
|
31646
31661
|
for (let t = 0; t < PCD_WORKER_POOL_SIZE; t++)
|
|
31647
31662
|
if (!this.pcdWorkerPoolOccupancy[t])
|
|
@@ -31895,35 +31910,35 @@ class LiveUniverseData extends BasicUniverseDataConnector {
|
|
|
31895
31910
|
}
|
|
31896
31911
|
throw new Error("Telemetry bitset not implemented");
|
|
31897
31912
|
}
|
|
31898
|
-
subscribeToOdometry(t, n, r) {
|
|
31913
|
+
subscribeToOdometry(t, n, r, o) {
|
|
31899
31914
|
if (n.sourceType === "realtime") {
|
|
31900
|
-
const
|
|
31901
|
-
if (
|
|
31902
|
-
const
|
|
31915
|
+
const s = (g, l) => {
|
|
31916
|
+
if (l.payload.odometry) {
|
|
31917
|
+
const u = l.payload.odometry;
|
|
31903
31918
|
r({
|
|
31904
|
-
worldToLocal:
|
|
31919
|
+
worldToLocal: u.worldToLocal,
|
|
31905
31920
|
pose: {
|
|
31906
31921
|
translation: {
|
|
31907
|
-
x:
|
|
31908
|
-
y:
|
|
31909
|
-
z:
|
|
31922
|
+
x: u.pose.translation.x,
|
|
31923
|
+
y: u.pose.translation.y,
|
|
31924
|
+
z: u.pose.translation.z
|
|
31910
31925
|
},
|
|
31911
31926
|
rotation: {
|
|
31912
|
-
x:
|
|
31913
|
-
y:
|
|
31914
|
-
z:
|
|
31915
|
-
w:
|
|
31927
|
+
x: u.pose.rotation.x,
|
|
31928
|
+
y: u.pose.rotation.y,
|
|
31929
|
+
z: u.pose.rotation.z,
|
|
31930
|
+
w: u.pose.rotation.w
|
|
31916
31931
|
}
|
|
31917
31932
|
},
|
|
31918
31933
|
covariance: []
|
|
31919
31934
|
});
|
|
31920
31935
|
}
|
|
31921
31936
|
};
|
|
31922
|
-
return this.subscribeToRealtimeMessages(t, n.rosTopicName,
|
|
31937
|
+
return this.subscribeToRealtimeMessages(t, n.rosTopicName, s), () => {
|
|
31923
31938
|
this.unsubscribeToRealtimeMessages(
|
|
31924
31939
|
t,
|
|
31925
31940
|
n.rosTopicName,
|
|
31926
|
-
|
|
31941
|
+
s
|
|
31927
31942
|
);
|
|
31928
31943
|
};
|
|
31929
31944
|
}
|
|
@@ -31931,35 +31946,35 @@ class LiveUniverseData extends BasicUniverseDataConnector {
|
|
|
31931
31946
|
return this.addRemovableTelemetrySubscription(
|
|
31932
31947
|
t,
|
|
31933
31948
|
n,
|
|
31934
|
-
async (
|
|
31935
|
-
let
|
|
31936
|
-
for (let
|
|
31937
|
-
const
|
|
31938
|
-
if (
|
|
31939
|
-
const [
|
|
31940
|
-
|
|
31949
|
+
async (s) => {
|
|
31950
|
+
let g, l;
|
|
31951
|
+
for (let u = 0; u < s.length; u += 1) {
|
|
31952
|
+
const c = s[u];
|
|
31953
|
+
if (c.deviceId === t && c.name === n.streamName && c.type === "localization") {
|
|
31954
|
+
const [d, B] = c.points[c.points.length - 1];
|
|
31955
|
+
g = B;
|
|
31941
31956
|
}
|
|
31942
31957
|
}
|
|
31943
|
-
return
|
|
31944
|
-
worldToLocal:
|
|
31958
|
+
return g && g.odometry && (l = {
|
|
31959
|
+
worldToLocal: g.odometry.worldToLocal,
|
|
31945
31960
|
pose: {
|
|
31946
31961
|
translation: {
|
|
31947
|
-
x:
|
|
31948
|
-
y:
|
|
31949
|
-
z:
|
|
31962
|
+
x: g.odometry.pose.translation.x,
|
|
31963
|
+
y: g.odometry.pose.translation.y,
|
|
31964
|
+
z: g.odometry.pose.translation.z
|
|
31950
31965
|
},
|
|
31951
31966
|
rotation: {
|
|
31952
|
-
x:
|
|
31953
|
-
y:
|
|
31954
|
-
z:
|
|
31955
|
-
w:
|
|
31967
|
+
x: g.odometry.pose.rotation.x,
|
|
31968
|
+
y: g.odometry.pose.rotation.y,
|
|
31969
|
+
z: g.odometry.pose.rotation.z,
|
|
31970
|
+
w: g.odometry.pose.rotation.w
|
|
31956
31971
|
}
|
|
31957
31972
|
},
|
|
31958
31973
|
covariance: []
|
|
31959
31974
|
}), {
|
|
31960
31975
|
deviceId: t,
|
|
31961
31976
|
sourceId: n.id,
|
|
31962
|
-
data:
|
|
31977
|
+
data: l
|
|
31963
31978
|
};
|
|
31964
31979
|
},
|
|
31965
31980
|
r
|
|
@@ -32387,14 +32402,17 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32387
32402
|
o(NoData);
|
|
32388
32403
|
return;
|
|
32389
32404
|
}
|
|
32390
|
-
const u = l[
|
|
32391
|
-
|
|
32392
|
-
|
|
32393
|
-
|
|
32394
|
-
|
|
32395
|
-
|
|
32396
|
-
|
|
32397
|
-
})
|
|
32405
|
+
const u = this.getNearestPoint(l)[1];
|
|
32406
|
+
if (u.url) {
|
|
32407
|
+
const c = await fetch(u.url).then(
|
|
32408
|
+
(d) => d.json()
|
|
32409
|
+
);
|
|
32410
|
+
c.path && o(c.path);
|
|
32411
|
+
return;
|
|
32412
|
+
} else if (u.path) {
|
|
32413
|
+
o(u.path);
|
|
32414
|
+
return;
|
|
32415
|
+
}
|
|
32398
32416
|
}
|
|
32399
32417
|
);
|
|
32400
32418
|
return () => {
|
|
@@ -32413,44 +32431,50 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32413
32431
|
}
|
|
32414
32432
|
addFinder(n, r, o, s, g) {
|
|
32415
32433
|
const l = (u) => {
|
|
32416
|
-
|
|
32417
|
-
|
|
32418
|
-
let d;
|
|
32419
|
-
g ? d = u : d = addSeconds(u, 5);
|
|
32420
|
-
let B = this.queryStore.moduleQuery(
|
|
32421
|
-
{
|
|
32422
|
-
deviceIds: [r]
|
|
32423
|
-
},
|
|
32434
|
+
const c = g ? addYears(u, -1) : addSeconds(u, -60), d = g ? addMilliseconds(u, 1) : addSeconds(u, 5), B = this.queryStore.moduleQuery(
|
|
32435
|
+
{ deviceIds: [r] },
|
|
32424
32436
|
o,
|
|
32425
32437
|
s,
|
|
32426
32438
|
c,
|
|
32427
32439
|
d,
|
|
32428
32440
|
g
|
|
32429
32441
|
);
|
|
32430
|
-
if (B === void 0)
|
|
32442
|
+
if (B === void 0) {
|
|
32431
32443
|
n(void 0);
|
|
32432
|
-
|
|
32444
|
+
return;
|
|
32445
|
+
}
|
|
32446
|
+
if (B === "too much data") {
|
|
32433
32447
|
n("too much data");
|
|
32434
|
-
|
|
32435
|
-
|
|
32436
|
-
|
|
32437
|
-
const p = f[f.length - 1];
|
|
32438
|
-
if (g)
|
|
32439
|
-
n(f);
|
|
32440
|
-
else {
|
|
32441
|
-
let U = p[0], y = p[1];
|
|
32442
|
-
f.forEach((w) => {
|
|
32443
|
-
const D = w[0], m = w[1];
|
|
32444
|
-
Math.abs(D - u.getTime()) < Math.abs(U - u.getTime()) && (U = D, y = m);
|
|
32445
|
-
}), n([[U, y]]);
|
|
32446
|
-
}
|
|
32447
|
-
} else
|
|
32448
|
-
n(void 0);
|
|
32449
|
-
} else
|
|
32448
|
+
return;
|
|
32449
|
+
}
|
|
32450
|
+
if (B.length === 0) {
|
|
32450
32451
|
n(void 0);
|
|
32452
|
+
return;
|
|
32453
|
+
}
|
|
32454
|
+
const R = B.reduce((f, p) => f.concat(p.points), []);
|
|
32455
|
+
if (!R || R.length === 0) {
|
|
32456
|
+
n(void 0);
|
|
32457
|
+
return;
|
|
32458
|
+
}
|
|
32459
|
+
if (g) {
|
|
32460
|
+
const p = R[R.length - 1][0], U = R.filter(
|
|
32461
|
+
(y) => y[0] > addSeconds(p, -15).getTime()
|
|
32462
|
+
);
|
|
32463
|
+
n(U);
|
|
32464
|
+
return;
|
|
32465
|
+
}
|
|
32466
|
+
n(R);
|
|
32451
32467
|
};
|
|
32452
32468
|
return this.timeFinders.push(l), l;
|
|
32453
32469
|
}
|
|
32470
|
+
getNearestPoint(n, r = this.time) {
|
|
32471
|
+
const o = r === "live" ? addMilliseconds(/* @__PURE__ */ new Date(), 1) : this.time;
|
|
32472
|
+
let s = n[0][0], g = n[0][1];
|
|
32473
|
+
return n.forEach((l) => {
|
|
32474
|
+
const u = l[0], c = l[1];
|
|
32475
|
+
Math.abs(u - o.getTime()) < Math.abs(s - o.getTime()) && (s = u, g = c);
|
|
32476
|
+
}), [s, g];
|
|
32477
|
+
}
|
|
32454
32478
|
removeFinder(n) {
|
|
32455
32479
|
this.timeFinders = this.timeFinders.filter((r) => r !== n);
|
|
32456
32480
|
}
|
|
@@ -32489,7 +32513,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32489
32513
|
o(NoData);
|
|
32490
32514
|
return;
|
|
32491
32515
|
}
|
|
32492
|
-
const d = c[
|
|
32516
|
+
const d = this.getNearestPoint(c)[1];
|
|
32493
32517
|
if (typeof d == "string")
|
|
32494
32518
|
o(JSON.parse(d));
|
|
32495
32519
|
else {
|
|
@@ -32511,7 +32535,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32511
32535
|
o(NoData);
|
|
32512
32536
|
return;
|
|
32513
32537
|
}
|
|
32514
|
-
let d = c[
|
|
32538
|
+
let d = this.getNearestPoint(c)[1];
|
|
32515
32539
|
d.url && (g.postMessage({ url: d.url }), g.onmessage = (B) => {
|
|
32516
32540
|
if (d = B.data.response, d.pointClouds) {
|
|
32517
32541
|
const { url: R, worldToLocal: f } = d.pointClouds[0];
|
|
@@ -32528,46 +32552,69 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32528
32552
|
this.releasePCDWorker(s), this.releaseDataFetchWorker(g), l(), u();
|
|
32529
32553
|
};
|
|
32530
32554
|
}
|
|
32531
|
-
subscribeToOdometry(n, r, o) {
|
|
32555
|
+
subscribeToOdometry(n, r, o, s = 0) {
|
|
32532
32556
|
if (r.sourceType !== "telemetry")
|
|
32533
32557
|
throw new Error("Telemetry sources only supported");
|
|
32534
|
-
const
|
|
32535
|
-
if (!
|
|
32558
|
+
const g = this.getAvailableDataFetchWorker();
|
|
32559
|
+
if (!g)
|
|
32536
32560
|
throw new Error("No available data fetch worker");
|
|
32537
|
-
const
|
|
32561
|
+
const l = this.subscribeTelemetry(
|
|
32538
32562
|
n,
|
|
32539
32563
|
r,
|
|
32540
32564
|
"localization",
|
|
32541
|
-
async (
|
|
32542
|
-
if (
|
|
32565
|
+
async (u) => {
|
|
32566
|
+
if (u === "too much data" || u === void 0) {
|
|
32543
32567
|
o(NoData);
|
|
32544
32568
|
return;
|
|
32545
32569
|
}
|
|
32546
|
-
const
|
|
32547
|
-
|
|
32548
|
-
|
|
32549
|
-
|
|
32550
|
-
|
|
32551
|
-
|
|
32552
|
-
|
|
32553
|
-
|
|
32554
|
-
|
|
32555
|
-
|
|
32556
|
-
|
|
32557
|
-
|
|
32558
|
-
|
|
32559
|
-
|
|
32560
|
-
|
|
32561
|
-
|
|
32570
|
+
const c = this.getNearestPoint(
|
|
32571
|
+
u
|
|
32572
|
+
);
|
|
32573
|
+
let d;
|
|
32574
|
+
if (c[1].url)
|
|
32575
|
+
try {
|
|
32576
|
+
d = (await (await fetch(c[1].url)).json()).odometry;
|
|
32577
|
+
} catch (B) {
|
|
32578
|
+
throw console.error("Failed to fetch odometry data:", B), B;
|
|
32579
|
+
}
|
|
32580
|
+
else
|
|
32581
|
+
d = c[1].odometry;
|
|
32582
|
+
if (s) {
|
|
32583
|
+
const R = u.filter(
|
|
32584
|
+
(f) => f[0] <= c[0] && f[0] >= c[0] - s * 1e3
|
|
32585
|
+
).map(async (f) => {
|
|
32586
|
+
var p, U;
|
|
32587
|
+
if (f[1].url)
|
|
32588
|
+
try {
|
|
32589
|
+
const w = await (await fetch(f[1].url)).json();
|
|
32590
|
+
return [f[0], (p = w.odometry) == null ? void 0 : p.pose];
|
|
32591
|
+
} catch (y) {
|
|
32592
|
+
throw console.error("Failed to fetch trail odometry data:", y), y;
|
|
32562
32593
|
}
|
|
32563
|
-
|
|
32564
|
-
covariance: []
|
|
32594
|
+
return [f[0], (U = f[1].odometry) == null ? void 0 : U.pose];
|
|
32565
32595
|
});
|
|
32596
|
+
try {
|
|
32597
|
+
const f = await Promise.all(R);
|
|
32598
|
+
o({
|
|
32599
|
+
worldToLocal: d.worldToLocal,
|
|
32600
|
+
pose: d.pose,
|
|
32601
|
+
trail: f,
|
|
32602
|
+
covariance: []
|
|
32603
|
+
});
|
|
32604
|
+
return;
|
|
32605
|
+
} catch (f) {
|
|
32606
|
+
throw console.error("Failed to process trail data:", f), f;
|
|
32607
|
+
}
|
|
32608
|
+
}
|
|
32609
|
+
o({
|
|
32610
|
+
worldToLocal: d.worldToLocal,
|
|
32611
|
+
pose: d.pose,
|
|
32612
|
+
covariance: []
|
|
32566
32613
|
});
|
|
32567
32614
|
}
|
|
32568
32615
|
);
|
|
32569
32616
|
return () => {
|
|
32570
|
-
this.releaseDataFetchWorker(
|
|
32617
|
+
this.releaseDataFetchWorker(g), l();
|
|
32571
32618
|
};
|
|
32572
32619
|
}
|
|
32573
32620
|
subscribeToPose(n, r, o) {
|
|
@@ -32587,7 +32634,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32587
32634
|
o(NoData);
|
|
32588
32635
|
return;
|
|
32589
32636
|
}
|
|
32590
|
-
let u = l[
|
|
32637
|
+
let u = this.getNearestPoint(l)[1];
|
|
32591
32638
|
u.startsWith("http") ? (s.postMessage({ url: u }), s.onmessage = (c) => {
|
|
32592
32639
|
u = JSON.stringify(c.data.response), o(JSON.parse(u));
|
|
32593
32640
|
}) : o(JSON.parse(u));
|
|
@@ -32618,7 +32665,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32618
32665
|
o(NoData);
|
|
32619
32666
|
return;
|
|
32620
32667
|
}
|
|
32621
|
-
const c = u[
|
|
32668
|
+
const c = this.getNearestPoint(u)[1];
|
|
32622
32669
|
if (c.url) {
|
|
32623
32670
|
if (s[c.url]) {
|
|
32624
32671
|
o(s[c.url]);
|
|
@@ -32655,7 +32702,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32655
32702
|
o(NoData);
|
|
32656
32703
|
return;
|
|
32657
32704
|
}
|
|
32658
|
-
const g = s[
|
|
32705
|
+
const g = this.getNearestPoint(s)[1], { url: l } = g, u = this.videoCache.get(l, async () => new Promise((c) => {
|
|
32659
32706
|
const d = document.createElement("video");
|
|
32660
32707
|
d.src = l, d.onload = () => {
|
|
32661
32708
|
};
|
|
@@ -32680,7 +32727,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32680
32727
|
o(NoData);
|
|
32681
32728
|
return;
|
|
32682
32729
|
}
|
|
32683
|
-
o(s[
|
|
32730
|
+
o(this.getNearestPoint(s)[1]);
|
|
32684
32731
|
}
|
|
32685
32732
|
);
|
|
32686
32733
|
}
|
|
@@ -32700,7 +32747,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32700
32747
|
o(NoData);
|
|
32701
32748
|
return;
|
|
32702
32749
|
}
|
|
32703
|
-
const u = l[
|
|
32750
|
+
const u = this.getNearestPoint(l)[1];
|
|
32704
32751
|
o(u);
|
|
32705
32752
|
}
|
|
32706
32753
|
);
|
|
@@ -32716,7 +32763,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32716
32763
|
o(NoData);
|
|
32717
32764
|
return;
|
|
32718
32765
|
}
|
|
32719
|
-
let g = s[
|
|
32766
|
+
let g = this.getNearestPoint(s)[1];
|
|
32720
32767
|
g.startsWith("http") && (g = await (await fetch(g)).text()), o(JSON.parse(g));
|
|
32721
32768
|
});
|
|
32722
32769
|
}
|
|
@@ -32728,7 +32775,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32728
32775
|
o(NoData);
|
|
32729
32776
|
return;
|
|
32730
32777
|
}
|
|
32731
|
-
o(s[
|
|
32778
|
+
o(this.getNearestPoint(s)[1]);
|
|
32732
32779
|
});
|
|
32733
32780
|
}
|
|
32734
32781
|
subscribeToNumeric(n, r, o) {
|
|
@@ -32766,7 +32813,7 @@ class TelemetryUniverseData extends BasicUniverseDataConnector {
|
|
|
32766
32813
|
o(NoData);
|
|
32767
32814
|
return;
|
|
32768
32815
|
}
|
|
32769
|
-
const g = s[
|
|
32816
|
+
const g = this.getNearestPoint(s)[1].url, l = new Image();
|
|
32770
32817
|
l.src = g, l.onload = () => {
|
|
32771
32818
|
const u = document.createElement("canvas");
|
|
32772
32819
|
u.width = l.width, u.height = l.height;
|