@fxi/zartigl 0.14.1 → 0.15.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.
@@ -0,0 +1,2991 @@
1
+ import { inflate as Ae } from "pako";
2
+ import Me from "numcodecs/blosc";
3
+ const Se = { label: "Thermal", tags: ["sequential", "temperature"], colors: ["#042333", "#2c3395", "#744796", "#b15f82", "#eb7958", "#fbb43d", "#e8fa5b"] }, Fe = { label: "Haline", tags: ["sequential", "salinity"], colors: ["#2a186c", "#17568b", "#1a7e8f", "#22a785", "#55c666", "#aadc32", "#fde333"] }, Ue = { label: "Solar", tags: ["sequential", "irradiance"], colors: ["#330f0b", "#6b2313", "#a83c12", "#d6621a", "#f3951e", "#f7c741", "#f9f871"] }, Ne = { label: "Ice", tags: ["sequential"], colors: ["#040d1a", "#123365", "#1c5f9e", "#2b8ece", "#62bde3", "#aaddf2", "#f2faff"] }, Ce = { label: "Deep", tags: ["sequential", "depth"], colors: ["#fdfecc", "#c8e59b", "#74c8a3", "#3194b0", "#2a5b8e", "#281a5e", "#0c0820"] }, De = { label: "RdYlBu", tags: ["diverging"], colors: ["#3288bd", "#66c2a5", "#abdda4", "#e6f598", "#fee08b", "#fdae61", "#f46d43", "#d53e4f"] }, Ie = { label: "Dense", tags: ["sequential"], colors: ["#e6f1f1", "#92c4ca", "#44929a", "#20627a", "#1a3c6a", "#211a50", "#0d0621"] }, Pe = { label: "Algae", tags: ["sequential", "biology", "log"], colors: ["#d7f9d0", "#a2d595", "#64b463", "#129450", "#126e45", "#1a482f", "#122414"] }, Le = { label: "Oxygen", tags: ["sequential", "biology", "hypoxia"], colors: ["#09060f", "#5b1028", "#d43d2f", "#f39b3d", "#f3e7b3", "#79cbd1", "#176b9c"] }, Ge = { label: "Matter", tags: ["sequential", "biology"], colors: ["#fdfecc", "#f2c98a", "#e07c4e", "#bc3754", "#8d1a6d", "#51156b", "#1c0c3f"] }, Ve = { label: "Viridis", tags: ["sequential", "perceptual"], colors: ["#440154", "#443983", "#31688e", "#21918c", "#35b779", "#90d743", "#fde725"] }, Oe = { label: "Plasma", tags: ["sequential", "perceptual"], colors: ["#0d0887", "#5e01a6", "#9c179e", "#cc4778", "#ed7953", "#fdb42f", "#f0f921"] }, Be = { label: "Cyclic", tags: ["cyclic", "direction"], colors: ["#2e22ea", "#b541fb", "#fc93c0", "#f1ee35", "#77c80d", "#458776", "#2c24e9"] }, $e = { label: "Tempo", tags: ["sequential"], colors: ["#fff6f4", "#c2d1b9", "#7db390", "#2a937f", "#156d73", "#1c455b", "#151d44"] }, Xe = { label: "Turbid", tags: ["sequential", "biology", "log"], colors: ["#e9f5a0", "#c8c86e", "#a09845", "#786031", "#533324", "#341423", "#150d17"] }, ze = { label: "Speed", tags: ["sequential", "velocity"], colors: ["#fcfea4", "#d5e429", "#94c63e", "#52a657", "#2d8169", "#1d5b6d", "#0d3361"] }, qe = { label: "Amp", tags: ["sequential"], colors: ["#f2f2f2", "#c0b8db", "#9180b6", "#6c4e9e", "#4e2e83", "#32185d", "#110a35"] }, We = { label: "Heat", tags: ["sequential"], colors: ["#fde725", "#fde725", "#f8961e", "#e63946", "#9d0208", "#3a0007"] }, He = { label: "Balance", tags: ["diverging"], colors: ["#181c43", "#3066af", "#9bbcdd", "#f2f2f2", "#e07d53", "#b13626", "#2c0b0e"] }, Ye = { label: "Delta", tags: ["diverging"], colors: ["#0e3f31", "#20877b", "#99d4c1", "#f2f2f2", "#a1b0d4", "#3c5b9e", "#0d1938"] }, je = { label: "Curl", tags: ["diverging"], colors: ["#152237", "#2471b3", "#8dbac4", "#f2f2f2", "#c79f84", "#a63827", "#270b17"] }, Ke = { label: "Gray", tags: ["sequential"], colors: ["#000000", "#252525", "#4d4d4d", "#7a7a7a", "#a8a8a8", "#d4d4d4", "#ffffff"] }, ye = {
4
+ thermal: Se,
5
+ "thermal-alt": { label: "Thermal Alt", tags: ["sequential", "temperature"], colors: ["#176b9c", "#79cbd1", "#f3e7b3", "#f39b3d", "#d43d2f", "#5b1028", "#09060f"] },
6
+ haline: Fe,
7
+ solar: Ue,
8
+ ice: Ne,
9
+ deep: Ce,
10
+ rdylbu: De,
11
+ dense: Ie,
12
+ algae: Pe,
13
+ oxygen: Le,
14
+ matter: Ge,
15
+ viridis: Ve,
16
+ plasma: Oe,
17
+ cyclic: Be,
18
+ tempo: $e,
19
+ turbid: Xe,
20
+ speed: ze,
21
+ amp: qe,
22
+ heat: We,
23
+ "heat-alert": { label: "Heat Alert", tags: ["sequential", "alpha", "deprecated"], colors: ["#fde72500", "#fde725cc", "#f8961e", "#e63946", "#9d0208", "#3a0007"] },
24
+ balance: He,
25
+ delta: Ye,
26
+ curl: je,
27
+ "mono-black": { label: "Black", tags: ["monochrome", "particles"], colors: ["#000000", "#000000"] },
28
+ "mono-white": { label: "White", tags: ["monochrome", "particles"], colors: ["#ffffff", "#ffffff"] },
29
+ "mono-pink": { label: "Pink", tags: ["monochrome", "particles"], colors: ["#ff2aa1", "#ff2aa1"] },
30
+ gray: Ke
31
+ }, oe = 64, Ze = {
32
+ linear: (i) => i,
33
+ // Rises fast: values just inside the zone already show.
34
+ log: (i) => Math.log10(1 + 9 * i),
35
+ // Stays faint longer: codec noise at the end of the range stays hidden.
36
+ exp: (i) => (10 ** i - 1) / 9
37
+ };
38
+ function Qe(i, e) {
39
+ const t = Ze[e.curve ?? "linear"], s = e.low ?? 0, r = e.high ?? 0;
40
+ let n = 1;
41
+ return s > 0 && i < s && (n = Math.min(n, t(Math.max(i, 0) / s))), r > 0 && i > 1 - r && (n = Math.min(n, t(Math.max(1 - i, 0) / r))), n;
42
+ }
43
+ function Je(i) {
44
+ let e = i.replace("#", "");
45
+ (e.length === 3 || e.length === 4) && (e = [...e].map((s) => s + s).join(""));
46
+ const t = (s) => parseInt(e.slice(s, s + 2), 16);
47
+ return [
48
+ t(0),
49
+ t(2),
50
+ t(4),
51
+ e.length === 8 ? t(6) : 255
52
+ ];
53
+ }
54
+ function et([i, e, t, s]) {
55
+ return `#${[i, e, t, s].map(
56
+ (r) => Math.round(Math.min(255, Math.max(0, r))).toString(16).padStart(2, "0")
57
+ ).join("")}`;
58
+ }
59
+ function tt(i, e) {
60
+ if (e <= i[0][0])
61
+ return i[0][1];
62
+ for (let t = 1; t < i.length; t++) {
63
+ const [s, r] = i[t];
64
+ if (e <= s) {
65
+ const [n, o] = i[t - 1], a = s === n ? 1 : (e - n) / (s - n);
66
+ return o.map((c, l) => c + (r[l] - c) * a);
67
+ }
68
+ }
69
+ return i[i.length - 1][1];
70
+ }
71
+ function it(i, e) {
72
+ const t = Object.entries(i).map(
73
+ ([r, n]) => [Number(r), Je(n)]
74
+ ).sort((r, n) => r[0] - n[0]), s = {};
75
+ for (let r = 0; r <= oe; r++) {
76
+ const n = r / oe, [o, a, c, l] = tt(t, n);
77
+ s[n] = et([o, a, c, l * Qe(n, e)]);
78
+ }
79
+ return s;
80
+ }
81
+ const st = (i) => !!i && ((i.low ?? 0) > 0 || (i.high ?? 0) > 0);
82
+ function ce(i) {
83
+ const e = {}, t = i.length - 1;
84
+ return i.forEach((s, r) => {
85
+ e[t === 0 ? 0 : r / t] = s;
86
+ }), e;
87
+ }
88
+ function rt(i, e) {
89
+ const t = nt(i, e?.reverse ?? !1);
90
+ return st(e?.alphaFade) ? it(t, e.alphaFade) : t;
91
+ }
92
+ function nt(i, e) {
93
+ const t = ye;
94
+ if (typeof i == "string") {
95
+ const s = t[i];
96
+ if (!s)
97
+ throw new Error(
98
+ `Palette "${i}" not found. Available palettes: ${Object.keys(
99
+ t
100
+ ).join(", ")}`
101
+ );
102
+ const r = e ? [...s.colors].reverse() : s.colors;
103
+ return ce(r);
104
+ }
105
+ if (Array.isArray(i)) {
106
+ const s = e ? [...i].reverse() : i;
107
+ return ce(s);
108
+ }
109
+ return e ? Object.fromEntries(
110
+ Object.entries(i).map(([s, r]) => [1 - Number(s), r])
111
+ ) : i;
112
+ }
113
+ function fi(i = {}) {
114
+ return Object.entries(ye).map(([t, s]) => ({ id: t, ...s })).filter(
115
+ (t) => i.includeDeprecated || !t.tags.includes("deprecated")
116
+ );
117
+ }
118
+ function le(i, e, t) {
119
+ const s = i.createShader(e);
120
+ if (!s)
121
+ throw new Error("Failed to create shader");
122
+ if (i.shaderSource(s, t), i.compileShader(s), !i.getShaderParameter(s, i.COMPILE_STATUS)) {
123
+ const r = i.getShaderInfoLog(s);
124
+ throw i.deleteShader(s), new Error(`Shader compile error: ${r}`);
125
+ }
126
+ return s;
127
+ }
128
+ function mi(i, e, t) {
129
+ const s = i.createProgram();
130
+ if (!s)
131
+ throw new Error("Failed to create program");
132
+ const r = le(i, i.VERTEX_SHADER, e), n = le(i, i.FRAGMENT_SHADER, t);
133
+ if (i.attachShader(s, r), i.attachShader(s, n), i.linkProgram(s), !i.getProgramParameter(s, i.LINK_STATUS)) {
134
+ const o = i.getProgramInfoLog(s);
135
+ throw i.deleteProgram(s), new Error(`Program link error: ${o}`);
136
+ }
137
+ return i.deleteShader(r), i.deleteShader(n), s;
138
+ }
139
+ function pi(i, e, t, s, r) {
140
+ const n = i.createTexture();
141
+ if (!n)
142
+ throw new Error("Failed to create texture");
143
+ return i.bindTexture(i.TEXTURE_2D, n), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, e), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, e), i.texImage2D(
144
+ i.TEXTURE_2D,
145
+ 0,
146
+ i.RGBA,
147
+ s,
148
+ r,
149
+ 0,
150
+ i.RGBA,
151
+ i.UNSIGNED_BYTE,
152
+ t
153
+ ), i.bindTexture(i.TEXTURE_2D, null), n;
154
+ }
155
+ function at(i, e, t) {
156
+ const s = i.getParameter(
157
+ i.TEXTURE_BINDING_2D
158
+ ), r = i.getParameter(
159
+ i.FRAMEBUFFER_BINDING
160
+ ), n = i.createTexture(), o = i.createFramebuffer();
161
+ if (!n || !o)
162
+ return n && i.deleteTexture(n), o && i.deleteFramebuffer(o), i.bindTexture(i.TEXTURE_2D, s), i.bindFramebuffer(i.FRAMEBUFFER, r), !1;
163
+ let a = !1;
164
+ try {
165
+ i.bindTexture(i.TEXTURE_2D, n), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, i.NEAREST), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, i.NEAREST), i.texImage2D(
166
+ i.TEXTURE_2D,
167
+ 0,
168
+ e,
169
+ 1,
170
+ 1,
171
+ 0,
172
+ i.RGBA,
173
+ t,
174
+ null
175
+ ), i.bindFramebuffer(i.FRAMEBUFFER, o), i.framebufferTexture2D(
176
+ i.FRAMEBUFFER,
177
+ i.COLOR_ATTACHMENT0,
178
+ i.TEXTURE_2D,
179
+ n,
180
+ 0
181
+ ), a = i.checkFramebufferStatus(i.FRAMEBUFFER) === i.FRAMEBUFFER_COMPLETE;
182
+ } finally {
183
+ i.bindFramebuffer(i.FRAMEBUFFER, r), i.bindTexture(i.TEXTURE_2D, s), i.deleteFramebuffer(o), i.deleteTexture(n);
184
+ }
185
+ return a;
186
+ }
187
+ function ot(i) {
188
+ return {
189
+ kind: "rgba8-packed",
190
+ internalFormat: i.RGBA,
191
+ type: i.UNSIGNED_BYTE
192
+ };
193
+ }
194
+ function gi(i) {
195
+ if (typeof WebGL2RenderingContext > "u" || !(i instanceof WebGL2RenderingContext))
196
+ throw new Error("zartigl requires WebGL2");
197
+ return i;
198
+ }
199
+ function Ei(i) {
200
+ const e = [];
201
+ i.getExtension("EXT_color_buffer_float") ? e.push(
202
+ { kind: "float32", internalFormat: i.RGBA32F, type: i.FLOAT },
203
+ { kind: "float16", internalFormat: i.RGBA16F, type: i.HALF_FLOAT }
204
+ ) : i.getExtension("EXT_color_buffer_half_float") && e.push({
205
+ kind: "float16",
206
+ internalFormat: i.RGBA16F,
207
+ type: i.HALF_FLOAT
208
+ });
209
+ for (const t of e)
210
+ if (at(
211
+ i,
212
+ t.internalFormat,
213
+ t.type
214
+ ))
215
+ return t;
216
+ return ot(i);
217
+ }
218
+ function Ti(i, e, t, s, r, n, o) {
219
+ const a = i.createTexture();
220
+ if (!a)
221
+ throw new Error("Failed to create texture");
222
+ return i.bindTexture(i.TEXTURE_2D, a), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, e), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, e), i.texImage2D(
223
+ i.TEXTURE_2D,
224
+ 0,
225
+ n,
226
+ s,
227
+ r,
228
+ 0,
229
+ i.RGBA,
230
+ o,
231
+ t
232
+ ), i.bindTexture(i.TEXTURE_2D, null), a;
233
+ }
234
+ function yi(i, e, t) {
235
+ i.activeTexture(i.TEXTURE0 + t), i.bindTexture(i.TEXTURE_2D, e);
236
+ }
237
+ function wi(i, e) {
238
+ const t = i.createFramebuffer();
239
+ if (!t)
240
+ throw new Error("Failed to create framebuffer");
241
+ return i.bindFramebuffer(i.FRAMEBUFFER, t), i.framebufferTexture2D(
242
+ i.FRAMEBUFFER,
243
+ i.COLOR_ATTACHMENT0,
244
+ i.TEXTURE_2D,
245
+ e,
246
+ 0
247
+ ), i.bindFramebuffer(i.FRAMEBUFFER, null), t;
248
+ }
249
+ function bi(i) {
250
+ const e = i.createBuffer();
251
+ if (!e)
252
+ throw new Error("Failed to create buffer");
253
+ return i.bindBuffer(i.ARRAY_BUFFER, e), i.bufferData(
254
+ i.ARRAY_BUFFER,
255
+ new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
256
+ i.STATIC_DRAW
257
+ ), e;
258
+ }
259
+ const ct = {
260
+ 0: "#3288bd",
261
+ 0.1: "#66c2a5",
262
+ 0.2: "#abdda4",
263
+ 0.3: "#e6f598",
264
+ 0.4: "#fee08b",
265
+ 0.5: "#fdae61",
266
+ 0.6: "#f46d43",
267
+ 1: "#d53e4f"
268
+ };
269
+ function xi(i, e, t) {
270
+ const s = rt(e ?? ct, t), r = document.createElement("canvas");
271
+ r.width = 256, r.height = 1;
272
+ const n = r.getContext("2d"), o = n.createLinearGradient(0, 0, 256, 0);
273
+ for (const [c, l] of Object.entries(s))
274
+ o.addColorStop(Number(c), l);
275
+ n.fillStyle = o, n.fillRect(0, 0, 256, 1);
276
+ const a = i.createTexture();
277
+ if (!a)
278
+ throw new Error("Failed to create color ramp texture");
279
+ return i.bindTexture(i.TEXTURE_2D, a), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, i.LINEAR), i.texImage2D(i.TEXTURE_2D, 0, i.RGBA, i.RGBA, i.UNSIGNED_BYTE, r), i.bindTexture(i.TEXTURE_2D, null), a;
280
+ }
281
+ function _i(i) {
282
+ const e = i.getExtension("WEBGL_debug_renderer_info");
283
+ return {
284
+ vendor: String(i.getParameter(i.VENDOR) ?? ""),
285
+ renderer: String(i.getParameter(i.RENDERER) ?? ""),
286
+ unmaskedVendor: e ? String(i.getParameter(e.UNMASKED_VENDOR_WEBGL) ?? "") : void 0,
287
+ unmaskedRenderer: e ? String(i.getParameter(e.UNMASKED_RENDERER_WEBGL) ?? "") : void 0,
288
+ version: String(i.getParameter(i.VERSION) ?? "")
289
+ };
290
+ }
291
+ function Ri(i) {
292
+ return {
293
+ program: i.getParameter(i.CURRENT_PROGRAM),
294
+ activeTexture: i.getParameter(i.ACTIVE_TEXTURE),
295
+ arrayBuffer: i.getParameter(i.ARRAY_BUFFER_BINDING),
296
+ elementBuffer: i.getParameter(i.ELEMENT_ARRAY_BUFFER_BINDING),
297
+ framebuffer: i.getParameter(i.FRAMEBUFFER_BINDING),
298
+ blend: i.isEnabled(i.BLEND),
299
+ depthTest: i.isEnabled(i.DEPTH_TEST),
300
+ stencilTest: i.isEnabled(i.STENCIL_TEST),
301
+ viewport: i.getParameter(i.VIEWPORT),
302
+ blendFunc: [
303
+ i.getParameter(i.BLEND_SRC_RGB),
304
+ i.getParameter(i.BLEND_DST_RGB)
305
+ ]
306
+ };
307
+ }
308
+ function vi(i, e) {
309
+ i.useProgram(e.program), i.activeTexture(e.activeTexture), i.bindBuffer(i.ARRAY_BUFFER, e.arrayBuffer), i.bindBuffer(i.ELEMENT_ARRAY_BUFFER, e.elementBuffer), i.bindFramebuffer(i.FRAMEBUFFER, e.framebuffer), e.blend ? i.enable(i.BLEND) : i.disable(i.BLEND), e.depthTest ? i.enable(i.DEPTH_TEST) : i.disable(i.DEPTH_TEST), e.stencilTest ? i.enable(i.STENCIL_TEST) : i.disable(i.STENCIL_TEST), i.viewport(e.viewport[0], e.viewport[1], e.viewport[2], e.viewport[3]), i.blendFunc(e.blendFunc[0], e.blendFunc[1]);
310
+ }
311
+ const we = new Float32Array([
312
+ 1,
313
+ 0,
314
+ 0,
315
+ 0,
316
+ 0,
317
+ 1,
318
+ 0,
319
+ 0,
320
+ 0,
321
+ 0,
322
+ 1,
323
+ 0,
324
+ 0,
325
+ 0,
326
+ 0,
327
+ 1
328
+ ]), ki = {
329
+ projectionTransition: 1,
330
+ fallbackMatrix: we
331
+ };
332
+ function Ai(i, e, t) {
333
+ i.uniform1f(
334
+ e.u_projection_transition,
335
+ t.projectionTransition ?? 1
336
+ ), i.uniformMatrix4fv(
337
+ e.u_fallback_matrix,
338
+ !1,
339
+ t.fallbackMatrix ? t.fallbackMatrix instanceof Float32Array ? t.fallbackMatrix : new Float32Array(Array.from(t.fallbackMatrix)) : we
340
+ );
341
+ }
342
+ const lt = {
343
+ degrees_c: "°C",
344
+ degc: "°C",
345
+ degrees_celsius: "°C",
346
+ degree_celsius: "°C",
347
+ celsius: "°C",
348
+ // Degree heating weeks accumulate °C over weeks: a product, not a rate.
349
+ degree_celsius_weeks: "°C-weeks",
350
+ degree: "°",
351
+ degrees: "°",
352
+ kelvin: "K",
353
+ 1: "",
354
+ "1e-3": "PSU",
355
+ "0.001": "PSU",
356
+ psu: "PSU",
357
+ stress_level: ""
358
+ }, dt = {
359
+ meter: "m",
360
+ meters: "m",
361
+ metre: "m",
362
+ metres: "m",
363
+ second: "s",
364
+ seconds: "s",
365
+ day: "d",
366
+ days: "d",
367
+ hour: "h",
368
+ hours: "h",
369
+ gram: "g",
370
+ grams: "g",
371
+ milligram: "mg",
372
+ milligrams: "mg",
373
+ kilogram: "kg",
374
+ kilograms: "kg",
375
+ mole: "mol",
376
+ millimole: "mmol",
377
+ watt: "W",
378
+ newton: "N",
379
+ pascal: "Pa",
380
+ kelvin: "K"
381
+ }, ht = "⁰¹²³⁴⁵⁶⁷⁸⁹";
382
+ function de(i) {
383
+ return i === 1 ? "" : [...String(i)].map((e) => ht[Number(e)]).join("");
384
+ }
385
+ function Mi(i) {
386
+ const e = i?.trim() ?? "", t = lt[e.toLowerCase()];
387
+ if (t != null)
388
+ return t;
389
+ if (e.includes("/"))
390
+ return e;
391
+ const s = [], r = [];
392
+ for (const n of e.split(/\s+/)) {
393
+ const o = /^([A-Za-z]+)\^?(-?\d+)?$/.exec(n);
394
+ if (!o)
395
+ return e.replace(/_/g, " ");
396
+ const a = dt[o[1]] ?? o[1], c = Number(o[2] ?? 1);
397
+ c < 0 ? r.push(a + de(-c)) : s.push(a + de(c));
398
+ }
399
+ return [s.join(" ") || "1", ...r].join("/");
400
+ }
401
+ const he = 20, ut = 600;
402
+ function ft(i) {
403
+ const e = Math.max(0, Math.min(1, i));
404
+ return he * Math.pow(ut / he, e);
405
+ }
406
+ function Si(i) {
407
+ return Math.exp(-1 / ft(i));
408
+ }
409
+ const mt = 0.8, pt = 120, gt = 300;
410
+ class Fi {
411
+ constructor(e) {
412
+ this.base = e, this.moving = !1, this.start = 0, this.duration = 0, this.from = e, this.to = e;
413
+ }
414
+ /** Configured opacity, applied at once unless the camera moves. */
415
+ setBase(e) {
416
+ this.base = e, this.moving || (this.from = e, this.to = e, this.duration = 0);
417
+ }
418
+ setMoving(e, t) {
419
+ e !== this.moving && (this.from = this.value(t), this.moving = e, this.to = e ? mt : this.base, this.start = t, this.duration = e ? pt : gt);
420
+ }
421
+ value(e) {
422
+ if (this.duration === 0)
423
+ return this.to;
424
+ const t = Math.min(1, Math.max(0, (e - this.start) / this.duration));
425
+ return t === 1 ? (this.duration = 0, this.from = this.to, this.to) : this.from + (this.to - this.from) * t * t * (3 - 2 * t);
426
+ }
427
+ }
428
+ var Et = `vec3 velocityValue(vec4 texel, vec2 minimum, vec2 maximum, float physical) {
429
+ if (physical > 0.5) return texel.xyz;
430
+ return vec3(mix(minimum, maximum, texel.rg), texel.a);
431
+ }
432
+
433
+ vec3 blendVelocity(vec3 a, vec3 b, float fraction) {
434
+ if (fraction <= 0.0) return a;
435
+ return mix(a, b, fraction);
436
+ }`, Tt = `vec3 applyVibrance(vec3 c, float v) {
437
+ float mx = max(c.r, max(c.g, c.b));
438
+ float mn = min(c.r, min(c.g, c.b));
439
+ float boost = v * (1.0 - (mx - mn));
440
+ float luma = dot(c, vec3(0.299, 0.587, 0.114));
441
+ return mix(vec3(luma), c, 1.0 + boost);
442
+ }
443
+
444
+ vec3 gradeColor(vec3 c, vec4 g) {
445
+ float m = max(c.r, max(c.g, c.b));
446
+ if (m > 0.0) {
447
+
448
+
449
+ float e = g.x > 1e-3 ? (1.0 - exp(-g.x * m)) / (1.0 - exp(-g.x)) : m;
450
+
451
+ e += g.w * smoothstep(0.5, 1.0, e) * (1.0 - e);
452
+ c *= e / m;
453
+ }
454
+
455
+ c = mix(c, c * c * (3.0 - 2.0 * c), g.y);
456
+ return clamp(applyVibrance(c, g.z), 0.0, 1.0);
457
+ }`, yt = `uniform vec2 u_code_range;
458
+ uniform vec2 u_value_range;
459
+ uniform float u_scalar_transfer;
460
+
461
+ float geoVideoScalarCode(float r) {
462
+ return clamp((r - u_code_range.x) / (u_code_range.y - u_code_range.x), 0.0, 1.0);
463
+ }
464
+
465
+ float geoVideoScalarValue(float r) {
466
+ float code = geoVideoScalarCode(r);
467
+ float t = mix(code, (pow(10.0, code) - 1.0) / 9.0, u_scalar_transfer);
468
+ return mix(u_value_range.x, u_value_range.y, t);
469
+ }`, wt = `uint pcg(uint v) {
470
+ uint state = v * 747796405u + 2891336453u;
471
+ uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
472
+ return (word >> 22u) ^ word;
473
+ }
474
+
475
+ float random(uvec3 v) {
476
+ return float(pcg(v.x ^ pcg(v.y ^ pcg(v.z))) >> 8u) * (1.0 / 16777216.0);
477
+ }`, bt = `vec3 applyVibrance(vec3 c, float v) {
478
+ float mx = max(c.r, max(c.g, c.b));
479
+ float mn = min(c.r, min(c.g, c.b));
480
+ float boost = v * (1.0 - (mx - mn));
481
+ float luma = dot(c, vec3(0.299, 0.587, 0.114));
482
+ return mix(vec3(luma), c, 1.0 + boost);
483
+ }`, xt = `#define GLOW_SCALE 4
484
+
485
+ vec4 glowGather(sampler2D trails, ivec2 texel) {
486
+ ivec2 last = textureSize(trails, 0) - 1;
487
+ ivec2 origin = texel * GLOW_SCALE;
488
+ vec4 sum = vec4(0.0);
489
+ for (int y = 0; y < GLOW_SCALE; y++) {
490
+ for (int x = 0; x < GLOW_SCALE; x++) {
491
+ vec4 c = texelFetch(trails, min(origin + ivec2(x, y), last), 0);
492
+ sum += vec4(c.rgb * c.a, c.a);
493
+ }
494
+ }
495
+ return sum / float(GLOW_SCALE * GLOW_SCALE);
496
+ }
497
+
498
+ vec4 addGlow(vec4 trail, sampler2D glowTex, vec2 uv, float gain) {
499
+ vec2 d = 1.0 / vec2(textureSize(glowTex, 0));
500
+ vec4 glow = 0.25 * (
501
+ texture(glowTex, uv + vec2(-d.x, -d.y)) +
502
+ texture(glowTex, uv + vec2(d.x, -d.y)) +
503
+ texture(glowTex, uv + vec2(-d.x, d.y)) +
504
+ texture(glowTex, uv + vec2(d.x, d.y)));
505
+ glow = min(glow * gain, vec4(1.0));
506
+ float under = 1.0 - trail.a;
507
+ float alpha = trail.a + glow.a * under;
508
+ vec3 rgb = (trail.rgb * trail.a + glow.rgb * under) / max(alpha, 1e-4);
509
+ return vec4(rgb, alpha);
510
+ }`;
511
+ const Ui = bt, Ni = Tt, Ci = wt, Di = yt, Ii = Et, Pi = xt, Li = 4, Gi = 1.2, ue = "x-zartigl-size", fe = "x-zartigl-stored-at", J = "x-zartigl-revision";
512
+ function _t(i, e, t, s) {
513
+ const r = i.indexOf("time");
514
+ if (r < 0 || !e[r] || !t[r])
515
+ return "";
516
+ const n = Math.floor((e[r] - 1) / t[r]);
517
+ return s[r] === n ? `t=${e[r]}` : "";
518
+ }
519
+ function Vi(i = "zartigl-chunks-v1") {
520
+ const e = typeof caches > "u" ? void 0 : caches;
521
+ if (!e)
522
+ return {
523
+ get: async () => {
524
+ },
525
+ put: async () => {
526
+ },
527
+ entries: async () => [],
528
+ delete: async () => {
529
+ },
530
+ estimate: async () => {
531
+ }
532
+ };
533
+ let t = null;
534
+ const s = () => t ??= e.open(i);
535
+ let r = !1;
536
+ const n = () => {
537
+ !r && typeof navigator < "u" && (r = !0, navigator.storage?.persist?.().catch(() => !1));
538
+ };
539
+ return {
540
+ async get(o, a = "") {
541
+ try {
542
+ const c = await (await s()).match(o);
543
+ return !c || (c.headers.get(J) ?? "") !== a ? void 0 : new Uint8Array(await c.arrayBuffer());
544
+ } catch {
545
+ return;
546
+ }
547
+ },
548
+ async put(o, a, c = "") {
549
+ n();
550
+ try {
551
+ const l = new Uint8Array(a);
552
+ await (await s()).put(
553
+ o,
554
+ new Response(l, {
555
+ headers: {
556
+ "content-type": "application/octet-stream",
557
+ [ue]: String(l.byteLength),
558
+ [fe]: String(Date.now()),
559
+ [J]: c
560
+ }
561
+ })
562
+ );
563
+ } catch {
564
+ }
565
+ },
566
+ async entries(o = "") {
567
+ try {
568
+ const a = await s(), c = [];
569
+ for (const l of await a.keys()) {
570
+ if (!l.url.startsWith(o))
571
+ continue;
572
+ const d = await a.match(l);
573
+ d && c.push({
574
+ url: l.url,
575
+ size: Number(d.headers.get(ue) ?? 0),
576
+ storedAt: Number(d.headers.get(fe) ?? 0),
577
+ revision: d.headers.get(J) ?? ""
578
+ });
579
+ }
580
+ return c;
581
+ } catch {
582
+ return [];
583
+ }
584
+ },
585
+ async delete(o) {
586
+ try {
587
+ const a = await s();
588
+ await Promise.all(Array.from(o, (c) => a.delete(c)));
589
+ } catch {
590
+ }
591
+ },
592
+ async estimate() {
593
+ try {
594
+ const o = await navigator.storage?.estimate?.();
595
+ return o ? { usage: o.usage ?? 0, quota: o.quota ?? 0 } : void 0;
596
+ } catch {
597
+ return;
598
+ }
599
+ }
600
+ };
601
+ }
602
+ const ee = [
603
+ "depth",
604
+ "elevation",
605
+ "level",
606
+ "altitude",
607
+ "pressure_level"
608
+ ];
609
+ class me extends Error {
610
+ constructor(e, t) {
611
+ super(`Chunk fetch failed: ${e} ${t}`), this.name = "ZarrChunkFetchError", this.status = e, this.url = t;
612
+ }
613
+ }
614
+ class Oi {
615
+ /**
616
+ * `options.chunkStore` keeps the compressed chunks across sessions (see
617
+ * chunkStore.ts); without it, chunks are only kept in memory.
618
+ */
619
+ constructor(e, t = 200, s = {}) {
620
+ this.meta = null, this.coords = null, this.initPromise = null, this.verticalName = "depth", this.timeUnits = "", this.timeCalendar = "standard", this.cache = /* @__PURE__ */ new Map(), this.abortControllers = /* @__PURE__ */ new Map(), this.bloscCodecCache = /* @__PURE__ */ new Map(), this.root = e.replace(/\/$/, ""), this.maxCacheSize = t, this.chunkStore = s.chunkStore;
621
+ }
622
+ /** The URL of a chunk, as fetched and as stored. */
623
+ chunkUrl(e, t) {
624
+ return `${this.root}/${e}/${t.join(this.getDimensionSeparator(e))}`;
625
+ }
626
+ /** The revision a stored chunk must carry to be current (see chunkRevision). */
627
+ chunkRevision(e, t) {
628
+ return _t(
629
+ this.getDimensions(e),
630
+ this.getShape(e),
631
+ this.getChunkShape(e),
632
+ t
633
+ );
634
+ }
635
+ async init() {
636
+ if (!this.coords) {
637
+ if (this.initPromise)
638
+ return this.initPromise;
639
+ this.initPromise = (async () => {
640
+ const e = await fetch(`${this.root}/.zmetadata`);
641
+ if (!e.ok)
642
+ throw new Error(`Failed to fetch .zmetadata: ${e.status}`);
643
+ this.meta = await e.json(), await this.loadCoordinates();
644
+ })();
645
+ try {
646
+ await this.initPromise;
647
+ } catch (e) {
648
+ throw this.meta = null, this.coords = null, e;
649
+ } finally {
650
+ this.initPromise = null;
651
+ }
652
+ }
653
+ }
654
+ getArrayMeta(e) {
655
+ const t = `${e}/.zarray`, s = this.meta.metadata[t];
656
+ if (!s || !("dtype" in s))
657
+ throw new Error(`No .zarray for ${e}`);
658
+ return s;
659
+ }
660
+ getAttrs(e) {
661
+ const t = `${e}/.zattrs`;
662
+ return this.meta.metadata[t] ?? {};
663
+ }
664
+ getDimensionSeparator(e) {
665
+ return this.getArrayMeta(e).dimension_separator ?? ".";
666
+ }
667
+ getShape(e) {
668
+ return this.getArrayMeta(e).shape;
669
+ }
670
+ getChunkShape(e) {
671
+ return this.getArrayMeta(e).chunks;
672
+ }
673
+ getCoords() {
674
+ if (!this.coords)
675
+ throw new Error("Call init() first");
676
+ return this.coords;
677
+ }
678
+ getTimeDimension() {
679
+ const e = this.getCoords().time, t = e.length, s = Array.from(e, (a) => this.zarrTimeToMs(a));
680
+ let r = t ? s[0] : NaN, n = r;
681
+ for (let a = 1; a < s.length; a++)
682
+ r = Math.min(r, s[a]), n = Math.max(n, s[a]);
683
+ const o = At(s);
684
+ return {
685
+ min: r,
686
+ max: n,
687
+ step: o,
688
+ size: t,
689
+ units: this.timeUnits,
690
+ values: s
691
+ };
692
+ }
693
+ getVerticalDimension(e) {
694
+ if (!this.verticalName || e && !this.getDimensions(e).includes(this.verticalName))
695
+ return;
696
+ const t = this.getAttrs(this.verticalName), s = typeof t.units == "string" ? t.units : void 0, r = typeof t.standard_name == "string" ? t.standard_name : "", n = s?.toLowerCase() ?? "", o = r.includes("pressure") || this.verticalName.includes("pressure") || /(^|\s)(pa|hpa|bar|dbar)($|\s)/i.test(n) ? "pressure" : r.includes("elevation") || this.verticalName === "elevation" || t.positive === "up" ? "elevation" : "depth";
697
+ return {
698
+ name: this.verticalName,
699
+ label: o,
700
+ units: s,
701
+ values: Array.from(this.getCoords().vertical)
702
+ };
703
+ }
704
+ hasVariable(e) {
705
+ const t = this.meta?.metadata[`${e}/.zarray`];
706
+ return !!(t && "dtype" in t);
707
+ }
708
+ getVariableAttrs(e) {
709
+ if (!this.meta)
710
+ throw new Error("Call init() first");
711
+ if (!this.hasVariable(e))
712
+ throw new Error(`No .zarray for ${e}`);
713
+ return { ...this.getAttrs(e) };
714
+ }
715
+ getDimensions(e) {
716
+ return this.getAttrs(e)._ARRAY_DIMENSIONS ?? ["time", "latitude", "longitude"];
717
+ }
718
+ findNearestIndex(e, t) {
719
+ let s = 0, r = Math.abs(e[0] - t);
720
+ for (let n = 1; n < e.length; n++) {
721
+ const o = Math.abs(e[n] - t);
722
+ o < r && (r = o, s = n);
723
+ }
724
+ return s;
725
+ }
726
+ findTimeIndex(e) {
727
+ const t = this.getCoords();
728
+ let s;
729
+ return typeof e == "string" ? s = new Date(e).getTime() : s = e, this.findNearestIndex(t.time, this.msToZarrTime(s));
730
+ }
731
+ /**
732
+ * Convert a Unix-ms timestamp to the native time units used by this zarr
733
+ * (read from the time variable's .zattrs "units" field).
734
+ * Unsupported units are rejected during initialization rather than guessed.
735
+ */
736
+ msToZarrTime(e) {
737
+ const { refMs: t, multiplier: s } = this.parseTimeEncoding();
738
+ return (e - t) / s;
739
+ }
740
+ zarrTimeToMs(e) {
741
+ const { refMs: t, multiplier: s } = this.parseTimeEncoding();
742
+ return t + e * s;
743
+ }
744
+ parseTimeEncoding() {
745
+ const e = this.timeCalendar.toLowerCase();
746
+ if (!["standard", "gregorian", "proleptic_gregorian"].includes(e))
747
+ throw new Error(`Unsupported Zarr time calendar: ${this.timeCalendar}`);
748
+ const t = this.timeUnits.match(
749
+ /^(milliseconds?|seconds?|minutes?|hours?|days?)\s+since\s+(.+)$/i
750
+ );
751
+ if (!t)
752
+ throw new Error(
753
+ `Unsupported Zarr time units: ${this.timeUnits || "<missing>"}`
754
+ );
755
+ const s = vt(t[2]);
756
+ if (!Number.isFinite(s))
757
+ throw new Error(`Invalid Zarr time epoch: ${t[2]}`);
758
+ const r = t[1].toLowerCase(), n = r.startsWith("ms") || r.startsWith("milli") ? 1 : r.startsWith("s") ? 1e3 : r.startsWith("min") ? 6e4 : r.startsWith("h") ? 36e5 : 864e5;
759
+ return { refMs: s, multiplier: n };
760
+ }
761
+ findNearestLongitudeIndex(e) {
762
+ const t = this.getCoords().longitude, s = t[0], r = t[t.length - 1];
763
+ let n = e;
764
+ return s >= 0 && r > 180 ? n = (e % 360 + 360) % 360 : n = ((e + 180) % 360 + 360) % 360 - 180, this.findNearestIndex(t, n);
765
+ }
766
+ async sampleVariableAt(e, t) {
767
+ const s = this.getDimensions(e), r = this.getChunkShape(e), n = this.getShape(e), o = new Array(s.length).fill(0), a = new Array(s.length).fill(0);
768
+ for (let d = 0; d < s.length; d++) {
769
+ const h = s[d];
770
+ let f = 0;
771
+ h === "time" ? f = t.timeIdx : h === "latitude" ? f = t.latIdx : h === "longitude" ? f = t.lonIdx : (h === this.verticalName || ee.includes(h)) && (f = t.depthIdx), f = Math.max(0, Math.min(n[d] - 1, f)), o[d] = Math.floor(f / r[d]), a[d] = f - o[d] * r[d];
772
+ }
773
+ let c;
774
+ try {
775
+ c = await this.fetchChunk(e, o);
776
+ } catch (d) {
777
+ if (d instanceof me && (d.status === 403 || d.status === 404))
778
+ return NaN;
779
+ throw d;
780
+ }
781
+ const l = this.getFlatOffset(e, a);
782
+ return l < c.length ? c[l] : NaN;
783
+ }
784
+ getFlatOffset(e, t) {
785
+ const s = this.getArrayMeta(e), r = s.chunks;
786
+ if (s.order === "F") {
787
+ let o = 0, a = 1;
788
+ for (let c = 0; c < t.length; c++)
789
+ o += t[c] * a, a *= r[c];
790
+ return o;
791
+ }
792
+ let n = 0;
793
+ for (let o = 0; o < t.length; o++)
794
+ n = n * r[o] + t[o];
795
+ return n;
796
+ }
797
+ findDepthIndex(e) {
798
+ return this.findNearestIndex(this.getCoords().vertical, e);
799
+ }
800
+ async sampleTimeSeries(e) {
801
+ await this.init();
802
+ const t = this.getCoords(), s = this.findNearestLongitudeIndex(e.longitude), r = this.findNearestIndex(t.latitude, e.latitude), n = this.findDepthIndex(e.depth ?? 0), o = Math.max(0, e.timeStartIndex ?? 0), a = Math.min(
803
+ t.time.length - 1,
804
+ e.timeEndIndex ?? t.time.length - 1
805
+ ), c = Math.max(1, Math.floor(e.stride ?? 1)), l = Math.max(
806
+ 0,
807
+ Math.floor(e.stopAfterMissingSamples ?? 0)
808
+ );
809
+ let d = 0;
810
+ const h = [];
811
+ for (let f = o; f <= a; f += c) {
812
+ const u = {};
813
+ for (const p of e.variables)
814
+ u[p] = await this.sampleVariableAt(p, {
815
+ timeIdx: f,
816
+ depthIdx: n,
817
+ latIdx: r,
818
+ lonIdx: s
819
+ });
820
+ const m = this.zarrTimeToMs(t.time[f]);
821
+ if (h.push({
822
+ axisValue: m,
823
+ time: m,
824
+ depth: t.vertical[n],
825
+ values: u
826
+ }), d = e.variables.every(
827
+ (p) => !Number.isFinite(u[p])
828
+ ) ? d + 1 : 0, l > 0 && d >= l)
829
+ break;
830
+ }
831
+ return {
832
+ longitude: t.longitude[s],
833
+ latitude: t.latitude[r],
834
+ depth: t.vertical[n],
835
+ points: h
836
+ };
837
+ }
838
+ async sampleVerticalProfile(e) {
839
+ await this.init();
840
+ const t = this.getCoords(), s = this.findNearestLongitudeIndex(e.longitude), r = this.findNearestIndex(t.latitude, e.latitude), n = this.findTimeIndex(e.time), o = Math.max(
841
+ 0,
842
+ Math.floor(e.stopAfterMissingSamples ?? 0)
843
+ );
844
+ let a = 0;
845
+ const c = [];
846
+ let l = Array.from(
847
+ { length: t.vertical.length },
848
+ (f, u) => u
849
+ ).sort(
850
+ (f, u) => Math.abs(t.vertical[f]) - Math.abs(t.vertical[u])
851
+ );
852
+ const d = Math.max(
853
+ 1,
854
+ Math.floor(e.maxDepths ?? l.length)
855
+ ), h = Math.max(
856
+ 1,
857
+ Math.floor(e.stride ?? Math.ceil(l.length / d))
858
+ );
859
+ l = l.filter((f, u) => u % h === 0).slice(0, d);
860
+ for (const f of l) {
861
+ const u = {};
862
+ for (const p of e.variables)
863
+ u[p] = await this.sampleVariableAt(p, {
864
+ timeIdx: n,
865
+ depthIdx: f,
866
+ latIdx: r,
867
+ lonIdx: s
868
+ });
869
+ const m = t.vertical[f];
870
+ if (c.push({
871
+ axisValue: m,
872
+ time: this.zarrTimeToMs(t.time[n]),
873
+ depth: m,
874
+ values: u
875
+ }), a = e.variables.every(
876
+ (p) => !Number.isFinite(u[p])
877
+ ) ? a + 1 : 0, o > 0 && a >= o)
878
+ break;
879
+ }
880
+ return {
881
+ longitude: t.longitude[s],
882
+ latitude: t.latitude[r],
883
+ time: this.zarrTimeToMs(t.time[n]),
884
+ points: c
885
+ };
886
+ }
887
+ /** Return the actual name of the vertical dimension ("depth" or "elevation"). */
888
+ getVerticalDimName() {
889
+ return this.verticalName;
890
+ }
891
+ /**
892
+ * Get chunk indices that intersect a geographic bounding box.
893
+ */
894
+ getChunksForBounds(e, t, s, r) {
895
+ const n = this.getCoords(), o = this.getChunkShape(e), a = this.getDimensions(e), c = a.indexOf("latitude"), l = a.indexOf("longitude"), d = o[c], h = o[l], f = n.latitude, u = n.longitude, m = this.findNearestIndex(f, r.north), T = this.findNearestIndex(f, r.south), p = this.findNearestIndex(u, r.west), y = this.findNearestIndex(u, r.east), k = Math.min(m, T), C = Math.max(m, T), U = Math.min(p, y), b = Math.max(p, y), x = Math.floor(k / d), A = Math.floor(C / d), M = Math.floor(U / h), v = Math.floor(b / h), N = this.getShape(e), O = N[c], Z = N[l], B = [];
896
+ for (let D = x; D <= A; D++)
897
+ for (let P = M; P <= v; P++) {
898
+ const E = D * d, g = P * h, I = Math.min(d, O - E), _ = Math.min(h, Z - g);
899
+ B.push({
900
+ timeIdx: t,
901
+ depthIdx: s,
902
+ latIdx: D,
903
+ lonIdx: P,
904
+ latRange: [f[E], f[E + I - 1]],
905
+ lonRange: [u[g], u[g + _ - 1]],
906
+ latSize: I,
907
+ lonSize: _
908
+ });
909
+ }
910
+ return B;
911
+ }
912
+ async fetchChunk(e, t) {
913
+ return (await this.fetchChunkResult(e, t)).data;
914
+ }
915
+ /**
916
+ * Fetch one latitude/longitude chunk and extract the requested time/vertical
917
+ * plane from it. Logical coordinate indices are converted to physical Zarr
918
+ * chunk indices before fetching.
919
+ */
920
+ async fetchSpatialChunkResult(e, t) {
921
+ const s = this.getDimensions(e), r = this.getChunkShape(e), n = s.indexOf("latitude"), o = s.indexOf("longitude");
922
+ if (n < 0 || o < 0)
923
+ throw new Error(
924
+ `Variable ${e} must have latitude and longitude dimensions`
925
+ );
926
+ const a = new Array(s.length).fill(0), c = new Array(s.length).fill(0);
927
+ for (let u = 0; u < s.length; u++) {
928
+ const m = s[u];
929
+ let T = 0;
930
+ if (m === "time")
931
+ T = t.timeIndex;
932
+ else if (m === this.verticalName || ee.includes(m))
933
+ T = t.verticalIndex;
934
+ else if (m === "latitude") {
935
+ a[u] = t.latitudeChunkIndex;
936
+ continue;
937
+ } else if (m === "longitude") {
938
+ a[u] = t.longitudeChunkIndex;
939
+ continue;
940
+ }
941
+ a[u] = Math.floor(T / r[u]), c[u] = T % r[u];
942
+ }
943
+ const l = await this.fetchChunkResult(e, a), d = r[n], h = r[o], f = new Float32Array(d * h);
944
+ f.fill(NaN);
945
+ for (let u = 0; u < d; u++) {
946
+ c[n] = u;
947
+ for (let m = 0; m < h; m++) {
948
+ c[o] = m;
949
+ const T = this.getFlatOffset(e, c);
950
+ T < l.data.length && (f[u * h + m] = l.data[T]);
951
+ }
952
+ }
953
+ return { ...l, data: f };
954
+ }
955
+ async fetchChunkResult(e, t) {
956
+ const s = this.getDimensionSeparator(e), r = t.join(s), n = `${e}/${r}`, o = `${this.root}/${e}/${r}`;
957
+ if (this.cache.has(n))
958
+ return { data: this.cache.get(n), missing: !1, url: o };
959
+ this.abortControllers.get(n)?.abort();
960
+ const a = new AbortController();
961
+ this.abortControllers.set(n, a);
962
+ const c = this.getArrayMeta(e), l = this.chunkStore ? this.chunkRevision(e, t) : "";
963
+ try {
964
+ const d = await this.chunkStore?.get(o, l);
965
+ if (d) {
966
+ const m = pe(
967
+ await this.decompress(d, c, e)
968
+ );
969
+ return this.cacheChunk(n, m), { data: m, missing: !1, url: o };
970
+ }
971
+ const h = await fetch(o, { signal: a.signal });
972
+ if (!h.ok) {
973
+ if (h.status === 403 || h.status === 404)
974
+ return {
975
+ data: Rt(c),
976
+ missing: !0,
977
+ status: h.status,
978
+ url: o
979
+ };
980
+ throw new me(h.status, o);
981
+ }
982
+ const f = new Uint8Array(await h.arrayBuffer());
983
+ this.chunkStore?.put(o, f, l);
984
+ const u = pe(
985
+ await this.decompress(f, c, e)
986
+ );
987
+ return this.cacheChunk(n, u), { data: u, missing: !1, url: o };
988
+ } finally {
989
+ this.abortControllers.get(n) === a && this.abortControllers.delete(n);
990
+ }
991
+ }
992
+ cancelAll() {
993
+ for (const e of this.abortControllers.values())
994
+ e.abort();
995
+ this.abortControllers.clear();
996
+ }
997
+ cacheChunk(e, t) {
998
+ if (this.cache.size >= this.maxCacheSize) {
999
+ const s = this.cache.keys().next().value;
1000
+ s !== void 0 && this.cache.delete(s);
1001
+ }
1002
+ this.cache.set(e, t);
1003
+ }
1004
+ getBloscCodec(e) {
1005
+ const t = e.compressor, s = `${t.cname ?? "lz4"}-${t.clevel ?? 5}-${t.shuffle ?? 1}-${t.blocksize ?? 0}`;
1006
+ let r = this.bloscCodecCache.get(s);
1007
+ return r || (r = Me.fromConfig({
1008
+ id: "blosc",
1009
+ cname: t.cname ?? "lz4",
1010
+ clevel: t.clevel ?? 5,
1011
+ shuffle: t.shuffle ?? 1,
1012
+ blocksize: t.blocksize ?? 0
1013
+ }), this.bloscCodecCache.set(s, r)), r;
1014
+ }
1015
+ async decompress(e, t, s) {
1016
+ let r;
1017
+ if (t.compressor)
1018
+ switch (t.compressor.id) {
1019
+ case "zlib":
1020
+ case "gzip":
1021
+ r = Ae(e);
1022
+ break;
1023
+ case "blosc": {
1024
+ r = await this.getBloscCodec(t).decode(e);
1025
+ break;
1026
+ }
1027
+ default:
1028
+ throw new Error(`Unsupported compressor: ${t.compressor.id}`);
1029
+ }
1030
+ else
1031
+ r = e;
1032
+ let n;
1033
+ const o = t.dtype;
1034
+ if (o === "<f4" || o === "|f4")
1035
+ n = new Float32Array(
1036
+ r.buffer,
1037
+ r.byteOffset,
1038
+ r.byteLength / 4
1039
+ );
1040
+ else if (o === "<f8" || o === "|f8")
1041
+ n = new Float64Array(
1042
+ r.buffer,
1043
+ r.byteOffset,
1044
+ r.byteLength / 8
1045
+ );
1046
+ else if (o === "<i2" || o === "|i2") {
1047
+ const c = new Int16Array(
1048
+ r.buffer,
1049
+ r.byteOffset,
1050
+ r.byteLength / 2
1051
+ );
1052
+ n = Float32Array.from(c);
1053
+ } else if (o === "<i4" || o === "|i4") {
1054
+ const c = new Int32Array(
1055
+ r.buffer,
1056
+ r.byteOffset,
1057
+ r.byteLength / 4
1058
+ );
1059
+ n = Float32Array.from(c);
1060
+ } else if (o === "<i8" || o === "|i8") {
1061
+ const c = new DataView(
1062
+ r.buffer,
1063
+ r.byteOffset,
1064
+ r.byteLength
1065
+ ), l = r.byteLength / 8;
1066
+ n = new Float64Array(l);
1067
+ for (let d = 0; d < l; d++)
1068
+ n[d] = Number(c.getBigInt64(d * 8, !0));
1069
+ } else
1070
+ throw new Error(`Unsupported dtype: ${o}`);
1071
+ const a = t.fill_value;
1072
+ if (a != null && typeof a == "number" && !isNaN(a))
1073
+ for (let c = 0; c < n.length; c++)
1074
+ n[c] === a && (n[c] = NaN);
1075
+ if (s) {
1076
+ const c = this.getAttrs(s), l = c.scale_factor, d = c.add_offset;
1077
+ if (l != null || d != null) {
1078
+ const h = l ?? 1, f = d ?? 0;
1079
+ for (let u = 0; u < n.length; u++)
1080
+ isNaN(n[u]) || (n[u] = n[u] * h + f);
1081
+ }
1082
+ }
1083
+ return n;
1084
+ }
1085
+ async loadCoordinates() {
1086
+ const e = async (c) => {
1087
+ const l = this.getArrayMeta(c), d = l.shape[0], h = Math.ceil(d / l.chunks[0]), f = [];
1088
+ for (let p = 0; p < h; p++) {
1089
+ const y = `${this.root}/${c}/${p}`, k = await fetch(y);
1090
+ if (!k.ok)
1091
+ throw new Error(`Failed to fetch coord ${c}/${p}`);
1092
+ const C = new Uint8Array(await k.arrayBuffer());
1093
+ f.push(await this.decompress(C, l));
1094
+ }
1095
+ if (f.length === 1)
1096
+ return f[0].length > d ? f[0].subarray(0, d) : f[0];
1097
+ const u = f.some((p) => p instanceof Float64Array) ? Float64Array : Float32Array, m = new u(d);
1098
+ let T = 0;
1099
+ for (const p of f) {
1100
+ const y = Math.min(p.length, d - T);
1101
+ if (m.set(p.subarray(0, y), T), T += y, T >= d)
1102
+ break;
1103
+ }
1104
+ return m;
1105
+ };
1106
+ let t = null;
1107
+ for (const c of ee) {
1108
+ const l = `${c}/.zarray`;
1109
+ if (this.meta.metadata[l] && "dtype" in this.meta.metadata[l]) {
1110
+ t = c;
1111
+ break;
1112
+ }
1113
+ }
1114
+ this.verticalName = t ?? "";
1115
+ const s = this.getAttrs("time");
1116
+ this.timeUnits = s.units ?? "", this.timeCalendar = s.calendar ?? "standard", this.parseTimeEncoding();
1117
+ const [r, n, o] = await Promise.all([
1118
+ e("time"),
1119
+ e("latitude"),
1120
+ e("longitude")
1121
+ ]);
1122
+ let a;
1123
+ t ? a = await e(t) : a = new Float32Array([0]), this.coords = {
1124
+ time: r,
1125
+ vertical: a,
1126
+ latitude: n,
1127
+ longitude: o
1128
+ };
1129
+ }
1130
+ }
1131
+ function pe(i) {
1132
+ return i instanceof Float32Array ? i : Float32Array.from(i);
1133
+ }
1134
+ function Rt(i) {
1135
+ const e = i.chunks.reduce((s, r) => s * r, 1), t = new Float32Array(e);
1136
+ return t.fill(NaN), t;
1137
+ }
1138
+ function vt(i) {
1139
+ const t = i.trim().replace(/\s+\([^)]*\)\s*$/, "").match(
1140
+ /^(\d{4})-(\d{2})-(\d{2})(?:(?:T|\s+)(\d{2})(?::(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?)?)?(?:\s*(Z|[+-]\d{2}:?\d{2}))?$/i
1141
+ );
1142
+ if (!t)
1143
+ return NaN;
1144
+ const s = Number(t[1]), r = Number(t[2]), n = Number(t[3]), o = Number(t[4] ?? 0), a = Number(t[5] ?? 0), c = Number(t[6] ?? 0), l = Number((t[7] ?? "").padEnd(3, "0").slice(0, 3)), d = t[8] ?? "Z";
1145
+ if (r < 1 || r > 12 || o > 23 || a > 59 || c > 59)
1146
+ return NaN;
1147
+ const h = /* @__PURE__ */ new Date(0);
1148
+ h.setUTCFullYear(s, r - 1, n), h.setUTCHours(o, a, c, l);
1149
+ const f = h.getTime();
1150
+ if (h.getUTCFullYear() !== s || h.getUTCMonth() !== r - 1 || h.getUTCDate() !== n || h.getUTCHours() !== o || h.getUTCMinutes() !== a || h.getUTCSeconds() !== c || h.getUTCMilliseconds() !== l)
1151
+ return NaN;
1152
+ if (/^z$/i.test(d))
1153
+ return f;
1154
+ const u = d.match(/^([+-])(\d{2}):?(\d{2})$/);
1155
+ if (!u)
1156
+ return NaN;
1157
+ const m = Number(u[2]), T = Number(u[3]);
1158
+ if (m > 23 || T > 59)
1159
+ return NaN;
1160
+ const p = (m * 60 + T) * 6e4;
1161
+ return f - (u[1] === "+" ? p : -p);
1162
+ }
1163
+ function kt(i) {
1164
+ if (typeof i != "number" || !Number.isFinite(i) || i <= 0)
1165
+ return i;
1166
+ const e = [
1167
+ 60 * 1e3,
1168
+ 180 * 1e3,
1169
+ 300 * 1e3,
1170
+ 600 * 1e3,
1171
+ 900 * 1e3,
1172
+ 1800 * 1e3,
1173
+ 3600 * 1e3,
1174
+ 10800 * 1e3,
1175
+ 360 * 60 * 1e3,
1176
+ 720 * 60 * 1e3,
1177
+ 1440 * 60 * 1e3,
1178
+ 10080 * 60 * 1e3
1179
+ ];
1180
+ for (const t of e)
1181
+ if (Math.abs(i - t) <= Math.max(1e3, t * 0.02))
1182
+ return t;
1183
+ return Math.round(i);
1184
+ }
1185
+ function At(i) {
1186
+ if (i.length < 2)
1187
+ return;
1188
+ const e = i[1] - i[0];
1189
+ if (!Number.isFinite(e) || e <= 0)
1190
+ return;
1191
+ const t = Math.max(1, Math.abs(e) * 1e-9);
1192
+ for (let s = 2; s < i.length; s++)
1193
+ if (Math.abs(i[s] - i[s - 1] - e) > t)
1194
+ return;
1195
+ return kt(e);
1196
+ }
1197
+ function Bi(i) {
1198
+ if (i == null)
1199
+ return null;
1200
+ if (!Number.isFinite(i[0]) || !Number.isFinite(i[1]) || i[0] >= i[1])
1201
+ throw new RangeError(
1202
+ "colorDomain must contain two finite, increasing values"
1203
+ );
1204
+ return [i[0], i[1]];
1205
+ }
1206
+ function S(i, e) {
1207
+ if (typeof i != "number" || !Number.isFinite(i))
1208
+ throw new Error(`Invalid GeoVideo manifest ${e}`);
1209
+ return i;
1210
+ }
1211
+ function q(i, e) {
1212
+ if (typeof i != "string")
1213
+ throw new Error(`Invalid GeoVideo manifest ${e}`);
1214
+ const t = new Date(i).getTime();
1215
+ if (!Number.isFinite(t))
1216
+ throw new Error(`Invalid GeoVideo manifest ${e}`);
1217
+ return t;
1218
+ }
1219
+ function te(i) {
1220
+ return typeof i == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(
1221
+ i
1222
+ );
1223
+ }
1224
+ function ge(i) {
1225
+ if (!i || typeof i != "object")
1226
+ throw new Error("Invalid GeoVideo manifest");
1227
+ const e = i;
1228
+ if (e.schemaVersion !== 3 || e.type !== "geovideo")
1229
+ throw new Error("Unsupported GeoVideo manifest version or type");
1230
+ if (e.projection !== "equirectangular")
1231
+ throw new Error(
1232
+ `Unsupported GeoVideo projection: ${String(e.projection)}`
1233
+ );
1234
+ if (!Array.isArray(e.bounds) || e.bounds.length !== 4)
1235
+ throw new Error("Invalid GeoVideo manifest bounds");
1236
+ const [t, s, r, n] = e.bounds.map(
1237
+ (u, m) => S(u, `bounds[${m}]`)
1238
+ );
1239
+ if (s < -90 || n > 90 || s >= n || t === r)
1240
+ throw new Error("Invalid GeoVideo geographic bounds");
1241
+ const o = e.media;
1242
+ if (!o || typeof o.url != "string" || !o.url)
1243
+ throw new Error("Invalid GeoVideo media");
1244
+ for (const u of ["width", "height", "fps", "durationSeconds"])
1245
+ if (S(o[u], `media.${u}`) <= 0)
1246
+ throw new Error(`Invalid GeoVideo media.${u}`);
1247
+ const a = e.encoding;
1248
+ if (!a || a.bits !== 8 || a.colorSpace !== "bt709" || a.colorRange !== "limited" && a.colorRange !== "full")
1249
+ throw new Error("Invalid GeoVideo encoding");
1250
+ const c = S(a.codeMin, "encoding.codeMin"), l = S(a.codeMax, "encoding.codeMax");
1251
+ if (c < 0 || l > 255 || c >= l)
1252
+ throw new Error("Invalid GeoVideo code range");
1253
+ let d = o.height;
1254
+ if (a.kind === "scalar-luma") {
1255
+ if (a.transfer !== "linear" && a.transfer !== "log10-1p9" || S(a.valueMin, "encoding.valueMin") >= S(a.valueMax, "encoding.valueMax"))
1256
+ throw new Error("Invalid GeoVideo scalar-luma encoding");
1257
+ } else if (a.kind === "vector-luma") {
1258
+ if (a.transfer !== "linear" && a.transfer !== "sqrt" || a.layout !== "stacked-uv" || S(a.valueDomain, "encoding.valueDomain") <= 0 || o.height % 2 !== 0)
1259
+ throw new Error("Invalid GeoVideo vector-luma encoding");
1260
+ d = o.height / 2;
1261
+ } else
1262
+ throw new Error("Unsupported GeoVideo encoding");
1263
+ const h = e.mask;
1264
+ if (!h || h.kind !== "static-validity" || typeof h.url != "string" || !h.url || S(h.width, "mask.width") !== o.width || S(h.height, "mask.height") !== d || S(h.threshold, "mask.threshold") < 0 || h.threshold > 1)
1265
+ throw new Error("Invalid GeoVideo static mask");
1266
+ if (e.timeline?.kind === "range") {
1267
+ const u = q(e.timeline.dateStart, "timeline.dateStart");
1268
+ if (q(e.timeline.dateEnd, "timeline.dateEnd") <= u)
1269
+ throw new Error("GeoVideo timeline end must follow start");
1270
+ if (e.timeline.interpolation !== "linear" && e.timeline.interpolation !== "nearest")
1271
+ throw new Error("Invalid GeoVideo interpolation");
1272
+ } else if (e.timeline?.kind === "snapshot-loop")
1273
+ q(e.timeline.date, "timeline.date");
1274
+ else if (e.timeline?.kind === "sample-sequence") {
1275
+ if (!Array.isArray(e.timeline.values) || e.timeline.values.length === 0)
1276
+ throw new Error("GeoVideo sample sequence must contain values");
1277
+ const u = e.timeline.values.map(
1278
+ (m, T) => q(m, `timeline.values[${T}]`)
1279
+ );
1280
+ if (u.some((m, T) => T > 0 && m <= u[T - 1]))
1281
+ throw new Error(
1282
+ "GeoVideo sample sequence values must be strictly increasing"
1283
+ );
1284
+ } else
1285
+ throw new Error("Invalid GeoVideo timeline");
1286
+ const f = e.style?.colorDomain;
1287
+ if (!Array.isArray(f) || f.length !== 2 || !f.every(Number.isFinite) || f[0] >= f[1])
1288
+ throw new Error("Invalid GeoVideo color domain");
1289
+ if (!te(e.id) || !e.provenance || !te(e.provenance.catalogEntryId) || !te(e.provenance.inputSourceId) || !Array.isArray(e.provenance.variables) || e.provenance.variables.length === 0)
1290
+ throw new Error("Invalid GeoVideo provenance");
1291
+ return { ...e, bounds: [t, s, r, n] };
1292
+ }
1293
+ async function Mt(i, e) {
1294
+ if (typeof i != "string")
1295
+ return ge(i);
1296
+ const t = await fetch(i, { signal: e });
1297
+ if (!t.ok)
1298
+ throw new Error(
1299
+ `GeoVideo manifest request failed (${t.status}): ${i}`
1300
+ );
1301
+ const s = await t.json(), r = ge(s), n = typeof document < "u" ? new URL(i, document.baseURI).href : i;
1302
+ return {
1303
+ ...r,
1304
+ media: { ...r.media, url: new URL(r.media.url, n).href },
1305
+ mask: { ...r.mask, url: new URL(r.mask.url, n).href }
1306
+ };
1307
+ }
1308
+ function L(i) {
1309
+ if (i.timeline.kind === "snapshot-loop")
1310
+ return [new Date(i.timeline.date).getTime()];
1311
+ if (i.timeline.kind === "sample-sequence")
1312
+ return i.timeline.values.map((r) => new Date(r).getTime());
1313
+ const e = new Date(i.timeline.dateStart).getTime(), t = new Date(i.timeline.dateEnd).getTime(), s = Math.max(
1314
+ 2,
1315
+ Math.round(i.media.durationSeconds * i.media.fps)
1316
+ );
1317
+ return Array.from(
1318
+ { length: s },
1319
+ (r, n) => e + (t - e) * n / (s - 1)
1320
+ );
1321
+ }
1322
+ function be(i) {
1323
+ return i.timeline.kind === "sample-sequence" ? i.timeline.values.length / i.media.durationSeconds : i.media.fps;
1324
+ }
1325
+ function $i(i, e) {
1326
+ return e / be(i);
1327
+ }
1328
+ function St(i, e) {
1329
+ if (i.timeline.kind === "snapshot-loop")
1330
+ return 0;
1331
+ if (i.timeline.kind === "sample-sequence") {
1332
+ const n = L(i);
1333
+ let o = 0;
1334
+ for (let c = 1; c < n.length; c += 1)
1335
+ Math.abs(n[c] - e) < Math.abs(n[o] - e) && (o = c);
1336
+ const a = i.media.durationSeconds / n.length;
1337
+ return o * a + Math.min(a / 2, 0.5 / i.media.fps);
1338
+ }
1339
+ const t = new Date(i.timeline.dateStart).getTime(), s = new Date(i.timeline.dateEnd).getTime();
1340
+ return Math.max(0, Math.min(1, (e - t) / (s - t))) * xe(i);
1341
+ }
1342
+ function Xi(i, e) {
1343
+ if (i.timeline.kind === "snapshot-loop")
1344
+ return new Date(i.timeline.date).getTime();
1345
+ if (i.timeline.kind === "sample-sequence") {
1346
+ const o = L(i), a = i.media.durationSeconds / o.length, c = Math.floor((e + 0.25 / i.media.fps) / a);
1347
+ return o[Math.max(0, Math.min(o.length - 1, c))];
1348
+ }
1349
+ const t = new Date(i.timeline.dateStart).getTime(), s = new Date(i.timeline.dateEnd).getTime(), r = xe(i), n = r > 0 ? Math.max(0, Math.min(1, e / r)) : 0;
1350
+ return t + (s - t) * n;
1351
+ }
1352
+ function xe(i) {
1353
+ return Math.max(0, i.media.durationSeconds - 1 / i.media.fps);
1354
+ }
1355
+ function Ft(i, e) {
1356
+ const t = new Uint8Array(i.length / 4);
1357
+ for (let s = 0; s < t.length; s++) {
1358
+ const r = i[s * 4];
1359
+ t[s] = e === "limited" ? Math.round(r * 219 / 255 + 16) : r;
1360
+ }
1361
+ return t;
1362
+ }
1363
+ class Ut {
1364
+ constructor() {
1365
+ this.gl = null, this.texture = null, this.framebuffer = null;
1366
+ }
1367
+ read(e, t, s) {
1368
+ const r = this.context();
1369
+ r.bindTexture(r.TEXTURE_2D, this.texture), r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL, !1), r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !1), r.pixelStorei(r.UNPACK_COLORSPACE_CONVERSION_WEBGL, r.NONE), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_MIN_FILTER, r.NEAREST), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_MAG_FILTER, r.NEAREST), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_WRAP_S, r.CLAMP_TO_EDGE), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_WRAP_T, r.CLAMP_TO_EDGE), r.texImage2D(r.TEXTURE_2D, 0, r.RGBA, r.RGBA, r.UNSIGNED_BYTE, e), r.bindFramebuffer(r.FRAMEBUFFER, this.framebuffer), r.framebufferTexture2D(
1370
+ r.FRAMEBUFFER,
1371
+ r.COLOR_ATTACHMENT0,
1372
+ r.TEXTURE_2D,
1373
+ this.texture,
1374
+ 0
1375
+ );
1376
+ const n = new Uint8Array(t * s * 4);
1377
+ return r.readPixels(0, 0, t, s, r.RGBA, r.UNSIGNED_BYTE, n), r.bindFramebuffer(r.FRAMEBUFFER, null), n;
1378
+ }
1379
+ release() {
1380
+ this.gl?.getExtension("WEBGL_lose_context")?.loseContext(), this.gl = null, this.texture = null, this.framebuffer = null;
1381
+ }
1382
+ context() {
1383
+ if (this.gl)
1384
+ return this.gl;
1385
+ const e = document.createElement("canvas"), t = {
1386
+ premultipliedAlpha: !1,
1387
+ antialias: !1
1388
+ }, s = e.getContext("webgl2", t);
1389
+ if (!s)
1390
+ throw new Error("WebGL2 is required to decode GeoVideo frames");
1391
+ return this.gl = s, this.texture = s.createTexture(), this.framebuffer = s.createFramebuffer(), s;
1392
+ }
1393
+ }
1394
+ function Ee(i) {
1395
+ const e = Math.max(4, Math.floor(i.length / 4 / 997) * 4);
1396
+ for (let t = 3; t < i.length; t += e)
1397
+ if (i[t] !== 0)
1398
+ return !1;
1399
+ return !0;
1400
+ }
1401
+ function w() {
1402
+ return new DOMException("GeoVideo frame request was cancelled", "AbortError");
1403
+ }
1404
+ function V(i, e, t) {
1405
+ return e ? e.aborted ? (i.catch(() => {
1406
+ }), t?.(), Promise.reject(w())) : new Promise((s, r) => {
1407
+ const n = () => {
1408
+ t?.(), r(w());
1409
+ };
1410
+ e.addEventListener("abort", n, { once: !0 }), i.then(s, r).finally(() => {
1411
+ e.removeEventListener("abort", n);
1412
+ });
1413
+ }) : i;
1414
+ }
1415
+ function ie(i, e) {
1416
+ return new Promise(
1417
+ (t) => i.addEventListener(e, () => t(), { once: !0 })
1418
+ );
1419
+ }
1420
+ const Nt = 250;
1421
+ function Ct(i) {
1422
+ return "requestVideoFrameCallback" in i ? Promise.race([
1423
+ new Promise(
1424
+ (e) => i.requestVideoFrameCallback(() => e())
1425
+ ),
1426
+ new Promise((e) => setTimeout(e, Nt))
1427
+ ]) : Promise.resolve();
1428
+ }
1429
+ class _e {
1430
+ constructor(e, t, s = {}) {
1431
+ this.reader = new Ut(), this.video = null, this.maskCodes = null, this.initPromise = null, this.presented = !1, this.primed = !1, this.queue = Promise.resolve(), this.frames = /* @__PURE__ */ new Map(), this.pending = /* @__PURE__ */ new Set(), this.manifest = e, this.planes = t, this.cacheSize = Math.max(1, s.cacheSize ?? 3), this.width = e.media.width, this.height = e.media.height / t, this.times = Float64Array.from(L(e));
1432
+ }
1433
+ /** Static validity, one 8-bit value per grid cell; null before init(). */
1434
+ get mask() {
1435
+ return this.maskCodes;
1436
+ }
1437
+ /** Luma codes of the presented frame, or null when it is blank. */
1438
+ readCodes(e, t) {
1439
+ const s = this.reader.read(e, this.width, t);
1440
+ return Ee(s) ? null : Ft(s, this.manifest.encoding.colorRange);
1441
+ }
1442
+ /** True when the decoder exposed no pixels; reads back one row only. */
1443
+ isBlank(e) {
1444
+ return Ee(this.reader.read(e, this.width, 1));
1445
+ }
1446
+ init() {
1447
+ return this.initPromise ??= this.load().catch((e) => {
1448
+ throw this.initPromise = null, e;
1449
+ }), this.initPromise;
1450
+ }
1451
+ /** Abort every pending frame decode; frames already decoded stay cached. */
1452
+ cancelAll() {
1453
+ for (const e of [...this.pending])
1454
+ this.drop(e);
1455
+ }
1456
+ /** Release the video element and GL context; a later init() reloads them. */
1457
+ release() {
1458
+ this.cancelAll(), this.frames.clear(), this.video && (this.video.removeAttribute("src"), this.video.load()), this.video = null, this.maskCodes = null, this.presented = !1, this.primed = !1, this.initPromise = null, this.reader.release();
1459
+ }
1460
+ /**
1461
+ * One decode per time step, cached and shared by concurrent requests.
1462
+ * Aborting `request.signal` rejects this request with an AbortError; the
1463
+ * decode goes on while another request waits for it.
1464
+ */
1465
+ frame(e, t = {}) {
1466
+ const { signal: s } = t;
1467
+ if (s?.aborted)
1468
+ return Promise.reject(w());
1469
+ let r = this.frames.get(e);
1470
+ if (r ? (this.frames.delete(e), this.frames.set(e, r)) : r = this.enqueue(e), r.settled)
1471
+ return r.promise;
1472
+ const n = r;
1473
+ return n.waiters++, V(n.promise, s, () => this.leave(n));
1474
+ }
1475
+ enqueue(e) {
1476
+ const t = new AbortController(), s = this.queue.then(
1477
+ () => t.signal.aborted ? Promise.reject(w()) : this.decode(e, t.signal)
1478
+ );
1479
+ this.queue = s.catch(() => {
1480
+ });
1481
+ const r = {
1482
+ index: e,
1483
+ controller: t,
1484
+ promise: V(s, t.signal),
1485
+ waiters: 0,
1486
+ settled: !1
1487
+ };
1488
+ for (this.pending.add(r), r.promise.then(
1489
+ () => {
1490
+ r.settled = !0, this.pending.delete(r);
1491
+ },
1492
+ () => {
1493
+ r.settled = !0, this.pending.delete(r), this.frames.get(e) === r && this.frames.delete(e);
1494
+ }
1495
+ ), this.frames.set(e, r); this.frames.size > this.cacheSize; )
1496
+ this.frames.delete(this.frames.keys().next().value);
1497
+ return r;
1498
+ }
1499
+ /** A request left; drop the decode when it was the last one waiting. */
1500
+ leave(e) {
1501
+ e.waiters--, e.waiters <= 0 && !e.settled && this.drop(e);
1502
+ }
1503
+ drop(e) {
1504
+ e.controller.abort(), this.pending.delete(e), this.frames.get(e.index) === e && this.frames.delete(e.index);
1505
+ }
1506
+ async load() {
1507
+ const [e] = await Promise.all([this.loadMask(), this.loadMedia()]);
1508
+ this.maskCodes = e;
1509
+ }
1510
+ async loadMask() {
1511
+ const { url: e, width: t, height: s } = this.manifest.mask, r = new Image();
1512
+ r.crossOrigin = "anonymous", r.src = e;
1513
+ try {
1514
+ await r.decode();
1515
+ } catch {
1516
+ throw new Error(`Failed to load GeoVideo mask: ${e}`);
1517
+ }
1518
+ if (r.naturalWidth !== t || r.naturalHeight !== s)
1519
+ throw new Error(
1520
+ `GeoVideo mask dimensions ${r.naturalWidth}x${r.naturalHeight} do not match manifest ${t}x${s}`
1521
+ );
1522
+ const n = this.reader.read(r, t, s), o = new Uint8Array(t * s);
1523
+ for (let a = 0; a < o.length; a++)
1524
+ o[a] = n[a * 4];
1525
+ return o;
1526
+ }
1527
+ /** Open the media; the default reads frames by seeking a video element. */
1528
+ async loadMedia() {
1529
+ const e = document.createElement("video");
1530
+ if (e.crossOrigin = "anonymous", e.muted = !0, e.playsInline = !0, e.preload = "metadata", e.src = this.manifest.media.url, this.video = e, await new Promise((t, s) => {
1531
+ e.addEventListener("loadedmetadata", () => t(), {
1532
+ once: !0
1533
+ }), e.addEventListener(
1534
+ "error",
1535
+ () => s(
1536
+ new Error(
1537
+ `Failed to load GeoVideo media: ${this.manifest.media.url}`
1538
+ )
1539
+ ),
1540
+ { once: !0 }
1541
+ );
1542
+ }), e.videoWidth !== this.manifest.media.width || e.videoHeight !== this.manifest.media.height)
1543
+ throw new Error(
1544
+ `GeoVideo media dimensions ${e.videoWidth}x${e.videoHeight} do not match manifest ${this.manifest.media.width}x${this.manifest.media.height}`
1545
+ );
1546
+ }
1547
+ /** Seek to a frame and wait until it is presented. */
1548
+ async presentFrame(e, t) {
1549
+ if (this.presented && Math.abs(e.currentTime - t) <= 1e-3 && !e.seeking)
1550
+ return;
1551
+ const s = Ct(e), r = ie(e, "seeked");
1552
+ e.currentTime = t, await r, e.readyState < HTMLMediaElement.HAVE_CURRENT_DATA && await Promise.race([ie(e, "loadeddata"), ie(e, "canplay")]), await s, this.presented = !0;
1553
+ }
1554
+ /**
1555
+ * Some mobile browsers expose no decoded pixels to WebGL until playback
1556
+ * started once. A muted play/pause primes the decoder, only when needed:
1557
+ * playback would otherwise buffer far beyond the requested frame.
1558
+ */
1559
+ async primeDecoder(e) {
1560
+ this.primed = !0;
1561
+ try {
1562
+ await e.play();
1563
+ } catch {
1564
+ }
1565
+ e.pause(), this.presented = !1;
1566
+ }
1567
+ /** Media time inside the video frame showing step `index`. */
1568
+ stepSeconds(e) {
1569
+ return this.manifest.timeline.kind === "snapshot-loop" ? e / this.manifest.media.fps : St(this.manifest, this.times[e]);
1570
+ }
1571
+ /**
1572
+ * Seek and capture one step. `signal` aborts it between steps; a seek
1573
+ * already started completes first, keeping the queue serial.
1574
+ */
1575
+ async decode(e, t) {
1576
+ if (t.aborted)
1577
+ throw w();
1578
+ await this.init();
1579
+ const s = this.video, r = this.maskCodes;
1580
+ if (t.aborted || !s || !r)
1581
+ throw w();
1582
+ const n = this.stepSeconds(e);
1583
+ if (await this.presentFrame(s, n), t.aborted || s !== this.video)
1584
+ throw w();
1585
+ const o = this.height * this.planes;
1586
+ let a = await this.capture(s, o, r);
1587
+ if (a === null && !this.primed) {
1588
+ if (await this.primeDecoder(s), await this.presentFrame(s, n), t.aborted || s !== this.video)
1589
+ throw w();
1590
+ a = await this.capture(s, o, r);
1591
+ }
1592
+ if (a === null)
1593
+ throw new Error("GeoVideo frame could not be read back from the decoder");
1594
+ return a;
1595
+ }
1596
+ }
1597
+ function Dt(i) {
1598
+ return {
1599
+ codeRange: [i.codeMin / 255, i.codeMax / 255],
1600
+ valueRange: [i.valueMin, i.valueMax],
1601
+ transfer: i.transfer === "log10-1p9" ? 1 : 0
1602
+ };
1603
+ }
1604
+ class It extends _e {
1605
+ constructor(e, t = {}) {
1606
+ if (e.encoding.kind !== "scalar-luma")
1607
+ throw new Error("GeoVideoScalarSource requires a scalar-luma manifest");
1608
+ super(e, 1, t);
1609
+ }
1610
+ async capture(e) {
1611
+ return this.isBlank(e) ? null : createImageBitmap(e, {
1612
+ premultiplyAlpha: "none",
1613
+ colorSpaceConversion: "none"
1614
+ });
1615
+ }
1616
+ }
1617
+ function F(i, e) {
1618
+ if (e <= i[0])
1619
+ return { index: 0, fraction: 0 };
1620
+ const t = i.length - 1;
1621
+ if (e >= i[t])
1622
+ return { index: t, fraction: 0 };
1623
+ let s = 0, r = t;
1624
+ for (; r - s > 1; ) {
1625
+ const n = s + r >> 1;
1626
+ i[n] <= e ? s = n : r = n;
1627
+ }
1628
+ return { index: s, fraction: (e - i[s]) / (i[r] - i[s]) };
1629
+ }
1630
+ function se(i, e) {
1631
+ const { index: t, fraction: s } = F(i, e);
1632
+ return t + s;
1633
+ }
1634
+ function Pt(i, e) {
1635
+ const t = Math.max(0, Math.min(i.length - 1, Math.floor(e))), s = Math.min(t + 1, i.length - 1);
1636
+ return i[t] + (i[s] - i[t]) * Math.max(0, e - t);
1637
+ }
1638
+ function j(i, e, t) {
1639
+ const s = [];
1640
+ let r = e;
1641
+ for (; r + 8 <= t; ) {
1642
+ let n = i.getUint32(r);
1643
+ const o = String.fromCharCode(
1644
+ i.getUint8(r + 4),
1645
+ i.getUint8(r + 5),
1646
+ i.getUint8(r + 6),
1647
+ i.getUint8(r + 7)
1648
+ );
1649
+ let a = 8;
1650
+ if (n === 1 ? (n = Number(i.getBigUint64(r + 8)), a = 16) : n === 0 && (n = t - r), n < a || r + n > t)
1651
+ throw new Error(`Malformed MP4 box ${o}`);
1652
+ s.push({ type: o, start: r + a, end: r + n }), r += n;
1653
+ }
1654
+ return s;
1655
+ }
1656
+ function R(i, e, t) {
1657
+ const s = j(i, e.start, e.end).find(
1658
+ (r) => r.type === t
1659
+ );
1660
+ if (!s)
1661
+ throw new Error(`MP4 box ${t} not found in ${e.type}`);
1662
+ return s;
1663
+ }
1664
+ function z(i, e, t) {
1665
+ return j(i, e.start, e.end).find((s) => s.type === t) ?? null;
1666
+ }
1667
+ function G(i, e) {
1668
+ return { at: e.start + 8, count: i.getUint32(e.start + 4) };
1669
+ }
1670
+ function Lt(i, e, t) {
1671
+ const s = z(i, e, "edts"), r = s && z(i, s, "elst");
1672
+ if (!r)
1673
+ return;
1674
+ const { at: n, count: o } = G(i, r), a = i.getUint8(r.start) === 1 ? Number(i.getBigInt64(n + 8)) : i.getInt32(n + 4);
1675
+ if (o !== 1 || a !== t)
1676
+ throw new Error("Unsupported MP4 edit list");
1677
+ }
1678
+ function Gt(i) {
1679
+ const e = new DataView(i), t = { type: "file", start: 0, end: i.byteLength }, s = R(e, t, "moov"), r = j(e, s.start, s.end).find((E) => {
1680
+ if (E.type !== "trak")
1681
+ return !1;
1682
+ const g = R(e, R(e, E, "mdia"), "hdlr");
1683
+ return String.fromCharCode(...new Uint8Array(i, g.start + 8, 4)) === "vide";
1684
+ });
1685
+ if (!r)
1686
+ throw new Error("MP4 has no video track");
1687
+ const n = R(
1688
+ e,
1689
+ R(e, R(e, r, "mdia"), "minf"),
1690
+ "stbl"
1691
+ ), o = R(e, n, "stsd"), [a] = j(e, o.start + 8, o.end);
1692
+ if (!a || a.type !== "avc1" && a.type !== "avc3")
1693
+ throw new Error(`Unsupported MP4 sample entry ${a?.type}`);
1694
+ const c = e.getUint16(a.start + 24), l = e.getUint16(a.start + 26), d = R(e, { ...a, start: a.start + 78 }, "avcC"), h = new Uint8Array(i.slice(d.start, d.end)), f = (E) => h[E].toString(16).padStart(2, "0"), u = `avc1.${f(1)}${f(2)}${f(3)}`, m = R(e, n, "stsz"), T = e.getUint32(m.start + 4), p = e.getUint32(m.start + 8), y = Array.from(
1695
+ { length: p },
1696
+ (E, g) => T || e.getUint32(m.start + 12 + g * 4)
1697
+ ), k = z(e, n, "co64"), C = k ?? R(e, n, "stco"), U = G(e, C), b = Array.from(
1698
+ { length: U.count },
1699
+ (E, g) => k ? Number(e.getBigUint64(U.at + g * 8)) : e.getUint32(U.at + g * 4)
1700
+ ), x = G(e, R(e, n, "stsc")), A = [];
1701
+ for (let E = 0; E < x.count; E++) {
1702
+ const g = x.at + E * 12, I = e.getUint32(g) - 1, _ = e.getUint32(g + 4), Q = E + 1 < x.count ? e.getUint32(g + 12) - 1 : b.length;
1703
+ for (let $ = I; $ < Q; $++) {
1704
+ let X = b[$];
1705
+ for (let ae = 0; ae < _ && A.length < p; ae++)
1706
+ A.push(X), X += y[A.length - 1];
1707
+ }
1708
+ }
1709
+ const M = G(e, R(e, n, "stts")), v = [];
1710
+ let N = 0;
1711
+ for (let E = 0; E < M.count; E++) {
1712
+ const g = e.getUint32(M.at + E * 8), I = e.getUint32(M.at + E * 8 + 4);
1713
+ for (let _ = 0; _ < g; _++)
1714
+ v.push(N), N += I;
1715
+ }
1716
+ const O = z(e, n, "ctts");
1717
+ if (O) {
1718
+ const E = e.getUint8(O.start) === 1, g = G(e, O);
1719
+ let I = 0;
1720
+ for (let _ = 0; _ < g.count; _++) {
1721
+ const Q = e.getUint32(g.at + _ * 8), $ = E ? e.getInt32(g.at + _ * 8 + 4) : e.getUint32(g.at + _ * 8 + 4);
1722
+ for (let X = 0; X < Q; X++)
1723
+ v[I++] += $;
1724
+ }
1725
+ }
1726
+ Lt(e, r, Math.min(...v.slice(0, p)));
1727
+ const Z = v.slice(0, p).map((E, g) => [E, g]).sort((E, g) => E[0] - g[0]), B = new Array(p);
1728
+ Z.forEach(([, E], g) => B[E] = g);
1729
+ const D = z(e, n, "stss"), P = /* @__PURE__ */ new Set();
1730
+ if (D) {
1731
+ const E = G(e, D);
1732
+ for (let g = 0; g < E.count; g++)
1733
+ P.add(e.getUint32(E.at + g * 4) - 1);
1734
+ }
1735
+ if (A.length !== p || v.length < p)
1736
+ throw new Error("Inconsistent MP4 sample tables");
1737
+ return {
1738
+ codec: u,
1739
+ description: h,
1740
+ width: c,
1741
+ height: l,
1742
+ samples: y.map((E, g) => ({
1743
+ offset: A[g],
1744
+ size: E,
1745
+ frame: B[g],
1746
+ key: D ? P.has(g) : !0
1747
+ }))
1748
+ };
1749
+ }
1750
+ const Vt = 50;
1751
+ class Ot extends It {
1752
+ constructor() {
1753
+ super(...arguments), this.track = null, this.data = null, this.sampleOfFrame = [], this.decoder = null, this.fed = -1, this.taken = -1, this.outputs = /* @__PURE__ */ new Map(), this.progress = null, this.failure = null, this.loading = null;
1754
+ }
1755
+ /** True once the media decodes through WebCodecs. */
1756
+ get usesWebCodecs() {
1757
+ return this.track !== null;
1758
+ }
1759
+ async loadMedia() {
1760
+ if (typeof VideoDecoder > "u" || typeof fetch > "u")
1761
+ return super.loadMedia();
1762
+ const e = new AbortController();
1763
+ this.loading = e;
1764
+ const t = await fetch(this.manifest.media.url, {
1765
+ signal: e.signal
1766
+ });
1767
+ if (!t.ok)
1768
+ throw new Error(
1769
+ `Failed to load GeoVideo media: ${this.manifest.media.url}`
1770
+ );
1771
+ const s = await t.arrayBuffer();
1772
+ let r;
1773
+ try {
1774
+ r = Gt(s);
1775
+ } catch {
1776
+ return this.loading === e ? super.loadMedia() : void 0;
1777
+ }
1778
+ if (r.width !== this.manifest.media.width || r.height !== this.manifest.media.height)
1779
+ throw new Error(
1780
+ `GeoVideo media dimensions ${r.width}x${r.height} do not match manifest ${this.manifest.media.width}x${this.manifest.media.height}`
1781
+ );
1782
+ const { supported: n } = await VideoDecoder.isConfigSupported(
1783
+ this.config(r)
1784
+ ).catch(() => ({ supported: !1 }));
1785
+ if (this.loading !== e)
1786
+ throw w();
1787
+ if (this.loading = null, !n)
1788
+ return super.loadMedia();
1789
+ this.sampleOfFrame = [], r.samples.forEach(
1790
+ (o, a) => this.sampleOfFrame[o.frame] = a
1791
+ ), this.data = s, this.track = r;
1792
+ }
1793
+ release() {
1794
+ this.loading?.abort(), this.loading = null, this.closeDecoder(), this.track = null, this.data = null, super.release();
1795
+ }
1796
+ async decode(e, t) {
1797
+ if (await this.init(), !this.track)
1798
+ return super.decode(e, t);
1799
+ if (t.aborted)
1800
+ throw w();
1801
+ const s = Math.min(
1802
+ this.track.samples.length - 1,
1803
+ Math.floor(this.stepSeconds(e) * this.manifest.media.fps + 1e-6)
1804
+ ), r = await this.decodeFrame(s, t);
1805
+ try {
1806
+ return await createImageBitmap(r, {
1807
+ premultiplyAlpha: "none",
1808
+ colorSpaceConversion: "none"
1809
+ });
1810
+ } finally {
1811
+ r.close();
1812
+ }
1813
+ }
1814
+ config(e) {
1815
+ return {
1816
+ codec: e.codec,
1817
+ description: e.description,
1818
+ codedWidth: e.width,
1819
+ codedHeight: e.height,
1820
+ optimizeForLatency: !0
1821
+ };
1822
+ }
1823
+ /** Video frame `frame`, owned by the caller. */
1824
+ async decodeFrame(e, t) {
1825
+ const s = this.track, r = this.sampleOfFrame[e], n = this.keySample(r);
1826
+ for ((this.fed < 0 || e <= this.taken || n > this.fed) && this.restart(n), this.taken = e - 1, this.dropOutputsBefore(e); !this.outputs.has(e); ) {
1827
+ if (this.failure)
1828
+ throw this.failure;
1829
+ if (t.aborted)
1830
+ throw w();
1831
+ const a = this.decoder;
1832
+ this.fed < s.samples.length && a.decodeQueueSize < 2 && (this.feed(this.fed++), this.fed === s.samples.length && a.flush().catch(() => {
1833
+ })), await this.waitProgress();
1834
+ }
1835
+ const o = this.outputs.get(e);
1836
+ return this.outputs.delete(e), this.taken = e, o;
1837
+ }
1838
+ dropOutputsBefore(e) {
1839
+ for (const [t, s] of this.outputs)
1840
+ t < e && (s.close(), this.outputs.delete(t));
1841
+ }
1842
+ keySample(e) {
1843
+ const { samples: t } = this.track;
1844
+ let s = e;
1845
+ for (; s > 0 && !t[s].key; )
1846
+ s--;
1847
+ return s;
1848
+ }
1849
+ restart(e) {
1850
+ this.closeDecoder(), this.failure = null;
1851
+ const t = new VideoDecoder({
1852
+ output: (s) => {
1853
+ this.decoder !== t || s.timestamp <= this.taken ? s.close() : this.outputs.set(s.timestamp, s), this.notify();
1854
+ },
1855
+ error: (s) => {
1856
+ this.decoder === t && (this.failure = s, this.fed = -1), this.notify();
1857
+ }
1858
+ });
1859
+ t.addEventListener("dequeue", () => this.notify()), t.configure(this.config(this.track)), this.decoder = t, this.fed = e, this.taken = this.track.samples[e].frame - 1;
1860
+ }
1861
+ feed(e) {
1862
+ const t = this.track.samples[e];
1863
+ this.decoder.decode(
1864
+ new EncodedVideoChunk({
1865
+ type: t.key ? "key" : "delta",
1866
+ // Video frame numbers: outputs carry them back in display order.
1867
+ timestamp: t.frame,
1868
+ data: new Uint8Array(this.data, t.offset, t.size)
1869
+ })
1870
+ );
1871
+ }
1872
+ /** Next output, dequeue or error; a timer for decoders without events. */
1873
+ waitProgress() {
1874
+ return new Promise((e) => {
1875
+ const t = setTimeout(s, Vt);
1876
+ function s() {
1877
+ clearTimeout(t), e();
1878
+ }
1879
+ this.progress = s;
1880
+ });
1881
+ }
1882
+ notify() {
1883
+ const e = this.progress;
1884
+ this.progress = null, e?.();
1885
+ }
1886
+ closeDecoder() {
1887
+ this.decoder && this.decoder.state !== "closed" && this.decoder.close(), this.decoder = null, this.fed = -1;
1888
+ for (const e of this.outputs.values())
1889
+ e.close();
1890
+ this.outputs.clear();
1891
+ }
1892
+ }
1893
+ function Bt(i, e) {
1894
+ let t = (i - e.codeMin) / (e.codeMax - e.codeMin) * 2 - 1;
1895
+ return t = Math.max(-1, Math.min(1, t)), e.transfer === "sqrt" && (t = Math.sign(t) * t * t), t * e.valueDomain;
1896
+ }
1897
+ function $t(i, e, t, s) {
1898
+ const r = e.length;
1899
+ if (i.length !== 2 * r)
1900
+ throw new Error(
1901
+ `GeoVideo vector frame has ${i.length} codes, expected ${2 * r}`
1902
+ );
1903
+ const n = new Float32Array(256);
1904
+ for (let l = 0; l < 256; l++)
1905
+ n[l] = Bt(l, s);
1906
+ const o = t * 255, a = new Float32Array(r), c = new Float32Array(r);
1907
+ for (let l = 0; l < r; l++) {
1908
+ const d = e[l] >= o;
1909
+ a[l] = d ? n[i[l]] : NaN, c[l] = d ? n[i[r + l]] : NaN;
1910
+ }
1911
+ return { u: a, v: c };
1912
+ }
1913
+ class Xt extends _e {
1914
+ constructor(e, t = {}) {
1915
+ if (e.encoding.kind !== "vector-luma")
1916
+ throw new Error("GeoVideoVectorSource requires a vector-luma manifest");
1917
+ super(e, 2, t), this.encoding = e.encoding;
1918
+ const [s, r, n, o] = e.bounds, a = (n - s) / this.width, c = (o - r) / this.height;
1919
+ this.coords = {
1920
+ time: this.times,
1921
+ vertical: new Float32Array([0]),
1922
+ latitude: Float32Array.from(
1923
+ { length: this.height },
1924
+ (l, d) => o - (d + 0.5) * c
1925
+ ),
1926
+ longitude: Float32Array.from(
1927
+ { length: this.width },
1928
+ (l, d) => s + (d + 0.5) * a
1929
+ )
1930
+ };
1931
+ }
1932
+ getValueDomain() {
1933
+ return this.encoding.valueDomain;
1934
+ }
1935
+ getCoords() {
1936
+ return this.coords;
1937
+ }
1938
+ getDimensions() {
1939
+ return ["time", "latitude", "longitude"];
1940
+ }
1941
+ getChunkShape() {
1942
+ return [1, this.height, this.width];
1943
+ }
1944
+ findDepthIndex() {
1945
+ return 0;
1946
+ }
1947
+ findTimeIndex(e) {
1948
+ const t = typeof e == "number" ? e : new Date(e).getTime(), s = this.coords.time;
1949
+ let r = 0;
1950
+ for (let n = 1; n < s.length; n++)
1951
+ Math.abs(s[n] - t) < Math.abs(s[r] - t) && (r = n);
1952
+ return r;
1953
+ }
1954
+ getChunksForBounds(e, t, s) {
1955
+ const { latitude: r, longitude: n } = this.coords;
1956
+ return [
1957
+ {
1958
+ timeIdx: t,
1959
+ depthIdx: s,
1960
+ latIdx: 0,
1961
+ lonIdx: 0,
1962
+ latRange: [r[0], r[this.height - 1]],
1963
+ lonRange: [n[0], n[this.width - 1]],
1964
+ latSize: this.height,
1965
+ lonSize: this.width
1966
+ }
1967
+ ];
1968
+ }
1969
+ async fetchSpatialChunkResult(e, t) {
1970
+ const s = await this.frame(t.timeIndex);
1971
+ return {
1972
+ data: e === "v" ? s.v : s.u,
1973
+ missing: !1,
1974
+ url: this.manifest.media.url
1975
+ };
1976
+ }
1977
+ /** u/v codes are written into luma: read back, then decoded on the CPU. */
1978
+ async capture(e, t, s) {
1979
+ const r = this.readCodes(e, t);
1980
+ return r ? $t(
1981
+ r,
1982
+ s,
1983
+ this.manifest.mask.threshold,
1984
+ this.encoding
1985
+ ) : null;
1986
+ }
1987
+ }
1988
+ function zt(i, e, t = {}) {
1989
+ const [s, r] = t.range ?? [-1 / 0, 1 / 0], n = [...i].sort((a, c) => a.start - c.start), o = n.find(
1990
+ (a) => a.start > e && a.start <= r
1991
+ ) ?? (t.loop ? n.find(
1992
+ (a) => a.end >= s && a.start <= r
1993
+ ) : void 0);
1994
+ return o ? { chunk: o, time: Math.max(o.start, s) } : null;
1995
+ }
1996
+ function qt(i, e) {
1997
+ let t = null, s = -1 / 0;
1998
+ for (const r of e) {
1999
+ const n = Math.min(i.end, r.end) - Math.max(i.start, r.start);
2000
+ Number.isFinite(n) && n >= 0 && n > s && (t = r, s = n);
2001
+ }
2002
+ return t;
2003
+ }
2004
+ function Wt(i) {
2005
+ return {
2006
+ width: i.mask.width,
2007
+ height: i.mask.height,
2008
+ bounds: i.bounds,
2009
+ rowOrder: "north-to-south"
2010
+ };
2011
+ }
2012
+ function Re(i, e = {}) {
2013
+ return i.encoding.kind === "vector-luma" ? new Xt(i, e) : new Ot(i, e);
2014
+ }
2015
+ const Ht = 3, Yt = 3, jt = 0.6, Kt = 1.5;
2016
+ function Zt(i) {
2017
+ const e = new AbortController();
2018
+ if (!i)
2019
+ return { controller: e, unlink: () => {
2020
+ } };
2021
+ const t = () => e.abort();
2022
+ return i.aborted && t(), i.addEventListener("abort", t, { once: !0 }), {
2023
+ controller: e,
2024
+ unlink: () => i.removeEventListener("abort", t)
2025
+ };
2026
+ }
2027
+ class zi {
2028
+ constructor(e) {
2029
+ this.manifests = /* @__PURE__ */ new Map(), this.open = /* @__PURE__ */ new Map(), this.id = e.id, this.chunks = e.chunks.filter(
2030
+ (t) => Number.isFinite(t.start) && Number.isFinite(t.end) && t.end >= t.start
2031
+ ).sort((t, s) => t.start - s.start), this.maxOpenChunks = Math.max(2, e.maxOpenChunks ?? Ht), this.frameCacheSize = Math.max(
2032
+ 1,
2033
+ e.frameCacheSize ?? Yt
2034
+ ), this.prefetchAt = e.prefetchAt ?? jt, this.maxGap = e.maxGap, this.loadManifest = e.loadManifest ?? Mt, this.createFrameSource = e.createFrameSource ?? ((t, s) => Re(
2035
+ t,
2036
+ s
2037
+ ));
2038
+ }
2039
+ /** First and last sample of the archive, or null without chunks. */
2040
+ get range() {
2041
+ const { chunks: e } = this;
2042
+ return e.length ? [e[0].start, Math.max(...e.map((t) => t.end))] : null;
2043
+ }
2044
+ /** The chunk whose sample range holds `time`, or null. */
2045
+ chunkAt(e) {
2046
+ const t = this.chunkIndexAt(e), s = t >= 0 ? this.chunks[t] : null;
2047
+ return s && e <= s.end ? s : null;
2048
+ }
2049
+ /** Every step time of the archive; loads all chunk manifests. */
2050
+ async steps(e = {}) {
2051
+ if (e.signal?.aborted)
2052
+ throw w();
2053
+ const t = await V(
2054
+ Promise.all(this.chunks.map((s) => this.manifest(s))),
2055
+ e.signal
2056
+ );
2057
+ return Float64Array.from(t.flatMap(L));
2058
+ }
2059
+ /**
2060
+ * The frames bracketing `time`, decoded; null out of coverage (before the
2061
+ * first step, after the last, or in a gap wider than `maxGap`).
2062
+ */
2063
+ async sample(e, t = {}) {
2064
+ const { signal: s } = t, r = t.mode ?? "interpolate";
2065
+ if (s?.aborted)
2066
+ throw w();
2067
+ const n = this.chunkIndexAt(e);
2068
+ if (n < 0)
2069
+ return null;
2070
+ const o = [], { controller: a, unlink: c } = Zt(s);
2071
+ try {
2072
+ const l = this.acquire(this.chunks[n], o), d = await V(l.ready, a.signal), { times: h } = d;
2073
+ let f;
2074
+ if (e <= h[h.length - 1]) {
2075
+ const { index: b, fraction: x } = F(h, e);
2076
+ f = r === "discrete" || x === 0 ? [l, b, l, b, 0] : [l, b, l, b + 1, x];
2077
+ } else {
2078
+ const b = this.chunks[n + 1];
2079
+ if (!b)
2080
+ return null;
2081
+ const x = this.acquire(b, o), A = await V(x.ready, a.signal), M = h.length - 1, v = h[M], N = A.times[0];
2082
+ if (N - v > this.gapLimit(h, A.times))
2083
+ return null;
2084
+ f = r === "discrete" ? [l, M, l, M, 0] : e >= N ? [x, 0, x, 0, 0] : [l, M, x, 0, (e - v) / (N - v)];
2085
+ }
2086
+ const [u, m, T, p, y] = f, k = u === T && m === p, C = [this.frame(u, m, a.signal)];
2087
+ k || C.push(this.frame(T, p, a.signal));
2088
+ let U;
2089
+ try {
2090
+ U = await Promise.all(C);
2091
+ } catch (b) {
2092
+ throw a.abort(), b;
2093
+ }
2094
+ return this.prefetchAfter(n, e), {
2095
+ time: e,
2096
+ a: U[0],
2097
+ b: U[k ? 0 : 1],
2098
+ mix: y
2099
+ };
2100
+ } finally {
2101
+ c();
2102
+ for (const l of o)
2103
+ l.users--;
2104
+ this.trim();
2105
+ }
2106
+ }
2107
+ /** Open `chunk` and decode its first frame ahead of a request. */
2108
+ prefetch(e) {
2109
+ if (this.open.has(e.key))
2110
+ return;
2111
+ const t = this.touch(e), s = new AbortController();
2112
+ t.prefetch = s, t.ready.then(({ source: r }) => r.frame(0, { signal: s.signal })).catch(() => {
2113
+ }).finally(() => {
2114
+ t.prefetch === s && (t.prefetch = null);
2115
+ }), this.trim();
2116
+ }
2117
+ /** Release every open chunk source; later requests reopen them. */
2118
+ release() {
2119
+ for (const e of [...this.open.values()])
2120
+ this.close(e);
2121
+ }
2122
+ chunkIndexAt(e) {
2123
+ let t = 0, s = this.chunks.length - 1, r = -1;
2124
+ for (; t <= s; ) {
2125
+ const n = t + s >> 1;
2126
+ this.chunks[n].start <= e ? (r = n, t = n + 1) : s = n - 1;
2127
+ }
2128
+ return r;
2129
+ }
2130
+ gapLimit(e, t) {
2131
+ if (this.maxGap !== void 0)
2132
+ return this.maxGap;
2133
+ const s = [
2134
+ e.length > 1 ? e[e.length - 1] - e[e.length - 2] : 0,
2135
+ t.length > 1 ? t[1] - t[0] : 0
2136
+ ], r = Math.max(...s);
2137
+ return r > 0 ? r * Kt : -1 / 0;
2138
+ }
2139
+ prefetchAfter(e, t) {
2140
+ const s = this.chunks[e], r = this.chunks[e + 1], n = s.end - s.start, o = n > 0 ? (t - s.start) / n : 1;
2141
+ r && o > this.prefetchAt && this.prefetch(r);
2142
+ }
2143
+ manifest(e) {
2144
+ let t = this.manifests.get(e.manifestUrl);
2145
+ return t || (t = this.loadManifest(e.manifestUrl), this.manifests.set(e.manifestUrl, t), t.catch(() => {
2146
+ this.manifests.get(e.manifestUrl) === t && this.manifests.delete(e.manifestUrl);
2147
+ })), t;
2148
+ }
2149
+ /** The open chunk, pinned for a running sample listed in `used`. */
2150
+ acquire(e, t) {
2151
+ const s = this.touch(e);
2152
+ return s.users++, t.push(s), s;
2153
+ }
2154
+ /** The open chunk, opened when needed, most recently used; not pinned. */
2155
+ touch(e) {
2156
+ let t = this.open.get(e.key);
2157
+ if (t)
2158
+ this.open.delete(e.key);
2159
+ else {
2160
+ const s = {
2161
+ chunk: e,
2162
+ ready: null,
2163
+ opened: null,
2164
+ users: 0,
2165
+ prefetch: null,
2166
+ released: !1
2167
+ };
2168
+ s.ready = this.manifest(e).then((r) => {
2169
+ if (s.released)
2170
+ throw w();
2171
+ return s.opened = {
2172
+ manifest: r,
2173
+ times: Float64Array.from(L(r)),
2174
+ grid: Wt(r),
2175
+ source: this.createFrameSource(r, {
2176
+ cacheSize: this.frameCacheSize
2177
+ })
2178
+ }, s.opened;
2179
+ }), s.ready.catch(() => {
2180
+ this.open.get(e.key) === s && this.open.delete(e.key);
2181
+ }), t = s;
2182
+ }
2183
+ return this.open.set(e.key, t), t;
2184
+ }
2185
+ async frame(e, t, s) {
2186
+ const { manifest: r, times: n, grid: o, source: a } = await V(
2187
+ e.ready,
2188
+ s
2189
+ );
2190
+ if (e.released)
2191
+ throw w();
2192
+ const c = await a.frame(t, { signal: s });
2193
+ return {
2194
+ key: `${this.id}/${e.chunk.key}/${t}`,
2195
+ chunk: e.chunk,
2196
+ step: t,
2197
+ time: n[t],
2198
+ data: c,
2199
+ grid: o,
2200
+ manifest: r
2201
+ };
2202
+ }
2203
+ /** Release least recently used chunks beyond the bound, unless in use. */
2204
+ trim() {
2205
+ let e = this.open.size - this.maxOpenChunks;
2206
+ for (const t of [...this.open.values()]) {
2207
+ if (e <= 0)
2208
+ return;
2209
+ t.users === 0 && (this.close(t), e--);
2210
+ }
2211
+ }
2212
+ close(e) {
2213
+ e.released = !0, e.prefetch?.abort(), e.prefetch = null, e.opened?.source.release(), e.opened = null, this.open.get(e.chunk.key) === e && this.open.delete(e.chunk.key);
2214
+ }
2215
+ }
2216
+ const Qt = {
2217
+ a: "u_vel0",
2218
+ b: "u_vel1",
2219
+ mix: "u_vel_mix",
2220
+ bounds: "u_bounds"
2221
+ }, Jt = {
2222
+ a: "u_tint0",
2223
+ b: "u_tint1",
2224
+ mix: "u_tint_mix",
2225
+ bounds: "u_tint_bounds"
2226
+ };
2227
+ function ei(i) {
2228
+ const e = new Float32Array(i.u.length * 4);
2229
+ for (let t = 0; t < i.u.length; t++) {
2230
+ const s = i.u[t], r = i.v[t];
2231
+ Number.isNaN(s) || Number.isNaN(r) || (e[t * 4] = s, e[t * 4 + 1] = r, e[t * 4 + 2] = 1);
2232
+ }
2233
+ return e;
2234
+ }
2235
+ class ti {
2236
+ constructor(e, t, s = {}) {
2237
+ this.gl = e, this.manifest = t, this.options = s, this.textures = /* @__PURE__ */ new Map(), this.pending = /* @__PURE__ */ new Map(), this.mask = null, this.pair = null, this.destroyed = !1, this.linearFilter = !0, this.uploadedFrames = 0, this.lastUploadDurationMs = 0, this.vector = t.encoding.kind === "vector-luma", this.source = Re(t, { cacheSize: 2 }), this.uniforms = this.vector ? Qt : Jt;
2238
+ const r = L(t);
2239
+ this.times = s.animateSnapshot && t.timeline.kind === "snapshot-loop" ? Array.from(
2240
+ {
2241
+ length: Math.max(
2242
+ 1,
2243
+ Math.round(t.media.durationSeconds * t.media.fps)
2244
+ )
2245
+ },
2246
+ (n, o) => r[0] + o * 1e3 / t.media.fps
2247
+ ) : r, this.bounds = t.bounds;
2248
+ }
2249
+ get currentPair() {
2250
+ return this.pair;
2251
+ }
2252
+ /** Fixed catalog color domain of a scalar field. */
2253
+ get domain() {
2254
+ return this.manifest.style.colorDomain;
2255
+ }
2256
+ /** Top of the color ramp and of the particle speed normalization. */
2257
+ get maxSpeed() {
2258
+ const { encoding: e, style: t } = this.manifest;
2259
+ return e.kind === "vector-luma" ? e.valueDomain : t.colorDomain[1];
2260
+ }
2261
+ /** Resolves once the step at `ms` is uploaded. */
2262
+ async prime(e) {
2263
+ const { index: t } = F(this.times, e);
2264
+ await this.request(t);
2265
+ }
2266
+ /** The uploaded texture of the step at `ms`, or null. */
2267
+ texture(e) {
2268
+ return this.textures.get(F(this.times, e).index) ?? null;
2269
+ }
2270
+ /** True once the frames interpolated at `ms` are uploaded. */
2271
+ ready(e) {
2272
+ const { index: t, fraction: s } = F(this.times, e);
2273
+ return this.textures.has(t) && (s === 0 || this.textures.has(t + 1));
2274
+ }
2275
+ /**
2276
+ * Latest wins while scrubbing: drop queued decodes outside the frames at
2277
+ * `ms`, then request those first.
2278
+ */
2279
+ focus(e) {
2280
+ const { index: t } = F(this.times, e), s = Math.min(t + 1, this.times.length - 1);
2281
+ [...this.pending.keys()].some(
2282
+ (n) => n !== t && n !== s
2283
+ ) && (this.source.cancelAll(), this.pending.clear());
2284
+ for (const n of [t, s])
2285
+ this.request(n).catch(() => {
2286
+ });
2287
+ }
2288
+ /**
2289
+ * Bracketing textures and their mix, retaining the last complete pair
2290
+ * while a requested frame decodes.
2291
+ */
2292
+ sample(e, t = !0) {
2293
+ const { index: s, fraction: r } = F(this.times, e), n = Math.min(s + 1, this.times.length - 1);
2294
+ [...this.pending.keys()].some((l) => l < s || l > n + 1) && (this.source.cancelAll(), this.pending.clear());
2295
+ for (const l of [s, n, n + 1])
2296
+ l < this.times.length && this.request(l).catch(() => {
2297
+ });
2298
+ const o = this.textures.get(s), a = this.textures.get(n), c = t ? r : 0;
2299
+ return o && (c === 0 || a) && (this.pair = [o, c === 0 ? o : a, c]), this.evict(s), this.pair;
2300
+ }
2301
+ /** Switch spatial filtering without changing the decoded-step cache. */
2302
+ setFilter(e) {
2303
+ if (this.linearFilter === e)
2304
+ return;
2305
+ this.linearFilter = e;
2306
+ const t = this.gl, s = t.getParameter(
2307
+ t.TEXTURE_BINDING_2D
2308
+ );
2309
+ for (const r of this.textures.values())
2310
+ t.bindTexture(t.TEXTURE_2D, r), t.texParameteri(
2311
+ t.TEXTURE_2D,
2312
+ t.TEXTURE_MIN_FILTER,
2313
+ e ? t.LINEAR : t.NEAREST
2314
+ ), t.texParameteri(
2315
+ t.TEXTURE_2D,
2316
+ t.TEXTURE_MAG_FILTER,
2317
+ e ? t.LINEAR : t.NEAREST
2318
+ );
2319
+ t.bindTexture(t.TEXTURE_2D, s);
2320
+ }
2321
+ get maskTexture() {
2322
+ return this.mask;
2323
+ }
2324
+ get cachedFrames() {
2325
+ return this.textures.size;
2326
+ }
2327
+ bind(e, t, s = 0) {
2328
+ if (!this.sample(t) || !this.pair)
2329
+ return !1;
2330
+ const r = this.uniforms;
2331
+ if (e.texture(r.a, s, this.pair[0]), e.texture(r.b, s + 1, this.pair[1]), e.float(r.mix, this.pair[2]), e.vec4(r.bounds, this.bounds), this.mask && this.manifest.encoding.kind === "scalar-luma") {
2332
+ const { codeRange: n, valueRange: o, transfer: a } = Dt(
2333
+ this.manifest.encoding
2334
+ );
2335
+ e.texture("u_tint_mask", s + 2, this.mask), e.vec2("u_code_range", ...n), e.vec2("u_value_range", ...o), e.float("u_scalar_transfer", a);
2336
+ }
2337
+ return !0;
2338
+ }
2339
+ destroy() {
2340
+ this.destroyed = !0, this.source.cancelAll(), this.source.release();
2341
+ for (const e of this.textures.values())
2342
+ this.gl.deleteTexture(e);
2343
+ this.textures.clear(), this.gl.deleteTexture(this.mask), this.mask = null, this.pair = null;
2344
+ }
2345
+ request(e) {
2346
+ if (this.textures.has(e))
2347
+ return Promise.resolve();
2348
+ const t = this.pending.get(e);
2349
+ if (t)
2350
+ return t;
2351
+ const s = this.source.frame(e).then((r) => {
2352
+ if (!this.destroyed && this.pending.get(e) === s && !this.textures.has(e)) {
2353
+ const n = performance.now();
2354
+ this.textures.set(e, this.uploadPreservingState(r)), this.uploadedFrames++, this.lastUploadDurationMs = performance.now() - n, this.options.onReady?.();
2355
+ }
2356
+ }).catch((r) => {
2357
+ throw !this.destroyed && this.pending.get(e) === s && !(r instanceof Error && r.name === "AbortError") && this.options.onError?.(r), r;
2358
+ }).finally(() => {
2359
+ this.pending.get(e) === s && this.pending.delete(e);
2360
+ });
2361
+ return this.pending.set(e, s), s;
2362
+ }
2363
+ uploadPreservingState(e) {
2364
+ const t = this.gl, s = t.getParameter(
2365
+ t.TEXTURE_BINDING_2D
2366
+ ), r = [
2367
+ t.UNPACK_FLIP_Y_WEBGL,
2368
+ t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,
2369
+ t.UNPACK_COLORSPACE_CONVERSION_WEBGL,
2370
+ t.UNPACK_ALIGNMENT
2371
+ ], n = r.map((o) => t.getParameter(o));
2372
+ try {
2373
+ return this.upload(e);
2374
+ } finally {
2375
+ t.bindTexture(t.TEXTURE_2D, s), r.forEach((o, a) => t.pixelStorei(o, n[a]));
2376
+ }
2377
+ }
2378
+ upload(e) {
2379
+ const t = this.gl, { width: s, height: r } = this.source, n = this.gridTexture();
2380
+ return this.vector ? t.texImage2D(
2381
+ t.TEXTURE_2D,
2382
+ 0,
2383
+ t.RGBA16F,
2384
+ s,
2385
+ r,
2386
+ 0,
2387
+ t.RGBA,
2388
+ t.FLOAT,
2389
+ ei(e)
2390
+ ) : (t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL, !1), t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !1), t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL, t.NONE), t.texImage2D(
2391
+ t.TEXTURE_2D,
2392
+ 0,
2393
+ t.RGBA8,
2394
+ t.RGBA,
2395
+ t.UNSIGNED_BYTE,
2396
+ e
2397
+ ), this.mask ??= this.uploadMask()), t.bindTexture(t.TEXTURE_2D, null), n;
2398
+ }
2399
+ /** The source's mask, loaded with its first frame, as an R8 texture. */
2400
+ uploadMask() {
2401
+ const e = this.source.mask;
2402
+ if (!e)
2403
+ return null;
2404
+ const t = this.gl, s = this.gridTexture();
2405
+ return this.options.nearestMask && (t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MIN_FILTER, t.NEAREST), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MAG_FILTER, t.NEAREST)), t.pixelStorei(t.UNPACK_ALIGNMENT, 1), t.texImage2D(
2406
+ t.TEXTURE_2D,
2407
+ 0,
2408
+ t.R8,
2409
+ this.source.width,
2410
+ this.source.height,
2411
+ 0,
2412
+ t.RED,
2413
+ t.UNSIGNED_BYTE,
2414
+ e
2415
+ ), t.pixelStorei(t.UNPACK_ALIGNMENT, 4), s;
2416
+ }
2417
+ /** A bound, linearly filtered texture over the field grid. */
2418
+ gridTexture() {
2419
+ const e = this.gl, t = e.createTexture();
2420
+ return e.bindTexture(e.TEXTURE_2D, t), e.texParameteri(
2421
+ e.TEXTURE_2D,
2422
+ e.TEXTURE_WRAP_S,
2423
+ this.options.repeatLongitude !== !1 && this.bounds[2] - this.bounds[0] >= 359 ? e.REPEAT : e.CLAMP_TO_EDGE
2424
+ ), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(
2425
+ e.TEXTURE_2D,
2426
+ e.TEXTURE_MIN_FILTER,
2427
+ this.linearFilter ? e.LINEAR : e.NEAREST
2428
+ ), e.texParameteri(
2429
+ e.TEXTURE_2D,
2430
+ e.TEXTURE_MAG_FILTER,
2431
+ this.linearFilter ? e.LINEAR : e.NEAREST
2432
+ ), t;
2433
+ }
2434
+ /** Keep a small window around the playhead. */
2435
+ evict(e) {
2436
+ for (const [t, s] of this.textures) {
2437
+ const r = this.pair && (this.pair[0] === s || this.pair[1] === s);
2438
+ (t < e - 1 || t > e + 3) && !r && (this.gl.deleteTexture(s), this.textures.delete(t));
2439
+ }
2440
+ }
2441
+ }
2442
+ class ii {
2443
+ constructor(e, t) {
2444
+ this.onPlaying = t, this.time = 0, this.endFraction = 0, this.held = !1, this.playingValue = e;
2445
+ }
2446
+ /** Playhead, epoch ms. Assigning it also resets a terminal step's hold. */
2447
+ get ms() {
2448
+ return this.time;
2449
+ }
2450
+ set ms(e) {
2451
+ this.time = e, this.endFraction = 0;
2452
+ }
2453
+ /** Progress through the final sample's held step, 0 elsewhere. */
2454
+ get holdFraction() {
2455
+ return this.endFraction;
2456
+ }
2457
+ get playing() {
2458
+ return this.playingValue;
2459
+ }
2460
+ setPlaying(e) {
2461
+ this.playingValue !== e && (this.playingValue = e, this.onPlaying(e));
2462
+ }
2463
+ /** Playing and not held. */
2464
+ get advancing() {
2465
+ return this.playingValue && !this.held;
2466
+ }
2467
+ /**
2468
+ * Advance in step units, including irregular timelines. Returns true at a
2469
+ * non-looping end. holdLastStep gives the final sample a full step's duration.
2470
+ */
2471
+ advance(e, t, s, r = [t[0], t[t.length - 1]], n = !1, o = !1) {
2472
+ if (!this.advancing || !t.length)
2473
+ return !1;
2474
+ const a = se(t, r[0]), c = se(t, r[1]), l = c + (o ? 1 : 0);
2475
+ let d = Math.max(a, se(t, this.ms) + this.endFraction) + Math.max(0, e) * s;
2476
+ const h = o ? d >= l : d > l;
2477
+ return h && n && l > a ? d = a + (d - a) % (l - a) : d = Math.min(l, d), this.time = Pt(t, Math.min(c, d)), this.endFraction = Math.max(0, d - c), h && !n;
2478
+ }
2479
+ }
2480
+ function W(i) {
2481
+ const e = L(i);
2482
+ return [e[0], e[e.length - 1]];
2483
+ }
2484
+ function re(i, e) {
2485
+ return e ? [Math.max(i[0], e[0]), Math.min(i[1], e[1])] : i;
2486
+ }
2487
+ function H([i, e], t) {
2488
+ return Math.max(i, Math.min(e, t));
2489
+ }
2490
+ class qi {
2491
+ constructor(e, t, s) {
2492
+ this.repaint = t, this.emit = s, this.field = null, this.manifest = null, this.gl = null, this.pendingField = null, this.standby = null, this.awaitingNext = !1, this.timeRange = null, this.lastTick = null, this.lastStepTime = null, this.seekId = 0, this.seeking = !1, this.failed = !1, this.exactTime = 0, this.endEmitted = !1, this.destroyed = !1, this.resumePlayback = !1, this.playOnReady = e.autoplay ?? !0, this.loop = e.loop ?? !0, this.playbackRate = e.playbackRate ?? 1, this.stepsPerSecond = e.stepsPerSecond;
2493
+ const r = typeof e.time == "string" ? Date.parse(e.time) : e.time;
2494
+ this.requestedTime = r != null && Number.isFinite(r) ? r : null, this.requestedTimeRange = e.timeRange, this.clock = new ii(
2495
+ !1,
2496
+ (n) => this.emit("playbackChange", n)
2497
+ );
2498
+ }
2499
+ async load(e, t) {
2500
+ if (this.gl = e, this.manifest = t, this.timeRange = re(
2501
+ W(t),
2502
+ this.requestedTimeRange
2503
+ ), this.timeRange[0] > this.timeRange[1])
2504
+ throw new Error(
2505
+ "GeoVideo time range does not overlap the manifest timeline"
2506
+ );
2507
+ this.pendingField = this.createField(t), await this.prepare(this.pendingField);
2508
+ }
2509
+ sample(e) {
2510
+ if (this.tick(e), !this.field)
2511
+ return null;
2512
+ const t = this.pendingField || this.seeking ? this.field.currentPair : this.field.sample(
2513
+ this.clock.advancing ? this.clock.ms : this.exactTime,
2514
+ this.clock.advancing && !this.awaitingNext
2515
+ );
2516
+ return this.handoff(t) ?? t;
2517
+ }
2518
+ /**
2519
+ * Through the final step of a chunk followed by a decoded one, the last
2520
+ * frame blends into the next chunk's first, as steps do within a chunk:
2521
+ * the chunk swap then lands on the frame already shown.
2522
+ */
2523
+ handoff(e) {
2524
+ const t = this.clock.holdFraction, s = this.pendingField ?? this.standby?.field, r = this.pendingField ? this.requestedTime : this.standby?.time;
2525
+ if (!e || t <= 0 || !s || r == null)
2526
+ return null;
2527
+ const n = s.texture(r);
2528
+ return n ? [e[0], n, Math.min(1, t)] : null;
2529
+ }
2530
+ get time() {
2531
+ return this.clock.ms;
2532
+ }
2533
+ get preloadedMediaUrl() {
2534
+ return this.standby?.field.manifest.media.url;
2535
+ }
2536
+ setStepsPerSecond(e) {
2537
+ if (!Number.isFinite(e) || e <= 0)
2538
+ throw new Error("GeoVideo steps per second must be positive");
2539
+ this.stepsPerSecond = e;
2540
+ }
2541
+ suspend() {
2542
+ this.resumePlayback = this.isPlaying(), this.pause();
2543
+ }
2544
+ resume() {
2545
+ this.resumePlayback && this.play(), this.resumePlayback = !1;
2546
+ }
2547
+ destroy() {
2548
+ this.destroyed = !0, this.seekId++, this.pendingField?.destroy(), this.pendingField = null, this.discardStandby(), this.field?.destroy(), this.field = null, this.gl = null;
2549
+ }
2550
+ tick(e) {
2551
+ if (!this.field || this.pendingField || this.seeking || this.awaitingNext || !this.clock.advancing) {
2552
+ this.lastTick = null;
2553
+ return;
2554
+ }
2555
+ const t = this.lastTick === null ? 0 : (e - this.lastTick) / 1e3;
2556
+ this.lastTick = e;
2557
+ const s = this.clock.advance(
2558
+ t,
2559
+ this.field.times,
2560
+ this.stepsPerSecond ?? this.playbackRate * be(this.field.manifest),
2561
+ this.playbackRange(this.field),
2562
+ this.loop,
2563
+ !0
2564
+ ), { index: r } = F(this.field.times, this.clock.ms), n = this.field.manifest.timeline.kind === "snapshot-loop" ? this.field.times[0] : H(this.timeRange, this.field.times[r]);
2565
+ n !== this.lastStepTime && (this.lastStepTime = n, this.emit("timeChange", n)), s ? this.reachEnd() : this.repaint();
2566
+ }
2567
+ setTime(e) {
2568
+ const t = typeof e == "number" ? e : Date.parse(e);
2569
+ if (!Number.isFinite(t))
2570
+ return;
2571
+ this.requestedTime = t, this.awaitingNext = !1;
2572
+ const s = this.pendingField ?? this.field;
2573
+ s && this.prepare(s).catch((r) => this.reportError(r));
2574
+ }
2575
+ /** Load the requested step first; stale seeks and swaps cannot replace it. */
2576
+ async prepare(e, t) {
2577
+ this.failed = !1;
2578
+ const s = ++this.seekId, r = this.timeRange ?? W(e.manifest), n = t ?? H(r, this.requestedTime ?? r[0]), o = F(e.times, n), a = Math.min(
2579
+ e.times.length - 1,
2580
+ o.index + (o.fraction > 0.5 ? 1 : 0)
2581
+ ), c = e.times[a];
2582
+ this.seeking = !0, this.lastTick = null, e.focus(c);
2583
+ try {
2584
+ await e.prime(c);
2585
+ } catch (d) {
2586
+ if (s !== this.seekId)
2587
+ return;
2588
+ throw d;
2589
+ }
2590
+ if (s !== this.seekId || this.destroyed)
2591
+ return;
2592
+ const l = this.pendingField === e;
2593
+ if (l && (this.field?.destroy(), this.field = e, this.pendingField = null, this.lastStepTime = null), this.exactTime = c, this.clock.ms = H(this.playbackRange(e), c), e.sample(c, !1), this.seeking = !1, this.endEmitted = !1, this.repaint(), l) {
2594
+ const d = e.manifest;
2595
+ if (this.emit("loaded", {
2596
+ min: d.style.colorDomain[0],
2597
+ max: d.style.colorDomain[1],
2598
+ unit: d.style.unit ?? "",
2599
+ time: new Date(this.clock.ms).toISOString()
2600
+ }), this.emit("status", { phase: "ready", time: this.clock.ms }), this.playOnReady) {
2601
+ this.playOnReady = !1;
2602
+ const h = this.clock.playing;
2603
+ await this.play(), h && this.emit("playbackChange", !0);
2604
+ }
2605
+ }
2606
+ }
2607
+ /** Keep the outgoing pair until the incoming chunk's requested step is ready. */
2608
+ replaceManifest(e, t = {}) {
2609
+ const s = this.replacementTimeRange(e, t);
2610
+ if (!s || !this.gl)
2611
+ return !1;
2612
+ this.playOnReady ||= this.isPlaying(), this.pendingField?.destroy();
2613
+ const r = this.standby;
2614
+ return this.standby = null, r && r.field.manifest.media.url !== e.media.url && r.field.destroy(), this.pendingField = r?.field.manifest.media.url === e.media.url ? r.field : this.createField(e), this.awaitingNext = !1, this.manifest = e, this.requestedTimeRange = t.timeRange, this.timeRange = s, this.requestedTime = t.time ?? s[0], this.loop = t.loop ?? this.loop, this.playbackRate = t.playbackRate ?? this.playbackRate, this.stepsPerSecond = t.stepsPerSecond ?? this.stepsPerSecond, this.lastTick = null, this.prepare(this.pendingField).catch(
2615
+ (n) => this.reportError(n)
2616
+ ), !0;
2617
+ }
2618
+ /** Decode the next chunk ahead of its swap, including its static mask. */
2619
+ preloadManifest(e, t = {}) {
2620
+ const s = this.replacementTimeRange(e, t);
2621
+ if (!s || !this.gl || e.media.url === this.manifest?.media.url)
2622
+ return !1;
2623
+ const r = H(s, t.time ?? s[0]);
2624
+ this.standby?.field.manifest.media.url !== e.media.url && (this.discardStandby(), this.standby = { field: this.createField(e), time: r });
2625
+ const n = this.standby;
2626
+ return n.time = r, n.field.focus(r), n.field.prime(r).catch(() => {
2627
+ this.standby === n && this.discardStandby();
2628
+ }), !0;
2629
+ }
2630
+ discardStandby() {
2631
+ this.standby?.field.destroy(), this.standby = null;
2632
+ }
2633
+ /** Clamped time range of a compatible replacement, else null. */
2634
+ replacementTimeRange(e, t) {
2635
+ const s = this.manifest;
2636
+ if (!s || e.encoding.kind !== s.encoding.kind || e.media.width !== s.media.width || e.media.height !== s.media.height || e.mask.width !== s.mask.width || e.mask.height !== s.mask.height)
2637
+ return null;
2638
+ const r = re(
2639
+ W(e),
2640
+ t.timeRange
2641
+ );
2642
+ return r[0] <= r[1] ? r : null;
2643
+ }
2644
+ async play() {
2645
+ if (!this.field || this.pendingField || this.awaitingNext) {
2646
+ this.playOnReady = !0, this.clock.setPlaying(!0);
2647
+ return;
2648
+ }
2649
+ this.failed && this.prepare(this.field, this.clock.ms).catch(
2650
+ (s) => this.reportError(s)
2651
+ );
2652
+ const e = this.endEmitted;
2653
+ this.endEmitted = !1;
2654
+ const t = this.playbackRange(this.field);
2655
+ e && this.setTime(t[0]), this.lastTick = null, this.clock.setPlaying(!0), this.repaint();
2656
+ }
2657
+ pause() {
2658
+ const e = this.playOnReady && !this.clock.playing;
2659
+ if (this.playOnReady = !1, this.awaitingNext = !1, this.clock.setPlaying(!1), this.field && !this.pendingField && !this.seeking && !this.endEmitted) {
2660
+ const { index: t } = F(this.field.times, this.clock.ms);
2661
+ this.prepare(this.field, this.field.times[t]).catch(
2662
+ (s) => this.reportError(s)
2663
+ );
2664
+ }
2665
+ e && this.emit("playbackChange", !1), this.lastTick = null, this.repaint();
2666
+ }
2667
+ isPlaying() {
2668
+ return this.clock.playing || this.playOnReady;
2669
+ }
2670
+ reachEnd() {
2671
+ this.endEmitted || (this.endEmitted = !0, this.exactTime = this.clock.ms, this.lastTick = null, this.standby ? (this.awaitingNext = !0, this.playOnReady = !0) : this.clock.setPlaying(!1), this.emit("playbackEnd"));
2672
+ }
2673
+ setLoop(e) {
2674
+ this.loop = e;
2675
+ }
2676
+ setPlaybackRate(e) {
2677
+ if (!Number.isFinite(e) || e <= 0)
2678
+ throw new Error("GeoVideo playback rate must be positive");
2679
+ this.playbackRate = e, this.stepsPerSecond = void 0;
2680
+ }
2681
+ setTimeRange(e) {
2682
+ if (!Number.isFinite(e[0]) || !Number.isFinite(e[1]) || e[0] > e[1])
2683
+ throw new Error("Invalid GeoVideo time range");
2684
+ const t = re(
2685
+ this.manifest ? W(this.manifest) : e,
2686
+ e
2687
+ );
2688
+ if (t[0] > t[1])
2689
+ throw new Error(
2690
+ "GeoVideo time range does not overlap the manifest timeline"
2691
+ );
2692
+ this.requestedTimeRange = e, this.timeRange = t, this.setTime(
2693
+ this.pendingField ? this.requestedTime ?? t[0] : this.clock.ms
2694
+ );
2695
+ }
2696
+ playbackRange(e) {
2697
+ return e.manifest.timeline.kind === "snapshot-loop" ? [e.times[0], e.times[e.times.length - 1]] : this.timeRange ?? [
2698
+ e.times[0],
2699
+ e.times[e.times.length - 1]
2700
+ ];
2701
+ }
2702
+ createField(e) {
2703
+ const t = new ti(this.gl, e, {
2704
+ nearestMask: !0,
2705
+ animateSnapshot: !0,
2706
+ onError: (s) => {
2707
+ this.field === t && !this.seeking && this.reportError(s);
2708
+ },
2709
+ onReady: () => this.repaint()
2710
+ });
2711
+ return t;
2712
+ }
2713
+ reportError(e) {
2714
+ const t = e instanceof Error ? e : new Error(String(e));
2715
+ t.name === "AbortError" || this.destroyed || (this.playOnReady = !1, this.awaitingNext = !1, this.failed = !0, this.seeking = !0, this.clock.setPlaying(!1), this.emit("status", { phase: "error", error: t }), this.emit("error", t));
2716
+ }
2717
+ }
2718
+ function K(i) {
2719
+ const { start: e, end: t } = i.temporal ?? {};
2720
+ return {
2721
+ source: i,
2722
+ start: Date.parse(e ?? ""),
2723
+ end: Date.parse(t ?? e ?? "")
2724
+ };
2725
+ }
2726
+ function Wi(i, e, t = {}) {
2727
+ const s = i.filter((n) => n.id === e.id && n.temporal?.start != null).map(K), r = zt(
2728
+ s,
2729
+ Date.parse(e.temporal?.end ?? ""),
2730
+ t
2731
+ );
2732
+ return r ? { source: r.chunk.source, time: r.time } : null;
2733
+ }
2734
+ function Hi(i, e) {
2735
+ return qt(K(i), e.map(K))?.source ?? null;
2736
+ }
2737
+ function Yi(i, e = {}) {
2738
+ const t = e.start ?? -1 / 0, s = e.end ?? 1 / 0, r = i.map(K).filter((a) => a.end >= t && a.start <= s).sort((a, c) => a.start - c.start);
2739
+ if (r.length === 0)
2740
+ return;
2741
+ if (e.time == null)
2742
+ return r[r.length - 1].source;
2743
+ const n = Math.min(s, Math.max(t, e.time)), o = (a) => n < a.start ? a.start - n : Math.max(0, n - a.end);
2744
+ return r.reduce(
2745
+ (a, c) => o(c) <= o(a) ? c : a
2746
+ ).source;
2747
+ }
2748
+ const si = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
2749
+ function ri(i) {
2750
+ return i instanceof Date ? i.getTime() : typeof i == "number" ? i : new Date(i).getTime();
2751
+ }
2752
+ function Te(i, e) {
2753
+ const t = ri(i);
2754
+ if (!Number.isFinite(t))
2755
+ throw new Error(`Invalid ${e}`);
2756
+ return t;
2757
+ }
2758
+ function ve(i, e) {
2759
+ const t = e.match(si);
2760
+ if (!t)
2761
+ throw new Error(`Invalid trailing time duration: ${e}`);
2762
+ const s = t.slice(1).map((y) => Number(y ?? 0));
2763
+ if (!s.some((y) => y > 0))
2764
+ throw new Error("Trailing time duration must be positive");
2765
+ const [r, n, o, a, c, l, d] = s, h = new Date(i), f = h.getUTCFullYear() * 12 + h.getUTCMonth() - r * 12 - n, u = Math.floor(f / 12), m = (f % 12 + 12) % 12, T = new Date(Date.UTC(u, m + 1, 0)).getUTCDate();
2766
+ return Date.UTC(
2767
+ u,
2768
+ m,
2769
+ Math.min(h.getUTCDate(), T),
2770
+ h.getUTCHours(),
2771
+ h.getUTCMinutes(),
2772
+ h.getUTCSeconds(),
2773
+ h.getUTCMilliseconds()
2774
+ ) - (((o * 7 + a) * 24 + c) * 60 + l) * 6e4 - d * 1e3;
2775
+ }
2776
+ function ji(i, [e, t]) {
2777
+ let s = e, r = t;
2778
+ if (typeof i.trailing == "string" ? s = ve(t, i.trailing) : (i.start != null && (s = Te(i.start, "time range start")), i.end != null && (r = Te(i.end, "time range end"))), s > r)
2779
+ throw new Error("Time range start must not follow its end");
2780
+ return [Math.max(e, s), Math.min(t, r)];
2781
+ }
2782
+ const ni = (i) => typeof i == "object" && i !== null && !Array.isArray(i);
2783
+ function Ki(i, e) {
2784
+ if (!ni(i))
2785
+ throw new Error(`${e} must be an object`);
2786
+ for (const n of Object.keys(i))
2787
+ if (n !== "start" && n !== "end" && n !== "trailing")
2788
+ throw new Error(`${e}.${n} is not a time range key`);
2789
+ if (i.trailing !== void 0) {
2790
+ if (i.start !== void 0 || i.end !== void 0)
2791
+ throw new Error(`${e}.trailing excludes start and end`);
2792
+ if (typeof i.trailing != "string")
2793
+ throw new Error(`${e}.trailing must be an ISO 8601 duration`);
2794
+ return ve(0, i.trailing), { trailing: i.trailing };
2795
+ }
2796
+ const t = (n) => {
2797
+ const o = i[n];
2798
+ if (o !== void 0) {
2799
+ if (typeof o != "string" || !Number.isFinite(Date.parse(o)))
2800
+ throw new Error(`${e}.${n} is not a date`);
2801
+ return o;
2802
+ }
2803
+ }, s = t("start"), r = t("end");
2804
+ if (s !== void 0 && r !== void 0 && Date.parse(s) > Date.parse(r))
2805
+ throw new Error(`${e}.start must not follow its end`);
2806
+ return {
2807
+ ...s !== void 0 && { start: s },
2808
+ ...r !== void 0 && { end: r }
2809
+ };
2810
+ }
2811
+ function Zi(i, e) {
2812
+ return !!i && !!e && i.name === e.name && i.units === e.units && i.positive === e.positive && i.value === e.value;
2813
+ }
2814
+ function Y(i) {
2815
+ const e = i;
2816
+ return !!e && typeof e.name == "string" && typeof e.units == "string" && typeof e.positive == "string" && Number.isFinite(e.value);
2817
+ }
2818
+ function ai(i) {
2819
+ const e = i.depths;
2820
+ if (e === void 0)
2821
+ return i.surface === void 0 || Y(i.surface);
2822
+ const t = i.surface ?? e?.[0];
2823
+ if (!Array.isArray(e) || !Y(t))
2824
+ return e?.length === 0;
2825
+ const s = new Set(i.surface ? [t.value] : []);
2826
+ return e.every((r) => {
2827
+ const n = Y(r) && typeof r.indexUrl == "string" && r.name === t.name && r.units === t.units && r.positive === t.positive && !s.has(r.value);
2828
+ return s.add(r.value), n;
2829
+ });
2830
+ }
2831
+ function Qi(i) {
2832
+ return i.type === "geovideo" && typeof i.indexUrl == "string";
2833
+ }
2834
+ function Ji(i, e) {
2835
+ return i.id === e.id && (i.type !== "geovideo" || e.type !== "geovideo" || i.manifestUrl === e.manifestUrl);
2836
+ }
2837
+ function ne(i) {
2838
+ return typeof i == "string" && Number.isFinite(Date.parse(i));
2839
+ }
2840
+ function oi(i) {
2841
+ const e = i.times;
2842
+ if (!Array.isArray(e) || e.length !== i.samples || e[0] !== i.start || e[e.length - 1] !== i.end)
2843
+ return !1;
2844
+ let t = -1 / 0;
2845
+ for (const s of e) {
2846
+ const r = ne(s) ? Date.parse(s) : NaN;
2847
+ if (!(r > t))
2848
+ return !1;
2849
+ t = r;
2850
+ }
2851
+ return !0;
2852
+ }
2853
+ function ci(i) {
2854
+ const e = i;
2855
+ if (!e || e.schemaVersion !== 1 || e.type !== "geovideo-index" || !Array.isArray(e.chunks))
2856
+ throw new Error("Unsupported GeoVideo index");
2857
+ if (!ai(e) || e.vertical !== void 0 && !Y(e.vertical))
2858
+ throw new Error("Invalid GeoVideo index levels");
2859
+ for (const t of e.chunks)
2860
+ if (!ne(t?.start) || !ne(t.end) || Date.parse(t.end) < Date.parse(t.start) || typeof t.manifestUrl != "string" || t.times !== void 0 && !oi(t))
2861
+ throw new Error("Invalid GeoVideo index chunk");
2862
+ return e;
2863
+ }
2864
+ async function es(i, e) {
2865
+ const t = await fetch(i, { signal: e });
2866
+ if (!t.ok)
2867
+ throw new Error(
2868
+ `GeoVideo index request failed (${t.status}): ${i}`
2869
+ );
2870
+ return ci(await t.json());
2871
+ }
2872
+ function ke(i) {
2873
+ return typeof document < "u" ? new URL(i, document.baseURI).href : i;
2874
+ }
2875
+ function li(i, e) {
2876
+ const t = ke(e);
2877
+ return i.chunks.map((s) => ({
2878
+ key: s.key,
2879
+ manifestUrl: new URL(s.manifestUrl, t).href,
2880
+ start: Date.parse(s.start),
2881
+ end: Date.parse(s.end),
2882
+ samples: s.samples,
2883
+ ...s.times ? { times: s.times.map(Date.parse) } : {},
2884
+ ...s.provisional ? { provisional: !0 } : {}
2885
+ }));
2886
+ }
2887
+ function di(i, e, t) {
2888
+ if (e.sourceId !== i.id || e.catalogEntryId !== t.id)
2889
+ throw new Error(
2890
+ `GeoVideo index identity does not match catalog entry/source: ${i.id}`
2891
+ );
2892
+ }
2893
+ function ts(i, e, t) {
2894
+ di(i, e, t);
2895
+ const s = li(e, i.indexUrl);
2896
+ return e.chunks.map(
2897
+ (r, n) => ({
2898
+ id: i.id,
2899
+ type: "geovideo",
2900
+ title: i.title,
2901
+ provenance: i.provenance,
2902
+ temporal: {
2903
+ mode: "fixed",
2904
+ cadence: i.temporal?.cadence,
2905
+ start: r.start,
2906
+ end: r.end
2907
+ },
2908
+ manifestUrl: s[n].manifestUrl
2909
+ })
2910
+ );
2911
+ }
2912
+ function is(i, e) {
2913
+ return new URL(i.indexUrl, ke(e)).href;
2914
+ }
2915
+ export {
2916
+ _i as $,
2917
+ Dt as A,
2918
+ L as B,
2919
+ Ni as C,
2920
+ fi as D,
2921
+ Qi as E,
2922
+ es as F,
2923
+ Di as G,
2924
+ Mt as H,
2925
+ Wi as I,
2926
+ zt as J,
2927
+ Hi as K,
2928
+ qt as L,
2929
+ Ki as M,
2930
+ rt as N,
2931
+ Pt as O,
2932
+ ve as P,
2933
+ F as Q,
2934
+ Ci as R,
2935
+ ji as S,
2936
+ Fi as T,
2937
+ se as U,
2938
+ Ii as V,
2939
+ ci as W,
2940
+ ge as X,
2941
+ Bi as Y,
2942
+ Oi as Z,
2943
+ ei as _,
2944
+ Gi as a,
2945
+ ot as a0,
2946
+ Ei as a1,
2947
+ bi as a2,
2948
+ Ti as a3,
2949
+ wi as a4,
2950
+ pi as a5,
2951
+ yi as a6,
2952
+ ki as a7,
2953
+ Ai as a8,
2954
+ gi as a9,
2955
+ Ri as aa,
2956
+ vi as ab,
2957
+ St as ac,
2958
+ Te as ad,
2959
+ Zi as ae,
2960
+ Ji as af,
2961
+ $i as ag,
2962
+ be as ah,
2963
+ Yi as ai,
2964
+ is as aj,
2965
+ Xi as ak,
2966
+ Pi as b,
2967
+ Li as c,
2968
+ zi as d,
2969
+ ii as e,
2970
+ Ot as f,
2971
+ ti as g,
2972
+ _e as h,
2973
+ qi as i,
2974
+ It as j,
2975
+ Xt as k,
2976
+ Ui as l,
2977
+ Qe as m,
2978
+ di as n,
2979
+ Vi as o,
2980
+ _t as p,
2981
+ xi as q,
2982
+ Re as r,
2983
+ mi as s,
2984
+ le as t,
2985
+ ft as u,
2986
+ Si as v,
2987
+ Mi as w,
2988
+ ts as x,
2989
+ Wt as y,
2990
+ li as z
2991
+ };