@wyndlass/app-sdk 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -188,6 +188,7 @@ export default reactApp(Board, { css });
188
188
  - **`useSnapshot(table)`:** a data table's snapshot, as `snapshot` gives it. The component renders when the rows change: when the screen gets a table's new version, or when a binding's rows, chosen on the layout's clock, change. On players before Wyndlass's live rows (WP-0149), which make the app again when a table changes, it renders at every frame, as before.
189
189
  - **`usePlayback()`, `useConnection()`, `useAudio()`, `usePlaying()`:** the player's state (starting, playing, paused, stopped, idle or error), online or offline, the volume and whether it is muted, and the items playing. Each renders only when its value changes. Each is `null` where the app has no controller: in the designer and the CMS's previews.
190
190
  - **`useCommand(name, handler)`:** each command of that name sent to the screen's apps, with its argument, while the component is mounted.
191
+ - **`useEmergency()`:** emergency messages at the screen (see below). The component renders when they change.
191
192
 
192
193
  The hooks reach the app's context through the SDK's own module, never through React's tree, so nothing another app could use hangs off the shadow root.
193
194
 
@@ -213,8 +214,20 @@ export default class Queue extends WyndlassApp {
213
214
 
214
215
  - **`tableSignal(this, table)`:** a read-only [Preact signal](https://github.com/preactjs/signals) of the table's snapshot. Its value changes when the rows do, and is the same object until then. Make it in `mount()`.
215
216
  - **`playbackSignal(this)`, `connectionSignal(this)`, `audioSignal(this)`, `nowSignal(this)`:** the player's state, online or offline, the volume and whether it is muted, and the items playing, as read-only signals. Each is set only when its value changes, and is `null` where the app has no controller. Make them in `mount()`.
217
+ - **`emergencySignal(this)`:** emergency messages at the screen (below), as a read-only signal.
216
218
  - **`effect`, `computed`, `batch`, `signal`, `untracked`:** Preact's, from the same copy. Import them from here, not from `@preact/signals-core`: an effect from another copy does not see these signals.
217
219
  - **Its own entry,** so an app that doesn't import it doesn't bundle it (about 2 KB gzipped when it does).
220
+
221
+ ## Emergency messages
222
+
223
+ A screen shows emergency messages itself, over every app: a takeover covers the screen, and a banner covers its bottom 14% while the content above it plays on. `emergencySignal(this)` and `useEmergency()` say what shows, so an app can behave:
224
+
225
+ - **`{ showing, messages }`:** `showing` is `none`, `banner` or `takeover`. Each message in force gives its `source`, `severity`, `presentation`, `event` and `category` where it has them, and `test` for a test or a drill.
226
+ - **`null`** where the app has no controller, or before the screen has said what it holds. That is not the same as `none`.
227
+ - **Under a banner,** the app plays on below it. It may lower its sound, stop calling numbers or pause what calls for attention, or show the way out.
228
+ - **Never an alert's words.** The screen shows them in one design that apps can't change, and an app that drew them again could show one out of date or mistranslated.
229
+ - **An app can't move, cover or hide the emergency layer.**
230
+ - **In the preview,** the controller's panel shows a Test banner or takeover over the app, drawn as a screen draws it, and the app gets its `emergency.changed`.
218
231
  - On players before WP-0149, the signal keeps the rows the app was made with: such a player makes the app again when a table changes.
219
232
 
220
233
  ## Limits
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * An event the controller emits (protocol/player-api.json, ADR 0050): to apps that subscribed on the screen, and in the ring player.events reads. Told apart by type.
3
3
  */
4
- export type PlayerAPIEvent = StateChanged | ContentUpdated | ItemStart | ItemEnd | ItemError | ConnectionChanged | AudioChanged | DisplayChanged | TimeChanged | AppCommand | AppFailed | AppHeld;
4
+ export type PlayerAPIEvent = StateChanged | ContentUpdated | ItemStart | ItemEnd | ItemError | ConnectionChanged | AudioChanged | DisplayChanged | TimeChanged | EmergencyChanged | AppCommand | AppFailed | AppHeld;
5
5
  /**
6
6
  * RFC 3339 timestamp with offset.
7
7
  */
@@ -189,6 +189,65 @@ export interface TimeChanged {
189
189
  at: CommonTimestamp;
190
190
  reason: "clock-adjusted" | "time-zone-changed";
191
191
  }
192
+ /**
193
+ * What the screen shows of emergency messages, or the messages in force, changed (WP-0150): the status's emergency as it is now.
194
+ */
195
+ export interface EmergencyChanged {
196
+ type: "emergency.changed";
197
+ /**
198
+ * The event's place in this player's sequence since it started; player.events pages by it.
199
+ */
200
+ seq: number;
201
+ at: CommonTimestamp;
202
+ emergency: PlayerApiCommonEmergency;
203
+ }
204
+ /**
205
+ * Emergency messages at the screen as apps and agents may read them (WP-0150 decision 4, ADR 0135): what shows, and of each message in force what conditions read (ADR 0127 decision 9) and whether it is a test. Never its words: no headline, description, instruction, area or sender. Absent until the shell has said what it holds.
206
+ */
207
+ export interface PlayerApiCommonEmergency {
208
+ /**
209
+ * What the screen shows of emergency messages now: a takeover, over everything; a banner across the bottom, over content that plays on; or none. A record shows nothing.
210
+ */
211
+ showing: "none" | "banner" | "takeover";
212
+ /**
213
+ * Each message in force at the screen, records and Test messages included.
214
+ */
215
+ messages: PlayerApiCommonEmergencyFact[];
216
+ }
217
+ /**
218
+ * One emergency message in force, as apps and agents may read it: never its words.
219
+ */
220
+ export interface PlayerApiCommonEmergencyFact {
221
+ /**
222
+ * Where it came from: a person (manual), an organization's own feed, the National Weather Service or IPAWS.
223
+ */
224
+ source: "manual" | "cap-feed" | "nws" | "ipaws";
225
+ /**
226
+ * CAP's severity, from highest.
227
+ */
228
+ severity: "Extreme" | "Severe" | "Moderate" | "Minor" | "Unknown";
229
+ /**
230
+ * takeover: above everything; banner: a strip over content that keeps playing; record: held and read by conditions, but not shown.
231
+ */
232
+ presentation: "takeover" | "banner" | "record";
233
+ /**
234
+ * CAP's event, such as Tornado Warning or Lockdown, where the message has one.
235
+ */
236
+ event?: string;
237
+ /**
238
+ * CAP's categories, where the message has them.
239
+ *
240
+ * @minItems 1
241
+ */
242
+ category?: [
243
+ ("Geo" | "Met" | "Safety" | "Security" | "Rescue" | "Fire" | "Health" | "Env" | "Transport" | "Infra" | "CBRNE" | "Other"),
244
+ ...("Geo" | "Met" | "Safety" | "Security" | "Rescue" | "Fire" | "Health" | "Env" | "Transport" | "Infra" | "CBRNE" | "Other")[]
245
+ ];
246
+ /**
247
+ * Status Test or Exercise: the screen marks it TEST.
248
+ */
249
+ test: boolean;
250
+ }
192
251
  export interface AppCommand {
193
252
  type: "app.command";
194
253
  /**
@@ -83,6 +83,7 @@ export interface PlayerAPIStatus {
83
83
  now: NowItem[];
84
84
  audio?: PlayerApiCommonAudio;
85
85
  display?: PlayerApiCommonDisplay;
86
+ emergency?: PlayerApiCommonEmergency;
86
87
  capabilities: PlayerApiCommonHostCapabilities;
87
88
  }
88
89
  /**
@@ -155,6 +156,53 @@ export interface PlayerApiCommonDisplay {
155
156
  power: "on" | "standby" | "unknown";
156
157
  brightness?: number;
157
158
  }
159
+ /**
160
+ * Emergency messages at the screen as apps and agents may read them (WP-0150 decision 4, ADR 0135): what shows, and of each message in force what conditions read (ADR 0127 decision 9) and whether it is a test. Never its words: no headline, description, instruction, area or sender. Absent until the shell has said what it holds.
161
+ */
162
+ export interface PlayerApiCommonEmergency {
163
+ /**
164
+ * What the screen shows of emergency messages now: a takeover, over everything; a banner across the bottom, over content that plays on; or none. A record shows nothing.
165
+ */
166
+ showing: "none" | "banner" | "takeover";
167
+ /**
168
+ * Each message in force at the screen, records and Test messages included.
169
+ */
170
+ messages: PlayerApiCommonEmergencyFact[];
171
+ }
172
+ /**
173
+ * One emergency message in force, as apps and agents may read it: never its words.
174
+ */
175
+ export interface PlayerApiCommonEmergencyFact {
176
+ /**
177
+ * Where it came from: a person (manual), an organization's own feed, the National Weather Service or IPAWS.
178
+ */
179
+ source: "manual" | "cap-feed" | "nws" | "ipaws";
180
+ /**
181
+ * CAP's severity, from highest.
182
+ */
183
+ severity: "Extreme" | "Severe" | "Moderate" | "Minor" | "Unknown";
184
+ /**
185
+ * takeover: above everything; banner: a strip over content that keeps playing; record: held and read by conditions, but not shown.
186
+ */
187
+ presentation: "takeover" | "banner" | "record";
188
+ /**
189
+ * CAP's event, such as Tornado Warning or Lockdown, where the message has one.
190
+ */
191
+ event?: string;
192
+ /**
193
+ * CAP's categories, where the message has them.
194
+ *
195
+ * @minItems 1
196
+ */
197
+ category?: [
198
+ ("Geo" | "Met" | "Safety" | "Security" | "Rescue" | "Fire" | "Health" | "Env" | "Transport" | "Infra" | "CBRNE" | "Other"),
199
+ ...("Geo" | "Met" | "Safety" | "Security" | "Rescue" | "Fire" | "Health" | "Env" | "Transport" | "Infra" | "CBRNE" | "Other")[]
200
+ ];
201
+ /**
202
+ * Status Test or Exercise: the screen marks it TEST.
203
+ */
204
+ test: boolean;
205
+ }
158
206
  /**
159
207
  * What the host can do beyond the controller's own; tools that need what it lacks are not listed.
160
208
  */
@@ -23,6 +23,10 @@ declare const FIELDS: {
23
23
  readonly events: readonly ["item.start", "item.end"];
24
24
  readonly read: (s: PlayerAPIStatus) => import("./contract/player-api-status.js").NowItem[];
25
25
  };
26
+ readonly emergency: {
27
+ readonly events: readonly ["emergency.changed"];
28
+ readonly read: (s: PlayerAPIStatus) => import("./contract/player-api-status.js").PlayerApiCommonEmergency | null;
29
+ };
26
30
  };
27
31
  export type Field = keyof typeof FIELDS;
28
32
  export type Followed<K extends Field> = ReturnType<(typeof FIELDS)[K]["read"]> | null;
package/dist/following.js CHANGED
@@ -5,6 +5,8 @@ const FIELDS = {
5
5
  connection: { events: ["connection.changed"], read: (s) => s.connection },
6
6
  audio: { events: ["audio.changed"], read: (s) => s.audio ?? null },
7
7
  now: { events: ["item.start", "item.end"], read: (s) => s.now },
8
+ // Absent until the shell has said what it holds: null then, as for an older player (WP-0150 decision 4).
9
+ emergency: { events: ["emergency.changed"], read: (s) => s.emergency ?? null },
8
10
  };
9
11
  export function follow(app, field) {
10
12
  const controller = controllerOf(app);
@@ -1,2 +1,2 @@
1
1
  /* @wyndlass/app-sdk's preview: player-core's app frame, compiled. MIT, (c) Northwynd Labs LLC. */
2
- "use strict";(()=>{var vt=Object.defineProperty;var kt=(e,t,n)=>t in e?vt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var m=(e,t,n)=>kt(e,typeof t!="symbol"?t+"":t,n);var Te={apiVersion:2,properties:[{name:"device",description:"What the device is: id, type, shell and versions, model, resolution and orientation. Fixed while the player runs."},{name:"mode",description:"Where player-core runs: player, preview (in the CMS) or designer. In preview and the designer, commands change nothing."},{name:"timeZone",description:"The player's time zone (IANA), from the host.",event:"time.changed"},{name:"locale",description:"The player's locale (BCP 47), from the host."},{name:"connection",description:"Whether the player is connected to Wyndlass.",event:"connection.changed"},{name:"state",description:"starting, playing, paused, stopped (the standby screen), idle (nothing to play) or error.",event:"state.changed"},{name:"held",description:"A remote pause or stop in effect, by whom and since when; absent when none.",event:"state.changed"},{name:"content",description:"The manifest playing, when it was issued and switched to; absent when there is none.",event:"content.updated"},{name:"now",description:"What each zone shows: the item, its blob and content type, when it started, and its duration and position when known.",event:"item.start"},{name:"audio",description:"The player's volume (0 to 100) and whether it is muted; only when the host can set them.",event:"audio.changed"},{name:"display",description:"The display's power and brightness; only when the host can report them.",event:"display.changed"},{name:"capabilities",description:"What the host can do: audio, display power, display brightness."}],events:[{name:"state.changed",description:"The player's state changed (playing, paused, stopped, idle, error), and who changed it."},{name:"content.updated",description:"A new manifest was switched to."},{name:"item.start",description:"An item started in a zone (source start)."},{name:"item.end",description:"An item ended in a zone (source end): completed, skipped, stopped, error, replaced by new content, or finished by its app."},{name:"item.error",description:"An item could not be shown."},{name:"connection.changed",description:"The player connected to Wyndlass or lost its connection."},{name:"audio.changed",description:"The volume or mute changed, and who changed it."},{name:"display.changed",description:"The display's power or brightness changed, and who changed it."},{name:"time.changed",description:"The clock was adjusted or the time zone changed."},{name:"app.command",description:"A command for apps on the screen (apps.sendCommand); an app reacts if it knows the name."},{name:"app.failed",description:"An app on the screen could not run, or misbehaved (WP-0100): its bundle did not load, it was not an app, it needs a newer player, it kept throwing and was stopped, or it was late or overran a clip."},{name:"app.held",description:"An app version was held back on this screen until the next manifest, after the page stopped answering twice in an hour while it was on screen (WP-0100)."}],commands:[{name:"player.status",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/status",description:"Everything about the player now: device, mode, time zone, locale, connection, state (and any hold), the content playing, what each zone shows, audio, display and what the host can do. Changes nothing.",idempotent:!0},{name:"player.events",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/events",result:"player-api-results.schema.json#/$defs/events",description:"The player's recent events (the last 200), oldest first, after a sequence number: state changes, content updates, item starts and ends, errors, connection, audio, display and time. Pass next as after to poll for more. Changes nothing.",idempotent:!0},{name:"time.now",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/timeNow",description:"The player's current time, its time zone and UTC offset, and whether its clock is synchronized. Changes nothing.",idempotent:!0},{name:"player.play",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Resumes or starts playback on the screen. From a remote caller it also ends a remote pause or stop.",idempotent:!0},{name:"player.pause",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Freezes the screen on what it shows now: the loop's timer and any media stop where they are. From a remote caller it holds until a remote player.play or a restart; apps cannot resume it, and new content arrives paused.",idempotent:!0},{name:"player.stop",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Stops playback and shows the standby screen (black, display on). From a remote caller it holds until a remote player.play or a restart; apps cannot restart it, and new content arrives stopped.",idempotent:!0},{name:"player.next",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Skips to the next item in a zone (main by default); the current item ends as skipped."},{name:"player.previous",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Goes back to the previous item in a zone (main by default); the current item ends as skipped."},{name:"player.playItem",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/playItem",result:"player-api-results.schema.json#/$defs/now",description:"Shows a given item of the content playing now in a zone (main by default), then continues the loop from it. Refused for an item the playing manifest does not have."},{name:"audio.setVolume",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setVolume",result:"player-api-results.schema.json#/$defs/audio",description:"Sets the player's volume, 0 to 100. Only on players whose host can set it to a level.",needs:"audio.volume",idempotent:!0},{name:"audio.setMuted",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setMuted",result:"player-api-results.schema.json#/$defs/audio",description:"Mutes or unmutes the player. Only on players whose host can.",needs:"audio",idempotent:!0},{name:"display.setPower",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setPower",result:"player-api-results.schema.json#/$defs/display",description:"Turns the display on or to standby. Only on players whose host can. Standby blanks the screen until it is turned on.",needs:"display.power",idempotent:!0},{name:"display.setBrightness",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setBrightness",result:"player-api-results.schema.json#/$defs/display",description:"Sets the display's brightness, 0 to 100. Only on players whose host can.",needs:"display.brightness",idempotent:!0},{name:"apps.sendCommand",access:"control",apps:"none",remote:!0,params:"player-api-params.schema.json#/$defs/sendCommand",result:"player-api-results.schema.json#/$defs/delivered",description:"Sends a named command, with an optional argument, to the apps on the screen; an app that knows the name reacts. Returns how many apps listen."},{name:"app.finish",access:"control",apps:"read",remote:!1,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/none",description:"An app ends its own slot now: its item ends as finished and the loop moves on. Apps only; not a tool."}],host:[{name:"host.describe",kind:"request",description:"What the device is, its time zone, locale, connection and capabilities.",result:"player-api-host.schema.json#/$defs/describeResult"},{name:"host.time",kind:"request",description:"The host's time and time zone.",result:"player-api-common.schema.json#/$defs/timeNow"},{name:"host.getAudio",kind:"request",description:"The player's volume and mute.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.setAudio",kind:"request",description:"Sets the volume, the mute or both; answers the audio after.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.getDisplay",kind:"request",description:"The display's power and brightness.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.setDisplay",kind:"request",description:"Sets the display's power, brightness or both; answers the display after.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.adRequest",kind:"request",description:"Asks Wyndlass's ad broker for one slot of a break over the host's NATS connection (WP-0075); the result is the broker's ad-decision (ad-decision.schema.json). Only a host whose describe says ads is asked."},{name:"host.mediaPrepare",kind:"request",description:"Lays a video out behind the page and prepares it to its first frame; host.mediaState says when (ADR 0055)."},{name:"host.mediaShow",kind:"request",description:"Shows and hides prepared videos; replies once its layer has changed."},{name:"host.mediaControl",kind:"request",description:"Plays, pauses or seeks a video, or asks for its position."},{name:"host.mediaRelease",kind:"request",description:"Removes a video and frees its decoder."},{name:"host.reply",kind:"reply",description:"The host's answer to a request: result or error (unsupported, failed)."},{name:"host.connection",kind:"event",description:"The connection to Wyndlass changed."},{name:"host.timeChanged",kind:"event",description:"The clock was adjusted or the time zone changed."},{name:"host.audioChanged",kind:"event",description:"The volume or mute changed outside the player."},{name:"host.displayChanged",kind:"event",description:"The display changed outside the player."},{name:"host.mediaState",kind:"event",description:"A video was prepared, started, ended or failed, or its position was asked for."},{name:"host.presence",kind:"event",description:"What one of the host's sensors sees now: the presences in view, with random ids that never leave the page (WP-0105)."},{name:"host.sensing",kind:"event",description:"The site's sensing mode as the host applies it, and its sensors (WP-0105)."},{name:"host.serialPorts",kind:"event",description:"The host's sensor controller ports, and which are open (WP-0043)."},{name:"host.serialLine",kind:"event",description:"One line from a sensor controller, as it arrived (WP-0043)."},{name:"host.serialWrite",kind:"request",description:"Writes lines to a sensor controller, a gap apart; replies once written (WP-0043)."},{name:"host.bleWatch",kind:"request",description:"What the page listens for: beacons' iBeacon UUIDs, Eddystone namespaces and addresses; replies once the scan follows it. Sent only to a host that has sent host.bleState (WP-0044)."},{name:"host.bleAdverts",kind:"event",description:"Beacon frames that match the watch, at most four a second of each kind from each beacon (WP-0044)."},{name:"host.bleState",kind:"event",description:"The host's Bluetooth scanner: scanning, idle, off, refused, missing or failed; sent only by a host that has one (WP-0044)."},{name:"host.gpioPins",kind:"event",description:"The GPIO pins the host reads, with their values (WP-0044)."},{name:"host.gpioEdge",kind:"event",description:"A GPIO pin changed (WP-0044)."},{name:"host.mcp",kind:"relay",description:"An MCP message from ctl.dev.{deviceId}, for player-core to answer."},{name:"core.ready",kind:"core",description:"player-core is ready to answer host.mcp; until then the shell answers -32002 itself."},{name:"core.mcpReply",kind:"core",description:"player-core's answer to a host.mcp, for the shell to send back."},{name:"core.sensors",kind:"core",description:"The page's sensor controllers, channels and inputs, and the beacons it hears, whenever they change, for the heartbeat and sensors.recent (WP-0043, WP-0044)."}]};var Me=Symbol.for("wyndlass.app.attach");var De=Reflect.apply,de=Object.getOwnPropertyDescriptor,Q=Object.getPrototypeOf,b=globalThis,a=(e,t,n)=>De(e,t,n),k=(e,t)=>e?de(e,t)?.get:void 0,pe=(e,t)=>e?de(e,t)?.set:void 0,g=e=>b[e]?.prototype,He=(e,t,n)=>De(e,t,n);var qn=Date.now,zn=new TextEncoder,_n=new TextDecoder,Zn=TextEncoder.prototype.encode,Kn=TextDecoder.prototype.decode;var Vn=k(Q(Uint8Array.prototype),"length");var xt=Uint8Array,St=e=>new xt(e),Et=[];for(let e=0;e<256;e++)Et[e]=(e<16?"0":"")+e.toString(16);var Tt=Object.create(null);for(let e=0;e<64;e++)Tt["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[e]]=e;var Fe=b.crypto?.subtle,le=Fe?Q(Fe):void 0,ae=b.crypto,Mt=ae?Q(ae).getRandomValues:void 0,Gn=le?.digest,Jn=le?.importKey,Yn=le?.sign;var Be=e=>a(Mt,ae,[St(e)]),Qn={setTimeout:b.setTimeout,clearTimeout:b.clearTimeout,setInterval:b.setInterval,clearInterval:b.clearInterval};var Xn=b.fetch;var q=g("MessagePort"),er=q&&q.postMessage,tr=pe(q,"onmessage"),nr=q&&q.start,ce=g("MessageEvent"),rr=k(ce,"data"),or=k(ce,"ports"),sr=k(ce,"source");var We=g("EventTarget"),ir=We?.addEventListener,ar=We?.removeEventListener;var dr=b.Worker,G=g("Worker"),pr=G&&G.postMessage,lr=pe(G,"onmessage"),cr=pe(G,"onerror");var Pe=b.Blob,J=b.URL,Re=J?.createObjectURL,Ft=J?.revokeObjectURL,ue=Pe&&Re?{make:(e,t)=>a(Re,J,[new Pe(e,{type:t})]),revoke:e=>a(Ft,J,[e])}:void 0,U=b.customElements,me=U?Q(U):void 0,Pt=me?.define,Rt=me?.get,fe=U&&me?{define:(e,t)=>a(Pt,U,[e,t]),get:e=>a(Rt,U,[e])}:void 0,$t=b.document,Y=g("Document"),Nt=Y?.createElement,ur=Y?.createElementNS,Ot=WeakSet.prototype.add,mr=WeakSet.prototype.has,Ct=new WeakSet;var Lt=(e,t)=>(a(Ot,e,[t]),t);function Ue(e){return Lt(Ct,a(Nt,$t,[e]))}var z=g("Node"),he=g("Element"),X=g("HTMLElement"),D=e=>k(z,e),$e=D("parentNode"),jt=D("firstChild"),It=D("lastChild"),Dt=D("nextSibling"),Ht=D("nodeType"),Bt=D("childNodes"),Wt=k(he,"localName"),Ut=z?.appendChild,qt=z?.insertBefore,zt=z?.removeChild,L=he,_t=L?.getAttribute,Zt=L?.getAttributeNames,Kt=L?.setAttribute,Vt=L?.removeAttribute,Gt=L?.matches,Jt=L?.attachShadow,Yt=L?.querySelectorAll,Qt=g("HTMLDialogElement")?.close,Xt=k(g("NodeList"),"length"),en=g("NodeList")?.item,ee=g("MutationRecord"),tn=k(ee,"type"),nn=k(ee,"target"),rn=k(ee,"addedNodes"),on=k(ee,"removedNodes"),Ne=b.MutationObserver,sn=g("MutationObserver")?.observe,qe=Y?de(Y,"adoptedStyleSheets"):void 0,Oe=qe?.get,Ce=qe?.set,an=b.requestAnimationFrame,Le=k(X,"style"),te=g("CSSStyleDeclaration"),dn=te?.getPropertyValue,pn=te?.getPropertyPriority,ln=te?.setProperty,je=X?.showPopover,Ie=X?.hidePopover,cn=k(g("Event"),"target"),un=g("Event")?.stopImmediatePropagation,V=e=>{let t=[];for(let n=0,r=a(Xt,e,[]);n<r;n++)t[n]=a(en,e,[n]);return t},ze=Ne&&z&&he&&X&&te?{parent:e=>a($e,e,[]),first:e=>a(jt,e,[]),last:e=>a(It,e,[]),next:e=>a(Dt,e,[]),isElement:e=>a(Ht,e,[])===1,name:e=>a(Wt,e,[]),children:e=>V(a(Bt,e,[])),append:(e,t)=>a(Ut,e,[t]),insert:(e,t,n)=>a(qt,e,[t,n]),remove:e=>{let t=a($e,e,[]);t&&a(zt,t,[e])},attribute:(e,t)=>a(_t,e,[t]),attributes:e=>a(Zt,e,[]),setAttribute:(e,t,n)=>a(Kt,e,[t,n]),removeAttribute:(e,t)=>a(Vt,e,[t]),matches:(e,t)=>a(Gt,e,[t]),all:(e,t)=>V(a(Yt,e,[t])),closeDialog:e=>a(Qt,e,[]),shadow:e=>a(Jt,e,[{mode:"closed"}]),style:(e,t)=>{let n=a(Le,e,[]);return[a(dn,n,[t]),a(pn,n,[t])]},setStyle:(e,t,n,r="")=>a(ln,a(Le,e,[]),[t,n,r]),observer:e=>new Ne(e),observe:(e,t,n)=>a(sn,e,[t,n]),record:e=>({type:a(tn,e,[]),target:a(nn,e,[]),added:V(a(rn,e,[])),removed:V(a(on,e,[]))}),adopted:Oe&&Ce?{count:e=>a(Oe,e,[]).length,clear:e=>a(Ce,e,[[]])}:void 0,frame:e=>a(an,globalThis,[e]),popover:je&&Ie?{show:e=>a(je,e,[]),hide:e=>a(Ie,e,[])}:void 0,target:e=>a(cn,e,[]),stop:e=>a(un,e,[])}:void 0;var P=class extends Error{constructor(n,r){super(`the app could not run (${n})`);m(this,"reason",n);m(this,"error",r)}};function j(e){try{let t=e instanceof Error?e.name:void 0;return typeof t=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(t)?t:void 0}catch{return}}function _(e){let t=e?.id;if(typeof t!="string"||t==="")return!0;for(let n=0;n<_e.length;n++)if(t[n]!==_e[n])return!1;return!0}var _e="com.wyndlass.";function mn(e=typeof navigator>"u"?"":navigator.userAgent){let t=/Chrom(?:e|ium)\/(\d+)/.exec(e);return t?Number(t[1]):void 0}function Ze(e,t=Te.apiVersion,n=mn()){return!(e?.playerApi!==void 0&&e.playerApi>t||e?.webView!==void 0&&n!==void 0&&e.webView>n)}function fn(e){let t;try{t=e.paging?.()}catch{return null}let n=t;return n&&Number.isInteger(n.count)&&n.count>1&&typeof n.ms=="number"&&n.ms>0?{count:n.count,ms:n.ms}:null}var ge=new Map;function hn(){let e=Be(8),t="";for(let n=0;n<8;n++)t+=gn[e[n]%26];return t}var gn="abcdefghijklmnopqrstuvwxyz",yn=0;function Ke(e,t,n){let r=ge.get(e);if(!r){let o=ue.make([t],"text/javascript");r=import(o).then(s=>bn(s,n),s=>{throw s instanceof P?s:new P("load",j(s))}).finally(()=>ue.revoke(o)),ge.set(e,r),r.catch(()=>ge.delete(e))}return r}function bn(e,t){let n=e.default;if(typeof n=="function"&&n.prototype instanceof HTMLElement){let r=n.prototype[Me];if(typeof r!="function")throw new P("shape");let o=class extends n{},s=`${t?.element??"wl-app"}-${hn()}${++yn}`;try{fe.define(s,o)}catch(c){throw new P("shape",j(c))}return{tag:s,shape:"class",attach:(c,A)=>{He(r,c,[A])}}}if(_(t)&&typeof e.element=="string"&&fe.get(e.element))return{tag:e.element,shape:"legacy"};throw new P("shape")}var wn=3,vn=6e4,ne=class{constructor(t,n){m(this,"element",t);m(this,"o",n);m(this,"faults",[]);m(this,"halted",!1)}get stopped(){return this.halted}has(t){try{return!this.halted&&typeof this.element[t]=="function"}catch{return!1}}update(t){this.halted||this.run(()=>this.element.update?.(t))}reset(){this.halted||this.run(()=>this.element.reset?.())}paging(){return this.halted?null:fn(this.element)}hook(t,n){if(this.halted)return Promise.resolve();let r;try{r=this.element[t]?.(n)}catch(o){return this.fault(o),Promise.resolve()}return Promise.resolve(r).then(()=>{},o=>this.fault(o))}stop(t){if(!this.halted){this.halted=!0;try{this.element.remove()}catch{}this.o.dispose?.(),this.o.onStop(t)}}dispose(){this.o.dispose?.()}run(t){try{t()}catch(n){this.fault(n)}}fault(t){let n=(this.o.now??Date.now)();this.faults=this.faults.filter(r=>n-r<vn),this.faults.push(n),this.faults.length>=wn&&this.stop(j(t))}},br=24*3600*1e3;var re="wyndlass.frame";function Ye(e,t){return!!e&&(e.apps?e.apps(t):!_(t))}var kn=new Set(["load","shape","unsupported","error","late","overran"]),Ve=50,Ge=250,ye=class{constructor(t,n,r,o){m(this,"frame",t);m(this,"port",n);m(this,"o",o);m(this,"halted",!1);m(this,"pages");m(this,"hooks");m(this,"pending",new Map);m(this,"next",0);m(this,"told");m(this,"last");m(this,"quiet");this.hooks=new Set(r.hooks),this.pages=r.paging}get stopped(){return this.halted}has(t){return!this.halted&&this.hooks.has(t)}paging(){return this.halted?null:this.pages}update(t){if(this.halted)return;let n=performance.now(),r=this.last;this.last={t,at:n};let o=this.told;if(o&&(o.running?Math.abs(t-(o.t+(n-o.at)))<=Ve:t===o.t)){o.running&&this.watch();return}let s=!!r&&n-r.at<Ge&&t>r.t&&Math.abs(t-r.t-(n-r.at))<=Ve;this.told={t,at:n,running:s},this.post({type:"clock",t,running:s}),s&&this.watch()}reset(){this.halted||this.post({type:"reset"})}snapshots(t){this.halted||this.post({type:"snapshots",snapshots:t})}hook(t,n){if(this.halted)return Promise.resolve();let r=++this.next;return new Promise(o=>{this.pending.set(r,o),this.post({type:"hook",id:r,kind:t,options:n})})}stop(t){this.halted||(this.halted=!0,this.frame.remove(),this.dispose(),this.o.onStop(t))}dispose(){this.o.dispose?.(),clearTimeout(this.quiet),this.port.close();for(let t of this.pending.values())t();this.pending.clear()}heard(t){t.type==="paging"?this.pages=Xe(t.paging):t.type==="hooked"&&typeof t.id=="number"?(this.pending.get(t.id)?.(),this.pending.delete(t.id)):t.type==="stopped"&&this.stop(et(t.error))}post(t){try{this.port.postMessage(t)}catch{}}watch(){clearTimeout(this.quiet),this.quiet=setTimeout(()=>{!this.told?.running||!this.last||this.halted||(this.told={...this.last,running:!1},this.post({type:"clock",t:this.last.t,running:!1}))},Ge)}};async function Qe(e,t,n,r,o,s,c,A,y,i){let l=e.appInfo??n.info,u;try{u=new URL(y.frames).origin}catch{return i("unsupported")}let d=document.createElement("iframe");d.setAttribute("sandbox","allow-scripts"),d.setAttribute("referrerpolicy","no-referrer"),d.title=l?.id??"app",d.tabIndex=-1,d.dataset.frame=l?.id??"",d.style.cssText="display:block;width:100%;height:100%;border:0;pointer-events:none;background:transparent;color-scheme:normal";let w=new Promise(T=>{d.addEventListener("load",()=>T(!0),{once:!0}),setTimeout(()=>T(!1),s)});d.src=`${u}/`,t.append(d);let E=(T,v)=>(d.remove(),i(T,v));if(!await w||!d.contentWindow)return E("load");let{port1:x,port2:Z}=new MessageChannel,O={type:"init",element:{id:e.id,type:"app",app:e.app,props:e.props??{},...e.binding?{binding:e.binding}:{},...e.appInfo?{appInfo:e.appInfo}:{}},bundle:{hash:n.hash,bytes:n.bytes.slice(),...n.info?{info:n.info}:{}},...r.place?{place:r.place}:{},screen:r.screen??null,timeZone:r.timeZone,locale:r.locale,preview:!!r.preview,clock:{t:o.now(),running:!1,startedAt:o.startedAt()},fonts:Sn(e.props??{},y),snapshots:Je(e,r),deadlineMs:s};return new Promise(T=>{let v,$=!1,M=B=>{$||($=!0,clearTimeout(C),T(B))},C=setTimeout(()=>{v?(M({app:v,late:!0}),v.update(o.now())):(x.close(),M(E("load")))},s+1e3),S=!1;x.onmessage=B=>{let h=B.data;if(!(!h||typeof h!="object")){if(h.type==="ask"){S&&An(h,r,x);return}if(v){h.type==="ready"?(M({app:v,late:h.late===!0}),v.update(o.now())):v.heard(h);return}if(h.type==="hello"&&!S)S=!0,x.postMessage(O,[O.bundle.bytes.buffer]);else if(h.type==="made"&&Array.isArray(h.hooks)){let W=tt(e),K,p=new ye(d,x,{type:"made",hooks:h.hooks.filter(f=>f==="enter"||f==="exit"),paging:Xe(h.paging)},{onStop:A,dispose:()=>K?.()});K=r.onSnapshots?.(f=>{f.some(F=>W.has(F))&&p.snapshots(Je(e,r))}),v=p,c(v)}else h.type==="failed"&&(x.close(),M(E(kn.has(h.reason)?h.reason:"error",et(h.error))))}},d.contentWindow.postMessage({type:re},"*",[Z])})}async function An(e,t,n){if(typeof e.id!="number")return;let r=(o,s=[])=>{try{n.postMessage(o,s)}catch{}};try{if(!t.data)throw new Error("no data service");if(e.what==="data"&&typeof e.source=="string")r({type:"answer",id:e.id,value:await t.data.get(e.source,xn(e.params))});else if(e.what==="image"&&typeof e.path=="string"){let o=await t.data.imageBlob(e.path),s=new Uint8Array(await o.arrayBuffer());r({type:"answer",id:e.id,value:{bytes:s,type:o.type}},[s.buffer])}else throw new TypeError("not a question")}catch(o){r({type:"answer",id:e.id,error:j(o)??"Error"})}}function xn(e){let t={};if(e&&typeof e=="object")for(let[n,r]of Object.entries(e))(typeof r=="string"||typeof r=="number"||typeof r=="boolean")&&(t[n]=r);return t}function Xe(e){let t=e;return t&&Number.isInteger(t.count)&&t.count>1&&typeof t.ms=="number"&&t.ms>0?{count:t.count,ms:t.ms}:null}function et(e){return typeof e=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(e)?e:void 0}function Sn(e,t){let n=new Set;for(let o of Object.values(e)){let s=o?.family;o&&typeof o=="object"&&typeof s=="string"&&n.add(s)}let r=[];for(let o of t.fonts??[]){let s=n.has(o.family)?t.font?.(o.blob):void 0;s&&r.push({family:o.family,weight:o.weight,style:o.style,blob:o.blob,bytes:s.slice()})}return r}function tt(e){let t=new Set;e.binding?.table&&t.add(e.binding.table);for(let n of Object.values(e.props??{}))typeof n=="string"&&/^tbl_[0-9a-z]{26}$/.test(n)&&t.add(n);return t}function Je(e,t){let n={};for(let r of tt(e)){let o=t.snapshot?.(r);o&&(n[r]=o)}return n}function nt(e){let t=ze?.setStyle??((n,r,o,s)=>n.style.setProperty(r,o,s));t(e,"contain","strict","important"),t(e,"overflow","clip","important")}var En=["name","type","tags","location","site","district","region","organization","path","timeZone"],Tn=["text","date","currency","truncate"],rt={site:"SITE",district:"DISTRICT",region:"REGION",organization:"ORGANIZATION"};function oe(e,t,n,r){if(!e)return n==="timeZone"&&t?t:void 0;if(n==="fields")return r&&e.fields?.[r]||void 0;let o=e.path??[];switch(n){case"name":return e.name||void 0;case"type":return e.type||void 0;case"tags":return e.tags?.length?e.tags.join(", "):void 0;case"location":return o.at(-1)?.name;case"path":return o.length?o.map(s=>s.name).join(" \u203A "):void 0;case"timeZone":return t||void 0;default:return rt[n]?[...o].reverse().find(s=>s.kind===rt[n])?.name:void 0}}function Mn(e,t){if(e==null||e==="")return;let n=String(e);if(t==="currency"){let r=Number(e);return Number.isFinite(r)?r.toFixed(2):n}if(t==="date"){let r=Date.parse(n);return Number.isNaN(r)?n:new Date(r).toISOString().slice(0,10)}return t==="truncate"&&n.length>40?n.slice(0,39)+"\u2026":n}function ot(e,t){return(e.source==="screen"?oe(t.screen,t.timeZone,e.field,e.key):Mn(t.tables?.[e.table]?.rows?.[e.row??0]?.[e.column],e.format))??e.fallback??""}function st(e){let t=/^\s*(?:screen\.(fields\.[a-z][A-Za-z0-9]{0,31}|[A-Za-z]+)|table\.([A-Za-z0-9_-]+)\[(\d+)\](?:\.([A-Za-z0-9_]+)|\["((?:[^"\\]|\\.)*)"\]))\s*((?:\|\s*(?:[a-z]+|"(?:[^"\\]|\\.)*")\s*)*)$/.exec(e);if(!t)return null;let n=[...t[6].matchAll(/\|\s*([a-z]+|"((?:[^"\\]|\\.)*)")/g)],r=n.find(s=>s[1].startsWith('"'))?.[2]?.replace(/\\(.)/g,"$1"),o=n.find(s=>!s[1].startsWith('"'))?.[1];return t[1]!==void 0?o?null:t[1].startsWith("fields.")?{source:"screen",field:"fields",key:t[1].slice(7),...r!==void 0?{fallback:r}:{}}:En.includes(t[1])?{source:"screen",field:t[1],...r!==void 0?{fallback:r}:{}}:null:o&&!Tn.includes(o)?null:{source:"table",table:t[2],row:Number(t[3]),column:t[4]??t[5].replace(/\\(.)/g,"$1"),...o?{format:o}:{},...r!==void 0?{fallback:r}:{}}}function it(e,t){return e.replace(/\{{2}([^{}]*)\}{2}/g,(n,r)=>{let o=st(r);return o?ot(o,t):n})}function at(e){return[...e.matchAll(/\{{2}([^{}]*)\}{2}/g)].some(t=>st(t[1])!==null)}function be(e,t){return Object.fromEntries(Object.entries(e).map(([n,r])=>[n,typeof r=="string"?it(r,t):r]))}var we=e=>e==null||e==="";function pt(e,t,n,r,o,s){return Fn(e,t,n,r,{now:o,timeZone:s})}function Fn(e,t,n,r,o){if(n===null&&(t==="eq"||t==="ne"))return t==="eq"?we(e):!we(e);if(we(e)||n===null||n===void 0)return!1;switch(r){case"number":case"currency":{let s=Number(e),c=Number(n);return typeof n!="boolean"&&n!==""&&Number.isFinite(s)&&Number.isFinite(c)&&ve(t,s-c)}case"boolean":{let s=n===!0||n==="true"?!0:n===!1||n==="false"?!1:void 0;return s!==void 0&&(t==="eq"?e===s:t==="ne"?e!==s:!1)}case"date":{let s=n==="today"?Pn(o.now,o.timeZone).date:String(n),c=String(e).slice(0,10);return/^\d{4}-\d{2}-\d{2}$/.test(s)&&ve(t,c<s?-1:c>s?1:0)}case"datetime":{let s=Date.parse(String(e)),c=n==="now"?o.now:Date.parse(String(n));return!Number.isNaN(s)&&!Number.isNaN(c)&&ve(t,s-c)}default:{let s=String(e).toLowerCase(),c=String(n).toLowerCase();return t==="eq"?s===c:t==="ne"?s!==c:t==="contains"?s.includes(c):!1}}}function ve(e,t){switch(e){case"eq":return t===0;case"ne":return t!==0;case"lt":return t<0;case"lte":return t<=0;case"gt":return t>0;case"gte":return t>=0;default:return!1}}var dt=new Map;function Pn(e,t){let n=dt.get(t);n||(n=new Intl.DateTimeFormat("en-US",{timeZone:t,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",weekday:"short"}),dt.set(t,n));let r=Object.fromEntries(n.formatToParts(new Date(e)).map(o=>[o.type,o.value]));return{date:`${r.year}-${r.month}-${r.day}`,minute:Number(r.hour)%24*60+Number(r.minute),day:String(r.weekday).slice(0,3).toLowerCase()}}var lt=e=>!!(e?.filter?.length||e?.sort||e?.limit),Rn=e=>e==null||e==="";function $n(e,t){if(!Rn(e))switch(t){case"number":case"currency":{let n=Number(e);return Number.isFinite(n)?n:void 0}case"datetime":{let n=Date.parse(String(e));return Number.isNaN(n)?void 0:n}case"boolean":return e===!0||String(e).toLowerCase()==="true"?1:0;case"date":return String(e).slice(0,10);default:return String(e).toLowerCase()}}function Nn(e,t){let n=Array.from(e),r=Array.from(t);for(let o=0;o<n.length&&o<r.length;o++){let s=n[o].codePointAt(0)-r[o].codePointAt(0);if(s!==0)return s}return n.length-r.length}function On(e,t,n,r,o){let s=e,c=Array.isArray(s?.rows)?s.rows:[],A=Array.isArray(s?.columns)?s.columns:void 0,y=i=>A?.find(l=>l.key===i)?.type??"text";for(let i of t.filter??[]){if(A&&!A.some(d=>d.key===i.column))return[];let l=i.value;if(l!==null&&typeof l=="object"){let d=l;if(l=oe(n,r,d.screen,d.key),l===void 0)return[]}let u=y(i.column);c=c.filter(d=>pt(d[i.column],i.op,l,u,o,r))}if(t.sort){let{column:i}=t.sort,l=y(i),u=t.sort.order==="desc"?-1:1;c=c.map((d,w)=>({row:d,i:w,key:$n(d[i],l)})).sort((d,w)=>{if(d.key===void 0||w.key===void 0)return d.key===void 0&&w.key===void 0?d.i-w.i:d.key===void 0?1:-1;let E=typeof d.key=="number"&&typeof w.key=="number"?d.key-w.key:Nn(String(d.key),String(w.key));return E===0?d.i-w.i:E<0?-u:u}).map(d=>d.row)}return t.limit?c.slice(0,t.limit):c}function ct(e,t,n,r,o){return!e||typeof e!="object"?e:{...e,rows:On(e,t,n,r,o)}}function ut(e){return{screen:e?.screen??null,timeZone:e?.timeZone,tables:new Proxy({},{get:(t,n)=>typeof n=="string"?e?.snapshot?.(n):void 0})}}async function ft(e,t,n,r,o,s,c,A=()=>{},y){let i=e.appInfo??n.info;nt(t),i?.id&&(t.dataset.app=i.id);let l=(p,f)=>(t.dataset.appFailed=p,{failed:p,...f?{error:f}:{}});if(!Ze(i?.requires))return l("unsupported");let u=r.appHost;if(u&&!u.custom&&!_(i))return l("unsupported");if(Ye(y,i))return Qe(e,t,n,r,o,s,c,A,y,l);let d=e.app;if(u?.held?.(d))return t.dataset.appHeld="",{held:!0};await u?.mounting?.(d,i?.id);let w=!1,E=()=>{w||(w=!0,u?.unmounted?.(d))},x;try{x=await Ke(n.hash,n.bytes,i)}catch(p){return E(),p instanceof P?l(p.reason,p.error):l("load")}let Z=x.tag,O=i?.id?r.controllerFor?.({id:i.id,instance:e.id,capability:i.player??"read"}):void 0,T,v=new Promise(p=>{T=p}),$,M=new Set,C={app:i?.id??e.app.id,element:Z,props:be(e.props??{},ut(r)),place:r.place,screen:r.screen??null,timeZone:r.timeZone??Intl.DateTimeFormat().resolvedOptions().timeZone,locale:r.locale??navigator.language,preview:!!r.preview,now:o.now,startedAt:o.startedAt,ready:()=>T(),data:(p,f)=>r.data?r.data.get(p,f):Promise.reject(new Error("no data service")),kept:(p,f)=>r.data?.kept?.(p,f),image:p=>r.data?r.data.image(p):Promise.reject(new Error("no data service")),snapshot:p=>{let f=r.snapshot?.(p)??null;if(!f||e.binding?.table!==p||!lt(e.binding))return f;let F=ct(f,e.binding,r.screen,C.timeZone,o.now());return $?.from===f&&$.rows.length===F.rows.length&&$.rows.every((bt,wt)=>bt===F.rows[wt])?$.snapshot:($={from:f,rows:F.rows,snapshot:F},F)},...e.binding?{binding:e.binding}:{},...r.onSnapshots?{onSnapshot:p=>(M.add(p),()=>{M.delete(p)})}:{},...e.sensors?.includes("impressions")&&r.impressions?.measuring?{impressions:{now:()=>r.impressions.now(),on:p=>r.impressions.on(p)}}:{},...O?{controller:O}:{}},S;try{S=Ue(Z),x.shape==="class"?x.attach(S,C):S.wyndlass=C}catch(p){return O?.dispose(),E(),l("error",j(p))}S.style.cssText="display:block;width:100%;height:100%",u?.contained?.(t,S);let B=Object.values(e.props??{}).some(p=>typeof p=="string"&&at(p)),h=r.onSnapshots?.(p=>{B&&(C.props=be(e.props??{},ut(r)));for(let f of p)for(let F of[...M])try{F(f)}catch{}}),W=new ne(S,{onStop:A,dispose:()=>{h?.(),M.clear(),O?.dispose(),E()}});t.append(S),c(W);let K=await Promise.race([v.then(()=>!1),new Promise(p=>setTimeout(()=>p(!0),s))]);return W.update(C.now()),{app:W,late:K}}var mt=new Set;async function ht(e,t){for(let n of e){let r=`${n.family}/${n.weight??400}/${n.style??"normal"}/${n.blob}`,o=t(n.blob);if(!(mt.has(r)||!o||typeof FontFace>"u"))try{let s=new FontFace(n.family,o,{weight:String(n.weight??400),style:n.style??"normal"});document.fonts.add(await s.load()),mt.add(r)}catch{}}}var Cn=Object.freeze,Ln=Object.values,gt=Reflect.apply;function se(e){if(e===null||typeof e!="object")return e;for(let t of gt(Ln,Object,[e]))se(t);return gt(Cn,Object,[e])}var ie,R,I={t:0,at:0,running:!1},H={},ke=new Set,Ae="null",xe=new Map,jn=0,N=e=>ie.postMessage(e),Se=()=>I.running?I.t+(performance.now()-I.at):I.t;addEventListener("message",e=>{ie||e.source!==parent||e.data?.type!==re||!e.ports[0]||(ie=e.ports[0],ie.onmessage=t=>In(t.data),N({type:"hello"}))});function In(e){switch(e.type){case"init":Dn(e);break;case"clock":I={t:e.t,at:performance.now(),running:e.running},R?.update(Se()),Ee();break;case"hook":{let t=e.id;(R?R.hook(e.kind,e.options):Promise.resolve()).then(()=>N({type:"hooked",id:t}));break}case"reset":R?.reset();break;case"snapshots":{let t=H;H=se(e.snapshots);let n=[...new Set([...Object.keys(t),...Object.keys(H)])].filter(r=>JSON.stringify(t[r])!==JSON.stringify(H[r]));if(n.length)for(let r of[...ke])r(n);break}case"answer":{let t=xe.get(e.id);xe.delete(e.id),e.error!==void 0?t?.reject(Object.assign(new Error("the host could not answer"),{name:e.error})):t?.resolve(e.value);break}}}function yt(e){let t=++jn;return new Promise((n,r)=>{xe.set(t,{resolve:n,reject:r}),N({type:"ask",id:t,...e})})}function Ee(){let e=R?.paging()??null,t=JSON.stringify(e);t!==Ae&&(Ae=t,N({type:"paging",paging:e}))}async function Dn(e){if(R)return;I={t:e.clock.t,at:performance.now(),running:e.clock.running},H=se(e.snapshots);let t=new Map,n=(i,l)=>`${i}?${JSON.stringify(Object.keys(l).sort().map(u=>[u,l[u]]))}`,o={data:{get:async(i,l)=>{let u=await yt({what:"data",source:i,params:l});return t.set(n(i,l),u),u},kept:(i,l)=>t.get(n(i,l)),image:async i=>{let{bytes:l,type:u}=await yt({what:"image",path:i});return URL.createObjectURL(new Blob([l],{type:u}))}},place:e.place,screen:e.screen,timeZone:e.timeZone,locale:e.locale,preview:e.preview,snapshot:i=>H[i]??null,onSnapshots:i=>(ke.add(i),()=>{ke.delete(i)})},s={now:Se,startedAt:()=>e.clock.startedAt},c=new Map(e.fonts.map(i=>[i.blob,i.bytes]));await ht(e.fonts,i=>c.get(i));let A=document.getElementById("app"),y=await ft(e.element,A,e.bundle,o,s,e.deadlineMs,i=>{R=i,Ae=JSON.stringify(i.paging()),N({type:"made",hooks:["enter","exit"].filter(l=>i.has(l)),paging:i.paging()})},i=>N({type:"stopped",...i?{error:i}:{}}));"failed"in y?N({type:"failed",reason:y.failed,...y.error?{error:y.error}:{}}):"app"in y&&(N({type:"ready",late:y.late}),Ee(),Hn())}function Hn(){let e=0,t=n=>{R?.stopped||(I.running&&R?.update(Se()),n-e>1e3&&(e=n,Ee()),requestAnimationFrame(t))};requestAnimationFrame(t)}})();
2
+ "use strict";(()=>{var vt=Object.defineProperty;var kt=(e,t,n)=>t in e?vt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var m=(e,t,n)=>kt(e,typeof t!="symbol"?t+"":t,n);var Te={apiVersion:2,properties:[{name:"device",description:"What the device is: id, type, shell and versions, model, resolution and orientation. Fixed while the player runs."},{name:"mode",description:"Where player-core runs: player, preview (in the CMS) or designer. In preview and the designer, commands change nothing."},{name:"timeZone",description:"The player's time zone (IANA), from the host.",event:"time.changed"},{name:"locale",description:"The player's locale (BCP 47), from the host."},{name:"connection",description:"Whether the player is connected to Wyndlass.",event:"connection.changed"},{name:"state",description:"starting, playing, paused, stopped (the standby screen), idle (nothing to play) or error.",event:"state.changed"},{name:"held",description:"A remote pause or stop in effect, by whom and since when; absent when none.",event:"state.changed"},{name:"content",description:"The manifest playing, when it was issued and switched to; absent when there is none.",event:"content.updated"},{name:"now",description:"What each zone shows: the item, its blob and content type, when it started, and its duration and position when known.",event:"item.start"},{name:"audio",description:"The player's volume (0 to 100) and whether it is muted; only when the host can set them.",event:"audio.changed"},{name:"display",description:"The display's power and brightness; only when the host can report them.",event:"display.changed"},{name:"emergency",description:"Emergency messages at the screen (WP-0150): what shows (none, a banner or a takeover), and of each message in force its source, severity, presentation, event, categories and whether it is a test. Never its words. Absent until the shell has said what it holds."},{name:"capabilities",description:"What the host can do: audio, display power, display brightness."}],events:[{name:"state.changed",description:"The player's state changed (playing, paused, stopped, idle, error), and who changed it."},{name:"content.updated",description:"A new manifest was switched to."},{name:"item.start",description:"An item started in a zone (source start)."},{name:"item.end",description:"An item ended in a zone (source end): completed, skipped, stopped, error, replaced by new content, or finished by its app."},{name:"item.error",description:"An item could not be shown."},{name:"connection.changed",description:"The player connected to Wyndlass or lost its connection."},{name:"audio.changed",description:"The volume or mute changed, and who changed it."},{name:"display.changed",description:"The display's power or brightness changed, and who changed it."},{name:"time.changed",description:"The clock was adjusted or the time zone changed."},{name:"emergency.changed",description:"What the screen shows of emergency messages, or the messages in force, changed."},{name:"app.command",description:"A command for apps on the screen (apps.sendCommand); an app reacts if it knows the name."},{name:"app.failed",description:"An app on the screen could not run, or misbehaved (WP-0100): its bundle did not load, it was not an app, it needs a newer player, it kept throwing and was stopped, or it was late or overran a clip."},{name:"app.held",description:"An app version was held back on this screen until the next manifest, after the page stopped answering twice in an hour while it was on screen (WP-0100)."}],commands:[{name:"player.status",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/status",description:"Everything about the player now: device, mode, time zone, locale, connection, state (and any hold), the content playing, what each zone shows, audio, display and what the host can do. Changes nothing.",idempotent:!0},{name:"player.events",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/events",result:"player-api-results.schema.json#/$defs/events",description:"The player's recent events (the last 200), oldest first, after a sequence number: state changes, content updates, item starts and ends, errors, connection, audio, display and time. Pass next as after to poll for more. Changes nothing.",idempotent:!0},{name:"time.now",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/timeNow",description:"The player's current time, its time zone and UTC offset, and whether its clock is synchronized. Changes nothing.",idempotent:!0},{name:"player.play",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Resumes or starts playback on the screen. From a remote caller it also ends a remote pause or stop.",idempotent:!0},{name:"player.pause",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Freezes the screen on what it shows now: the loop's timer and any media stop where they are. From a remote caller it holds until a remote player.play or a restart; apps cannot resume it, and new content arrives paused.",idempotent:!0},{name:"player.stop",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Stops playback and shows the standby screen (black, display on). From a remote caller it holds until a remote player.play or a restart; apps cannot restart it, and new content arrives stopped.",idempotent:!0},{name:"player.next",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Skips to the next item in a zone (main by default); the current item ends as skipped."},{name:"player.previous",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Goes back to the previous item in a zone (main by default); the current item ends as skipped."},{name:"player.playItem",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/playItem",result:"player-api-results.schema.json#/$defs/now",description:"Shows a given item of the content playing now in a zone (main by default), then continues the loop from it. Refused for an item the playing manifest does not have."},{name:"audio.setVolume",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setVolume",result:"player-api-results.schema.json#/$defs/audio",description:"Sets the player's volume, 0 to 100. Only on players whose host can set it to a level.",needs:"audio.volume",idempotent:!0},{name:"audio.setMuted",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setMuted",result:"player-api-results.schema.json#/$defs/audio",description:"Mutes or unmutes the player. Only on players whose host can.",needs:"audio",idempotent:!0},{name:"display.setPower",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setPower",result:"player-api-results.schema.json#/$defs/display",description:"Turns the display on or to standby. Only on players whose host can. Standby blanks the screen until it is turned on.",needs:"display.power",idempotent:!0},{name:"display.setBrightness",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setBrightness",result:"player-api-results.schema.json#/$defs/display",description:"Sets the display's brightness, 0 to 100. Only on players whose host can.",needs:"display.brightness",idempotent:!0},{name:"apps.sendCommand",access:"control",apps:"none",remote:!0,params:"player-api-params.schema.json#/$defs/sendCommand",result:"player-api-results.schema.json#/$defs/delivered",description:"Sends a named command, with an optional argument, to the apps on the screen; an app that knows the name reacts. Returns how many apps listen."},{name:"app.finish",access:"control",apps:"read",remote:!1,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/none",description:"An app ends its own slot now: its item ends as finished and the loop moves on. Apps only; not a tool."}],host:[{name:"host.describe",kind:"request",description:"What the device is, its time zone, locale, connection and capabilities.",result:"player-api-host.schema.json#/$defs/describeResult"},{name:"host.time",kind:"request",description:"The host's time and time zone.",result:"player-api-common.schema.json#/$defs/timeNow"},{name:"host.getAudio",kind:"request",description:"The player's volume and mute.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.setAudio",kind:"request",description:"Sets the volume, the mute or both; answers the audio after.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.getDisplay",kind:"request",description:"The display's power and brightness.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.setDisplay",kind:"request",description:"Sets the display's power, brightness or both; answers the display after.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.adRequest",kind:"request",description:"Asks Wyndlass's ad broker for one slot of a break over the host's NATS connection (WP-0075); the result is the broker's ad-decision (ad-decision.schema.json). Only a host whose describe says ads is asked."},{name:"host.mediaPrepare",kind:"request",description:"Lays a video out behind the page and prepares it to its first frame; host.mediaState says when (ADR 0055)."},{name:"host.mediaShow",kind:"request",description:"Shows and hides prepared videos; replies once its layer has changed."},{name:"host.mediaControl",kind:"request",description:"Plays, pauses or seeks a video, or asks for its position."},{name:"host.mediaRelease",kind:"request",description:"Removes a video and frees its decoder."},{name:"host.reply",kind:"reply",description:"The host's answer to a request: result or error (unsupported, failed)."},{name:"host.connection",kind:"event",description:"The connection to Wyndlass changed."},{name:"host.timeChanged",kind:"event",description:"The clock was adjusted or the time zone changed."},{name:"host.audioChanged",kind:"event",description:"The volume or mute changed outside the player."},{name:"host.displayChanged",kind:"event",description:"The display changed outside the player."},{name:"host.mediaState",kind:"event",description:"A video was prepared, started, ended or failed, or its position was asked for."},{name:"host.presence",kind:"event",description:"What one of the host's sensors sees now: the presences in view, with random ids that never leave the page (WP-0105)."},{name:"host.sensing",kind:"event",description:"The site's sensing mode as the host applies it, and its sensors (WP-0105)."},{name:"host.serialPorts",kind:"event",description:"The host's sensor controller ports, and which are open (WP-0043)."},{name:"host.serialLine",kind:"event",description:"One line from a sensor controller, as it arrived (WP-0043)."},{name:"host.serialWrite",kind:"request",description:"Writes lines to a sensor controller, a gap apart; replies once written (WP-0043)."},{name:"host.bleWatch",kind:"request",description:"What the page listens for: beacons' iBeacon UUIDs, Eddystone namespaces and addresses; replies once the scan follows it. Sent only to a host that has sent host.bleState (WP-0044)."},{name:"host.bleAdverts",kind:"event",description:"Beacon frames that match the watch, at most four a second of each kind from each beacon (WP-0044)."},{name:"host.bleState",kind:"event",description:"The host's Bluetooth scanner: scanning, idle, off, refused, missing or failed; sent only by a host that has one (WP-0044)."},{name:"host.gpioPins",kind:"event",description:"The GPIO pins the host reads, with their values (WP-0044)."},{name:"host.gpioEdge",kind:"event",description:"A GPIO pin changed (WP-0044)."},{name:"host.mcp",kind:"relay",description:"An MCP message from ctl.dev.{deviceId}, for player-core to answer."},{name:"core.ready",kind:"core",description:"player-core is ready to answer host.mcp; until then the shell answers -32002 itself."},{name:"core.mcpReply",kind:"core",description:"player-core's answer to a host.mcp, for the shell to send back."},{name:"core.sensors",kind:"core",description:"The page's sensor controllers, channels and inputs, and the beacons it hears, whenever they change, for the heartbeat and sensors.recent (WP-0043, WP-0044)."}]};var Me=Symbol.for("wyndlass.app.attach");var De=Reflect.apply,de=Object.getOwnPropertyDescriptor,Q=Object.getPrototypeOf,b=globalThis,a=(e,t,n)=>De(e,t,n),k=(e,t)=>e?de(e,t)?.get:void 0,pe=(e,t)=>e?de(e,t)?.set:void 0,g=e=>b[e]?.prototype,He=(e,t,n)=>De(e,t,n);var qn=Date.now,zn=new TextEncoder,_n=new TextDecoder,Zn=TextEncoder.prototype.encode,Kn=TextDecoder.prototype.decode;var Vn=k(Q(Uint8Array.prototype),"length");var xt=Uint8Array,St=e=>new xt(e),Et=[];for(let e=0;e<256;e++)Et[e]=(e<16?"0":"")+e.toString(16);var Tt=Object.create(null);for(let e=0;e<64;e++)Tt["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[e]]=e;var Pe=b.crypto?.subtle,le=Pe?Q(Pe):void 0,ae=b.crypto,Mt=ae?Q(ae).getRandomValues:void 0,Gn=le?.digest,Jn=le?.importKey,Yn=le?.sign;var Be=e=>a(Mt,ae,[St(e)]),Qn={setTimeout:b.setTimeout,clearTimeout:b.clearTimeout,setInterval:b.setInterval,clearInterval:b.clearInterval};var Xn=b.fetch;var q=g("MessagePort"),er=q&&q.postMessage,tr=pe(q,"onmessage"),nr=q&&q.start,ce=g("MessageEvent"),rr=k(ce,"data"),sr=k(ce,"ports"),or=k(ce,"source");var We=g("EventTarget"),ir=We?.addEventListener,ar=We?.removeEventListener;var dr=b.Worker,G=g("Worker"),pr=G&&G.postMessage,lr=pe(G,"onmessage"),cr=pe(G,"onerror");var Fe=b.Blob,J=b.URL,Re=J?.createObjectURL,Pt=J?.revokeObjectURL,ue=Fe&&Re?{make:(e,t)=>a(Re,J,[new Fe(e,{type:t})]),revoke:e=>a(Pt,J,[e])}:void 0,U=b.customElements,me=U?Q(U):void 0,Ft=me?.define,Rt=me?.get,fe=U&&me?{define:(e,t)=>a(Ft,U,[e,t]),get:e=>a(Rt,U,[e])}:void 0,$t=b.document,Y=g("Document"),Nt=Y?.createElement,ur=Y?.createElementNS,Ot=WeakSet.prototype.add,mr=WeakSet.prototype.has,Ct=new WeakSet;var Lt=(e,t)=>(a(Ot,e,[t]),t);function Ue(e){return Lt(Ct,a(Nt,$t,[e]))}var z=g("Node"),he=g("Element"),X=g("HTMLElement"),D=e=>k(z,e),$e=D("parentNode"),jt=D("firstChild"),It=D("lastChild"),Dt=D("nextSibling"),Ht=D("nodeType"),Bt=D("childNodes"),Wt=k(he,"localName"),Ut=z?.appendChild,qt=z?.insertBefore,zt=z?.removeChild,L=he,_t=L?.getAttribute,Zt=L?.getAttributeNames,Kt=L?.setAttribute,Vt=L?.removeAttribute,Gt=L?.matches,Jt=L?.attachShadow,Yt=L?.querySelectorAll,Qt=g("HTMLDialogElement")?.close,Xt=k(g("NodeList"),"length"),en=g("NodeList")?.item,ee=g("MutationRecord"),tn=k(ee,"type"),nn=k(ee,"target"),rn=k(ee,"addedNodes"),sn=k(ee,"removedNodes"),Ne=b.MutationObserver,on=g("MutationObserver")?.observe,qe=Y?de(Y,"adoptedStyleSheets"):void 0,Oe=qe?.get,Ce=qe?.set,an=b.requestAnimationFrame,Le=k(X,"style"),te=g("CSSStyleDeclaration"),dn=te?.getPropertyValue,pn=te?.getPropertyPriority,ln=te?.setProperty,je=X?.showPopover,Ie=X?.hidePopover,cn=k(g("Event"),"target"),un=g("Event")?.stopImmediatePropagation,V=e=>{let t=[];for(let n=0,r=a(Xt,e,[]);n<r;n++)t[n]=a(en,e,[n]);return t},ze=Ne&&z&&he&&X&&te?{parent:e=>a($e,e,[]),first:e=>a(jt,e,[]),last:e=>a(It,e,[]),next:e=>a(Dt,e,[]),isElement:e=>a(Ht,e,[])===1,name:e=>a(Wt,e,[]),children:e=>V(a(Bt,e,[])),append:(e,t)=>a(Ut,e,[t]),insert:(e,t,n)=>a(qt,e,[t,n]),remove:e=>{let t=a($e,e,[]);t&&a(zt,t,[e])},attribute:(e,t)=>a(_t,e,[t]),attributes:e=>a(Zt,e,[]),setAttribute:(e,t,n)=>a(Kt,e,[t,n]),removeAttribute:(e,t)=>a(Vt,e,[t]),matches:(e,t)=>a(Gt,e,[t]),all:(e,t)=>V(a(Yt,e,[t])),closeDialog:e=>a(Qt,e,[]),shadow:e=>a(Jt,e,[{mode:"closed"}]),style:(e,t)=>{let n=a(Le,e,[]);return[a(dn,n,[t]),a(pn,n,[t])]},setStyle:(e,t,n,r="")=>a(ln,a(Le,e,[]),[t,n,r]),observer:e=>new Ne(e),observe:(e,t,n)=>a(on,e,[t,n]),record:e=>({type:a(tn,e,[]),target:a(nn,e,[]),added:V(a(rn,e,[])),removed:V(a(sn,e,[]))}),adopted:Oe&&Ce?{count:e=>a(Oe,e,[]).length,clear:e=>a(Ce,e,[[]])}:void 0,frame:e=>a(an,globalThis,[e]),popover:je&&Ie?{show:e=>a(je,e,[]),hide:e=>a(Ie,e,[])}:void 0,target:e=>a(cn,e,[]),stop:e=>a(un,e,[])}:void 0;var F=class extends Error{constructor(n,r){super(`the app could not run (${n})`);m(this,"reason",n);m(this,"error",r)}};function j(e){try{let t=e instanceof Error?e.name:void 0;return typeof t=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(t)?t:void 0}catch{return}}function _(e){let t=e?.id;if(typeof t!="string"||t==="")return!0;for(let n=0;n<_e.length;n++)if(t[n]!==_e[n])return!1;return!0}var _e="com.wyndlass.";function mn(e=typeof navigator>"u"?"":navigator.userAgent){let t=/Chrom(?:e|ium)\/(\d+)/.exec(e);return t?Number(t[1]):void 0}function Ze(e,t=Te.apiVersion,n=mn()){return!(e?.playerApi!==void 0&&e.playerApi>t||e?.webView!==void 0&&n!==void 0&&e.webView>n)}function fn(e){let t;try{t=e.paging?.()}catch{return null}let n=t;return n&&Number.isInteger(n.count)&&n.count>1&&typeof n.ms=="number"&&n.ms>0?{count:n.count,ms:n.ms}:null}var ge=new Map;function hn(){let e=Be(8),t="";for(let n=0;n<8;n++)t+=gn[e[n]%26];return t}var gn="abcdefghijklmnopqrstuvwxyz",yn=0;function Ke(e,t,n){let r=ge.get(e);if(!r){let s=ue.make([t],"text/javascript");r=import(s).then(o=>bn(o,n),o=>{throw o instanceof F?o:new F("load",j(o))}).finally(()=>ue.revoke(s)),ge.set(e,r),r.catch(()=>ge.delete(e))}return r}function bn(e,t){let n=e.default;if(typeof n=="function"&&n.prototype instanceof HTMLElement){let r=n.prototype[Me];if(typeof r!="function")throw new F("shape");let s=class extends n{},o=`${t?.element??"wl-app"}-${hn()}${++yn}`;try{fe.define(o,s)}catch(c){throw new F("shape",j(c))}return{tag:o,shape:"class",attach:(c,A)=>{He(r,c,[A])}}}if(_(t)&&typeof e.element=="string"&&fe.get(e.element))return{tag:e.element,shape:"legacy"};throw new F("shape")}var wn=3,vn=6e4,ne=class{constructor(t,n){m(this,"element",t);m(this,"o",n);m(this,"faults",[]);m(this,"halted",!1)}get stopped(){return this.halted}has(t){try{return!this.halted&&typeof this.element[t]=="function"}catch{return!1}}update(t){this.halted||this.run(()=>this.element.update?.(t))}reset(){this.halted||this.run(()=>this.element.reset?.())}paging(){return this.halted?null:fn(this.element)}hook(t,n){if(this.halted)return Promise.resolve();let r;try{r=this.element[t]?.(n)}catch(s){return this.fault(s),Promise.resolve()}return Promise.resolve(r).then(()=>{},s=>this.fault(s))}stop(t){if(!this.halted){this.halted=!0;try{this.element.remove()}catch{}this.o.dispose?.(),this.o.onStop(t)}}dispose(){this.o.dispose?.()}run(t){try{t()}catch(n){this.fault(n)}}fault(t){let n=(this.o.now??Date.now)();this.faults=this.faults.filter(r=>n-r<vn),this.faults.push(n),this.faults.length>=wn&&this.stop(j(t))}},br=24*3600*1e3;var re="wyndlass.frame";function Ye(e,t){return!!e&&(e.apps?e.apps(t):!_(t))}var kn=new Set(["load","shape","unsupported","error","late","overran"]),Ve=50,Ge=250,ye=class{constructor(t,n,r,s){m(this,"frame",t);m(this,"port",n);m(this,"o",s);m(this,"halted",!1);m(this,"pages");m(this,"hooks");m(this,"pending",new Map);m(this,"next",0);m(this,"told");m(this,"last");m(this,"quiet");this.hooks=new Set(r.hooks),this.pages=r.paging}get stopped(){return this.halted}has(t){return!this.halted&&this.hooks.has(t)}paging(){return this.halted?null:this.pages}update(t){if(this.halted)return;let n=performance.now(),r=this.last;this.last={t,at:n};let s=this.told;if(s&&(s.running?Math.abs(t-(s.t+(n-s.at)))<=Ve:t===s.t)){s.running&&this.watch();return}let o=!!r&&n-r.at<Ge&&t>r.t&&Math.abs(t-r.t-(n-r.at))<=Ve;this.told={t,at:n,running:o},this.post({type:"clock",t,running:o}),o&&this.watch()}reset(){this.halted||this.post({type:"reset"})}snapshots(t){this.halted||this.post({type:"snapshots",snapshots:t})}hook(t,n){if(this.halted)return Promise.resolve();let r=++this.next;return new Promise(s=>{this.pending.set(r,s),this.post({type:"hook",id:r,kind:t,options:n})})}stop(t){this.halted||(this.halted=!0,this.frame.remove(),this.dispose(),this.o.onStop(t))}dispose(){this.o.dispose?.(),clearTimeout(this.quiet),this.port.close();for(let t of this.pending.values())t();this.pending.clear()}heard(t){t.type==="paging"?this.pages=Xe(t.paging):t.type==="hooked"&&typeof t.id=="number"?(this.pending.get(t.id)?.(),this.pending.delete(t.id)):t.type==="stopped"&&this.stop(et(t.error))}post(t){try{this.port.postMessage(t)}catch{}}watch(){clearTimeout(this.quiet),this.quiet=setTimeout(()=>{!this.told?.running||!this.last||this.halted||(this.told={...this.last,running:!1},this.post({type:"clock",t:this.last.t,running:!1}))},Ge)}};async function Qe(e,t,n,r,s,o,c,A,y,i){let l=e.appInfo??n.info,u;try{u=new URL(y.frames).origin}catch{return i("unsupported")}let d=document.createElement("iframe");d.setAttribute("sandbox","allow-scripts"),d.setAttribute("referrerpolicy","no-referrer"),d.title=l?.id??"app",d.tabIndex=-1,d.dataset.frame=l?.id??"",d.style.cssText="display:block;width:100%;height:100%;border:0;pointer-events:none;background:transparent;color-scheme:normal";let w=new Promise(T=>{d.addEventListener("load",()=>T(!0),{once:!0}),setTimeout(()=>T(!1),o)});d.src=`${u}/`,t.append(d);let E=(T,v)=>(d.remove(),i(T,v));if(!await w||!d.contentWindow)return E("load");let{port1:x,port2:Z}=new MessageChannel,O={type:"init",element:{id:e.id,type:"app",app:e.app,props:e.props??{},...e.binding?{binding:e.binding}:{},...e.appInfo?{appInfo:e.appInfo}:{}},bundle:{hash:n.hash,bytes:n.bytes.slice(),...n.info?{info:n.info}:{}},...r.place?{place:r.place}:{},screen:r.screen??null,timeZone:r.timeZone,locale:r.locale,preview:!!r.preview,clock:{t:s.now(),running:!1,startedAt:s.startedAt()},fonts:Sn(e.props??{},y),snapshots:Je(e,r),deadlineMs:o};return new Promise(T=>{let v,$=!1,M=B=>{$||($=!0,clearTimeout(C),T(B))},C=setTimeout(()=>{v?(M({app:v,late:!0}),v.update(s.now())):(x.close(),M(E("load")))},o+1e3),S=!1;x.onmessage=B=>{let h=B.data;if(!(!h||typeof h!="object")){if(h.type==="ask"){S&&An(h,r,x);return}if(v){h.type==="ready"?(M({app:v,late:h.late===!0}),v.update(s.now())):v.heard(h);return}if(h.type==="hello"&&!S)S=!0,x.postMessage(O,[O.bundle.bytes.buffer]);else if(h.type==="made"&&Array.isArray(h.hooks)){let W=tt(e),K,p=new ye(d,x,{type:"made",hooks:h.hooks.filter(f=>f==="enter"||f==="exit"),paging:Xe(h.paging)},{onStop:A,dispose:()=>K?.()});K=r.onSnapshots?.(f=>{f.some(P=>W.has(P))&&p.snapshots(Je(e,r))}),v=p,c(v)}else h.type==="failed"&&(x.close(),M(E(kn.has(h.reason)?h.reason:"error",et(h.error))))}},d.contentWindow.postMessage({type:re},"*",[Z])})}async function An(e,t,n){if(typeof e.id!="number")return;let r=(s,o=[])=>{try{n.postMessage(s,o)}catch{}};try{if(!t.data)throw new Error("no data service");if(e.what==="data"&&typeof e.source=="string")r({type:"answer",id:e.id,value:await t.data.get(e.source,xn(e.params))});else if(e.what==="image"&&typeof e.path=="string"){let s=await t.data.imageBlob(e.path),o=new Uint8Array(await s.arrayBuffer());r({type:"answer",id:e.id,value:{bytes:o,type:s.type}},[o.buffer])}else throw new TypeError("not a question")}catch(s){r({type:"answer",id:e.id,error:j(s)??"Error"})}}function xn(e){let t={};if(e&&typeof e=="object")for(let[n,r]of Object.entries(e))(typeof r=="string"||typeof r=="number"||typeof r=="boolean")&&(t[n]=r);return t}function Xe(e){let t=e;return t&&Number.isInteger(t.count)&&t.count>1&&typeof t.ms=="number"&&t.ms>0?{count:t.count,ms:t.ms}:null}function et(e){return typeof e=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(e)?e:void 0}function Sn(e,t){let n=new Set;for(let s of Object.values(e)){let o=s?.family;s&&typeof s=="object"&&typeof o=="string"&&n.add(o)}let r=[];for(let s of t.fonts??[]){let o=n.has(s.family)?t.font?.(s.blob):void 0;o&&r.push({family:s.family,weight:s.weight,style:s.style,blob:s.blob,bytes:o.slice()})}return r}function tt(e){let t=new Set;e.binding?.table&&t.add(e.binding.table);for(let n of Object.values(e.props??{}))typeof n=="string"&&/^tbl_[0-9a-z]{26}$/.test(n)&&t.add(n);return t}function Je(e,t){let n={};for(let r of tt(e)){let s=t.snapshot?.(r);s&&(n[r]=s)}return n}function nt(e){let t=ze?.setStyle??((n,r,s,o)=>n.style.setProperty(r,s,o));t(e,"contain","strict","important"),t(e,"overflow","clip","important")}var En=["name","type","tags","location","site","district","region","organization","path","timeZone"],Tn=["text","date","currency","truncate"],rt={site:"SITE",district:"DISTRICT",region:"REGION",organization:"ORGANIZATION"};function se(e,t,n,r){if(!e)return n==="timeZone"&&t?t:void 0;if(n==="fields")return r&&e.fields?.[r]||void 0;let s=e.path??[];switch(n){case"name":return e.name||void 0;case"type":return e.type||void 0;case"tags":return e.tags?.length?e.tags.join(", "):void 0;case"location":return s.at(-1)?.name;case"path":return s.length?s.map(o=>o.name).join(" \u203A "):void 0;case"timeZone":return t||void 0;default:return rt[n]?[...s].reverse().find(o=>o.kind===rt[n])?.name:void 0}}function Mn(e,t){if(e==null||e==="")return;let n=String(e);if(t==="currency"){let r=Number(e);return Number.isFinite(r)?r.toFixed(2):n}if(t==="date"){let r=Date.parse(n);return Number.isNaN(r)?n:new Date(r).toISOString().slice(0,10)}return t==="truncate"&&n.length>40?n.slice(0,39)+"\u2026":n}function st(e,t){return(e.source==="screen"?se(t.screen,t.timeZone,e.field,e.key):Mn(t.tables?.[e.table]?.rows?.[e.row??0]?.[e.column],e.format))??e.fallback??""}function ot(e){let t=/^\s*(?:screen\.(fields\.[a-z][A-Za-z0-9]{0,31}|[A-Za-z]+)|table\.([A-Za-z0-9_-]+)\[(\d+)\](?:\.([A-Za-z0-9_]+)|\["((?:[^"\\]|\\.)*)"\]))\s*((?:\|\s*(?:[a-z]+|"(?:[^"\\]|\\.)*")\s*)*)$/.exec(e);if(!t)return null;let n=[...t[6].matchAll(/\|\s*([a-z]+|"((?:[^"\\]|\\.)*)")/g)],r=n.find(o=>o[1].startsWith('"'))?.[2]?.replace(/\\(.)/g,"$1"),s=n.find(o=>!o[1].startsWith('"'))?.[1];return t[1]!==void 0?s?null:t[1].startsWith("fields.")?{source:"screen",field:"fields",key:t[1].slice(7),...r!==void 0?{fallback:r}:{}}:En.includes(t[1])?{source:"screen",field:t[1],...r!==void 0?{fallback:r}:{}}:null:s&&!Tn.includes(s)?null:{source:"table",table:t[2],row:Number(t[3]),column:t[4]??t[5].replace(/\\(.)/g,"$1"),...s?{format:s}:{},...r!==void 0?{fallback:r}:{}}}function it(e,t){return e.replace(/\{{2}([^{}]*)\}{2}/g,(n,r)=>{let s=ot(r);return s?st(s,t):n})}function at(e){return[...e.matchAll(/\{{2}([^{}]*)\}{2}/g)].some(t=>ot(t[1])!==null)}function be(e,t){return Object.fromEntries(Object.entries(e).map(([n,r])=>[n,typeof r=="string"?it(r,t):r]))}var we=e=>e==null||e==="";function pt(e,t,n,r,s,o){return Pn(e,t,n,r,{now:s,timeZone:o})}function Pn(e,t,n,r,s){if(n===null&&(t==="eq"||t==="ne"))return t==="eq"?we(e):!we(e);if(we(e)||n===null||n===void 0)return!1;switch(r){case"number":case"currency":{let o=Number(e),c=Number(n);return typeof n!="boolean"&&n!==""&&Number.isFinite(o)&&Number.isFinite(c)&&ve(t,o-c)}case"boolean":{let o=n===!0||n==="true"?!0:n===!1||n==="false"?!1:void 0;return o!==void 0&&(t==="eq"?e===o:t==="ne"?e!==o:!1)}case"date":{let o=n==="today"?Fn(s.now,s.timeZone).date:String(n),c=String(e).slice(0,10);return/^\d{4}-\d{2}-\d{2}$/.test(o)&&ve(t,c<o?-1:c>o?1:0)}case"datetime":{let o=Date.parse(String(e)),c=n==="now"?s.now:Date.parse(String(n));return!Number.isNaN(o)&&!Number.isNaN(c)&&ve(t,o-c)}default:{let o=String(e).toLowerCase(),c=String(n).toLowerCase();return t==="eq"?o===c:t==="ne"?o!==c:t==="contains"?o.includes(c):!1}}}function ve(e,t){switch(e){case"eq":return t===0;case"ne":return t!==0;case"lt":return t<0;case"lte":return t<=0;case"gt":return t>0;case"gte":return t>=0;default:return!1}}var dt=new Map;function Fn(e,t){let n=dt.get(t);n||(n=new Intl.DateTimeFormat("en-US",{timeZone:t,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",weekday:"short"}),dt.set(t,n));let r=Object.fromEntries(n.formatToParts(new Date(e)).map(s=>[s.type,s.value]));return{date:`${r.year}-${r.month}-${r.day}`,minute:Number(r.hour)%24*60+Number(r.minute),day:String(r.weekday).slice(0,3).toLowerCase()}}var lt=e=>!!(e?.filter?.length||e?.sort||e?.limit),Rn=e=>e==null||e==="";function $n(e,t){if(!Rn(e))switch(t){case"number":case"currency":{let n=Number(e);return Number.isFinite(n)?n:void 0}case"datetime":{let n=Date.parse(String(e));return Number.isNaN(n)?void 0:n}case"boolean":return e===!0||String(e).toLowerCase()==="true"?1:0;case"date":return String(e).slice(0,10);default:return String(e).toLowerCase()}}function Nn(e,t){let n=Array.from(e),r=Array.from(t);for(let s=0;s<n.length&&s<r.length;s++){let o=n[s].codePointAt(0)-r[s].codePointAt(0);if(o!==0)return o}return n.length-r.length}function On(e,t,n,r,s){let o=e,c=Array.isArray(o?.rows)?o.rows:[],A=Array.isArray(o?.columns)?o.columns:void 0,y=i=>A?.find(l=>l.key===i)?.type??"text";for(let i of t.filter??[]){if(A&&!A.some(d=>d.key===i.column))return[];let l=i.value;if(l!==null&&typeof l=="object"){let d=l;if(l=se(n,r,d.screen,d.key),l===void 0)return[]}let u=y(i.column);c=c.filter(d=>pt(d[i.column],i.op,l,u,s,r))}if(t.sort){let{column:i}=t.sort,l=y(i),u=t.sort.order==="desc"?-1:1;c=c.map((d,w)=>({row:d,i:w,key:$n(d[i],l)})).sort((d,w)=>{if(d.key===void 0||w.key===void 0)return d.key===void 0&&w.key===void 0?d.i-w.i:d.key===void 0?1:-1;let E=typeof d.key=="number"&&typeof w.key=="number"?d.key-w.key:Nn(String(d.key),String(w.key));return E===0?d.i-w.i:E<0?-u:u}).map(d=>d.row)}return t.limit?c.slice(0,t.limit):c}function ct(e,t,n,r,s){return!e||typeof e!="object"?e:{...e,rows:On(e,t,n,r,s)}}function ut(e){return{screen:e?.screen??null,timeZone:e?.timeZone,tables:new Proxy({},{get:(t,n)=>typeof n=="string"?e?.snapshot?.(n):void 0})}}async function ft(e,t,n,r,s,o,c,A=()=>{},y){let i=e.appInfo??n.info;nt(t),i?.id&&(t.dataset.app=i.id);let l=(p,f)=>(t.dataset.appFailed=p,{failed:p,...f?{error:f}:{}});if(!Ze(i?.requires))return l("unsupported");let u=r.appHost;if(u&&!u.custom&&!_(i))return l("unsupported");if(Ye(y,i))return Qe(e,t,n,r,s,o,c,A,y,l);let d=e.app;if(u?.held?.(d))return t.dataset.appHeld="",{held:!0};await u?.mounting?.(d,i?.id);let w=!1,E=()=>{w||(w=!0,u?.unmounted?.(d))},x;try{x=await Ke(n.hash,n.bytes,i)}catch(p){return E(),p instanceof F?l(p.reason,p.error):l("load")}let Z=x.tag,O=i?.id?r.controllerFor?.({id:i.id,instance:e.id,capability:i.player??"read"}):void 0,T,v=new Promise(p=>{T=p}),$,M=new Set,C={app:i?.id??e.app.id,element:Z,props:be(e.props??{},ut(r)),place:r.place,screen:r.screen??null,timeZone:r.timeZone??Intl.DateTimeFormat().resolvedOptions().timeZone,locale:r.locale??navigator.language,preview:!!r.preview,now:s.now,startedAt:s.startedAt,ready:()=>T(),data:(p,f)=>r.data?r.data.get(p,f):Promise.reject(new Error("no data service")),kept:(p,f)=>r.data?.kept?.(p,f),image:p=>r.data?r.data.image(p):Promise.reject(new Error("no data service")),snapshot:p=>{let f=r.snapshot?.(p)??null;if(!f||e.binding?.table!==p||!lt(e.binding))return f;let P=ct(f,e.binding,r.screen,C.timeZone,s.now());return $?.from===f&&$.rows.length===P.rows.length&&$.rows.every((bt,wt)=>bt===P.rows[wt])?$.snapshot:($={from:f,rows:P.rows,snapshot:P},P)},...e.binding?{binding:e.binding}:{},...r.onSnapshots?{onSnapshot:p=>(M.add(p),()=>{M.delete(p)})}:{},...e.sensors?.includes("impressions")&&r.impressions?.measuring?{impressions:{now:()=>r.impressions.now(),on:p=>r.impressions.on(p)}}:{},...O?{controller:O}:{}},S;try{S=Ue(Z),x.shape==="class"?x.attach(S,C):S.wyndlass=C}catch(p){return O?.dispose(),E(),l("error",j(p))}S.style.cssText="display:block;width:100%;height:100%",u?.contained?.(t,S);let B=Object.values(e.props??{}).some(p=>typeof p=="string"&&at(p)),h=r.onSnapshots?.(p=>{B&&(C.props=be(e.props??{},ut(r)));for(let f of p)for(let P of[...M])try{P(f)}catch{}}),W=new ne(S,{onStop:A,dispose:()=>{h?.(),M.clear(),O?.dispose(),E()}});t.append(S),c(W);let K=await Promise.race([v.then(()=>!1),new Promise(p=>setTimeout(()=>p(!0),o))]);return W.update(C.now()),{app:W,late:K}}var mt=new Set;async function ht(e,t){for(let n of e){let r=`${n.family}/${n.weight??400}/${n.style??"normal"}/${n.blob}`,s=t(n.blob);if(!(mt.has(r)||!s||typeof FontFace>"u"))try{let o=new FontFace(n.family,s,{weight:String(n.weight??400),style:n.style??"normal"});document.fonts.add(await o.load()),mt.add(r)}catch{}}}var Cn=Object.freeze,Ln=Object.values,gt=Reflect.apply;function oe(e){if(e===null||typeof e!="object")return e;for(let t of gt(Ln,Object,[e]))oe(t);return gt(Cn,Object,[e])}var ie,R,I={t:0,at:0,running:!1},H={},ke=new Set,Ae="null",xe=new Map,jn=0,N=e=>ie.postMessage(e),Se=()=>I.running?I.t+(performance.now()-I.at):I.t;addEventListener("message",e=>{ie||e.source!==parent||e.data?.type!==re||!e.ports[0]||(ie=e.ports[0],ie.onmessage=t=>In(t.data),N({type:"hello"}))});function In(e){switch(e.type){case"init":Dn(e);break;case"clock":I={t:e.t,at:performance.now(),running:e.running},R?.update(Se()),Ee();break;case"hook":{let t=e.id;(R?R.hook(e.kind,e.options):Promise.resolve()).then(()=>N({type:"hooked",id:t}));break}case"reset":R?.reset();break;case"snapshots":{let t=H;H=oe(e.snapshots);let n=[...new Set([...Object.keys(t),...Object.keys(H)])].filter(r=>JSON.stringify(t[r])!==JSON.stringify(H[r]));if(n.length)for(let r of[...ke])r(n);break}case"answer":{let t=xe.get(e.id);xe.delete(e.id),e.error!==void 0?t?.reject(Object.assign(new Error("the host could not answer"),{name:e.error})):t?.resolve(e.value);break}}}function yt(e){let t=++jn;return new Promise((n,r)=>{xe.set(t,{resolve:n,reject:r}),N({type:"ask",id:t,...e})})}function Ee(){let e=R?.paging()??null,t=JSON.stringify(e);t!==Ae&&(Ae=t,N({type:"paging",paging:e}))}async function Dn(e){if(R)return;I={t:e.clock.t,at:performance.now(),running:e.clock.running},H=oe(e.snapshots);let t=new Map,n=(i,l)=>`${i}?${JSON.stringify(Object.keys(l).sort().map(u=>[u,l[u]]))}`,s={data:{get:async(i,l)=>{let u=await yt({what:"data",source:i,params:l});return t.set(n(i,l),u),u},kept:(i,l)=>t.get(n(i,l)),image:async i=>{let{bytes:l,type:u}=await yt({what:"image",path:i});return URL.createObjectURL(new Blob([l],{type:u}))}},place:e.place,screen:e.screen,timeZone:e.timeZone,locale:e.locale,preview:e.preview,snapshot:i=>H[i]??null,onSnapshots:i=>(ke.add(i),()=>{ke.delete(i)})},o={now:Se,startedAt:()=>e.clock.startedAt},c=new Map(e.fonts.map(i=>[i.blob,i.bytes]));await ht(e.fonts,i=>c.get(i));let A=document.getElementById("app"),y=await ft(e.element,A,e.bundle,s,o,e.deadlineMs,i=>{R=i,Ae=JSON.stringify(i.paging()),N({type:"made",hooks:["enter","exit"].filter(l=>i.has(l)),paging:i.paging()})},i=>N({type:"stopped",...i?{error:i}:{}}));"failed"in y?N({type:"failed",reason:y.failed,...y.error?{error:y.error}:{}}):"app"in y&&(N({type:"ready",late:y.late}),Ee(),Hn())}function Hn(){let e=0,t=n=>{R?.stopped||(I.running&&R?.update(Se()),n-e>1e3&&(e=n,Ee()),requestAnimationFrame(t))};requestAnimationFrame(t)}})();
@@ -1,7 +1,42 @@
1
1
  /* @wyndlass/app-sdk's preview: player-core's host, compiled. MIT, (c) Northwynd Labs LLC. */
2
- "use strict";(()=>{var as=Object.defineProperty;var ls=(t,e,n)=>e in t?as(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var h=(t,e,n)=>ls(t,typeof e!="symbol"?e+"":e,n);var Ht=Reflect.apply,qe=Object.getOwnPropertyDescriptor,Ae=Object.getPrototypeOf,N=globalThis,x=(t,e,n)=>Ht(t,e,n),D=(t,e)=>t?qe(t,e)?.get:void 0,We=(t,e)=>t?qe(t,e)?.set:void 0,C=t=>N[t]?.prototype,Bt=(t,e,n)=>Ht(t,e,n);var yi=Date.now,bi=new TextEncoder,wi=new TextDecoder,vi=TextEncoder.prototype.encode,ki=TextDecoder.prototype.decode;var xi=D(Ae(Uint8Array.prototype),"length");var ds=Uint8Array,ps=t=>new ds(t),cs=[];for(let t=0;t<256;t++)cs[t]=(t<16?"0":"")+t.toString(16);var us=Object.create(null);for(let t=0;t<64;t++)us["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[t]]=t;var Lt=N.crypto?.subtle,ze=Lt?Ae(Lt):void 0,_e=N.crypto,hs=_e?Ae(_e).getRandomValues:void 0,Mi=ze?.digest,Ai=ze?.importKey,Si=ze?.sign;var Ut=t=>x(hs,_e,[ps(t)]),Ei={setTimeout:N.setTimeout,clearTimeout:N.clearTimeout,setInterval:N.setInterval,clearInterval:N.clearInterval};var Ti=N.fetch;var oe=C("MessagePort"),Pi=oe&&oe.postMessage,Li=We(oe,"onmessage"),Ii=oe&&oe.start,Ve=C("MessageEvent"),Ci=D(Ve,"data"),Ri=D(Ve,"ports"),Ni=D(Ve,"source");var _t=C("EventTarget"),Oi=_t?.addEventListener,$i=_t?.removeEventListener;var Di=N.Worker,ke=C("Worker"),ji=ke&&ke.postMessage,Fi=We(ke,"onmessage"),Hi=We(ke,"onerror");var It=N.Blob,xe=N.URL,Ct=xe?.createObjectURL,ms=xe?.revokeObjectURL,Ke=It&&Ct?{make:(t,e)=>x(Ct,xe,[new It(t,{type:e})]),revoke:t=>x(ms,xe,[t])}:void 0,re=N.customElements,Ze=re?Ae(re):void 0,fs=Ze?.define,gs=Ze?.get,Je=re&&Ze?{define:(t,e)=>x(fs,re,[t,e]),get:t=>x(gs,re,[t])}:void 0,qt=N.document,Me=C("Document"),ys=Me?.createElement,bs=Me?.createElementNS,ws=WeakSet.prototype.add,Bi=WeakSet.prototype.has,Ye=new WeakSet,vs=new WeakSet,Se=(t,e)=>(x(ws,t,[e]),e);function H(t){return Se(Ye,x(ys,qt,[t]))}var Ee=t=>Se(Ye,x(bs,qt,["http://www.w3.org/2000/svg",t]));var X=t=>Se(vs,t);var ae=C("Node"),Xe=C("Element"),Te=C("HTMLElement"),G=t=>D(ae,t),Rt=G("parentNode"),ks=G("firstChild"),xs=G("lastChild"),Ms=G("nextSibling"),As=G("nodeType"),Ss=G("childNodes"),Es=D(Xe,"localName"),Ts=ae?.appendChild,Ps=ae?.insertBefore,Ls=ae?.removeChild,K=Xe,Is=K?.getAttribute,Cs=K?.getAttributeNames,Rs=K?.setAttribute,Ns=K?.removeAttribute,Os=K?.matches,$s=K?.attachShadow,Ds=K?.querySelectorAll,js=C("HTMLDialogElement")?.close,Fs=D(C("NodeList"),"length"),Hs=C("NodeList")?.item,Pe=C("MutationRecord"),Bs=D(Pe,"type"),Us=D(Pe,"target"),_s=D(Pe,"addedNodes"),qs=D(Pe,"removedNodes"),Nt=N.MutationObserver,Ws=C("MutationObserver")?.observe,Wt=Me?qe(Me,"adoptedStyleSheets"):void 0,Ot=Wt?.get,$t=Wt?.set,zs=N.requestAnimationFrame,Dt=D(Te,"style"),Le=C("CSSStyleDeclaration"),Vs=Le?.getPropertyValue,Ks=Le?.getPropertyPriority,Zs=Le?.setProperty,jt=Te?.showPopover,Ft=Te?.hidePopover,Js=D(C("Event"),"target"),Ys=C("Event")?.stopImmediatePropagation,ve=t=>{let e=[];for(let n=0,s=x(Fs,t,[]);n<s;n++)e[n]=x(Hs,t,[n]);return e},ie=Nt&&ae&&Xe&&Te&&Le?{parent:t=>x(Rt,t,[]),first:t=>x(ks,t,[]),last:t=>x(xs,t,[]),next:t=>x(Ms,t,[]),isElement:t=>x(As,t,[])===1,name:t=>x(Es,t,[]),children:t=>ve(x(Ss,t,[])),append:(t,e)=>x(Ts,t,[e]),insert:(t,e,n)=>x(Ps,t,[e,n]),remove:t=>{let e=x(Rt,t,[]);e&&x(Ls,e,[t])},attribute:(t,e)=>x(Is,t,[e]),attributes:t=>x(Cs,t,[]),setAttribute:(t,e,n)=>x(Rs,t,[e,n]),removeAttribute:(t,e)=>x(Ns,t,[e]),matches:(t,e)=>x(Os,t,[e]),all:(t,e)=>ve(x(Ds,t,[e])),closeDialog:t=>x(js,t,[]),shadow:t=>x($s,t,[{mode:"closed"}]),style:(t,e)=>{let n=x(Dt,t,[]);return[x(Vs,n,[e]),x(Ks,n,[e])]},setStyle:(t,e,n,s="")=>x(Zs,x(Dt,t,[]),[e,n,s]),observer:t=>new Nt(t),observe:(t,e,n)=>x(Ws,t,[e,n]),record:t=>({type:x(Bs,t,[]),target:x(Us,t,[]),added:ve(x(_s,t,[])),removed:ve(x(qs,t,[]))}),adopted:Ot&&$t?{count:t=>x(Ot,t,[]).length,clear:t=>x($t,t,[[]])}:void 0,frame:t=>x(zs,globalThis,[t]),popover:jt&&Ft?{show:t=>x(jt,t,[]),hide:t=>x(Ft,t,[])}:void 0,target:t=>x(Js,t,[]),stop:t=>x(Ys,t,[])}:void 0;function Ge(t){if(Se(Ye,t),ie)for(let e of ie.children(t))ie.isElement(e)&&Ge(e);return t}var Xs;function Qe(t,e){try{Xs?.caught(t,e)}catch{}}var et=t=>new TextEncoder().encode(t);function Gs(t){let e=t instanceof Uint8Array?t:new Uint8Array(t),n="";for(let s of e)n+=s.toString(16).padStart(2,"0");return n}async function tt(t){return Gs(await crypto.subtle.digest("SHA-256",t))}var Qs=["name","type","tags","location","site","district","region","organization","path","timeZone"],er=["text","date","currency","truncate"],zt={site:"SITE",district:"DISTRICT",region:"REGION",organization:"ORGANIZATION"};function Ie(t,e,n,s){if(!t)return n==="timeZone"&&e?e:void 0;if(n==="fields")return s&&t.fields?.[s]||void 0;let r=t.path??[];switch(n){case"name":return t.name||void 0;case"type":return t.type||void 0;case"tags":return t.tags?.length?t.tags.join(", "):void 0;case"location":return r.at(-1)?.name;case"path":return r.length?r.map(o=>o.name).join(" \u203A "):void 0;case"timeZone":return e||void 0;default:return zt[n]?[...r].reverse().find(o=>o.kind===zt[n])?.name:void 0}}function tr(t,e){if(t==null||t==="")return;let n=String(t);if(e==="currency"){let s=Number(t);return Number.isFinite(s)?s.toFixed(2):n}if(e==="date"){let s=Date.parse(n);return Number.isNaN(s)?n:new Date(s).toISOString().slice(0,10)}return e==="truncate"&&n.length>40?n.slice(0,39)+"\u2026":n}function nt(t,e){return(t.source==="screen"?Ie(e.screen,e.timeZone,t.field,t.key):tr(e.tables?.[t.table]?.rows?.[t.row??0]?.[t.column],t.format))??t.fallback??""}function Vt(t){let e=/^\s*(?:screen\.(fields\.[a-z][A-Za-z0-9]{0,31}|[A-Za-z]+)|table\.([A-Za-z0-9_-]+)\[(\d+)\](?:\.([A-Za-z0-9_]+)|\["((?:[^"\\]|\\.)*)"\]))\s*((?:\|\s*(?:[a-z]+|"(?:[^"\\]|\\.)*")\s*)*)$/.exec(t);if(!e)return null;let n=[...e[6].matchAll(/\|\s*([a-z]+|"((?:[^"\\]|\\.)*)")/g)],s=n.find(o=>o[1].startsWith('"'))?.[2]?.replace(/\\(.)/g,"$1"),r=n.find(o=>!o[1].startsWith('"'))?.[1];return e[1]!==void 0?r?null:e[1].startsWith("fields.")?{source:"screen",field:"fields",key:e[1].slice(7),...s!==void 0?{fallback:s}:{}}:Qs.includes(e[1])?{source:"screen",field:e[1],...s!==void 0?{fallback:s}:{}}:null:r&&!er.includes(r)?null:{source:"table",table:e[2],row:Number(e[3]),column:e[4]??e[5].replace(/\\(.)/g,"$1"),...r?{format:r}:{},...s!==void 0?{fallback:s}:{}}}function st(t,e){return t.replace(/\{{2}([^{}]*)\}{2}/g,(n,s)=>{let r=Vt(s);return r?nt(r,e):n})}function Ce(t){return[...t.matchAll(/\{{2}([^{}]*)\}{2}/g)].some(e=>Vt(e[1])!==null)}function rt(t,e){return Object.fromEntries(Object.entries(t).map(([n,s])=>[n,typeof s=="string"?st(s,e):s]))}var it=t=>t==null||t==="";function Zt(t,e,n,s,r,o){return nr(t,e,n,s,{now:r,timeZone:o})}function nr(t,e,n,s,r){if(n===null&&(e==="eq"||e==="ne"))return e==="eq"?it(t):!it(t);if(it(t)||n===null||n===void 0)return!1;switch(s){case"number":case"currency":{let o=Number(t),i=Number(n);return typeof n!="boolean"&&n!==""&&Number.isFinite(o)&&Number.isFinite(i)&&ot(e,o-i)}case"boolean":{let o=n===!0||n==="true"?!0:n===!1||n==="false"?!1:void 0;return o!==void 0&&(e==="eq"?t===o:e==="ne"?t!==o:!1)}case"date":{let o=n==="today"?sr(r.now,r.timeZone).date:String(n),i=String(t).slice(0,10);return/^\d{4}-\d{2}-\d{2}$/.test(o)&&ot(e,i<o?-1:i>o?1:0)}case"datetime":{let o=Date.parse(String(t)),i=n==="now"?r.now:Date.parse(String(n));return!Number.isNaN(o)&&!Number.isNaN(i)&&ot(e,o-i)}default:{let o=String(t).toLowerCase(),i=String(n).toLowerCase();return e==="eq"?o===i:e==="ne"?o!==i:e==="contains"?o.includes(i):!1}}}function ot(t,e){switch(t){case"eq":return e===0;case"ne":return e!==0;case"lt":return e<0;case"lte":return e<=0;case"gt":return e>0;case"gte":return e>=0;default:return!1}}var Kt=new Map;function sr(t,e){let n=Kt.get(e);n||(n=new Intl.DateTimeFormat("en-US",{timeZone:e,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",weekday:"short"}),Kt.set(e,n));let s=Object.fromEntries(n.formatToParts(new Date(t)).map(r=>[r.type,r.value]));return{date:`${s.year}-${s.month}-${s.day}`,minute:Number(s.hour)%24*60+Number(s.minute),day:String(s.weekday).slice(0,3).toLowerCase()}}var Jt=(t,e)=>!t||(t.from===void 0||t.from<=e)&&(t.until===void 0||e<t.until);var le=class{constructor(e,n,s,r,o){h(this,"renderer",e);h(this,"wrap",r);h(this,"onShown",o);h(this,"timer");h(this,"turns",0);h(this,"turnAt");h(this,"left");h(this,"stopped",!1);h(this,"share");h(this,"pages");this.pages=n.pages??[],this.share=n.durationMs/Math.max(1,this.pages.length),this.turnAt=s+this.share,this.arm()}arm(){clearTimeout(this.timer);let e=this.pages.length;if(this.stopped||this.left!==void 0||e<2||!this.wrap&&this.turns+1>=e)return;let n=this.pages[(this.turns+1)%e];this.renderer.prepare?.(n).catch(()=>{}),this.timer=setTimeout(()=>{this.turn(n)},Math.min(Math.max(0,this.turnAt-Date.now()),2**31-1))}async turn(e){try{await this.renderer.show(e)}catch{}this.stopped||(this.turns++,this.turnAt+=this.share,this.onShown?.(e),this.arm())}pause(){this.stopped||this.left!==void 0||(clearTimeout(this.timer),this.left=Math.max(0,this.turnAt-Date.now()))}resume(){this.stopped||this.left===void 0||(this.turnAt=Date.now()+this.left,this.left=void 0,this.arm())}stop(){if(!this.stopped){this.stopped=!0,clearTimeout(this.timer);for(let e of this.pages)this.renderer.release?.(e)}}};var ar=Object.freeze,lr=Object.values,Yt=Reflect.apply;function Re(t){if(t===null||typeof t!="object")return t;for(let e of Yt(lr,Object,[t]))Re(e);return Yt(ar,Object,[t])}var at=class extends Error{constructor(n,s){super(s);h(this,"code",n);this.name="MediaError"}};function lt(t){return t instanceof at?{code:t.code.slice(0,64),message:t.message.slice(0,1e3)}:{code:"not-shown",message:String(t instanceof Error?t.message:t??"").slice(0,1e3)}}var Xt=t=>t.blob.contentType.startsWith("video/");var dt="position:absolute;inset:0;width:100%;height:100%;object-fit:contain",dr=1,Ne=class{constructor(e,n={}){h(this,"container",e);h(this,"options",n);h(this,"prepared",new Map);h(this,"shown",null);h(this,"visible",null);h(this,"turns",0);h(this,"latest",null);h(this,"endListeners",new Set);h(this,"itemListeners",new Set);h(this,"appListeners",new Set);h(this,"held",null);h(this,"heldFor",null);h(this,"drawn",0);h(this,"shownHash",null);let s=n.media;s&&(document.documentElement.style.background="transparent",document.body.style.background="transparent",e.style.background="#000",s.onEnd((r,o)=>{let i=this.shown;if(i?.mediaId===r)for(let a of this.endListeners)a(i.slide,o)}))}onMediaEnd(e){this.endListeners.add(e)}onElementItem(e){this.itemListeners.add(e)}onApp(e){this.appListeners.add(e)}app(e){for(let n of this.appListeners)n(e);this.options.onApp?.(e)}prepare(e){let n=this.prepared.get(e);if(n)return n.ready;let s;try{s=this.make(e)}catch(r){return e.layout&&Qe(r,"layout"),Promise.reject(r)}return this.prepared.set(e,s),s.ready.catch(()=>{this.prepared.get(e)===s&&(this.prepared.delete(e),this.dispose(s))}),s.ready}release(e){let n=this.prepared.get(e);n&&(this.prepared.delete(e),this.dispose(n))}async show(e){let n=++this.turns;this.latest=e;let s=()=>n!==this.turns;if(await this.prepare(e),s())return this.latest!==e&&this.release(e),"cut";let r=this.prepared.get(e);if(!r)throw new Error("the slide was released before it was shown");this.prepared.delete(e);let o=this.visible,i=this.options.media,a=o?Qt(e):void 0;if(r.kind==="layout"&&a===void 0){if(!await _(()=>s()?!1:(o?this.container.insertBefore(r.el,o.el):this.container.append(r.el),this.shown=r,this.shownHash=e.blob.hash,!0)))return this.drop(r);this.hold(r),await r.view.start().catch(()=>{});let l=Promise.resolve();return await _(()=>s()?!1:(r.el.style.visibility="",o?.el.remove(),this.visible=r,i&&this.paint("transparent"),i&&o?.mediaId&&(l=i.show([],[o.mediaId],Date.now())),!0))?(await l.catch(()=>{}),o&&this.dispose(o),this.releaseHeld(r),"cut"):this.drop(r)}if(a!==void 0&&i&&r.kind==="native"&&o.kind==="native"){if(r.fadesIn&&!r.queued){let l=Promise.resolve();return await _(()=>s()?!1:(r.el.style.visibility="",this.container.insertBefore(r.el,o.el),l=i.show([r.mediaId],[],Date.now()),this.shown=r,this.visible=r,this.shownHash=e.blob.hash,!0))?(await l.catch(()=>{}),pr(a).then(async()=>{await i.show([],[o.mediaId],Date.now()).catch(()=>{}),o.el.remove(),this.dispose(o)}),"crossfade"):this.drop(r)}}else if(a!==void 0&&i&&r.kind==="native"){let l=Promise.resolve();return await _(()=>s()?!1:(r.el.style.visibility="",this.container.insertBefore(r.el,o.el),l=i.show([r.mediaId],[],Date.now()),this.shown=r,this.visible=r,this.shownHash=e.blob.hash,!0))?(await l.catch(()=>{}),this.paint("transparent"),en(o.el,1,0,a).then(()=>{o.el.remove(),this.dispose(o)}),"crossfade"):this.drop(r)}else if(a!==void 0)return await _(()=>s()?!1:(r.el.style.visibility="",r.el.style.opacity="0",this.container.append(r.el),r.kind==="video"&&pt(r.el),this.shown=r,this.visible=r,this.shownHash=e.blob.hash,!0))?(r.view&&(this.hold(r),r.view.start().then(()=>this.releaseHeld(r))),en(r.el,0,1,a).then(async()=>{o.el.remove(),this.shown===r&&this.paint(i?"#000":""),i&&o.mediaId&&await i.show([],[o.mediaId],Date.now()).catch(()=>{}),this.dispose(o)}),"crossfade"):this.drop(r);if(i&&r.kind==="native"){let l=Promise.resolve();if(!await _(()=>s()?!1:(r.el.style.visibility="",o?this.container.insertBefore(r.el,o.el):this.container.prepend(r.el),l=i.show([r.mediaId],o?.mediaId?[o.mediaId]:[],Date.now()),this.shown=r,this.shownHash=e.blob.hash,!0)))return this.drop(r);if(await l.catch(()=>{}),!await _(()=>s()?!1:(o?.el.remove(),this.visible=r,this.paint("transparent"),!0)))return this.shown===r&&o?.mediaId&&i.show([o.mediaId],[],Date.now()).catch(()=>{}),this.drop(r)}else{let l=Promise.resolve();if(!await _(()=>s()?!1:(r.el.style.visibility="",r.el.parentNode!==this.container&&this.container.append(r.el),o?.el.remove(),this.paint(i?"#000":""),i&&o?.mediaId&&(l=i.show([],[o.mediaId],Date.now())),r.kind==="video"&&pt(r.el),this.shown=r,this.visible=r,this.shownHash=e.blob.hash,!0)))return this.drop(r);await l.catch(()=>{})}return o&&this.dispose(o),"cut"}paint(e){this.options.background?this.options.background(e):this.container.style.background=e}standby(){this.turns++,this.latest=null;let e=this.visible;this.shown=null,this.visible=null,this.shownHash=null,this.paint(this.options.media?"#000":""),e&&(e.mediaId&&this.options.media?.show([],[e.mediaId],Date.now()).catch(()=>{}),this.dispose(e))}pause(){let e=this.shown;e?.view?.pause(),e?.kind==="video"?e.el.pause():e?.mediaId&&this.options.media?.control(e.mediaId,"pause").catch(()=>{})}resume(){let e=this.shown;e?.view?.resume(),e?.kind==="video"?pt(e.el):e?.mediaId&&this.options.media?.control(e.mediaId,"play").catch(()=>{})}make(e){if(e.layout){let{doc:i,source:a,untilPass:l}=e.layout,p=X(H("div"));p.dataset.blob=e.blob.hash,p.style.cssText=`${dt};visibility:hidden`,this.container.append(p);let c=String(++this.drawn),d={slide:e,kind:"layout",el:p,drawing:c,ready:Promise.resolve()},m=y=>this.options.path?`${this.options.path}/${y}`:y;return d.view=new Q(i,a,p,{media:this.options.media,path:this.options.path,endsWith:l?m(l):void 0,onItem:y=>{if(d.dropped)return;let w={...y,slide:y.slide?`${c}.${y.slide}`:c};this.held?this.held.push(w):this.item(w)},onPassEnd:y=>{if(l&&y===m(l)&&this.shown===d){for(let w of this.endListeners)w(e);return"hold"}return this.options.onPassEnd?.(y)},onApp:y=>this.app(y)}),d.ready=d.view.ready,d}if(!Xt(e)){if(!e.bytes&&!e.url)throw new Error(`no bytes for ${e.blob.hash}`);let i=e.bytes?URL.createObjectURL(new Blob([e.bytes],{type:e.blob.contentType})):void 0,a=X(H("img"));return a.src=i??e.url,a.alt="",a.dataset.blob=e.blob.hash,a.style.cssText=this.fill(),{slide:e,kind:"image",el:a,objectUrl:i,ready:a.decode()}}let n=this.options.media;if(n){let i=`m-${dr++}`,a=X(H("div"));a.dataset.blob=e.blob.hash,a.dataset.media=i,a.style.cssText=`${dt};visibility:hidden`;let l=this.container.getBoundingClientRect(),p={x:l.left,y:l.top,w:l.width||window.innerWidth,h:l.height||window.innerHeight},c=Qt(e),d=c!==void 0&&this.shown?.kind==="native"&&n.capability.animates&&n.capability.layers>=2,m=d?[{property:"opacity",keyframes:[{t:0,v:0},{t:c,v:1}]}]:[],y={slide:e,kind:"native",el:a,mediaId:i,fadesIn:d,ready:Promise.resolve()},w=this.options.fit??"contain";return y.ready=n.prepare({mediaId:i,blob:e.blob.hash,contentType:e.blob.contentType,box:p,z:d?1:0,loop:e.loop,muted:!1,fit:w,...d?{tracks:m}:{}}).then(f=>{f.queued&&(y.queued=!0)}),y}let s=e.url?void 0:URL.createObjectURL(new Blob([e.bytes],{type:e.blob.contentType})),r=X(H("video"));r.dataset.blob=e.blob.hash,r.style.cssText=`${this.fill()};visibility:hidden`,r.muted=!1,r.playsInline=!0,r.preload="auto",r.loop=e.loop,r.src=e.url??s,r.addEventListener("ended",()=>{if(this.shown?.el===r)for(let i of this.endListeners)i(e)}),r.addEventListener("error",()=>{if(this.shown?.el===r)for(let i of this.endListeners)i(e,`video: ${r.error?.message??"error"}`)});let o=new Promise((i,a)=>{if(r.readyState>=2)return i();r.addEventListener("loadeddata",()=>i(),{once:!0}),r.addEventListener("error",()=>a(new Error(`video: ${r.error?.message??"cannot load"}`)),{once:!0})});return this.container.append(r),{slide:e,kind:"video",el:r,objectUrl:s,ready:o}}item(e){this.options.onItem?.(e);for(let n of this.itemListeners)n(e)}hold(e){this.held??(this.held=[]),this.heldFor=e}releaseHeld(e){if(this.heldFor!==e)return;let n=this.held;this.held=null,this.heldFor=null,n?.length&&setTimeout(()=>{for(let s of n)this.item(s)},0)}drop(e){e.dropped=!0;let n=e.drawing;return this.held&&n&&(this.held=this.held.filter(s=>s.slide!==n&&!s.slide?.startsWith(`${n}.`))),this.releaseHeld(e),this.shown===e&&(this.shown=this.visible,this.shownHash=this.visible?.slide.blob.hash??null),this.dispose(e),"cut"}fill(){let e=this.options.fit==="stretch"?"fill":this.options.fit??"contain";return dt.replace("object-fit:contain",`object-fit:${e}`)}dispose(e){if(this.shown!==e){if(e.view?.dispose(),e.el.remove(),e.kind==="video"){let n=e.el;n.pause(),n.removeAttribute("src"),n.load()}e.mediaId&&this.options.media?.release(e.mediaId).catch(()=>{}),e.objectUrl&&URL.revokeObjectURL(e.objectUrl)}}};function Qt(t){if(t.transition?.type==="crossfade")return Math.max(0,Math.min(t.transition.durationMs??1e3,t.durationMs/2))}var pr=t=>new Promise(e=>setTimeout(e,t));function en(t,e,n,s){return new Promise(r=>{let o=Date.now(),i=!1,a=()=>{i||(i=!0,t.style.opacity=n===1?"":String(n),r())};t.style.opacity=String(e);let l=()=>{if(i)return;let p=Math.min(1,(Date.now()-o)/s);if(p>=1)return a();t.style.opacity=String(e+(n-e)*p),requestAnimationFrame(l)};requestAnimationFrame(l),setTimeout(a,s+250)})}function pt(t){t.play().catch(()=>(t.muted=!0,t.play())).catch(()=>{})}function _(t){return new Promise((e,n)=>{let s=!1,r=()=>{if(!s){s=!0;try{e(t())}catch(o){n(o)}}};requestAnimationFrame(r),setTimeout(r,250)})}var de={apiVersion:2,properties:[{name:"device",description:"What the device is: id, type, shell and versions, model, resolution and orientation. Fixed while the player runs."},{name:"mode",description:"Where player-core runs: player, preview (in the CMS) or designer. In preview and the designer, commands change nothing."},{name:"timeZone",description:"The player's time zone (IANA), from the host.",event:"time.changed"},{name:"locale",description:"The player's locale (BCP 47), from the host."},{name:"connection",description:"Whether the player is connected to Wyndlass.",event:"connection.changed"},{name:"state",description:"starting, playing, paused, stopped (the standby screen), idle (nothing to play) or error.",event:"state.changed"},{name:"held",description:"A remote pause or stop in effect, by whom and since when; absent when none.",event:"state.changed"},{name:"content",description:"The manifest playing, when it was issued and switched to; absent when there is none.",event:"content.updated"},{name:"now",description:"What each zone shows: the item, its blob and content type, when it started, and its duration and position when known.",event:"item.start"},{name:"audio",description:"The player's volume (0 to 100) and whether it is muted; only when the host can set them.",event:"audio.changed"},{name:"display",description:"The display's power and brightness; only when the host can report them.",event:"display.changed"},{name:"capabilities",description:"What the host can do: audio, display power, display brightness."}],events:[{name:"state.changed",description:"The player's state changed (playing, paused, stopped, idle, error), and who changed it."},{name:"content.updated",description:"A new manifest was switched to."},{name:"item.start",description:"An item started in a zone (source start)."},{name:"item.end",description:"An item ended in a zone (source end): completed, skipped, stopped, error, replaced by new content, or finished by its app."},{name:"item.error",description:"An item could not be shown."},{name:"connection.changed",description:"The player connected to Wyndlass or lost its connection."},{name:"audio.changed",description:"The volume or mute changed, and who changed it."},{name:"display.changed",description:"The display's power or brightness changed, and who changed it."},{name:"time.changed",description:"The clock was adjusted or the time zone changed."},{name:"app.command",description:"A command for apps on the screen (apps.sendCommand); an app reacts if it knows the name."},{name:"app.failed",description:"An app on the screen could not run, or misbehaved (WP-0100): its bundle did not load, it was not an app, it needs a newer player, it kept throwing and was stopped, or it was late or overran a clip."},{name:"app.held",description:"An app version was held back on this screen until the next manifest, after the page stopped answering twice in an hour while it was on screen (WP-0100)."}],commands:[{name:"player.status",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/status",description:"Everything about the player now: device, mode, time zone, locale, connection, state (and any hold), the content playing, what each zone shows, audio, display and what the host can do. Changes nothing.",idempotent:!0},{name:"player.events",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/events",result:"player-api-results.schema.json#/$defs/events",description:"The player's recent events (the last 200), oldest first, after a sequence number: state changes, content updates, item starts and ends, errors, connection, audio, display and time. Pass next as after to poll for more. Changes nothing.",idempotent:!0},{name:"time.now",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/timeNow",description:"The player's current time, its time zone and UTC offset, and whether its clock is synchronized. Changes nothing.",idempotent:!0},{name:"player.play",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Resumes or starts playback on the screen. From a remote caller it also ends a remote pause or stop.",idempotent:!0},{name:"player.pause",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Freezes the screen on what it shows now: the loop's timer and any media stop where they are. From a remote caller it holds until a remote player.play or a restart; apps cannot resume it, and new content arrives paused.",idempotent:!0},{name:"player.stop",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Stops playback and shows the standby screen (black, display on). From a remote caller it holds until a remote player.play or a restart; apps cannot restart it, and new content arrives stopped.",idempotent:!0},{name:"player.next",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Skips to the next item in a zone (main by default); the current item ends as skipped."},{name:"player.previous",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Goes back to the previous item in a zone (main by default); the current item ends as skipped."},{name:"player.playItem",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/playItem",result:"player-api-results.schema.json#/$defs/now",description:"Shows a given item of the content playing now in a zone (main by default), then continues the loop from it. Refused for an item the playing manifest does not have."},{name:"audio.setVolume",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setVolume",result:"player-api-results.schema.json#/$defs/audio",description:"Sets the player's volume, 0 to 100. Only on players whose host can set it to a level.",needs:"audio.volume",idempotent:!0},{name:"audio.setMuted",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setMuted",result:"player-api-results.schema.json#/$defs/audio",description:"Mutes or unmutes the player. Only on players whose host can.",needs:"audio",idempotent:!0},{name:"display.setPower",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setPower",result:"player-api-results.schema.json#/$defs/display",description:"Turns the display on or to standby. Only on players whose host can. Standby blanks the screen until it is turned on.",needs:"display.power",idempotent:!0},{name:"display.setBrightness",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setBrightness",result:"player-api-results.schema.json#/$defs/display",description:"Sets the display's brightness, 0 to 100. Only on players whose host can.",needs:"display.brightness",idempotent:!0},{name:"apps.sendCommand",access:"control",apps:"none",remote:!0,params:"player-api-params.schema.json#/$defs/sendCommand",result:"player-api-results.schema.json#/$defs/delivered",description:"Sends a named command, with an optional argument, to the apps on the screen; an app that knows the name reacts. Returns how many apps listen."},{name:"app.finish",access:"control",apps:"read",remote:!1,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/none",description:"An app ends its own slot now: its item ends as finished and the loop moves on. Apps only; not a tool."}],host:[{name:"host.describe",kind:"request",description:"What the device is, its time zone, locale, connection and capabilities.",result:"player-api-host.schema.json#/$defs/describeResult"},{name:"host.time",kind:"request",description:"The host's time and time zone.",result:"player-api-common.schema.json#/$defs/timeNow"},{name:"host.getAudio",kind:"request",description:"The player's volume and mute.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.setAudio",kind:"request",description:"Sets the volume, the mute or both; answers the audio after.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.getDisplay",kind:"request",description:"The display's power and brightness.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.setDisplay",kind:"request",description:"Sets the display's power, brightness or both; answers the display after.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.adRequest",kind:"request",description:"Asks Wyndlass's ad broker for one slot of a break over the host's NATS connection (WP-0075); the result is the broker's ad-decision (ad-decision.schema.json). Only a host whose describe says ads is asked."},{name:"host.mediaPrepare",kind:"request",description:"Lays a video out behind the page and prepares it to its first frame; host.mediaState says when (ADR 0055)."},{name:"host.mediaShow",kind:"request",description:"Shows and hides prepared videos; replies once its layer has changed."},{name:"host.mediaControl",kind:"request",description:"Plays, pauses or seeks a video, or asks for its position."},{name:"host.mediaRelease",kind:"request",description:"Removes a video and frees its decoder."},{name:"host.reply",kind:"reply",description:"The host's answer to a request: result or error (unsupported, failed)."},{name:"host.connection",kind:"event",description:"The connection to Wyndlass changed."},{name:"host.timeChanged",kind:"event",description:"The clock was adjusted or the time zone changed."},{name:"host.audioChanged",kind:"event",description:"The volume or mute changed outside the player."},{name:"host.displayChanged",kind:"event",description:"The display changed outside the player."},{name:"host.mediaState",kind:"event",description:"A video was prepared, started, ended or failed, or its position was asked for."},{name:"host.presence",kind:"event",description:"What one of the host's sensors sees now: the presences in view, with random ids that never leave the page (WP-0105)."},{name:"host.sensing",kind:"event",description:"The site's sensing mode as the host applies it, and its sensors (WP-0105)."},{name:"host.serialPorts",kind:"event",description:"The host's sensor controller ports, and which are open (WP-0043)."},{name:"host.serialLine",kind:"event",description:"One line from a sensor controller, as it arrived (WP-0043)."},{name:"host.serialWrite",kind:"request",description:"Writes lines to a sensor controller, a gap apart; replies once written (WP-0043)."},{name:"host.bleWatch",kind:"request",description:"What the page listens for: beacons' iBeacon UUIDs, Eddystone namespaces and addresses; replies once the scan follows it. Sent only to a host that has sent host.bleState (WP-0044)."},{name:"host.bleAdverts",kind:"event",description:"Beacon frames that match the watch, at most four a second of each kind from each beacon (WP-0044)."},{name:"host.bleState",kind:"event",description:"The host's Bluetooth scanner: scanning, idle, off, refused, missing or failed; sent only by a host that has one (WP-0044)."},{name:"host.gpioPins",kind:"event",description:"The GPIO pins the host reads, with their values (WP-0044)."},{name:"host.gpioEdge",kind:"event",description:"A GPIO pin changed (WP-0044)."},{name:"host.mcp",kind:"relay",description:"An MCP message from ctl.dev.{deviceId}, for player-core to answer."},{name:"core.ready",kind:"core",description:"player-core is ready to answer host.mcp; until then the shell answers -32002 itself."},{name:"core.mcpReply",kind:"core",description:"player-core's answer to a host.mcp, for the shell to send back."},{name:"core.sensors",kind:"core",description:"The page's sensor controllers, channels and inputs, and the beacons it hears, whenever they change, for the heartbeat and sensors.recent (WP-0043, WP-0044)."}]};var tn=Symbol.for("wyndlass.app.attach");var U=class extends Error{constructor(n,s){super(`the app could not run (${n})`);h(this,"reason",n);h(this,"error",s)}};function Z(t){try{let e=t instanceof Error?t.name:void 0;return typeof e=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(e)?e:void 0}catch{return}}function pe(t){let e=t?.id;if(typeof e!="string"||e==="")return!0;for(let n=0;n<nn.length;n++)if(e[n]!==nn[n])return!1;return!0}var nn="com.wyndlass.";function ur(t=typeof navigator>"u"?"":navigator.userAgent){let e=/Chrom(?:e|ium)\/(\d+)/.exec(t);return e?Number(e[1]):void 0}function sn(t,e=de.apiVersion,n=ur()){return!(t?.playerApi!==void 0&&t.playerApi>e||t?.webView!==void 0&&n!==void 0&&t.webView>n)}function hr(t){let e;try{e=t.paging?.()}catch{return null}let n=e;return n&&Number.isInteger(n.count)&&n.count>1&&typeof n.ms=="number"&&n.ms>0?{count:n.count,ms:n.ms}:null}var ct=new Map;function mr(){let t=Ut(8),e="";for(let n=0;n<8;n++)e+=fr[t[n]%26];return e}var fr="abcdefghijklmnopqrstuvwxyz",gr=0;function rn(t,e,n){let s=ct.get(t);if(!s){let r=Ke.make([e],"text/javascript");s=import(r).then(o=>yr(o,n),o=>{throw o instanceof U?o:new U("load",Z(o))}).finally(()=>Ke.revoke(r)),ct.set(t,s),s.catch(()=>ct.delete(t))}return s}function yr(t,e){let n=t.default;if(typeof n=="function"&&n.prototype instanceof HTMLElement){let s=n.prototype[tn];if(typeof s!="function")throw new U("shape");let r=class extends n{},o=`${e?.element??"wl-app"}-${mr()}${++gr}`;try{Je.define(o,r)}catch(i){throw new U("shape",Z(i))}return{tag:o,shape:"class",attach:(i,a)=>{Bt(s,i,[a])}}}if(pe(e)&&typeof t.element=="string"&&Je.get(t.element))return{tag:t.element,shape:"legacy"};throw new U("shape")}var br=3,wr=6e4,Oe=class{constructor(e,n){h(this,"element",e);h(this,"o",n);h(this,"faults",[]);h(this,"halted",!1)}get stopped(){return this.halted}has(e){try{return!this.halted&&typeof this.element[e]=="function"}catch{return!1}}update(e){this.halted||this.run(()=>this.element.update?.(e))}reset(){this.halted||this.run(()=>this.element.reset?.())}paging(){return this.halted?null:hr(this.element)}hook(e,n){if(this.halted)return Promise.resolve();let s;try{s=this.element[e]?.(n)}catch(r){return this.fault(r),Promise.resolve()}return Promise.resolve(s).then(()=>{},r=>this.fault(r))}stop(e){if(!this.halted){this.halted=!0;try{this.element.remove()}catch{}this.o.dispose?.(),this.o.onStop(e)}}dispose(){this.o.dispose?.()}run(e){try{e()}catch(n){this.fault(n)}}fault(e){let n=(this.o.now??Date.now)();this.faults=this.faults.filter(s=>n-s<wr),this.faults.push(n),this.faults.length>=br&&this.stop(Z(e))}},vr=24*3600*1e3,$e=class t{constructor(e){h(this,"o",e);h(this,"memory",new Map);h(this,"inflight",new Map);h(this,"images",new Map);h(this,"pictures",new Map)}now(){return this.o.now?.()??Date.now()}url(e){let n=this.o.base();if(!n)return;let s=this.o.token(),r=`${n.replace(/\/$/,"")}${e}`;return s?`${r}${r.includes("?")?"&":"?"}${s}`:r}stored(e){return this.memory.get(e)??this.o.store?.getItem(e)??void 0}static keyOf(e,n){let s=Object.keys(n).sort().map(r=>`${encodeURIComponent(r)}=${encodeURIComponent(String(n[r]))}`).join("&");return{query:s,key:`wyndlass:data:${e}?${s}`}}kept(e,n){let s=this.stored(t.keyOf(e,n).key);if(s)try{let r=JSON.parse(s);return this.dress(r,Date.parse(r.expiresAt)<=this.now())}catch{return}}keep(e,n){this.memory.set(e,n);try{this.o.store?.setItem(e,n)}catch{}}get(e,n){let{query:s,key:r}=t.keyOf(e,n),o=this.inflight.get(r);if(o)return o;let i=this.o.fetch??fetch,a=(async()=>{let l=this.stored(r),p=l?JSON.parse(l):void 0;if(p&&Date.parse(p.expiresAt)>this.now())return this.dress(p,!1);let c=this.url(`/v0/${encodeURIComponent(e)}?${s}`);try{if(!c)throw new Error("no data service");let d=await i(c);if(!d.ok)throw new Error(`the data service answered ${d.status}`);let m=await d.text();return this.keep(r,m),this.dress(JSON.parse(m),!1)}catch(d){if(p&&Date.parse(p.expiresAt)+vr>this.now())return this.dress(p,!0);throw d}})().finally(()=>this.inflight.delete(r));return this.inflight.set(r,a),a}dress(e,n){return{...e,offline:n,ageMs:Math.max(0,this.now()-Date.parse(e.fetchedAt))}}image(e){let n=this.images.get(e);return n||(n=this.imageBlob(e).then(s=>URL.createObjectURL(s)),this.images.set(e,n),n.catch(()=>this.images.delete(e))),n}imageBlob(e){let n=this.pictures.get(e);if(!n){let s=this.url(e);n=s?(this.o.fetch??fetch)(s).then(r=>{if(!r.ok)throw new Error(`the image answered ${r.status}`);return r.blob()}):Promise.reject(new Error("no data service")),this.pictures.set(e,n),n.catch(()=>this.pictures.delete(e))}return n}};var on="wyndlass.frame";function pn(t,e){return!!t&&(t.apps?t.apps(e):!pe(e))}var kr=new Set(["load","shape","unsupported","error","late","overran"]),an=50,ln=250,ut=class{constructor(e,n,s,r){h(this,"frame",e);h(this,"port",n);h(this,"o",r);h(this,"halted",!1);h(this,"pages");h(this,"hooks");h(this,"pending",new Map);h(this,"next",0);h(this,"told");h(this,"last");h(this,"quiet");this.hooks=new Set(s.hooks),this.pages=s.paging}get stopped(){return this.halted}has(e){return!this.halted&&this.hooks.has(e)}paging(){return this.halted?null:this.pages}update(e){if(this.halted)return;let n=performance.now(),s=this.last;this.last={t:e,at:n};let r=this.told;if(r&&(r.running?Math.abs(e-(r.t+(n-r.at)))<=an:e===r.t)){r.running&&this.watch();return}let o=!!s&&n-s.at<ln&&e>s.t&&Math.abs(e-s.t-(n-s.at))<=an;this.told={t:e,at:n,running:o},this.post({type:"clock",t:e,running:o}),o&&this.watch()}reset(){this.halted||this.post({type:"reset"})}snapshots(e){this.halted||this.post({type:"snapshots",snapshots:e})}hook(e,n){if(this.halted)return Promise.resolve();let s=++this.next;return new Promise(r=>{this.pending.set(s,r),this.post({type:"hook",id:s,kind:e,options:n})})}stop(e){this.halted||(this.halted=!0,this.frame.remove(),this.dispose(),this.o.onStop(e))}dispose(){this.o.dispose?.(),clearTimeout(this.quiet),this.port.close();for(let e of this.pending.values())e();this.pending.clear()}heard(e){e.type==="paging"?this.pages=un(e.paging):e.type==="hooked"&&typeof e.id=="number"?(this.pending.get(e.id)?.(),this.pending.delete(e.id)):e.type==="stopped"&&this.stop(hn(e.error))}post(e){try{this.port.postMessage(e)}catch{}}watch(){clearTimeout(this.quiet),this.quiet=setTimeout(()=>{!this.told?.running||!this.last||this.halted||(this.told={...this.last,running:!1},this.post({type:"clock",t:this.last.t,running:!1}))},ln)}};async function cn(t,e,n,s,r,o,i,a,l,p){let c=t.appInfo??n.info,d;try{d=new URL(l.frames).origin}catch{return p("unsupported")}let m=document.createElement("iframe");m.setAttribute("sandbox","allow-scripts"),m.setAttribute("referrerpolicy","no-referrer"),m.title=c?.id??"app",m.tabIndex=-1,m.dataset.frame=c?.id??"",m.style.cssText="display:block;width:100%;height:100%;border:0;pointer-events:none;background:transparent;color-scheme:normal";let y=new Promise(A=>{m.addEventListener("load",()=>A(!0),{once:!0}),setTimeout(()=>A(!1),o)});m.src=`${d}/`,e.append(m);let w=(A,k)=>(m.remove(),p(A,k));if(!await y||!m.contentWindow)return w("load");let{port1:f,port2:b}=new MessageChannel,v={type:"init",element:{id:t.id,type:"app",app:t.app,props:t.props??{},...t.binding?{binding:t.binding}:{},...t.appInfo?{appInfo:t.appInfo}:{}},bundle:{hash:n.hash,bytes:n.bytes.slice(),...n.info?{info:n.info}:{}},...s.place?{place:s.place}:{},screen:s.screen??null,timeZone:s.timeZone,locale:s.locale,preview:!!s.preview,clock:{t:r.now(),running:!1,startedAt:r.startedAt()},fonts:Ar(t.props??{},l),snapshots:dn(t,s),deadlineMs:o};return new Promise(A=>{let k,I=!1,$=ne=>{I||(I=!0,clearTimeout(V),A(ne))},V=setTimeout(()=>{k?($({app:k,late:!0}),k.update(r.now())):(f.close(),$(w("load")))},o+1e3),F=!1;f.onmessage=ne=>{let L=ne.data;if(!(!L||typeof L!="object")){if(L.type==="ask"){F&&xr(L,s,f);return}if(k){L.type==="ready"?($({app:k,late:L.late===!0}),k.update(r.now())):k.heard(L);return}if(L.type==="hello"&&!F)F=!0,f.postMessage(v,[v.bundle.bytes.buffer]);else if(L.type==="made"&&Array.isArray(L.hooks)){let se=mn(t),we,M=new ut(m,f,{type:"made",hooks:L.hooks.filter(P=>P==="enter"||P==="exit"),paging:un(L.paging)},{onStop:a,dispose:()=>we?.()});we=s.onSnapshots?.(P=>{P.some(B=>se.has(B))&&M.snapshots(dn(t,s))}),k=M,i(k)}else L.type==="failed"&&(f.close(),$(w(kr.has(L.reason)?L.reason:"error",hn(L.error))))}},m.contentWindow.postMessage({type:on},"*",[b])})}async function xr(t,e,n){if(typeof t.id!="number")return;let s=(r,o=[])=>{try{n.postMessage(r,o)}catch{}};try{if(!e.data)throw new Error("no data service");if(t.what==="data"&&typeof t.source=="string")s({type:"answer",id:t.id,value:await e.data.get(t.source,Mr(t.params))});else if(t.what==="image"&&typeof t.path=="string"){let r=await e.data.imageBlob(t.path),o=new Uint8Array(await r.arrayBuffer());s({type:"answer",id:t.id,value:{bytes:o,type:r.type}},[o.buffer])}else throw new TypeError("not a question")}catch(r){s({type:"answer",id:t.id,error:Z(r)??"Error"})}}function Mr(t){let e={};if(t&&typeof t=="object")for(let[n,s]of Object.entries(t))(typeof s=="string"||typeof s=="number"||typeof s=="boolean")&&(e[n]=s);return e}function un(t){let e=t;return e&&Number.isInteger(e.count)&&e.count>1&&typeof e.ms=="number"&&e.ms>0?{count:e.count,ms:e.ms}:null}function hn(t){return typeof t=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(t)?t:void 0}function Ar(t,e){let n=new Set;for(let r of Object.values(t)){let o=r?.family;r&&typeof r=="object"&&typeof o=="string"&&n.add(o)}let s=[];for(let r of e.fonts??[]){let o=n.has(r.family)?e.font?.(r.blob):void 0;o&&s.push({family:r.family,weight:r.weight,style:r.style,blob:r.blob,bytes:o.slice()})}return s}function mn(t){let e=new Set;t.binding?.table&&e.add(t.binding.table);for(let n of Object.values(t.props??{}))typeof n=="string"&&/^tbl_[0-9a-z]{26}$/.test(n)&&e.add(n);return e}function dn(t,e){let n={};for(let s of mn(t)){let r=e.snapshot?.(s);r&&(n[s]=r)}return n}function fn(t){let e=ie?.setStyle??((n,s,r,o)=>n.style.setProperty(s,r,o));e(t,"contain","strict","important"),e(t,"overflow","clip","important")}var gn=t=>!!(t?.filter?.length||t?.sort||t?.limit),Sr=t=>t==null||t==="";function Er(t,e){if(!Sr(t))switch(e){case"number":case"currency":{let n=Number(t);return Number.isFinite(n)?n:void 0}case"datetime":{let n=Date.parse(String(t));return Number.isNaN(n)?void 0:n}case"boolean":return t===!0||String(t).toLowerCase()==="true"?1:0;case"date":return String(t).slice(0,10);default:return String(t).toLowerCase()}}function Tr(t,e){let n=Array.from(t),s=Array.from(e);for(let r=0;r<n.length&&r<s.length;r++){let o=n[r].codePointAt(0)-s[r].codePointAt(0);if(o!==0)return o}return n.length-s.length}function Pr(t,e,n,s,r){let o=t,i=Array.isArray(o?.rows)?o.rows:[],a=Array.isArray(o?.columns)?o.columns:void 0,l=p=>a?.find(c=>c.key===p)?.type??"text";for(let p of e.filter??[]){if(a&&!a.some(m=>m.key===p.column))return[];let c=p.value;if(c!==null&&typeof c=="object"){let m=c;if(c=Ie(n,s,m.screen,m.key),c===void 0)return[]}let d=l(p.column);i=i.filter(m=>Zt(m[p.column],p.op,c,d,r,s))}if(e.sort){let{column:p}=e.sort,c=l(p),d=e.sort.order==="desc"?-1:1;i=i.map((m,y)=>({row:m,i:y,key:Er(m[p],c)})).sort((m,y)=>{if(m.key===void 0||y.key===void 0)return m.key===void 0&&y.key===void 0?m.i-y.i:m.key===void 0?1:-1;let w=typeof m.key=="number"&&typeof y.key=="number"?m.key-y.key:Tr(String(m.key),String(y.key));return w===0?m.i-y.i:w<0?-d:d}).map(m=>m.row)}return e.limit?i.slice(0,e.limit):i}function yn(t,e,n,s,r){return!t||typeof t!="object"?t:{...t,rows:Pr(t,e,n,s,r)}}function Lr(t){if(!t)return"#000000";if("value"in t)return t.value;let e=t.gradient,n=[...e.stops].sort((s,r)=>s.at-r.at).map(s=>`${s.color.value} ${Math.round(s.at*1e4)/100}%`).join(", ");return e.kind==="radial"?`radial-gradient(circle, ${n})`:`linear-gradient(${e.angle??180}deg, ${n})`}function wn(t,e,n,s=[]){let r=H("div");if(r.dataset.background="",r.style.cssText="position:absolute;inset:0;pointer-events:none",r.style.background=Lr(e),s.length){let o=[`M0 0H${n.width}V${n.height}H0Z`,...s.map(l=>`M${l.x} ${l.y}H${l.x+l.w}V${l.y+l.h}H${l.x}Z`)].join(""),i=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${n.width} ${n.height}" preserveAspectRatio="none"><path fill-rule="evenodd" d="${o}"/></svg>`,a=`url("data:image/svg+xml,${encodeURIComponent(i)}")`;r.dataset.holes=String(s.length);for(let[l,p]of[["maskImage",a],["maskSize","100% 100%"],["maskRepeat","no-repeat"]])r.style[l]=p,r.style[`webkit${l[0].toUpperCase()}${l.slice(1)}`]=p}return t.prepend(r),r}function vn(t,e=t.frame){let n=H("div");return n.dataset.element=t.id,n.style.cssText="position:absolute;box-sizing:border-box",Ir(n,e),n}function Ir(t,e){Object.assign(t.style,{left:`${e.x}px`,top:`${e.y}px`,width:`${e.w}px`,height:`${e.h}px`,transform:e.rotation?`rotate(${e.rotation}deg)`:""})}function kn(t,e,n){if(e.type==="text"){let s=e.style??{};t.textContent=ht(e,ce(n)),Object.assign(t.style,{fontFamily:s.font?.family?`"${s.font.family}", sans-serif`:"",fontWeight:String(s.font?.weight??400),fontStyle:s.font?.style??"normal",fontSize:`${s.size??48}px`,color:s.color?.value??"#ffffff",background:s.background?.value??"",whiteSpace:"pre-wrap",textAlign:{start:"left",end:"right"}[s.align??"start"]??s.align??"left",display:"flex",flexDirection:"column",justifyContent:{top:"flex-start",middle:"center",bottom:"flex-end"}[s.verticalAlign??"top"],lineHeight:s.lineHeight?String(s.lineHeight):"",opacity:s.opacity!==void 0?String(s.opacity):"",textDecorationLine:s.decoration?.length?s.decoration.join(" "):"",textTransform:s.transform&&s.transform!=="none"?s.transform:"",letterSpacing:s.letterSpacing?`${s.letterSpacing}em`:"",textShadow:s.shadow?`${s.shadow.x??0}px ${s.shadow.y??2}px ${s.shadow.blur??4}px ${s.shadow.color?.value??"#000000"}`:""})}else e.type==="shape"&&Cr(e)?(t.style.opacity=e.opacity!==void 0?String(e.opacity):"",t.append(Rr(e))):e.type==="shape"?Object.assign(t.style,{background:e.fill?.value??"",opacity:e.opacity!==void 0?String(e.opacity):"",border:e.stroke?.width?`${e.stroke.width}px ${e.stroke.dash??"solid"} ${e.stroke.color?.value??"#000"}`:"",borderRadius:e.shape==="ellipse"?"50%":e.radius?`${e.radius}px`:"",overflow:e.clip!==!1?"hidden":""}):e.type==="library"&&(t.style.overflow="hidden",t.style.background=e.playback?.background?.value??"")}function ht(t,e){return t.bind?nt(t.bind,e):st(t.text??"",e)}function ce(t){return{screen:t?.screen??null,timeZone:t?.timeZone,tables:new Proxy({},{get:(e,n)=>typeof n=="string"?t?.snapshot?.(n):void 0})}}var Cr=t=>t.shape==="line"||t.shape==="arrow"||t.shape==="polygon";function Rr(t){let e=Ee("svg");e.setAttribute("width","100%"),e.setAttribute("height","100%"),e.style.cssText="position:absolute;inset:0;overflow:visible";let n=t.frame.w,s=t.frame.h,r=t.stroke?.width??(t.shape==="polygon"?0:4),i=(t.points?.length?t.points:t.shape==="polygon"?[[.5,0],[1,1],[0,1]]:[[0,.5],[1,.5]]).map(([c,d])=>[c*n,d*s]),a=t.stroke?.color?.value??"#000000",l=t.stroke?.dash==="dashed"?`${r*3} ${r*2}`:t.stroke?.dash==="dotted"?`0 ${r*2}`:"",p=Ee(t.shape==="polygon"?"polygon":"polyline");if(p.setAttribute("points",i.map(c=>`${c[0]},${c[1]}`).join(" ")),p.setAttribute("fill",t.shape==="polygon"?t.fill?.value??"none":"none"),r&&(p.setAttribute("stroke",a),p.setAttribute("stroke-width",String(r)),p.setAttribute("stroke-linecap",t.stroke?.dash==="dotted"?"round":"butt"),p.setAttribute("stroke-linejoin","round"),l&&p.setAttribute("stroke-dasharray",l)),e.append(p),t.shape==="arrow"&&i.length>=2){let[c,d]=[i[i.length-2],i[i.length-1]],m=Math.atan2(d[1]-c[1],d[0]-c[0]),y=Math.max(10,r*3.5),w=b=>`${d[0]-y*Math.cos(m)+b*y*.5*Math.sin(m)},${d[1]-y*Math.sin(m)-b*y*.5*Math.cos(m)}`;p.setAttribute("points",[...i.slice(0,-1),[d[0]-y*.8*Math.cos(m),d[1]-y*.8*Math.sin(m)]].map(b=>`${b[0]},${b[1]}`).join(" "));let f=Ee("polygon");f.setAttribute("points",`${d[0]},${d[1]} ${w(1)} ${w(-1)}`),f.setAttribute("fill",a),e.append(f)}return e}async function xn(t,e,n,s,r,o,i,a=()=>{},l){let p=t.appInfo??n.info;fn(e),p?.id&&(e.dataset.app=p.id);let c=(M,P)=>(e.dataset.appFailed=M,{failed:M,...P?{error:P}:{}});if(!sn(p?.requires))return c("unsupported");let d=s.appHost;if(d&&!d.custom&&!pe(p))return c("unsupported");if(pn(l,p))return cn(t,e,n,s,r,o,i,a,l,c);let m=t.app;if(d?.held?.(m))return e.dataset.appHeld="",{held:!0};await d?.mounting?.(m,p?.id);let y=!1,w=()=>{y||(y=!0,d?.unmounted?.(m))},f;try{f=await rn(n.hash,n.bytes,p)}catch(M){return w(),M instanceof U?c(M.reason,M.error):c("load")}let b=f.tag,v=p?.id?s.controllerFor?.({id:p.id,instance:t.id,capability:p.player??"read"}):void 0,A,k=new Promise(M=>{A=M}),I,$=new Set,V={app:p?.id??t.app.id,element:b,props:rt(t.props??{},ce(s)),place:s.place,screen:s.screen??null,timeZone:s.timeZone??Intl.DateTimeFormat().resolvedOptions().timeZone,locale:s.locale??navigator.language,preview:!!s.preview,now:r.now,startedAt:r.startedAt,ready:()=>A(),data:(M,P)=>s.data?s.data.get(M,P):Promise.reject(new Error("no data service")),kept:(M,P)=>s.data?.kept?.(M,P),image:M=>s.data?s.data.image(M):Promise.reject(new Error("no data service")),snapshot:M=>{let P=s.snapshot?.(M)??null;if(!P||t.binding?.table!==M||!gn(t.binding))return P;let B=yn(P,t.binding,s.screen,V.timeZone,r.now());return I?.from===P&&I.rows.length===B.rows.length&&I.rows.every((is,os)=>is===B.rows[os])?I.snapshot:(I={from:P,rows:B.rows,snapshot:B},B)},...t.binding?{binding:t.binding}:{},...s.onSnapshots?{onSnapshot:M=>($.add(M),()=>{$.delete(M)})}:{},...t.sensors?.includes("impressions")&&s.impressions?.measuring?{impressions:{now:()=>s.impressions.now(),on:M=>s.impressions.on(M)}}:{},...v?{controller:v}:{}},F;try{F=H(b),f.shape==="class"?f.attach(F,V):F.wyndlass=V}catch(M){return v?.dispose(),w(),c("error",Z(M))}F.style.cssText="display:block;width:100%;height:100%",d?.contained?.(e,F);let ne=Object.values(t.props??{}).some(M=>typeof M=="string"&&Ce(M)),L=s.onSnapshots?.(M=>{ne&&(V.props=rt(t.props??{},ce(s)));for(let P of M)for(let B of[...$])try{B(P)}catch{}}),se=new Oe(F,{onStop:a,dispose:()=>{L?.(),$.clear(),v?.dispose(),w()}});e.append(F),i(se);let we=await Promise.race([k.then(()=>!1),new Promise(M=>setTimeout(()=>M(!0),o))]);return se.update(V.now()),{app:se,late:we}}var bn=new Set;async function Mn(t,e){for(let n of t){let s=`${n.family}/${n.weight??400}/${n.style??"normal"}/${n.blob}`,r=e(n.blob);if(!(bn.has(s)||!r||typeof FontFace>"u"))try{let o=new FontFace(n.family,r,{weight:String(n.weight??400),style:n.style??"normal"});document.fonts.add(await o.load()),bn.add(s)}catch{}}}function ue(t){let e=[],n=null;for(let s of t){let r=s.start,o=Math.max(0,r.kind==="at"?r.ms:r.kind==="withPrevious"?(n?.startMs??0)+(r.offsetMs??0):(n?.endMs??0)+(r.offsetMs??0));n={startMs:o,endMs:o+s.durationMs},e.push(n)}return{clips:e,autoDurationMs:e.reduce((s,r)=>Math.max(s,r.endMs),0)}}var Nr=new Set(["x","y","scaleX","scaleY","rotation","opacity","reveal"]);function Or(t,{pageBelow:e=!1}={},n=null){let s=o=>({path:"page",reason:o});if(!n)return s("no-media-layer");if(e)return s("page-element-beneath");let r=t.slice(0,-1).filter(o=>o.type==="shape"&&o.clip!==!1);if(r.some(o=>o.shape!=="rectangle"||(o.radius??0)>0))return s("clipped-to-shape");if(r.some(o=>(o.rotation??0)%360!==0))return s("clipped-by-rotated-shape");if(!n.animates){if(t.some(o=>(o.rotation??0)%360!==0))return s("rotated");if(t.some(o=>(o.opacity??1)<1))return s("translucent");if(t.some(o=>(o.animated??[]).some(i=>Nr.has(i))))return s("animated")}return{path:"native"}}var $r={fade:["opacity"],slide:["x","opacity"],scale:["scaleX","scaleY","opacity"],pulse:["scaleX","scaleY"],loop:["scaleX","scaleY"],wipe:["reveal"]};function An(t,e,n,s){let r=e&&t.overrides?.[e]||{},o=new Map;for(let d of t.animation?.clips??[]){let m=[...d.preset?$r[d.preset]??[]:[],...(d.lanes??[]).map(y=>y.property)];o.set(d.element,[...o.get(d.element)??[],...m])}let i=d=>d.type==="library"&&!!d.source&&!!n[d.source.item.id]?.video,a=d=>!i(d)&&!(d.type==="shape"&&!d.fill&&!(d.stroke?.width??0)),l=[],p=(d,m,y,w)=>{for(let f of d){let b=r[f.id];if(b?.hidden??f.hidden??!1)continue;let v=b?.frame??f.frame,A={x:m.x+v.x,y:m.y+v.y,w:v.w,h:v.h},k={type:f.type==="shape"?"shape":"library",rotation:v.rotation??0,opacity:f.opacity??f.style?.opacity??1,animated:o.get(f.id)??[],...f.type==="shape"?{shape:f.shape,radius:f.radius,clip:f.clip}:{}};l.push({e:f,box:A,chain:[...y,k],ancestors:w}),f.type==="shape"&&p(f.children??[],A,[...y,k],[...w,f])}};p(t.elements,{x:0,y:0},[],[]);let c=(d,m)=>d.x<m.x+m.w&&m.x<d.x+d.w&&d.y<m.y+m.h&&m.y<d.y+d.h;return l.flatMap((d,m)=>{if(!i(d.e))return[];let y=l.slice(0,m).some(w=>a(w.e)&&c(w.box,d.box));return[{element:d.e.id,path:Or(d.chain,{pageBelow:y},s),box:d.box}]})}var Dr=[0,0,1,1];function mt(t,e){if(e<=0)return 0;if(e>=1)return 1;let[n,s,r,o]=t;if(n===s&&r===o)return e;let i=3*n,a=3*(r-n)-i,l=1-i-a,p=3*s,c=3*(o-s)-p,d=1-p-c,m=k=>((l*k+a)*k+i)*k,y=k=>((d*k+c)*k+p)*k,w=k=>(3*l*k+2*a)*k+i,f=1e-7,b=e;for(let k=0;k<8;k++){let I=m(b)-e;if(Math.abs(I)<f)return y(b);let $=w(b);if(Math.abs($)<1e-6)break;b-=I/$}let v=0,A=1;for(b=e;v<A;){let k=m(b);if(Math.abs(k-e)<f||(e>k?v=b:A=b,b=(A-v)/2+v,A-v<f))break}return y(b)}function De(t,e){let n=t.keyframes;if(e<=n[0].t)return n[0].v;let s=n[n.length-1];if(e>=s.t)return s.v;let r=0;for(;e>=n[r+1].t;)r++;let o=n[r],i=n[r+1];return o.v+(i.v-o.v)*mt(o.easing??Dr,(e-o.t)/(i.t-o.t))}function Sn(t,e,n){let s={x:t.x,y:t.y,scaleX:1,scaleY:1,rotation:0,opacity:1};for(let r of e??[])s[r.property]=De(r,n);return s}var he={linear:[0,0,1,1],ease:[.25,.1,.25,1],"ease-in":[.42,0,1,1],"ease-out":[0,0,.58,1],"ease-in-out":[.42,0,.58,1]};function En(t){if(!t)return he.ease;if(he[t])return he[t];let n=/^cubic-bezier\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\)$/.exec(t)?.slice(1).map(Number);return n&&n.every(Number.isFinite)?n:he.ease}function jr(t){let e=typeof t=="string"?/^#([0-9a-fA-F]{6})([0-9a-fA-F]{2})?$/.exec(t):null;if(!e)return null;let n=parseInt(e[1],16);return[n>>16&255,n>>8&255,n&255,e[2]?parseInt(e[2],16)/255:1]}var Ln={fade:()=>({opacity:0}),slide:t=>({x:t.x-t.w*.1,opacity:0}),scale:()=>({scaleX:.8,scaleY:.8,opacity:0}),wipe:()=>({reveal:0}),typewriter:()=>({chars:0}),"count-up":()=>({count:0})},Da=Object.keys(Ln);var Fr={x:t=>t.x,y:t=>t.y,scaleX:()=>1,scaleY:()=>1,rotation:()=>0,opacity:()=>1,reveal:()=>1,chars:()=>1,count:()=>1},Tn=1e3,Hr=he["ease-in-out"];function In(t,e){let n=ue(t).clips,s=new Map,r=new Set,o=a=>{let l=s.get(a);return l||s.set(a,l={keys:new Map,colour:null,loops:[],tickers:[]}),l},i=(a,l,p)=>{let c=o(a).keys,d=c.get(l)??[];c.set(l,d),d.push(p)};t.forEach((a,l)=>{let p=e.get(a.element);if(!p)return;let{startMs:c,endMs:d}=n[l],m=En(a.easing);if(a.lanes?.length){for(let f of a.lanes)for(let b of f.keyframes){let v={t:c+b.at,easing:En(b.easing??a.easing)};if(f.property==="color"){let A=jr(b.value);if(!A)continue;let k=o(a.element);k.colour??(k.colour=[[],[],[],[]]),A.forEach((I,$)=>k.colour[$].push({...v,v:I}))}else i(a.element,f.property,{...v,v:Number(b.value)})}return}let y=a.preset??"fade";if(a.kind==="emphasis"){y==="pulse"?(i(a.element,"pulse",{t:c,v:1,easing:m}),i(a.element,"pulse",{t:(c+d)/2,v:1.05,easing:m}),i(a.element,"pulse",{t:d,v:1})):y==="loop"?o(a.element).loops.push({startMs:c,endMs:d}):y==="ticker"?o(a.element).tickers.push({startMs:c,endMs:d}):r.add(y);return}let w=Ln[y];if(!w){r.add(y);return}for(let[f,b]of Object.entries(w(p))){let v=Fr[f](p),[A,k]=a.kind==="enter"?[b,v]:[v,b];i(a.element,f,{t:c,v:A,easing:m}),i(a.element,f,{t:d,v:k})}});for(let a of s.values()){for(let l of a.keys.values())l.sort((p,c)=>p.t-c.t);for(let l of a.colour??[])l.sort((p,c)=>p.t-c.t)}return{motions:s,unplayed:[...r].sort()}}var Br=["x","y","scaleX","scaleY","rotation","opacity"];function Cn(t,e,n,s=!1){if(s)return Ur(t,e,n);let r=(l,p)=>{let c=t?.keys.get(l);return c?De({property:"x",keyframes:c},n):p},o=Sn(e,Br.flatMap(l=>t?.keys.get(l)?[{property:l,keyframes:t.keys.get(l)}]:[]),n),i=r("pulse",1);for(let l of t?.loops??[])if(n>=l.startMs&&n<l.endMs){let p=(n-l.startMs)%Tn/Tn;i*=1+.05*mt(Hr,p<.5?p*2:2-p*2)}let a=t?.tickers.find(l=>n>=l.startMs&&n<l.endMs);return{...o,reveal:r("reveal",1),chars:r("chars",1),count:r("count",1),pulse:i,scroll:a?(n-a.startMs)/(a.endMs-a.startMs):null,color:t?.colour?t.colour.map(l=>De({property:"x",keyframes:l},n)):null}}function Pn(t,e){if(e<t[0].t)return t[0].v;let n=0;for(;n+1<t.length&&t[n+1].t<=e;)n++;return n+1<t.length?t[n+1].v:t[n].v}function Ur(t,e,n){let s=(r,o)=>{let i=t?.keys.get(r);return i?Pn(i,n):o};return{x:s("x",e.x),y:s("y",e.y),scaleX:s("scaleX",1),scaleY:s("scaleY",1),rotation:s("rotation",0),opacity:s("opacity",1),reveal:s("reveal",1),chars:s("chars",1),count:s("count",1),pulse:1,scroll:null,color:t?.colour?t.colour.map(r=>Pn(r,n)):null}}function _r(t,e){let n=Array.from(t);return e>=1?t:n.slice(0,Math.max(0,Math.round(e*n.length))).join("")}function qr(t,e){return e>=1?t:t.replace(/\d+(?:\.\d+)?/g,n=>(Number(n)*Math.max(0,e)).toFixed((n.split(".")[1]??"").length))}function Rn(t,e,n){if(t<=1||e<=0)return[{page:0,startMs:0,endMs:n}];let s=[];for(let r=0;r*e<n&&r<1e3;r++)s.push({page:r%t,startMs:r*e,endMs:Math.min((r+1)*e,n)});return s}function Nn(t,e,n,s){t.style.left=`${n.x}px`,t.style.top=`${n.y}px`,t.style.transform=`rotate(${(e.frame.rotation??0)+n.rotation}deg) scale(${n.scaleX*n.pulse}, ${n.scaleY*n.pulse})`,t.style.opacity=String((e.opacity??e.style?.opacity??1)*n.opacity),t.style.clipPath=n.reveal>=1?"":`inset(0 ${(1-Math.max(0,n.reveal))*100}% 0 0)`;let r=n.color?`rgba(${n.color.slice(0,3).map(o=>Math.round(o)).join(",")},${n.color[3]})`:null;if(e.type==="text"&&s!==void 0){let o=qr(_r(s,n.chars),n.count);if(n.scroll!==null){let i=t.querySelector("[data-ticker]");i||(i=document.createElement("span"),i.dataset.ticker="",i.style.cssText="display:inline-block;white-space:nowrap;will-change:transform",t.replaceChildren(i),t.style.overflow="hidden"),i.textContent!==o&&(i.textContent=o);let a=e.frame.w,l=i.scrollWidth;i.style.transform=`translateX(${a-n.scroll*(a+l)}px)`}else(t.textContent!==o||t.querySelector("[data-ticker]"))&&(t.textContent=o,t.style.overflow="");r&&(t.style.color=r)}else if(e.type==="shape"&&r){let o=t.querySelector("polygon, polyline");o&&e.shape==="polygon"?o.setAttribute("fill",r):o||(t.style.background=r)}}function Wr(t){let e=t>>>0;return()=>{e=e+1831565813|0;let n=Math.imul(e^e>>>15,1|e);return n=n+Math.imul(n^n>>>7,61|n)^n,((n^n>>>14)>>>0)/4294967296}}async function On(t,e,n,s){let r=parseInt((await tt(et(`${t}
2
+ "use strict";(()=>{var ws=Object.defineProperty;var vs=(t,e,n)=>e in t?ws(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var c=(t,e,n)=>vs(t,typeof e!="symbol"?e+"":e,n);var Kt=Reflect.apply,Ye=Object.getOwnPropertyDescriptor,Te=Object.getPrototypeOf,O=globalThis,x=(t,e,n)=>Kt(t,e,n),j=(t,e)=>t?Ye(t,e)?.get:void 0,Ge=(t,e)=>t?Ye(t,e)?.set:void 0,R=t=>O[t]?.prototype,Zt=(t,e,n)=>Kt(t,e,n);var Ur=Date.now,Wr=new TextEncoder,_r=new TextDecoder,qr=TextEncoder.prototype.encode,zr=TextDecoder.prototype.decode;var Vr=j(Te(Uint8Array.prototype),"length");var ks=Uint8Array,xs=t=>new ks(t),Ms=[];for(let t=0;t<256;t++)Ms[t]=(t<16?"0":"")+t.toString(16);var Es=Object.create(null);for(let t=0;t<64;t++)Es["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[t]]=t;var jt=O.crypto?.subtle,Xe=jt?Te(jt):void 0,Je=O.crypto,As=Je?Te(Je).getRandomValues:void 0,Kr=Xe?.digest,Zr=Xe?.importKey,Jr=Xe?.sign;var Jt=t=>x(As,Je,[xs(t)]),Yr={setTimeout:O.setTimeout,clearTimeout:O.clearTimeout,setInterval:O.setInterval,clearInterval:O.clearInterval};var Gr=O.fetch;var le=R("MessagePort"),Xr=le&&le.postMessage,Qr=Ge(le,"onmessage"),eo=le&&le.start,Qe=R("MessageEvent"),to=j(Qe,"data"),no=j(Qe,"ports"),so=j(Qe,"source");var Yt=R("EventTarget"),Ss=Yt?.addEventListener,io=Yt?.removeEventListener,et=(t,e,n,s=!1)=>x(Ss,t,[e,n,s]);var ro=O.Worker,Ee=R("Worker"),oo=Ee&&Ee.postMessage,ao=Ge(Ee,"onmessage"),lo=Ge(Ee,"onerror");var Ft=O.Blob,Ae=O.URL,Ht=Ae?.createObjectURL,Ts=Ae?.revokeObjectURL,tt=Ft&&Ht?{make:(t,e)=>x(Ht,Ae,[new Ft(t,{type:e})]),revoke:t=>x(Ts,Ae,[t])}:void 0,ae=O.customElements,nt=ae?Te(ae):void 0,Ps=nt?.define,Ls=nt?.get,st=ae&&nt?{define:(t,e)=>x(Ps,ae,[t,e]),get:t=>x(Ls,ae,[t])}:void 0,Gt=O.document,Se=R("Document"),Cs=Se?.createElement,Is=Se?.createElementNS,Rs=WeakSet.prototype.add,po=WeakSet.prototype.has,it=new WeakSet,Ns=new WeakSet,Pe=(t,e)=>(x(Rs,t,[e]),e);function F(t){return Pe(it,x(Cs,Gt,[t]))}var Le=t=>Pe(it,x(Is,Gt,["http://www.w3.org/2000/svg",t]));var W=t=>Pe(Ns,t);var de=R("Node"),rt=R("Element"),Ce=R("HTMLElement"),ee=t=>j(de,t),Bt=ee("parentNode"),Os=ee("firstChild"),Ds=ee("lastChild"),$s=ee("nextSibling"),js=ee("nodeType"),Fs=ee("childNodes"),Hs=j(rt,"localName"),Bs=de?.appendChild,Us=de?.insertBefore,Ws=de?.removeChild,J=rt,_s=J?.getAttribute,qs=J?.getAttributeNames,zs=J?.setAttribute,Vs=J?.removeAttribute,Ks=J?.matches,Zs=J?.attachShadow,Js=J?.querySelectorAll,Ys=R("HTMLDialogElement")?.close,Gs=j(R("NodeList"),"length"),Xs=R("NodeList")?.item,Ie=R("MutationRecord"),Qs=j(Ie,"type"),ei=j(Ie,"target"),ti=j(Ie,"addedNodes"),ni=j(Ie,"removedNodes"),Ut=O.MutationObserver,si=R("MutationObserver")?.observe,Xt=Se?Ye(Se,"adoptedStyleSheets"):void 0,Wt=Xt?.get,_t=Xt?.set,ii=O.requestAnimationFrame,qt=j(Ce,"style"),Re=R("CSSStyleDeclaration"),ri=Re?.getPropertyValue,oi=Re?.getPropertyPriority,ai=Re?.setProperty,zt=Ce?.showPopover,Vt=Ce?.hidePopover,li=j(R("Event"),"target"),di=R("Event")?.stopImmediatePropagation,Me=t=>{let e=[];for(let n=0,s=x(Gs,t,[]);n<s;n++)e[n]=x(Xs,t,[n]);return e},I=Ut&&de&&rt&&Ce&&Re?{parent:t=>x(Bt,t,[]),first:t=>x(Os,t,[]),last:t=>x(Ds,t,[]),next:t=>x($s,t,[]),isElement:t=>x(js,t,[])===1,name:t=>x(Hs,t,[]),children:t=>Me(x(Fs,t,[])),append:(t,e)=>x(Bs,t,[e]),insert:(t,e,n)=>x(Us,t,[e,n]),remove:t=>{let e=x(Bt,t,[]);e&&x(Ws,e,[t])},attribute:(t,e)=>x(_s,t,[e]),attributes:t=>x(qs,t,[]),setAttribute:(t,e,n)=>x(zs,t,[e,n]),removeAttribute:(t,e)=>x(Vs,t,[e]),matches:(t,e)=>x(Ks,t,[e]),all:(t,e)=>Me(x(Js,t,[e])),closeDialog:t=>x(Ys,t,[]),shadow:t=>x(Zs,t,[{mode:"closed"}]),style:(t,e)=>{let n=x(qt,t,[]);return[x(ri,n,[e]),x(oi,n,[e])]},setStyle:(t,e,n,s="")=>x(ai,x(qt,t,[]),[e,n,s]),observer:t=>new Ut(t),observe:(t,e,n)=>x(si,t,[e,n]),record:t=>({type:x(Qs,t,[]),target:x(ei,t,[]),added:Me(x(ti,t,[])),removed:Me(x(ni,t,[]))}),adopted:Wt&&_t?{count:t=>x(Wt,t,[]).length,clear:t=>x(_t,t,[[]])}:void 0,frame:t=>x(ii,globalThis,[t]),popover:zt&&Vt?{show:t=>x(zt,t,[]),hide:t=>x(Vt,t,[])}:void 0,target:t=>x(li,t,[]),stop:t=>x(di,t,[])}:void 0;function ot(t){if(Pe(it,t),I)for(let e of I.children(t))I.isElement(e)&&ot(e);return t}var pi;function at(t,e){try{pi?.caught(t,e)}catch{}}var Ne=t=>new TextEncoder().encode(t);function ci(t){let e=t instanceof Uint8Array?t:new Uint8Array(t),n="";for(let s of e)n+=s.toString(16).padStart(2,"0");return n}async function lt(t){return ci(await crypto.subtle.digest("SHA-256",t))}var mi=["name","type","tags","location","site","district","region","organization","path","timeZone"],fi=["text","date","currency","truncate"],Qt={site:"SITE",district:"DISTRICT",region:"REGION",organization:"ORGANIZATION"};function Oe(t,e,n,s){if(!t)return n==="timeZone"&&e?e:void 0;if(n==="fields")return s&&t.fields?.[s]||void 0;let i=t.path??[];switch(n){case"name":return t.name||void 0;case"type":return t.type||void 0;case"tags":return t.tags?.length?t.tags.join(", "):void 0;case"location":return i.at(-1)?.name;case"path":return i.length?i.map(r=>r.name).join(" \u203A "):void 0;case"timeZone":return e||void 0;default:return Qt[n]?[...i].reverse().find(r=>r.kind===Qt[n])?.name:void 0}}function gi(t,e){if(t==null||t==="")return;let n=String(t);if(e==="currency"){let s=Number(t);return Number.isFinite(s)?s.toFixed(2):n}if(e==="date"){let s=Date.parse(n);return Number.isNaN(s)?n:new Date(s).toISOString().slice(0,10)}return e==="truncate"&&n.length>40?n.slice(0,39)+"\u2026":n}function dt(t,e){return(t.source==="screen"?Oe(e.screen,e.timeZone,t.field,t.key):gi(e.tables?.[t.table]?.rows?.[t.row??0]?.[t.column],t.format))??t.fallback??""}function en(t){let e=/^\s*(?:screen\.(fields\.[a-z][A-Za-z0-9]{0,31}|[A-Za-z]+)|table\.([A-Za-z0-9_-]+)\[(\d+)\](?:\.([A-Za-z0-9_]+)|\["((?:[^"\\]|\\.)*)"\]))\s*((?:\|\s*(?:[a-z]+|"(?:[^"\\]|\\.)*")\s*)*)$/.exec(t);if(!e)return null;let n=[...e[6].matchAll(/\|\s*([a-z]+|"((?:[^"\\]|\\.)*)")/g)],s=n.find(r=>r[1].startsWith('"'))?.[2]?.replace(/\\(.)/g,"$1"),i=n.find(r=>!r[1].startsWith('"'))?.[1];return e[1]!==void 0?i?null:e[1].startsWith("fields.")?{source:"screen",field:"fields",key:e[1].slice(7),...s!==void 0?{fallback:s}:{}}:mi.includes(e[1])?{source:"screen",field:e[1],...s!==void 0?{fallback:s}:{}}:null:i&&!fi.includes(i)?null:{source:"table",table:e[2],row:Number(e[3]),column:e[4]??e[5].replace(/\\(.)/g,"$1"),...i?{format:i}:{},...s!==void 0?{fallback:s}:{}}}function pt(t,e){return t.replace(/\{{2}([^{}]*)\}{2}/g,(n,s)=>{let i=en(s);return i?dt(i,e):n})}function De(t){return[...t.matchAll(/\{{2}([^{}]*)\}{2}/g)].some(e=>en(e[1])!==null)}function ct(t,e){return Object.fromEntries(Object.entries(t).map(([n,s])=>[n,typeof s=="string"?pt(s,e):s]))}var ut=t=>t==null||t==="";function nn(t,e,n,s,i,r){return yi(t,e,n,s,{now:i,timeZone:r})}function yi(t,e,n,s,i){if(n===null&&(e==="eq"||e==="ne"))return e==="eq"?ut(t):!ut(t);if(ut(t)||n===null||n===void 0)return!1;switch(s){case"number":case"currency":{let r=Number(t),o=Number(n);return typeof n!="boolean"&&n!==""&&Number.isFinite(r)&&Number.isFinite(o)&&ht(e,r-o)}case"boolean":{let r=n===!0||n==="true"?!0:n===!1||n==="false"?!1:void 0;return r!==void 0&&(e==="eq"?t===r:e==="ne"?t!==r:!1)}case"date":{let r=n==="today"?bi(i.now,i.timeZone).date:String(n),o=String(t).slice(0,10);return/^\d{4}-\d{2}-\d{2}$/.test(r)&&ht(e,o<r?-1:o>r?1:0)}case"datetime":{let r=Date.parse(String(t)),o=n==="now"?i.now:Date.parse(String(n));return!Number.isNaN(r)&&!Number.isNaN(o)&&ht(e,r-o)}default:{let r=String(t).toLowerCase(),o=String(n).toLowerCase();return e==="eq"?r===o:e==="ne"?r!==o:e==="contains"?r.includes(o):!1}}}function ht(t,e){switch(t){case"eq":return e===0;case"ne":return e!==0;case"lt":return e<0;case"lte":return e<=0;case"gt":return e>0;case"gte":return e>=0;default:return!1}}var tn=new Map;function bi(t,e){let n=tn.get(e);n||(n=new Intl.DateTimeFormat("en-US",{timeZone:e,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",weekday:"short"}),tn.set(e,n));let s=Object.fromEntries(n.formatToParts(new Date(t)).map(i=>[i.type,i.value]));return{date:`${s.year}-${s.month}-${s.day}`,minute:Number(s.hour)%24*60+Number(s.minute),day:String(s.weekday).slice(0,3).toLowerCase()}}var sn=(t,e)=>!t||(t.from===void 0||t.from<=e)&&(t.until===void 0||e<t.until);var pe=class{constructor(e,n,s,i,r){c(this,"renderer",e);c(this,"wrap",i);c(this,"onShown",r);c(this,"timer");c(this,"turns",0);c(this,"turnAt");c(this,"left");c(this,"stopped",!1);c(this,"share");c(this,"pages");this.pages=n.pages??[],this.share=n.durationMs/Math.max(1,this.pages.length),this.turnAt=s+this.share,this.arm()}arm(){clearTimeout(this.timer);let e=this.pages.length;if(this.stopped||this.left!==void 0||e<2||!this.wrap&&this.turns+1>=e)return;let n=this.pages[(this.turns+1)%e];this.renderer.prepare?.(n).catch(()=>{}),this.timer=setTimeout(()=>{this.turn(n)},Math.min(Math.max(0,this.turnAt-Date.now()),2**31-1))}async turn(e){try{await this.renderer.show(e)}catch{}this.stopped||(this.turns++,this.turnAt+=this.share,this.onShown?.(e),this.arm())}pause(){this.stopped||this.left!==void 0||(clearTimeout(this.timer),this.left=Math.max(0,this.turnAt-Date.now()))}resume(){this.stopped||this.left===void 0||(this.turnAt=Date.now()+this.left,this.left=void 0,this.arm())}stop(){if(!this.stopped){this.stopped=!0,clearTimeout(this.timer);for(let e of this.pages)this.renderer.release?.(e)}}};var xi=Object.freeze,Mi=Object.values,rn=Reflect.apply;function $e(t){if(t===null||typeof t!="object")return t;for(let e of rn(Mi,Object,[t]))$e(e);return rn(xi,Object,[t])}var mt=class extends Error{constructor(n,s){super(s);c(this,"code",n);this.name="MediaError"}};function ft(t){return t instanceof mt?{code:t.code.slice(0,64),message:t.message.slice(0,1e3)}:{code:"not-shown",message:String(t instanceof Error?t.message:t??"").slice(0,1e3)}}var on=t=>t.blob.contentType.startsWith("video/");var gt="position:absolute;inset:0;width:100%;height:100%;object-fit:contain",Ei=1,je=class{constructor(e,n={}){c(this,"container",e);c(this,"options",n);c(this,"prepared",new Map);c(this,"shown",null);c(this,"visible",null);c(this,"turns",0);c(this,"latest",null);c(this,"endListeners",new Set);c(this,"itemListeners",new Set);c(this,"appListeners",new Set);c(this,"held",null);c(this,"heldFor",null);c(this,"drawn",0);c(this,"shownHash",null);let s=n.media;s&&(document.documentElement.style.background="transparent",document.body.style.background="transparent",e.style.background="#000",s.onEnd((i,r)=>{let o=this.shown;if(o?.mediaId===i)for(let a of this.endListeners)a(o.slide,r)}))}onMediaEnd(e){this.endListeners.add(e)}onElementItem(e){this.itemListeners.add(e)}onApp(e){this.appListeners.add(e)}app(e){for(let n of this.appListeners)n(e);this.options.onApp?.(e)}prepare(e){let n=this.prepared.get(e);if(n)return n.ready;let s;try{s=this.make(e)}catch(i){return e.layout&&at(i,"layout"),Promise.reject(i)}return this.prepared.set(e,s),s.ready.catch(()=>{this.prepared.get(e)===s&&(this.prepared.delete(e),this.dispose(s))}),s.ready}release(e){let n=this.prepared.get(e);n&&(this.prepared.delete(e),this.dispose(n))}async show(e){let n=++this.turns;this.latest=e;let s=()=>n!==this.turns;if(await this.prepare(e),s())return this.latest!==e&&this.release(e),"cut";let i=this.prepared.get(e);if(!i)throw new Error("the slide was released before it was shown");this.prepared.delete(e);let r=this.visible,o=this.options.media,a=r?ln(e):void 0;if(i.kind==="layout"&&a===void 0){if(!await z(()=>s()?!1:(r?this.container.insertBefore(i.el,r.el):this.container.append(i.el),this.shown=i,this.shownHash=e.blob.hash,!0)))return this.drop(i);this.hold(i),await i.view.start().catch(()=>{});let l=Promise.resolve();return await z(()=>s()?!1:(i.el.style.visibility="",r?.el.remove(),this.visible=i,o&&this.paint("transparent"),o&&r?.mediaId&&(l=o.show([],[r.mediaId],Date.now())),!0))?(await l.catch(()=>{}),r&&this.dispose(r),this.releaseHeld(i),"cut"):this.drop(i)}if(a!==void 0&&o&&i.kind==="native"&&r.kind==="native"){if(i.fadesIn&&!i.queued){let l=Promise.resolve();return await z(()=>s()?!1:(i.el.style.visibility="",this.container.insertBefore(i.el,r.el),l=o.show([i.mediaId],[],Date.now()),this.shown=i,this.visible=i,this.shownHash=e.blob.hash,!0))?(await l.catch(()=>{}),Ai(a).then(async()=>{await o.show([],[r.mediaId],Date.now()).catch(()=>{}),r.el.remove(),this.dispose(r)}),"crossfade"):this.drop(i)}}else if(a!==void 0&&o&&i.kind==="native"){let l=Promise.resolve();return await z(()=>s()?!1:(i.el.style.visibility="",this.container.insertBefore(i.el,r.el),l=o.show([i.mediaId],[],Date.now()),this.shown=i,this.visible=i,this.shownHash=e.blob.hash,!0))?(await l.catch(()=>{}),this.paint("transparent"),dn(r.el,1,0,a).then(()=>{r.el.remove(),this.dispose(r)}),"crossfade"):this.drop(i)}else if(a!==void 0)return await z(()=>s()?!1:(i.el.style.visibility="",i.el.style.opacity="0",this.container.append(i.el),i.kind==="video"&&yt(i.el),this.shown=i,this.visible=i,this.shownHash=e.blob.hash,!0))?(i.view&&(this.hold(i),i.view.start().then(()=>this.releaseHeld(i))),dn(i.el,0,1,a).then(async()=>{r.el.remove(),this.shown===i&&this.paint(o?"#000":""),o&&r.mediaId&&await o.show([],[r.mediaId],Date.now()).catch(()=>{}),this.dispose(r)}),"crossfade"):this.drop(i);if(o&&i.kind==="native"){let l=Promise.resolve();if(!await z(()=>s()?!1:(i.el.style.visibility="",r?this.container.insertBefore(i.el,r.el):this.container.prepend(i.el),l=o.show([i.mediaId],r?.mediaId?[r.mediaId]:[],Date.now()),this.shown=i,this.shownHash=e.blob.hash,!0)))return this.drop(i);if(await l.catch(()=>{}),!await z(()=>s()?!1:(r?.el.remove(),this.visible=i,this.paint("transparent"),!0)))return this.shown===i&&r?.mediaId&&o.show([r.mediaId],[],Date.now()).catch(()=>{}),this.drop(i)}else{let l=Promise.resolve();if(!await z(()=>s()?!1:(i.el.style.visibility="",i.el.parentNode!==this.container&&this.container.append(i.el),r?.el.remove(),this.paint(o?"#000":""),o&&r?.mediaId&&(l=o.show([],[r.mediaId],Date.now())),i.kind==="video"&&yt(i.el),this.shown=i,this.visible=i,this.shownHash=e.blob.hash,!0)))return this.drop(i);await l.catch(()=>{})}return r&&this.dispose(r),"cut"}paint(e){this.options.background?this.options.background(e):this.container.style.background=e}standby(){this.turns++,this.latest=null;let e=this.visible;this.shown=null,this.visible=null,this.shownHash=null,this.paint(this.options.media?"#000":""),e&&(e.mediaId&&this.options.media?.show([],[e.mediaId],Date.now()).catch(()=>{}),this.dispose(e))}pause(){let e=this.shown;e?.view?.pause(),e?.kind==="video"?e.el.pause():e?.mediaId&&this.options.media?.control(e.mediaId,"pause").catch(()=>{})}resume(){let e=this.shown;e?.view?.resume(),e?.kind==="video"?yt(e.el):e?.mediaId&&this.options.media?.control(e.mediaId,"play").catch(()=>{})}make(e){if(e.layout){let{doc:o,source:a,untilPass:l}=e.layout,p=W(F("div"));p.dataset.blob=e.blob.hash,p.style.cssText=`${gt};visibility:hidden`,this.container.append(p);let u=String(++this.drawn),d={slide:e,kind:"layout",el:p,drawing:u,ready:Promise.resolve()},m=g=>this.options.path?`${this.options.path}/${g}`:g;return d.view=new te(o,a,p,{media:this.options.media,path:this.options.path,endsWith:l?m(l):void 0,onItem:g=>{if(d.dropped)return;let k={...g,slide:g.slide?`${u}.${g.slide}`:u};this.held?this.held.push(k):this.item(k)},onPassEnd:g=>{if(l&&g===m(l)&&this.shown===d){for(let k of this.endListeners)k(e);return"hold"}return this.options.onPassEnd?.(g)},onApp:g=>this.app(g)}),d.ready=d.view.ready,d}if(!on(e)){if(!e.bytes&&!e.url)throw new Error(`no bytes for ${e.blob.hash}`);let o=e.bytes?URL.createObjectURL(new Blob([e.bytes],{type:e.blob.contentType})):void 0,a=W(F("img"));return a.src=o??e.url,a.alt="",a.dataset.blob=e.blob.hash,a.style.cssText=this.fill(),{slide:e,kind:"image",el:a,objectUrl:o,ready:a.decode()}}let n=this.options.media;if(n){let o=`m-${Ei++}`,a=W(F("div"));a.dataset.blob=e.blob.hash,a.dataset.media=o,a.style.cssText=`${gt};visibility:hidden`;let l=this.container.getBoundingClientRect(),p={x:l.left,y:l.top,w:l.width||window.innerWidth,h:l.height||window.innerHeight},u=ln(e),d=u!==void 0&&this.shown?.kind==="native"&&n.capability.animates&&n.capability.layers>=2,m=d?[{property:"opacity",keyframes:[{t:0,v:0},{t:u,v:1}]}]:[],g={slide:e,kind:"native",el:a,mediaId:o,fadesIn:d,ready:Promise.resolve()},k=this.options.fit??"contain";return g.ready=n.prepare({mediaId:o,blob:e.blob.hash,contentType:e.blob.contentType,box:p,z:d?1:0,loop:e.loop,muted:!1,fit:k,...d?{tracks:m}:{}}).then(f=>{f.queued&&(g.queued=!0)}),g}let s=e.url?void 0:URL.createObjectURL(new Blob([e.bytes],{type:e.blob.contentType})),i=W(F("video"));i.dataset.blob=e.blob.hash,i.style.cssText=`${this.fill()};visibility:hidden`,i.muted=!1,i.playsInline=!0,i.preload="auto",i.loop=e.loop,i.src=e.url??s,i.addEventListener("ended",()=>{if(this.shown?.el===i)for(let o of this.endListeners)o(e)}),i.addEventListener("error",()=>{if(this.shown?.el===i)for(let o of this.endListeners)o(e,`video: ${i.error?.message??"error"}`)});let r=new Promise((o,a)=>{if(i.readyState>=2)return o();i.addEventListener("loadeddata",()=>o(),{once:!0}),i.addEventListener("error",()=>a(new Error(`video: ${i.error?.message??"cannot load"}`)),{once:!0})});return this.container.append(i),{slide:e,kind:"video",el:i,objectUrl:s,ready:r}}item(e){this.options.onItem?.(e);for(let n of this.itemListeners)n(e)}hold(e){this.held??(this.held=[]),this.heldFor=e}releaseHeld(e){if(this.heldFor!==e)return;let n=this.held;this.held=null,this.heldFor=null,n?.length&&setTimeout(()=>{for(let s of n)this.item(s)},0)}drop(e){e.dropped=!0;let n=e.drawing;return this.held&&n&&(this.held=this.held.filter(s=>s.slide!==n&&!s.slide?.startsWith(`${n}.`))),this.releaseHeld(e),this.shown===e&&(this.shown=this.visible,this.shownHash=this.visible?.slide.blob.hash??null),this.dispose(e),"cut"}fill(){let e=this.options.fit==="stretch"?"fill":this.options.fit??"contain";return gt.replace("object-fit:contain",`object-fit:${e}`)}dispose(e){if(this.shown!==e){if(e.view?.dispose(),e.el.remove(),e.kind==="video"){let n=e.el;n.pause(),n.removeAttribute("src"),n.load()}e.mediaId&&this.options.media?.release(e.mediaId).catch(()=>{}),e.objectUrl&&URL.revokeObjectURL(e.objectUrl)}}};function ln(t){if(t.transition?.type==="crossfade")return Math.max(0,Math.min(t.transition.durationMs??1e3,t.durationMs/2))}var Ai=t=>new Promise(e=>setTimeout(e,t));function dn(t,e,n,s){return new Promise(i=>{let r=Date.now(),o=!1,a=()=>{o||(o=!0,t.style.opacity=n===1?"":String(n),i())};t.style.opacity=String(e);let l=()=>{if(o)return;let p=Math.min(1,(Date.now()-r)/s);if(p>=1)return a();t.style.opacity=String(e+(n-e)*p),requestAnimationFrame(l)};requestAnimationFrame(l),setTimeout(a,s+250)})}function yt(t){t.play().catch(()=>(t.muted=!0,t.play())).catch(()=>{})}function z(t){return new Promise((e,n)=>{let s=!1,i=()=>{if(!s){s=!0;try{e(t())}catch(r){n(r)}}};requestAnimationFrame(i),setTimeout(i,250)})}var ce={apiVersion:2,properties:[{name:"device",description:"What the device is: id, type, shell and versions, model, resolution and orientation. Fixed while the player runs."},{name:"mode",description:"Where player-core runs: player, preview (in the CMS) or designer. In preview and the designer, commands change nothing."},{name:"timeZone",description:"The player's time zone (IANA), from the host.",event:"time.changed"},{name:"locale",description:"The player's locale (BCP 47), from the host."},{name:"connection",description:"Whether the player is connected to Wyndlass.",event:"connection.changed"},{name:"state",description:"starting, playing, paused, stopped (the standby screen), idle (nothing to play) or error.",event:"state.changed"},{name:"held",description:"A remote pause or stop in effect, by whom and since when; absent when none.",event:"state.changed"},{name:"content",description:"The manifest playing, when it was issued and switched to; absent when there is none.",event:"content.updated"},{name:"now",description:"What each zone shows: the item, its blob and content type, when it started, and its duration and position when known.",event:"item.start"},{name:"audio",description:"The player's volume (0 to 100) and whether it is muted; only when the host can set them.",event:"audio.changed"},{name:"display",description:"The display's power and brightness; only when the host can report them.",event:"display.changed"},{name:"emergency",description:"Emergency messages at the screen (WP-0150): what shows (none, a banner or a takeover), and of each message in force its source, severity, presentation, event, categories and whether it is a test. Never its words. Absent until the shell has said what it holds."},{name:"capabilities",description:"What the host can do: audio, display power, display brightness."}],events:[{name:"state.changed",description:"The player's state changed (playing, paused, stopped, idle, error), and who changed it."},{name:"content.updated",description:"A new manifest was switched to."},{name:"item.start",description:"An item started in a zone (source start)."},{name:"item.end",description:"An item ended in a zone (source end): completed, skipped, stopped, error, replaced by new content, or finished by its app."},{name:"item.error",description:"An item could not be shown."},{name:"connection.changed",description:"The player connected to Wyndlass or lost its connection."},{name:"audio.changed",description:"The volume or mute changed, and who changed it."},{name:"display.changed",description:"The display's power or brightness changed, and who changed it."},{name:"time.changed",description:"The clock was adjusted or the time zone changed."},{name:"emergency.changed",description:"What the screen shows of emergency messages, or the messages in force, changed."},{name:"app.command",description:"A command for apps on the screen (apps.sendCommand); an app reacts if it knows the name."},{name:"app.failed",description:"An app on the screen could not run, or misbehaved (WP-0100): its bundle did not load, it was not an app, it needs a newer player, it kept throwing and was stopped, or it was late or overran a clip."},{name:"app.held",description:"An app version was held back on this screen until the next manifest, after the page stopped answering twice in an hour while it was on screen (WP-0100)."}],commands:[{name:"player.status",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/status",description:"Everything about the player now: device, mode, time zone, locale, connection, state (and any hold), the content playing, what each zone shows, audio, display and what the host can do. Changes nothing.",idempotent:!0},{name:"player.events",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/events",result:"player-api-results.schema.json#/$defs/events",description:"The player's recent events (the last 200), oldest first, after a sequence number: state changes, content updates, item starts and ends, errors, connection, audio, display and time. Pass next as after to poll for more. Changes nothing.",idempotent:!0},{name:"time.now",access:"read",apps:"read",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/timeNow",description:"The player's current time, its time zone and UTC offset, and whether its clock is synchronized. Changes nothing.",idempotent:!0},{name:"player.play",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Resumes or starts playback on the screen. From a remote caller it also ends a remote pause or stop.",idempotent:!0},{name:"player.pause",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Freezes the screen on what it shows now: the loop's timer and any media stop where they are. From a remote caller it holds until a remote player.play or a restart; apps cannot resume it, and new content arrives paused.",idempotent:!0},{name:"player.stop",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/state",description:"Stops playback and shows the standby screen (black, display on). From a remote caller it holds until a remote player.play or a restart; apps cannot restart it, and new content arrives stopped.",idempotent:!0},{name:"player.next",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Skips to the next item in a zone (main by default); the current item ends as skipped."},{name:"player.previous",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/zone",result:"player-api-results.schema.json#/$defs/now",description:"Goes back to the previous item in a zone (main by default); the current item ends as skipped."},{name:"player.playItem",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/playItem",result:"player-api-results.schema.json#/$defs/now",description:"Shows a given item of the content playing now in a zone (main by default), then continues the loop from it. Refused for an item the playing manifest does not have."},{name:"audio.setVolume",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setVolume",result:"player-api-results.schema.json#/$defs/audio",description:"Sets the player's volume, 0 to 100. Only on players whose host can set it to a level.",needs:"audio.volume",idempotent:!0},{name:"audio.setMuted",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setMuted",result:"player-api-results.schema.json#/$defs/audio",description:"Mutes or unmutes the player. Only on players whose host can.",needs:"audio",idempotent:!0},{name:"display.setPower",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setPower",result:"player-api-results.schema.json#/$defs/display",description:"Turns the display on or to standby. Only on players whose host can. Standby blanks the screen until it is turned on.",needs:"display.power",idempotent:!0},{name:"display.setBrightness",access:"control",apps:"control",remote:!0,params:"player-api-params.schema.json#/$defs/setBrightness",result:"player-api-results.schema.json#/$defs/display",description:"Sets the display's brightness, 0 to 100. Only on players whose host can.",needs:"display.brightness",idempotent:!0},{name:"apps.sendCommand",access:"control",apps:"none",remote:!0,params:"player-api-params.schema.json#/$defs/sendCommand",result:"player-api-results.schema.json#/$defs/delivered",description:"Sends a named command, with an optional argument, to the apps on the screen; an app that knows the name reacts. Returns how many apps listen."},{name:"app.finish",access:"control",apps:"read",remote:!1,params:"player-api-params.schema.json#/$defs/empty",result:"player-api-results.schema.json#/$defs/none",description:"An app ends its own slot now: its item ends as finished and the loop moves on. Apps only; not a tool."}],host:[{name:"host.describe",kind:"request",description:"What the device is, its time zone, locale, connection and capabilities.",result:"player-api-host.schema.json#/$defs/describeResult"},{name:"host.time",kind:"request",description:"The host's time and time zone.",result:"player-api-common.schema.json#/$defs/timeNow"},{name:"host.getAudio",kind:"request",description:"The player's volume and mute.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.setAudio",kind:"request",description:"Sets the volume, the mute or both; answers the audio after.",result:"player-api-common.schema.json#/$defs/audio"},{name:"host.getDisplay",kind:"request",description:"The display's power and brightness.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.setDisplay",kind:"request",description:"Sets the display's power, brightness or both; answers the display after.",result:"player-api-common.schema.json#/$defs/display"},{name:"host.adRequest",kind:"request",description:"Asks Wyndlass's ad broker for one slot of a break over the host's NATS connection (WP-0075); the result is the broker's ad-decision (ad-decision.schema.json). Only a host whose describe says ads is asked."},{name:"host.mediaPrepare",kind:"request",description:"Lays a video out behind the page and prepares it to its first frame; host.mediaState says when (ADR 0055)."},{name:"host.mediaShow",kind:"request",description:"Shows and hides prepared videos; replies once its layer has changed."},{name:"host.mediaControl",kind:"request",description:"Plays, pauses or seeks a video, or asks for its position."},{name:"host.mediaRelease",kind:"request",description:"Removes a video and frees its decoder."},{name:"host.reply",kind:"reply",description:"The host's answer to a request: result or error (unsupported, failed)."},{name:"host.connection",kind:"event",description:"The connection to Wyndlass changed."},{name:"host.timeChanged",kind:"event",description:"The clock was adjusted or the time zone changed."},{name:"host.audioChanged",kind:"event",description:"The volume or mute changed outside the player."},{name:"host.displayChanged",kind:"event",description:"The display changed outside the player."},{name:"host.mediaState",kind:"event",description:"A video was prepared, started, ended or failed, or its position was asked for."},{name:"host.presence",kind:"event",description:"What one of the host's sensors sees now: the presences in view, with random ids that never leave the page (WP-0105)."},{name:"host.sensing",kind:"event",description:"The site's sensing mode as the host applies it, and its sensors (WP-0105)."},{name:"host.serialPorts",kind:"event",description:"The host's sensor controller ports, and which are open (WP-0043)."},{name:"host.serialLine",kind:"event",description:"One line from a sensor controller, as it arrived (WP-0043)."},{name:"host.serialWrite",kind:"request",description:"Writes lines to a sensor controller, a gap apart; replies once written (WP-0043)."},{name:"host.bleWatch",kind:"request",description:"What the page listens for: beacons' iBeacon UUIDs, Eddystone namespaces and addresses; replies once the scan follows it. Sent only to a host that has sent host.bleState (WP-0044)."},{name:"host.bleAdverts",kind:"event",description:"Beacon frames that match the watch, at most four a second of each kind from each beacon (WP-0044)."},{name:"host.bleState",kind:"event",description:"The host's Bluetooth scanner: scanning, idle, off, refused, missing or failed; sent only by a host that has one (WP-0044)."},{name:"host.gpioPins",kind:"event",description:"The GPIO pins the host reads, with their values (WP-0044)."},{name:"host.gpioEdge",kind:"event",description:"A GPIO pin changed (WP-0044)."},{name:"host.mcp",kind:"relay",description:"An MCP message from ctl.dev.{deviceId}, for player-core to answer."},{name:"core.ready",kind:"core",description:"player-core is ready to answer host.mcp; until then the shell answers -32002 itself."},{name:"core.mcpReply",kind:"core",description:"player-core's answer to a host.mcp, for the shell to send back."},{name:"core.sensors",kind:"core",description:"The page's sensor controllers, channels and inputs, and the beacons it hears, whenever they change, for the heartbeat and sensors.recent (WP-0043, WP-0044)."}]};var pn=Symbol.for("wyndlass.app.attach");var _=class extends Error{constructor(n,s){super(`the app could not run (${n})`);c(this,"reason",n);c(this,"error",s)}};function Y(t){try{let e=t instanceof Error?t.name:void 0;return typeof e=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(e)?e:void 0}catch{return}}function ue(t){let e=t?.id;if(typeof e!="string"||e==="")return!0;for(let n=0;n<cn.length;n++)if(e[n]!==cn[n])return!1;return!0}var cn="com.wyndlass.";function Ti(t=typeof navigator>"u"?"":navigator.userAgent){let e=/Chrom(?:e|ium)\/(\d+)/.exec(t);return e?Number(e[1]):void 0}function un(t,e=ce.apiVersion,n=Ti()){return!(t?.playerApi!==void 0&&t.playerApi>e||t?.webView!==void 0&&n!==void 0&&t.webView>n)}function Pi(t){let e;try{e=t.paging?.()}catch{return null}let n=e;return n&&Number.isInteger(n.count)&&n.count>1&&typeof n.ms=="number"&&n.ms>0?{count:n.count,ms:n.ms}:null}var bt=new Map;function Li(){let t=Jt(8),e="";for(let n=0;n<8;n++)e+=Ci[t[n]%26];return e}var Ci="abcdefghijklmnopqrstuvwxyz",Ii=0;function hn(t,e,n){let s=bt.get(t);if(!s){let i=tt.make([e],"text/javascript");s=import(i).then(r=>Ri(r,n),r=>{throw r instanceof _?r:new _("load",Y(r))}).finally(()=>tt.revoke(i)),bt.set(t,s),s.catch(()=>bt.delete(t))}return s}function Ri(t,e){let n=t.default;if(typeof n=="function"&&n.prototype instanceof HTMLElement){let s=n.prototype[pn];if(typeof s!="function")throw new _("shape");let i=class extends n{},r=`${e?.element??"wl-app"}-${Li()}${++Ii}`;try{st.define(r,i)}catch(o){throw new _("shape",Y(o))}return{tag:r,shape:"class",attach:(o,a)=>{Zt(s,o,[a])}}}if(ue(e)&&typeof t.element=="string"&&st.get(t.element))return{tag:t.element,shape:"legacy"};throw new _("shape")}var Ni=3,Oi=6e4,Fe=class{constructor(e,n){c(this,"element",e);c(this,"o",n);c(this,"faults",[]);c(this,"halted",!1)}get stopped(){return this.halted}has(e){try{return!this.halted&&typeof this.element[e]=="function"}catch{return!1}}update(e){this.halted||this.run(()=>this.element.update?.(e))}reset(){this.halted||this.run(()=>this.element.reset?.())}paging(){return this.halted?null:Pi(this.element)}hook(e,n){if(this.halted)return Promise.resolve();let s;try{s=this.element[e]?.(n)}catch(i){return this.fault(i),Promise.resolve()}return Promise.resolve(s).then(()=>{},i=>this.fault(i))}stop(e){if(!this.halted){this.halted=!0;try{this.element.remove()}catch{}this.o.dispose?.(),this.o.onStop(e)}}dispose(){this.o.dispose?.()}run(e){try{e()}catch(n){this.fault(n)}}fault(e){let n=(this.o.now??Date.now)();this.faults=this.faults.filter(s=>n-s<Oi),this.faults.push(n),this.faults.length>=Ni&&this.stop(Y(e))}},Di=24*3600*1e3,He=class t{constructor(e){c(this,"o",e);c(this,"memory",new Map);c(this,"inflight",new Map);c(this,"images",new Map);c(this,"pictures",new Map)}now(){return this.o.now?.()??Date.now()}url(e){let n=this.o.base();if(!n)return;let s=this.o.token(),i=`${n.replace(/\/$/,"")}${e}`;return s?`${i}${i.includes("?")?"&":"?"}${s}`:i}stored(e){return this.memory.get(e)??this.o.store?.getItem(e)??void 0}static keyOf(e,n){let s=Object.keys(n).sort().map(i=>`${encodeURIComponent(i)}=${encodeURIComponent(String(n[i]))}`).join("&");return{query:s,key:`wyndlass:data:${e}?${s}`}}kept(e,n){let s=this.stored(t.keyOf(e,n).key);if(s)try{let i=JSON.parse(s);return this.dress(i,Date.parse(i.expiresAt)<=this.now())}catch{return}}keep(e,n){this.memory.set(e,n);try{this.o.store?.setItem(e,n)}catch{}}get(e,n){let{query:s,key:i}=t.keyOf(e,n),r=this.inflight.get(i);if(r)return r;let o=this.o.fetch??fetch,a=(async()=>{let l=this.stored(i),p=l?JSON.parse(l):void 0;if(p&&Date.parse(p.expiresAt)>this.now())return this.dress(p,!1);let u=this.url(`/v0/${encodeURIComponent(e)}?${s}`);try{if(!u)throw new Error("no data service");let d=await o(u);if(!d.ok)throw new Error(`the data service answered ${d.status}`);let m=await d.text();return this.keep(i,m),this.dress(JSON.parse(m),!1)}catch(d){if(p&&Date.parse(p.expiresAt)+Di>this.now())return this.dress(p,!0);throw d}})().finally(()=>this.inflight.delete(i));return this.inflight.set(i,a),a}dress(e,n){return{...e,offline:n,ageMs:Math.max(0,this.now()-Date.parse(e.fetchedAt))}}image(e){let n=this.images.get(e);return n||(n=this.imageBlob(e).then(s=>URL.createObjectURL(s)),this.images.set(e,n),n.catch(()=>this.images.delete(e))),n}imageBlob(e){let n=this.pictures.get(e);if(!n){let s=this.url(e);n=s?(this.o.fetch??fetch)(s).then(i=>{if(!i.ok)throw new Error(`the image answered ${i.status}`);return i.blob()}):Promise.reject(new Error("no data service")),this.pictures.set(e,n),n.catch(()=>this.pictures.delete(e))}return n}};var mn="wyndlass.frame";function bn(t,e){return!!t&&(t.apps?t.apps(e):!ue(e))}var $i=new Set(["load","shape","unsupported","error","late","overran"]),fn=50,gn=250,wt=class{constructor(e,n,s,i){c(this,"frame",e);c(this,"port",n);c(this,"o",i);c(this,"halted",!1);c(this,"pages");c(this,"hooks");c(this,"pending",new Map);c(this,"next",0);c(this,"told");c(this,"last");c(this,"quiet");this.hooks=new Set(s.hooks),this.pages=s.paging}get stopped(){return this.halted}has(e){return!this.halted&&this.hooks.has(e)}paging(){return this.halted?null:this.pages}update(e){if(this.halted)return;let n=performance.now(),s=this.last;this.last={t:e,at:n};let i=this.told;if(i&&(i.running?Math.abs(e-(i.t+(n-i.at)))<=fn:e===i.t)){i.running&&this.watch();return}let r=!!s&&n-s.at<gn&&e>s.t&&Math.abs(e-s.t-(n-s.at))<=fn;this.told={t:e,at:n,running:r},this.post({type:"clock",t:e,running:r}),r&&this.watch()}reset(){this.halted||this.post({type:"reset"})}snapshots(e){this.halted||this.post({type:"snapshots",snapshots:e})}hook(e,n){if(this.halted)return Promise.resolve();let s=++this.next;return new Promise(i=>{this.pending.set(s,i),this.post({type:"hook",id:s,kind:e,options:n})})}stop(e){this.halted||(this.halted=!0,this.frame.remove(),this.dispose(),this.o.onStop(e))}dispose(){this.o.dispose?.(),clearTimeout(this.quiet),this.port.close();for(let e of this.pending.values())e();this.pending.clear()}heard(e){e.type==="paging"?this.pages=vn(e.paging):e.type==="hooked"&&typeof e.id=="number"?(this.pending.get(e.id)?.(),this.pending.delete(e.id)):e.type==="stopped"&&this.stop(kn(e.error))}post(e){try{this.port.postMessage(e)}catch{}}watch(){clearTimeout(this.quiet),this.quiet=setTimeout(()=>{!this.told?.running||!this.last||this.halted||(this.told={...this.last,running:!1},this.post({type:"clock",t:this.last.t,running:!1}))},gn)}};async function wn(t,e,n,s,i,r,o,a,l,p){let u=t.appInfo??n.info,d;try{d=new URL(l.frames).origin}catch{return p("unsupported")}let m=document.createElement("iframe");m.setAttribute("sandbox","allow-scripts"),m.setAttribute("referrerpolicy","no-referrer"),m.title=u?.id??"app",m.tabIndex=-1,m.dataset.frame=u?.id??"",m.style.cssText="display:block;width:100%;height:100%;border:0;pointer-events:none;background:transparent;color-scheme:normal";let g=new Promise(M=>{m.addEventListener("load",()=>M(!0),{once:!0}),setTimeout(()=>M(!1),r)});m.src=`${d}/`,e.append(m);let k=(M,w)=>(m.remove(),p(M,w));if(!await g||!m.contentWindow)return k("load");let{port1:f,port2:v}=new MessageChannel,b={type:"init",element:{id:t.id,type:"app",app:t.app,props:t.props??{},...t.binding?{binding:t.binding}:{},...t.appInfo?{appInfo:t.appInfo}:{}},bundle:{hash:n.hash,bytes:n.bytes.slice(),...n.info?{info:n.info}:{}},...s.place?{place:s.place}:{},screen:s.screen??null,timeZone:s.timeZone,locale:s.locale,preview:!!s.preview,clock:{t:i.now(),running:!1,startedAt:i.startedAt()},fonts:Hi(t.props??{},l),snapshots:yn(t,s),deadlineMs:r};return new Promise(M=>{let w,P=!1,$=re=>{P||(P=!0,clearTimeout(Z),M(re))},Z=setTimeout(()=>{w?($({app:w,late:!0}),w.update(i.now())):(f.close(),$(k("load")))},r+1e3),B=!1;f.onmessage=re=>{let C=re.data;if(!(!C||typeof C!="object")){if(C.type==="ask"){B&&ji(C,s,f);return}if(w){C.type==="ready"?($({app:w,late:C.late===!0}),w.update(i.now())):w.heard(C);return}if(C.type==="hello"&&!B)B=!0,f.postMessage(b,[b.bundle.bytes.buffer]);else if(C.type==="made"&&Array.isArray(C.hooks)){let oe=xn(t),xe,E=new wt(m,f,{type:"made",hooks:C.hooks.filter(L=>L==="enter"||L==="exit"),paging:vn(C.paging)},{onStop:a,dispose:()=>xe?.()});xe=s.onSnapshots?.(L=>{L.some(U=>oe.has(U))&&E.snapshots(yn(t,s))}),w=E,o(w)}else C.type==="failed"&&(f.close(),$(k($i.has(C.reason)?C.reason:"error",kn(C.error))))}},m.contentWindow.postMessage({type:mn},"*",[v])})}async function ji(t,e,n){if(typeof t.id!="number")return;let s=(i,r=[])=>{try{n.postMessage(i,r)}catch{}};try{if(!e.data)throw new Error("no data service");if(t.what==="data"&&typeof t.source=="string")s({type:"answer",id:t.id,value:await e.data.get(t.source,Fi(t.params))});else if(t.what==="image"&&typeof t.path=="string"){let i=await e.data.imageBlob(t.path),r=new Uint8Array(await i.arrayBuffer());s({type:"answer",id:t.id,value:{bytes:r,type:i.type}},[r.buffer])}else throw new TypeError("not a question")}catch(i){s({type:"answer",id:t.id,error:Y(i)??"Error"})}}function Fi(t){let e={};if(t&&typeof t=="object")for(let[n,s]of Object.entries(t))(typeof s=="string"||typeof s=="number"||typeof s=="boolean")&&(e[n]=s);return e}function vn(t){let e=t;return e&&Number.isInteger(e.count)&&e.count>1&&typeof e.ms=="number"&&e.ms>0?{count:e.count,ms:e.ms}:null}function kn(t){return typeof t=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(t)?t:void 0}function Hi(t,e){let n=new Set;for(let i of Object.values(t)){let r=i?.family;i&&typeof i=="object"&&typeof r=="string"&&n.add(r)}let s=[];for(let i of e.fonts??[]){let r=n.has(i.family)?e.font?.(i.blob):void 0;r&&s.push({family:i.family,weight:i.weight,style:i.style,blob:i.blob,bytes:r.slice()})}return s}function xn(t){let e=new Set;t.binding?.table&&e.add(t.binding.table);for(let n of Object.values(t.props??{}))typeof n=="string"&&/^tbl_[0-9a-z]{26}$/.test(n)&&e.add(n);return e}function yn(t,e){let n={};for(let s of xn(t)){let i=e.snapshot?.(s);i&&(n[s]=i)}return n}function Mn(t){let e=I?.setStyle??((n,s,i,r)=>n.style.setProperty(s,i,r));e(t,"contain","strict","important"),e(t,"overflow","clip","important")}var En=t=>!!(t?.filter?.length||t?.sort||t?.limit),Bi=t=>t==null||t==="";function Ui(t,e){if(!Bi(t))switch(e){case"number":case"currency":{let n=Number(t);return Number.isFinite(n)?n:void 0}case"datetime":{let n=Date.parse(String(t));return Number.isNaN(n)?void 0:n}case"boolean":return t===!0||String(t).toLowerCase()==="true"?1:0;case"date":return String(t).slice(0,10);default:return String(t).toLowerCase()}}function Wi(t,e){let n=Array.from(t),s=Array.from(e);for(let i=0;i<n.length&&i<s.length;i++){let r=n[i].codePointAt(0)-s[i].codePointAt(0);if(r!==0)return r}return n.length-s.length}function _i(t,e,n,s,i){let r=t,o=Array.isArray(r?.rows)?r.rows:[],a=Array.isArray(r?.columns)?r.columns:void 0,l=p=>a?.find(u=>u.key===p)?.type??"text";for(let p of e.filter??[]){if(a&&!a.some(m=>m.key===p.column))return[];let u=p.value;if(u!==null&&typeof u=="object"){let m=u;if(u=Oe(n,s,m.screen,m.key),u===void 0)return[]}let d=l(p.column);o=o.filter(m=>nn(m[p.column],p.op,u,d,i,s))}if(e.sort){let{column:p}=e.sort,u=l(p),d=e.sort.order==="desc"?-1:1;o=o.map((m,g)=>({row:m,i:g,key:Ui(m[p],u)})).sort((m,g)=>{if(m.key===void 0||g.key===void 0)return m.key===void 0&&g.key===void 0?m.i-g.i:m.key===void 0?1:-1;let k=typeof m.key=="number"&&typeof g.key=="number"?m.key-g.key:Wi(String(m.key),String(g.key));return k===0?m.i-g.i:k<0?-d:d}).map(m=>m.row)}return e.limit?o.slice(0,e.limit):o}function An(t,e,n,s,i){return!t||typeof t!="object"?t:{...t,rows:_i(t,e,n,s,i)}}function qi(t){if(!t)return"#000000";if("value"in t)return t.value;let e=t.gradient,n=[...e.stops].sort((s,i)=>s.at-i.at).map(s=>`${s.color.value} ${Math.round(s.at*1e4)/100}%`).join(", ");return e.kind==="radial"?`radial-gradient(circle, ${n})`:`linear-gradient(${e.angle??180}deg, ${n})`}function Tn(t,e,n,s=[]){let i=F("div");if(i.dataset.background="",i.style.cssText="position:absolute;inset:0;pointer-events:none",i.style.background=qi(e),s.length){let r=[`M0 0H${n.width}V${n.height}H0Z`,...s.map(l=>`M${l.x} ${l.y}H${l.x+l.w}V${l.y+l.h}H${l.x}Z`)].join(""),o=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${n.width} ${n.height}" preserveAspectRatio="none"><path fill-rule="evenodd" d="${r}"/></svg>`,a=`url("data:image/svg+xml,${encodeURIComponent(o)}")`;i.dataset.holes=String(s.length);for(let[l,p]of[["maskImage",a],["maskSize","100% 100%"],["maskRepeat","no-repeat"]])i.style[l]=p,i.style[`webkit${l[0].toUpperCase()}${l.slice(1)}`]=p}return t.prepend(i),i}function Pn(t,e=t.frame){let n=F("div");return n.dataset.element=t.id,n.style.cssText="position:absolute;box-sizing:border-box",zi(n,e),n}function zi(t,e){Object.assign(t.style,{left:`${e.x}px`,top:`${e.y}px`,width:`${e.w}px`,height:`${e.h}px`,transform:e.rotation?`rotate(${e.rotation}deg)`:""})}function Ln(t,e,n){if(e.type==="text"){let s=e.style??{};t.textContent=vt(e,he(n)),Object.assign(t.style,{fontFamily:s.font?.family?`"${s.font.family}", sans-serif`:"",fontWeight:String(s.font?.weight??400),fontStyle:s.font?.style??"normal",fontSize:`${s.size??48}px`,color:s.color?.value??"#ffffff",background:s.background?.value??"",whiteSpace:"pre-wrap",textAlign:{start:"left",end:"right"}[s.align??"start"]??s.align??"left",display:"flex",flexDirection:"column",justifyContent:{top:"flex-start",middle:"center",bottom:"flex-end"}[s.verticalAlign??"top"],lineHeight:s.lineHeight?String(s.lineHeight):"",opacity:s.opacity!==void 0?String(s.opacity):"",textDecorationLine:s.decoration?.length?s.decoration.join(" "):"",textTransform:s.transform&&s.transform!=="none"?s.transform:"",letterSpacing:s.letterSpacing?`${s.letterSpacing}em`:"",textShadow:s.shadow?`${s.shadow.x??0}px ${s.shadow.y??2}px ${s.shadow.blur??4}px ${s.shadow.color?.value??"#000000"}`:""})}else e.type==="shape"&&Vi(e)?(t.style.opacity=e.opacity!==void 0?String(e.opacity):"",t.append(Ki(e))):e.type==="shape"?Object.assign(t.style,{background:e.fill?.value??"",opacity:e.opacity!==void 0?String(e.opacity):"",border:e.stroke?.width?`${e.stroke.width}px ${e.stroke.dash??"solid"} ${e.stroke.color?.value??"#000"}`:"",borderRadius:e.shape==="ellipse"?"50%":e.radius?`${e.radius}px`:"",overflow:e.clip!==!1?"hidden":""}):e.type==="library"&&(t.style.overflow="hidden",t.style.background=e.playback?.background?.value??"")}function vt(t,e){return t.bind?dt(t.bind,e):pt(t.text??"",e)}function he(t){return{screen:t?.screen??null,timeZone:t?.timeZone,tables:new Proxy({},{get:(e,n)=>typeof n=="string"?t?.snapshot?.(n):void 0})}}var Vi=t=>t.shape==="line"||t.shape==="arrow"||t.shape==="polygon";function Ki(t){let e=Le("svg");e.setAttribute("width","100%"),e.setAttribute("height","100%"),e.style.cssText="position:absolute;inset:0;overflow:visible";let n=t.frame.w,s=t.frame.h,i=t.stroke?.width??(t.shape==="polygon"?0:4),o=(t.points?.length?t.points:t.shape==="polygon"?[[.5,0],[1,1],[0,1]]:[[0,.5],[1,.5]]).map(([u,d])=>[u*n,d*s]),a=t.stroke?.color?.value??"#000000",l=t.stroke?.dash==="dashed"?`${i*3} ${i*2}`:t.stroke?.dash==="dotted"?`0 ${i*2}`:"",p=Le(t.shape==="polygon"?"polygon":"polyline");if(p.setAttribute("points",o.map(u=>`${u[0]},${u[1]}`).join(" ")),p.setAttribute("fill",t.shape==="polygon"?t.fill?.value??"none":"none"),i&&(p.setAttribute("stroke",a),p.setAttribute("stroke-width",String(i)),p.setAttribute("stroke-linecap",t.stroke?.dash==="dotted"?"round":"butt"),p.setAttribute("stroke-linejoin","round"),l&&p.setAttribute("stroke-dasharray",l)),e.append(p),t.shape==="arrow"&&o.length>=2){let[u,d]=[o[o.length-2],o[o.length-1]],m=Math.atan2(d[1]-u[1],d[0]-u[0]),g=Math.max(10,i*3.5),k=v=>`${d[0]-g*Math.cos(m)+v*g*.5*Math.sin(m)},${d[1]-g*Math.sin(m)-v*g*.5*Math.cos(m)}`;p.setAttribute("points",[...o.slice(0,-1),[d[0]-g*.8*Math.cos(m),d[1]-g*.8*Math.sin(m)]].map(v=>`${v[0]},${v[1]}`).join(" "));let f=Le("polygon");f.setAttribute("points",`${d[0]},${d[1]} ${k(1)} ${k(-1)}`),f.setAttribute("fill",a),e.append(f)}return e}async function Cn(t,e,n,s,i,r,o,a=()=>{},l){let p=t.appInfo??n.info;Mn(e),p?.id&&(e.dataset.app=p.id);let u=(E,L)=>(e.dataset.appFailed=E,{failed:E,...L?{error:L}:{}});if(!un(p?.requires))return u("unsupported");let d=s.appHost;if(d&&!d.custom&&!ue(p))return u("unsupported");if(bn(l,p))return wn(t,e,n,s,i,r,o,a,l,u);let m=t.app;if(d?.held?.(m))return e.dataset.appHeld="",{held:!0};await d?.mounting?.(m,p?.id);let g=!1,k=()=>{g||(g=!0,d?.unmounted?.(m))},f;try{f=await hn(n.hash,n.bytes,p)}catch(E){return k(),E instanceof _?u(E.reason,E.error):u("load")}let v=f.tag,b=p?.id?s.controllerFor?.({id:p.id,instance:t.id,capability:p.player??"read"}):void 0,M,w=new Promise(E=>{M=E}),P,$=new Set,Z={app:p?.id??t.app.id,element:v,props:ct(t.props??{},he(s)),place:s.place,screen:s.screen??null,timeZone:s.timeZone??Intl.DateTimeFormat().resolvedOptions().timeZone,locale:s.locale??navigator.language,preview:!!s.preview,now:i.now,startedAt:i.startedAt,ready:()=>M(),data:(E,L)=>s.data?s.data.get(E,L):Promise.reject(new Error("no data service")),kept:(E,L)=>s.data?.kept?.(E,L),image:E=>s.data?s.data.image(E):Promise.reject(new Error("no data service")),snapshot:E=>{let L=s.snapshot?.(E)??null;if(!L||t.binding?.table!==E||!En(t.binding))return L;let U=An(L,t.binding,s.screen,Z.timeZone,i.now());return P?.from===L&&P.rows.length===U.rows.length&&P.rows.every((ys,bs)=>ys===U.rows[bs])?P.snapshot:(P={from:L,rows:U.rows,snapshot:U},U)},...t.binding?{binding:t.binding}:{},...s.onSnapshots?{onSnapshot:E=>($.add(E),()=>{$.delete(E)})}:{},...t.sensors?.includes("impressions")&&s.impressions?.measuring?{impressions:{now:()=>s.impressions.now(),on:E=>s.impressions.on(E)}}:{},...b?{controller:b}:{}},B;try{B=F(v),f.shape==="class"?f.attach(B,Z):B.wyndlass=Z}catch(E){return b?.dispose(),k(),u("error",Y(E))}B.style.cssText="display:block;width:100%;height:100%",d?.contained?.(e,B);let re=Object.values(t.props??{}).some(E=>typeof E=="string"&&De(E)),C=s.onSnapshots?.(E=>{re&&(Z.props=ct(t.props??{},he(s)));for(let L of E)for(let U of[...$])try{U(L)}catch{}}),oe=new Fe(B,{onStop:a,dispose:()=>{C?.(),$.clear(),b?.dispose(),k()}});e.append(B),o(oe);let xe=await Promise.race([w.then(()=>!1),new Promise(E=>setTimeout(()=>E(!0),r))]);return oe.update(Z.now()),{app:oe,late:xe}}var Sn=new Set;async function In(t,e){for(let n of t){let s=`${n.family}/${n.weight??400}/${n.style??"normal"}/${n.blob}`,i=e(n.blob);if(!(Sn.has(s)||!i||typeof FontFace>"u"))try{let r=new FontFace(n.family,i,{weight:String(n.weight??400),style:n.style??"normal"});document.fonts.add(await r.load()),Sn.add(s)}catch{}}}function me(t){let e=[],n=null;for(let s of t){let i=s.start,r=Math.max(0,i.kind==="at"?i.ms:i.kind==="withPrevious"?(n?.startMs??0)+(i.offsetMs??0):(n?.endMs??0)+(i.offsetMs??0));n={startMs:r,endMs:r+s.durationMs},e.push(n)}return{clips:e,autoDurationMs:e.reduce((s,i)=>Math.max(s,i.endMs),0)}}var Zi=new Set(["x","y","scaleX","scaleY","rotation","opacity","reveal"]);function Ji(t,{pageBelow:e=!1}={},n=null){let s=r=>({path:"page",reason:r});if(!n)return s("no-media-layer");if(e)return s("page-element-beneath");let i=t.slice(0,-1).filter(r=>r.type==="shape"&&r.clip!==!1);if(i.some(r=>r.shape!=="rectangle"||(r.radius??0)>0))return s("clipped-to-shape");if(i.some(r=>(r.rotation??0)%360!==0))return s("clipped-by-rotated-shape");if(!n.animates){if(t.some(r=>(r.rotation??0)%360!==0))return s("rotated");if(t.some(r=>(r.opacity??1)<1))return s("translucent");if(t.some(r=>(r.animated??[]).some(o=>Zi.has(o))))return s("animated")}return{path:"native"}}var Yi={fade:["opacity"],slide:["x","opacity"],scale:["scaleX","scaleY","opacity"],pulse:["scaleX","scaleY"],loop:["scaleX","scaleY"],wipe:["reveal"]};function Rn(t,e,n,s){let i=e&&t.overrides?.[e]||{},r=new Map;for(let d of t.animation?.clips??[]){let m=[...d.preset?Yi[d.preset]??[]:[],...(d.lanes??[]).map(g=>g.property)];r.set(d.element,[...r.get(d.element)??[],...m])}let o=d=>d.type==="library"&&!!d.source&&!!n[d.source.item.id]?.video,a=d=>!o(d)&&!(d.type==="shape"&&!d.fill&&!(d.stroke?.width??0)),l=[],p=(d,m,g,k)=>{for(let f of d){let v=i[f.id];if(v?.hidden??f.hidden??!1)continue;let b=v?.frame??f.frame,M={x:m.x+b.x,y:m.y+b.y,w:b.w,h:b.h},w={type:f.type==="shape"?"shape":"library",rotation:b.rotation??0,opacity:f.opacity??f.style?.opacity??1,animated:r.get(f.id)??[],...f.type==="shape"?{shape:f.shape,radius:f.radius,clip:f.clip}:{}};l.push({e:f,box:M,chain:[...g,w],ancestors:k}),f.type==="shape"&&p(f.children??[],M,[...g,w],[...k,f])}};p(t.elements,{x:0,y:0},[],[]);let u=(d,m)=>d.x<m.x+m.w&&m.x<d.x+d.w&&d.y<m.y+m.h&&m.y<d.y+d.h;return l.flatMap((d,m)=>{if(!o(d.e))return[];let g=l.slice(0,m).some(k=>a(k.e)&&u(k.box,d.box));return[{element:d.e.id,path:Ji(d.chain,{pageBelow:g},s),box:d.box}]})}var Gi=[0,0,1,1];function kt(t,e){if(e<=0)return 0;if(e>=1)return 1;let[n,s,i,r]=t;if(n===s&&i===r)return e;let o=3*n,a=3*(i-n)-o,l=1-o-a,p=3*s,u=3*(r-s)-p,d=1-p-u,m=w=>((l*w+a)*w+o)*w,g=w=>((d*w+u)*w+p)*w,k=w=>(3*l*w+2*a)*w+o,f=1e-7,v=e;for(let w=0;w<8;w++){let P=m(v)-e;if(Math.abs(P)<f)return g(v);let $=k(v);if(Math.abs($)<1e-6)break;v-=P/$}let b=0,M=1;for(v=e;b<M;){let w=m(v);if(Math.abs(w-e)<f||(e>w?b=v:M=v,v=(M-b)/2+b,M-b<f))break}return g(v)}function Be(t,e){let n=t.keyframes;if(e<=n[0].t)return n[0].v;let s=n[n.length-1];if(e>=s.t)return s.v;let i=0;for(;e>=n[i+1].t;)i++;let r=n[i],o=n[i+1];return r.v+(o.v-r.v)*kt(r.easing??Gi,(e-r.t)/(o.t-r.t))}function Nn(t,e,n){let s={x:t.x,y:t.y,scaleX:1,scaleY:1,rotation:0,opacity:1};for(let i of e??[])s[i.property]=Be(i,n);return s}var fe={linear:[0,0,1,1],ease:[.25,.1,.25,1],"ease-in":[.42,0,1,1],"ease-out":[0,0,.58,1],"ease-in-out":[.42,0,.58,1]};function On(t){if(!t)return fe.ease;if(fe[t])return fe[t];let n=/^cubic-bezier\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\)$/.exec(t)?.slice(1).map(Number);return n&&n.every(Number.isFinite)?n:fe.ease}function Xi(t){let e=typeof t=="string"?/^#([0-9a-fA-F]{6})([0-9a-fA-F]{2})?$/.exec(t):null;if(!e)return null;let n=parseInt(e[1],16);return[n>>16&255,n>>8&255,n&255,e[2]?parseInt(e[2],16)/255:1]}var jn={fade:()=>({opacity:0}),slide:t=>({x:t.x-t.w*.1,opacity:0}),scale:()=>({scaleX:.8,scaleY:.8,opacity:0}),wipe:()=>({reveal:0}),typewriter:()=>({chars:0}),"count-up":()=>({count:0})},sl=Object.keys(jn);var Qi={x:t=>t.x,y:t=>t.y,scaleX:()=>1,scaleY:()=>1,rotation:()=>0,opacity:()=>1,reveal:()=>1,chars:()=>1,count:()=>1},Dn=1e3,er=fe["ease-in-out"];function Fn(t,e){let n=me(t).clips,s=new Map,i=new Set,r=a=>{let l=s.get(a);return l||s.set(a,l={keys:new Map,colour:null,loops:[],tickers:[]}),l},o=(a,l,p)=>{let u=r(a).keys,d=u.get(l)??[];u.set(l,d),d.push(p)};t.forEach((a,l)=>{let p=e.get(a.element);if(!p)return;let{startMs:u,endMs:d}=n[l],m=On(a.easing);if(a.lanes?.length){for(let f of a.lanes)for(let v of f.keyframes){let b={t:u+v.at,easing:On(v.easing??a.easing)};if(f.property==="color"){let M=Xi(v.value);if(!M)continue;let w=r(a.element);w.colour??(w.colour=[[],[],[],[]]),M.forEach((P,$)=>w.colour[$].push({...b,v:P}))}else o(a.element,f.property,{...b,v:Number(v.value)})}return}let g=a.preset??"fade";if(a.kind==="emphasis"){g==="pulse"?(o(a.element,"pulse",{t:u,v:1,easing:m}),o(a.element,"pulse",{t:(u+d)/2,v:1.05,easing:m}),o(a.element,"pulse",{t:d,v:1})):g==="loop"?r(a.element).loops.push({startMs:u,endMs:d}):g==="ticker"?r(a.element).tickers.push({startMs:u,endMs:d}):i.add(g);return}let k=jn[g];if(!k){i.add(g);return}for(let[f,v]of Object.entries(k(p))){let b=Qi[f](p),[M,w]=a.kind==="enter"?[v,b]:[b,v];o(a.element,f,{t:u,v:M,easing:m}),o(a.element,f,{t:d,v:w})}});for(let a of s.values()){for(let l of a.keys.values())l.sort((p,u)=>p.t-u.t);for(let l of a.colour??[])l.sort((p,u)=>p.t-u.t)}return{motions:s,unplayed:[...i].sort()}}var tr=["x","y","scaleX","scaleY","rotation","opacity"];function Hn(t,e,n,s=!1){if(s)return nr(t,e,n);let i=(l,p)=>{let u=t?.keys.get(l);return u?Be({property:"x",keyframes:u},n):p},r=Nn(e,tr.flatMap(l=>t?.keys.get(l)?[{property:l,keyframes:t.keys.get(l)}]:[]),n),o=i("pulse",1);for(let l of t?.loops??[])if(n>=l.startMs&&n<l.endMs){let p=(n-l.startMs)%Dn/Dn;o*=1+.05*kt(er,p<.5?p*2:2-p*2)}let a=t?.tickers.find(l=>n>=l.startMs&&n<l.endMs);return{...r,reveal:i("reveal",1),chars:i("chars",1),count:i("count",1),pulse:o,scroll:a?(n-a.startMs)/(a.endMs-a.startMs):null,color:t?.colour?t.colour.map(l=>Be({property:"x",keyframes:l},n)):null}}function $n(t,e){if(e<t[0].t)return t[0].v;let n=0;for(;n+1<t.length&&t[n+1].t<=e;)n++;return n+1<t.length?t[n+1].v:t[n].v}function nr(t,e,n){let s=(i,r)=>{let o=t?.keys.get(i);return o?$n(o,n):r};return{x:s("x",e.x),y:s("y",e.y),scaleX:s("scaleX",1),scaleY:s("scaleY",1),rotation:s("rotation",0),opacity:s("opacity",1),reveal:s("reveal",1),chars:s("chars",1),count:s("count",1),pulse:1,scroll:null,color:t?.colour?t.colour.map(i=>$n(i,n)):null}}function sr(t,e){let n=Array.from(t);return e>=1?t:n.slice(0,Math.max(0,Math.round(e*n.length))).join("")}function ir(t,e){return e>=1?t:t.replace(/\d+(?:\.\d+)?/g,n=>(Number(n)*Math.max(0,e)).toFixed((n.split(".")[1]??"").length))}function Bn(t,e,n){if(t<=1||e<=0)return[{page:0,startMs:0,endMs:n}];let s=[];for(let i=0;i*e<n&&i<1e3;i++)s.push({page:i%t,startMs:i*e,endMs:Math.min((i+1)*e,n)});return s}function Un(t,e,n,s){t.style.left=`${n.x}px`,t.style.top=`${n.y}px`,t.style.transform=`rotate(${(e.frame.rotation??0)+n.rotation}deg) scale(${n.scaleX*n.pulse}, ${n.scaleY*n.pulse})`,t.style.opacity=String((e.opacity??e.style?.opacity??1)*n.opacity),t.style.clipPath=n.reveal>=1?"":`inset(0 ${(1-Math.max(0,n.reveal))*100}% 0 0)`;let i=n.color?`rgba(${n.color.slice(0,3).map(r=>Math.round(r)).join(",")},${n.color[3]})`:null;if(e.type==="text"&&s!==void 0){let r=ir(sr(s,n.chars),n.count);if(n.scroll!==null){let o=t.querySelector("[data-ticker]");o||(o=document.createElement("span"),o.dataset.ticker="",o.style.cssText="display:inline-block;white-space:nowrap;will-change:transform",t.replaceChildren(o),t.style.overflow="hidden"),o.textContent!==r&&(o.textContent=r);let a=e.frame.w,l=o.scrollWidth;o.style.transform=`translateX(${a-n.scroll*(a+l)}px)`}else(t.textContent!==r||t.querySelector("[data-ticker]"))&&(t.textContent=r,t.style.overflow="");i&&(t.style.color=i)}else if(e.type==="shape"&&i){let r=t.querySelector("polygon, polyline");r&&e.shape==="polygon"?r.setAttribute("fill",i):r||(t.style.background=i)}}function rr(t){let e=t>>>0;return()=>{e=e+1831565813|0;let n=Math.imul(e^e>>>15,1|e);return n=n+Math.imul(n^n>>>7,61|n)^n,((n^n>>>14)>>>0)/4294967296}}async function Wn(t,e,n,s){let i=parseInt((await lt(Ne(`${t}
3
3
  ${e}
4
- ${n}`))).slice(0,8),16),o=Wr(r),i=Array.from({length:s},(a,l)=>l);for(let a=s-1;a>0;a--){let l=Math.floor(o()*(a+1));[i[a],i[l]]=[i[l],i[a]]}return i}var zr=250,Vr=1e3;function Gt(t,e){let n=t.animation?.duration;if(n?.kind==="fixed")return{durationMs:n.ms};if(n?.kind==="untilPlaylistEnds"){let s=jn(t.elements,n.element);return{durationMs:(s?.source?.kind==="playlist"?e.playlist(s.source.item)??[]:s?.source?[{item:s.source.item}]:[]).reduce((i,a)=>i+(e.slide(a,{imageDurationMs:s?.playback?.imageDurationMs})?.durationMs??0),0)||1e4,untilPass:n.element}}return{durationMs:ue(t.animation?.clips??[]).autoDurationMs}}function Dn(t,e,n=0){let s={},r=o=>{for(let i of o){if(i.type==="library"&&i.source){let a=i.source.kind==="playlist"?e.playlist(i.source.item)??[]:[{item:i.source.item}];s[i.source.item.id]={video:a.some(l=>{let p=e.slide(l);if(!p)return!1;if(p.blob.contentType.startsWith("video/"))return!0;let c=p.layout;return!!c&&n<4&&Object.values(Dn(c.doc,c.source,n+1)).some(d=>d.video)})}}i.children&&r(i.children)}};return r(t.elements),s}function jn(t,e){for(let n of t){if(n.id===e)return n;let s=n.children&&jn(n.children,e);if(s)return s}}var Q=class{constructor(e,n,s,r={}){h(this,"source",n);h(this,"o",r);h(this,"el");h(this,"ready");h(this,"unplayed");h(this,"doc");h(this,"motions");h(this,"native");h(this,"animated",[]);h(this,"loops",[]);h(this,"startedAt",0);h(this,"frame",0);h(this,"running",!1);h(this,"disposed",!1);h(this,"apps",[]);h(this,"heldAt");h(this,"late",[]);h(this,"overran",[]);h(this,"timers",[]);h(this,"bound",[]);h(this,"unheard");h(this,"reduced",typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches);let o=s.clientWidth||window.innerWidth,i=s.clientHeight||window.innerHeight,a=!e.profiles[0].width,l=a?{...e.profiles[0],width:o,height:i}:e.profiles[0];a&&(e={...e,elements:e.elements.map(v=>v.frame.w?v:{...v,frame:{x:0,y:0,w:o,h:i}})});let p=Math.min(o/l.width,i/l.height);this.el=H("div"),this.el.dataset.layout=l.id,this.el.style.cssText=`position:absolute;left:${(o-l.width*p)/2}px;top:${(i-l.height*p)/2}px;width:${l.width}px;height:${l.height}px;transform:scale(${p});transform-origin:0 0;overflow:hidden`,s.append(this.el),this.doc=e;let c=new Map,d=v=>{for(let A of v)c.set(A.id,A.frame),A.children&&d(A.children)};d(e.elements);let m=In(e.animation?.clips??[],c);this.motions=m.motions;let y=new Set(m.unplayed.map(v=>`preset ${v}`)),w=[this.loadFonts()],f=r.media?An(e,void 0,Dn(e,n),r.media.capability):[];this.native=new Set(f.filter(v=>v.path.path==="native").map(v=>v.element));let b=(v,A)=>{for(let k of v){if(k.hidden)continue;let I=this.element(k,y,w);A.append(I),k.children?.length&&k.type==="shape"&&b(k.children,I)}};b(e.elements,this.el),e.background&&wn(this.el,e.background,l,f.filter(v=>this.native.has(v.element)).map(v=>v.box)),this.unplayed=[...y].sort(),this.ready=Promise.all(w).then(()=>{}),this.bound.length&&(this.unheard=n.onSnapshots?.(()=>this.refill()))}refill(){let e=ce(this.source),n=(this.heldAt??Date.now())-this.startedAt;for(let{el:s,e:r}of this.bound){let o=ht(r,e),i=this.animated.find(a=>a.el===s);i?(i.text=o,this.running||this.place(i,n)):s.textContent!==o&&(s.textContent=o)}}path(e){return this.o.path?`${this.o.path}/${e}`:e}element(e,n,s){let r=vn(e);kn(r,e,this.source),e.type==="text"&&(e.bind||Ce(e.text??""))&&this.bound.push({el:r,e});let o=this.motions.get(e.id);if(o){let i={el:r,e,motion:o,text:e.type==="text"?r.textContent??"":void 0};this.animated.push(i),this.place(i,0)}if(e.type==="library"&&e.source){let i=e.source.kind==="playlist"?this.source.playlist(e.source.item)??[]:[{item:e.source.item}],a=new ft(r,i,e.playback??{},this.source,this.path(e.id),{...this.o,media:this.native.has(e.id)?this.o.media:void 0},e.source.kind==="playlist"?e.source.item:void 0);this.loops.push(a),s.push(a.ready);for(let l of a.unplayed)n.add(l)}else if(e.type==="app"){let i=e.app?this.source.app?.(e.app):null;i?s.push(this.mountApp(e,r,i)):n.add(`app ${e.app?.id??e.id}`)}return r}place(e,n){Nn(e.el,e.e,Cn(e.motion,e.e.frame,n,this.reduced),e.text);let s=e.e.type==="text"?e.el.firstElementChild:null;s&&Ge(s)}loadFonts(){return Mn(this.doc.fonts??[],e=>this.source.font(e))}async mountApp(e,n,s){let r=this.path(e.id),o=e.app,i=(e.appInfo??s.info)?.id,a={now:()=>this.heldAt??Date.now(),startedAt:()=>this.startedAt||Date.now()},l=(d,m)=>this.o.onApp?.({type:"app.failed",element:r,item:o,...i?{app:i}:{},reason:d,...m?{error:m}:{}}),p=this.o.isolate?{...this.o.isolate,fonts:this.doc.fonts,font:d=>this.source.font(d)}:void 0,c=await xn(e,n,s,this.source,a,this.o.appDeadlineMs??5e3,d=>{this.disposed?d.dispose():this.apps.push({app:d,box:n,path:r,id:e.id,item:o})},d=>l("error",d),p);if(!("held"in c)){if("failed"in c){l(c.failed,c.error);return}c.late&&(this.late.push(r),this.o.onAppLate?.(r,o.id),l("late"))}}async start(e=Date.now()){this.startedAt=e,this.heldAt=void 0,this.running=!0,this.hooks(e);let n=()=>{if(!this.running)return;let s=Date.now(),r=s-this.startedAt;for(let o of this.animated)this.place(o,r);for(let o of this.apps)o.app.update(s);this.frame=requestAnimationFrame(n)};(this.animated.length||this.apps.length)&&(this.frame=requestAnimationFrame(n)),await Promise.all(this.loops.map(s=>s.start()))}hooks(e){let n=this.doc.animation?.clips??[],s=ue(n).clips,r=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches;for(let o of this.apps){let a=n.map((f,b)=>({c:f,t:s[b]})).filter(f=>f.c.element===o.id&&(f.c.kind==="enter"||f.c.kind==="exit")).filter(f=>o.app.has(f.c.kind));if(!a.length)continue;let l=o.box,p=this.animated.findIndex(f=>f.el===l);p>=0&&(this.animated.splice(p,1),Object.assign(l.style,{opacity:"",transform:"",clipPath:""}));let c=(f,b,v)=>this.hook(o,f.kind,{startAt:b,preset:f.preset??"fade",durationMs:f.durationMs,easing:f.easing,delayMs:0,...f.staggerMs?{staggerMs:f.staggerMs}:{},...v!==void 0?{page:v}:{},reducedMotion:r},l);for(let{c:f,t:b}of a)c(f,e+b.startMs);let d=o.app.paging();if(!d)continue;let m=a.find(f=>f.c.kind==="enter")?.c,y=a.find(f=>f.c.kind==="exit")?.c,w=Rn(d.count,d.ms,Gt(this.doc,this.source).durationMs);for(let f=1;f<w.length;f++){let b=e+w[f].startMs;y&&c(y,b-y.durationMs,w[f-1].page),m&&c(m,b,w[f].page)}}}hook(e,n,s,r){let o=!1;e.app.hook(n,s).finally(()=>{o=!0});let i=s.startAt+s.durationMs;this.timers.push(setTimeout(()=>{o||!this.running||(this.overran.includes(e.path)||(this.overran.push(e.path),this.o.onAppOverran?.(e.path,e.item.id),this.o.onApp?.({type:"app.failed",element:e.path,item:e.item,reason:"overran"})),n==="exit"&&(r.style.visibility="hidden"))},Math.max(0,i+zr-Date.now())))}pause(){this.heldAt=Date.now();for(let e of this.loops)e.pause();for(let e of this.apps)e.app.update(this.heldAt)}seek(e){this.running=!1,cancelAnimationFrame(this.frame);for(let n of this.loops)n.pause();for(let n of this.animated)this.place(n,e);this.heldAt=this.startedAt+e;for(let n of this.apps)n.app.update(this.heldAt)}resume(){this.heldAt=void 0;for(let e of this.loops)e.resume()}paging(e){return this.apps.find(n=>n.id===e)?.app.paging()??null}dispose(){this.running=!1,this.disposed=!0,cancelAnimationFrame(this.frame);for(let e of this.timers)clearTimeout(e);for(let e of this.loops)e.stop();for(let e of this.apps)e.app.dispose();this.unheard?.(),this.el.remove()}},$n=t=>Math.min(Math.max(0,t),2**31-1),ft=class{constructor(e,n,s,r,o,i,a){h(this,"region",e);h(this,"playback",s);h(this,"source",r);h(this,"path",o);h(this,"o",i);h(this,"list",a);h(this,"ready");h(this,"unplayed",[]);h(this,"renderer");h(this,"slides");h(this,"order",[]);h(this,"pass",0);h(this,"at",0);h(this,"timer");h(this,"current");h(this,"shownAt",0);h(this,"remaining");h(this,"stopped",!1);h(this,"ended",!1);h(this,"empty",!1);h(this,"open");h(this,"pages");this.renderer=new Ne(e,{media:i.media,fit:s.fit,path:o,onItem:i.onItem,onPassEnd:i.onPassEnd,onApp:i.onApp}),s.transition==="slide"&&this.unplayed.push("transition slide");let l=s.transition==="fade"?{type:"crossfade"}:void 0,p=n.map(c=>r.slide(c,{imageDurationMs:s.imageDurationMs,transition:l,region:!0})).filter(c=>!!c);this.slides=p.length===1&&p[0].untilEnd&&(s.onEnd??"loop")==="loop"?[{...p[0],untilEnd:!1,loop:!0}]:p,this.renderer.onMediaEnd(c=>{c===this.current&&!this.stopped&&(clearTimeout(this.timer),this.next("completed"))}),this.ready=this.newPass().then(()=>this.slides.length?this.renderer.prepare(this.slides[this.order[0]]):void 0).catch(()=>{})}async newPass(){let e=this.slides.length;this.order=this.playback.order==="shuffle"?await On(this.source.deviceId,this.path,this.pass,e):[...Array(e).keys()],this.at=0}async start(){this.slides.length&&await this.first()}bounds(e){return[this.source.bounds?.(e.item),this.list&&this.source.bounds?.(this.list)]}seek(e){let n=Date.now(),s=e;for(;s<this.order.length&&!this.bounds(this.slides[this.order[s]]).every(r=>Jt(r,n));)s++;return s}async first(){if(this.at=this.seek(0),this.at<this.order.length){this.empty=!1,await this.show();return}this.empty=!0,this.current=void 0,this.renderer.standby();let e=Date.now(),n=this.slides.flatMap(s=>this.bounds(s).map(r=>r?.from??0)).filter(s=>s>e);clearTimeout(this.timer),n.length&&(this.timer=setTimeout(()=>{!this.stopped&&!this.ended&&this.first()},$n(Math.min(...n)-e)))}async show(){let e=this.slides[this.order[this.at]];this.current=e;try{await this.renderer.show(e)}catch(s){if(this.stopped)return;this.o.onItem?.({type:"item.error",element:this.path,item:e.item,blob:e.blob.hash,...lt(s)}),this.o.onItem?.({type:"item.end",element:this.path,item:e.item,blob:e.blob.hash,endedAt:Date.now(),reason:"error"}),this.schedule(Vr);return}if(this.stopped)return;if(this.shownAt=Date.now(),this.open=e,this.o.onItem?.({type:"item.start",element:this.path,item:e.item,blob:e.blob.hash,contentType:e.blob.contentType,startedAt:this.shownAt,durationMs:e.durationMs}),e.pages&&(this.pages=new le(this.renderer,e,this.shownAt,!1)),!(this.slides.length===1&&e.loop))this.schedule(e.durationMs+(e.untilEnd?5e3:0));else{let s=this.bounds(e).flatMap(r=>r?.until??[]);s.length&&this.schedule(Math.min(...s)-this.shownAt)}let n=this.peek();n&&n!==e&&this.renderer.prepare(n).catch(()=>{})}peek(){let e=this.seek(this.at+1);if(e<this.order.length)return this.slides[this.order[e]];if(this.o.endsWith!==this.path)return this.playback.onEnd==="hold"||this.playback.onEnd==="hide"||this.playback.order==="shuffle"?void 0:this.slides[this.order[0]]}schedule(e){clearTimeout(this.timer),this.timer=setTimeout(()=>{this.next("completed")},$n(e))}async next(e){if(this.stopped||this.ended||!this.current)return;let n=()=>this.endOpen(e),s=this.seek(this.at+1);if(s<this.order.length){this.at=s,n(),await this.show();return}let o=this.o.onPassEnd?.(this.path)==="hold"?"hold":this.playback.onEnd??"loop";if(o==="hold"){this.ended=!0;return}if(o==="hide"){this.ended=!0,n(),this.renderer.standby(),this.region.style.visibility="hidden";return}this.pass++,await this.newPass(),n(),await this.first()}pause(){clearTimeout(this.timer),this.current&&this.remaining===void 0&&(this.remaining=Math.max(0,this.current.durationMs-(Date.now()-this.shownAt))),this.pages?.pause(),this.renderer.pause()}resume(){if(this.empty&&!this.ended&&!this.stopped){this.first();return}this.remaining===void 0||this.ended||(this.renderer.resume(),this.pages?.resume(),this.shownAt=Date.now()-(this.current.durationMs-this.remaining),this.schedule(this.remaining),this.remaining=void 0)}endOpen(e){this.pages?.stop(),this.pages=void 0;let n=this.open;n&&(this.open=void 0,this.o.onItem?.({type:"item.end",element:this.path,item:n.item,blob:n.blob.hash,endedAt:Date.now(),reason:e}))}stop(){this.endOpen("stopped"),this.stopped=!0,clearTimeout(this.timer),this.renderer.standby();for(let e of this.slides)this.renderer.release(e)}};var gt=t=>t!=null&&t!==""&&!(Array.isArray(t)&&t.length===0);function Fn(t,e,n,s=[]){let r=t[n];if(!r)return!1;if(!r.when)return!0;if(s.includes(n))return!1;let o=i=>String(i);for(let[i,a]of Object.entries(r.when)){if(!t[i]||i===n)return!1;let p=Fn(t,e,i,[...s,n])?e[i]!==void 0?e[i]:t[i].default:void 0,c=Array.isArray(p)?p.map(o):gt(p)?[o(p)]:[];if(a.set!==void 0&&a.set!==gt(p)||a.anyOf&&!(gt(p)&&!Array.isArray(p)?a.anyOf.map(o).includes(o(p)):c.some(d=>a.anyOf.map(o).includes(d)))||a.allOf&&!a.allOf.map(o).every(d=>c.includes(d))||a.noneOf&&c.some(d=>a.noneOf.map(o).includes(d)))return!1}return!0}function Hn(t,e){return Object.keys(t).filter(n=>Fn(t,e,n))}var el=de.apiVersion,Bn=new Map(de.commands.map(t=>[t.name,t]));var J=class extends Error{constructor(n,s){super(s);h(this,"code",n)}};function Un(t,e){let n=e.capability??"read",s={kind:"app",app:e.id,instance:e.instance},r=new Set,o=!1,i=async(a,l={})=>{if(o)throw new J("NOT_ALLOWED","This app has been removed from the screen.");let p=Bn.get(a);if(!p)throw new J("UNKNOWN",`There is no command ${a}.`);if(p.apps==="none")throw new J("NOT_ALLOWED",`Apps cannot call ${a}.`);if(p.apps==="control"&&n!=="control")throw new J("NOT_ALLOWED",`${a} needs capabilities.player: control in ${e.id}'s definition.`);let c=await t.call(a,l,s);if(c.ok)return c.result;if(c.code==="PREVIEW")return{applied:!1,reason:"preview"};throw new J(c.code,c.message)};return{app:e.id,instance:e.instance,capability:n,status:()=>t.status(),get:a=>t.status()[a],on(a,l){if(o)return()=>{};let p=t.on(a,l),c=()=>{p(),r.delete(c)};return r.add(c),c},time:()=>i("time.now"),call:i,play:()=>i("player.play"),pause:()=>i("player.pause"),stop:()=>i("player.stop"),next:()=>i("player.next"),previous:()=>i("player.previous"),finish:()=>i("app.finish"),dispose(){o=!0;for(let a of[...r])a()}}}var yt={"Intl.DateTimeFormat":"date formatters (Intl.DateTimeFormat)","Intl.NumberFormat":"number formatters (Intl.NumberFormat)","Intl.Collator":"collators (Intl.Collator)","Intl.PluralRules":"plural rules (Intl.PluralRules)","Intl.RelativeTimeFormat":"relative time formatters (Intl.RelativeTimeFormat)","Intl.ListFormat":"list formatters (Intl.ListFormat)","Intl.DisplayNames":"display names (Intl.DisplayNames)","Intl.Segmenter":"segmenters (Intl.Segmenter)",toLocale:"formatters, through toLocaleString, toLocaleDateString or toLocaleTimeString with options",canvas:"canvases",context:"canvas contexts",bitmap:"image bitmaps (createImageBitmap)",objectUrl:"object URLs (URL.createObjectURL)",worker:"workers",listener:"listeners on window or document"};function _n(t){let e=0,n=s=>{for(let r=s.firstChild;r;r=r.nextSibling){if(r.nodeType===1){e++;let o=r.shadowRoot;o&&n(o)}n(r)}};return n(t),e}function qn(t,e){let n={},s=c=>{n[c]=(n[c]??0)+1},r=(c,d)=>new Proxy(c,{construct:(m,y,w)=>(s(d),Reflect.construct(m,y,w)),apply:(m,y,w)=>(s(d),Reflect.apply(m,y,w))}),o=t.Intl;for(let c of["DateTimeFormat","NumberFormat","Collator","PluralRules","RelativeTimeFormat","ListFormat","DisplayNames","Segmenter"]){let d=o[c];d&&(o[c]=r(d,`Intl.${c}`))}let i=(c,d,m)=>{let y=c&&c[d];typeof y=="function"&&(c[d]=function(...w){let f=Reflect.apply(y,this,w),b=m(w,this,f);return b&&s(b),f})},a=c=>c[1]!==void 0?"toLocale":null;for(let c of["toLocaleString","toLocaleDateString","toLocaleTimeString"])i(t.Date?.prototype,c,a);i(t.Number?.prototype,"toLocaleString",a),i(t.Document?.prototype,"createElement",c=>String(c[0]).toLowerCase()==="canvas"?"canvas":null),t.OffscreenCanvas&&(t.OffscreenCanvas=r(t.OffscreenCanvas,"canvas"));let l=new WeakSet,p=(c,d,m)=>!m||typeof m!="object"||l.has(m)?null:(l.add(m),"context");return i(t.HTMLCanvasElement?.prototype,"getContext",p),i(t.OffscreenCanvas?.prototype,"getContext",p),i(t,"createImageBitmap",()=>"bitmap"),i(t.URL,"createObjectURL",()=>"objectUrl"),t.Worker&&(t.Worker=r(t.Worker,"worker")),i(t.EventTarget?.prototype,"addEventListener",(c,d)=>d===void 0||d===t||d===t.document?"listener":null),()=>({kinds:{...n},nodes:e()})}var Wn=["none","fade","scale","slide-up","slide-left"],je=[["1920 \xD7 1080",1920,1080],["1080 \xD7 1920",1080,1920],["3840 \xD7 2160",3840,2160]],Kr=[.25,.5,1,2,4],fe=3e4,Jn=5e3,Zr={id:"med_preview",version:1},u={width:1920,height:1080,props:{},touched:new Set,playing:!0,speed:1,t:0,enter:"none",exit:"none",clipMs:800,timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,locale:navigator.language||"en-US",screen:{name:"Preview screen",lat:49.9,lon:-97.14,fields:"{}"},samples:{},tables:new Map,people:[]},E={frames:"",tables:{},controller:{status:{},events:{}}},vt,Jr={"connection.changed":{type:"connection.changed",seq:0,at:"2026-10-01T14:02:00Z",connection:"offline"},"audio.changed":{type:"audio.changed",seq:0,at:"2026-10-01T14:03:00Z",audio:{volume:.3,muted:!0},by:{kind:"player"}}},z={people:new Set,player:new Map},be=[],ge=new Map,kt=new Map,xt=new Set,Fe=0,T=null,Mt=null,At=null,Yn=-1,W=null,me=0,ee={wall:0,t:0},He=0,Be=[],O=t=>document.getElementById(t),St=O("stage"),Yr=O("controls"),zn=O("report"),bt=O("made"),Xr=qn(window,()=>_n(St)),Et={kinds:{},nodes:0};addEventListener("message",t=>{let e=t.data;E.frames&&t.origin==="null"&&e?.wyndlassPreview==="made"&&e.made&&typeof e.made=="object"&&(Et=e.made)});var Xn=500,Vn=3,j={last:null,reads:[],said:""};function g(t,e={},...n){let s=document.createElement(t);for(let[r,o]of Object.entries(e))o==null||o===!1||(r.startsWith("on")&&typeof o=="function"?s.addEventListener(r.slice(2),o):r==="value"||r in s&&typeof o!="string"?s[r]=o:s.setAttribute(r,o===!0?"":String(o)));for(let r of n)r!=null&&s.append(r);return s}var Gr=0;function S(t,e,n=!1){return e.id||(e.id=`c${++Gr}`),n?g("div",{class:"field inline"},e,g("label",{for:e.id},t)):g("div",{class:"field"},g("label",{for:e.id},t),e)}function q(t,e,n){let s=g("select",{onchange:()=>n(s.value)},...t.map(r=>{let[o,i]=Array.isArray(r)?r:[r,r];return g("option",{value:o,selected:o===e},i)}));return s}async function Kn(){let[t,e,n,s]=await Promise.all([fetch("/app.json").then(i=>i.json()),fetch("/app.js"),fetch("/samples.json").then(i=>i.json()),fetch("/config.json").then(i=>i.json())]);E=s,E.controller.status=vt??(vt=E.controller.status),E.controller.events={...E.controller.events,...Jr};for(let[i,a]of Object.entries(E.tables))u.tables.has(Ue(i))||Tt(i,a);T=t,Yn=Number(e.headers.get("x-preview-version")??-1),At=e.ok?null:await e.text(),Mt=e.ok?new Uint8Array(await e.arrayBuffer()):null;let r=T.params??{},o={};for(let[i,a]of Object.entries(r))o[i]=u.touched.has(i)?u.props[i]:a.default;u.props=o;for(let[i,a]of Object.entries(n))i in u.samples||(u.samples[i]=a);Pt(),document.title=`${T.name}: Wyndlass app preview`,O("title").textContent=T.name,O("subtitle").textContent=`${T.id} ${T.version}`}var Ue=t=>`tbl_${(t.replace(/\.(json|csv)$/i,"").toLowerCase().replace(/[^a-z0-9]+/g,"")||"table").slice(0,26).padEnd(26,"0")}`;function Qr(t){let e=[],n=[],s="",r=!1;for(let o=0;o<t.length;o++){let i=t[o];if(r){i==='"'&&t[o+1]==='"'?(s+='"',o++):i==='"'?r=!1:s+=i;continue}i==='"'?r=!0:i===","?(n.push(s),s=""):i===`
5
- `||i==="\r"?(i==="\r"&&t[o+1]===`
6
- `&&o++,n.push(s),e.push(n),n=[],s=""):s+=i}return(s||n.length)&&(n.push(s),e.push(n)),e.filter(o=>o.some(i=>i!==""))}function ei(t,e){let n="";for(let r of t.normalize("NFD").replace(/\p{Mn}/gu,""))/[A-Za-z0-9]/.test(r)?n+=r.toLowerCase():n&&!n.endsWith("_")&&(n+="_");n=n.replace(/^_+|_+$/g,""),/^[a-z]/.test(n)||(n=`c_${n}`),n=n.length>60?n.slice(0,60).replace(/_+$/,""):n;let s=n;for(let r=2;[...e].some(o=>o.toLowerCase()===s);r++)s=`${n}_${r}`;return e.add(s),s}function Gn(t,e){let n=Ue(t),s=(o,i)=>({table:n,version:1,rows:i,columns:o.map(({key:a,label:l})=>({key:a,label:l,type:i.length&&i.every(p=>p[a]===""||p[a]===void 0||Number.isFinite(Number(p[a])))?"number":"text"}))});if(/\.csv$/i.test(t)){let[o=[],...i]=Qr(e),a=new Set,l=o.map(d=>({label:d.trim(),key:ei(d.trim()||"column",a)})),p=i.map(d=>Object.fromEntries(l.map((m,y)=>[m.key,d[y]??""]))),c=s(l,p);for(let d of c.columns)if(d.type==="number")for(let m of p)m[d.key]!==""&&(m[d.key]=Number(m[d.key]));return c}let r=JSON.parse(e);if(r&&typeof r=="object"&&"columns"in r&&"rows"in r)return{...r,table:n};if(Array.isArray(r))return s([...new Set(r.flatMap(o=>Object.keys(o)))].map(o=>({key:o,label:o})),r);throw new Error(`${t} is not a table: a snapshot, an array of rows, or CSV`)}function Tt(t,e){kt.set(t,e);try{u.tables.set(Ue(t),Re(Gn(t,e))),ge.delete(t)}catch(n){ge.set(t,String(n.message))}}function Qn(t,e,n){let s=u.tables.get(t);if(!s)return;u.tables.set(t,Re({...s,version:s.version+1,rows:e,...n?{columns:n}:{}}));for(let i of[...xt])i([t]);let r=document.querySelector(`[data-testid="table"][data-table="${t}"]`);r&&(r.textContent=ss(u.tables.get(t)));let o=document.querySelector(`textarea[data-rows="${t}"]`);o&&document.activeElement!==o&&(o.value=JSON.stringify(e,null,2))}async function ti(){let t=await fetch("/config.json").then(n=>n.json()),e=!1;for(let[n,s]of Object.entries(t.tables)){if(kt.get(n)===s)continue;let r=Ue(n);if(!u.tables.has(r)){Tt(n,s),e=!0;continue}kt.set(n,s);try{let o=Gn(n,s);ge.delete(n),Qn(r,o.rows,o.columns)}catch(o){ge.set(n,String(o.message)),te()}}e&&(Pt(),te(),await ye())}function Pt(){let t=[...u.tables.keys()][0];if(!(!t||!T))for(let[e,n]of Object.entries(T.params??{}))n.type==="datatable"&&!u.props[e]&&(u.props[e]=t,u.touched.add(e))}function ni(){return{measuring:!0,now:()=>[{source:"preview",present:u.people.length,longestDwellS:u.people.length?Math.round((Date.now()-Math.min(...u.people))/1e3):0}],on(t){return z.people.add(t),()=>{z.people.delete(t)}}}}function wt(t){if(t==="enter"&&u.people.push(Date.now()),t==="leave"&&!u.people.length)return;let e=t==="leave"?u.people.shift():0,n=t==="leave"?{type:"leave",source:"preview",dwellS:Math.round((Date.now()-e)/1e3)}:{type:t,source:"preview"};for(let s of z.people)s([n]);O("people-count").textContent=`${u.people.length} in view`}var si={status:()=>E.controller.status,on(t,e){let n=z.player.get(t)??new Set;return n.add(e),z.player.set(t,n),()=>{n.delete(e)}},async call(t,e,n){return be.push(`controller: ${n.app??"the app"} called ${t}, not applied (a preview)`),Y({}),{ok:!1,code:"PREVIEW",message:"a preview"}}},ri={time:"time.now",play:"player.play",pause:"player.pause",stop:"player.stop",next:"player.next",previous:"player.previous",finish:"app.finish"};function ii(t){let e=s=>r=>{throw be.push(`controller: ${s} refused, ${r.code??"error"}: ${r.message}`),Y({}),r},n={...t,call:(s,r)=>t.call(s,r).catch(e(s))};for(let[s,r]of Object.entries(ri))n[s]=()=>t[s]().catch(e(r));return n}function es(t){oi(t);for(let e of[t.type,"*"])for(let n of z.player.get(e)??[])n(t)}function oi(t){let e=vt??{};switch(t.type){case"state.changed":e.state=t.state;break;case"connection.changed":e.connection=t.connection;break;case"audio.changed":e.audio=t.audio;break;case"display.changed":e.display=t.display;break;case"item.start":e.now=[{zone:t.zone,item:t.item,blob:t.blob,contentType:t.contentType,startedAt:t.startedAt,...t.durationMs===void 0?{}:{durationMs:t.durationMs}}];break;case"item.end":e.now=(e.now??[]).filter(n=>n.item.id!==t.item.id);break}}function ai(){let t=O("command-name").value.trim(),e=O("command-argument").value.trim(),n;try{n=e?JSON.parse(e):void 0}catch{return}t&&(be.push(`controller: the command ${t} sent to the app`),Y({}),es({type:"app.command",seq:0,at:new Date().toISOString(),name:t,...n?{argument:n}:{},by:{kind:"remote",principal:"user:preview"}}))}function li(){return new $e({base:()=>location.origin,token:()=>{},fetch:(async t=>{let e=new URL(String(t),location.origin);if(e.pathname.endsWith("/v0/image"))return fetch("/picture.svg");let n=decodeURIComponent(e.pathname.split("/").pop()??"");if(!(n in u.samples))return new Response(`the preview has no answer for ${n}: declare it in app.json's data`,{status:404});let s=Date.now();return new Response(JSON.stringify({source:n,params:Object.fromEntries(e.searchParams),fetchedAt:new Date(s).toISOString(),expiresAt:new Date(s+36e5).toISOString(),stale:!1,data:u.samples[n]}))})})}function di(){let t=[...u.enter!=="none"?[{element:"app",kind:"enter",preset:u.enter,start:{kind:"at",ms:0},durationMs:u.clipMs,easing:"ease-out"}]:[],...u.exit!=="none"?[{element:"app",kind:"exit",preset:u.exit,start:{kind:"at",ms:fe-u.clipMs},durationMs:u.clipMs,easing:"ease-in"}]:[]];return{profiles:[{id:"preview",width:u.width,height:u.height}],elements:[{type:"app",id:"app",frame:{x:0,y:0,w:u.width,h:u.height},app:Zr,props:u.props,...T.slots&&u.tables.size?{binding:{table:[...u.tables.keys()][0]}}:{},...T.capabilities?.sensors?{sensors:T.capabilities.sensors}:{},appInfo:{id:T.id,element:T.element,player:T.capabilities?.player==="control"?"control":"read"}}],animation:{duration:{kind:"fixed",ms:fe},clips:t}}}async function ye(){let t=++me;if(cancelAnimationFrame(He),W?.dispose(),W=null,St.replaceChildren(),Be.length=0,be.length=0,j.last=null,j.reads=[],Et={kinds:{},nodes:0},!T||!Mt){Y({building:!0});return}let e={};try{e=JSON.parse(u.screen.fields||"{}")}catch{}let n=Mt,s={deviceId:"preview",slide:()=>null,playlist:()=>null,font:()=>{},app:()=>({hash:`preview-${me}`,bytes:n}),data:li(),place:{lat:u.screen.lat,lon:u.screen.lon},screen:{name:u.screen.name,type:"preview",tags:[],path:[{name:"Preview",kind:"organization"}],fields:e},timeZone:u.timeZone,locale:u.locale,preview:!1,snapshot:a=>u.tables.get(a)??null,onSnapshots:a=>(xt.add(a),()=>{xt.delete(a)}),...E.frames?{}:{...T.capabilities?.sensors?.includes("impressions")?{impressions:ni()}:{},controllerFor:a=>ii(Un(si,a))}};z.people.clear(),z.player.clear();let r=performance.now(),o=!1;Fe++;let i=new Q(di(),s,St,{appDeadlineMs:Jn,...E.frames?{isolate:{frames:E.frames,apps:()=>!0}}:{},onAppLate:()=>{o=!0},onApp:a=>{t===me&&(Be.push(`app.failed: ${a.reason}${a.error?` (${a.error})`:""}`),Y({}))}});W=i,Y({waiting:!0}),await i.ready,t===me&&(Y({readyMs:o?void 0:Math.round(performance.now()-r),late:o}),await i.start(Date.now()-u.t),t===me&&(i.seek(u.t),ee={wall:Date.now(),t:u.t},pi(),ci()))}function pi(){cancelAnimationFrame(He);let t=()=>{if(W){if(u.playing){if(u.t=ee.t+(Date.now()-ee.wall)*u.speed,u.t>=fe){u.t=0,ye();return}W.seek(u.t)}O("clock-seek").value=String(Math.round(u.t)),O("clock-time").textContent=`${(u.t/1e3).toFixed(1)} s`,He=requestAnimationFrame(t)}};He=requestAnimationFrame(t)}function ci(){let t=O("pages"),e=W?.paging("app")??null;t.replaceChildren(e&&e.count>1?g("div",{},g("p",{"data-testid":"pages"},`${e.count} pages of ${(e.ms/1e3).toFixed(1)} s`),g("div",{class:"row"},...Array.from({length:e.count},(n,s)=>g("button",{onclick:()=>ts(s*e.ms)},`Page ${s+1}`)))):g("p",{"data-testid":"pages"},"One page"))}function ts(t){u.t=Math.max(0,Math.min(fe-1,t)),ee={wall:Date.now(),t:u.t},W?.seek(u.t)}function Y(t){let e=[];if(At?e.push(g("pre",{"data-testid":"build-error"},`The module does not build:
7
- ${At}`)):t.building&&e.push(g("span",{},"Building\u2026")),t.waiting&&e.push(g("span",{"data-testid":"ready"},"Waiting for ready()\u2026")),t.late)e.push(g("span",{class:"late","data-testid":"ready"},`Late: not ready within ${Jn/1e3} s. A screen reports app.failed (late) and shows the app as it is.`));else if(t.readyMs!==void 0)e.push(g("span",{class:"ok","data-testid":"ready"},`Ready in ${t.readyMs} ms`));else if(!t.waiting&&!t.building){let n=zn.querySelector('[data-testid="ready"]');n&&e.push(n)}for(let n of Be)e.push(g("span",{class:"failed","data-testid":"failure"},n));E.frames&&Be.some(n=>/SecurityError/.test(n))&&e.push(g("span",{class:"warn","data-testid":"frame-why"},"In its frame, as in the CMS, an app has no storage, cookies or parent page: localStorage, sessionStorage, document.cookie and parent's document throw SecurityError. Keep nothing there that matters; a screen may lose it too."));for(let n of be.slice(-5))e.push(g("span",{"data-testid":"command"},n));Fe&&e.push(g("span",{"data-testid":"made-times"},`Made ${Fe===1?"once":`${Fe} times`}: at each start of its layout, and when its code, params or screen change. A table's change reaches it as it plays.`)),zn.replaceChildren(...e)}function ui(){let t=E.frames?Et:Xr();if(j.last&&u.playing&&W){let i={};for(let[a,l]of Object.entries(t.kinds)){let p=l-(j.last.kinds[a]??0);p>0&&(i[a]=p)}j.reads=[...j.reads,i].slice(-Vn)}j.last=t;let e=j.reads.length===Vn?Object.keys(yt).filter(i=>j.reads.every(a=>a[i])):[],n=i=>Math.round(j.reads.reduce((a,l)=>a+(l[i]??0),0)*1e3/(Xn*j.reads.length)),s=e.map(i=>[i,`Makes ${n(i)} ${yt[i]} a second while it plays. ${i==="listener"?"Add a listener once, in mount(), and take it off when the app goes":"Make it once, in mount() or with useMemo, never in draw() or a render"}: one made at every frame holds memory a screen frees late, and can run it out.`]),r=`${e.length?"":"Nothing made at every frame. "}${t.nodes} DOM nodes in the app.`,o=JSON.stringify(s);if(o===j.said&&bt.firstChild){bt.querySelector('[data-testid="made-counts"]').textContent=r;return}j.said=o,bt.replaceChildren(...s.map(([i,a])=>g("span",{class:"warn","data-testid":"made","data-kind":i},a)),g("span",{"data-testid":"made-counts"},r))}function hi(){let t=Object.entries(T?.params??{}).find(([,n])=>n.type==="datatable")?.[0],e=T?.slots?[...u.tables.keys()][0]:t?u.props[t]:void 0;return typeof e=="string"?u.tables.get(e):void 0}var ns=t=>t.label&&t.label!==t.key?`${t.label} (${t.key})`:t.key,ss=t=>`${t.table}: ${t.rows.length} rows, ${t.columns.map(ns).join(", ")}`;function mi(t,e){let n=u.props[t],s=o=>{u.props[t]=o,u.touched.add(t),rs(),R()},r=e.label??t;if(e.type==="boolean")return S(r,g("input",{type:"checkbox",checked:n===!0,onchange:o=>s(o.target.checked)}),!0);if(e.type==="enum"){let o=(e.values??[]).map(i=>i&&typeof i=="object"?[String(i.value),String(i.label??i.value)]:String(i));return S(r,q(o,String(n??""),s))}if(e.type==="number")return S(r,g("input",{type:"number",value:n===void 0?"":String(n),min:e.min,max:e.max,step:e.step??"any",onchange:o=>{let i=o.target.value;s(i===""?void 0:Number(i))}}));if(["string","text","color","url","datetime","duration","secret"].includes(e.type)){let o=e.type==="text"?g("textarea",{value:String(n??""),onchange:i=>s(i.target.value)}):g("input",{type:"text",value:String(n??""),placeholder:e.type==="color"?"#rrggbb or #rrggbbaa":void 0,onchange:i=>s(i.target.value)});return S(r,o)}return e.type==="datatable"?S(r,q(["",...u.tables.keys()],String(n??""),s)):e.type==="column"?S(r,q(["",...(hi()?.columns??[]).map(o=>[o.key,ns(o)])],String(n??""),s)):S(`${r} (JSON)`,g("textarea",{value:n===void 0?"":JSON.stringify(n,null,2),onchange:o=>{let i=o.target.value.trim();try{s(i?JSON.parse(i):void 0)}catch{s(i)}}}))}function rs(){let t=O("params"),e=T?.params??{},n=new Set(Hn(e,u.props));t.replaceChildren(...Object.entries(e).filter(([s])=>n.has(s)).map(([s,r])=>mi(s,r))),t.children.length||t.append(g("p",{},"No params."))}var Zn;function R(){clearTimeout(Zn),Zn=setTimeout(()=>{ye()},150)}function te(){let t=!je.some(([,i,a])=>i===u.width&&a===u.height),e=g("input",{type:"number",value:String(u.width),min:64,max:7680,onchange:i=>{u.width=Number(i.target.value)||1920,R()}}),n=g("input",{type:"number",value:String(u.height),min:64,max:7680,onchange:i=>{u.height=Number(i.target.value)||1080,R()}}),s=g("button",{type:"button","aria-pressed":String(!u.playing),onclick:()=>{u.playing=!u.playing,s.textContent=u.playing?"Pause":"Play",s.setAttribute("aria-pressed",String(!u.playing)),ee={wall:Date.now(),t:u.t}}},u.playing?"Pause":"Play"),r=g("input",{id:"clock-seek",type:"range",min:0,max:fe,step:100,value:String(u.t),oninput:i=>ts(Number(i.target.value))}),o=[g("h2",{},"Screen"),S("Size",q([...je.map(([i])=>i),"Custom"],t?"Custom":je.find(([,i,a])=>i===u.width&&a===u.height)[0],i=>{let a=je.find(([l])=>l===i);a&&(u.width=a[1],u.height=a[2]),te(),R()})),t?g("div",{class:"row"},S("Width",e),S("Height",n)):null,g("div",{class:"row"},S("Time zone",g("input",{type:"text",value:u.timeZone,onchange:i=>{u.timeZone=i.target.value||"UTC",R()}})),S("Locale",g("input",{type:"text",value:u.locale,onchange:i=>{u.locale=i.target.value||"en-US",R()}}))),S("Screen's name",g("input",{type:"text",value:u.screen.name,onchange:i=>{u.screen.name=i.target.value,R()}})),g("div",{class:"row"},S("Latitude",g("input",{type:"number",step:"any",value:String(u.screen.lat),onchange:i=>{u.screen.lat=Number(i.target.value),R()}})),S("Longitude",g("input",{type:"number",step:"any",value:String(u.screen.lon),onchange:i=>{u.screen.lon=Number(i.target.value),R()}}))),S("Screen's fields (JSON)",g("textarea",{value:u.screen.fields,onchange:i=>{u.screen.fields=i.target.value,R()}})),g("h2",{},"Clock"),g("div",{class:"row"},s,S("Speed",q(Kr.map(i=>[String(i),`${i}\xD7`]),String(u.speed),i=>{ee={wall:Date.now(),t:u.t},u.speed=Number(i)})),g("span",{id:"clock-time"},"0.0 s")),S("Time in the layout",r),g("h2",{},"Enter and exit"),g("div",{class:"row"},S("Enter",q(Wn,u.enter,i=>{u.enter=i,R()})),S("Exit",q(Wn,u.exit,i=>{u.exit=i,R()}))),S("Each lasts (ms)",g("input",{type:"number",min:0,max:5e3,step:100,value:String(u.clipMs),onchange:i=>{u.clipMs=Number(i.target.value)||0,R()}})),g("div",{id:"pages"}),g("h2",{},"Params"),g("div",{id:"params"}),E.frames?g("p",{"data-testid":"framed"},`In a frame on ${E.frames}, as in the CMS: no storage, cookies, parent page, controller or impressions.`):null,g("h2",{},"Tables"),...[...u.tables.values()].flatMap(i=>[g("p",{"data-testid":"table","data-table":i.table},ss(i)),S(`${i.table}'s rows (JSON)`,g("textarea",{"data-rows":i.table,value:JSON.stringify(i.rows,null,2),rows:6,onchange:a=>{try{let l=JSON.parse(a.target.value);Array.isArray(l)&&Qn(i.table,l)}catch{}}}))]),...[...ge].map(([i,a])=>g("p",{class:"failed","data-testid":"table-error"},`${i}: ${a}`)),S("Add a table (JSON or CSV)",g("input",{type:"file",accept:".json,.csv",onchange:async i=>{let a=i.target.files?.[0];a&&(Tt(a.name,await a.text()),Pt(),te(),R())}})),...T?.capabilities?.sensors?.includes("impressions")&&!E.frames?[g("h2",{},"People at the screen"),g("div",{class:"row"},g("button",{type:"button",onclick:()=>wt("enter")},"Someone arrives"),g("button",{type:"button",onclick:()=>wt("look")},"Someone looks"),g("button",{type:"button",onclick:()=>wt("leave")},"Someone leaves")),g("p",{id:"people-count"},`${u.people.length} in view`)]:[],...E.frames?[]:[g("h2",{},"The player's controller"),g("p",{},`The app may ${T?.capabilities?.player==="control"?"read it and call its commands":"read it (capabilities.player: read)"}. Commands are not applied here.`),...Object.keys(E.controller.events).length?[S("Event",q(Object.keys(E.controller.events),Object.keys(E.controller.events)[0],i=>{O("event-json").value=JSON.stringify(E.controller.events[i],null,2)})),S("Its JSON",g("textarea",{id:"event-json",rows:6,value:JSON.stringify(Object.values(E.controller.events)[0],null,2)})),g("button",{type:"button","data-testid":"send-event",onclick:()=>{try{es(JSON.parse(O("event-json").value))}catch{}}},"Send to the app")]:[],S("A command's name",g("input",{id:"command-name",value:"showSpecial"})),S("Its argument (JSON, or nothing)",g("textarea",{id:"command-argument",rows:3,value:JSON.stringify({sku:"1234"})})),g("button",{type:"button","data-testid":"send-command",onclick:ai},"Send the command")],g("h2",{},"Data"),...Object.keys(u.samples).map(i=>S(`${i} answer's data (JSON)`,g("textarea",{"data-source":i,value:JSON.stringify(u.samples[i],null,2),rows:8,onchange:a=>{try{u.samples[i]=JSON.parse(a.target.value),R()}catch{}}}))),Object.keys(u.samples).length?null:g("p",{},"The app declares no data source with a sample (weather, news or calendar).")];Yr.replaceChildren(...o.filter(i=>i!==null)),rs()}async function fi(){await Kn(),te(),setInterval(ui,Xn),await ye();let t=new EventSource("/events"),e=()=>{Kn().then(()=>(te(),ye()))};t.addEventListener("hello",n=>{JSON.parse(n.data).version!==Yn&&e()}),t.addEventListener("reload",e),t.addEventListener("tables",()=>{ti()}),window.addEventListener("resize",()=>R())}fi();})();
4
+ ${n}`))).slice(0,8),16),r=rr(i),o=Array.from({length:s},(a,l)=>l);for(let a=s-1;a>0;a--){let l=Math.floor(r()*(a+1));[o[a],o[l]]=[o[l],o[a]]}return o}var or=250,ar=1e3;function an(t,e){let n=t.animation?.duration;if(n?.kind==="fixed")return{durationMs:n.ms};if(n?.kind==="untilPlaylistEnds"){let s=zn(t.elements,n.element);return{durationMs:(s?.source?.kind==="playlist"?e.playlist(s.source.item)??[]:s?.source?[{item:s.source.item}]:[]).reduce((o,a)=>o+(e.slide(a,{imageDurationMs:s?.playback?.imageDurationMs})?.durationMs??0),0)||1e4,untilPass:n.element}}return{durationMs:me(t.animation?.clips??[]).autoDurationMs}}function qn(t,e,n=0){let s={},i=r=>{for(let o of r){if(o.type==="library"&&o.source){let a=o.source.kind==="playlist"?e.playlist(o.source.item)??[]:[{item:o.source.item}];s[o.source.item.id]={video:a.some(l=>{let p=e.slide(l);if(!p)return!1;if(p.blob.contentType.startsWith("video/"))return!0;let u=p.layout;return!!u&&n<4&&Object.values(qn(u.doc,u.source,n+1)).some(d=>d.video)})}}o.children&&i(o.children)}};return i(t.elements),s}function zn(t,e){for(let n of t){if(n.id===e)return n;let s=n.children&&zn(n.children,e);if(s)return s}}var te=class{constructor(e,n,s,i={}){c(this,"source",n);c(this,"o",i);c(this,"el");c(this,"ready");c(this,"unplayed");c(this,"doc");c(this,"motions");c(this,"native");c(this,"animated",[]);c(this,"loops",[]);c(this,"startedAt",0);c(this,"frame",0);c(this,"running",!1);c(this,"disposed",!1);c(this,"apps",[]);c(this,"heldAt");c(this,"late",[]);c(this,"overran",[]);c(this,"timers",[]);c(this,"bound",[]);c(this,"unheard");c(this,"reduced",typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches);let r=s.clientWidth||window.innerWidth,o=s.clientHeight||window.innerHeight,a=!e.profiles[0].width,l=a?{...e.profiles[0],width:r,height:o}:e.profiles[0];a&&(e={...e,elements:e.elements.map(b=>b.frame.w?b:{...b,frame:{x:0,y:0,w:r,h:o}})});let p=Math.min(r/l.width,o/l.height);this.el=F("div"),this.el.dataset.layout=l.id,this.el.style.cssText=`position:absolute;left:${(r-l.width*p)/2}px;top:${(o-l.height*p)/2}px;width:${l.width}px;height:${l.height}px;transform:scale(${p});transform-origin:0 0;overflow:hidden`,s.append(this.el),this.doc=e;let u=new Map,d=b=>{for(let M of b)u.set(M.id,M.frame),M.children&&d(M.children)};d(e.elements);let m=Fn(e.animation?.clips??[],u);this.motions=m.motions;let g=new Set(m.unplayed.map(b=>`preset ${b}`)),k=[this.loadFonts()],f=i.media?Rn(e,void 0,qn(e,n),i.media.capability):[];this.native=new Set(f.filter(b=>b.path.path==="native").map(b=>b.element));let v=(b,M)=>{for(let w of b){if(w.hidden)continue;let P=this.element(w,g,k);M.append(P),w.children?.length&&w.type==="shape"&&v(w.children,P)}};v(e.elements,this.el),e.background&&Tn(this.el,e.background,l,f.filter(b=>this.native.has(b.element)).map(b=>b.box)),this.unplayed=[...g].sort(),this.ready=Promise.all(k).then(()=>{}),this.bound.length&&(this.unheard=n.onSnapshots?.(()=>this.refill()))}refill(){let e=he(this.source),n=(this.heldAt??Date.now())-this.startedAt;for(let{el:s,e:i}of this.bound){let r=vt(i,e),o=this.animated.find(a=>a.el===s);o?(o.text=r,this.running||this.place(o,n)):s.textContent!==r&&(s.textContent=r)}}path(e){return this.o.path?`${this.o.path}/${e}`:e}element(e,n,s){let i=Pn(e);Ln(i,e,this.source),e.type==="text"&&(e.bind||De(e.text??""))&&this.bound.push({el:i,e});let r=this.motions.get(e.id);if(r){let o={el:i,e,motion:r,text:e.type==="text"?i.textContent??"":void 0};this.animated.push(o),this.place(o,0)}if(e.type==="library"&&e.source){let o=e.source.kind==="playlist"?this.source.playlist(e.source.item)??[]:[{item:e.source.item}],a=new xt(i,o,e.playback??{},this.source,this.path(e.id),{...this.o,media:this.native.has(e.id)?this.o.media:void 0},e.source.kind==="playlist"?e.source.item:void 0);this.loops.push(a),s.push(a.ready);for(let l of a.unplayed)n.add(l)}else if(e.type==="app"){let o=e.app?this.source.app?.(e.app):null;o?s.push(this.mountApp(e,i,o)):n.add(`app ${e.app?.id??e.id}`)}return i}place(e,n){Un(e.el,e.e,Hn(e.motion,e.e.frame,n,this.reduced),e.text);let s=e.e.type==="text"?e.el.firstElementChild:null;s&&ot(s)}loadFonts(){return In(this.doc.fonts??[],e=>this.source.font(e))}async mountApp(e,n,s){let i=this.path(e.id),r=e.app,o=(e.appInfo??s.info)?.id,a={now:()=>this.heldAt??Date.now(),startedAt:()=>this.startedAt||Date.now()},l=(d,m)=>this.o.onApp?.({type:"app.failed",element:i,item:r,...o?{app:o}:{},reason:d,...m?{error:m}:{}}),p=this.o.isolate?{...this.o.isolate,fonts:this.doc.fonts,font:d=>this.source.font(d)}:void 0,u=await Cn(e,n,s,this.source,a,this.o.appDeadlineMs??5e3,d=>{this.disposed?d.dispose():this.apps.push({app:d,box:n,path:i,id:e.id,item:r})},d=>l("error",d),p);if(!("held"in u)){if("failed"in u){l(u.failed,u.error);return}u.late&&(this.late.push(i),this.o.onAppLate?.(i,r.id),l("late"))}}async start(e=Date.now()){this.startedAt=e,this.heldAt=void 0,this.running=!0,this.hooks(e);let n=()=>{if(!this.running)return;let s=Date.now(),i=s-this.startedAt;for(let r of this.animated)this.place(r,i);for(let r of this.apps)r.app.update(s);this.frame=requestAnimationFrame(n)};(this.animated.length||this.apps.length)&&(this.frame=requestAnimationFrame(n)),await Promise.all(this.loops.map(s=>s.start()))}hooks(e){let n=this.doc.animation?.clips??[],s=me(n).clips,i=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches;for(let r of this.apps){let a=n.map((f,v)=>({c:f,t:s[v]})).filter(f=>f.c.element===r.id&&(f.c.kind==="enter"||f.c.kind==="exit")).filter(f=>r.app.has(f.c.kind));if(!a.length)continue;let l=r.box,p=this.animated.findIndex(f=>f.el===l);p>=0&&(this.animated.splice(p,1),Object.assign(l.style,{opacity:"",transform:"",clipPath:""}));let u=(f,v,b)=>this.hook(r,f.kind,{startAt:v,preset:f.preset??"fade",durationMs:f.durationMs,easing:f.easing,delayMs:0,...f.staggerMs?{staggerMs:f.staggerMs}:{},...b!==void 0?{page:b}:{},reducedMotion:i},l);for(let{c:f,t:v}of a)u(f,e+v.startMs);let d=r.app.paging();if(!d)continue;let m=a.find(f=>f.c.kind==="enter")?.c,g=a.find(f=>f.c.kind==="exit")?.c,k=Bn(d.count,d.ms,an(this.doc,this.source).durationMs);for(let f=1;f<k.length;f++){let v=e+k[f].startMs;g&&u(g,v-g.durationMs,k[f-1].page),m&&u(m,v,k[f].page)}}}hook(e,n,s,i){let r=!1;e.app.hook(n,s).finally(()=>{r=!0});let o=s.startAt+s.durationMs;this.timers.push(setTimeout(()=>{r||!this.running||(this.overran.includes(e.path)||(this.overran.push(e.path),this.o.onAppOverran?.(e.path,e.item.id),this.o.onApp?.({type:"app.failed",element:e.path,item:e.item,reason:"overran"})),n==="exit"&&(i.style.visibility="hidden"))},Math.max(0,o+or-Date.now())))}pause(){this.heldAt=Date.now();for(let e of this.loops)e.pause();for(let e of this.apps)e.app.update(this.heldAt)}seek(e){this.running=!1,cancelAnimationFrame(this.frame);for(let n of this.loops)n.pause();for(let n of this.animated)this.place(n,e);this.heldAt=this.startedAt+e;for(let n of this.apps)n.app.update(this.heldAt)}resume(){this.heldAt=void 0;for(let e of this.loops)e.resume()}paging(e){return this.apps.find(n=>n.id===e)?.app.paging()??null}dispose(){this.running=!1,this.disposed=!0,cancelAnimationFrame(this.frame);for(let e of this.timers)clearTimeout(e);for(let e of this.loops)e.stop();for(let e of this.apps)e.app.dispose();this.unheard?.(),this.el.remove()}},_n=t=>Math.min(Math.max(0,t),2**31-1),xt=class{constructor(e,n,s,i,r,o,a){c(this,"region",e);c(this,"playback",s);c(this,"source",i);c(this,"path",r);c(this,"o",o);c(this,"list",a);c(this,"ready");c(this,"unplayed",[]);c(this,"renderer");c(this,"slides");c(this,"order",[]);c(this,"pass",0);c(this,"at",0);c(this,"timer");c(this,"current");c(this,"shownAt",0);c(this,"remaining");c(this,"stopped",!1);c(this,"ended",!1);c(this,"empty",!1);c(this,"open");c(this,"pages");this.renderer=new je(e,{media:o.media,fit:s.fit,path:r,onItem:o.onItem,onPassEnd:o.onPassEnd,onApp:o.onApp}),s.transition==="slide"&&this.unplayed.push("transition slide");let l=s.transition==="fade"?{type:"crossfade"}:void 0,p=n.map(u=>i.slide(u,{imageDurationMs:s.imageDurationMs,transition:l,region:!0})).filter(u=>!!u);this.slides=p.length===1&&p[0].untilEnd&&(s.onEnd??"loop")==="loop"?[{...p[0],untilEnd:!1,loop:!0}]:p,this.renderer.onMediaEnd(u=>{u===this.current&&!this.stopped&&(clearTimeout(this.timer),this.next("completed"))}),this.ready=this.newPass().then(()=>this.slides.length?this.renderer.prepare(this.slides[this.order[0]]):void 0).catch(()=>{})}async newPass(){let e=this.slides.length;this.order=this.playback.order==="shuffle"?await Wn(this.source.deviceId,this.path,this.pass,e):[...Array(e).keys()],this.at=0}async start(){this.slides.length&&await this.first()}bounds(e){return[this.source.bounds?.(e.item),this.list&&this.source.bounds?.(this.list)]}seek(e){let n=Date.now(),s=e;for(;s<this.order.length&&!this.bounds(this.slides[this.order[s]]).every(i=>sn(i,n));)s++;return s}async first(){if(this.at=this.seek(0),this.at<this.order.length){this.empty=!1,await this.show();return}this.empty=!0,this.current=void 0,this.renderer.standby();let e=Date.now(),n=this.slides.flatMap(s=>this.bounds(s).map(i=>i?.from??0)).filter(s=>s>e);clearTimeout(this.timer),n.length&&(this.timer=setTimeout(()=>{!this.stopped&&!this.ended&&this.first()},_n(Math.min(...n)-e)))}async show(){let e=this.slides[this.order[this.at]];this.current=e;try{await this.renderer.show(e)}catch(s){if(this.stopped)return;this.o.onItem?.({type:"item.error",element:this.path,item:e.item,blob:e.blob.hash,...ft(s)}),this.o.onItem?.({type:"item.end",element:this.path,item:e.item,blob:e.blob.hash,endedAt:Date.now(),reason:"error"}),this.schedule(ar);return}if(this.stopped)return;if(this.shownAt=Date.now(),this.open=e,this.o.onItem?.({type:"item.start",element:this.path,item:e.item,blob:e.blob.hash,contentType:e.blob.contentType,startedAt:this.shownAt,durationMs:e.durationMs}),e.pages&&(this.pages=new pe(this.renderer,e,this.shownAt,!1)),!(this.slides.length===1&&e.loop))this.schedule(e.durationMs+(e.untilEnd?5e3:0));else{let s=this.bounds(e).flatMap(i=>i?.until??[]);s.length&&this.schedule(Math.min(...s)-this.shownAt)}let n=this.peek();n&&n!==e&&this.renderer.prepare(n).catch(()=>{})}peek(){let e=this.seek(this.at+1);if(e<this.order.length)return this.slides[this.order[e]];if(this.o.endsWith!==this.path)return this.playback.onEnd==="hold"||this.playback.onEnd==="hide"||this.playback.order==="shuffle"?void 0:this.slides[this.order[0]]}schedule(e){clearTimeout(this.timer),this.timer=setTimeout(()=>{this.next("completed")},_n(e))}async next(e){if(this.stopped||this.ended||!this.current)return;let n=()=>this.endOpen(e),s=this.seek(this.at+1);if(s<this.order.length){this.at=s,n(),await this.show();return}let r=this.o.onPassEnd?.(this.path)==="hold"?"hold":this.playback.onEnd??"loop";if(r==="hold"){this.ended=!0;return}if(r==="hide"){this.ended=!0,n(),this.renderer.standby(),this.region.style.visibility="hidden";return}this.pass++,await this.newPass(),n(),await this.first()}pause(){clearTimeout(this.timer),this.current&&this.remaining===void 0&&(this.remaining=Math.max(0,this.current.durationMs-(Date.now()-this.shownAt))),this.pages?.pause(),this.renderer.pause()}resume(){if(this.empty&&!this.ended&&!this.stopped){this.first();return}this.remaining===void 0||this.ended||(this.renderer.resume(),this.pages?.resume(),this.shownAt=Date.now()-(this.current.durationMs-this.remaining),this.schedule(this.remaining),this.remaining=void 0)}endOpen(e){this.pages?.stop(),this.pages=void 0;let n=this.open;n&&(this.open=void 0,this.o.onItem?.({type:"item.end",element:this.path,item:n.item,blob:n.blob.hash,endedAt:Date.now(),reason:e}))}stop(){this.endOpen("stopped"),this.stopped=!0,clearTimeout(this.timer),this.renderer.standby();for(let e of this.slides)this.renderer.release(e)}};var Mt=t=>t!=null&&t!==""&&!(Array.isArray(t)&&t.length===0);function Vn(t,e,n,s=[]){let i=t[n];if(!i)return!1;if(!i.when)return!0;if(s.includes(n))return!1;let r=o=>String(o);for(let[o,a]of Object.entries(i.when)){if(!t[o]||o===n)return!1;let p=Vn(t,e,o,[...s,n])?e[o]!==void 0?e[o]:t[o].default:void 0,u=Array.isArray(p)?p.map(r):Mt(p)?[r(p)]:[];if(a.set!==void 0&&a.set!==Mt(p)||a.anyOf&&!(Mt(p)&&!Array.isArray(p)?a.anyOf.map(r).includes(r(p)):u.some(d=>a.anyOf.map(r).includes(d)))||a.allOf&&!a.allOf.map(r).every(d=>u.includes(d))||a.noneOf&&u.some(d=>a.noneOf.map(r).includes(d)))return!1}return!0}function Kn(t,e){return Object.keys(t).filter(n=>Vn(t,e,n))}var kl=ce.apiVersion,Zn=new Map(ce.commands.map(t=>[t.name,t]));var G=class extends Error{constructor(n,s){super(s);c(this,"code",n)}};function Jn(t,e){let n=e.capability??"read",s={kind:"app",app:e.id,instance:e.instance},i=new Set,r=!1,o=async(a,l={})=>{if(r)throw new G("NOT_ALLOWED","This app has been removed from the screen.");let p=Zn.get(a);if(!p)throw new G("UNKNOWN",`There is no command ${a}.`);if(p.apps==="none")throw new G("NOT_ALLOWED",`Apps cannot call ${a}.`);if(p.apps==="control"&&n!=="control")throw new G("NOT_ALLOWED",`${a} needs capabilities.player: control in ${e.id}'s definition.`);let u=await t.call(a,l,s);if(u.ok)return u.result;if(u.code==="PREVIEW")return{applied:!1,reason:"preview"};throw new G(u.code,u.message)};return{app:e.id,instance:e.instance,capability:n,status:()=>t.status(),get:a=>t.status()[a],on(a,l){if(r)return()=>{};let p=t.on(a,l),u=()=>{p(),i.delete(u)};return i.add(u),u},time:()=>o("time.now"),call:o,play:()=>o("player.play"),pause:()=>o("player.pause"),stop:()=>o("player.stop"),next:()=>o("player.next"),previous:()=>o("player.previous"),finish:()=>o("app.finish"),dispose(){r=!0;for(let a of[...i])a()}}}var Yn=t=>t.status!=="Actual";function Gn(t,e){let n=e?.split("-")[0],s=t.translations?.find(r=>r.locale===e)??t.translations?.find(r=>r.locale.split("-")[0]===n),i={headline:s?.headline??t.headline,description:s?.description??t.description,instruction:s?.instruction??t.instruction};return Object.fromEntries(Object.entries(i).filter(([,r])=>r!==void 0))}function Xn(t,e){let n=e?.split("-")[0];return(t.translations?.find(i=>i.locale===e)??t.translations?.find(i=>i.locale.split("-")[0]===n))?.locale??t.language}var At={"pairing.title":"Pair this screen","pairing.instructions":"On a phone or computer, go to {url} and enter","pairing.scan":"Or scan with your phone's camera","pairing.codeChanges":"The code changes every few minutes.","pairing.starting":"Getting a pairing code\u2026","pairing.unreachable":"Can't reach Wyndlass yet. Trying again\u2026","pairing.waiting.title":"Waiting for approval","pairing.waiting.body":"Someone added this screen. It joins as soon as the change is approved.","pairing.joined.title":"Joined {organization}","pairing.joined.body":"{name}, at {place}","pairing.network.online":"Online","pairing.network.connecting":"Connecting\u2026","pairing.network.offline":"No network connection","pairing.resolution":"{width} \xD7 {height}","pairing.enrolling.title":"Joining {place}","pairing.enrolling.body":"This screen is setting itself up from its deployment file.","pairing.notice.refused":"The deployment file's token didn't work: it may be used up, expired or revoked. Pair this screen with the code instead.","pairing.notice.invalid":"The deployment file couldn't be checked, so this screen ignored it. Pair it with the code instead.","pairing.notice.ended":"The deployment file has expired. Pair this screen with the code instead.","emergency.severity.Extreme":"Extreme threat","emergency.severity.Severe":"Severe threat","emergency.severity.Moderate":"Moderate threat","emergency.severity.Minor":"Minor threat","emergency.severity.Unknown":"Emergency message","emergency.test":"TEST \u2014 no action needed","emergency.area":"Area: {area}","emergency.until":"Until {time}","emergency.turn":"{n} of {count}","emergency.page":"Page {n} of {count}","screen.nothingScheduled":"Nothing scheduled","settings.title":"Settings","settings.close":"Close","settings.locked.title":"Settings are locked on this screen","settings.locked.body":"Set a screen PIN in Wyndlass to open them here.","settings.pin.title":"Enter the screen PIN","settings.pin.body":"The PIN for this workspace's screens, from your Wyndlass admin.","settings.pin.entered":"Digits entered: {count}","settings.pin.delete":"Delete","settings.pin.enter":"Unlock","settings.pin.wrong":"Wrong PIN. Tries left: {left}.","settings.pin.lockedOut":"Too many wrong PINs. Try again in {wait}.","settings.section.screen":"This screen","settings.section.connection":"Connection","settings.section.content":"Content","settings.section.network":"Network","settings.section.display":"Display, sound and time","settings.section.versions":"Versions","settings.section.actions":"Actions","settings.setInWyndlass":"Set in Wyndlass","settings.screen.name":"Name","settings.screen.place":"Place","settings.screen.type":"Type","settings.screen.id":"Device id","settings.screen.management":"Management","settings.screen.management.deviceOwner":"Device Owner","settings.screen.management.managed":"Managed","settings.screen.management.none":"None","settings.screen.management.vendor":"The box maker's API","settings.screen.paired":"Paired","settings.screen.unpaired":"Not paired yet","settings.connection.state":"Status","settings.connection.connected":"Connected since {since}","settings.connection.disconnected":"Not connected","settings.connection.server":"Server","settings.connection.certificate":"Certificate ends","settings.connection.renews":"Renews","settings.connection.key":"Key kept in","settings.connection.key.hardware":"Hardware","settings.connection.key.software":"Software","settings.connection.key.none":"None","settings.content.manifest":"Playing","settings.content.manifest.value":"{manifest}, since {applied}","settings.content.none":"Nothing yet","settings.content.lastSync":"Last sync","settings.content.lastSync.value":"{at}: {result}","settings.content.failures":"Verify failures","settings.content.storage":"Storage","settings.content.storage.value":"{held} held, {free} free, {budget} budget","settings.network.type":"Type","settings.network.type.ethernet":"Ethernet","settings.network.type.wifi":"Wi-Fi","settings.network.type.cellular":"Cellular","settings.network.type.other":"Other","settings.network.type.none":"No network","settings.network.addresses":"IP addresses","settings.network.signal":"Wi-Fi signal","settings.network.signal.value":"{dbm} dBm","settings.network.proxy":"Proxy","settings.network.proxy.none":"None","settings.section.sensing":"People at the screen","settings.sensing.mode":"Measuring","settings.sensing.mode.off":"Off","settings.sensing.mode.presence":"People in view","settings.sensing.mode.attention":"People in view, and whether they look","settings.sensing.sources":"Sensors","settings.sensing.none":"None","settings.sensing.source":"{kind}: {state}","settings.sensing.problem":"{kind}: {state} ({problem})","settings.sensing.state.running":"running","settings.sensing.state.stopped":"stopped","settings.sensing.state.failed":"failed","settings.section.sensors":"Sensors","settings.sensors.controllers":"Controllers","settings.sensors.none":"None found","settings.sensors.controller":"{transport}, {state}","settings.sensors.controller.problem":"{transport}, {state} ({problem})","settings.sensors.transport.serial":"USB or serial","settings.sensors.transport.udp":"Network (UDP)","settings.sensors.state.open":"open","settings.sensors.state.closed":"closed","settings.sensors.state.failed":"failed","settings.sensors.channel":"Channel {channel}","settings.sensors.channel.sensor":"{product} ({family})","settings.sensors.channel.inputs":"{sensor}: {inputs}","settings.sensors.messages":"Messages, newest last","settings.sensors.waiting":"No messages yet","settings.sensors.line":"{time} {port} {line}","settings.sensors.sent":"{time} {port} sent {line}","settings.sensors.beacons":"Beacons","settings.sensors.beacon.unnamed":"Not named","settings.sensors.beacon":"{address}: {state}, {rssi} dBm, heard at {time}","settings.sensors.beacon.battery":"{address}: {state}, {rssi} dBm, battery {volts} V, heard at {time}","settings.sensors.beacon.batteryLow":"{address}: {state}, {rssi} dBm, battery low ({volts} V), heard at {time}","settings.sensors.beacon.state.active":"active","settings.sensors.beacon.state.idle":"idle","settings.sensors.beacon.state.absent":"not heard","settings.proxy.host":"Proxy host","settings.proxy.port":"Port","settings.proxy.bypass":"Reach directly (commas between hosts)","settings.proxy.save":"Save proxy","settings.proxy.remove":"Use no proxy","settings.proxy.invalid":"Enter a host and a port from 1 to 65535.","settings.display.resolution":"Resolution","settings.display.resolution.value":"{width} \xD7 {height}","settings.display.rotation":"Rotation","settings.display.rotation.value":"{degrees}\xB0","settings.display.brightness":"Brightness","settings.display.volume":"Volume","settings.display.percent":"{value}%","settings.display.time":"Time","settings.display.timeZone":"Time zone","settings.display.locale":"Language","settings.versions.shell":"Player app","settings.versions.core":"Player core","settings.versions.webView":"WebView","settings.versions.electron":"Electron","settings.versions.chromium":"Chromium","settings.versions.os":"Operating system","settings.action.sync":"Sync now","settings.action.restart":"Restart the player","settings.action.reboot":"Reboot","settings.action.wifi":"Wi-Fi settings","settings.action.deploymentFile":"Use a deployment file","settings.action.pairAgain":"Pair again","settings.pairAgain.first":"Pair this screen again? It leaves {organization} and shows a new pairing code. Its content and settings from Wyndlass are removed.","settings.pairAgain.second":"Are you sure? Someone will need to pair it again, or replace it in Wyndlass.","settings.pairAgain.confirm":"Pair again","settings.pairAgain.cancel":"Keep it","settings.result.ok":"Done.","settings.result.failed":"That didn't work: {reason}","settings.result.failedPlain":"That didn't work.","settings.wifi.title":"Wi-Fi","settings.wifi.current":"Connected to {ssid}","settings.wifi.offline":"Not on a Wi-Fi network","settings.wifi.scanning":"Looking for networks\u2026","settings.wifi.none":"No networks found.","settings.wifi.noList":"No list: {reason}","settings.wifi.secured":"secured","settings.wifi.open":"open","settings.wifi.signal":"signal {bars} of 4","settings.wifi.connected":"Connected","settings.wifi.other":"Other network","settings.wifi.scanAgain":"Look again","settings.wifi.back":"Back","settings.wifi.join.title":"Join {ssid}","settings.wifi.join.otherTitle":"Join a network that hides its name","settings.wifi.join.ssid":"Network name","settings.wifi.join.security":"Security","settings.wifi.security.open":"Open","settings.wifi.security.wep":"WEP","settings.wifi.security.wpa":"WPA","settings.wifi.security.wpa2":"WPA2","settings.wifi.security.wpa3":"WPA3","settings.wifi.join.password":"Passphrase","settings.wifi.join.show":"Show passphrase","settings.wifi.join.hide":"Hide passphrase","settings.wifi.join.join":"Join","settings.wifi.join.cancel":"Cancel","settings.wifi.join.invalidSsid":"Enter the network's name, up to 32 characters.","settings.wifi.join.invalidPassword":"Enter a passphrase of 8 to 63 characters.","settings.wifi.joining":"Joining {ssid}\u2026 This can take up to 30 seconds.","settings.wifi.joined":"Connected to {ssid}.","settings.wifi.notJoined":"Not connected: {reason}","settings.unknown":"\u2014"},lr={a:"\xE1",b:"\u0180",c:"\xE7",d:"\xF0",e:"\xE9",f:"\u0192",g:"\u011D",h:"\u0125",i:"\xED",j:"\u0135",k:"\u0137",l:"\u013C",m:"\u0271",n:"\xF1",o:"\xF3",p:"\xFE",q:"\u01EB",r:"\u0155",s:"\u0161",t:"\u0163",u:"\xFA",v:"\u1E7D",w:"\u0175",x:"\u1E8B",y:"\xFD",z:"\u017E",A:"\xC1",B:"\u0181",C:"\xC7",D:"\xD0",E:"\xC9",F:"\u0191",G:"\u011C",H:"\u0124",I:"\xCD",J:"\u0134",K:"\u0136",L:"\u013B",M:"\u1E40",N:"\xD1",O:"\xD3",P:"\xDE",Q:"\u01EA",R:"\u0154",S:"\u0160",T:"\u0162",U:"\xDA",V:"\u1E7C",W:"\u0174",X:"\u1E8A",Y:"\xDD",Z:"\u017D"};function dr(t){let e=t.split(/(\{\w+\})/).map(s=>/^\{\w+\}$/.test(s)?s:[...s].map(i=>lr[i]??i).join("")).join(""),n=t.replace(/\{\w+\}/g,"").length;return`[${e} ${"~".repeat(Math.max(2,Math.round(n*.35)))}]`}var Et={en:At,"en-XA":Object.fromEntries(Object.entries(At).map(([t,e])=>[t,dr(e)]))};function X(t,e,n={}){return((t&&(Et[t]??Et[t.split("-")[0]])||Et.en)[e]??At[e]).replace(/\{(\w+)\}/g,(i,r)=>r in n?String(n[r]):i)}var Qn=`
5
+ .wl-emergency { position: fixed; inset: 0; z-index: 40; pointer-events: none;
6
+ font-family: system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; }
7
+ .wl-emergency[hidden] { display: none; }
8
+ .wl-em { position: absolute; box-sizing: border-box; display: flex; overflow: hidden; pointer-events: auto; cursor: none; }
9
+ .wl-em-red { background: #8b0000; color: #fff; }
10
+ .wl-em-amber { background: #ffbf00; color: #000; }
11
+ .wl-em-takeover { inset: 0; flex-direction: column; padding: 0 0 3vmin; }
12
+ .wl-em-banner { left: 0; right: 0; bottom: 0; height: 14%; align-items: stretch; }
13
+ .wl-em-band { display: flex; flex-wrap: wrap; gap: 0 3vmin; align-items: baseline; margin: 0; padding: 2vmin 4vmin; font-size: 3.2vmin; font-weight: 700; line-height: 1.25; }
14
+ .wl-em-red .wl-em-band { background: #5c0000; color: #fff; }
15
+ .wl-em-amber .wl-em-band { background: #000; color: #ffbf00; }
16
+ .wl-em-test { margin: 0; padding: 1.2vmin 4vmin; background: #fff; color: #000; font-size: 3.2vmin; font-weight: 800; letter-spacing: 0.04em; line-height: 1.25; }
17
+ .wl-em-headline { margin: 3vmin 4vmin 2vmin; font-weight: 800; line-height: 1.1; overflow-wrap: anywhere; }
18
+ .wl-em-view { flex: 1 1 auto; min-height: 0; overflow: hidden; margin: 0 4vmin; }
19
+ .wl-em-text { display: flow-root; font-size: 3.8vmin; line-height: 1.3; }
20
+ .wl-em-text p { margin: 0 0 1.3em; overflow-wrap: anywhere; }
21
+ .wl-em-text p:last-child { margin-bottom: 0; }
22
+ .wl-em-area { font-style: italic; }
23
+ .wl-em-foot { display: flex; flex-wrap: wrap; gap: 1vmin 4vmin; justify-content: space-between; margin: 2vmin 4vmin 0; font-size: 3.2vmin; font-weight: 700; line-height: 1.25; }
24
+ .wl-em-badge { display: flex; flex-direction: column; justify-content: center; gap: 0.6vmin; flex: none; max-width: 26%; padding: 0 2.4vmin; font-size: 2.4vmin; font-weight: 700; line-height: 1.2; }
25
+ .wl-em-red .wl-em-badge { background: #5c0000; color: #fff; }
26
+ .wl-em-amber .wl-em-badge { background: #000; color: #ffbf00; }
27
+ .wl-em-badge .wl-em-test { padding: 0.4vmin 1vmin; font-size: 2.2vmin; }
28
+ .wl-em-banner .wl-em-view { align-self: center; height: 82%; margin: 0 2.4vmin; flex: 1 1 auto; }
29
+ .wl-em-banner .wl-em-text p { margin: 0; }
30
+ .wl-em-banner .wl-em-headline-inline { font-weight: 800; }
31
+ .wl-em-meta { display: flex; flex-direction: column; justify-content: center; align-items: flex-end; gap: 0.6vmin; flex: none; padding: 0 2.4vmin; font-size: 2.4vmin; font-weight: 700; line-height: 1.2; }
32
+ `,pr=`
33
+ :host { all: initial !important; display: block !important; position: fixed !important; inset: 0 !important;
34
+ z-index: 2147483647 !important; width: auto !important; height: auto !important; max-width: none !important; max-height: none !important;
35
+ margin: 0 !important; padding: 0 !important; border: 0 !important; background: transparent !important; overflow: visible !important;
36
+ pointer-events: none !important; }
37
+ :host::before, :host::after { content: none !important; display: none !important; }
38
+ :host::backdrop { display: none !important; }
39
+ `;async function cr(){let t=globalThis.AudioContext??globalThis.webkitAudioContext;if(!t)return!1;let e=new t;try{e.state==="suspended"&&await Promise.race([e.resume(),new Promise(s=>setTimeout(s,1e3))])}catch{}if(e.state!=="running")return e.close().catch(()=>{}),!1;let n=e.currentTime+.05;for(let s=0;s<3;s++){let i=n+s*.75,r=e.createGain();r.gain.setValueAtTime(0,i),r.gain.linearRampToValueAtTime(.4,i+.01),r.gain.setValueAtTime(.4,i+.49),r.gain.linearRampToValueAtTime(0,i+.5),r.connect(e.destination);for(let o of[853,960]){let a=e.createOscillator();a.frequency.value=o,a.connect(r),a.start(i),a.stop(i+.5)}}return setTimeout(()=>{e.close().catch(()=>{})},2500),!0}var Ue=class{constructor(e,n={}){c(this,"options",n);c(this,"root");c(this,"host");c(this,"tones",new Map);c(this,"takeovers");c(this,"banners");c(this,"keeping",!1);let s=e.ownerDocument;if(this.root=s.createElement("div"),this.root.id="wl-emergency",this.root.className="wl-emergency",this.root.hidden=!0,n.closed&&I){let i=this.host=W(F("div"));i.dataset.wyndlass="emergency",I.popover&&i.setAttribute("popover","manual");let r=s.createElement("style");r.textContent=pr+Qn,I.shadow(i).append(r,this.root),I.append(s.documentElement,i);let o=a=>{I.target(a)===i&&I.stop(a)};et(s.defaultView??window,"beforetoggle",o,!0),et(s.defaultView??window,"toggle",o,!0)}else{if(!s.getElementById("wl-emergency-style")){let i=W(s.createElement("style"));i.id="wl-emergency-style",i.textContent=Qn,s.head.append(i)}e.append(this.root)}this.takeovers=new We(this,"takeover"),this.banners=new We(this,"banner")}show(e){if((e.takeovers.length||e.banners.length)&&(this.root.hidden=!1),this.takeovers.set(e.takeovers),this.banners.set(e.banners),this.root.hidden=!e.takeovers.length&&!e.banners.length,!this.host)return;let n=this.takeovers.showing?"takeover":this.banners.showing?"banner":"";n?this.host.dataset.showing=n:delete this.host.dataset.showing,n?this.keep():this.leave()}turn(e){this.root.style.cssText=e}keep(){if(this.keeping)return;this.keeping=!0;let e=()=>{if(this.root.hidden){this.keeping=!1;return}I.frame(e),this.onTop()};I.frame(e),this.onTop()}leave(){try{I.popover&&I.matches(this.host,":popover-open")&&I.popover.hide(this.host)}catch{}}raise(){this.host&&!this.root.hidden&&this.onTop()}onTop(){let e=I,n=this.host,s=n.ownerDocument.documentElement;if((e.parent(n)!==s||e.last(s)!==n)&&e.append(s,n),!!e.popover)try{e.matches(n,":popover-open")&&e.popover.hide(n),e.popover.show(n)}catch{}}get covering(){return this.takeovers.showing}stop(){this.takeovers.set([]),this.banners.set([]),this.root.remove(),this.host?.remove()}sound(e){!e.tone||this.tones.has(e.id)||(this.tones.set(e.id,"played"),(this.options.tone??cr)().catch(()=>!1).then(n=>{n||(this.tones.set(e.id,"refused"),console.warn(`emergency ${e.id}: the page may not play sound, so its tone didn't sound`))}))}},We=class{constructor(e,n){c(this,"layer",e);c(this,"kind",n);c(this,"list",[]);c(this,"index",0);c(this,"page",0);c(this,"pages",1);c(this,"pageHeight",0);c(this,"since",0);c(this,"timer");c(this,"section");c(this,"text");c(this,"counter");c(this,"pageLabel")}get showing(){return!!this.section}get pageMs(){return this.layer.options.pageMs??12e3}get turnMs(){return this.layer.options.turnMs??2e4}set(e){let n=this.section?this.list[this.index]:void 0;if(this.list=e,!e.length){clearTimeout(this.timer),this.timer=void 0,this.section?.remove(),this.section=void 0;return}let s=n?e.findIndex(i=>i.id===n.id):-1;if(s<0){this.index=0,this.begin();return}this.index=s,this.label(),!this.timer&&e.length>1&&this.wait(Math.max(0,this.turnMs-(Date.now()-this.since)))}begin(){clearTimeout(this.timer),this.timer=void 0;let e=this.list[this.index];this.page=0,this.since=Date.now(),this.draw(e),this.kind==="takeover"&&this.layer.sound(e),this.pages>1?this.wait(this.pageMs):this.list.length>1&&this.wait(this.turnMs)}wait(e){clearTimeout(this.timer),this.timer=setTimeout(()=>{this.timer=void 0,this.next()},e)}next(){if(this.page+1<this.pages){this.turn(this.page+1),this.wait(this.pageMs);return}if(this.list.length>1){let e=this.turnMs-(Date.now()-this.since);if(e>0){this.wait(e);return}this.index=(this.index+1)%this.list.length,this.begin();return}this.pages>1&&(this.turn(0),this.wait(this.pageMs))}turn(e){this.page=e,this.text&&(this.text.style.transform=e?`translateY(${-e*this.pageHeight}px)`:""),this.label()}label(){let e=this.layer.options.locale?.();this.counter&&(this.counter.textContent=this.list.length>1?X(e,"emergency.turn",{n:this.index+1,count:this.list.length}):""),this.pageLabel&&(this.pageLabel.textContent=this.pages>1?X(e,"emergency.page",{n:this.page+1,count:this.pages}):"")}draw(e){let n=this.layer,s=n.root.ownerDocument,i=n.options.locale?.(),r=(b,M,w)=>{let P=s.createElement(b);return P.className=M,w!==void 0&&(P.textContent=w),P},o=Gn(e,i),a=r("section",`wl-em wl-em-${this.kind} wl-em-${e.severity==="Extreme"||e.severity==="Severe"?"red":"amber"}`);a.setAttribute("role","alert"),a.dataset.emergency=e.id;let l=Xn(e,i);l&&(a.lang=l);let p=r("span","wl-em-severity",X(i,`emergency.severity.${e.severity}`)),u=e.senderName?r("span","wl-em-sender",e.senderName):void 0,d=Yn(e)?r("p","wl-em-test",X(i,"emergency.test")):void 0,m=r("div","wl-em-text"),g=r("div","wl-em-view"),k=[o.instruction,o.description].filter(b=>!!b).map(b=>r("p","",b)),f=e.areaDesc?r("p","wl-em-area",X(i,"emergency.area",{area:e.areaDesc})):void 0,v=r("span","wl-em-until",X(i,"emergency.until",{time:hr(e.expires,i,n.options.timeZone?.(),n.options.now?.()??Date.now())}));if(this.counter=r("span","wl-em-count"),this.pageLabel=r("span","wl-em-page"),this.kind==="takeover"){let b=r("p","wl-em-band");b.append(p,...u?[u]:[]);let M=r("h1","wl-em-headline",o.headline);m.append(...k,...f?[f]:[]),g.append(m);let w=r("div","wl-em-foot");w.append(v,this.pageLabel,this.counter),a.append(b,...d?[d]:[],M,g,w)}else{let b=r("div","wl-em-badge");b.append(...d?[d]:[],p,...u?[u]:[]);let M=r("p","wl-em-headline-inline",o.headline);m.append(M,...k,...f?[f]:[]),g.append(m);let w=r("div","wl-em-meta");w.append(v,this.pageLabel,this.counter),a.append(b,g,w)}this.section?.remove(),n.root.append(a),this.section=a,this.text=m,this.kind==="takeover"?ur(a.querySelector(".wl-em-headline"),n.root):m.style.fontSize=`${Math.max(12,Math.floor(a.clientHeight*.82/2/1.3))}px`,this.paginate(g,m),this.label()}paginate(e,n){let s=parseFloat(getComputedStyle(n).lineHeight)||16,i=Math.max(1,Math.floor(e.clientHeight/s));this.pageHeight=i*s,this.kind==="takeover"&&(e.style.flex="none"),e.style.height=`${this.pageHeight}px`,this.pages=Math.max(1,Math.ceil((n.getBoundingClientRect().height-1)/this.pageHeight))}};function ur(t,e){let n=e.clientHeight,s=Math.max(12,Math.round(Math.min(e.clientWidth,n)*.07));for(t.style.fontSize=`${s}px`;s>12&&t.getBoundingClientRect().height>n*.4;)s=Math.max(12,Math.floor(s*.92)),t.style.fontSize=`${s}px`}function hr(t,e,n,s){let i=new Date(t),r=(a,l)=>{try{return new Intl.DateTimeFormat(e,{...a,timeZone:n}).format(l)}catch{return new Intl.DateTimeFormat("en",{...a,timeZone:"UTC"}).format(l)}},o=a=>r({year:"numeric",month:"2-digit",day:"2-digit"},a);return r(o(i)===o(new Date(s))?{hour:"numeric",minute:"2-digit"}:{weekday:"short",hour:"numeric",minute:"2-digit"},i)}var St={"Intl.DateTimeFormat":"date formatters (Intl.DateTimeFormat)","Intl.NumberFormat":"number formatters (Intl.NumberFormat)","Intl.Collator":"collators (Intl.Collator)","Intl.PluralRules":"plural rules (Intl.PluralRules)","Intl.RelativeTimeFormat":"relative time formatters (Intl.RelativeTimeFormat)","Intl.ListFormat":"list formatters (Intl.ListFormat)","Intl.DisplayNames":"display names (Intl.DisplayNames)","Intl.Segmenter":"segmenters (Intl.Segmenter)",toLocale:"formatters, through toLocaleString, toLocaleDateString or toLocaleTimeString with options",canvas:"canvases",context:"canvas contexts",bitmap:"image bitmaps (createImageBitmap)",objectUrl:"object URLs (URL.createObjectURL)",worker:"workers",listener:"listeners on window or document"};function es(t){let e=0,n=s=>{for(let i=s.firstChild;i;i=i.nextSibling){if(i.nodeType===1){e++;let r=i.shadowRoot;r&&n(r)}n(i)}};return n(t),e}function ts(t,e){let n={},s=u=>{n[u]=(n[u]??0)+1},i=(u,d)=>new Proxy(u,{construct:(m,g,k)=>(s(d),Reflect.construct(m,g,k)),apply:(m,g,k)=>(s(d),Reflect.apply(m,g,k))}),r=t.Intl;for(let u of["DateTimeFormat","NumberFormat","Collator","PluralRules","RelativeTimeFormat","ListFormat","DisplayNames","Segmenter"]){let d=r[u];d&&(r[u]=i(d,`Intl.${u}`))}let o=(u,d,m)=>{let g=u&&u[d];typeof g=="function"&&(u[d]=function(...k){let f=Reflect.apply(g,this,k),v=m(k,this,f);return v&&s(v),f})},a=u=>u[1]!==void 0?"toLocale":null;for(let u of["toLocaleString","toLocaleDateString","toLocaleTimeString"])o(t.Date?.prototype,u,a);o(t.Number?.prototype,"toLocaleString",a),o(t.Document?.prototype,"createElement",u=>String(u[0]).toLowerCase()==="canvas"?"canvas":null),t.OffscreenCanvas&&(t.OffscreenCanvas=i(t.OffscreenCanvas,"canvas"));let l=new WeakSet,p=(u,d,m)=>!m||typeof m!="object"||l.has(m)?null:(l.add(m),"context");return o(t.HTMLCanvasElement?.prototype,"getContext",p),o(t.OffscreenCanvas?.prototype,"getContext",p),o(t,"createImageBitmap",()=>"bitmap"),o(t.URL,"createObjectURL",()=>"objectUrl"),t.Worker&&(t.Worker=i(t.Worker,"worker")),o(t.EventTarget?.prototype,"addEventListener",(u,d)=>d===void 0||d===t||d===t.document?"listener":null),()=>({kinds:{...n},nodes:e()})}var ns=["none","fade","scale","slide-up","slide-left"],_e=[["1920 \xD7 1080",1920,1080],["1080 \xD7 1920",1080,1920],["3840 \xD7 2160",3840,2160]],mr=[.25,.5,1,2,4],ye=3e4,as=5e3,fr={id:"med_preview",version:1},h={width:1920,height:1080,props:{},touched:new Set,playing:!0,speed:1,t:0,enter:"none",exit:"none",clipMs:800,timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,locale:navigator.language||"en-US",screen:{name:"Preview screen",lat:49.9,lon:-97.14,fields:"{}"},samples:{},tables:new Map,people:[],emergency:"none"},S={frames:"",tables:{},controller:{status:{},events:{}}},ne,gr={"connection.changed":{type:"connection.changed",seq:0,at:"2026-10-01T14:02:00Z",connection:"offline"},"audio.changed":{type:"audio.changed",seq:0,at:"2026-10-01T14:03:00Z",audio:{volume:.3,muted:!0},by:{kind:"player"}}},K={people:new Set,player:new Map},ke=[],be=new Map,Lt=new Map,Ct=new Set,qe=0,T=null,It=null,Rt=null,ls=-1,V=null,ge=0,se={wall:0,t:0},ze=0,Ke=[],D=t=>document.getElementById(t),we=D("stage"),yr=D("controls"),ss=D("report"),Tt=D("made"),br=ts(window,()=>es(we)),Nt={kinds:{},nodes:0};addEventListener("message",t=>{let e=t.data;S.frames&&t.origin==="null"&&e?.wyndlassPreview==="made"&&e.made&&typeof e.made=="object"&&(Nt=e.made)});var ds=500,is=3,H={last:null,reads:[],said:""};function y(t,e={},...n){let s=document.createElement(t);for(let[i,r]of Object.entries(e))r==null||r===!1||(i.startsWith("on")&&typeof r=="function"?s.addEventListener(i.slice(2),r):i==="value"||i in s&&typeof r!="string"?s[i]=r:s.setAttribute(i,r===!0?"":String(r)));for(let i of n)i!=null&&s.append(i);return s}var wr=0;function A(t,e,n=!1){return e.id||(e.id=`c${++wr}`),n?y("div",{class:"field inline"},e,y("label",{for:e.id},t)):y("div",{class:"field"},y("label",{for:e.id},t),e)}function q(t,e,n){let s=y("select",{onchange:()=>n(s.value)},...t.map(i=>{let[r,o]=Array.isArray(i)?i:[i,i];return y("option",{value:r,selected:r===e},o)}));return s}async function rs(){let[t,e,n,s]=await Promise.all([fetch("/app.json").then(o=>o.json()),fetch("/app.js"),fetch("/samples.json").then(o=>o.json()),fetch("/config.json").then(o=>o.json())]);S=s,S.controller.status=ne??(ne=S.controller.status),ne.emergency??(ne.emergency={showing:"none",messages:[]}),S.controller.events={...S.controller.events,...gr};for(let[o,a]of Object.entries(S.tables))h.tables.has(Ze(o))||Ot(o,a);T=t,ls=Number(e.headers.get("x-preview-version")??-1),Rt=e.ok?null:await e.text(),It=e.ok?new Uint8Array(await e.arrayBuffer()):null;let i=T.params??{},r={};for(let[o,a]of Object.entries(i))r[o]=h.touched.has(o)?h.props[o]:a.default;h.props=r;for(let[o,a]of Object.entries(n))o in h.samples||(h.samples[o]=a);Dt(),document.title=`${T.name}: Wyndlass app preview`,D("title").textContent=T.name,D("subtitle").textContent=`${T.id} ${T.version}`}var Ze=t=>`tbl_${(t.replace(/\.(json|csv)$/i,"").toLowerCase().replace(/[^a-z0-9]+/g,"")||"table").slice(0,26).padEnd(26,"0")}`;function vr(t){let e=[],n=[],s="",i=!1;for(let r=0;r<t.length;r++){let o=t[r];if(i){o==='"'&&t[r+1]==='"'?(s+='"',r++):o==='"'?i=!1:s+=o;continue}o==='"'?i=!0:o===","?(n.push(s),s=""):o===`
40
+ `||o==="\r"?(o==="\r"&&t[r+1]===`
41
+ `&&r++,n.push(s),e.push(n),n=[],s=""):s+=o}return(s||n.length)&&(n.push(s),e.push(n)),e.filter(r=>r.some(o=>o!==""))}function kr(t,e){let n="";for(let i of t.normalize("NFD").replace(/\p{Mn}/gu,""))/[A-Za-z0-9]/.test(i)?n+=i.toLowerCase():n&&!n.endsWith("_")&&(n+="_");n=n.replace(/^_+|_+$/g,""),/^[a-z]/.test(n)||(n=`c_${n}`),n=n.length>60?n.slice(0,60).replace(/_+$/,""):n;let s=n;for(let i=2;[...e].some(r=>r.toLowerCase()===s);i++)s=`${n}_${i}`;return e.add(s),s}function ps(t,e){let n=Ze(t),s=(r,o)=>({table:n,version:1,rows:o,columns:r.map(({key:a,label:l})=>({key:a,label:l,type:o.length&&o.every(p=>p[a]===""||p[a]===void 0||Number.isFinite(Number(p[a])))?"number":"text"}))});if(/\.csv$/i.test(t)){let[r=[],...o]=vr(e),a=new Set,l=r.map(d=>({label:d.trim(),key:kr(d.trim()||"column",a)})),p=o.map(d=>Object.fromEntries(l.map((m,g)=>[m.key,d[g]??""]))),u=s(l,p);for(let d of u.columns)if(d.type==="number")for(let m of p)m[d.key]!==""&&(m[d.key]=Number(m[d.key]));return u}let i=JSON.parse(e);if(i&&typeof i=="object"&&"columns"in i&&"rows"in i)return{...i,table:n};if(Array.isArray(i))return s([...new Set(i.flatMap(r=>Object.keys(r)))].map(r=>({key:r,label:r})),i);throw new Error(`${t} is not a table: a snapshot, an array of rows, or CSV`)}function Ot(t,e){Lt.set(t,e);try{h.tables.set(Ze(t),$e(ps(t,e))),be.delete(t)}catch(n){be.set(t,String(n.message))}}function cs(t,e,n){let s=h.tables.get(t);if(!s)return;h.tables.set(t,$e({...s,version:s.version+1,rows:e,...n?{columns:n}:{}}));for(let o of[...Ct])o([t]);let i=document.querySelector(`[data-testid="table"][data-table="${t}"]`);i&&(i.textContent=fs(h.tables.get(t)));let r=document.querySelector(`textarea[data-rows="${t}"]`);r&&document.activeElement!==r&&(r.value=JSON.stringify(e,null,2))}async function xr(){let t=await fetch("/config.json").then(n=>n.json()),e=!1;for(let[n,s]of Object.entries(t.tables)){if(Lt.get(n)===s)continue;let i=Ze(n);if(!h.tables.has(i)){Ot(n,s),e=!0;continue}Lt.set(n,s);try{let r=ps(n,s);be.delete(n),cs(i,r.rows,r.columns)}catch(r){be.set(n,String(r.message)),ie()}}e&&(Dt(),ie(),await ve())}function Dt(){let t=[...h.tables.keys()][0];if(!(!t||!T))for(let[e,n]of Object.entries(T.params??{}))n.type==="datatable"&&!h.props[e]&&(h.props[e]=t,h.touched.add(e))}function Mr(){return{measuring:!0,now:()=>[{source:"preview",present:h.people.length,longestDwellS:h.people.length?Math.round((Date.now()-Math.min(...h.people))/1e3):0}],on(t){return K.people.add(t),()=>{K.people.delete(t)}}}}function Pt(t){if(t==="enter"&&h.people.push(Date.now()),t==="leave"&&!h.people.length)return;let e=t==="leave"?h.people.shift():0,n=t==="leave"?{type:"leave",source:"preview",dwellS:Math.round((Date.now()-e)/1e3)}:{type:t,source:"preview"};for(let s of K.people)s([n]);D("people-count").textContent=`${h.people.length} in view`}var Er={status:()=>S.controller.status,on(t,e){let n=K.player.get(t)??new Set;return n.add(e),K.player.set(t,n),()=>{n.delete(e)}},async call(t,e,n){return ke.push(`controller: ${n.app??"the app"} called ${t}, not applied (a preview)`),Q({}),{ok:!1,code:"PREVIEW",message:"a preview"}}},Ar={time:"time.now",play:"player.play",pause:"player.pause",stop:"player.stop",next:"player.next",previous:"player.previous",finish:"app.finish"};function Sr(t){let e=s=>i=>{throw ke.push(`controller: ${s} refused, ${i.code??"error"}: ${i.message}`),Q({}),i},n={...t,call:(s,i)=>t.call(s,i).catch(e(s))};for(let[s,i]of Object.entries(Ar))n[s]=()=>t[s]().catch(e(i));return n}function $t(t){Tr(t);for(let e of[t.type,"*"])for(let n of K.player.get(e)??[])n(t)}function Tr(t){let e=ne??{};switch(t.type){case"state.changed":e.state=t.state;break;case"connection.changed":e.connection=t.connection;break;case"audio.changed":e.audio=t.audio;break;case"display.changed":e.display=t.display;break;case"emergency.changed":e.emergency=t.emergency;break;case"item.start":e.now=[{zone:t.zone,item:t.item,blob:t.blob,contentType:t.contentType,startedAt:t.startedAt,...t.durationMs===void 0?{}:{durationMs:t.durationMs}}];break;case"item.end":e.now=(e.now??[]).filter(n=>n.item.id!==t.item.id);break}}var Ve=null;function Pr(){Ve?.stop(),Ve=null;let t=we.getBoundingClientRect(),e=Math.min(t.width/h.width,t.height/h.height),n=h.width*e,s=h.height*e,i=y("iframe",{"data-testid":"emergency-frame",title:"Emergency messages",tabindex:"-1",style:`position:absolute;left:${(t.width-n)/2}px;top:${(t.height-s)/2}px;width:${n}px;height:${s}px;border:0;pointer-events:none;z-index:40`});we.append(i);let r=i.contentDocument;r.open(),r.write(`<!doctype html><html style="color-scheme:${getComputedStyle(document.documentElement).colorScheme};background:transparent"><head></head><body style="margin:0;background:transparent"></body></html>`),r.close(),Ve=new Ue(r.body,{locale:()=>h.locale,timeZone:()=>h.timeZone}),us()}function Lr(t){let e=Date.now();return{v:0,id:`emg_01jd00000000000000000000${t==="banner"?"bb":"tt"}`,tenantId:"ten_preview",source:"manual",msgType:"Alert",status:"Test",severity:t==="banner"?"Moderate":"Extreme",presentation:t,senderName:"wyndlass-app preview",headline:t==="banner"?"A test banner from the preview":"A test takeover from the preview",instruction:"What the app does under it is its own: lower its sound, or pause what calls for attention.",effective:new Date(e-6e4).toISOString(),expires:new Date(e+36e5).toISOString(),targets:{all:!0}}}function us(){let t=h.emergency==="none"?[]:[Lr(h.emergency)];Ve?.show({takeovers:t.filter(e=>e.presentation==="takeover"),banners:t.filter(e=>e.presentation==="banner")})}function Cr(t){h.emergency=t;let e=t==="none"?[]:[{source:"manual",severity:t==="banner"?"Moderate":"Extreme",presentation:t,test:!0}];$t({type:"emergency.changed",seq:0,at:new Date().toISOString(),emergency:{showing:t,messages:e}}),us()}function Ir(){let t=D("command-name").value.trim(),e=D("command-argument").value.trim(),n;try{n=e?JSON.parse(e):void 0}catch{return}t&&(ke.push(`controller: the command ${t} sent to the app`),Q({}),$t({type:"app.command",seq:0,at:new Date().toISOString(),name:t,...n?{argument:n}:{},by:{kind:"remote",principal:"user:preview"}}))}function Rr(){return new He({base:()=>location.origin,token:()=>{},fetch:(async t=>{let e=new URL(String(t),location.origin);if(e.pathname.endsWith("/v0/image"))return fetch("/picture.svg");let n=decodeURIComponent(e.pathname.split("/").pop()??"");if(!(n in h.samples))return new Response(`the preview has no answer for ${n}: declare it in app.json's data`,{status:404});let s=Date.now();return new Response(JSON.stringify({source:n,params:Object.fromEntries(e.searchParams),fetchedAt:new Date(s).toISOString(),expiresAt:new Date(s+36e5).toISOString(),stale:!1,data:h.samples[n]}))})})}function Nr(){let t=[...h.enter!=="none"?[{element:"app",kind:"enter",preset:h.enter,start:{kind:"at",ms:0},durationMs:h.clipMs,easing:"ease-out"}]:[],...h.exit!=="none"?[{element:"app",kind:"exit",preset:h.exit,start:{kind:"at",ms:ye-h.clipMs},durationMs:h.clipMs,easing:"ease-in"}]:[]];return{profiles:[{id:"preview",width:h.width,height:h.height}],elements:[{type:"app",id:"app",frame:{x:0,y:0,w:h.width,h:h.height},app:fr,props:h.props,...T.slots&&h.tables.size?{binding:{table:[...h.tables.keys()][0]}}:{},...T.capabilities?.sensors?{sensors:T.capabilities.sensors}:{},appInfo:{id:T.id,element:T.element,player:T.capabilities?.player==="control"?"control":"read"}}],animation:{duration:{kind:"fixed",ms:ye},clips:t}}}async function ve(){let t=++ge;if(cancelAnimationFrame(ze),V?.dispose(),V=null,we.replaceChildren(),Ke.length=0,ke.length=0,H.last=null,H.reads=[],Nt={kinds:{},nodes:0},!T||!It){Q({building:!0});return}let e={};try{e=JSON.parse(h.screen.fields||"{}")}catch{}let n=It,s={deviceId:"preview",slide:()=>null,playlist:()=>null,font:()=>{},app:()=>({hash:`preview-${ge}`,bytes:n}),data:Rr(),place:{lat:h.screen.lat,lon:h.screen.lon},screen:{name:h.screen.name,type:"preview",tags:[],path:[{name:"Preview",kind:"organization"}],fields:e},timeZone:h.timeZone,locale:h.locale,preview:!1,snapshot:a=>h.tables.get(a)??null,onSnapshots:a=>(Ct.add(a),()=>{Ct.delete(a)}),...S.frames?{}:{...T.capabilities?.sensors?.includes("impressions")?{impressions:Mr()}:{},controllerFor:a=>Sr(Jn(Er,a))}};K.people.clear(),K.player.clear();let i=performance.now(),r=!1;qe++;let o=new te(Nr(),s,we,{appDeadlineMs:as,...S.frames?{isolate:{frames:S.frames,apps:()=>!0}}:{},onAppLate:()=>{r=!0},onApp:a=>{t===ge&&(Ke.push(`app.failed: ${a.reason}${a.error?` (${a.error})`:""}`),Q({}))}});V=o,S.frames||Pr(),Q({waiting:!0}),await o.ready,t===ge&&(Q({readyMs:r?void 0:Math.round(performance.now()-i),late:r}),await o.start(Date.now()-h.t),t===ge&&(o.seek(h.t),se={wall:Date.now(),t:h.t},Or(),Dr()))}function Or(){cancelAnimationFrame(ze);let t=()=>{if(V){if(h.playing){if(h.t=se.t+(Date.now()-se.wall)*h.speed,h.t>=ye){h.t=0,ve();return}V.seek(h.t)}D("clock-seek").value=String(Math.round(h.t)),D("clock-time").textContent=`${(h.t/1e3).toFixed(1)} s`,ze=requestAnimationFrame(t)}};ze=requestAnimationFrame(t)}function Dr(){let t=D("pages"),e=V?.paging("app")??null;t.replaceChildren(e&&e.count>1?y("div",{},y("p",{"data-testid":"pages"},`${e.count} pages of ${(e.ms/1e3).toFixed(1)} s`),y("div",{class:"row"},...Array.from({length:e.count},(n,s)=>y("button",{onclick:()=>hs(s*e.ms)},`Page ${s+1}`)))):y("p",{"data-testid":"pages"},"One page"))}function hs(t){h.t=Math.max(0,Math.min(ye-1,t)),se={wall:Date.now(),t:h.t},V?.seek(h.t)}function Q(t){let e=[];if(Rt?e.push(y("pre",{"data-testid":"build-error"},`The module does not build:
42
+ ${Rt}`)):t.building&&e.push(y("span",{},"Building\u2026")),t.waiting&&e.push(y("span",{"data-testid":"ready"},"Waiting for ready()\u2026")),t.late)e.push(y("span",{class:"late","data-testid":"ready"},`Late: not ready within ${as/1e3} s. A screen reports app.failed (late) and shows the app as it is.`));else if(t.readyMs!==void 0)e.push(y("span",{class:"ok","data-testid":"ready"},`Ready in ${t.readyMs} ms`));else if(!t.waiting&&!t.building){let n=ss.querySelector('[data-testid="ready"]');n&&e.push(n)}for(let n of Ke)e.push(y("span",{class:"failed","data-testid":"failure"},n));S.frames&&Ke.some(n=>/SecurityError/.test(n))&&e.push(y("span",{class:"warn","data-testid":"frame-why"},"In its frame, as in the CMS, an app has no storage, cookies or parent page: localStorage, sessionStorage, document.cookie and parent's document throw SecurityError. Keep nothing there that matters; a screen may lose it too."));for(let n of ke.slice(-5))e.push(y("span",{"data-testid":"command"},n));qe&&e.push(y("span",{"data-testid":"made-times"},`Made ${qe===1?"once":`${qe} times`}: at each start of its layout, and when its code, params or screen change. A table's change reaches it as it plays.`)),ss.replaceChildren(...e)}function $r(){let t=S.frames?Nt:br();if(H.last&&h.playing&&V){let o={};for(let[a,l]of Object.entries(t.kinds)){let p=l-(H.last.kinds[a]??0);p>0&&(o[a]=p)}H.reads=[...H.reads,o].slice(-is)}H.last=t;let e=H.reads.length===is?Object.keys(St).filter(o=>H.reads.every(a=>a[o])):[],n=o=>Math.round(H.reads.reduce((a,l)=>a+(l[o]??0),0)*1e3/(ds*H.reads.length)),s=e.map(o=>[o,`Makes ${n(o)} ${St[o]} a second while it plays. ${o==="listener"?"Add a listener once, in mount(), and take it off when the app goes":"Make it once, in mount() or with useMemo, never in draw() or a render"}: one made at every frame holds memory a screen frees late, and can run it out.`]),i=`${e.length?"":"Nothing made at every frame. "}${t.nodes} DOM nodes in the app.`,r=JSON.stringify(s);if(r===H.said&&Tt.firstChild){Tt.querySelector('[data-testid="made-counts"]').textContent=i;return}H.said=r,Tt.replaceChildren(...s.map(([o,a])=>y("span",{class:"warn","data-testid":"made","data-kind":o},a)),y("span",{"data-testid":"made-counts"},i))}function jr(){let t=Object.entries(T?.params??{}).find(([,n])=>n.type==="datatable")?.[0],e=T?.slots?[...h.tables.keys()][0]:t?h.props[t]:void 0;return typeof e=="string"?h.tables.get(e):void 0}var ms=t=>t.label&&t.label!==t.key?`${t.label} (${t.key})`:t.key,fs=t=>`${t.table}: ${t.rows.length} rows, ${t.columns.map(ms).join(", ")}`;function Fr(t,e){let n=h.props[t],s=r=>{h.props[t]=r,h.touched.add(t),gs(),N()},i=e.label??t;if(e.type==="boolean")return A(i,y("input",{type:"checkbox",checked:n===!0,onchange:r=>s(r.target.checked)}),!0);if(e.type==="enum"){let r=(e.values??[]).map(o=>o&&typeof o=="object"?[String(o.value),String(o.label??o.value)]:String(o));return A(i,q(r,String(n??""),s))}if(e.type==="number")return A(i,y("input",{type:"number",value:n===void 0?"":String(n),min:e.min,max:e.max,step:e.step??"any",onchange:r=>{let o=r.target.value;s(o===""?void 0:Number(o))}}));if(["string","text","color","url","datetime","duration","secret"].includes(e.type)){let r=e.type==="text"?y("textarea",{value:String(n??""),onchange:o=>s(o.target.value)}):y("input",{type:"text",value:String(n??""),placeholder:e.type==="color"?"#rrggbb or #rrggbbaa":void 0,onchange:o=>s(o.target.value)});return A(i,r)}return e.type==="datatable"?A(i,q(["",...h.tables.keys()],String(n??""),s)):e.type==="column"?A(i,q(["",...(jr()?.columns??[]).map(r=>[r.key,ms(r)])],String(n??""),s)):A(`${i} (JSON)`,y("textarea",{value:n===void 0?"":JSON.stringify(n,null,2),onchange:r=>{let o=r.target.value.trim();try{s(o?JSON.parse(o):void 0)}catch{s(o)}}}))}function gs(){let t=D("params"),e=T?.params??{},n=new Set(Kn(e,h.props));t.replaceChildren(...Object.entries(e).filter(([s])=>n.has(s)).map(([s,i])=>Fr(s,i))),t.children.length||t.append(y("p",{},"No params."))}var os;function N(){clearTimeout(os),os=setTimeout(()=>{ve()},150)}function ie(){let t=!_e.some(([,o,a])=>o===h.width&&a===h.height),e=y("input",{type:"number",value:String(h.width),min:64,max:7680,onchange:o=>{h.width=Number(o.target.value)||1920,N()}}),n=y("input",{type:"number",value:String(h.height),min:64,max:7680,onchange:o=>{h.height=Number(o.target.value)||1080,N()}}),s=y("button",{type:"button","aria-pressed":String(!h.playing),onclick:()=>{h.playing=!h.playing,s.textContent=h.playing?"Pause":"Play",s.setAttribute("aria-pressed",String(!h.playing)),se={wall:Date.now(),t:h.t}}},h.playing?"Pause":"Play"),i=y("input",{id:"clock-seek",type:"range",min:0,max:ye,step:100,value:String(h.t),oninput:o=>hs(Number(o.target.value))}),r=[y("h2",{},"Screen"),A("Size",q([..._e.map(([o])=>o),"Custom"],t?"Custom":_e.find(([,o,a])=>o===h.width&&a===h.height)[0],o=>{let a=_e.find(([l])=>l===o);a&&(h.width=a[1],h.height=a[2]),ie(),N()})),t?y("div",{class:"row"},A("Width",e),A("Height",n)):null,y("div",{class:"row"},A("Time zone",y("input",{type:"text",value:h.timeZone,onchange:o=>{h.timeZone=o.target.value||"UTC",N()}})),A("Locale",y("input",{type:"text",value:h.locale,onchange:o=>{h.locale=o.target.value||"en-US",N()}}))),A("Screen's name",y("input",{type:"text",value:h.screen.name,onchange:o=>{h.screen.name=o.target.value,N()}})),y("div",{class:"row"},A("Latitude",y("input",{type:"number",step:"any",value:String(h.screen.lat),onchange:o=>{h.screen.lat=Number(o.target.value),N()}})),A("Longitude",y("input",{type:"number",step:"any",value:String(h.screen.lon),onchange:o=>{h.screen.lon=Number(o.target.value),N()}}))),A("Screen's fields (JSON)",y("textarea",{value:h.screen.fields,onchange:o=>{h.screen.fields=o.target.value,N()}})),y("h2",{},"Clock"),y("div",{class:"row"},s,A("Speed",q(mr.map(o=>[String(o),`${o}\xD7`]),String(h.speed),o=>{se={wall:Date.now(),t:h.t},h.speed=Number(o)})),y("span",{id:"clock-time"},"0.0 s")),A("Time in the layout",i),y("h2",{},"Enter and exit"),y("div",{class:"row"},A("Enter",q(ns,h.enter,o=>{h.enter=o,N()})),A("Exit",q(ns,h.exit,o=>{h.exit=o,N()}))),A("Each lasts (ms)",y("input",{type:"number",min:0,max:5e3,step:100,value:String(h.clipMs),onchange:o=>{h.clipMs=Number(o.target.value)||0,N()}})),y("div",{id:"pages"}),y("h2",{},"Params"),y("div",{id:"params"}),S.frames?y("p",{"data-testid":"framed"},`In a frame on ${S.frames}, as in the CMS: no storage, cookies, parent page, controller or impressions.`):null,y("h2",{},"Tables"),...[...h.tables.values()].flatMap(o=>[y("p",{"data-testid":"table","data-table":o.table},fs(o)),A(`${o.table}'s rows (JSON)`,y("textarea",{"data-rows":o.table,value:JSON.stringify(o.rows,null,2),rows:6,onchange:a=>{try{let l=JSON.parse(a.target.value);Array.isArray(l)&&cs(o.table,l)}catch{}}}))]),...[...be].map(([o,a])=>y("p",{class:"failed","data-testid":"table-error"},`${o}: ${a}`)),A("Add a table (JSON or CSV)",y("input",{type:"file",accept:".json,.csv",onchange:async o=>{let a=o.target.files?.[0];a&&(Ot(a.name,await a.text()),Dt(),ie(),N())}})),...T?.capabilities?.sensors?.includes("impressions")&&!S.frames?[y("h2",{},"People at the screen"),y("div",{class:"row"},y("button",{type:"button",onclick:()=>Pt("enter")},"Someone arrives"),y("button",{type:"button",onclick:()=>Pt("look")},"Someone looks"),y("button",{type:"button",onclick:()=>Pt("leave")},"Someone leaves")),y("p",{id:"people-count"},`${h.people.length} in view`)]:[],...S.frames?[]:[y("h2",{},"The player's controller"),y("p",{},`The app may ${T?.capabilities?.player==="control"?"read it and call its commands":"read it (capabilities.player: read)"}. Commands are not applied here.`),...Object.keys(S.controller.events).length?[A("Event",q(Object.keys(S.controller.events),Object.keys(S.controller.events)[0],o=>{D("event-json").value=JSON.stringify(S.controller.events[o],null,2)})),A("Its JSON",y("textarea",{id:"event-json",rows:6,value:JSON.stringify(Object.values(S.controller.events)[0],null,2)})),y("button",{type:"button","data-testid":"send-event",onclick:()=>{try{$t(JSON.parse(D("event-json").value))}catch{}}},"Send to the app")]:[],A("A command's name",y("input",{id:"command-name",value:"showSpecial"})),A("Its argument (JSON, or nothing)",y("textarea",{id:"command-argument",rows:3,value:JSON.stringify({sku:"1234"})})),y("button",{type:"button","data-testid":"send-command",onclick:Ir},"Send the command"),A("Emergency message (a Test one, shown over the app as a screen shows it)",q([["none","None"],["banner","A banner"],["takeover","A takeover"]],h.emergency,o=>Cr(o)))],y("h2",{},"Data"),...Object.keys(h.samples).map(o=>A(`${o} answer's data (JSON)`,y("textarea",{"data-source":o,value:JSON.stringify(h.samples[o],null,2),rows:8,onchange:a=>{try{h.samples[o]=JSON.parse(a.target.value),N()}catch{}}}))),Object.keys(h.samples).length?null:y("p",{},"The app declares no data source with a sample (weather, news or calendar).")];yr.replaceChildren(...r.filter(o=>o!==null)),gs()}async function Hr(){await rs(),ie(),setInterval($r,ds),await ve();let t=new EventSource("/events"),e=()=>{rs().then(()=>(ie(),ve()))};t.addEventListener("hello",n=>{JSON.parse(n.data).version!==ls&&e()}),t.addEventListener("reload",e),t.addEventListener("tables",()=>{xr()}),window.addEventListener("resize",()=>N())}Hr();})();
package/dist/react.d.ts CHANGED
@@ -74,4 +74,10 @@ export declare function usePlaying(): Followed<"now">;
74
74
  * WP-0150 decision 3), from mount until the component goes. The handler may change between renders: the latest is called.
75
75
  */
76
76
  export declare function useCommand(name: string, handler: (argument: Record<string, unknown> | undefined) => void): void;
77
+ /**
78
+ * Emergency messages at the screen (WP-0150 decision 5): what shows (`none`, `banner` or `takeover`) and each message's
79
+ * facts, never its words; the component renders when they change. Null without a controller, or before the screen has
80
+ * said what it holds. Under a banner the app plays on below it: it may lower its sound or pause what calls for attention.
81
+ */
82
+ export declare function useEmergency(): Followed<"emergency">;
77
83
  export {};
package/dist/react.js CHANGED
@@ -195,3 +195,9 @@ export function useCommand(name, handler) {
195
195
  latest.current = handler;
196
196
  useEffect(() => onCommand(app, name, argument => latest.current(argument)), [app, name]);
197
197
  }
198
+ /**
199
+ * Emergency messages at the screen (WP-0150 decision 5): what shows (`none`, `banner` or `takeover`) and each message's
200
+ * facts, never its words; the component renders when they change. Null without a controller, or before the screen has
201
+ * said what it holds. Under a banner the app plays on below it: it may lower its sound or pause what calls for attention.
202
+ */
203
+ export function useEmergency() { return useFollowed("emergency"); }
package/dist/signals.d.ts CHANGED
@@ -31,3 +31,11 @@ export declare function connectionSignal(app: WyndlassApp): ReadonlySignal<Playe
31
31
  export declare function audioSignal(app: WyndlassApp): ReadonlySignal<NonNullable<PlayerAPIStatus["audio"]> | null>;
32
32
  /** The items playing (the status's `now`), as a read-only signal read again on each `item.start` and `item.end`; null without a controller. */
33
33
  export declare function nowSignal(app: WyndlassApp): ReadonlySignal<PlayerAPIStatus["now"] | null>;
34
+ /**
35
+ * Emergency messages at the screen, as a read-only signal set on each `emergency.changed` (WP-0150 decision 5): what
36
+ * shows (`none`, `banner` or `takeover`), and of each message in force its source, severity, presentation, event,
37
+ * categories and whether it is a test. Never its words: the screen shows them, over the app. Null without a controller,
38
+ * or before the screen has said what it holds. Under a banner the app plays on below it: it may lower its sound, pause
39
+ * what calls for attention, or show the way out. It cannot move or cover the emergency layer.
40
+ */
41
+ export declare function emergencySignal(app: WyndlassApp): ReadonlySignal<NonNullable<PlayerAPIStatus["emergency"]> | null>;
package/dist/signals.js CHANGED
@@ -59,3 +59,13 @@ export function audioSignal(app) {
59
59
  export function nowSignal(app) {
60
60
  return followed(app, "now");
61
61
  }
62
+ /**
63
+ * Emergency messages at the screen, as a read-only signal set on each `emergency.changed` (WP-0150 decision 5): what
64
+ * shows (`none`, `banner` or `takeover`), and of each message in force its source, severity, presentation, event,
65
+ * categories and whether it is a test. Never its words: the screen shows them, over the app. Null without a controller,
66
+ * or before the screen has said what it holds. Under a banner the app plays on below it: it may lower its sound, pause
67
+ * what calls for attention, or show the way out. It cannot move or cover the emergency layer.
68
+ */
69
+ export function emergencySignal(app) {
70
+ return followed(app, "emergency");
71
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wyndlass/app-sdk",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Build apps for Wyndlass's screens: web components on the app contract (Player API 2), with the runtime Wyndlass's own apps use.",
5
5
  "keywords": [
6
6
  "wyndlass",
@@ -46,7 +46,8 @@ A paged app also defines `paging()`, returning `{count, ms}`, so the layout can
46
46
  - `useData(source, params)`: `{answer, error}`. The kept answer at once, then the service's, asked again every 10 minutes;
47
47
  - `useSnapshot(table)`: a data table's rows, as `snapshot` gives them. The component renders when they change;
48
48
  - `usePlayback()`, `useConnection()`, `useAudio()`, `usePlaying()`: the player's state (starting, playing, paused, stopped, idle, error), online or offline, `{volume, muted}`, and the items playing. Each renders only when its value changes; `null` without a controller;
49
- - `useCommand(name, handler)`: each command of that name, with its argument, while the component is mounted.
49
+ - `useCommand(name, handler)`: each command of that name, with its argument, while the component is mounted;
50
+ - `useEmergency()`: emergency messages at the screen (below).
50
51
 
51
52
  ## Signals (`@wyndlass/app-sdk/signals`)
52
53
 
@@ -55,8 +56,17 @@ For a vanilla app that updates its DOM when its rows or the player's state chang
55
56
  - `playbackSignal(this)`, `connectionSignal(this)`, `audioSignal(this)`, `nowSignal(this)`: the player's state, online or offline, `{volume, muted}`, and the items playing, as read-only signals made in `mount()`. Each is set only when its value changes; `null` without a controller;
56
57
  - `effect`, `computed`, `batch`, `signal`, `untracked`: Preact's, from the same copy. Import them from here, never from `@preact/signals-core`, whose effects would not see these signals.
57
58
 
59
+ - `emergencySignal(this)`: emergency messages at the screen (below), as a read-only signal.
60
+
58
61
  Draw in an `effect(() => { … rows.value … })` made in `mount()`, and leave `draw()` empty.
59
62
 
63
+ ## Emergency messages
64
+
65
+ The screen shows them itself, over every app: a takeover over all of it, a banner over its bottom 14% while the app plays on above. `emergencySignal(this)` and `useEmergency()` give `{ showing, messages }`: `showing` is `none`, `banner` or `takeover`, and each message gives `source`, `severity`, `presentation`, `event` and `category` where it has them, and `test`. `null` without a controller or before the screen has said what it holds, which is not `none`.
66
+ - **Under a banner,** lower the app's sound, stop calling numbers or pause what calls for attention, or show the way out.
67
+ - **Never draw an alert's words,** and never try to move, cover or hide the emergency layer: the screen shows the words in one design, and the layer stays on top.
68
+ - **Try it in the preview:** the controller's panel shows a Test banner or takeover over the app.
69
+
60
70
  ## The definition, `app.json`
61
71
 
62
72
  Valid against `node_modules/@wyndlass/app-sdk/protocol/app-definition.schema.json`.
@@ -7,6 +7,7 @@ An app for Wyndlass's screens, on `@wyndlass/app-sdk` and React. Its README says
7
7
  - **Nothing made in a render:** the component renders at every frame, many times a second. Make formatters (`Intl.DateTimeFormat`, `Intl.NumberFormat`) and other objects with `useMemo` on what they depend on, never in the render. One made in each draw holds memory a screen does not free in time: an app that did so ran a 4 GB screen out of memory within an hour.
8
8
  - **A table's rows from `useSnapshot(table)`:** a screen gives the app a table's new rows while it plays, and the component renders when they change. Never keep a copy made once. They are frozen: copy before you sort or change them.
9
9
  - **The player's state** (playing or paused, online or offline, its sound): `usePlayback()`, `useConnection()` and `useAudio()`, which render only when it changes. **Commands** sent to the screen's apps: `useCommand(name, handler)`. A command is an event, and the app cannot answer it.
10
+ - **Emergency messages:** the screen shows them over the app itself. `useEmergency()` says what shows: under a banner the app plays on, so lower its sound or pause what calls for attention. Never draw an alert's words, and never try to move, cover or hide the emergency layer. Try it in the preview's controller panel.
10
11
  - **Ready:** call `useApp().ready()` once drawn, within 5 s, or the screen reports the app late. `useData()` gives the answer the screen kept at once, then the service's.
11
12
  - **Data:** only through `useData(source, params)`, and only the sources `app.json`'s `data` lists. Pages: `usePaging(count, ms)`.
12
13
  - **Styles:** `src/app.css`, passed as `css`, never a `<style>`.
@@ -7,6 +7,7 @@ An app for Wyndlass's screens, on `@wyndlass/app-sdk`. Its README says what it i
7
7
  - **Nothing made in `draw`:** it runs at every frame, many times a second. Make formatters (`Intl.DateTimeFormat`, `Intl.NumberFormat`) and other objects in `mount()`, never in `draw`. One made in each draw holds memory a screen does not free in time: an app that did so ran a 4 GB screen out of memory within an hour.
8
8
  - **A table's rows where you draw:** a screen gives the app a table's new rows while it plays. Read them with `snapshot(this, table)` in `draw`, or with `tableSignal(this, table)` and an `effect` from `@wyndlass/app-sdk/signals`, made in `mount()`. Never read them once in `mount()` and keep them. They are frozen: copy before you sort or change them.
9
9
  - **The player's state** (playing or paused, online or offline, its sound): `playbackSignal(this)`, `connectionSignal(this)` and `audioSignal(this)` from `@wyndlass/app-sdk/signals`, made in `mount()`, never `status()` read at each frame. **Commands** sent to the screen's apps: `onCommand(this, name, handler)`. A command is an event, and the app cannot answer it.
10
+ - **Emergency messages:** the screen shows them over the app itself. `emergencySignal(this)` says what shows: under a banner the app plays on, so lower its sound or pause what calls for attention. Never draw an alert's words, and never try to move, cover or hide the emergency layer. Try it in the preview's controller panel.
10
11
  - **Ready:** call `ready()` once drawn, within 5 s, or the screen reports the app late. Draw the answer `kept()` gives at once, then ask `data()`.
11
12
  - **Data:** only through `data(this, source, params)`, and only the sources `app.json`'s `data` lists. Images a data answer names through `image(this, path)`.
12
13
  - **Styles:** `this.css(text)`, never a `<style>`. A CSS file the source imports is its text.