@vectoriox/iox-ui 5.76.0 → 5.76.1

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.
@@ -140,6 +140,30 @@ function nearestLoadedFrame(loaded, index) {
140
140
  }
141
141
  return -1;
142
142
  }
143
+ /**
144
+ * How much unpacked picture one player holds at once. A browser keeps few of 300 unpacked pictures (a wide set is 1.7 GB
145
+ * unpacked) and unpacked again on the page's own thread, at the moment of drawing, 22 ms a 1600×900 picture: longer than a
146
+ * whole frame, so the film and the page beside it skipped a beat for every new picture (Doron's recording, 2026-11-04).
147
+ */
148
+ const FRAMES_UNPACKED_BYTES = 96 * 1024 * 1024;
149
+ const MIN_UNPACKED = 6;
150
+ const MAX_UNPACKED = 24;
151
+ /** How many pictures of `width`×`height` a player holds unpacked. */
152
+ function unpackedFrameCount(width, height) {
153
+ return Math.min(MAX_UNPACKED, Math.max(MIN_UNPACKED, Math.floor(FRAMES_UNPACKED_BYTES / (width * height * 4))));
154
+ }
155
+ /** The `size` pictures to hold unpacked around `position`, nearest first, each side in turn starting ahead. */
156
+ function framesToHold(position, count, size) {
157
+ const from = Math.min(count - 1, Math.max(0, Math.floor(position)));
158
+ const held = [from];
159
+ for (let distance = 1; held.length < Math.min(size, count); distance++) {
160
+ if (from + distance < count)
161
+ held.push(from + distance);
162
+ if (from - distance >= 0 && held.length < size)
163
+ held.push(from - distance);
164
+ }
165
+ return held;
166
+ }
143
167
  /** The longest side of a wide picture and of a phone picture. A phone's is not its width: a landscape video covers a
144
168
  * tall stage by its height, so a picture sized to the phone's width would be enlarged five times. */
145
169
  const WIDE_LONG_SIDE = 1600;
@@ -183,6 +207,7 @@ var FramesClass;
183
207
  FramesClass["Canvas"] = "iox-video__frames";
184
208
  })(FramesClass || (FramesClass = {}));
185
209
  const LOAD_CONCURRENCY = 6;
210
+ const UNPACK_CONCURRENCY = 4;
186
211
  const NEAR_MARGIN = '100% 0px';
187
212
  /** Under these the visitor keeps the poster: nobody on a metered 2G connection asked to download a film. */
188
213
  const SLOW_CONNECTIONS = new Set(['slow-2g', '2g']);
@@ -190,6 +215,11 @@ const SLOW_CONNECTIONS = new Set(['slow-2g', '2g']);
190
215
  * The player: draws the picture nearest what the scroll asked for on a canvas laid over the poster, and nothing until a
191
216
  * first picture has arrived, so the poster is what a visitor sees until then, and for good if the pictures never come.
192
217
  * Browser only. It writes and never reads, so the driver can call it in its write phase.
218
+ *
219
+ * Each picture is downloaded as a file and unpacked off the page's thread (`createImageBitmap` of the file), a window of
220
+ * them around where the film stands, so drawing one never waits for it. A browser that cannot (no `fetch` or
221
+ * `createImageBitmap`, or storage that refuses the download) plays from `<img>` pictures, as before: it works, and pays the
222
+ * unpacking on the page's thread.
193
223
  */
194
224
  class FramePlayer {
195
225
  constructor(el, sequence, options = {}) {
@@ -204,13 +234,21 @@ class FramePlayer {
204
234
  this.loading = 0;
205
235
  this.started = false;
206
236
  this.destroyed = false;
237
+ this.held = new Set();
238
+ this.unpacked = new Map();
239
+ this.unpacking = new Set();
207
240
  this.pending = new Set();
208
241
  this.host = options.host ?? window;
209
242
  const { set, info } = frameSetFor(sequence, !!options.phone);
210
243
  this.set = set;
211
244
  this.info = info;
212
- this.images = new Array(info.count).fill(null);
245
+ this.ready = new Array(info.count).fill(null);
246
+ this.files = new Array(info.count).fill(null);
213
247
  this.order = frameLoadOrder(info.count);
248
+ this.holdCount = unpackedFrameCount(info.width, info.height);
249
+ this.fromFiles = typeof this.host.fetch === 'function' && typeof this.host.createImageBitmap === 'function';
250
+ const Controller = this.host.AbortController;
251
+ this.downloads = this.fromFiles && Controller ? new Controller() : null;
214
252
  if (!this.allowed())
215
253
  return;
216
254
  const Observer = this.host.IntersectionObserver;
@@ -232,6 +270,7 @@ class FramePlayer {
232
270
  if (played === this.played)
233
271
  return;
234
272
  this.played = played;
273
+ this.hold();
235
274
  this.draw();
236
275
  }
237
276
  /** Whether a re-render took the canvas away with the markup it sat in. */
@@ -243,12 +282,16 @@ class FramePlayer {
243
282
  this.el.removeAttribute(FRAMES_SHOWING_ATTRIBUTE);
244
283
  this.observer?.disconnect();
245
284
  this.observer = null;
285
+ this.downloads?.abort();
246
286
  for (const image of this.pending) {
247
287
  image.onload = null;
248
288
  image.onerror = null;
249
289
  image.src = '';
250
290
  }
251
291
  this.pending.clear();
292
+ for (const bitmap of this.unpacked.values())
293
+ bitmap.close();
294
+ this.unpacked.clear();
252
295
  this.canvas?.remove();
253
296
  this.canvas = null;
254
297
  this.context = null;
@@ -267,26 +310,55 @@ class FramePlayer {
267
310
  }
268
311
  pump() {
269
312
  while (!this.destroyed && this.loading < LOAD_CONCURRENCY && this.nextToLoad < this.order.length) {
270
- this.load(this.order[this.nextToLoad++]);
313
+ const index = this.order[this.nextToLoad++];
314
+ if (this.fromFiles)
315
+ this.download(index);
316
+ else
317
+ this.loadImage(index);
271
318
  }
272
319
  }
273
- load(index) {
320
+ loaded(arrived) {
321
+ this.loading--;
322
+ if (this.destroyed)
323
+ return;
324
+ if (arrived)
325
+ this.draw();
326
+ this.pump();
327
+ }
328
+ download(index) {
329
+ this.loading++;
330
+ const url = frameUrl(this.sequence, this.set, index);
331
+ this.host.fetch(url, this.downloads ? { signal: this.downloads.signal } : undefined)
332
+ .then(response => (response.ok ? response.blob() : null))
333
+ .then(file => {
334
+ if (this.destroyed)
335
+ return;
336
+ // A picture that failed is a gap: its neighbours stand in.
337
+ this.files[index] = file;
338
+ this.loading--;
339
+ this.hold();
340
+ this.pump();
341
+ }, () => {
342
+ if (this.destroyed)
343
+ return;
344
+ // Storage that refuses a download from the page's address still serves an <img>: play from those.
345
+ this.fromFiles = false;
346
+ this.loading--;
347
+ this.loadImage(index);
348
+ });
349
+ }
350
+ loadImage(index) {
274
351
  const image = this.host.document.createElement('img');
275
352
  image.decoding = 'async';
276
353
  this.loading++;
277
354
  this.pending.add(image);
278
355
  const done = (arrived) => {
279
356
  this.pending.delete(image);
280
- this.loading--;
281
- if (this.destroyed)
282
- return;
283
- if (arrived) {
284
- this.images[index] = image;
285
- this.draw();
286
- }
287
- this.pump();
357
+ if (!this.destroyed && arrived)
358
+ this.ready[index] = image;
359
+ this.loaded(arrived);
288
360
  };
289
- // Decoded before it counts, or the first draw of each picture decodes on the driver's frame and the scroll stutters.
361
+ // Decoded before it counts, or its first draw decodes on the driver's frame.
290
362
  image.onload = () => {
291
363
  const decoded = image.decode?.();
292
364
  if (decoded)
@@ -294,19 +366,58 @@ class FramePlayer {
294
366
  else
295
367
  done(true);
296
368
  };
297
- // A picture that failed is a gap: its neighbours stand in.
298
369
  image.onerror = () => done(false);
299
370
  image.src = frameUrl(this.sequence, this.set, index);
300
371
  }
372
+ /** Unpack the pictures around where the film stands, nearest first, and let go of the ones it has left. */
373
+ hold() {
374
+ if (this.destroyed)
375
+ return;
376
+ const wanted = framesToHold(framePosition(this.played ?? 0, this.info.count), this.info.count, this.holdCount);
377
+ this.held = new Set(wanted);
378
+ for (const [index, bitmap] of this.unpacked) {
379
+ if (this.held.has(index))
380
+ continue;
381
+ bitmap.close();
382
+ this.unpacked.delete(index);
383
+ this.ready[index] = null;
384
+ }
385
+ for (const index of wanted) {
386
+ if (this.unpacking.size >= UNPACK_CONCURRENCY)
387
+ return;
388
+ if (this.files[index] && !this.ready[index] && !this.unpacking.has(index))
389
+ this.unpack(index);
390
+ }
391
+ }
392
+ unpack(index) {
393
+ this.unpacking.add(index);
394
+ this.host.createImageBitmap(this.files[index]).then(bitmap => {
395
+ this.unpacking.delete(index);
396
+ if (this.destroyed || !this.held.has(index)) {
397
+ bitmap.close();
398
+ }
399
+ else {
400
+ this.unpacked.set(index, bitmap);
401
+ this.ready[index] = bitmap;
402
+ this.draw();
403
+ }
404
+ this.hold();
405
+ }, () => {
406
+ // A file that will not unpack is a gap, like one that never came.
407
+ this.unpacking.delete(index);
408
+ this.files[index] = null;
409
+ this.hold();
410
+ });
411
+ }
301
412
  draw() {
302
413
  if (this.destroyed || this.played === null)
303
414
  return;
304
- const blend = frameBlendAt(this.images, framePosition(this.played, this.info.count));
415
+ const blend = frameBlendAt(this.ready, framePosition(this.played, this.info.count));
305
416
  const last = this.drawn;
306
417
  if (!blend || (last && last.from === blend.from && last.to === blend.to && last.mix === blend.mix))
307
418
  return;
308
- const image = this.images[blend.from];
309
- if (!this.ensureCanvas(image))
419
+ const picture = this.ready[blend.from];
420
+ if (!this.ensureCanvas(picture))
310
421
  return;
311
422
  const context = this.context;
312
423
  const { width, height } = this.canvas;
@@ -317,28 +428,29 @@ class FramePlayer {
317
428
  // a time instead of moving.
318
429
  context.globalCompositeOperation = 'lighter';
319
430
  context.globalAlpha = 1 - blend.mix;
320
- context.drawImage(image, 0, 0, width, height);
431
+ context.drawImage(picture, 0, 0, width, height);
321
432
  context.globalAlpha = blend.mix;
322
- context.drawImage(this.images[blend.to], 0, 0, width, height);
433
+ context.drawImage(this.ready[blend.to], 0, 0, width, height);
323
434
  context.globalAlpha = 1;
324
435
  context.globalCompositeOperation = 'source-over';
325
436
  }
326
437
  else {
327
- context.drawImage(image, 0, 0, width, height);
438
+ context.drawImage(picture, 0, 0, width, height);
328
439
  }
329
440
  // Over a transparent film the poster would show through: a second, stiller subject behind the moving one.
330
441
  if (!this.drawn)
331
442
  this.el.setAttribute(FRAMES_SHOWING_ATTRIBUTE, '');
332
443
  this.drawn = blend;
333
444
  }
334
- ensureCanvas(image) {
445
+ ensureCanvas(picture) {
335
446
  if (this.canvas)
336
447
  return !!this.context;
448
+ const size = picture;
337
449
  const canvas = this.host.document.createElement('canvas');
338
450
  canvas.className = FramesClass.Canvas;
339
451
  canvas.setAttribute('aria-hidden', 'true');
340
- canvas.width = image.naturalWidth || this.info.width;
341
- canvas.height = image.naturalHeight || this.info.height;
452
+ canvas.width = size.naturalWidth || Number(size.width) || this.info.width;
453
+ canvas.height = size.naturalHeight || Number(size.height) || this.info.height;
342
454
  this.context = canvas.getContext('2d');
343
455
  if (!this.context)
344
456
  return false;
@@ -968,5 +1080,5 @@ function videoRuntimeOf(el) {
968
1080
  * Generated bundle index. Do not edit.
969
1081
  */
970
1082
 
971
- export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT, FRAMES_PHONE_MAX_WIDTH, FRAMES_SHOWING_ATTRIBUTE, FRAME_BLEND_STEPS, FRAME_SEQUENCE_ID, FrameExtension, FramePlayer, FrameSet, FramesClass, MAX_FRAMES, MAX_FRAME_BYTES, PHONE_LONG_SIDE, VIDEO_EMBED_ORIGINS, VIDEO_NODE_TYPE, VIDEO_PROVIDER_COMPANY, VIDEO_PROVIDER_LABEL, VIDEO_WORDS, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRuntime, VideoSource, VideoTrait, WIDE_LONG_SIDE, attachVideoAt, attachVideos, documentConsentTransport, fittedFrameSize, frameBlendAt, frameFileName, frameIndexAt, frameLoadOrder, framePosition, frameSetFor, frameSummary, frameUrl, isThirdPartyPoster, nearestLoadedFrame, normalizeFrameSequence, parseVideoUrl, phoneFrameCount, phoneFrameSrcset, planVideo, readConsentRecord, sampledFrameIndexes, serializeVideoAttributes, sortFrameFiles, videoConsentCategory, videoEmbedUrl, videoFrameCount, videoInnerHtml, videoPlayLabel, videoPosterFileName, videoProp, videoRefOf, videoRootAttributes, videoRuntimeOf, videoSourceOf, videoThumbnailRequest, videoWords };
1083
+ export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT, FRAMES_PHONE_MAX_WIDTH, FRAMES_SHOWING_ATTRIBUTE, FRAMES_UNPACKED_BYTES, FRAME_BLEND_STEPS, FRAME_SEQUENCE_ID, FrameExtension, FramePlayer, FrameSet, FramesClass, MAX_FRAMES, MAX_FRAME_BYTES, PHONE_LONG_SIDE, VIDEO_EMBED_ORIGINS, VIDEO_NODE_TYPE, VIDEO_PROVIDER_COMPANY, VIDEO_PROVIDER_LABEL, VIDEO_WORDS, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRuntime, VideoSource, VideoTrait, WIDE_LONG_SIDE, attachVideoAt, attachVideos, documentConsentTransport, fittedFrameSize, frameBlendAt, frameFileName, frameIndexAt, frameLoadOrder, framePosition, frameSetFor, frameSummary, frameUrl, framesToHold, isThirdPartyPoster, nearestLoadedFrame, normalizeFrameSequence, parseVideoUrl, phoneFrameCount, phoneFrameSrcset, planVideo, readConsentRecord, sampledFrameIndexes, serializeVideoAttributes, sortFrameFiles, unpackedFrameCount, videoConsentCategory, videoEmbedUrl, videoFrameCount, videoInnerHtml, videoPlayLabel, videoPosterFileName, videoProp, videoRefOf, videoRootAttributes, videoRuntimeOf, videoSourceOf, videoThumbnailRequest, videoWords };
972
1084
  //# sourceMappingURL=vectoriox-iox-ui-media-core.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"vectoriox-iox-ui-media-core.mjs","sources":["../../../projects/iox-ui/src/media-core/frames.ts","../../../projects/iox-ui/src/media-core/video.ts","../../../projects/iox-ui/src/media-core/video-runtime.ts","../../../projects/iox-ui/src/media-core/public-api.ts","../../../projects/iox-ui/src/media-core/vectoriox-iox-ui-media-core.ts"],"sourcesContent":["/**\n * A video played by the scroll, as pictures (premium sites SC4). Every source, a video file or a folder of rendered frames,\n * becomes the same numbered set of pictures, prepared once in the author's browser, one set for wide screens and a lighter\n * one for phones. So there is one player and it is the same on every browser: a `<video>` seeked by the scroll needs a\n * dense-keyframe encode no pod here can run, and on an iPhone it accepts seeks it never answers.\n *\n * The saved value is a small description, never a list of addresses: a page holding 300 URLs would ship them in its HTML.\n */\n\nexport enum FrameSet {\n Wide = 'w',\n Phone = 'p',\n}\n\nexport interface FrameSetInfo {\n count: number;\n width: number;\n height: number;\n}\n\nexport interface FrameSequence {\n /** Where the numbered pictures live: `<base>/<set>/0001.<ext>`. */\n base: string;\n ext: FrameExtension;\n wide: FrameSetInfo;\n /** Absent = phones play the wide set. */\n phone?: FrameSetInfo;\n /**\n * A phone film of its own, framed for a tall screen, lives under its own name: a replacement that fails half way leaves\n * the one playing untouched. Absent = the phone set is the wide film made smaller, under `base`.\n */\n phoneBase?: string;\n /** What the sequence weighs in storage, both sets. Shown to the author. */\n bytes?: number;\n}\n\n/** At or under this width a screen is a phone. Scene's own limit says the same: scene-core reads media-core, never the reverse. */\nexport const FRAMES_PHONE_MAX_WIDTH = 767;\n\nexport enum FrameExtension {\n Webp = 'webp',\n Jpeg = 'jpg',\n}\n\n/** The most pictures one set may hold. Past this a phone runs out of memory before the visitor runs out of scroll. */\nexport const MAX_FRAMES = 300;\n/** The most one picture may weigh when uploaded. */\nexport const MAX_FRAME_BYTES = 3 * 1024 * 1024;\n/** A sequence's name in storage: what the browser generates and what the server accepts in a key. */\nexport const FRAME_SEQUENCE_ID = /^[a-z0-9]{8,40}$/;\n\nconst SAFE_BASE = /^https:\\/\\/[^\\s\"'<>\\\\]+$/;\nconst PAD = 4;\nconst ALL_EXTENSIONS: ReadonlySet<string> = new Set(Object.values(FrameExtension));\n\nfunction setInfo(raw: unknown): FrameSetInfo | null {\n const { count, width, height } = (raw ?? {}) as Partial<FrameSetInfo>;\n const valid = (v: unknown, max: number): v is number => Number.isInteger(v) && (v as number) > 0 && (v as number) <= max;\n return valid(count, MAX_FRAMES) && valid(width, 8192) && valid(height, 8192) ? { count, width, height } : null;\n}\n\n/** The sequence a saved value really describes, or null. Never throws on what a page document holds. */\nexport function normalizeFrameSequence(raw: unknown): FrameSequence | null {\n const value = (typeof raw === 'string' ? parseJson(raw) : raw) as Partial<FrameSequence> | null;\n if (!value || typeof value !== 'object') return null;\n const wide = setInfo(value.wide);\n if (!wide || typeof value.base !== 'string' || !SAFE_BASE.test(value.base) || !ALL_EXTENSIONS.has(String(value.ext))) return null;\n const phone = setInfo(value.phone);\n const phoneBase = phone && typeof value.phoneBase === 'string' && SAFE_BASE.test(value.phoneBase) ? value.phoneBase.replace(/\\/+$/, '') : '';\n return {\n base: value.base.replace(/\\/+$/, ''),\n ext: value.ext as FrameExtension,\n wide,\n ...(phone ? { phone } : {}),\n ...(phoneBase ? { phoneBase } : {}),\n ...(Number.isFinite(value.bytes) && (value.bytes as number) > 0 ? { bytes: value.bytes } : {}),\n };\n}\n\nfunction parseJson(raw: string): unknown {\n try { return JSON.parse(raw); } catch { return null; }\n}\n\n/** The name a picture is stored under: its place in the set, from 1. */\nexport function frameFileName(index: number, ext: FrameExtension): string {\n return `${String(index + 1).padStart(PAD, '0')}.${ext}`;\n}\n\n/** Picture `index` (from 0) of a set. */\nexport function frameUrl(sequence: FrameSequence, set: FrameSet, index: number): string {\n const base = set === FrameSet.Phone && sequence.phoneBase ? sequence.phoneBase : sequence.base;\n return `${base}/${set}/${frameFileName(index, sequence.ext)}`;\n}\n\n/** The first picture of each set, for a poster's `srcset`; '' when there is only one set. */\nexport function phoneFrameSrcset(sequence: FrameSequence): string {\n if (!sequence.phone) return '';\n return `${frameUrl(sequence, FrameSet.Phone, 0)} ${sequence.phone.width}w, ${frameUrl(sequence, FrameSet.Wide, 0)} ${sequence.wide.width}w`;\n}\n\n/** Which set plays: the phone's on a phone, when there is one. */\nexport function frameSetFor(sequence: FrameSequence, phone: boolean): { set: FrameSet; info: FrameSetInfo } {\n return phone && sequence.phone ? { set: FrameSet.Phone, info: sequence.phone } : { set: FrameSet.Wide, info: sequence.wide };\n}\n\n/** Where `played` % stands in a set of `count`: 2.5 is half way from the third picture to the fourth. */\nexport function framePosition(played: number, count: number): number {\n return (Math.min(100, Math.max(0, played)) / 100) * (count - 1);\n}\n\n/** On a Video whose pictures are drawing: the poster has done its job and steps aside. */\nexport const FRAMES_SHOWING_ATTRIBUTE = 'data-iox-frames-showing';\n\n/** How finely two neighbours mix. Finer than the eye reads, and a scroll that moves less than a step draws nothing. */\nexport const FRAME_BLEND_STEPS = 32;\n\n/** What to draw: picture `from`, with `to` over it at `mix` when the moment falls between two that have arrived. */\nexport interface FrameBlend {\n from: number;\n to: number;\n mix: number;\n}\n\n/**\n * The moment between two pictures. A long Scene gives a picture 50px of scroll or more, so a slow scroll would otherwise\n * show the film stepping. Blending the two neighbours keeps it moving under the finger, at the cost of one more drawImage.\n * A neighbour still loading never blends: the nearest arrived picture stands in, and null means none has.\n */\nexport function frameBlendAt(loaded: ReadonlyArray<unknown>, position: number): FrameBlend | null {\n const from = Math.floor(position);\n const to = from + 1;\n const mix = Math.round((position - from) * FRAME_BLEND_STEPS) / FRAME_BLEND_STEPS;\n if (mix > 0 && mix < 1 && loaded[from] && loaded[to]) return { from, to, mix };\n const nearest = nearestLoadedFrame(loaded, Math.round(position));\n return nearest < 0 ? null : { from: nearest, to: nearest, mix: 0 };\n}\n\n/** The picture at `played` % of a set of `count`. */\nexport function frameIndexAt(played: number, count: number): number {\n if (count <= 1) return 0;\n return Math.round((Math.min(100, Math.max(0, played)) / 100) * (count - 1));\n}\n\n/**\n * The order to fetch a set in: the two ends, then every 16th, every 8th and so on down to all of them. Any scroll position\n * then has a near picture almost at once, and the movement sharpens as the rest arrive. Fetching in sequence would leave a\n * visitor who scrolls fast looking at the first frames.\n */\nexport function frameLoadOrder(count: number): number[] {\n const order: number[] = [];\n const seen = new Set<number>();\n const add = (i: number): void => {\n if (i >= 0 && i < count && !seen.has(i)) {\n seen.add(i);\n order.push(i);\n }\n };\n add(0);\n add(count - 1);\n for (let stride = 16; stride >= 1; stride /= 2) {\n for (let i = 0; i < count; i += stride) add(i);\n }\n return order;\n}\n\n/** The loaded picture nearest `index`, or -1 when none has arrived. Ties go backward: the picture already passed. */\nexport function nearestLoadedFrame(loaded: ReadonlyArray<unknown>, index: number): number {\n for (let distance = 0; distance < loaded.length; distance++) {\n if (loaded[index - distance]) return index - distance;\n if (loaded[index + distance]) return index + distance;\n }\n return -1;\n}\n\nexport interface FrameSizes {\n width: number;\n height: number;\n}\n\n/** The longest side of a wide picture and of a phone picture. A phone's is not its width: a landscape video covers a\n * tall stage by its height, so a picture sized to the phone's width would be enlarged five times. */\nexport const WIDE_LONG_SIDE = 1600;\nexport const PHONE_LONG_SIDE = 1100;\n/** How many pictures a second of video becomes, before the cap. */\nconst VIDEO_FRAMES_PER_SECOND = 24;\n/** A video's cap: the pictures a scroll can show, at a weight a page can carry. A set of pictures is the author's own count. */\nconst VIDEO_MAX_FRAMES = 180;\n\n/** `width`×`height` fitted inside `longSide`, never enlarged. */\nexport function fittedFrameSize(width: number, height: number, longSide: number): FrameSizes {\n const scale = Math.min(1, longSide / Math.max(width, height));\n return { width: Math.max(1, Math.round(width * scale)), height: Math.max(1, Math.round(height * scale)) };\n}\n\n/** How many pictures a video of `seconds` becomes. */\nexport function videoFrameCount(seconds: number): number {\n return Math.min(VIDEO_MAX_FRAMES, Math.max(2, Math.ceil(seconds * VIDEO_FRAMES_PER_SECOND)));\n}\n\n/** Which of `sourceCount` pictures make a set of `count`, spread evenly, first and last always in. */\nexport function sampledFrameIndexes(sourceCount: number, count: number): number[] {\n if (count >= sourceCount) return Array.from({ length: sourceCount }, (_, i) => i);\n if (count <= 1) return [0];\n return Array.from({ length: count }, (_, i) => Math.round((i * (sourceCount - 1)) / (count - 1)));\n}\n\n/** A phone plays half the pictures: it has less memory, and half is plenty on a small screen. */\nexport function phoneFrameCount(wideCount: number): number {\n return Math.max(2, Math.ceil(wideCount / 2));\n}\n\nconst NATURAL = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });\n\n/** Rendered frames in their real order: `frame2` before `frame10`. */\nexport function sortFrameFiles<T extends { name: string }>(files: ReadonlyArray<T>): T[] {\n return [...files].sort((a, b) => NATURAL.compare(a.name, b.name));\n}\n\n/** A sequence's weight, for the author. */\nexport function frameSummary(sequence: FrameSequence): { frames: number; megabytes: number | null } {\n return { frames: sequence.wide.count, megabytes: sequence.bytes ? Math.round((sequence.bytes / (1024 * 1024)) * 10) / 10 : null };\n}\n\nexport enum FramesClass {\n Canvas = 'iox-video__frames',\n}\n\nconst LOAD_CONCURRENCY = 6;\nconst NEAR_MARGIN = '100% 0px';\n/** Under these the visitor keeps the poster: nobody on a metered 2G connection asked to download a film. */\nconst SLOW_CONNECTIONS: ReadonlySet<string> = new Set(['slow-2g', '2g']);\n\ninterface NetworkInformationLike {\n saveData?: boolean;\n effectiveType?: string;\n}\n\nexport interface FramePlayerOptions {\n /** Play the phone's set. */\n phone?: boolean;\n /** Start fetching when this comes near the screen. Not the layer itself: a layer clipped shut intersects nothing. */\n near?: Element;\n /** The window, for a test. */\n host?: Window;\n}\n\n/**\n * The player: draws the picture nearest what the scroll asked for on a canvas laid over the poster, and nothing until a\n * first picture has arrived, so the poster is what a visitor sees until then, and for good if the pictures never come.\n * Browser only. It writes and never reads, so the driver can call it in its write phase.\n */\nexport class FramePlayer {\n private played: number | null = null;\n private readonly set: FrameSet;\n private readonly info: FrameSetInfo;\n private readonly images: Array<HTMLImageElement | null>;\n private readonly order: number[];\n private readonly host: Window;\n private observer: IntersectionObserver | null = null;\n private canvas: HTMLCanvasElement | null = null;\n private context: CanvasRenderingContext2D | null = null;\n private drawn: FrameBlend | null = null;\n private nextToLoad = 0;\n private loading = 0;\n private started = false;\n private destroyed = false;\n private readonly pending = new Set<HTMLImageElement>();\n\n constructor(private readonly el: HTMLElement, private readonly sequence: FrameSequence, options: FramePlayerOptions = {}) {\n this.host = options.host ?? window;\n const { set, info } = frameSetFor(sequence, !!options.phone);\n this.set = set;\n this.info = info;\n this.images = new Array(info.count).fill(null);\n this.order = frameLoadOrder(info.count);\n if (!this.allowed()) return;\n const Observer = (this.host as Window & { IntersectionObserver?: typeof IntersectionObserver }).IntersectionObserver;\n if (!Observer) {\n this.start();\n return;\n }\n this.observer = new Observer(entries => {\n if (entries.some(entry => entry.isIntersecting)) this.start();\n }, { rootMargin: NEAR_MARGIN });\n this.observer.observe(options.near ?? el);\n }\n\n /**\n * Stand at `played` %, exactly. The film keeps no motion of its own: the scroll's glide, and the slowing at its end,\n * are the caller's, so the film slows with the page and stops when it stops. Between two pictures it blends them.\n */\n seek(played: number): void {\n if (played === this.played) return;\n this.played = played;\n this.draw();\n }\n\n /** Whether a re-render took the canvas away with the markup it sat in. */\n get detached(): boolean {\n return !!this.canvas && !this.canvas.isConnected;\n }\n\n destroy(): void {\n this.destroyed = true;\n this.el.removeAttribute(FRAMES_SHOWING_ATTRIBUTE);\n this.observer?.disconnect();\n this.observer = null;\n for (const image of this.pending) {\n image.onload = null;\n image.onerror = null;\n image.src = '';\n }\n this.pending.clear();\n this.canvas?.remove();\n this.canvas = null;\n this.context = null;\n }\n\n private allowed(): boolean {\n const connection = (this.host.navigator as Navigator & { connection?: NetworkInformationLike } | undefined)?.connection;\n return !connection?.saveData && !SLOW_CONNECTIONS.has(connection?.effectiveType ?? '');\n }\n\n private start(): void {\n if (this.started) return;\n this.started = true;\n this.observer?.disconnect();\n this.observer = null;\n this.pump();\n }\n\n private pump(): void {\n while (!this.destroyed && this.loading < LOAD_CONCURRENCY && this.nextToLoad < this.order.length) {\n this.load(this.order[this.nextToLoad++]);\n }\n }\n\n private load(index: number): void {\n const image = this.host.document.createElement('img');\n image.decoding = 'async';\n this.loading++;\n this.pending.add(image);\n const done = (arrived: boolean): void => {\n this.pending.delete(image);\n this.loading--;\n if (this.destroyed) return;\n if (arrived) {\n this.images[index] = image;\n this.draw();\n }\n this.pump();\n };\n // Decoded before it counts, or the first draw of each picture decodes on the driver's frame and the scroll stutters.\n image.onload = () => {\n const decoded = image.decode?.();\n if (decoded) void decoded.then(() => done(true), () => done(true));\n else done(true);\n };\n // A picture that failed is a gap: its neighbours stand in.\n image.onerror = () => done(false);\n image.src = frameUrl(this.sequence, this.set, index);\n }\n\n private draw(): void {\n if (this.destroyed || this.played === null) return;\n const blend = frameBlendAt(this.images, framePosition(this.played, this.info.count));\n const last = this.drawn;\n if (!blend || (last && last.from === blend.from && last.to === blend.to && last.mix === blend.mix)) return;\n const image = this.images[blend.from]!;\n if (!this.ensureCanvas(image)) return;\n const context = this.context!;\n const { width, height } = this.canvas!;\n context.clearRect(0, 0, width, height);\n if (blend.mix > 0) {\n // A true mix, (1 − mix)·from + mix·to, even where a see-through film has nothing on one side. Drawing `to` over\n // an opaque `from` kept `from`'s outline whole until the next picture, so the subject's edge jumped a picture at\n // a time instead of moving.\n context.globalCompositeOperation = 'lighter';\n context.globalAlpha = 1 - blend.mix;\n context.drawImage(image, 0, 0, width, height);\n context.globalAlpha = blend.mix;\n context.drawImage(this.images[blend.to]!, 0, 0, width, height);\n context.globalAlpha = 1;\n context.globalCompositeOperation = 'source-over';\n } else {\n context.drawImage(image, 0, 0, width, height);\n }\n // Over a transparent film the poster would show through: a second, stiller subject behind the moving one.\n if (!this.drawn) this.el.setAttribute(FRAMES_SHOWING_ATTRIBUTE, '');\n this.drawn = blend;\n }\n\n private ensureCanvas(image: HTMLImageElement): boolean {\n if (this.canvas) return !!this.context;\n const canvas = this.host.document.createElement('canvas');\n canvas.className = FramesClass.Canvas;\n canvas.setAttribute('aria-hidden', 'true');\n canvas.width = image.naturalWidth || this.info.width;\n canvas.height = image.naturalHeight || this.info.height;\n this.context = canvas.getContext('2d');\n if (!this.context) return false;\n this.canvas = canvas;\n this.el.appendChild(canvas);\n return true;\n }\n}\n","import { ConsentCategory, ConsentDecision, hasConsent } from '@vectoriox/iox-ui/consent-core';\n\nimport { FRAMES_PHONE_MAX_WIDTH, FrameSequence, FrameSet, frameUrl, normalizeFrameSequence, phoneFrameSrcset } from './frames';\n\n/**\n * VIDEO (CC3 — complex-components plan §7b, board 5). A LEAF type with two sources:\n * - an uploaded FILE renders as a real `<video>` (poster, `preload=\"metadata\"`, captions, controls);\n * - a YouTube / Vimeo address is ALWAYS a FACADE (D5): the studio's poster and a play button named after the video,\n * behind the site's consent gate (Marketing). The player's `<iframe>` exists only after a click AND a grant —\n * never in the server's HTML, never on the builder canvas.\n *\n * `planVideo(node, consent)` is the ONE decision — the only code that knows the URL shapes, the embed hosts and the\n * consent category. Both engine paths and the canvas render from it (`videoInnerHtml`), and the runtime\n * (`video-runtime.ts`) builds the player's address from the same plan.\n */\n\nexport const VIDEO_NODE_TYPE = 'Video';\n\nexport enum VideoSource {\n File = 'file',\n YouTube = 'youtube',\n Vimeo = 'vimeo',\n}\n\nexport enum VideoMode {\n /** In the page, with the player's controls. */\n Inline = 'inline',\n /** Muted, looped, no controls, an always-visible pause button (WCAG 2.2.2) — an uploaded file only. */\n Background = 'background',\n}\n\n/** The node's traits (Bindings ▸ Media · Behaviour · Accessibility · Privacy). */\nexport enum VideoTrait {\n /** Not `source`: across the builder `source` names a DATA source (a Repeater's, a Slider's). */\n Source = 'videoSource',\n Src = 'src',\n Poster = 'poster',\n Mode = 'mode',\n Autoplay = 'autoplay',\n Title = 'title',\n Captions = 'captions',\n CaptionsLang = 'captionsLang',\n Consent = 'consentCategory',\n /** Pictures the scroll plays (SC4): a `FrameSequence`. Written by the Scene panel, never typed. */\n Frames = 'frames',\n}\n\n/** What a plan renders. */\nexport enum VideoKind {\n /** An uploaded file: a real `<video>`. */\n File = 'file',\n /** YouTube / Vimeo: poster + play, the player loaded on a click after consent. */\n Facade = 'facade',\n /** No address yet: the poster blank (DS3) and nothing to play. */\n Empty = 'empty',\n /** Pictures the scroll plays: the poster, and the driver's canvas over it. No player, no controls. */\n Frames = 'frames',\n}\n\n/** A recognised embed: which provider, its video id and (Vimeo, unlisted) its privacy hash. */\nexport interface VideoRef {\n source: VideoSource.YouTube | VideoSource.Vimeo;\n id: string;\n hash?: string;\n}\n\nexport const VIDEO_PROVIDER_LABEL: Readonly<Record<VideoRef['source'], string>> = {\n [VideoSource.YouTube]: 'YouTube',\n [VideoSource.Vimeo]: 'Vimeo',\n};\n\n/** Who the visitor's IP address and cookies go to, named in the consent prompt. */\nexport const VIDEO_PROVIDER_COMPANY: Readonly<Record<VideoRef['source'], string>> = {\n [VideoSource.YouTube]: 'Google',\n [VideoSource.Vimeo]: 'Vimeo',\n};\n\n/** The two hosts a player ever loads from — youtube-nocookie and Vimeo's player (with Do Not Track). */\nexport const VIDEO_EMBED_ORIGINS: ReadonlyArray<string> = ['https://www.youtube-nocookie.com', 'https://player.vimeo.com'];\n\nconst YOUTUBE_ID = /^[A-Za-z0-9_-]{11}$/;\nconst VIMEO_ID = /^\\d{6,12}$/;\nconst VIMEO_HASH = /^[0-9a-f]{6,20}$/i;\nconst YOUTUBE_HOSTS = new Set(['youtube.com', 'www.youtube.com', 'm.youtube.com', 'music.youtube.com', 'youtube-nocookie.com', 'www.youtube-nocookie.com']);\nconst YOUTUBE_SHORT_HOSTS = new Set(['youtu.be', 'www.youtu.be']);\nconst YOUTUBE_PATH_PREFIXES = ['embed', 'shorts', 'live', 'v'];\nconst VIMEO_HOSTS = new Set(['vimeo.com', 'www.vimeo.com', 'player.vimeo.com']);\n\nfunction toUrl(raw: string): URL | null {\n const text = raw.trim();\n if (!text) return null;\n try {\n return new URL(/^[a-z][a-z0-9+.-]*:\\/\\//i.test(text) ? text : `https://${text}`);\n } catch {\n return null;\n }\n}\n\nfunction parseYouTube(url: URL): VideoRef | null {\n const host = url.hostname.toLowerCase();\n const segments = url.pathname.split('/').filter(Boolean);\n let id: string | null = null;\n if (YOUTUBE_SHORT_HOSTS.has(host)) id = segments[0] ?? null;\n else if (YOUTUBE_HOSTS.has(host)) {\n if (segments[0] === 'watch') id = url.searchParams.get('v');\n else if (YOUTUBE_PATH_PREFIXES.includes(segments[0] ?? '')) id = segments[1] ?? null;\n } else return null;\n return id && YOUTUBE_ID.test(id) ? { source: VideoSource.YouTube, id } : null;\n}\n\nfunction parseVimeo(url: URL): VideoRef | null {\n if (!VIMEO_HOSTS.has(url.hostname.toLowerCase())) return null;\n const segments = url.pathname.split('/').filter(Boolean);\n // player.vimeo.com/video/<id>, vimeo.com/<id>[/<hash>], vimeo.com/channels/<c>/<id>, vimeo.com/groups/<g>/videos/<id>\n const index = segments.findIndex(s => VIMEO_ID.test(s));\n if (index < 0) return null;\n const id = segments[index];\n const hash = url.searchParams.get('h') ?? segments[index + 1];\n return { source: VideoSource.Vimeo, id, ...(hash && VIMEO_HASH.test(hash) ? { hash } : {}) };\n}\n\n/** The embed a pasted address names — a YouTube or Vimeo watch, share, embed or short link — or null. */\nexport function parseVideoUrl(raw: string | null | undefined): VideoRef | null {\n const url = typeof raw === 'string' ? toUrl(raw) : null;\n if (!url || !/^https?:$/.test(url.protocol)) return null;\n return parseYouTube(url) ?? parseVimeo(url);\n}\n\n/** The source a node plays: its declared source when it is one, else what its address is. */\nexport function videoSourceOf(src: unknown, declared?: unknown): VideoSource {\n if (declared === VideoSource.YouTube || declared === VideoSource.Vimeo || declared === VideoSource.File) return declared;\n return parseVideoUrl(typeof src === 'string' ? src : '')?.source ?? VideoSource.File;\n}\n\n/** The player's address — loaded only after a click and a grant. Autoplays (the visitor just pressed play). */\nexport function videoEmbedUrl(ref: VideoRef): string {\n if (ref.source === VideoSource.YouTube) {\n return `https://www.youtube-nocookie.com/embed/${encodeURIComponent(ref.id)}?autoplay=1&rel=0&playsinline=1`;\n }\n return `https://player.vimeo.com/video/${encodeURIComponent(ref.id)}?autoplay=1&dnt=1${ref.hash ? `&h=${encodeURIComponent(ref.hash)}` : ''}`;\n}\n\n/** Where the SERVER fetches an embed's thumbnail to store as the studio's own poster (never the visitor). */\nexport interface VideoThumbnailRequest {\n /** `image`: the url IS the picture; `oembed`: the url answers JSON whose `thumbnail_url` is the picture. */\n kind: 'image' | 'oembed';\n url: string;\n /** The only hosts the picture itself may come from (the server refuses anything else). */\n imageHosts: ReadonlyArray<string>;\n}\n\nexport function videoThumbnailRequest(ref: VideoRef): VideoThumbnailRequest {\n if (ref.source === VideoSource.YouTube) {\n return { kind: 'image', url: `https://i.ytimg.com/vi/${encodeURIComponent(ref.id)}/hqdefault.jpg`, imageHosts: ['i.ytimg.com'] };\n }\n const page = `https://vimeo.com/${ref.id}${ref.hash ? `/${ref.hash}` : ''}`;\n return { kind: 'oembed', url: `https://vimeo.com/api/oembed.json?url=${encodeURIComponent(page)}&width=1280`, imageHosts: ['i.vimeocdn.com'] };\n}\n\n/** A stored poster's object name — one per video, so fetching it again overwrites rather than piles up. */\nexport function videoPosterFileName(ref: VideoRef): string {\n return `video-poster-${ref.source}-${ref.id}.jpg`;\n}\n\n// ── the node, in either shape (saved props / builder traits) ───────────────────────────────────────\n\nexport interface VideoNodeLike {\n type?: string;\n props?: Record<string, unknown> | null;\n traits?: ReadonlyArray<{ name?: string; default?: unknown }> | null;\n}\n\n/** A content value of a Video node, saved (`props`) or builder (`traits[].default`) shape. */\nexport function videoProp(node: VideoNodeLike | null | undefined, name: VideoTrait | string): unknown {\n if (!node) return undefined;\n if (node.props && Object.prototype.hasOwnProperty.call(node.props, name)) return node.props[name];\n return node.traits?.find(t => t?.name === name)?.default;\n}\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\nconst truthy = (v: unknown): boolean => v === true || v === 'true';\n\n/** The consent category an embed waits for — Marketing by default (D5); an uploaded file waits for none. */\nexport function videoConsentCategory(node: VideoNodeLike | null | undefined, source: VideoSource = videoSourceOf(videoProp(node, VideoTrait.Src), videoProp(node, VideoTrait.Source))): ConsentCategory | null {\n if (source === VideoSource.File) return null;\n const declared = videoProp(node, VideoTrait.Consent);\n return declared === ConsentCategory.Analytics ? ConsentCategory.Analytics : ConsentCategory.Marketing;\n}\n\nexport interface VideoPlan {\n kind: VideoKind;\n source: VideoSource;\n /** An embed's provider and id (Facade). */\n ref: VideoRef | null;\n /** An uploaded file's address (File). */\n src: string;\n /** The studio's own poster ('' = the token blank). Never a provider's thumbnail URL. */\n poster: string;\n /** The video's name — the play button's accessible name. */\n title: string;\n mode: VideoMode;\n background: boolean;\n /** Muted autoplay when motion is allowed (the runtime asks; the server never writes `autoplay`). */\n autoplay: boolean;\n muted: boolean;\n loop: boolean;\n controls: boolean;\n /** A `.vtt` file ('' = none). */\n captions: string;\n captionsLang: string;\n /** What the facade waits for (null for a file). */\n consentCategory: ConsentCategory | null;\n /** The visitor's decision grants it. */\n granted: boolean;\n /** The player's address — only when granted (the runtime loads it on a click). */\n embedUrl: string | null;\n /** \"YouTube\" / \"Vimeo\" ('' for a file). */\n providerLabel: string;\n /** Pictures the scroll plays (Frames). */\n frames: FrameSequence | null;\n}\n\n/**\n * The ONE decision for a Video node and a visitor's consent (null = none recorded — the server always passes null,\n * so its HTML is always the facade). A poster that is a provider's thumbnail URL is dropped: the poster is the\n * studio's own image (or the thumbnail the server fetched and stored for it), never a request to a third party.\n */\nexport function planVideo(node: VideoNodeLike | null | undefined, consent: ConsentDecision | null): VideoPlan {\n const frames = normalizeFrameSequence(videoProp(node, VideoTrait.Frames));\n if (frames) return planFrames(node, frames);\n const rawSrc = str(videoProp(node, VideoTrait.Src));\n const source = videoSourceOf(rawSrc, videoProp(node, VideoTrait.Source));\n const ref = source === VideoSource.File ? null : parseVideoUrl(rawSrc);\n const background = source === VideoSource.File && videoProp(node, VideoTrait.Mode) === VideoMode.Background;\n const consentCategory = videoConsentCategory(node, source);\n const granted = consentCategory ? hasConsent(consent, consentCategory) : true;\n const kind = source === VideoSource.File ? (rawSrc ? VideoKind.File : VideoKind.Empty) : (ref ? VideoKind.Facade : VideoKind.Empty);\n const poster = str(videoProp(node, VideoTrait.Poster));\n return {\n kind,\n source,\n ref,\n src: source === VideoSource.File ? rawSrc : '',\n poster: isThirdPartyPoster(poster) ? '' : poster,\n title: str(videoProp(node, VideoTrait.Title)),\n mode: background ? VideoMode.Background : VideoMode.Inline,\n background,\n autoplay: background || (source === VideoSource.File && truthy(videoProp(node, VideoTrait.Autoplay))),\n muted: background || truthy(videoProp(node, VideoTrait.Autoplay)),\n loop: background,\n controls: !background,\n captions: background ? '' : str(videoProp(node, VideoTrait.Captions)),\n captionsLang: str(videoProp(node, VideoTrait.CaptionsLang)) || 'en',\n consentCategory,\n granted,\n embedUrl: kind === VideoKind.Facade && granted && ref ? videoEmbedUrl(ref) : null,\n providerLabel: ref ? VIDEO_PROVIDER_LABEL[ref.source] : '',\n frames: null,\n };\n}\n\n/** Pictures win over any address the node also holds: it was turned into them. No player, no consent, nothing to press. */\nfunction planFrames(node: VideoNodeLike | null | undefined, frames: FrameSequence): VideoPlan {\n const poster = str(videoProp(node, VideoTrait.Poster));\n return {\n kind: VideoKind.Frames,\n source: VideoSource.File,\n ref: null,\n src: '',\n poster: poster && !isThirdPartyPoster(poster) ? poster : frameUrl(frames, FrameSet.Wide, 0),\n title: str(videoProp(node, VideoTrait.Title)),\n mode: VideoMode.Inline,\n background: false,\n autoplay: false,\n muted: false,\n loop: false,\n controls: false,\n captions: '',\n captionsLang: 'en',\n consentCategory: null,\n granted: true,\n embedUrl: null,\n providerLabel: '',\n frames,\n };\n}\n\nconst THIRD_PARTY_POSTER_HOSTS = ['ytimg.com', 'youtube.com', 'vimeocdn.com', 'vimeo.com', 'googleusercontent.com'];\n\n/** A poster served by the video's provider — a request to a third party before consent, so it never renders. */\nexport function isThirdPartyPoster(url: string): boolean {\n const parsed = url ? toUrl(url) : null;\n if (!parsed || !/^https?:$/.test(parsed.protocol)) return false;\n const host = parsed.hostname.toLowerCase();\n return THIRD_PARTY_POSTER_HOSTS.some(h => host === h || host.endsWith(`.${h}`));\n}\n\n// ── words ───────────────────────────────────────────────────────────────────────────────────────────\n\n/**\n * The words the renderer draws (board 5; Q7: the consent prompt is NOT an editable part — its words are the\n * consent vocabulary's, one source, translated). English and Hebrew; the page's `lang` picks.\n */\nexport interface VideoWords {\n /** The play button's name: the video's title and its provider. */\n play(title: string, provider: string): string;\n /** The play button's name with no title. */\n playUntitled(provider: string): string;\n pauseBackground: string;\n playBackground: string;\n /** The consent prompt (a group): its name, its lead and its body. */\n promptLabel: string;\n promptLead(provider: string): string;\n promptBody(company: string): string;\n /** The same prompt where the player is narrow (board 5's phone): one shorter sentence, its lead in bold. */\n promptCompactLead(provider: string): string;\n promptCompactBody: string;\n allow: string;\n settings: string;\n}\n\nexport const VIDEO_WORDS: Readonly<Record<'en' | 'he', VideoWords>> = {\n en: {\n play: (title, provider) => (provider ? `Play: ${title} (${provider})` : `Play: ${title}`),\n playUntitled: provider => (provider ? `Play video (${provider})` : 'Play video'),\n pauseBackground: 'Pause background video',\n playBackground: 'Play background video',\n promptLabel: 'This video needs your permission',\n promptLead: provider => `This video is hosted by ${provider}.`,\n promptBody: company => `Playing it lets ${company} set cookies and see your IP address. Nothing has loaded yet.`,\n promptCompactLead: provider => `Plays from ${provider},`,\n promptCompactBody: 'which sets cookies and sees your IP address. Nothing has loaded yet.',\n allow: 'Allow and play',\n settings: 'Privacy settings',\n },\n he: {\n play: (title, provider) => (provider ? `הפעלה: ${title} (${provider})` : `הפעלה: ${title}`),\n playUntitled: provider => (provider ? `הפעלת הסרטון (${provider})` : 'הפעלת הסרטון'),\n pauseBackground: 'השהיית סרטון הרקע',\n playBackground: 'הפעלת סרטון הרקע',\n promptLabel: 'הסרטון הזה צריך את רשותך',\n promptLead: provider => `הסרטון מתארח ב-${provider}.`,\n promptBody: company => `ההפעלה מאפשרת ל-${company} להגדיר קובצי Cookie ולראות את כתובת ה-IP שלך. עדיין לא נטען דבר.`,\n promptCompactLead: provider => `מתנגן מ-${provider},`,\n promptCompactBody: 'שמגדיר קובצי Cookie ורואה את כתובת ה-IP שלך. עדיין לא נטען דבר.',\n allow: 'לאשר ולהפעיל',\n settings: 'הגדרות פרטיות',\n },\n};\n\n/** The words for a page language (`he`, `he-IL` → Hebrew; anything else → English). */\nexport function videoWords(lang?: string | null): VideoWords {\n return (lang ?? '').toLowerCase().startsWith('he') ? VIDEO_WORDS.he : VIDEO_WORDS.en;\n}\n\n/** The play button's accessible name. */\nexport function videoPlayLabel(plan: VideoPlan, words: VideoWords = VIDEO_WORDS.en): string {\n return plan.title ? words.play(plan.title, plan.providerLabel) : words.playUntitled(plan.providerLabel);\n}\n\n// ── markup (one builder for both engine paths and the canvas) ────────────────────────────────────────\n\nexport enum VideoClass {\n Root = 'iox-video',\n Poster = 'iox-video__poster',\n Play = 'iox-video__play',\n Badge = 'iox-video__badge',\n Media = 'iox-video__media',\n Frame = 'iox-video__frame',\n Toggle = 'iox-video__toggle',\n Consent = 'iox-video__consent',\n ConsentText = 'iox-video__consent-text',\n /** The prompt's text on a wide player / on a narrow one (a container query shows one). */\n ConsentWide = 'iox-video__consent-wide',\n ConsentCompact = 'iox-video__consent-compact',\n ConsentRow = 'iox-video__consent-row',\n Allow = 'iox-video__allow',\n Settings = 'iox-video__settings',\n}\n\nexport enum VideoAttribute {\n /** On the node element: its kind (`file` · `facade` · `empty`) — what the runtime attaches to. */\n Root = 'data-iox-video',\n Source = 'data-iox-video-source',\n Id = 'data-iox-video-id',\n Hash = 'data-iox-video-hash',\n Mode = 'data-iox-video-mode',\n Autoplay = 'data-iox-video-autoplay',\n Consent = 'data-iox-video-consent',\n Title = 'data-iox-video-title',\n /** The poster is the token blank (no image): the shared CSS fills it with `surface-2`. */\n PosterEmpty = 'data-iox-video-poster-empty',\n /** The player is loaded (after the click and the grant). */\n Playing = 'data-iox-video-playing',\n /** The consent prompt is showing. */\n Asking = 'data-iox-video-asking',\n /** The pictures the scroll plays, as JSON: what the driver reads, so it needs no node tree. */\n Frames = 'data-iox-video-frames',\n}\n\nexport enum VideoIcon {\n Play = 'ph-fill ph-play',\n Pause = 'ph-fill ph-pause',\n}\n\n/** The attributes the node's own element carries (both engine paths, the canvas). */\nexport function videoRootAttributes(plan: VideoPlan): Record<string, string> {\n const attrs: Record<string, string> = { [VideoAttribute.Root]: plan.kind, [VideoAttribute.Source]: plan.source };\n if (plan.ref) {\n attrs[VideoAttribute.Id] = plan.ref.id;\n if (plan.ref.hash) attrs[VideoAttribute.Hash] = plan.ref.hash;\n }\n if (plan.background) attrs[VideoAttribute.Mode] = VideoMode.Background;\n if (plan.autoplay) attrs[VideoAttribute.Autoplay] = '';\n if (plan.consentCategory) attrs[VideoAttribute.Consent] = plan.consentCategory;\n if (plan.title) attrs[VideoAttribute.Title] = plan.title;\n if (!plan.poster) attrs[VideoAttribute.PosterEmpty] = '';\n if (plan.frames) attrs[VideoAttribute.Frames] = JSON.stringify(plan.frames);\n return attrs;\n}\n\nexport interface VideoMarkupOptions {\n /** HTML-escape an attribute or text value. */\n esc: (value: string) => string;\n /** The builder canvas: the poster ONLY — no `<video>`, no player, nothing that loads or takes a click. */\n canvas?: boolean;\n words?: VideoWords;\n}\n\nconst iconHtml = (cls: string) => `<i class=\"${cls}\" aria-hidden=\"true\"></i>`;\n\n/** The element's inner markup. The server's HTML for a facade holds no `<iframe>` and requests nothing from\n * the provider: only the studio's poster, the play button and the (hidden) consent prompt. */\nexport function videoInnerHtml(plan: VideoPlan, options: VideoMarkupOptions): string {\n const { esc } = options;\n const words = options.words ?? VIDEO_WORDS.en;\n // The same on the canvas and on the site: the first picture is real content, so it is fetched at once, named, and the\n // size a phone needs. A driver's canvas covers it when pictures arrive; with no script it is what there is.\n if (plan.kind === VideoKind.Frames) {\n const own = !!plan.frames && !isAuthoredPoster(plan);\n const srcset = own ? phoneFrameSrcset(plan.frames!) : '';\n // Its real size, so where a Scene flows (reduced motion, no script) the picture holds its height before it loads.\n const size = own ? ` width=\"${plan.frames!.wide.width}\" height=\"${plan.frames!.wide.height}\"` : '';\n const image = (attrs: string): string => `<img class=\"${VideoClass.Poster}\" src=\"${esc(plan.poster)}\"${attrs} alt=\"${esc(plan.title)}\" decoding=\"async\">`;\n // A phone film is framed for a tall screen, so it is chosen by the screen, never by the pixels a high-density phone asks for.\n if (own && plan.frames!.phoneBase) {\n const { width, height } = plan.frames!.phone!;\n return `<picture><source media=\"(max-width: ${FRAMES_PHONE_MAX_WIDTH}px)\" srcset=\"${esc(frameUrl(plan.frames!, FrameSet.Phone, 0))}\" width=\"${width}\" height=\"${height}\">${image(size)}</picture>`;\n }\n return image(`${srcset ? ` srcset=\"${esc(srcset)}\" sizes=\"100vw\"` : ''}${size}`);\n }\n const poster = plan.poster ? `<img class=\"${VideoClass.Poster}\" src=\"${esc(plan.poster)}\" alt=\"\" loading=\"lazy\" decoding=\"async\">` : '';\n const label = esc(videoPlayLabel(plan, words));\n const playSpan = `<span class=\"${VideoClass.Play}\" aria-hidden=\"true\">${iconHtml(VideoIcon.Play)}</span>`;\n const badge = plan.providerLabel ? `<span class=\"${VideoClass.Badge}\">${iconHtml(VideoIcon.Play)}${esc(plan.providerLabel)}</span>` : '';\n\n if (options.canvas || plan.kind === VideoKind.Empty) {\n return `${poster}${plan.kind === VideoKind.Empty && !options.canvas ? '' : playSpan}${badge}`;\n }\n\n if (plan.kind === VideoKind.File) {\n const media = [\n `<video class=\"${VideoClass.Media}\" src=\"${esc(plan.src)}\" preload=\"metadata\" playsinline`,\n plan.poster ? ` poster=\"${esc(plan.poster)}\"` : '',\n // A captions file is fetched with CORS (a <track> from another origin loads only so): the studio's bucket\n // answers CORS for every object, the video included.\n plan.captions ? ' crossorigin=\"anonymous\"' : '',\n plan.controls ? ' controls' : '',\n plan.muted ? ' muted' : '',\n plan.loop ? ' loop' : '',\n plan.background ? ' aria-hidden=\"true\" tabindex=\"-1\"' : (plan.title ? ` aria-label=\"${esc(plan.title)}\"` : ''),\n '>',\n plan.captions ? `<track kind=\"captions\" src=\"${esc(plan.captions)}\" srclang=\"${esc(plan.captionsLang)}\" label=\"${esc(plan.captionsLang)}\" default>` : '',\n '</video>',\n ].join('');\n if (plan.background) {\n // Rendered paused (the server cannot know the visitor's motion setting): the runtime starts it when motion\n // is allowed and turns this into the PAUSE button. Always visible (WCAG 2.2.2).\n return `${media}<button type=\"button\" class=\"${VideoClass.Toggle}\" aria-label=\"${esc(words.playBackground)}\" aria-pressed=\"true\">${iconHtml(VideoIcon.Play)}</button>`;\n }\n return `${media}<button type=\"button\" class=\"${VideoClass.Play}\" aria-label=\"${label}\">${iconHtml(VideoIcon.Play)}</button>`;\n }\n\n const company = plan.ref ? VIDEO_PROVIDER_COMPANY[plan.ref.source] : '';\n const prompt = `<div class=\"${VideoClass.Consent}\" role=\"group\" aria-label=\"${esc(words.promptLabel)}\" hidden>` +\n `<p class=\"${VideoClass.ConsentText} ${VideoClass.ConsentWide}\"><b>${esc(words.promptLead(plan.providerLabel))}</b> ${esc(words.promptBody(company))}</p>` +\n `<p class=\"${VideoClass.ConsentText} ${VideoClass.ConsentCompact}\"><b>${esc(words.promptCompactLead(plan.providerLabel))}</b> ${esc(words.promptCompactBody)}</p>` +\n `<div class=\"${VideoClass.ConsentRow}\">` +\n `<button type=\"button\" class=\"${VideoClass.Allow}\">${esc(words.allow)}</button>` +\n `<button type=\"button\" class=\"${VideoClass.Settings}\">${esc(words.settings)}</button>` +\n `</div></div>`;\n return `${poster}<button type=\"button\" class=\"${VideoClass.Play}\" aria-label=\"${label}\">${iconHtml(VideoIcon.Play)}</button>${badge}${prompt}`;\n}\n\nconst isAuthoredPoster = (plan: VideoPlan): boolean => !!plan.frames && plan.poster !== frameUrl(plan.frames, FrameSet.Wide, 0);\n\n/** Serialise attributes for a string renderer (a present boolean attribute is written bare). */\nexport function serializeVideoAttributes(attrs: Readonly<Record<string, string>>, esc: (value: string) => string): string {\n return Object.entries(attrs).map(([name, value]) => (value === '' ? ` ${name}` : ` ${name}=\"${esc(value)}\"`)).join('');\n}\n","import {\n CONSENT_COOKIE_NAME, ConsentCategory, ConsentDecision, cookieAttributes, decode, encode, hasConsent, setCategoryDecision,\n} from '@vectoriox/iox-ui/consent-core';\n\nimport { VIDEO_PROVIDER_LABEL, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRef, VideoSource, videoEmbedUrl, VideoWords, videoWords } from './video';\n\n/**\n * The Video's RUNTIME (CC3, board 5) — DOM only, ONE copy for both engine paths (the component path attaches it from\n * its component, the string path from the page's interaction service; `attachVideoAt` is idempotent). It reads the\n * markup `videoInnerHtml` writes. The builder canvas never attaches it (the canvas shows the poster only).\n *\n * - FACADE: play → the visitor's consent grants the category → the player's `<iframe>` replaces the poster, focused,\n * autoplaying (the visitor just pressed play). Not granted → the consent prompt: \"Allow and play\" grants the\n * category in the site's ONE consent record (the banner and its preferences read the same cookie) and plays;\n * \"Privacy settings\" opens the site's own preferences dialog.\n * - FILE: the play button starts the `<video>`; muted autoplay only when motion is allowed.\n * - BACKGROUND: muted and looped; it plays only when motion is allowed (never under reduced motion), and its\n * pause button is always there (WCAG 2.2.2).\n */\n\n/** Ask the page to record a category the visitor granted (cancelable: the site's consent service handles it). */\nexport const CONSENT_GRANT_EVENT = 'iox-consent-grant';\n/** Ask the page to open its consent preferences (cancelable: handled = a dialog opened). */\nexport const CONSENT_PREFERENCES_EVENT = 'iox-consent-preferences';\n\nexport interface ConsentGrantDetail { category: ConsentCategory }\n\n/** How the runtime reads and writes the visitor's ONE consent record — the page's transport. */\nexport interface ConsentTransport {\n read(): ConsentDecision | null;\n /** Record the category as granted (synchronously, before the player loads). */\n grant(category: ConsentCategory): void;\n /** Open the site's privacy preferences; false when the page has none. */\n openPreferences(): boolean;\n}\n\nconst REDUCED_MOTION = '(prefers-reduced-motion: reduce)';\nconst RUNTIME_KEY = '__ioxVideo';\nconst IFRAME_ALLOW = 'autoplay; encrypted-media; picture-in-picture; fullscreen';\n\n/** The cookie the consent record lives in, read from a document. */\nexport function readConsentRecord(doc: Document): ConsentDecision | null {\n const raw = (doc.cookie ?? '').split('; ').find(c => c.startsWith(`${CONSENT_COOKIE_NAME}=`));\n return decode(raw ? decodeURIComponent(raw.slice(CONSENT_COOKIE_NAME.length + 1)) : null);\n}\n\n/**\n * The default transport: the page's own consent service answers the events (the engine records the decision, tells\n * Consent Mode, re-syncs the banner's switches); a page with no such service (the admin's Preview) records the cookie\n * itself, through the same consent-core decision, so the record is the same shape either way.\n */\nexport function documentConsentTransport(doc: Document): ConsentTransport {\n return {\n read: () => readConsentRecord(doc),\n grant: category => {\n const event = new CustomEvent<ConsentGrantDetail>(CONSENT_GRANT_EVENT, { detail: { category }, cancelable: true });\n doc.dispatchEvent(event);\n if (event.defaultPrevented) return;\n const previous = readConsentRecord(doc);\n const anonymousId = previous?.anonymousId ?? randomId();\n const decision = setCategoryDecision(previous, category, true, anonymousId, previous?.policyVersion ?? '1');\n const secure = doc.location?.protocol === 'https:';\n doc.cookie = `${CONSENT_COOKIE_NAME}=${encodeURIComponent(encode(decision))}; ${cookieAttributes(12, secure)}`;\n },\n openPreferences: () => {\n const event = new CustomEvent(CONSENT_PREFERENCES_EVENT, { cancelable: true });\n doc.dispatchEvent(event);\n return event.defaultPrevented;\n },\n };\n}\n\nfunction randomId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n return c?.randomUUID ? c.randomUUID() : Math.random().toString(36).slice(2);\n}\n\nexport interface VideoRuntimeOptions {\n consent?: ConsentTransport;\n /** True to stop motion (default: the visitor's reduced-motion setting). */\n reducedMotion?: () => boolean;\n words?: VideoWords;\n}\n\n/** The embed a facade root names (its provider, id and hash attributes). */\nexport function videoRefOf(root: Element): VideoRef | null {\n const source = root.getAttribute(VideoAttribute.Source);\n const id = root.getAttribute(VideoAttribute.Id);\n if ((source !== VideoSource.YouTube && source !== VideoSource.Vimeo) || !id) return null;\n const hash = root.getAttribute(VideoAttribute.Hash);\n return { source, id, ...(hash ? { hash } : {}) };\n}\n\nexport class VideoRuntime {\n private readonly cleanups: Array<() => void> = [];\n private readonly consent: ConsentTransport;\n private readonly reduced: () => boolean;\n private readonly words: VideoWords;\n private readonly doc: Document;\n\n constructor(readonly root: HTMLElement, options: VideoRuntimeOptions = {}) {\n this.doc = root.ownerDocument;\n this.consent = options.consent ?? documentConsentTransport(this.doc);\n const view = this.doc.defaultView;\n this.reduced = options.reducedMotion ?? (() => !!view?.matchMedia?.(REDUCED_MOTION)?.matches);\n this.words = options.words ?? videoWords(this.doc.documentElement?.getAttribute('lang'));\n const kind = root.getAttribute(VideoAttribute.Root);\n if (kind === VideoKind.Facade) this.attachFacade();\n else if (kind === VideoKind.File) this.attachFile();\n }\n\n destroy(): void {\n this.cleanups.splice(0).forEach(fn => fn());\n delete (this.root as unknown as Record<string, unknown>)[RUNTIME_KEY];\n }\n\n /** The category a facade waits for (Marketing unless the node named another). */\n private get category(): ConsentCategory {\n const declared = this.root.getAttribute(VideoAttribute.Consent);\n return declared === ConsentCategory.Analytics ? ConsentCategory.Analytics : ConsentCategory.Marketing;\n }\n\n private on(el: Element | null, type: string, fn: (e: Event) => void): void {\n if (!el) return;\n el.addEventListener(type, fn);\n this.cleanups.push(() => el.removeEventListener(type, fn));\n }\n\n // ── facade ────────────────────────────────────────────────────────────────────────────────────\n\n private attachFacade(): void {\n const play = this.root.querySelector<HTMLButtonElement>(`button.${VideoClass.Play}`);\n const allow = this.root.querySelector<HTMLButtonElement>(`.${VideoClass.Allow}`);\n const settings = this.root.querySelector<HTMLButtonElement>(`.${VideoClass.Settings}`);\n this.on(play, 'click', () => this.requestPlay());\n this.on(allow, 'click', () => {\n this.consent.grant(this.category);\n this.loadPlayer();\n });\n this.on(settings, 'click', () => { this.consent.openPreferences(); });\n }\n\n /** Play pressed: the player when the category is granted, else the consent prompt. */\n requestPlay(): void {\n if (hasConsent(this.consent.read(), this.category)) {\n this.loadPlayer();\n return;\n }\n const prompt = this.root.querySelector<HTMLElement>(`.${VideoClass.Consent}`);\n if (!prompt) return;\n prompt.hidden = false;\n this.root.setAttribute(VideoAttribute.Asking, '');\n const play = this.root.querySelector<HTMLElement>(`button.${VideoClass.Play}`);\n if (play) play.hidden = true;\n this.root.querySelector<HTMLElement>(`.${VideoClass.Allow}`)?.focus();\n }\n\n /** The player — created only now, after the click and the grant. */\n loadPlayer(): void {\n const ref = videoRefOf(this.root);\n if (!ref || this.root.hasAttribute(VideoAttribute.Playing)) return;\n const frame = this.doc.createElement('iframe');\n frame.className = VideoClass.Frame;\n frame.src = videoEmbedUrl(ref);\n frame.title = this.root.getAttribute(VideoAttribute.Title) || this.words.playUntitled(VIDEO_PROVIDER_LABEL[ref.source]);\n frame.setAttribute('allow', IFRAME_ALLOW);\n frame.setAttribute('allowfullscreen', '');\n frame.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');\n this.root.replaceChildren(frame);\n this.root.removeAttribute(VideoAttribute.Asking);\n this.root.setAttribute(VideoAttribute.Playing, '');\n frame.focus();\n }\n\n // ── uploaded file ─────────────────────────────────────────────────────────────────────────────\n\n private attachFile(): void {\n const video = this.root.querySelector<HTMLVideoElement>(`video.${VideoClass.Media}`);\n if (!video) return;\n if (this.root.getAttribute(VideoAttribute.Mode) === VideoMode.Background) {\n this.attachBackground(video);\n return;\n }\n const play = this.root.querySelector<HTMLButtonElement>(`button.${VideoClass.Play}`);\n const hidePlay = () => { if (play) play.hidden = true; };\n this.on(play, 'click', () => { hidePlay(); void video.play()?.catch?.(() => undefined); video.focus(); });\n this.on(video, 'play', hidePlay);\n // Autoplay (muted) only while motion is allowed — never under reduced motion.\n if (this.root.hasAttribute(VideoAttribute.Autoplay) && !this.reduced()) {\n video.muted = true;\n void video.play()?.catch?.(() => undefined);\n }\n }\n\n private attachBackground(video: HTMLVideoElement): void {\n const toggle = this.root.querySelector<HTMLButtonElement>(`.${VideoClass.Toggle}`);\n video.muted = true;\n const sync = () => {\n const paused = video.paused;\n if (!toggle) return;\n toggle.setAttribute('aria-pressed', paused ? 'true' : 'false');\n toggle.setAttribute('aria-label', paused ? this.words.playBackground : this.words.pauseBackground);\n const icon = toggle.querySelector('i');\n if (icon) icon.className = paused ? VideoIcon.Play : VideoIcon.Pause;\n };\n this.on(video, 'play', sync);\n this.on(video, 'pause', sync);\n this.on(toggle, 'click', () => {\n if (video.paused) void video.play()?.catch?.(() => undefined);\n else video.pause();\n sync();\n });\n // It moves only when motion is allowed; under reduced motion it rests on its poster, paused.\n if (!this.reduced()) void video.play()?.catch?.(() => sync());\n sync();\n }\n}\n\n/** Run the video at `el` (a `[data-iox-video]` element) once; null when it is not one or already runs. */\nexport function attachVideoAt(el: HTMLElement | null | undefined, options: VideoRuntimeOptions = {}): VideoRuntime | null {\n if (!el?.hasAttribute?.(VideoAttribute.Root)) return null;\n const host = el as unknown as Record<string, unknown>;\n if (host[RUNTIME_KEY]) return null;\n const runtime = new VideoRuntime(el, options);\n host[RUNTIME_KEY] = runtime;\n return runtime;\n}\n\n/** Every video under `container` that is not running yet (the string path's globals and pages). */\nexport function attachVideos(container: ParentNode, options: VideoRuntimeOptions = {}): VideoRuntime[] {\n return Array.from(container.querySelectorAll<HTMLElement>(`[${VideoAttribute.Root}]`))\n .map(el => attachVideoAt(el, options))\n .filter((r): r is VideoRuntime => !!r);\n}\n\n/** The runtime already running at `el`, if any. */\nexport function videoRuntimeOf(el: Element | null | undefined): VideoRuntime | null {\n return ((el as unknown as Record<string, unknown> | null)?.[RUNTIME_KEY] as VideoRuntime | undefined) ?? null;\n}\n","/**\n * @vectoriox/iox-ui/media-core — media decisions shared by the builder, both engine paths and iox-cms (CC3).\n * FRAMEWORK-FREE: `planVideo` is the one place that knows a YouTube / Vimeo address, the player's host and the consent\n * category a facade waits for; the runtime is DOM-only. iox-cms reads `parseVideoUrl` / `videoThumbnailRequest` to\n * fetch and store an embed's poster (the visitor never asks the provider for it).\n * ⚠️ Consumers wire the usual trio — ng-package raw-ts assets, jest moduleNameMapper, tsconfig paths.\n */\nexport * from './frames';\nexport * from './video';\nexport * from './video-runtime';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;;;AAOG;IAES;AAAZ,CAAA,UAAY,QAAQ,EAAA;AAChB,IAAA,QAAA,CAAA,MAAA,CAAA,GAAA,GAAU;AACV,IAAA,QAAA,CAAA,OAAA,CAAA,GAAA,GAAW;AACf,CAAC,EAHW,QAAQ,KAAR,QAAQ,GAAA,EAAA,CAAA,CAAA;AA2BpB;AACO,MAAM,sBAAsB,GAAG;IAE1B;AAAZ,CAAA,UAAY,cAAc,EAAA;AACtB,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,KAAY;AAChB,CAAC,EAHW,cAAc,KAAd,cAAc,GAAA,EAAA,CAAA,CAAA;AAK1B;AACO,MAAM,UAAU,GAAG;AAC1B;MACa,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG;AAC1C;AACO,MAAM,iBAAiB,GAAG;AAEjC,MAAM,SAAS,GAAG,0BAA0B;AAC5C,MAAM,GAAG,GAAG,CAAC;AACb,MAAM,cAAc,GAAwB,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAElF,SAAS,OAAO,CAAC,GAAY,EAAA;AACzB,IAAA,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,CAA0B;IACrE,MAAM,KAAK,GAAG,CAAC,CAAU,EAAE,GAAW,KAAkB,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAK,CAAY,GAAG,CAAC,IAAK,CAAY,IAAI,GAAG;AACxH,IAAA,OAAO,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;AAClH;AAEA;AACM,SAAU,sBAAsB,CAAC,GAAY,EAAA;AAC/C,IAAA,MAAM,KAAK,IAAI,OAAO,GAAG,KAAK,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,CAAkC;AAC/F,IAAA,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;AAAE,QAAA,OAAO,IAAI;IACpD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;AAChC,IAAA,IAAI,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAAE,QAAA,OAAO,IAAI;IACjI,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAClC,IAAA,MAAM,SAAS,GAAG,KAAK,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,EAAE;IAC5I,OAAO;QACH,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,GAAG,EAAE,KAAK,CAAC,GAAqB;QAChC,IAAI;AACJ,QAAA,IAAI,KAAK,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC3B,QAAA,IAAI,SAAS,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;AACnC,QAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAK,KAAK,CAAC,KAAgB,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;KACjG;AACL;AAEA,SAAS,SAAS,CAAC,GAAW,EAAA;AAC1B,IAAA,IAAI;AAAE,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IAAE;AAAE,IAAA,MAAM;AAAE,QAAA,OAAO,IAAI;IAAE;AACzD;AAEA;AACM,SAAU,aAAa,CAAC,KAAa,EAAE,GAAmB,EAAA;AAC5D,IAAA,OAAO,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA,CAAA,EAAI,GAAG,EAAE;AAC3D;AAEA;SACgB,QAAQ,CAAC,QAAuB,EAAE,GAAa,EAAE,KAAa,EAAA;IAC1E,MAAM,IAAI,GAAG,GAAG,KAAK,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,GAAG,QAAQ,CAAC,IAAI;AAC9F,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;AACjE;AAEA;AACM,SAAU,gBAAgB,CAAC,QAAuB,EAAA;IACpD,IAAI,CAAC,QAAQ,CAAC,KAAK;AAAE,QAAA,OAAO,EAAE;AAC9B,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA,CAAA,EAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAA,GAAA,EAAM,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA,CAAA,EAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG;AAC/I;AAEA;AACM,SAAU,WAAW,CAAC,QAAuB,EAAE,KAAc,EAAA;AAC/D,IAAA,OAAO,KAAK,IAAI,QAAQ,CAAC,KAAK,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE;AAChI;AAEA;AACM,SAAU,aAAa,CAAC,MAAc,EAAE,KAAa,EAAA;IACvD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,GAAG,KAAK,KAAK,GAAG,CAAC,CAAC;AACnE;AAEA;AACO,MAAM,wBAAwB,GAAG;AAExC;AACO,MAAM,iBAAiB,GAAG;AASjC;;;;AAIG;AACG,SAAU,YAAY,CAAC,MAA8B,EAAE,QAAgB,EAAA;IACzE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,IAAA,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC;AACnB,IAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,IAAI,IAAI,iBAAiB,CAAC,GAAG,iBAAiB;AACjF,IAAA,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC;AAAE,QAAA,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE;AAC9E,IAAA,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChE,OAAO,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;AACtE;AAEA;AACM,SAAU,YAAY,CAAC,MAAc,EAAE,KAAa,EAAA;IACtD,IAAI,KAAK,IAAI,CAAC;AAAE,QAAA,OAAO,CAAC;AACxB,IAAA,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,GAAG,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;AAC/E;AAEA;;;;AAIG;AACG,SAAU,cAAc,CAAC,KAAa,EAAA;IACxC,MAAM,KAAK,GAAa,EAAE;AAC1B,IAAA,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU;AAC9B,IAAA,MAAM,GAAG,GAAG,CAAC,CAAS,KAAU;AAC5B,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACrC,YAAA,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACX,YAAA,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACjB;AACJ,IAAA,CAAC;IACD,GAAG,CAAC,CAAC,CAAC;AACN,IAAA,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;AACd,IAAA,KAAK,IAAI,MAAM,GAAG,EAAE,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,MAAM;YAAE,GAAG,CAAC,CAAC,CAAC;IAClD;AACA,IAAA,OAAO,KAAK;AAChB;AAEA;AACM,SAAU,kBAAkB,CAAC,MAA8B,EAAE,KAAa,EAAA;AAC5E,IAAA,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;AACzD,QAAA,IAAI,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC;YAAE,OAAO,KAAK,GAAG,QAAQ;AACrD,QAAA,IAAI,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC;YAAE,OAAO,KAAK,GAAG,QAAQ;IACzD;IACA,OAAO,CAAC,CAAC;AACb;AAOA;AACsG;AAC/F,MAAM,cAAc,GAAG;AACvB,MAAM,eAAe,GAAG;AAC/B;AACA,MAAM,uBAAuB,GAAG,EAAE;AAClC;AACA,MAAM,gBAAgB,GAAG,GAAG;AAE5B;SACgB,eAAe,CAAC,KAAa,EAAE,MAAc,EAAE,QAAgB,EAAA;AAC3E,IAAA,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAC7D,IAAA,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,EAAE;AAC7G;AAEA;AACM,SAAU,eAAe,CAAC,OAAe,EAAA;IAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,uBAAuB,CAAC,CAAC,CAAC;AAChG;AAEA;AACM,SAAU,mBAAmB,CAAC,WAAmB,EAAE,KAAa,EAAA;IAClE,IAAI,KAAK,IAAI,WAAW;AAAE,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACjF,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC;AAC1B,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AACrG;AAEA;AACM,SAAU,eAAe,CAAC,SAAiB,EAAA;AAC7C,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AAChD;AAEA,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AAE/E;AACM,SAAU,cAAc,CAA6B,KAAuB,EAAA;IAC9E,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACrE;AAEA;AACM,SAAU,YAAY,CAAC,QAAuB,EAAA;AAChD,IAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE;AACrI;IAEY;AAAZ,CAAA,UAAY,WAAW,EAAA;AACnB,IAAA,WAAA,CAAA,QAAA,CAAA,GAAA,mBAA4B;AAChC,CAAC,EAFW,WAAW,KAAX,WAAW,GAAA,EAAA,CAAA,CAAA;AAIvB,MAAM,gBAAgB,GAAG,CAAC;AAC1B,MAAM,WAAW,GAAG,UAAU;AAC9B;AACA,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAgBxE;;;;AAIG;MACU,WAAW,CAAA;AAiBpB,IAAA,WAAA,CAA6B,EAAe,EAAmB,QAAuB,EAAE,UAA8B,EAAE,EAAA;QAA3F,IAAA,CAAA,EAAE,GAAF,EAAE;QAAgC,IAAA,CAAA,QAAQ,GAAR,QAAQ;QAhB/D,IAAA,CAAA,MAAM,GAAkB,IAAI;QAM5B,IAAA,CAAA,QAAQ,GAAgC,IAAI;QAC5C,IAAA,CAAA,MAAM,GAA6B,IAAI;QACvC,IAAA,CAAA,OAAO,GAAoC,IAAI;QAC/C,IAAA,CAAA,KAAK,GAAsB,IAAI;QAC/B,IAAA,CAAA,UAAU,GAAG,CAAC;QACd,IAAA,CAAA,OAAO,GAAG,CAAC;QACX,IAAA,CAAA,OAAO,GAAG,KAAK;QACf,IAAA,CAAA,SAAS,GAAG,KAAK;AACR,QAAA,IAAA,CAAA,OAAO,GAAG,IAAI,GAAG,EAAoB;QAGlD,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM;AAClC,QAAA,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5D,QAAA,IAAI,CAAC,GAAG,GAAG,GAAG;AACd,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAChB,QAAA,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9C,IAAI,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;AACvC,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAAE;AACrB,QAAA,MAAM,QAAQ,GAAI,IAAI,CAAC,IAAwE,CAAC,oBAAoB;QACpH,IAAI,CAAC,QAAQ,EAAE;YACX,IAAI,CAAC,KAAK,EAAE;YACZ;QACJ;QACA,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,OAAO,IAAG;YACnC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,cAAc,CAAC;gBAAE,IAAI,CAAC,KAAK,EAAE;AACjE,QAAA,CAAC,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;QAC/B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;IAC7C;AAEA;;;AAGG;AACH,IAAA,IAAI,CAAC,MAAc,EAAA;AACf,QAAA,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE;AAC5B,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;QACpB,IAAI,CAAC,IAAI,EAAE;IACf;;AAGA,IAAA,IAAI,QAAQ,GAAA;AACR,QAAA,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW;IACpD;IAEA,OAAO,GAAA;AACH,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,QAAA,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,wBAAwB,CAAC;AACjD,QAAA,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE;AAC3B,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;AACpB,QAAA,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE;AAC9B,YAAA,KAAK,CAAC,MAAM,GAAG,IAAI;AACnB,YAAA,KAAK,CAAC,OAAO,GAAG,IAAI;AACpB,YAAA,KAAK,CAAC,GAAG,GAAG,EAAE;QAClB;AACA,QAAA,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;AACpB,QAAA,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;AACrB,QAAA,IAAI,CAAC,MAAM,GAAG,IAAI;AAClB,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;IACvB;IAEQ,OAAO,GAAA;QACX,MAAM,UAAU,GAAI,IAAI,CAAC,IAAI,CAAC,SAA6E,EAAE,UAAU;AACvH,QAAA,OAAO,CAAC,UAAU,EAAE,QAAQ,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,CAAC;IAC1F;IAEQ,KAAK,GAAA;QACT,IAAI,IAAI,CAAC,OAAO;YAAE;AAClB,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;AACnB,QAAA,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE;AAC3B,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;QACpB,IAAI,CAAC,IAAI,EAAE;IACf;IAEQ,IAAI,GAAA;QACR,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,GAAG,gBAAgB,IAAI,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;AAC9F,YAAA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAC5C;IACJ;AAEQ,IAAA,IAAI,CAAC,KAAa,EAAA;AACtB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AACrD,QAAA,KAAK,CAAC,QAAQ,GAAG,OAAO;QACxB,IAAI,CAAC,OAAO,EAAE;AACd,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACvB,QAAA,MAAM,IAAI,GAAG,CAAC,OAAgB,KAAU;AACpC,YAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;YAC1B,IAAI,CAAC,OAAO,EAAE;YACd,IAAI,IAAI,CAAC,SAAS;gBAAE;YACpB,IAAI,OAAO,EAAE;AACT,gBAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK;gBAC1B,IAAI,CAAC,IAAI,EAAE;YACf;YACA,IAAI,CAAC,IAAI,EAAE;AACf,QAAA,CAAC;;AAED,QAAA,KAAK,CAAC,MAAM,GAAG,MAAK;AAChB,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,IAAI;AAChC,YAAA,IAAI,OAAO;gBAAE,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;;gBAC7D,IAAI,CAAC,IAAI,CAAC;AACnB,QAAA,CAAC;;QAED,KAAK,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;AACjC,QAAA,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC;IACxD;IAEQ,IAAI,GAAA;QACR,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;YAAE;QAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACpF,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AACvB,QAAA,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAAC;YAAE;QACpG,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAE;AACtC,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAAE;AAC/B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAQ;QAC7B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,MAAO;QACtC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;AACtC,QAAA,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,EAAE;;;;AAIf,YAAA,OAAO,CAAC,wBAAwB,GAAG,SAAS;YAC5C,OAAO,CAAC,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG;AACnC,YAAA,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;AAC7C,YAAA,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,GAAG;YAC/B,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;AAC9D,YAAA,OAAO,CAAC,WAAW,GAAG,CAAC;AACvB,YAAA,OAAO,CAAC,wBAAwB,GAAG,aAAa;QACpD;aAAO;AACH,YAAA,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;QACjD;;QAEA,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,wBAAwB,EAAE,EAAE,CAAC;AACnE,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;IACtB;AAEQ,IAAA,YAAY,CAAC,KAAuB,EAAA;QACxC,IAAI,IAAI,CAAC,MAAM;AAAE,YAAA,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO;AACtC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AACzD,QAAA,MAAM,CAAC,SAAS,GAAG,WAAW,CAAC,MAAM;AACrC,QAAA,MAAM,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC;AAC1C,QAAA,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK;AACpD,QAAA,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;QACvD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,KAAK;AAC/B,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;AACpB,QAAA,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC;AAC3B,QAAA,OAAO,IAAI;IACf;AACH;;ACjZD;;;;;;;;;;AAUG;AAEI,MAAM,eAAe,GAAG;IAEnB;AAAZ,CAAA,UAAY,WAAW,EAAA;AACnB,IAAA,WAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,WAAA,CAAA,SAAA,CAAA,GAAA,SAAmB;AACnB,IAAA,WAAA,CAAA,OAAA,CAAA,GAAA,OAAe;AACnB,CAAC,EAJW,WAAW,KAAX,WAAW,GAAA,EAAA,CAAA,CAAA;IAMX;AAAZ,CAAA,UAAY,SAAS,EAAA;;AAEjB,IAAA,SAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;;AAEjB,IAAA,SAAA,CAAA,YAAA,CAAA,GAAA,YAAyB;AAC7B,CAAC,EALW,SAAS,KAAT,SAAS,GAAA,EAAA,CAAA,CAAA;AAOrB;IACY;AAAZ,CAAA,UAAY,UAAU,EAAA;;AAElB,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,aAAsB;AACtB,IAAA,UAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACX,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,UAAA,CAAA,UAAA,CAAA,GAAA,UAAqB;AACrB,IAAA,UAAA,CAAA,OAAA,CAAA,GAAA,OAAe;AACf,IAAA,UAAA,CAAA,UAAA,CAAA,GAAA,UAAqB;AACrB,IAAA,UAAA,CAAA,cAAA,CAAA,GAAA,cAA6B;AAC7B,IAAA,UAAA,CAAA,SAAA,CAAA,GAAA,iBAA2B;;AAE3B,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACrB,CAAC,EAbW,UAAU,KAAV,UAAU,GAAA,EAAA,CAAA,CAAA;AAetB;IACY;AAAZ,CAAA,UAAY,SAAS,EAAA;;AAEjB,IAAA,SAAA,CAAA,MAAA,CAAA,GAAA,MAAa;;AAEb,IAAA,SAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;;AAEjB,IAAA,SAAA,CAAA,OAAA,CAAA,GAAA,OAAe;;AAEf,IAAA,SAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACrB,CAAC,EATW,SAAS,KAAT,SAAS,GAAA,EAAA,CAAA,CAAA;AAkBd,MAAM,oBAAoB,GAAiD;AAC9E,IAAA,CAAC,WAAW,CAAC,OAAO,GAAG,SAAS;AAChC,IAAA,CAAC,WAAW,CAAC,KAAK,GAAG,OAAO;;AAGhC;AACO,MAAM,sBAAsB,GAAiD;AAChF,IAAA,CAAC,WAAW,CAAC,OAAO,GAAG,QAAQ;AAC/B,IAAA,CAAC,WAAW,CAAC,KAAK,GAAG,OAAO;;AAGhC;MACa,mBAAmB,GAA0B,CAAC,kCAAkC,EAAE,0BAA0B;AAEzH,MAAM,UAAU,GAAG,qBAAqB;AACxC,MAAM,QAAQ,GAAG,YAAY;AAC7B,MAAM,UAAU,GAAG,mBAAmB;AACtC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,0BAA0B,CAAC,CAAC;AAC3J,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;AACjE,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC;AAC9D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,eAAe,EAAE,kBAAkB,CAAC,CAAC;AAE/E,SAAS,KAAK,CAAC,GAAW,EAAA;AACtB,IAAA,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE;AACvB,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;AACtB,IAAA,IAAI;QACA,OAAO,IAAI,GAAG,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,WAAW,IAAI,CAAA,CAAE,CAAC;IACpF;AAAE,IAAA,MAAM;AACJ,QAAA,OAAO,IAAI;IACf;AACJ;AAEA,SAAS,YAAY,CAAC,GAAQ,EAAA;IAC1B,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE;AACvC,IAAA,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IACxD,IAAI,EAAE,GAAkB,IAAI;AAC5B,IAAA,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;AAAE,QAAA,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI;AACtD,SAAA,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AAC9B,QAAA,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO;YAAE,EAAE,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC;aACtD,IAAI,qBAAqB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAAE,YAAA,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI;IACxF;;AAAO,QAAA,OAAO,IAAI;IAClB,OAAO,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,IAAI;AACjF;AAEA,SAAS,UAAU,CAAC,GAAQ,EAAA;IACxB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;AAAE,QAAA,OAAO,IAAI;AAC7D,IAAA,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;;AAExD,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvD,IAAI,KAAK,GAAG,CAAC;AAAE,QAAA,OAAO,IAAI;AAC1B,IAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC;AAC1B,IAAA,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;AAC7D,IAAA,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;AAChG;AAEA;AACM,SAAU,aAAa,CAAC,GAA8B,EAAA;AACxD,IAAA,MAAM,GAAG,GAAG,OAAO,GAAG,KAAK,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI;IACvD,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAAE,QAAA,OAAO,IAAI;IACxD,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC;AAC/C;AAEA;AACM,SAAU,aAAa,CAAC,GAAY,EAAE,QAAkB,EAAA;AAC1D,IAAA,IAAI,QAAQ,KAAK,WAAW,CAAC,OAAO,IAAI,QAAQ,KAAK,WAAW,CAAC,KAAK,IAAI,QAAQ,KAAK,WAAW,CAAC,IAAI;AAAE,QAAA,OAAO,QAAQ;IACxH,OAAO,aAAa,CAAC,OAAO,GAAG,KAAK,QAAQ,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,MAAM,IAAI,WAAW,CAAC,IAAI;AACxF;AAEA;AACM,SAAU,aAAa,CAAC,GAAa,EAAA;IACvC,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,OAAO,EAAE;QACpC,OAAO,CAAA,uCAAA,EAA0C,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,iCAAiC;IAChH;IACA,OAAO,CAAA,+BAAA,EAAkC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA,iBAAA,EAAoB,GAAG,CAAC,IAAI,GAAG,CAAA,GAAA,EAAM,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA,CAAE,GAAG,EAAE,CAAA,CAAE;AACjJ;AAWM,SAAU,qBAAqB,CAAC,GAAa,EAAA;IAC/C,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,OAAO,EAAE;QACpC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAA,uBAAA,EAA0B,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,gBAAgB,EAAE,UAAU,EAAE,CAAC,aAAa,CAAC,EAAE;IACpI;IACA,MAAM,IAAI,GAAG,CAAA,kBAAA,EAAqB,GAAG,CAAC,EAAE,CAAA,EAAG,GAAG,CAAC,IAAI,GAAG,CAAA,CAAA,EAAI,GAAG,CAAC,IAAI,CAAA,CAAE,GAAG,EAAE,CAAA,CAAE;IAC3E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,yCAAyC,kBAAkB,CAAC,IAAI,CAAC,CAAA,WAAA,CAAa,EAAE,UAAU,EAAE,CAAC,gBAAgB,CAAC,EAAE;AAClJ;AAEA;AACM,SAAU,mBAAmB,CAAC,GAAa,EAAA;IAC7C,OAAO,CAAA,aAAA,EAAgB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,EAAE,CAAA,IAAA,CAAM;AACrD;AAUA;AACM,SAAU,SAAS,CAAC,IAAsC,EAAE,IAAyB,EAAA;AACvF,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,SAAS;AAC3B,IAAA,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC;AAAE,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AACjG,IAAA,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC,EAAE,OAAO;AAC5D;AAEA,MAAM,GAAG,GAAG,CAAC,CAAU,MAAc,OAAO,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;AAC3E,MAAM,MAAM,GAAG,CAAC,CAAU,KAAc,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,MAAM;AAElE;AACM,SAAU,oBAAoB,CAAC,IAAsC,EAAE,SAAsB,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,EAAA;AACjL,IAAA,IAAI,MAAM,KAAK,WAAW,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;IAC5C,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC;AACpD,IAAA,OAAO,QAAQ,KAAK,eAAe,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS;AACzG;AAmCA;;;;AAIG;AACG,SAAU,SAAS,CAAC,IAAsC,EAAE,OAA+B,EAAA;AAC7F,IAAA,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;AACzE,IAAA,IAAI,MAAM;AAAE,QAAA,OAAO,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC;AAC3C,IAAA,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;AACnD,IAAA,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;AACxE,IAAA,MAAM,GAAG,GAAG,MAAM,KAAK,WAAW,CAAC,IAAI,GAAG,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC;IACtE,MAAM,UAAU,GAAG,MAAM,KAAK,WAAW,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,UAAU;IAC3G,MAAM,eAAe,GAAG,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC;AAC1D,IAAA,MAAM,OAAO,GAAG,eAAe,GAAG,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,GAAG,IAAI;AAC7E,IAAA,MAAM,IAAI,GAAG,MAAM,KAAK,WAAW,CAAC,IAAI,IAAI,MAAM,GAAG,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC;AACnI,IAAA,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO;QACH,IAAI;QACJ,MAAM;QACN,GAAG;AACH,QAAA,GAAG,EAAE,MAAM,KAAK,WAAW,CAAC,IAAI,GAAG,MAAM,GAAG,EAAE;AAC9C,QAAA,MAAM,EAAE,kBAAkB,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,MAAM;QAChD,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;AAC7C,QAAA,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,MAAM;QAC1D,UAAU;QACV,QAAQ,EAAE,UAAU,KAAK,MAAM,KAAK,WAAW,CAAC,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AACrG,QAAA,KAAK,EAAE,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;AACjE,QAAA,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,CAAC,UAAU;AACrB,QAAA,QAAQ,EAAE,UAAU,GAAG,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;AACrE,QAAA,YAAY,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,IAAI;QACnE,eAAe;QACf,OAAO;QACP,QAAQ,EAAE,IAAI,KAAK,SAAS,CAAC,MAAM,IAAI,OAAO,IAAI,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;AACjF,QAAA,aAAa,EAAE,GAAG,GAAG,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE;AAC1D,QAAA,MAAM,EAAE,IAAI;KACf;AACL;AAEA;AACA,SAAS,UAAU,CAAC,IAAsC,EAAE,MAAqB,EAAA;AAC7E,IAAA,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO;QACH,IAAI,EAAE,SAAS,CAAC,MAAM;QACtB,MAAM,EAAE,WAAW,CAAC,IAAI;AACxB,QAAA,GAAG,EAAE,IAAI;AACT,QAAA,GAAG,EAAE,EAAE;QACP,MAAM,EAAE,MAAM,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3F,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,EAAE,SAAS,CAAC,MAAM;AACtB,QAAA,UAAU,EAAE,KAAK;AACjB,QAAA,QAAQ,EAAE,KAAK;AACf,QAAA,KAAK,EAAE,KAAK;AACZ,QAAA,IAAI,EAAE,KAAK;AACX,QAAA,QAAQ,EAAE,KAAK;AACf,QAAA,QAAQ,EAAE,EAAE;AACZ,QAAA,YAAY,EAAE,IAAI;AAClB,QAAA,eAAe,EAAE,IAAI;AACrB,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,QAAQ,EAAE,IAAI;AACd,QAAA,aAAa,EAAE,EAAE;QACjB,MAAM;KACT;AACL;AAEA,MAAM,wBAAwB,GAAG,CAAC,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,uBAAuB,CAAC;AAEnH;AACM,SAAU,kBAAkB,CAAC,GAAW,EAAA;AAC1C,IAAA,MAAM,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI;IACtC,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;AAAE,QAAA,OAAO,KAAK;IAC/D,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE;IAC1C,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC,CAAC;AACnF;AA0BO,MAAM,WAAW,GAA8C;AAClE,IAAA,EAAE,EAAE;QACA,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,MAAM,QAAQ,GAAG,CAAA,MAAA,EAAS,KAAK,CAAA,EAAA,EAAK,QAAQ,CAAA,CAAA,CAAG,GAAG,CAAA,MAAA,EAAS,KAAK,CAAA,CAAE,CAAC;AACzF,QAAA,YAAY,EAAE,QAAQ,KAAK,QAAQ,GAAG,eAAe,QAAQ,CAAA,CAAA,CAAG,GAAG,YAAY,CAAC;AAChF,QAAA,eAAe,EAAE,wBAAwB;AACzC,QAAA,cAAc,EAAE,uBAAuB;AACvC,QAAA,WAAW,EAAE,kCAAkC;AAC/C,QAAA,UAAU,EAAE,QAAQ,IAAI,CAAA,wBAAA,EAA2B,QAAQ,CAAA,CAAA,CAAG;AAC9D,QAAA,UAAU,EAAE,OAAO,IAAI,CAAA,gBAAA,EAAmB,OAAO,CAAA,6DAAA,CAA+D;AAChH,QAAA,iBAAiB,EAAE,QAAQ,IAAI,CAAA,WAAA,EAAc,QAAQ,CAAA,CAAA,CAAG;AACxD,QAAA,iBAAiB,EAAE,sEAAsE;AACzF,QAAA,KAAK,EAAE,gBAAgB;AACvB,QAAA,QAAQ,EAAE,kBAAkB;AAC/B,KAAA;AACD,IAAA,EAAE,EAAE;QACA,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,MAAM,QAAQ,GAAG,CAAA,OAAA,EAAU,KAAK,CAAA,EAAA,EAAK,QAAQ,CAAA,CAAA,CAAG,GAAG,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAC;AAC3F,QAAA,YAAY,EAAE,QAAQ,KAAK,QAAQ,GAAG,iBAAiB,QAAQ,CAAA,CAAA,CAAG,GAAG,cAAc,CAAC;AACpF,QAAA,eAAe,EAAE,mBAAmB;AACpC,QAAA,cAAc,EAAE,kBAAkB;AAClC,QAAA,WAAW,EAAE,0BAA0B;AACvC,QAAA,UAAU,EAAE,QAAQ,IAAI,CAAA,eAAA,EAAkB,QAAQ,CAAA,CAAA,CAAG;AACrD,QAAA,UAAU,EAAE,OAAO,IAAI,CAAA,gBAAA,EAAmB,OAAO,CAAA,iEAAA,CAAmE;AACpH,QAAA,iBAAiB,EAAE,QAAQ,IAAI,CAAA,QAAA,EAAW,QAAQ,CAAA,CAAA,CAAG;AACrD,QAAA,iBAAiB,EAAE,iEAAiE;AACpF,QAAA,KAAK,EAAE,cAAc;AACrB,QAAA,QAAQ,EAAE,eAAe;AAC5B,KAAA;;AAGL;AACM,SAAU,UAAU,CAAC,IAAoB,EAAA;IAC3C,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,EAAE,GAAG,WAAW,CAAC,EAAE;AACxF;AAEA;AACM,SAAU,cAAc,CAAC,IAAe,EAAE,KAAA,GAAoB,WAAW,CAAC,EAAE,EAAA;AAC9E,IAAA,OAAO,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC;AAC3G;AAEA;IAEY;AAAZ,CAAA,UAAY,UAAU,EAAA;AAClB,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,WAAkB;AAClB,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,mBAA4B;AAC5B,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,iBAAwB;AACxB,IAAA,UAAA,CAAA,OAAA,CAAA,GAAA,kBAA0B;AAC1B,IAAA,UAAA,CAAA,OAAA,CAAA,GAAA,kBAA0B;AAC1B,IAAA,UAAA,CAAA,OAAA,CAAA,GAAA,kBAA0B;AAC1B,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,mBAA4B;AAC5B,IAAA,UAAA,CAAA,SAAA,CAAA,GAAA,oBAA8B;AAC9B,IAAA,UAAA,CAAA,aAAA,CAAA,GAAA,yBAAuC;;AAEvC,IAAA,UAAA,CAAA,aAAA,CAAA,GAAA,yBAAuC;AACvC,IAAA,UAAA,CAAA,gBAAA,CAAA,GAAA,4BAA6C;AAC7C,IAAA,UAAA,CAAA,YAAA,CAAA,GAAA,wBAAqC;AACrC,IAAA,UAAA,CAAA,OAAA,CAAA,GAAA,kBAA0B;AAC1B,IAAA,UAAA,CAAA,UAAA,CAAA,GAAA,qBAAgC;AACpC,CAAC,EAhBW,UAAU,KAAV,UAAU,GAAA,EAAA,CAAA,CAAA;IAkBV;AAAZ,CAAA,UAAY,cAAc,EAAA;;AAEtB,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,gBAAuB;AACvB,IAAA,cAAA,CAAA,QAAA,CAAA,GAAA,uBAAgC;AAChC,IAAA,cAAA,CAAA,IAAA,CAAA,GAAA,mBAAwB;AACxB,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,qBAA4B;AAC5B,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,qBAA4B;AAC5B,IAAA,cAAA,CAAA,UAAA,CAAA,GAAA,yBAAoC;AACpC,IAAA,cAAA,CAAA,SAAA,CAAA,GAAA,wBAAkC;AAClC,IAAA,cAAA,CAAA,OAAA,CAAA,GAAA,sBAA8B;;AAE9B,IAAA,cAAA,CAAA,aAAA,CAAA,GAAA,6BAA2C;;AAE3C,IAAA,cAAA,CAAA,SAAA,CAAA,GAAA,wBAAkC;;AAElC,IAAA,cAAA,CAAA,QAAA,CAAA,GAAA,uBAAgC;;AAEhC,IAAA,cAAA,CAAA,QAAA,CAAA,GAAA,uBAAgC;AACpC,CAAC,EAlBW,cAAc,KAAd,cAAc,GAAA,EAAA,CAAA,CAAA;IAoBd;AAAZ,CAAA,UAAY,SAAS,EAAA;AACjB,IAAA,SAAA,CAAA,MAAA,CAAA,GAAA,iBAAwB;AACxB,IAAA,SAAA,CAAA,OAAA,CAAA,GAAA,kBAA0B;AAC9B,CAAC,EAHW,SAAS,KAAT,SAAS,GAAA,EAAA,CAAA,CAAA;AAKrB;AACM,SAAU,mBAAmB,CAAC,IAAe,EAAA;IAC/C,MAAM,KAAK,GAA2B,EAAE,CAAC,cAAc,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE;AAChH,IAAA,IAAI,IAAI,CAAC,GAAG,EAAE;QACV,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE;AACtC,QAAA,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI;YAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI;IACjE;IACA,IAAI,IAAI,CAAC,UAAU;QAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,UAAU;IACtE,IAAI,IAAI,CAAC,QAAQ;AAAE,QAAA,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,EAAE;IACtD,IAAI,IAAI,CAAC,eAAe;QAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,eAAe;IAC9E,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK;IACxD,IAAI,CAAC,IAAI,CAAC,MAAM;AAAE,QAAA,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,EAAE;IACxD,IAAI,IAAI,CAAC,MAAM;AAAE,QAAA,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3E,IAAA,OAAO,KAAK;AAChB;AAUA,MAAM,QAAQ,GAAG,CAAC,GAAW,KAAK,CAAA,UAAA,EAAa,GAAG,CAAA,yBAAA,CAA2B;AAE7E;AAC+F;AACzF,SAAU,cAAc,CAAC,IAAe,EAAE,OAA2B,EAAA;AACvE,IAAA,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO;IACvB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,EAAE;;;IAG7C,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,MAAM,EAAE;AAChC,QAAA,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;AACpD,QAAA,MAAM,MAAM,GAAG,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAO,CAAC,GAAG,EAAE;;QAExD,MAAM,IAAI,GAAG,GAAG,GAAG,CAAA,QAAA,EAAW,IAAI,CAAC,MAAO,CAAC,IAAI,CAAC,KAAK,CAAA,UAAA,EAAa,IAAI,CAAC,MAAO,CAAC,IAAI,CAAC,MAAM,CAAA,CAAA,CAAG,GAAG,EAAE;AAClG,QAAA,MAAM,KAAK,GAAG,CAAC,KAAa,KAAa,CAAA,YAAA,EAAe,UAAU,CAAC,MAAM,CAAA,OAAA,EAAU,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA,CAAA,EAAI,KAAK,CAAA,MAAA,EAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA,mBAAA,CAAqB;;QAEzJ,IAAI,GAAG,IAAI,IAAI,CAAC,MAAO,CAAC,SAAS,EAAE;YAC/B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,MAAO,CAAC,KAAM;AAC7C,YAAA,OAAO,CAAA,oCAAA,EAAuC,sBAAsB,CAAA,aAAA,EAAgB,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA,SAAA,EAAY,KAAK,CAAA,UAAA,EAAa,MAAM,CAAA,EAAA,EAAK,KAAK,CAAC,IAAI,CAAC,CAAA,UAAA,CAAY;QACtM;QACA,OAAO,KAAK,CAAC,CAAA,EAAG,MAAM,GAAG,YAAY,GAAG,CAAC,MAAM,CAAC,CAAA,eAAA,CAAiB,GAAG,EAAE,CAAA,EAAG,IAAI,CAAA,CAAE,CAAC;IACpF;IACA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAA,YAAA,EAAe,UAAU,CAAC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,2CAA2C,GAAG,EAAE;IACvI,MAAM,KAAK,GAAG,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC9C,IAAA,MAAM,QAAQ,GAAG,CAAA,aAAA,EAAgB,UAAU,CAAC,IAAI,CAAA,qBAAA,EAAwB,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS;AACzG,IAAA,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,GAAG,CAAA,aAAA,EAAgB,UAAU,CAAC,KAAK,KAAK,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,EAAG,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA,OAAA,CAAS,GAAG,EAAE;AAExI,IAAA,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,EAAE;QACjD,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,GAAG,QAAQ,CAAA,EAAG,KAAK,CAAA,CAAE;IACjG;IAEA,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,EAAE;AAC9B,QAAA,MAAM,KAAK,GAAG;YACV,CAAA,cAAA,EAAiB,UAAU,CAAC,KAAK,CAAA,OAAA,EAAU,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA,gCAAA,CAAkC;AAC1F,YAAA,IAAI,CAAC,MAAM,GAAG,YAAY,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA,CAAA,CAAG,GAAG,EAAE;;;YAGlD,IAAI,CAAC,QAAQ,GAAG,0BAA0B,GAAG,EAAE;YAC/C,IAAI,CAAC,QAAQ,GAAG,WAAW,GAAG,EAAE;YAChC,IAAI,CAAC,KAAK,GAAG,QAAQ,GAAG,EAAE;YAC1B,IAAI,CAAC,IAAI,GAAG,OAAO,GAAG,EAAE;AACxB,YAAA,IAAI,CAAC,UAAU,GAAG,mCAAmC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAA,aAAA,EAAgB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA,CAAA,CAAG,GAAG,EAAE,CAAC;YAC9G,GAAG;AACH,YAAA,IAAI,CAAC,QAAQ,GAAG,CAAA,4BAAA,EAA+B,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA,SAAA,EAAY,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA,UAAA,CAAY,GAAG,EAAE;YACxJ,UAAU;AACb,SAAA,CAAC,IAAI,CAAC,EAAE,CAAC;AACV,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;;;YAGjB,OAAO,CAAA,EAAG,KAAK,CAAA,6BAAA,EAAgC,UAAU,CAAC,MAAM,CAAA,cAAA,EAAiB,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,yBAAyB,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,SAAA,CAAW;QAC1K;AACA,QAAA,OAAO,GAAG,KAAK,CAAA,6BAAA,EAAgC,UAAU,CAAC,IAAI,CAAA,cAAA,EAAiB,KAAK,CAAA,EAAA,EAAK,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW;IAChI;IAEA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,GAAG,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE;AACvE,IAAA,MAAM,MAAM,GAAG,CAAA,YAAA,EAAe,UAAU,CAAC,OAAO,CAAA,2BAAA,EAA8B,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA,SAAA,CAAW;AAC3G,QAAA,CAAA,UAAA,EAAa,UAAU,CAAC,WAAW,CAAA,CAAA,EAAI,UAAU,CAAC,WAAW,CAAA,KAAA,EAAQ,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA,KAAA,EAAQ,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA,IAAA,CAAM;QAC1J,CAAA,UAAA,EAAa,UAAU,CAAC,WAAW,CAAA,CAAA,EAAI,UAAU,CAAC,cAAc,CAAA,KAAA,EAAQ,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA,KAAA,EAAQ,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA,IAAA,CAAM;QAClK,CAAA,YAAA,EAAe,UAAU,CAAC,UAAU,CAAA,EAAA,CAAI;QACxC,CAAA,6BAAA,EAAgC,UAAU,CAAC,KAAK,CAAA,EAAA,EAAK,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA,SAAA,CAAW;QAChF,CAAA,6BAAA,EAAgC,UAAU,CAAC,QAAQ,CAAA,EAAA,EAAK,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA,SAAA,CAAW;AACtF,QAAA,CAAA,YAAA,CAAc;IAClB,OAAO,CAAA,EAAG,MAAM,CAAA,6BAAA,EAAgC,UAAU,CAAC,IAAI,CAAA,cAAA,EAAiB,KAAK,CAAA,EAAA,EAAK,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,SAAA,EAAY,KAAK,CAAA,EAAG,MAAM,EAAE;AAClJ;AAEA,MAAM,gBAAgB,GAAG,CAAC,IAAe,KAAc,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AAE/H;AACM,SAAU,wBAAwB,CAAC,KAAuC,EAAE,GAA8B,EAAA;IAC5G,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,KAAK,KAAK,EAAE,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,EAAA,EAAK,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1H;;AC7eA;;;;;;;;;;;;AAYG;AAEH;AACO,MAAM,mBAAmB,GAAG;AACnC;AACO,MAAM,yBAAyB,GAAG;AAazC,MAAM,cAAc,GAAG,kCAAkC;AACzD,MAAM,WAAW,GAAG,YAAY;AAChC,MAAM,YAAY,GAAG,2DAA2D;AAEhF;AACM,SAAU,iBAAiB,CAAC,GAAa,EAAA;AAC3C,IAAA,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAA,EAAG,mBAAmB,CAAA,CAAA,CAAG,CAAC,CAAC;IAC7F,OAAO,MAAM,CAAC,GAAG,GAAG,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AAC7F;AAEA;;;;AAIG;AACG,SAAU,wBAAwB,CAAC,GAAa,EAAA;IAClD,OAAO;AACH,QAAA,IAAI,EAAE,MAAM,iBAAiB,CAAC,GAAG,CAAC;QAClC,KAAK,EAAE,QAAQ,IAAG;AACd,YAAA,MAAM,KAAK,GAAG,IAAI,WAAW,CAAqB,mBAAmB,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAClH,YAAA,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC;YACxB,IAAI,KAAK,CAAC,gBAAgB;gBAAE;AAC5B,YAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC;YACvC,MAAM,WAAW,GAAG,QAAQ,EAAE,WAAW,IAAI,QAAQ,EAAE;AACvD,YAAA,MAAM,QAAQ,GAAG,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,IAAI,GAAG,CAAC;YAC3G,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,QAAQ;YAClD,GAAG,CAAC,MAAM,GAAG,CAAA,EAAG,mBAAmB,CAAA,CAAA,EAAI,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA,CAAE;QAClH,CAAC;QACD,eAAe,EAAE,MAAK;AAClB,YAAA,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,yBAAyB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC9E,YAAA,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC;YACxB,OAAO,KAAK,CAAC,gBAAgB;QACjC,CAAC;KACJ;AACL;AAEA,SAAS,QAAQ,GAAA;AACb,IAAA,MAAM,CAAC,GAAI,UAAyD,CAAC,MAAM;IAC3E,OAAO,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/E;AASA;AACM,SAAU,UAAU,CAAC,IAAa,EAAA;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC;IACvD,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;AAC/C,IAAA,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,OAAO,IAAI,MAAM,KAAK,WAAW,CAAC,KAAK,KAAK,CAAC,EAAE;AAAE,QAAA,OAAO,IAAI;IACxF,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,IAAI,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;AACpD;MAEa,YAAY,CAAA;IAOrB,WAAA,CAAqB,IAAiB,EAAE,OAAA,GAA+B,EAAE,EAAA;QAApD,IAAA,CAAA,IAAI,GAAJ,IAAI;QANR,IAAA,CAAA,QAAQ,GAAsB,EAAE;AAO7C,QAAA,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,aAAa;AAC7B,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC;AACpE,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW;QACjC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,aAAa,KAAK,MAAM,CAAC,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,CAAC,EAAE,OAAO,CAAC;QAC7F,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;QACxF,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC;AACnD,QAAA,IAAI,IAAI,KAAK,SAAS,CAAC,MAAM;YAAE,IAAI,CAAC,YAAY,EAAE;AAC7C,aAAA,IAAI,IAAI,KAAK,SAAS,CAAC,IAAI;YAAE,IAAI,CAAC,UAAU,EAAE;IACvD;IAEA,OAAO,GAAA;AACH,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;AAC3C,QAAA,OAAQ,IAAI,CAAC,IAA2C,CAAC,WAAW,CAAC;IACzE;;AAGA,IAAA,IAAY,QAAQ,GAAA;AAChB,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC;AAC/D,QAAA,OAAO,QAAQ,KAAK,eAAe,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS;IACzG;AAEQ,IAAA,EAAE,CAAC,EAAkB,EAAE,IAAY,EAAE,EAAsB,EAAA;AAC/D,QAAA,IAAI,CAAC,EAAE;YAAE;AACT,QAAA,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC;AAC7B,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC9D;;IAIQ,YAAY,GAAA;AAChB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAoB,CAAA,OAAA,EAAU,UAAU,CAAC,IAAI,CAAA,CAAE,CAAC;AACpF,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAoB,CAAA,CAAA,EAAI,UAAU,CAAC,KAAK,CAAA,CAAE,CAAC;AAChF,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAoB,CAAA,CAAA,EAAI,UAAU,CAAC,QAAQ,CAAA,CAAE,CAAC;AACtF,QAAA,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAK;YACzB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;YACjC,IAAI,CAAC,UAAU,EAAE;AACrB,QAAA,CAAC,CAAC;QACF,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAK,EAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,CAAC;IACzE;;IAGA,WAAW,GAAA;AACP,QAAA,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;YAChD,IAAI,CAAC,UAAU,EAAE;YACjB;QACJ;AACA,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAc,CAAA,CAAA,EAAI,UAAU,CAAC,OAAO,CAAA,CAAE,CAAC;AAC7E,QAAA,IAAI,CAAC,MAAM;YAAE;AACb,QAAA,MAAM,CAAC,MAAM,GAAG,KAAK;QACrB,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC;AACjD,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAc,CAAA,OAAA,EAAU,UAAU,CAAC,IAAI,CAAA,CAAE,CAAC;AAC9E,QAAA,IAAI,IAAI;AAAE,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI;AAC5B,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAc,CAAA,CAAA,EAAI,UAAU,CAAC,KAAK,CAAA,CAAE,CAAC,EAAE,KAAK,EAAE;IACzE;;IAGA,UAAU,GAAA;QACN,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,QAAA,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC;YAAE;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC9C,QAAA,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,KAAK;AAClC,QAAA,KAAK,CAAC,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC;QAC9B,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACvH,QAAA,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC;AACzC,QAAA,KAAK,CAAC,YAAY,CAAC,iBAAiB,EAAE,EAAE,CAAC;AACzC,QAAA,KAAK,CAAC,YAAY,CAAC,gBAAgB,EAAE,iCAAiC,CAAC;AACvE,QAAA,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,MAAM,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC;QAClD,KAAK,CAAC,KAAK,EAAE;IACjB;;IAIQ,UAAU,GAAA;AACd,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAmB,CAAA,MAAA,EAAS,UAAU,CAAC,KAAK,CAAA,CAAE,CAAC;AACpF,QAAA,IAAI,CAAC,KAAK;YAAE;AACZ,QAAA,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,UAAU,EAAE;AACtE,YAAA,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;YAC5B;QACJ;AACA,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAoB,CAAA,OAAA,EAAU,UAAU,CAAC,IAAI,CAAA,CAAE,CAAC;AACpF,QAAA,MAAM,QAAQ,GAAG,MAAK,EAAG,IAAI,IAAI;AAAE,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;AACxD,QAAA,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAK,EAAG,QAAQ,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QACzG,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC;;AAEhC,QAAA,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;AACpE,YAAA,KAAK,CAAC,KAAK,GAAG,IAAI;AAClB,YAAA,KAAK,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,GAAG,MAAM,SAAS,CAAC;QAC/C;IACJ;AAEQ,IAAA,gBAAgB,CAAC,KAAuB,EAAA;AAC5C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAoB,CAAA,CAAA,EAAI,UAAU,CAAC,MAAM,CAAA,CAAE,CAAC;AAClF,QAAA,KAAK,CAAC,KAAK,GAAG,IAAI;QAClB,MAAM,IAAI,GAAG,MAAK;AACd,YAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;AAC3B,YAAA,IAAI,CAAC,MAAM;gBAAE;AACb,YAAA,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;YAC9D,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC;YAClG,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;AACtC,YAAA,IAAI,IAAI;AAAE,gBAAA,IAAI,CAAC,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK;AACxE,QAAA,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC;QAC5B,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;QAC7B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAK;YAC1B,IAAI,KAAK,CAAC,MAAM;AAAE,gBAAA,KAAK,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,GAAG,MAAM,SAAS,CAAC;;gBACxD,KAAK,CAAC,KAAK,EAAE;AAClB,YAAA,IAAI,EAAE;AACV,QAAA,CAAC,CAAC;;AAEF,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AAAE,YAAA,KAAK,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;AAC7D,QAAA,IAAI,EAAE;IACV;AACH;AAED;SACgB,aAAa,CAAC,EAAkC,EAAE,UAA+B,EAAE,EAAA;IAC/F,IAAI,CAAC,EAAE,EAAE,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC;AAAE,QAAA,OAAO,IAAI;IACzD,MAAM,IAAI,GAAG,EAAwC;IACrD,IAAI,IAAI,CAAC,WAAW,CAAC;AAAE,QAAA,OAAO,IAAI;IAClC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC;AAC7C,IAAA,IAAI,CAAC,WAAW,CAAC,GAAG,OAAO;AAC3B,IAAA,OAAO,OAAO;AAClB;AAEA;SACgB,YAAY,CAAC,SAAqB,EAAE,UAA+B,EAAE,EAAA;AACjF,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAc,CAAA,CAAA,EAAI,cAAc,CAAC,IAAI,CAAA,CAAA,CAAG,CAAC;SAChF,GAAG,CAAC,EAAE,IAAI,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC;SACpC,MAAM,CAAC,CAAC,CAAC,KAAwB,CAAC,CAAC,CAAC,CAAC;AAC9C;AAEA;AACM,SAAU,cAAc,CAAC,EAA8B,EAAA;AACzD,IAAA,OAAS,EAAgD,GAAG,WAAW,CAA8B,IAAI,IAAI;AACjH;;AC9OA;;;;;;AAMG;;ACNH;;AAEG;;;;"}
1
+ {"version":3,"file":"vectoriox-iox-ui-media-core.mjs","sources":["../../../projects/iox-ui/src/media-core/frames.ts","../../../projects/iox-ui/src/media-core/video.ts","../../../projects/iox-ui/src/media-core/video-runtime.ts","../../../projects/iox-ui/src/media-core/public-api.ts","../../../projects/iox-ui/src/media-core/vectoriox-iox-ui-media-core.ts"],"sourcesContent":["/**\n * A video played by the scroll, as pictures (premium sites SC4). Every source, a video file or a folder of rendered frames,\n * becomes the same numbered set of pictures, prepared once in the author's browser, one set for wide screens and a lighter\n * one for phones. So there is one player and it is the same on every browser: a `<video>` seeked by the scroll needs a\n * dense-keyframe encode no pod here can run, and on an iPhone it accepts seeks it never answers.\n *\n * The saved value is a small description, never a list of addresses: a page holding 300 URLs would ship them in its HTML.\n */\n\nexport enum FrameSet {\n Wide = 'w',\n Phone = 'p',\n}\n\nexport interface FrameSetInfo {\n count: number;\n width: number;\n height: number;\n}\n\nexport interface FrameSequence {\n /** Where the numbered pictures live: `<base>/<set>/0001.<ext>`. */\n base: string;\n ext: FrameExtension;\n wide: FrameSetInfo;\n /** Absent = phones play the wide set. */\n phone?: FrameSetInfo;\n /**\n * A phone film of its own, framed for a tall screen, lives under its own name: a replacement that fails half way leaves\n * the one playing untouched. Absent = the phone set is the wide film made smaller, under `base`.\n */\n phoneBase?: string;\n /** What the sequence weighs in storage, both sets. Shown to the author. */\n bytes?: number;\n}\n\n/** At or under this width a screen is a phone. Scene's own limit says the same: scene-core reads media-core, never the reverse. */\nexport const FRAMES_PHONE_MAX_WIDTH = 767;\n\nexport enum FrameExtension {\n Webp = 'webp',\n Jpeg = 'jpg',\n}\n\n/** The most pictures one set may hold. Past this a phone runs out of memory before the visitor runs out of scroll. */\nexport const MAX_FRAMES = 300;\n/** The most one picture may weigh when uploaded. */\nexport const MAX_FRAME_BYTES = 3 * 1024 * 1024;\n/** A sequence's name in storage: what the browser generates and what the server accepts in a key. */\nexport const FRAME_SEQUENCE_ID = /^[a-z0-9]{8,40}$/;\n\nconst SAFE_BASE = /^https:\\/\\/[^\\s\"'<>\\\\]+$/;\nconst PAD = 4;\nconst ALL_EXTENSIONS: ReadonlySet<string> = new Set(Object.values(FrameExtension));\n\nfunction setInfo(raw: unknown): FrameSetInfo | null {\n const { count, width, height } = (raw ?? {}) as Partial<FrameSetInfo>;\n const valid = (v: unknown, max: number): v is number => Number.isInteger(v) && (v as number) > 0 && (v as number) <= max;\n return valid(count, MAX_FRAMES) && valid(width, 8192) && valid(height, 8192) ? { count, width, height } : null;\n}\n\n/** The sequence a saved value really describes, or null. Never throws on what a page document holds. */\nexport function normalizeFrameSequence(raw: unknown): FrameSequence | null {\n const value = (typeof raw === 'string' ? parseJson(raw) : raw) as Partial<FrameSequence> | null;\n if (!value || typeof value !== 'object') return null;\n const wide = setInfo(value.wide);\n if (!wide || typeof value.base !== 'string' || !SAFE_BASE.test(value.base) || !ALL_EXTENSIONS.has(String(value.ext))) return null;\n const phone = setInfo(value.phone);\n const phoneBase = phone && typeof value.phoneBase === 'string' && SAFE_BASE.test(value.phoneBase) ? value.phoneBase.replace(/\\/+$/, '') : '';\n return {\n base: value.base.replace(/\\/+$/, ''),\n ext: value.ext as FrameExtension,\n wide,\n ...(phone ? { phone } : {}),\n ...(phoneBase ? { phoneBase } : {}),\n ...(Number.isFinite(value.bytes) && (value.bytes as number) > 0 ? { bytes: value.bytes } : {}),\n };\n}\n\nfunction parseJson(raw: string): unknown {\n try { return JSON.parse(raw); } catch { return null; }\n}\n\n/** The name a picture is stored under: its place in the set, from 1. */\nexport function frameFileName(index: number, ext: FrameExtension): string {\n return `${String(index + 1).padStart(PAD, '0')}.${ext}`;\n}\n\n/** Picture `index` (from 0) of a set. */\nexport function frameUrl(sequence: FrameSequence, set: FrameSet, index: number): string {\n const base = set === FrameSet.Phone && sequence.phoneBase ? sequence.phoneBase : sequence.base;\n return `${base}/${set}/${frameFileName(index, sequence.ext)}`;\n}\n\n/** The first picture of each set, for a poster's `srcset`; '' when there is only one set. */\nexport function phoneFrameSrcset(sequence: FrameSequence): string {\n if (!sequence.phone) return '';\n return `${frameUrl(sequence, FrameSet.Phone, 0)} ${sequence.phone.width}w, ${frameUrl(sequence, FrameSet.Wide, 0)} ${sequence.wide.width}w`;\n}\n\n/** Which set plays: the phone's on a phone, when there is one. */\nexport function frameSetFor(sequence: FrameSequence, phone: boolean): { set: FrameSet; info: FrameSetInfo } {\n return phone && sequence.phone ? { set: FrameSet.Phone, info: sequence.phone } : { set: FrameSet.Wide, info: sequence.wide };\n}\n\n/** Where `played` % stands in a set of `count`: 2.5 is half way from the third picture to the fourth. */\nexport function framePosition(played: number, count: number): number {\n return (Math.min(100, Math.max(0, played)) / 100) * (count - 1);\n}\n\n/** On a Video whose pictures are drawing: the poster has done its job and steps aside. */\nexport const FRAMES_SHOWING_ATTRIBUTE = 'data-iox-frames-showing';\n\n/** How finely two neighbours mix. Finer than the eye reads, and a scroll that moves less than a step draws nothing. */\nexport const FRAME_BLEND_STEPS = 32;\n\n/** What to draw: picture `from`, with `to` over it at `mix` when the moment falls between two that have arrived. */\nexport interface FrameBlend {\n from: number;\n to: number;\n mix: number;\n}\n\n/**\n * The moment between two pictures. A long Scene gives a picture 50px of scroll or more, so a slow scroll would otherwise\n * show the film stepping. Blending the two neighbours keeps it moving under the finger, at the cost of one more drawImage.\n * A neighbour still loading never blends: the nearest arrived picture stands in, and null means none has.\n */\nexport function frameBlendAt(loaded: ReadonlyArray<unknown>, position: number): FrameBlend | null {\n const from = Math.floor(position);\n const to = from + 1;\n const mix = Math.round((position - from) * FRAME_BLEND_STEPS) / FRAME_BLEND_STEPS;\n if (mix > 0 && mix < 1 && loaded[from] && loaded[to]) return { from, to, mix };\n const nearest = nearestLoadedFrame(loaded, Math.round(position));\n return nearest < 0 ? null : { from: nearest, to: nearest, mix: 0 };\n}\n\n/** The picture at `played` % of a set of `count`. */\nexport function frameIndexAt(played: number, count: number): number {\n if (count <= 1) return 0;\n return Math.round((Math.min(100, Math.max(0, played)) / 100) * (count - 1));\n}\n\n/**\n * The order to fetch a set in: the two ends, then every 16th, every 8th and so on down to all of them. Any scroll position\n * then has a near picture almost at once, and the movement sharpens as the rest arrive. Fetching in sequence would leave a\n * visitor who scrolls fast looking at the first frames.\n */\nexport function frameLoadOrder(count: number): number[] {\n const order: number[] = [];\n const seen = new Set<number>();\n const add = (i: number): void => {\n if (i >= 0 && i < count && !seen.has(i)) {\n seen.add(i);\n order.push(i);\n }\n };\n add(0);\n add(count - 1);\n for (let stride = 16; stride >= 1; stride /= 2) {\n for (let i = 0; i < count; i += stride) add(i);\n }\n return order;\n}\n\n/** The loaded picture nearest `index`, or -1 when none has arrived. Ties go backward: the picture already passed. */\nexport function nearestLoadedFrame(loaded: ReadonlyArray<unknown>, index: number): number {\n for (let distance = 0; distance < loaded.length; distance++) {\n if (loaded[index - distance]) return index - distance;\n if (loaded[index + distance]) return index + distance;\n }\n return -1;\n}\n\n/**\n * How much unpacked picture one player holds at once. A browser keeps few of 300 unpacked pictures (a wide set is 1.7 GB\n * unpacked) and unpacked again on the page's own thread, at the moment of drawing, 22 ms a 1600×900 picture: longer than a\n * whole frame, so the film and the page beside it skipped a beat for every new picture (Doron's recording, 2026-11-04).\n */\nexport const FRAMES_UNPACKED_BYTES = 96 * 1024 * 1024;\nconst MIN_UNPACKED = 6;\nconst MAX_UNPACKED = 24;\n\n/** How many pictures of `width`×`height` a player holds unpacked. */\nexport function unpackedFrameCount(width: number, height: number): number {\n return Math.min(MAX_UNPACKED, Math.max(MIN_UNPACKED, Math.floor(FRAMES_UNPACKED_BYTES / (width * height * 4))));\n}\n\n/** The `size` pictures to hold unpacked around `position`, nearest first, each side in turn starting ahead. */\nexport function framesToHold(position: number, count: number, size: number): number[] {\n const from = Math.min(count - 1, Math.max(0, Math.floor(position)));\n const held: number[] = [from];\n for (let distance = 1; held.length < Math.min(size, count); distance++) {\n if (from + distance < count) held.push(from + distance);\n if (from - distance >= 0 && held.length < size) held.push(from - distance);\n }\n return held;\n}\n\nexport interface FrameSizes {\n width: number;\n height: number;\n}\n\n/** The longest side of a wide picture and of a phone picture. A phone's is not its width: a landscape video covers a\n * tall stage by its height, so a picture sized to the phone's width would be enlarged five times. */\nexport const WIDE_LONG_SIDE = 1600;\nexport const PHONE_LONG_SIDE = 1100;\n/** How many pictures a second of video becomes, before the cap. */\nconst VIDEO_FRAMES_PER_SECOND = 24;\n/** A video's cap: the pictures a scroll can show, at a weight a page can carry. A set of pictures is the author's own count. */\nconst VIDEO_MAX_FRAMES = 180;\n\n/** `width`×`height` fitted inside `longSide`, never enlarged. */\nexport function fittedFrameSize(width: number, height: number, longSide: number): FrameSizes {\n const scale = Math.min(1, longSide / Math.max(width, height));\n return { width: Math.max(1, Math.round(width * scale)), height: Math.max(1, Math.round(height * scale)) };\n}\n\n/** How many pictures a video of `seconds` becomes. */\nexport function videoFrameCount(seconds: number): number {\n return Math.min(VIDEO_MAX_FRAMES, Math.max(2, Math.ceil(seconds * VIDEO_FRAMES_PER_SECOND)));\n}\n\n/** Which of `sourceCount` pictures make a set of `count`, spread evenly, first and last always in. */\nexport function sampledFrameIndexes(sourceCount: number, count: number): number[] {\n if (count >= sourceCount) return Array.from({ length: sourceCount }, (_, i) => i);\n if (count <= 1) return [0];\n return Array.from({ length: count }, (_, i) => Math.round((i * (sourceCount - 1)) / (count - 1)));\n}\n\n/** A phone plays half the pictures: it has less memory, and half is plenty on a small screen. */\nexport function phoneFrameCount(wideCount: number): number {\n return Math.max(2, Math.ceil(wideCount / 2));\n}\n\nconst NATURAL = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });\n\n/** Rendered frames in their real order: `frame2` before `frame10`. */\nexport function sortFrameFiles<T extends { name: string }>(files: ReadonlyArray<T>): T[] {\n return [...files].sort((a, b) => NATURAL.compare(a.name, b.name));\n}\n\n/** A sequence's weight, for the author. */\nexport function frameSummary(sequence: FrameSequence): { frames: number; megabytes: number | null } {\n return { frames: sequence.wide.count, megabytes: sequence.bytes ? Math.round((sequence.bytes / (1024 * 1024)) * 10) / 10 : null };\n}\n\nexport enum FramesClass {\n Canvas = 'iox-video__frames',\n}\n\nconst LOAD_CONCURRENCY = 6;\nconst UNPACK_CONCURRENCY = 4;\nconst NEAR_MARGIN = '100% 0px';\n/** Under these the visitor keeps the poster: nobody on a metered 2G connection asked to download a film. */\nconst SLOW_CONNECTIONS: ReadonlySet<string> = new Set(['slow-2g', '2g']);\n\ninterface NetworkInformationLike {\n saveData?: boolean;\n effectiveType?: string;\n}\n\nexport interface FramePlayerOptions {\n /** Play the phone's set. */\n phone?: boolean;\n /** Start fetching when this comes near the screen. Not the layer itself: a layer clipped shut intersects nothing. */\n near?: Element;\n /** The window, for a test. */\n host?: Window;\n}\n\n/**\n * The player: draws the picture nearest what the scroll asked for on a canvas laid over the poster, and nothing until a\n * first picture has arrived, so the poster is what a visitor sees until then, and for good if the pictures never come.\n * Browser only. It writes and never reads, so the driver can call it in its write phase.\n *\n * Each picture is downloaded as a file and unpacked off the page's thread (`createImageBitmap` of the file), a window of\n * them around where the film stands, so drawing one never waits for it. A browser that cannot (no `fetch` or\n * `createImageBitmap`, or storage that refuses the download) plays from `<img>` pictures, as before: it works, and pays the\n * unpacking on the page's thread.\n */\nexport class FramePlayer {\n private played: number | null = null;\n private readonly set: FrameSet;\n private readonly info: FrameSetInfo;\n /** What a draw may use: an unpacked picture, or an `<img>` on a browser that plays from them. */\n private readonly ready: Array<CanvasImageSource | null>;\n /** The downloaded files, unpacked when the film comes near them. */\n private readonly files: Array<Blob | null>;\n private readonly order: number[];\n private readonly host: Window;\n private readonly holdCount: number;\n private fromFiles: boolean;\n private observer: IntersectionObserver | null = null;\n private canvas: HTMLCanvasElement | null = null;\n private context: CanvasRenderingContext2D | null = null;\n private drawn: FrameBlend | null = null;\n private nextToLoad = 0;\n private loading = 0;\n private started = false;\n private destroyed = false;\n private held = new Set<number>();\n private readonly unpacked = new Map<number, ImageBitmap>();\n private readonly unpacking = new Set<number>();\n private readonly pending = new Set<HTMLImageElement>();\n private readonly downloads: AbortController | null;\n\n constructor(private readonly el: HTMLElement, private readonly sequence: FrameSequence, options: FramePlayerOptions = {}) {\n this.host = options.host ?? window;\n const { set, info } = frameSetFor(sequence, !!options.phone);\n this.set = set;\n this.info = info;\n this.ready = new Array(info.count).fill(null);\n this.files = new Array(info.count).fill(null);\n this.order = frameLoadOrder(info.count);\n this.holdCount = unpackedFrameCount(info.width, info.height);\n this.fromFiles = typeof this.host.fetch === 'function' && typeof this.host.createImageBitmap === 'function';\n const Controller = (this.host as Window & { AbortController?: typeof AbortController }).AbortController;\n this.downloads = this.fromFiles && Controller ? new Controller() : null;\n if (!this.allowed()) return;\n const Observer = (this.host as Window & { IntersectionObserver?: typeof IntersectionObserver }).IntersectionObserver;\n if (!Observer) {\n this.start();\n return;\n }\n this.observer = new Observer(entries => {\n if (entries.some(entry => entry.isIntersecting)) this.start();\n }, { rootMargin: NEAR_MARGIN });\n this.observer.observe(options.near ?? el);\n }\n\n /**\n * Stand at `played` %, exactly. The film keeps no motion of its own: the scroll's glide, and the slowing at its end,\n * are the caller's, so the film slows with the page and stops when it stops. Between two pictures it blends them.\n */\n seek(played: number): void {\n if (played === this.played) return;\n this.played = played;\n this.hold();\n this.draw();\n }\n\n /** Whether a re-render took the canvas away with the markup it sat in. */\n get detached(): boolean {\n return !!this.canvas && !this.canvas.isConnected;\n }\n\n destroy(): void {\n this.destroyed = true;\n this.el.removeAttribute(FRAMES_SHOWING_ATTRIBUTE);\n this.observer?.disconnect();\n this.observer = null;\n this.downloads?.abort();\n for (const image of this.pending) {\n image.onload = null;\n image.onerror = null;\n image.src = '';\n }\n this.pending.clear();\n for (const bitmap of this.unpacked.values()) bitmap.close();\n this.unpacked.clear();\n this.canvas?.remove();\n this.canvas = null;\n this.context = null;\n }\n\n private allowed(): boolean {\n const connection = (this.host.navigator as Navigator & { connection?: NetworkInformationLike } | undefined)?.connection;\n return !connection?.saveData && !SLOW_CONNECTIONS.has(connection?.effectiveType ?? '');\n }\n\n private start(): void {\n if (this.started) return;\n this.started = true;\n this.observer?.disconnect();\n this.observer = null;\n this.pump();\n }\n\n private pump(): void {\n while (!this.destroyed && this.loading < LOAD_CONCURRENCY && this.nextToLoad < this.order.length) {\n const index = this.order[this.nextToLoad++];\n if (this.fromFiles) this.download(index);\n else this.loadImage(index);\n }\n }\n\n private loaded(arrived: boolean): void {\n this.loading--;\n if (this.destroyed) return;\n if (arrived) this.draw();\n this.pump();\n }\n\n private download(index: number): void {\n this.loading++;\n const url = frameUrl(this.sequence, this.set, index);\n this.host.fetch(url, this.downloads ? { signal: this.downloads.signal } : undefined)\n .then(response => (response.ok ? response.blob() : null))\n .then(file => {\n if (this.destroyed) return;\n // A picture that failed is a gap: its neighbours stand in.\n this.files[index] = file;\n this.loading--;\n this.hold();\n this.pump();\n }, () => {\n if (this.destroyed) return;\n // Storage that refuses a download from the page's address still serves an <img>: play from those.\n this.fromFiles = false;\n this.loading--;\n this.loadImage(index);\n });\n }\n\n private loadImage(index: number): void {\n const image = this.host.document.createElement('img');\n image.decoding = 'async';\n this.loading++;\n this.pending.add(image);\n const done = (arrived: boolean): void => {\n this.pending.delete(image);\n if (!this.destroyed && arrived) this.ready[index] = image;\n this.loaded(arrived);\n };\n // Decoded before it counts, or its first draw decodes on the driver's frame.\n image.onload = () => {\n const decoded = image.decode?.();\n if (decoded) void decoded.then(() => done(true), () => done(true));\n else done(true);\n };\n image.onerror = () => done(false);\n image.src = frameUrl(this.sequence, this.set, index);\n }\n\n /** Unpack the pictures around where the film stands, nearest first, and let go of the ones it has left. */\n private hold(): void {\n if (this.destroyed) return;\n const wanted = framesToHold(framePosition(this.played ?? 0, this.info.count), this.info.count, this.holdCount);\n this.held = new Set(wanted);\n for (const [index, bitmap] of this.unpacked) {\n if (this.held.has(index)) continue;\n bitmap.close();\n this.unpacked.delete(index);\n this.ready[index] = null;\n }\n for (const index of wanted) {\n if (this.unpacking.size >= UNPACK_CONCURRENCY) return;\n if (this.files[index] && !this.ready[index] && !this.unpacking.has(index)) this.unpack(index);\n }\n }\n\n private unpack(index: number): void {\n this.unpacking.add(index);\n this.host.createImageBitmap(this.files[index]!).then(bitmap => {\n this.unpacking.delete(index);\n if (this.destroyed || !this.held.has(index)) {\n bitmap.close();\n } else {\n this.unpacked.set(index, bitmap);\n this.ready[index] = bitmap;\n this.draw();\n }\n this.hold();\n }, () => {\n // A file that will not unpack is a gap, like one that never came.\n this.unpacking.delete(index);\n this.files[index] = null;\n this.hold();\n });\n }\n\n private draw(): void {\n if (this.destroyed || this.played === null) return;\n const blend = frameBlendAt(this.ready, framePosition(this.played, this.info.count));\n const last = this.drawn;\n if (!blend || (last && last.from === blend.from && last.to === blend.to && last.mix === blend.mix)) return;\n const picture = this.ready[blend.from]!;\n if (!this.ensureCanvas(picture)) return;\n const context = this.context!;\n const { width, height } = this.canvas!;\n context.clearRect(0, 0, width, height);\n if (blend.mix > 0) {\n // A true mix, (1 − mix)·from + mix·to, even where a see-through film has nothing on one side. Drawing `to` over\n // an opaque `from` kept `from`'s outline whole until the next picture, so the subject's edge jumped a picture at\n // a time instead of moving.\n context.globalCompositeOperation = 'lighter';\n context.globalAlpha = 1 - blend.mix;\n context.drawImage(picture, 0, 0, width, height);\n context.globalAlpha = blend.mix;\n context.drawImage(this.ready[blend.to]!, 0, 0, width, height);\n context.globalAlpha = 1;\n context.globalCompositeOperation = 'source-over';\n } else {\n context.drawImage(picture, 0, 0, width, height);\n }\n // Over a transparent film the poster would show through: a second, stiller subject behind the moving one.\n if (!this.drawn) this.el.setAttribute(FRAMES_SHOWING_ATTRIBUTE, '');\n this.drawn = blend;\n }\n\n private ensureCanvas(picture: CanvasImageSource): boolean {\n if (this.canvas) return !!this.context;\n const size = picture as { naturalWidth?: number; naturalHeight?: number; width?: number; height?: number };\n const canvas = this.host.document.createElement('canvas');\n canvas.className = FramesClass.Canvas;\n canvas.setAttribute('aria-hidden', 'true');\n canvas.width = size.naturalWidth || Number(size.width) || this.info.width;\n canvas.height = size.naturalHeight || Number(size.height) || this.info.height;\n this.context = canvas.getContext('2d');\n if (!this.context) return false;\n this.canvas = canvas;\n this.el.appendChild(canvas);\n return true;\n }\n}\n","import { ConsentCategory, ConsentDecision, hasConsent } from '@vectoriox/iox-ui/consent-core';\n\nimport { FRAMES_PHONE_MAX_WIDTH, FrameSequence, FrameSet, frameUrl, normalizeFrameSequence, phoneFrameSrcset } from './frames';\n\n/**\n * VIDEO (CC3 — complex-components plan §7b, board 5). A LEAF type with two sources:\n * - an uploaded FILE renders as a real `<video>` (poster, `preload=\"metadata\"`, captions, controls);\n * - a YouTube / Vimeo address is ALWAYS a FACADE (D5): the studio's poster and a play button named after the video,\n * behind the site's consent gate (Marketing). The player's `<iframe>` exists only after a click AND a grant —\n * never in the server's HTML, never on the builder canvas.\n *\n * `planVideo(node, consent)` is the ONE decision — the only code that knows the URL shapes, the embed hosts and the\n * consent category. Both engine paths and the canvas render from it (`videoInnerHtml`), and the runtime\n * (`video-runtime.ts`) builds the player's address from the same plan.\n */\n\nexport const VIDEO_NODE_TYPE = 'Video';\n\nexport enum VideoSource {\n File = 'file',\n YouTube = 'youtube',\n Vimeo = 'vimeo',\n}\n\nexport enum VideoMode {\n /** In the page, with the player's controls. */\n Inline = 'inline',\n /** Muted, looped, no controls, an always-visible pause button (WCAG 2.2.2) — an uploaded file only. */\n Background = 'background',\n}\n\n/** The node's traits (Bindings ▸ Media · Behaviour · Accessibility · Privacy). */\nexport enum VideoTrait {\n /** Not `source`: across the builder `source` names a DATA source (a Repeater's, a Slider's). */\n Source = 'videoSource',\n Src = 'src',\n Poster = 'poster',\n Mode = 'mode',\n Autoplay = 'autoplay',\n Title = 'title',\n Captions = 'captions',\n CaptionsLang = 'captionsLang',\n Consent = 'consentCategory',\n /** Pictures the scroll plays (SC4): a `FrameSequence`. Written by the Scene panel, never typed. */\n Frames = 'frames',\n}\n\n/** What a plan renders. */\nexport enum VideoKind {\n /** An uploaded file: a real `<video>`. */\n File = 'file',\n /** YouTube / Vimeo: poster + play, the player loaded on a click after consent. */\n Facade = 'facade',\n /** No address yet: the poster blank (DS3) and nothing to play. */\n Empty = 'empty',\n /** Pictures the scroll plays: the poster, and the driver's canvas over it. No player, no controls. */\n Frames = 'frames',\n}\n\n/** A recognised embed: which provider, its video id and (Vimeo, unlisted) its privacy hash. */\nexport interface VideoRef {\n source: VideoSource.YouTube | VideoSource.Vimeo;\n id: string;\n hash?: string;\n}\n\nexport const VIDEO_PROVIDER_LABEL: Readonly<Record<VideoRef['source'], string>> = {\n [VideoSource.YouTube]: 'YouTube',\n [VideoSource.Vimeo]: 'Vimeo',\n};\n\n/** Who the visitor's IP address and cookies go to, named in the consent prompt. */\nexport const VIDEO_PROVIDER_COMPANY: Readonly<Record<VideoRef['source'], string>> = {\n [VideoSource.YouTube]: 'Google',\n [VideoSource.Vimeo]: 'Vimeo',\n};\n\n/** The two hosts a player ever loads from — youtube-nocookie and Vimeo's player (with Do Not Track). */\nexport const VIDEO_EMBED_ORIGINS: ReadonlyArray<string> = ['https://www.youtube-nocookie.com', 'https://player.vimeo.com'];\n\nconst YOUTUBE_ID = /^[A-Za-z0-9_-]{11}$/;\nconst VIMEO_ID = /^\\d{6,12}$/;\nconst VIMEO_HASH = /^[0-9a-f]{6,20}$/i;\nconst YOUTUBE_HOSTS = new Set(['youtube.com', 'www.youtube.com', 'm.youtube.com', 'music.youtube.com', 'youtube-nocookie.com', 'www.youtube-nocookie.com']);\nconst YOUTUBE_SHORT_HOSTS = new Set(['youtu.be', 'www.youtu.be']);\nconst YOUTUBE_PATH_PREFIXES = ['embed', 'shorts', 'live', 'v'];\nconst VIMEO_HOSTS = new Set(['vimeo.com', 'www.vimeo.com', 'player.vimeo.com']);\n\nfunction toUrl(raw: string): URL | null {\n const text = raw.trim();\n if (!text) return null;\n try {\n return new URL(/^[a-z][a-z0-9+.-]*:\\/\\//i.test(text) ? text : `https://${text}`);\n } catch {\n return null;\n }\n}\n\nfunction parseYouTube(url: URL): VideoRef | null {\n const host = url.hostname.toLowerCase();\n const segments = url.pathname.split('/').filter(Boolean);\n let id: string | null = null;\n if (YOUTUBE_SHORT_HOSTS.has(host)) id = segments[0] ?? null;\n else if (YOUTUBE_HOSTS.has(host)) {\n if (segments[0] === 'watch') id = url.searchParams.get('v');\n else if (YOUTUBE_PATH_PREFIXES.includes(segments[0] ?? '')) id = segments[1] ?? null;\n } else return null;\n return id && YOUTUBE_ID.test(id) ? { source: VideoSource.YouTube, id } : null;\n}\n\nfunction parseVimeo(url: URL): VideoRef | null {\n if (!VIMEO_HOSTS.has(url.hostname.toLowerCase())) return null;\n const segments = url.pathname.split('/').filter(Boolean);\n // player.vimeo.com/video/<id>, vimeo.com/<id>[/<hash>], vimeo.com/channels/<c>/<id>, vimeo.com/groups/<g>/videos/<id>\n const index = segments.findIndex(s => VIMEO_ID.test(s));\n if (index < 0) return null;\n const id = segments[index];\n const hash = url.searchParams.get('h') ?? segments[index + 1];\n return { source: VideoSource.Vimeo, id, ...(hash && VIMEO_HASH.test(hash) ? { hash } : {}) };\n}\n\n/** The embed a pasted address names — a YouTube or Vimeo watch, share, embed or short link — or null. */\nexport function parseVideoUrl(raw: string | null | undefined): VideoRef | null {\n const url = typeof raw === 'string' ? toUrl(raw) : null;\n if (!url || !/^https?:$/.test(url.protocol)) return null;\n return parseYouTube(url) ?? parseVimeo(url);\n}\n\n/** The source a node plays: its declared source when it is one, else what its address is. */\nexport function videoSourceOf(src: unknown, declared?: unknown): VideoSource {\n if (declared === VideoSource.YouTube || declared === VideoSource.Vimeo || declared === VideoSource.File) return declared;\n return parseVideoUrl(typeof src === 'string' ? src : '')?.source ?? VideoSource.File;\n}\n\n/** The player's address — loaded only after a click and a grant. Autoplays (the visitor just pressed play). */\nexport function videoEmbedUrl(ref: VideoRef): string {\n if (ref.source === VideoSource.YouTube) {\n return `https://www.youtube-nocookie.com/embed/${encodeURIComponent(ref.id)}?autoplay=1&rel=0&playsinline=1`;\n }\n return `https://player.vimeo.com/video/${encodeURIComponent(ref.id)}?autoplay=1&dnt=1${ref.hash ? `&h=${encodeURIComponent(ref.hash)}` : ''}`;\n}\n\n/** Where the SERVER fetches an embed's thumbnail to store as the studio's own poster (never the visitor). */\nexport interface VideoThumbnailRequest {\n /** `image`: the url IS the picture; `oembed`: the url answers JSON whose `thumbnail_url` is the picture. */\n kind: 'image' | 'oembed';\n url: string;\n /** The only hosts the picture itself may come from (the server refuses anything else). */\n imageHosts: ReadonlyArray<string>;\n}\n\nexport function videoThumbnailRequest(ref: VideoRef): VideoThumbnailRequest {\n if (ref.source === VideoSource.YouTube) {\n return { kind: 'image', url: `https://i.ytimg.com/vi/${encodeURIComponent(ref.id)}/hqdefault.jpg`, imageHosts: ['i.ytimg.com'] };\n }\n const page = `https://vimeo.com/${ref.id}${ref.hash ? `/${ref.hash}` : ''}`;\n return { kind: 'oembed', url: `https://vimeo.com/api/oembed.json?url=${encodeURIComponent(page)}&width=1280`, imageHosts: ['i.vimeocdn.com'] };\n}\n\n/** A stored poster's object name — one per video, so fetching it again overwrites rather than piles up. */\nexport function videoPosterFileName(ref: VideoRef): string {\n return `video-poster-${ref.source}-${ref.id}.jpg`;\n}\n\n// ── the node, in either shape (saved props / builder traits) ───────────────────────────────────────\n\nexport interface VideoNodeLike {\n type?: string;\n props?: Record<string, unknown> | null;\n traits?: ReadonlyArray<{ name?: string; default?: unknown }> | null;\n}\n\n/** A content value of a Video node, saved (`props`) or builder (`traits[].default`) shape. */\nexport function videoProp(node: VideoNodeLike | null | undefined, name: VideoTrait | string): unknown {\n if (!node) return undefined;\n if (node.props && Object.prototype.hasOwnProperty.call(node.props, name)) return node.props[name];\n return node.traits?.find(t => t?.name === name)?.default;\n}\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\nconst truthy = (v: unknown): boolean => v === true || v === 'true';\n\n/** The consent category an embed waits for — Marketing by default (D5); an uploaded file waits for none. */\nexport function videoConsentCategory(node: VideoNodeLike | null | undefined, source: VideoSource = videoSourceOf(videoProp(node, VideoTrait.Src), videoProp(node, VideoTrait.Source))): ConsentCategory | null {\n if (source === VideoSource.File) return null;\n const declared = videoProp(node, VideoTrait.Consent);\n return declared === ConsentCategory.Analytics ? ConsentCategory.Analytics : ConsentCategory.Marketing;\n}\n\nexport interface VideoPlan {\n kind: VideoKind;\n source: VideoSource;\n /** An embed's provider and id (Facade). */\n ref: VideoRef | null;\n /** An uploaded file's address (File). */\n src: string;\n /** The studio's own poster ('' = the token blank). Never a provider's thumbnail URL. */\n poster: string;\n /** The video's name — the play button's accessible name. */\n title: string;\n mode: VideoMode;\n background: boolean;\n /** Muted autoplay when motion is allowed (the runtime asks; the server never writes `autoplay`). */\n autoplay: boolean;\n muted: boolean;\n loop: boolean;\n controls: boolean;\n /** A `.vtt` file ('' = none). */\n captions: string;\n captionsLang: string;\n /** What the facade waits for (null for a file). */\n consentCategory: ConsentCategory | null;\n /** The visitor's decision grants it. */\n granted: boolean;\n /** The player's address — only when granted (the runtime loads it on a click). */\n embedUrl: string | null;\n /** \"YouTube\" / \"Vimeo\" ('' for a file). */\n providerLabel: string;\n /** Pictures the scroll plays (Frames). */\n frames: FrameSequence | null;\n}\n\n/**\n * The ONE decision for a Video node and a visitor's consent (null = none recorded — the server always passes null,\n * so its HTML is always the facade). A poster that is a provider's thumbnail URL is dropped: the poster is the\n * studio's own image (or the thumbnail the server fetched and stored for it), never a request to a third party.\n */\nexport function planVideo(node: VideoNodeLike | null | undefined, consent: ConsentDecision | null): VideoPlan {\n const frames = normalizeFrameSequence(videoProp(node, VideoTrait.Frames));\n if (frames) return planFrames(node, frames);\n const rawSrc = str(videoProp(node, VideoTrait.Src));\n const source = videoSourceOf(rawSrc, videoProp(node, VideoTrait.Source));\n const ref = source === VideoSource.File ? null : parseVideoUrl(rawSrc);\n const background = source === VideoSource.File && videoProp(node, VideoTrait.Mode) === VideoMode.Background;\n const consentCategory = videoConsentCategory(node, source);\n const granted = consentCategory ? hasConsent(consent, consentCategory) : true;\n const kind = source === VideoSource.File ? (rawSrc ? VideoKind.File : VideoKind.Empty) : (ref ? VideoKind.Facade : VideoKind.Empty);\n const poster = str(videoProp(node, VideoTrait.Poster));\n return {\n kind,\n source,\n ref,\n src: source === VideoSource.File ? rawSrc : '',\n poster: isThirdPartyPoster(poster) ? '' : poster,\n title: str(videoProp(node, VideoTrait.Title)),\n mode: background ? VideoMode.Background : VideoMode.Inline,\n background,\n autoplay: background || (source === VideoSource.File && truthy(videoProp(node, VideoTrait.Autoplay))),\n muted: background || truthy(videoProp(node, VideoTrait.Autoplay)),\n loop: background,\n controls: !background,\n captions: background ? '' : str(videoProp(node, VideoTrait.Captions)),\n captionsLang: str(videoProp(node, VideoTrait.CaptionsLang)) || 'en',\n consentCategory,\n granted,\n embedUrl: kind === VideoKind.Facade && granted && ref ? videoEmbedUrl(ref) : null,\n providerLabel: ref ? VIDEO_PROVIDER_LABEL[ref.source] : '',\n frames: null,\n };\n}\n\n/** Pictures win over any address the node also holds: it was turned into them. No player, no consent, nothing to press. */\nfunction planFrames(node: VideoNodeLike | null | undefined, frames: FrameSequence): VideoPlan {\n const poster = str(videoProp(node, VideoTrait.Poster));\n return {\n kind: VideoKind.Frames,\n source: VideoSource.File,\n ref: null,\n src: '',\n poster: poster && !isThirdPartyPoster(poster) ? poster : frameUrl(frames, FrameSet.Wide, 0),\n title: str(videoProp(node, VideoTrait.Title)),\n mode: VideoMode.Inline,\n background: false,\n autoplay: false,\n muted: false,\n loop: false,\n controls: false,\n captions: '',\n captionsLang: 'en',\n consentCategory: null,\n granted: true,\n embedUrl: null,\n providerLabel: '',\n frames,\n };\n}\n\nconst THIRD_PARTY_POSTER_HOSTS = ['ytimg.com', 'youtube.com', 'vimeocdn.com', 'vimeo.com', 'googleusercontent.com'];\n\n/** A poster served by the video's provider — a request to a third party before consent, so it never renders. */\nexport function isThirdPartyPoster(url: string): boolean {\n const parsed = url ? toUrl(url) : null;\n if (!parsed || !/^https?:$/.test(parsed.protocol)) return false;\n const host = parsed.hostname.toLowerCase();\n return THIRD_PARTY_POSTER_HOSTS.some(h => host === h || host.endsWith(`.${h}`));\n}\n\n// ── words ───────────────────────────────────────────────────────────────────────────────────────────\n\n/**\n * The words the renderer draws (board 5; Q7: the consent prompt is NOT an editable part — its words are the\n * consent vocabulary's, one source, translated). English and Hebrew; the page's `lang` picks.\n */\nexport interface VideoWords {\n /** The play button's name: the video's title and its provider. */\n play(title: string, provider: string): string;\n /** The play button's name with no title. */\n playUntitled(provider: string): string;\n pauseBackground: string;\n playBackground: string;\n /** The consent prompt (a group): its name, its lead and its body. */\n promptLabel: string;\n promptLead(provider: string): string;\n promptBody(company: string): string;\n /** The same prompt where the player is narrow (board 5's phone): one shorter sentence, its lead in bold. */\n promptCompactLead(provider: string): string;\n promptCompactBody: string;\n allow: string;\n settings: string;\n}\n\nexport const VIDEO_WORDS: Readonly<Record<'en' | 'he', VideoWords>> = {\n en: {\n play: (title, provider) => (provider ? `Play: ${title} (${provider})` : `Play: ${title}`),\n playUntitled: provider => (provider ? `Play video (${provider})` : 'Play video'),\n pauseBackground: 'Pause background video',\n playBackground: 'Play background video',\n promptLabel: 'This video needs your permission',\n promptLead: provider => `This video is hosted by ${provider}.`,\n promptBody: company => `Playing it lets ${company} set cookies and see your IP address. Nothing has loaded yet.`,\n promptCompactLead: provider => `Plays from ${provider},`,\n promptCompactBody: 'which sets cookies and sees your IP address. Nothing has loaded yet.',\n allow: 'Allow and play',\n settings: 'Privacy settings',\n },\n he: {\n play: (title, provider) => (provider ? `הפעלה: ${title} (${provider})` : `הפעלה: ${title}`),\n playUntitled: provider => (provider ? `הפעלת הסרטון (${provider})` : 'הפעלת הסרטון'),\n pauseBackground: 'השהיית סרטון הרקע',\n playBackground: 'הפעלת סרטון הרקע',\n promptLabel: 'הסרטון הזה צריך את רשותך',\n promptLead: provider => `הסרטון מתארח ב-${provider}.`,\n promptBody: company => `ההפעלה מאפשרת ל-${company} להגדיר קובצי Cookie ולראות את כתובת ה-IP שלך. עדיין לא נטען דבר.`,\n promptCompactLead: provider => `מתנגן מ-${provider},`,\n promptCompactBody: 'שמגדיר קובצי Cookie ורואה את כתובת ה-IP שלך. עדיין לא נטען דבר.',\n allow: 'לאשר ולהפעיל',\n settings: 'הגדרות פרטיות',\n },\n};\n\n/** The words for a page language (`he`, `he-IL` → Hebrew; anything else → English). */\nexport function videoWords(lang?: string | null): VideoWords {\n return (lang ?? '').toLowerCase().startsWith('he') ? VIDEO_WORDS.he : VIDEO_WORDS.en;\n}\n\n/** The play button's accessible name. */\nexport function videoPlayLabel(plan: VideoPlan, words: VideoWords = VIDEO_WORDS.en): string {\n return plan.title ? words.play(plan.title, plan.providerLabel) : words.playUntitled(plan.providerLabel);\n}\n\n// ── markup (one builder for both engine paths and the canvas) ────────────────────────────────────────\n\nexport enum VideoClass {\n Root = 'iox-video',\n Poster = 'iox-video__poster',\n Play = 'iox-video__play',\n Badge = 'iox-video__badge',\n Media = 'iox-video__media',\n Frame = 'iox-video__frame',\n Toggle = 'iox-video__toggle',\n Consent = 'iox-video__consent',\n ConsentText = 'iox-video__consent-text',\n /** The prompt's text on a wide player / on a narrow one (a container query shows one). */\n ConsentWide = 'iox-video__consent-wide',\n ConsentCompact = 'iox-video__consent-compact',\n ConsentRow = 'iox-video__consent-row',\n Allow = 'iox-video__allow',\n Settings = 'iox-video__settings',\n}\n\nexport enum VideoAttribute {\n /** On the node element: its kind (`file` · `facade` · `empty`) — what the runtime attaches to. */\n Root = 'data-iox-video',\n Source = 'data-iox-video-source',\n Id = 'data-iox-video-id',\n Hash = 'data-iox-video-hash',\n Mode = 'data-iox-video-mode',\n Autoplay = 'data-iox-video-autoplay',\n Consent = 'data-iox-video-consent',\n Title = 'data-iox-video-title',\n /** The poster is the token blank (no image): the shared CSS fills it with `surface-2`. */\n PosterEmpty = 'data-iox-video-poster-empty',\n /** The player is loaded (after the click and the grant). */\n Playing = 'data-iox-video-playing',\n /** The consent prompt is showing. */\n Asking = 'data-iox-video-asking',\n /** The pictures the scroll plays, as JSON: what the driver reads, so it needs no node tree. */\n Frames = 'data-iox-video-frames',\n}\n\nexport enum VideoIcon {\n Play = 'ph-fill ph-play',\n Pause = 'ph-fill ph-pause',\n}\n\n/** The attributes the node's own element carries (both engine paths, the canvas). */\nexport function videoRootAttributes(plan: VideoPlan): Record<string, string> {\n const attrs: Record<string, string> = { [VideoAttribute.Root]: plan.kind, [VideoAttribute.Source]: plan.source };\n if (plan.ref) {\n attrs[VideoAttribute.Id] = plan.ref.id;\n if (plan.ref.hash) attrs[VideoAttribute.Hash] = plan.ref.hash;\n }\n if (plan.background) attrs[VideoAttribute.Mode] = VideoMode.Background;\n if (plan.autoplay) attrs[VideoAttribute.Autoplay] = '';\n if (plan.consentCategory) attrs[VideoAttribute.Consent] = plan.consentCategory;\n if (plan.title) attrs[VideoAttribute.Title] = plan.title;\n if (!plan.poster) attrs[VideoAttribute.PosterEmpty] = '';\n if (plan.frames) attrs[VideoAttribute.Frames] = JSON.stringify(plan.frames);\n return attrs;\n}\n\nexport interface VideoMarkupOptions {\n /** HTML-escape an attribute or text value. */\n esc: (value: string) => string;\n /** The builder canvas: the poster ONLY — no `<video>`, no player, nothing that loads or takes a click. */\n canvas?: boolean;\n words?: VideoWords;\n}\n\nconst iconHtml = (cls: string) => `<i class=\"${cls}\" aria-hidden=\"true\"></i>`;\n\n/** The element's inner markup. The server's HTML for a facade holds no `<iframe>` and requests nothing from\n * the provider: only the studio's poster, the play button and the (hidden) consent prompt. */\nexport function videoInnerHtml(plan: VideoPlan, options: VideoMarkupOptions): string {\n const { esc } = options;\n const words = options.words ?? VIDEO_WORDS.en;\n // The same on the canvas and on the site: the first picture is real content, so it is fetched at once, named, and the\n // size a phone needs. A driver's canvas covers it when pictures arrive; with no script it is what there is.\n if (plan.kind === VideoKind.Frames) {\n const own = !!plan.frames && !isAuthoredPoster(plan);\n const srcset = own ? phoneFrameSrcset(plan.frames!) : '';\n // Its real size, so where a Scene flows (reduced motion, no script) the picture holds its height before it loads.\n const size = own ? ` width=\"${plan.frames!.wide.width}\" height=\"${plan.frames!.wide.height}\"` : '';\n const image = (attrs: string): string => `<img class=\"${VideoClass.Poster}\" src=\"${esc(plan.poster)}\"${attrs} alt=\"${esc(plan.title)}\" decoding=\"async\">`;\n // A phone film is framed for a tall screen, so it is chosen by the screen, never by the pixels a high-density phone asks for.\n if (own && plan.frames!.phoneBase) {\n const { width, height } = plan.frames!.phone!;\n return `<picture><source media=\"(max-width: ${FRAMES_PHONE_MAX_WIDTH}px)\" srcset=\"${esc(frameUrl(plan.frames!, FrameSet.Phone, 0))}\" width=\"${width}\" height=\"${height}\">${image(size)}</picture>`;\n }\n return image(`${srcset ? ` srcset=\"${esc(srcset)}\" sizes=\"100vw\"` : ''}${size}`);\n }\n const poster = plan.poster ? `<img class=\"${VideoClass.Poster}\" src=\"${esc(plan.poster)}\" alt=\"\" loading=\"lazy\" decoding=\"async\">` : '';\n const label = esc(videoPlayLabel(plan, words));\n const playSpan = `<span class=\"${VideoClass.Play}\" aria-hidden=\"true\">${iconHtml(VideoIcon.Play)}</span>`;\n const badge = plan.providerLabel ? `<span class=\"${VideoClass.Badge}\">${iconHtml(VideoIcon.Play)}${esc(plan.providerLabel)}</span>` : '';\n\n if (options.canvas || plan.kind === VideoKind.Empty) {\n return `${poster}${plan.kind === VideoKind.Empty && !options.canvas ? '' : playSpan}${badge}`;\n }\n\n if (plan.kind === VideoKind.File) {\n const media = [\n `<video class=\"${VideoClass.Media}\" src=\"${esc(plan.src)}\" preload=\"metadata\" playsinline`,\n plan.poster ? ` poster=\"${esc(plan.poster)}\"` : '',\n // A captions file is fetched with CORS (a <track> from another origin loads only so): the studio's bucket\n // answers CORS for every object, the video included.\n plan.captions ? ' crossorigin=\"anonymous\"' : '',\n plan.controls ? ' controls' : '',\n plan.muted ? ' muted' : '',\n plan.loop ? ' loop' : '',\n plan.background ? ' aria-hidden=\"true\" tabindex=\"-1\"' : (plan.title ? ` aria-label=\"${esc(plan.title)}\"` : ''),\n '>',\n plan.captions ? `<track kind=\"captions\" src=\"${esc(plan.captions)}\" srclang=\"${esc(plan.captionsLang)}\" label=\"${esc(plan.captionsLang)}\" default>` : '',\n '</video>',\n ].join('');\n if (plan.background) {\n // Rendered paused (the server cannot know the visitor's motion setting): the runtime starts it when motion\n // is allowed and turns this into the PAUSE button. Always visible (WCAG 2.2.2).\n return `${media}<button type=\"button\" class=\"${VideoClass.Toggle}\" aria-label=\"${esc(words.playBackground)}\" aria-pressed=\"true\">${iconHtml(VideoIcon.Play)}</button>`;\n }\n return `${media}<button type=\"button\" class=\"${VideoClass.Play}\" aria-label=\"${label}\">${iconHtml(VideoIcon.Play)}</button>`;\n }\n\n const company = plan.ref ? VIDEO_PROVIDER_COMPANY[plan.ref.source] : '';\n const prompt = `<div class=\"${VideoClass.Consent}\" role=\"group\" aria-label=\"${esc(words.promptLabel)}\" hidden>` +\n `<p class=\"${VideoClass.ConsentText} ${VideoClass.ConsentWide}\"><b>${esc(words.promptLead(plan.providerLabel))}</b> ${esc(words.promptBody(company))}</p>` +\n `<p class=\"${VideoClass.ConsentText} ${VideoClass.ConsentCompact}\"><b>${esc(words.promptCompactLead(plan.providerLabel))}</b> ${esc(words.promptCompactBody)}</p>` +\n `<div class=\"${VideoClass.ConsentRow}\">` +\n `<button type=\"button\" class=\"${VideoClass.Allow}\">${esc(words.allow)}</button>` +\n `<button type=\"button\" class=\"${VideoClass.Settings}\">${esc(words.settings)}</button>` +\n `</div></div>`;\n return `${poster}<button type=\"button\" class=\"${VideoClass.Play}\" aria-label=\"${label}\">${iconHtml(VideoIcon.Play)}</button>${badge}${prompt}`;\n}\n\nconst isAuthoredPoster = (plan: VideoPlan): boolean => !!plan.frames && plan.poster !== frameUrl(plan.frames, FrameSet.Wide, 0);\n\n/** Serialise attributes for a string renderer (a present boolean attribute is written bare). */\nexport function serializeVideoAttributes(attrs: Readonly<Record<string, string>>, esc: (value: string) => string): string {\n return Object.entries(attrs).map(([name, value]) => (value === '' ? ` ${name}` : ` ${name}=\"${esc(value)}\"`)).join('');\n}\n","import {\n CONSENT_COOKIE_NAME, ConsentCategory, ConsentDecision, cookieAttributes, decode, encode, hasConsent, setCategoryDecision,\n} from '@vectoriox/iox-ui/consent-core';\n\nimport { VIDEO_PROVIDER_LABEL, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRef, VideoSource, videoEmbedUrl, VideoWords, videoWords } from './video';\n\n/**\n * The Video's RUNTIME (CC3, board 5) — DOM only, ONE copy for both engine paths (the component path attaches it from\n * its component, the string path from the page's interaction service; `attachVideoAt` is idempotent). It reads the\n * markup `videoInnerHtml` writes. The builder canvas never attaches it (the canvas shows the poster only).\n *\n * - FACADE: play → the visitor's consent grants the category → the player's `<iframe>` replaces the poster, focused,\n * autoplaying (the visitor just pressed play). Not granted → the consent prompt: \"Allow and play\" grants the\n * category in the site's ONE consent record (the banner and its preferences read the same cookie) and plays;\n * \"Privacy settings\" opens the site's own preferences dialog.\n * - FILE: the play button starts the `<video>`; muted autoplay only when motion is allowed.\n * - BACKGROUND: muted and looped; it plays only when motion is allowed (never under reduced motion), and its\n * pause button is always there (WCAG 2.2.2).\n */\n\n/** Ask the page to record a category the visitor granted (cancelable: the site's consent service handles it). */\nexport const CONSENT_GRANT_EVENT = 'iox-consent-grant';\n/** Ask the page to open its consent preferences (cancelable: handled = a dialog opened). */\nexport const CONSENT_PREFERENCES_EVENT = 'iox-consent-preferences';\n\nexport interface ConsentGrantDetail { category: ConsentCategory }\n\n/** How the runtime reads and writes the visitor's ONE consent record — the page's transport. */\nexport interface ConsentTransport {\n read(): ConsentDecision | null;\n /** Record the category as granted (synchronously, before the player loads). */\n grant(category: ConsentCategory): void;\n /** Open the site's privacy preferences; false when the page has none. */\n openPreferences(): boolean;\n}\n\nconst REDUCED_MOTION = '(prefers-reduced-motion: reduce)';\nconst RUNTIME_KEY = '__ioxVideo';\nconst IFRAME_ALLOW = 'autoplay; encrypted-media; picture-in-picture; fullscreen';\n\n/** The cookie the consent record lives in, read from a document. */\nexport function readConsentRecord(doc: Document): ConsentDecision | null {\n const raw = (doc.cookie ?? '').split('; ').find(c => c.startsWith(`${CONSENT_COOKIE_NAME}=`));\n return decode(raw ? decodeURIComponent(raw.slice(CONSENT_COOKIE_NAME.length + 1)) : null);\n}\n\n/**\n * The default transport: the page's own consent service answers the events (the engine records the decision, tells\n * Consent Mode, re-syncs the banner's switches); a page with no such service (the admin's Preview) records the cookie\n * itself, through the same consent-core decision, so the record is the same shape either way.\n */\nexport function documentConsentTransport(doc: Document): ConsentTransport {\n return {\n read: () => readConsentRecord(doc),\n grant: category => {\n const event = new CustomEvent<ConsentGrantDetail>(CONSENT_GRANT_EVENT, { detail: { category }, cancelable: true });\n doc.dispatchEvent(event);\n if (event.defaultPrevented) return;\n const previous = readConsentRecord(doc);\n const anonymousId = previous?.anonymousId ?? randomId();\n const decision = setCategoryDecision(previous, category, true, anonymousId, previous?.policyVersion ?? '1');\n const secure = doc.location?.protocol === 'https:';\n doc.cookie = `${CONSENT_COOKIE_NAME}=${encodeURIComponent(encode(decision))}; ${cookieAttributes(12, secure)}`;\n },\n openPreferences: () => {\n const event = new CustomEvent(CONSENT_PREFERENCES_EVENT, { cancelable: true });\n doc.dispatchEvent(event);\n return event.defaultPrevented;\n },\n };\n}\n\nfunction randomId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n return c?.randomUUID ? c.randomUUID() : Math.random().toString(36).slice(2);\n}\n\nexport interface VideoRuntimeOptions {\n consent?: ConsentTransport;\n /** True to stop motion (default: the visitor's reduced-motion setting). */\n reducedMotion?: () => boolean;\n words?: VideoWords;\n}\n\n/** The embed a facade root names (its provider, id and hash attributes). */\nexport function videoRefOf(root: Element): VideoRef | null {\n const source = root.getAttribute(VideoAttribute.Source);\n const id = root.getAttribute(VideoAttribute.Id);\n if ((source !== VideoSource.YouTube && source !== VideoSource.Vimeo) || !id) return null;\n const hash = root.getAttribute(VideoAttribute.Hash);\n return { source, id, ...(hash ? { hash } : {}) };\n}\n\nexport class VideoRuntime {\n private readonly cleanups: Array<() => void> = [];\n private readonly consent: ConsentTransport;\n private readonly reduced: () => boolean;\n private readonly words: VideoWords;\n private readonly doc: Document;\n\n constructor(readonly root: HTMLElement, options: VideoRuntimeOptions = {}) {\n this.doc = root.ownerDocument;\n this.consent = options.consent ?? documentConsentTransport(this.doc);\n const view = this.doc.defaultView;\n this.reduced = options.reducedMotion ?? (() => !!view?.matchMedia?.(REDUCED_MOTION)?.matches);\n this.words = options.words ?? videoWords(this.doc.documentElement?.getAttribute('lang'));\n const kind = root.getAttribute(VideoAttribute.Root);\n if (kind === VideoKind.Facade) this.attachFacade();\n else if (kind === VideoKind.File) this.attachFile();\n }\n\n destroy(): void {\n this.cleanups.splice(0).forEach(fn => fn());\n delete (this.root as unknown as Record<string, unknown>)[RUNTIME_KEY];\n }\n\n /** The category a facade waits for (Marketing unless the node named another). */\n private get category(): ConsentCategory {\n const declared = this.root.getAttribute(VideoAttribute.Consent);\n return declared === ConsentCategory.Analytics ? ConsentCategory.Analytics : ConsentCategory.Marketing;\n }\n\n private on(el: Element | null, type: string, fn: (e: Event) => void): void {\n if (!el) return;\n el.addEventListener(type, fn);\n this.cleanups.push(() => el.removeEventListener(type, fn));\n }\n\n // ── facade ────────────────────────────────────────────────────────────────────────────────────\n\n private attachFacade(): void {\n const play = this.root.querySelector<HTMLButtonElement>(`button.${VideoClass.Play}`);\n const allow = this.root.querySelector<HTMLButtonElement>(`.${VideoClass.Allow}`);\n const settings = this.root.querySelector<HTMLButtonElement>(`.${VideoClass.Settings}`);\n this.on(play, 'click', () => this.requestPlay());\n this.on(allow, 'click', () => {\n this.consent.grant(this.category);\n this.loadPlayer();\n });\n this.on(settings, 'click', () => { this.consent.openPreferences(); });\n }\n\n /** Play pressed: the player when the category is granted, else the consent prompt. */\n requestPlay(): void {\n if (hasConsent(this.consent.read(), this.category)) {\n this.loadPlayer();\n return;\n }\n const prompt = this.root.querySelector<HTMLElement>(`.${VideoClass.Consent}`);\n if (!prompt) return;\n prompt.hidden = false;\n this.root.setAttribute(VideoAttribute.Asking, '');\n const play = this.root.querySelector<HTMLElement>(`button.${VideoClass.Play}`);\n if (play) play.hidden = true;\n this.root.querySelector<HTMLElement>(`.${VideoClass.Allow}`)?.focus();\n }\n\n /** The player — created only now, after the click and the grant. */\n loadPlayer(): void {\n const ref = videoRefOf(this.root);\n if (!ref || this.root.hasAttribute(VideoAttribute.Playing)) return;\n const frame = this.doc.createElement('iframe');\n frame.className = VideoClass.Frame;\n frame.src = videoEmbedUrl(ref);\n frame.title = this.root.getAttribute(VideoAttribute.Title) || this.words.playUntitled(VIDEO_PROVIDER_LABEL[ref.source]);\n frame.setAttribute('allow', IFRAME_ALLOW);\n frame.setAttribute('allowfullscreen', '');\n frame.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');\n this.root.replaceChildren(frame);\n this.root.removeAttribute(VideoAttribute.Asking);\n this.root.setAttribute(VideoAttribute.Playing, '');\n frame.focus();\n }\n\n // ── uploaded file ─────────────────────────────────────────────────────────────────────────────\n\n private attachFile(): void {\n const video = this.root.querySelector<HTMLVideoElement>(`video.${VideoClass.Media}`);\n if (!video) return;\n if (this.root.getAttribute(VideoAttribute.Mode) === VideoMode.Background) {\n this.attachBackground(video);\n return;\n }\n const play = this.root.querySelector<HTMLButtonElement>(`button.${VideoClass.Play}`);\n const hidePlay = () => { if (play) play.hidden = true; };\n this.on(play, 'click', () => { hidePlay(); void video.play()?.catch?.(() => undefined); video.focus(); });\n this.on(video, 'play', hidePlay);\n // Autoplay (muted) only while motion is allowed — never under reduced motion.\n if (this.root.hasAttribute(VideoAttribute.Autoplay) && !this.reduced()) {\n video.muted = true;\n void video.play()?.catch?.(() => undefined);\n }\n }\n\n private attachBackground(video: HTMLVideoElement): void {\n const toggle = this.root.querySelector<HTMLButtonElement>(`.${VideoClass.Toggle}`);\n video.muted = true;\n const sync = () => {\n const paused = video.paused;\n if (!toggle) return;\n toggle.setAttribute('aria-pressed', paused ? 'true' : 'false');\n toggle.setAttribute('aria-label', paused ? this.words.playBackground : this.words.pauseBackground);\n const icon = toggle.querySelector('i');\n if (icon) icon.className = paused ? VideoIcon.Play : VideoIcon.Pause;\n };\n this.on(video, 'play', sync);\n this.on(video, 'pause', sync);\n this.on(toggle, 'click', () => {\n if (video.paused) void video.play()?.catch?.(() => undefined);\n else video.pause();\n sync();\n });\n // It moves only when motion is allowed; under reduced motion it rests on its poster, paused.\n if (!this.reduced()) void video.play()?.catch?.(() => sync());\n sync();\n }\n}\n\n/** Run the video at `el` (a `[data-iox-video]` element) once; null when it is not one or already runs. */\nexport function attachVideoAt(el: HTMLElement | null | undefined, options: VideoRuntimeOptions = {}): VideoRuntime | null {\n if (!el?.hasAttribute?.(VideoAttribute.Root)) return null;\n const host = el as unknown as Record<string, unknown>;\n if (host[RUNTIME_KEY]) return null;\n const runtime = new VideoRuntime(el, options);\n host[RUNTIME_KEY] = runtime;\n return runtime;\n}\n\n/** Every video under `container` that is not running yet (the string path's globals and pages). */\nexport function attachVideos(container: ParentNode, options: VideoRuntimeOptions = {}): VideoRuntime[] {\n return Array.from(container.querySelectorAll<HTMLElement>(`[${VideoAttribute.Root}]`))\n .map(el => attachVideoAt(el, options))\n .filter((r): r is VideoRuntime => !!r);\n}\n\n/** The runtime already running at `el`, if any. */\nexport function videoRuntimeOf(el: Element | null | undefined): VideoRuntime | null {\n return ((el as unknown as Record<string, unknown> | null)?.[RUNTIME_KEY] as VideoRuntime | undefined) ?? null;\n}\n","/**\n * @vectoriox/iox-ui/media-core — media decisions shared by the builder, both engine paths and iox-cms (CC3).\n * FRAMEWORK-FREE: `planVideo` is the one place that knows a YouTube / Vimeo address, the player's host and the consent\n * category a facade waits for; the runtime is DOM-only. iox-cms reads `parseVideoUrl` / `videoThumbnailRequest` to\n * fetch and store an embed's poster (the visitor never asks the provider for it).\n * ⚠️ Consumers wire the usual trio — ng-package raw-ts assets, jest moduleNameMapper, tsconfig paths.\n */\nexport * from './frames';\nexport * from './video';\nexport * from './video-runtime';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -85,6 +85,16 @@ declare function frameIndexAt(played: number, count: number): number;
85
85
  declare function frameLoadOrder(count: number): number[];
86
86
  /** The loaded picture nearest `index`, or -1 when none has arrived. Ties go backward: the picture already passed. */
87
87
  declare function nearestLoadedFrame(loaded: ReadonlyArray<unknown>, index: number): number;
88
+ /**
89
+ * How much unpacked picture one player holds at once. A browser keeps few of 300 unpacked pictures (a wide set is 1.7 GB
90
+ * unpacked) and unpacked again on the page's own thread, at the moment of drawing, 22 ms a 1600×900 picture: longer than a
91
+ * whole frame, so the film and the page beside it skipped a beat for every new picture (Doron's recording, 2026-11-04).
92
+ */
93
+ declare const FRAMES_UNPACKED_BYTES: number;
94
+ /** How many pictures of `width`×`height` a player holds unpacked. */
95
+ declare function unpackedFrameCount(width: number, height: number): number;
96
+ /** The `size` pictures to hold unpacked around `position`, nearest first, each side in turn starting ahead. */
97
+ declare function framesToHold(position: number, count: number, size: number): number[];
88
98
  interface FrameSizes {
89
99
  width: number;
90
100
  height: number;
@@ -125,6 +135,11 @@ interface FramePlayerOptions {
125
135
  * The player: draws the picture nearest what the scroll asked for on a canvas laid over the poster, and nothing until a
126
136
  * first picture has arrived, so the poster is what a visitor sees until then, and for good if the pictures never come.
127
137
  * Browser only. It writes and never reads, so the driver can call it in its write phase.
138
+ *
139
+ * Each picture is downloaded as a file and unpacked off the page's thread (`createImageBitmap` of the file), a window of
140
+ * them around where the film stands, so drawing one never waits for it. A browser that cannot (no `fetch` or
141
+ * `createImageBitmap`, or storage that refuses the download) plays from `<img>` pictures, as before: it works, and pays the
142
+ * unpacking on the page's thread.
128
143
  */
129
144
  declare class FramePlayer {
130
145
  private readonly el;
@@ -132,9 +147,14 @@ declare class FramePlayer {
132
147
  private played;
133
148
  private readonly set;
134
149
  private readonly info;
135
- private readonly images;
150
+ /** What a draw may use: an unpacked picture, or an `<img>` on a browser that plays from them. */
151
+ private readonly ready;
152
+ /** The downloaded files, unpacked when the film comes near them. */
153
+ private readonly files;
136
154
  private readonly order;
137
155
  private readonly host;
156
+ private readonly holdCount;
157
+ private fromFiles;
138
158
  private observer;
139
159
  private canvas;
140
160
  private context;
@@ -143,7 +163,11 @@ declare class FramePlayer {
143
163
  private loading;
144
164
  private started;
145
165
  private destroyed;
166
+ private held;
167
+ private readonly unpacked;
168
+ private readonly unpacking;
146
169
  private readonly pending;
170
+ private readonly downloads;
147
171
  constructor(el: HTMLElement, sequence: FrameSequence, options?: FramePlayerOptions);
148
172
  /**
149
173
  * Stand at `played` %, exactly. The film keeps no motion of its own: the scroll's glide, and the slowing at its end,
@@ -156,7 +180,12 @@ declare class FramePlayer {
156
180
  private allowed;
157
181
  private start;
158
182
  private pump;
159
- private load;
183
+ private loaded;
184
+ private download;
185
+ private loadImage;
186
+ /** Unpack the pictures around where the film stands, nearest first, and let go of the ones it has left. */
187
+ private hold;
188
+ private unpack;
160
189
  private draw;
161
190
  private ensureCanvas;
162
191
  }
@@ -442,5 +471,5 @@ declare function attachVideos(container: ParentNode, options?: VideoRuntimeOptio
442
471
  /** The runtime already running at `el`, if any. */
443
472
  declare function videoRuntimeOf(el: Element | null | undefined): VideoRuntime | null;
444
473
 
445
- export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT, FRAMES_PHONE_MAX_WIDTH, FRAMES_SHOWING_ATTRIBUTE, FRAME_BLEND_STEPS, FRAME_SEQUENCE_ID, FrameExtension, FramePlayer, FrameSet, FramesClass, MAX_FRAMES, MAX_FRAME_BYTES, PHONE_LONG_SIDE, VIDEO_EMBED_ORIGINS, VIDEO_NODE_TYPE, VIDEO_PROVIDER_COMPANY, VIDEO_PROVIDER_LABEL, VIDEO_WORDS, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRuntime, VideoSource, VideoTrait, WIDE_LONG_SIDE, attachVideoAt, attachVideos, documentConsentTransport, fittedFrameSize, frameBlendAt, frameFileName, frameIndexAt, frameLoadOrder, framePosition, frameSetFor, frameSummary, frameUrl, isThirdPartyPoster, nearestLoadedFrame, normalizeFrameSequence, parseVideoUrl, phoneFrameCount, phoneFrameSrcset, planVideo, readConsentRecord, sampledFrameIndexes, serializeVideoAttributes, sortFrameFiles, videoConsentCategory, videoEmbedUrl, videoFrameCount, videoInnerHtml, videoPlayLabel, videoPosterFileName, videoProp, videoRefOf, videoRootAttributes, videoRuntimeOf, videoSourceOf, videoThumbnailRequest, videoWords };
474
+ export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT, FRAMES_PHONE_MAX_WIDTH, FRAMES_SHOWING_ATTRIBUTE, FRAMES_UNPACKED_BYTES, FRAME_BLEND_STEPS, FRAME_SEQUENCE_ID, FrameExtension, FramePlayer, FrameSet, FramesClass, MAX_FRAMES, MAX_FRAME_BYTES, PHONE_LONG_SIDE, VIDEO_EMBED_ORIGINS, VIDEO_NODE_TYPE, VIDEO_PROVIDER_COMPANY, VIDEO_PROVIDER_LABEL, VIDEO_WORDS, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRuntime, VideoSource, VideoTrait, WIDE_LONG_SIDE, attachVideoAt, attachVideos, documentConsentTransport, fittedFrameSize, frameBlendAt, frameFileName, frameIndexAt, frameLoadOrder, framePosition, frameSetFor, frameSummary, frameUrl, framesToHold, isThirdPartyPoster, nearestLoadedFrame, normalizeFrameSequence, parseVideoUrl, phoneFrameCount, phoneFrameSrcset, planVideo, readConsentRecord, sampledFrameIndexes, serializeVideoAttributes, sortFrameFiles, unpackedFrameCount, videoConsentCategory, videoEmbedUrl, videoFrameCount, videoInnerHtml, videoPlayLabel, videoPosterFileName, videoProp, videoRefOf, videoRootAttributes, videoRuntimeOf, videoSourceOf, videoThumbnailRequest, videoWords };
446
475
  export type { ConsentGrantDetail, ConsentTransport, FrameBlend, FramePlayerOptions, FrameSequence, FrameSetInfo, FrameSizes, VideoMarkupOptions, VideoNodeLike, VideoPlan, VideoRef, VideoRuntimeOptions, VideoThumbnailRequest, VideoWords };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectoriox/iox-ui",
3
- "version": "5.76.0",
3
+ "version": "5.76.1",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=20.0.0",
6
6
  "@angular/core": ">=20.0.0",
@@ -172,6 +172,31 @@ export function nearestLoadedFrame(loaded: ReadonlyArray<unknown>, index: number
172
172
  return -1;
173
173
  }
174
174
 
175
+ /**
176
+ * How much unpacked picture one player holds at once. A browser keeps few of 300 unpacked pictures (a wide set is 1.7 GB
177
+ * unpacked) and unpacked again on the page's own thread, at the moment of drawing, 22 ms a 1600×900 picture: longer than a
178
+ * whole frame, so the film and the page beside it skipped a beat for every new picture (Doron's recording, 2026-11-04).
179
+ */
180
+ export const FRAMES_UNPACKED_BYTES = 96 * 1024 * 1024;
181
+ const MIN_UNPACKED = 6;
182
+ const MAX_UNPACKED = 24;
183
+
184
+ /** How many pictures of `width`×`height` a player holds unpacked. */
185
+ export function unpackedFrameCount(width: number, height: number): number {
186
+ return Math.min(MAX_UNPACKED, Math.max(MIN_UNPACKED, Math.floor(FRAMES_UNPACKED_BYTES / (width * height * 4))));
187
+ }
188
+
189
+ /** The `size` pictures to hold unpacked around `position`, nearest first, each side in turn starting ahead. */
190
+ export function framesToHold(position: number, count: number, size: number): number[] {
191
+ const from = Math.min(count - 1, Math.max(0, Math.floor(position)));
192
+ const held: number[] = [from];
193
+ for (let distance = 1; held.length < Math.min(size, count); distance++) {
194
+ if (from + distance < count) held.push(from + distance);
195
+ if (from - distance >= 0 && held.length < size) held.push(from - distance);
196
+ }
197
+ return held;
198
+ }
199
+
175
200
  export interface FrameSizes {
176
201
  width: number;
177
202
  height: number;
@@ -226,6 +251,7 @@ export enum FramesClass {
226
251
  }
227
252
 
228
253
  const LOAD_CONCURRENCY = 6;
254
+ const UNPACK_CONCURRENCY = 4;
229
255
  const NEAR_MARGIN = '100% 0px';
230
256
  /** Under these the visitor keeps the poster: nobody on a metered 2G connection asked to download a film. */
231
257
  const SLOW_CONNECTIONS: ReadonlySet<string> = new Set(['slow-2g', '2g']);
@@ -248,14 +274,24 @@ export interface FramePlayerOptions {
248
274
  * The player: draws the picture nearest what the scroll asked for on a canvas laid over the poster, and nothing until a
249
275
  * first picture has arrived, so the poster is what a visitor sees until then, and for good if the pictures never come.
250
276
  * Browser only. It writes and never reads, so the driver can call it in its write phase.
277
+ *
278
+ * Each picture is downloaded as a file and unpacked off the page's thread (`createImageBitmap` of the file), a window of
279
+ * them around where the film stands, so drawing one never waits for it. A browser that cannot (no `fetch` or
280
+ * `createImageBitmap`, or storage that refuses the download) plays from `<img>` pictures, as before: it works, and pays the
281
+ * unpacking on the page's thread.
251
282
  */
252
283
  export class FramePlayer {
253
284
  private played: number | null = null;
254
285
  private readonly set: FrameSet;
255
286
  private readonly info: FrameSetInfo;
256
- private readonly images: Array<HTMLImageElement | null>;
287
+ /** What a draw may use: an unpacked picture, or an `<img>` on a browser that plays from them. */
288
+ private readonly ready: Array<CanvasImageSource | null>;
289
+ /** The downloaded files, unpacked when the film comes near them. */
290
+ private readonly files: Array<Blob | null>;
257
291
  private readonly order: number[];
258
292
  private readonly host: Window;
293
+ private readonly holdCount: number;
294
+ private fromFiles: boolean;
259
295
  private observer: IntersectionObserver | null = null;
260
296
  private canvas: HTMLCanvasElement | null = null;
261
297
  private context: CanvasRenderingContext2D | null = null;
@@ -264,15 +300,24 @@ export class FramePlayer {
264
300
  private loading = 0;
265
301
  private started = false;
266
302
  private destroyed = false;
303
+ private held = new Set<number>();
304
+ private readonly unpacked = new Map<number, ImageBitmap>();
305
+ private readonly unpacking = new Set<number>();
267
306
  private readonly pending = new Set<HTMLImageElement>();
307
+ private readonly downloads: AbortController | null;
268
308
 
269
309
  constructor(private readonly el: HTMLElement, private readonly sequence: FrameSequence, options: FramePlayerOptions = {}) {
270
310
  this.host = options.host ?? window;
271
311
  const { set, info } = frameSetFor(sequence, !!options.phone);
272
312
  this.set = set;
273
313
  this.info = info;
274
- this.images = new Array(info.count).fill(null);
314
+ this.ready = new Array(info.count).fill(null);
315
+ this.files = new Array(info.count).fill(null);
275
316
  this.order = frameLoadOrder(info.count);
317
+ this.holdCount = unpackedFrameCount(info.width, info.height);
318
+ this.fromFiles = typeof this.host.fetch === 'function' && typeof this.host.createImageBitmap === 'function';
319
+ const Controller = (this.host as Window & { AbortController?: typeof AbortController }).AbortController;
320
+ this.downloads = this.fromFiles && Controller ? new Controller() : null;
276
321
  if (!this.allowed()) return;
277
322
  const Observer = (this.host as Window & { IntersectionObserver?: typeof IntersectionObserver }).IntersectionObserver;
278
323
  if (!Observer) {
@@ -292,6 +337,7 @@ export class FramePlayer {
292
337
  seek(played: number): void {
293
338
  if (played === this.played) return;
294
339
  this.played = played;
340
+ this.hold();
295
341
  this.draw();
296
342
  }
297
343
 
@@ -305,12 +351,15 @@ export class FramePlayer {
305
351
  this.el.removeAttribute(FRAMES_SHOWING_ATTRIBUTE);
306
352
  this.observer?.disconnect();
307
353
  this.observer = null;
354
+ this.downloads?.abort();
308
355
  for (const image of this.pending) {
309
356
  image.onload = null;
310
357
  image.onerror = null;
311
358
  image.src = '';
312
359
  }
313
360
  this.pending.clear();
361
+ for (const bitmap of this.unpacked.values()) bitmap.close();
362
+ this.unpacked.clear();
314
363
  this.canvas?.remove();
315
364
  this.canvas = null;
316
365
  this.context = null;
@@ -331,43 +380,104 @@ export class FramePlayer {
331
380
 
332
381
  private pump(): void {
333
382
  while (!this.destroyed && this.loading < LOAD_CONCURRENCY && this.nextToLoad < this.order.length) {
334
- this.load(this.order[this.nextToLoad++]);
383
+ const index = this.order[this.nextToLoad++];
384
+ if (this.fromFiles) this.download(index);
385
+ else this.loadImage(index);
335
386
  }
336
387
  }
337
388
 
338
- private load(index: number): void {
389
+ private loaded(arrived: boolean): void {
390
+ this.loading--;
391
+ if (this.destroyed) return;
392
+ if (arrived) this.draw();
393
+ this.pump();
394
+ }
395
+
396
+ private download(index: number): void {
397
+ this.loading++;
398
+ const url = frameUrl(this.sequence, this.set, index);
399
+ this.host.fetch(url, this.downloads ? { signal: this.downloads.signal } : undefined)
400
+ .then(response => (response.ok ? response.blob() : null))
401
+ .then(file => {
402
+ if (this.destroyed) return;
403
+ // A picture that failed is a gap: its neighbours stand in.
404
+ this.files[index] = file;
405
+ this.loading--;
406
+ this.hold();
407
+ this.pump();
408
+ }, () => {
409
+ if (this.destroyed) return;
410
+ // Storage that refuses a download from the page's address still serves an <img>: play from those.
411
+ this.fromFiles = false;
412
+ this.loading--;
413
+ this.loadImage(index);
414
+ });
415
+ }
416
+
417
+ private loadImage(index: number): void {
339
418
  const image = this.host.document.createElement('img');
340
419
  image.decoding = 'async';
341
420
  this.loading++;
342
421
  this.pending.add(image);
343
422
  const done = (arrived: boolean): void => {
344
423
  this.pending.delete(image);
345
- this.loading--;
346
- if (this.destroyed) return;
347
- if (arrived) {
348
- this.images[index] = image;
349
- this.draw();
350
- }
351
- this.pump();
424
+ if (!this.destroyed && arrived) this.ready[index] = image;
425
+ this.loaded(arrived);
352
426
  };
353
- // Decoded before it counts, or the first draw of each picture decodes on the driver's frame and the scroll stutters.
427
+ // Decoded before it counts, or its first draw decodes on the driver's frame.
354
428
  image.onload = () => {
355
429
  const decoded = image.decode?.();
356
430
  if (decoded) void decoded.then(() => done(true), () => done(true));
357
431
  else done(true);
358
432
  };
359
- // A picture that failed is a gap: its neighbours stand in.
360
433
  image.onerror = () => done(false);
361
434
  image.src = frameUrl(this.sequence, this.set, index);
362
435
  }
363
436
 
437
+ /** Unpack the pictures around where the film stands, nearest first, and let go of the ones it has left. */
438
+ private hold(): void {
439
+ if (this.destroyed) return;
440
+ const wanted = framesToHold(framePosition(this.played ?? 0, this.info.count), this.info.count, this.holdCount);
441
+ this.held = new Set(wanted);
442
+ for (const [index, bitmap] of this.unpacked) {
443
+ if (this.held.has(index)) continue;
444
+ bitmap.close();
445
+ this.unpacked.delete(index);
446
+ this.ready[index] = null;
447
+ }
448
+ for (const index of wanted) {
449
+ if (this.unpacking.size >= UNPACK_CONCURRENCY) return;
450
+ if (this.files[index] && !this.ready[index] && !this.unpacking.has(index)) this.unpack(index);
451
+ }
452
+ }
453
+
454
+ private unpack(index: number): void {
455
+ this.unpacking.add(index);
456
+ this.host.createImageBitmap(this.files[index]!).then(bitmap => {
457
+ this.unpacking.delete(index);
458
+ if (this.destroyed || !this.held.has(index)) {
459
+ bitmap.close();
460
+ } else {
461
+ this.unpacked.set(index, bitmap);
462
+ this.ready[index] = bitmap;
463
+ this.draw();
464
+ }
465
+ this.hold();
466
+ }, () => {
467
+ // A file that will not unpack is a gap, like one that never came.
468
+ this.unpacking.delete(index);
469
+ this.files[index] = null;
470
+ this.hold();
471
+ });
472
+ }
473
+
364
474
  private draw(): void {
365
475
  if (this.destroyed || this.played === null) return;
366
- const blend = frameBlendAt(this.images, framePosition(this.played, this.info.count));
476
+ const blend = frameBlendAt(this.ready, framePosition(this.played, this.info.count));
367
477
  const last = this.drawn;
368
478
  if (!blend || (last && last.from === blend.from && last.to === blend.to && last.mix === blend.mix)) return;
369
- const image = this.images[blend.from]!;
370
- if (!this.ensureCanvas(image)) return;
479
+ const picture = this.ready[blend.from]!;
480
+ if (!this.ensureCanvas(picture)) return;
371
481
  const context = this.context!;
372
482
  const { width, height } = this.canvas!;
373
483
  context.clearRect(0, 0, width, height);
@@ -377,26 +487,27 @@ export class FramePlayer {
377
487
  // a time instead of moving.
378
488
  context.globalCompositeOperation = 'lighter';
379
489
  context.globalAlpha = 1 - blend.mix;
380
- context.drawImage(image, 0, 0, width, height);
490
+ context.drawImage(picture, 0, 0, width, height);
381
491
  context.globalAlpha = blend.mix;
382
- context.drawImage(this.images[blend.to]!, 0, 0, width, height);
492
+ context.drawImage(this.ready[blend.to]!, 0, 0, width, height);
383
493
  context.globalAlpha = 1;
384
494
  context.globalCompositeOperation = 'source-over';
385
495
  } else {
386
- context.drawImage(image, 0, 0, width, height);
496
+ context.drawImage(picture, 0, 0, width, height);
387
497
  }
388
498
  // Over a transparent film the poster would show through: a second, stiller subject behind the moving one.
389
499
  if (!this.drawn) this.el.setAttribute(FRAMES_SHOWING_ATTRIBUTE, '');
390
500
  this.drawn = blend;
391
501
  }
392
502
 
393
- private ensureCanvas(image: HTMLImageElement): boolean {
503
+ private ensureCanvas(picture: CanvasImageSource): boolean {
394
504
  if (this.canvas) return !!this.context;
505
+ const size = picture as { naturalWidth?: number; naturalHeight?: number; width?: number; height?: number };
395
506
  const canvas = this.host.document.createElement('canvas');
396
507
  canvas.className = FramesClass.Canvas;
397
508
  canvas.setAttribute('aria-hidden', 'true');
398
- canvas.width = image.naturalWidth || this.info.width;
399
- canvas.height = image.naturalHeight || this.info.height;
509
+ canvas.width = size.naturalWidth || Number(size.width) || this.info.width;
510
+ canvas.height = size.naturalHeight || Number(size.height) || this.info.height;
400
511
  this.context = canvas.getContext('2d');
401
512
  if (!this.context) return false;
402
513
  this.canvas = canvas;