@wyndlass/app-sdk 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,7 +61,7 @@ Its controls:
61
61
  - **The clock:** play, pause, seek, and speeds from 0.25× to 4×.
62
62
  - **Enter and exit,** with each preset and how long it lasts, and the app's pages.
63
63
  - **Data:** each data source's answer, from samples you can edit in the page. `--data <dir>` reads `<source>.json` there instead (the answer's `data`, or a whole answer). The preview reaches no data service. A source the definition doesn't declare gets no answer, as on a screen.
64
- - **Tables:** each file in `<dir>/tables/`, or one you add in the page. A file may be CSV (its header gives the columns), a JSON array of rows, or a snapshot. A `datatable` param chooses among them, and an app with `slots` is bound to the first.
64
+ - **Tables:** each file in `<dir>/tables/`, or one you add in the page. A file may be CSV, a JSON array of rows, or a snapshot. A CSV's header gives its columns' labels, and their keys are made as Wyndlass makes a table's (`Now serving` is `now_serving`), so a `column` param holds the key it will on screens. A `datatable` param chooses among the tables, a `column` param among the chosen table's columns, and an app with `slots` is bound to the first table.
65
65
  - **The people at the screen,** for an app that declares the `impressions` sensor: someone arrives, looks, or leaves.
66
66
  - **The player's controller,** for what `capabilities.player` allows. The page sends the app the player's events, each one editable. A command the app may give is answered "not applied", and one it may not is refused, as on a screen.
67
67
 
package/dist/index.d.ts CHANGED
@@ -33,7 +33,11 @@ export declare function data<T = unknown>(app: WyndlassApp, source: string, para
33
33
  export declare function kept<T = unknown>(app: WyndlassApp, source: string, params: Params): DataAnswer<T> | undefined;
34
34
  /** An image a data answer names, as a blob URL the app can draw; refused outside a host. */
35
35
  export declare function image(app: WyndlassApp, path: string): Promise<string>;
36
- /** A data table's snapshot as the manifest carries it, the bound table's with only the rows the binding chooses; null without one. */
36
+ /**
37
+ * A data table's snapshot as the manifest carries it: a table the layout names, in a datatable param or in the element's
38
+ * binding, which needs no binding of its own; the bound table's with only the rows the binding chooses. Null when the
39
+ * screen has no snapshot of that table.
40
+ */
37
41
  export declare function snapshot(app: WyndlassApp, table: string): unknown | null;
38
42
  /** The app's view of the player's controller (ADR 0050), on screens, as its definition's `capabilities.player` allows. */
39
43
  export declare function controllerOf(app: WyndlassApp): AppController | undefined;
package/dist/index.js CHANGED
@@ -47,7 +47,11 @@ export function image(app, path) {
47
47
  const c = contextOf(app);
48
48
  return c ? c.image(path) : Promise.reject(unavailable());
49
49
  }
50
- /** A data table's snapshot as the manifest carries it, the bound table's with only the rows the binding chooses; null without one. */
50
+ /**
51
+ * A data table's snapshot as the manifest carries it: a table the layout names, in a datatable param or in the element's
52
+ * binding, which needs no binding of its own; the bound table's with only the rows the binding chooses. Null when the
53
+ * screen has no snapshot of that table.
54
+ */
51
55
  export function snapshot(app, table) {
52
56
  return contextOf(app)?.snapshot(table) ?? null;
53
57
  }
@@ -1,7 +1,7 @@
1
1
  /* @wyndlass/app-sdk's preview: player-core's host, compiled. MIT, (c) Northwynd Labs LLC. */
2
- "use strict";(()=>{var Nn=Object.defineProperty;var On=(t,e,n)=>e in t?Nn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var h=(t,e,n)=>On(t,typeof e!="symbol"?e+"":e,n);var wt=Reflect.apply,Ne=Object.getOwnPropertyDescriptor,fe=Object.getPrototypeOf,R=globalThis,v=(t,e,n)=>wt(t,e,n),O=(t,e)=>t?Ne(t,e)?.get:void 0,Oe=(t,e)=>t?Ne(t,e)?.set:void 0,P=t=>R[t]?.prototype,vt=(t,e,n)=>wt(t,e,n);var Oi=Date.now,$i=new TextEncoder,Di=new TextDecoder,ji=TextEncoder.prototype.encode,Fi=TextDecoder.prototype.decode;var Hi=O(fe(Uint8Array.prototype),"length");var $n=Uint8Array,Dn=t=>new $n(t),jn=[];for(let t=0;t<256;t++)jn[t]=(t<16?"0":"")+t.toString(16);var Fn=Object.create(null);for(let t=0;t<64;t++)Fn["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[t]]=t;var lt=R.crypto?.subtle,$e=lt?fe(lt):void 0,Re=R.crypto,Hn=Re?fe(Re).getRandomValues:void 0,Bi=$e?.digest,Ui=$e?.importKey,qi=$e?.sign;var kt=t=>v(Hn,Re,[Dn(t)]),_i={setTimeout:R.setTimeout,clearTimeout:R.clearTimeout,setInterval:R.setInterval,clearInterval:R.clearInterval};var Wi=R.fetch;var ne=P("MessagePort"),zi=ne&&ne.postMessage,Vi=Oe(ne,"onmessage"),Ki=ne&&ne.start,De=P("MessageEvent"),Zi=O(De,"data"),Ji=O(De,"ports"),Yi=O(De,"source");var xt=P("EventTarget"),Xi=xt?.addEventListener,Gi=xt?.removeEventListener;var Qi=R.Worker,ue=P("Worker"),er=ue&&ue.postMessage,tr=Oe(ue,"onmessage"),nr=Oe(ue,"onerror");var pt=R.Blob,he=R.URL,ct=he?.createObjectURL,Bn=he?.revokeObjectURL,je=pt&&ct?{make:(t,e)=>v(ct,he,[new pt(t,{type:e})]),revoke:t=>v(Bn,he,[t])}:void 0,ee=R.customElements,Fe=ee?fe(ee):void 0,Un=Fe?.define,qn=Fe?.get,He=ee&&Fe?{define:(t,e)=>v(Un,ee,[t,e]),get:t=>v(qn,ee,[t])}:void 0,At=R.document,me=P("Document"),_n=me?.createElement,Wn=me?.createElementNS,zn=WeakSet.prototype.add,sr=WeakSet.prototype.has,Be=new WeakSet,Vn=new WeakSet,ge=(t,e)=>(v(zn,t,[e]),e);function D(t){return ge(Be,v(_n,At,[t]))}var ye=t=>ge(Be,v(Wn,At,["http://www.w3.org/2000/svg",t]));var K=t=>ge(Vn,t);var se=P("Node"),Ue=P("Element"),be=P("HTMLElement"),Z=t=>O(se,t),ut=Z("parentNode"),Kn=Z("firstChild"),Zn=Z("lastChild"),Jn=Z("nextSibling"),Yn=Z("nodeType"),Xn=Z("childNodes"),Gn=O(Ue,"localName"),Qn=se?.appendChild,es=se?.insertBefore,ts=se?.removeChild,q=Ue,ns=q?.getAttribute,ss=q?.getAttributeNames,is=q?.setAttribute,rs=q?.removeAttribute,os=q?.matches,as=q?.attachShadow,ds=q?.querySelectorAll,ls=P("HTMLDialogElement")?.close,ps=O(P("NodeList"),"length"),cs=P("NodeList")?.item,we=P("MutationRecord"),us=O(we,"type"),hs=O(we,"target"),ms=O(we,"addedNodes"),fs=O(we,"removedNodes"),ht=R.MutationObserver,gs=P("MutationObserver")?.observe,Mt=me?Ne(me,"adoptedStyleSheets"):void 0,mt=Mt?.get,ft=Mt?.set,ys=R.requestAnimationFrame,gt=O(be,"style"),ve=P("CSSStyleDeclaration"),bs=ve?.getPropertyValue,ws=ve?.getPropertyPriority,vs=ve?.setProperty,yt=be?.showPopover,bt=be?.hidePopover,ks=O(P("Event"),"target"),xs=P("Event")?.stopImmediatePropagation,ce=t=>{let e=[];for(let n=0,s=v(ps,t,[]);n<s;n++)e[n]=v(cs,t,[n]);return e},te=ht&&se&&Ue&&be&&ve?{parent:t=>v(ut,t,[]),first:t=>v(Kn,t,[]),last:t=>v(Zn,t,[]),next:t=>v(Jn,t,[]),isElement:t=>v(Yn,t,[])===1,name:t=>v(Gn,t,[]),children:t=>ce(v(Xn,t,[])),append:(t,e)=>v(Qn,t,[e]),insert:(t,e,n)=>v(es,t,[e,n]),remove:t=>{let e=v(ut,t,[]);e&&v(ts,e,[t])},attribute:(t,e)=>v(ns,t,[e]),attributes:t=>v(ss,t,[]),setAttribute:(t,e,n)=>v(is,t,[e,n]),removeAttribute:(t,e)=>v(rs,t,[e]),matches:(t,e)=>v(os,t,[e]),all:(t,e)=>ce(v(ds,t,[e])),closeDialog:t=>v(ls,t,[]),shadow:t=>v(as,t,[{mode:"closed"}]),style:(t,e)=>{let n=v(gt,t,[]);return[v(bs,n,[e]),v(ws,n,[e])]},setStyle:(t,e,n,s="")=>v(vs,v(gt,t,[]),[e,n,s]),observer:t=>new ht(t),observe:(t,e,n)=>v(gs,t,[e,n]),record:t=>({type:v(us,t,[]),target:v(hs,t,[]),added:ce(v(ms,t,[])),removed:ce(v(fs,t,[]))}),adopted:mt&&ft?{count:t=>v(mt,t,[]).length,clear:t=>v(ft,t,[[]])}:void 0,frame:t=>v(ys,globalThis,[t]),popover:yt&&bt?{show:t=>v(yt,t,[]),hide:t=>v(bt,t,[])}:void 0,target:t=>v(ks,t,[]),stop:t=>v(xs,t,[])}:void 0;function qe(t){if(ge(Be,t),te)for(let e of te.children(t))te.isElement(e)&&qe(e);return t}var _e=t=>new TextEncoder().encode(t);function As(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 We(t){return As(await crypto.subtle.digest("SHA-256",t))}var Ms=["name","type","tags","location","site","district","region","organization","path","timeZone"],Es=["text","date","currency","truncate"],Et={site:"SITE",district:"DISTRICT",region:"REGION",organization:"ORGANIZATION"};function ke(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(o=>o.name).join(" \u203A "):void 0;case"timeZone":return e||void 0;default:return Et[n]?[...i].reverse().find(o=>o.kind===Et[n])?.name:void 0}}function Ss(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 ze(t,e){return(t.source==="screen"?ke(e.screen,e.timeZone,t.field,t.key):Ss(e.tables?.[t.table]?.rows?.[t.row??0]?.[t.column],t.format))??t.fallback??""}function Ts(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"),i=n.find(o=>!o[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}:{}}:Ms.includes(e[1])?{source:"screen",field:e[1],...s!==void 0?{fallback:s}:{}}:null:i&&!Es.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 Ve(t,e){return t.replace(/\{{2}([^{}]*)\}{2}/g,(n,s)=>{let i=Ts(s);return i?ze(i,e):n})}function St(t,e){return Object.fromEntries(Object.entries(t).map(([n,s])=>[n,typeof s=="string"?Ve(s,e):s]))}var Ke=t=>t==null||t==="";function Pt(t,e,n,s,i,o){return Ps(t,e,n,s,{now:i,timeZone:o})}function Ps(t,e,n,s,i){if(n===null&&(e==="eq"||e==="ne"))return e==="eq"?Ke(t):!Ke(t);if(Ke(t)||n===null||n===void 0)return!1;switch(s){case"number":case"currency":{let o=Number(t),r=Number(n);return typeof n!="boolean"&&n!==""&&Number.isFinite(o)&&Number.isFinite(r)&&Ze(e,o-r)}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"?Ls(i.now,i.timeZone).date:String(n),r=String(t).slice(0,10);return/^\d{4}-\d{2}-\d{2}$/.test(o)&&Ze(e,r<o?-1:r>o?1:0)}case"datetime":{let o=Date.parse(String(t)),r=n==="now"?i.now:Date.parse(String(n));return!Number.isNaN(o)&&!Number.isNaN(r)&&Ze(e,o-r)}default:{let o=String(t).toLowerCase(),r=String(n).toLowerCase();return e==="eq"?o===r:e==="ne"?o!==r:e==="contains"?o.includes(r):!1}}}function Ze(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 Tt=new Map;function Ls(t,e){let n=Tt.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"}),Tt.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 Lt=(t,e)=>!t||(t.from===void 0||t.from<=e)&&(t.until===void 0||e<t.until);var ie=class{constructor(e,n,s,i,o){h(this,"renderer",e);h(this,"wrap",i);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 Je=class extends Error{constructor(n,s){super(s);h(this,"code",n);this.name="MediaError"}};function Ye(t){return t instanceof Je?{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 It=t=>t.blob.contentType.startsWith("video/");var Xe="position:absolute;inset:0;width:100%;height:100%;object-fit:contain",Cs=1,xe=class{constructor(e,n={}){h(this,"container",e);h(this,"options",n);h(this,"prepared",new Map);h(this,"shown",null);h(this,"endListeners",new Set);h(this,"itemListeners",new Set);h(this,"appListeners",new Set);h(this,"held",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((i,o)=>{let r=this.shown;if(r?.mediaId===i)for(let a of this.endListeners)a(r.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(i){return 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){await this.prepare(e);let n=this.prepared.get(e);if(!n)throw new Error("the slide was released before it was shown");this.prepared.delete(e);let s=this.shown,i=this.options.media,o=s?Rt(e):void 0;if(n.kind==="layout"&&o===void 0){await H(()=>{s?this.container.insertBefore(n.el,s.el):this.container.append(n.el),this.shown=n,this.shownHash=e.blob.hash}),this.held=[],await n.view.start().catch(()=>{});let r=Promise.resolve();return await H(()=>{this.shown===n&&(n.el.style.visibility="",s?.el.remove(),i&&this.paint("transparent"),i&&s?.mediaId&&(r=i.show([],[s.mediaId],Date.now())))}),await r.catch(()=>{}),s&&this.dispose(s),this.releaseHeld(),"cut"}if(o!==void 0&&i&&n.kind==="native"&&s.kind==="native"){if(n.fadesIn&&!n.queued){let r=Promise.resolve();return await H(()=>{n.el.style.visibility="",this.container.insertBefore(n.el,s.el),r=i.show([n.mediaId],[],Date.now()),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{}),Rs(o).then(async()=>{await i.show([],[s.mediaId],Date.now()).catch(()=>{}),s.el.remove(),this.dispose(s)}),"crossfade"}}else if(o!==void 0&&i&&n.kind==="native"){let r=Promise.resolve();return await H(()=>{n.el.style.visibility="",this.container.insertBefore(n.el,s.el),r=i.show([n.mediaId],[],Date.now()),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{}),this.paint("transparent"),Nt(s.el,1,0,o).then(()=>{s.el.remove(),this.dispose(s)}),"crossfade"}else if(o!==void 0)return await H(()=>{n.el.style.visibility="",n.el.style.opacity="0",this.container.append(n.el),n.kind==="video"&&Ge(n.el),this.shown=n,this.shownHash=e.blob.hash}),n.view&&(this.held=[],n.view.start().then(()=>this.releaseHeld())),Nt(n.el,0,1,o).then(async()=>{s.el.remove(),this.shown===n&&this.paint(i?"#000":""),i&&s.mediaId&&await i.show([],[s.mediaId],Date.now()).catch(()=>{}),this.dispose(s)}),"crossfade";if(i&&n.kind==="native"){let r=Promise.resolve();await H(()=>{n.el.style.visibility="",s?this.container.insertBefore(n.el,s.el):this.container.prepend(n.el),r=i.show([n.mediaId],s?.mediaId?[s.mediaId]:[],Date.now()),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{}),await H(()=>{this.shown===n&&(s?.el.remove(),this.paint("transparent"))})}else{let r=Promise.resolve();await H(()=>{n.el.style.visibility="",n.el.parentNode!==this.container&&this.container.append(n.el),s?.el.remove(),this.paint(i?"#000":""),i&&s?.mediaId&&(r=i.show([],[s.mediaId],Date.now())),n.kind==="video"&&Ge(n.el),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{})}return s&&this.dispose(s),"cut"}paint(e){this.options.background?this.options.background(e):this.container.style.background=e}standby(){let e=this.shown;this.shown=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"?Ge(e.el):e?.mediaId&&this.options.media?.control(e.mediaId,"play").catch(()=>{})}make(e){if(e.layout){let{doc:r,source:a,untilPass:d}=e.layout,l=K(D("div"));l.dataset.blob=e.blob.hash,l.style.cssText=`${Xe};visibility:hidden`,this.container.append(l);let c={slide:e,kind:"layout",el:l,ready:Promise.resolve()},p=y=>this.options.path?`${this.options.path}/${y}`:y,m=String(++this.drawn);return c.view=new J(r,a,l,{media:this.options.media,path:this.options.path,endsWith:d?p(d):void 0,onItem:y=>{let A={...y,slide:y.slide?`${m}.${y.slide}`:m};this.held?this.held.push(A):this.item(A)},onPassEnd:y=>{if(d&&y===p(d)&&this.shown===c){for(let A of this.endListeners)A(e);return"hold"}return this.options.onPassEnd?.(y)},onApp:y=>this.app(y)}),c.ready=c.view.ready,c}if(!It(e)){if(!e.bytes&&!e.url)throw new Error(`no bytes for ${e.blob.hash}`);let r=e.bytes?URL.createObjectURL(new Blob([e.bytes],{type:e.blob.contentType})):void 0,a=K(D("img"));return a.src=r??e.url,a.alt="",a.dataset.blob=e.blob.hash,a.style.cssText=this.fill(),{slide:e,kind:"image",el:a,objectUrl:r,ready:a.decode()}}let n=this.options.media;if(n){let r=`m-${Cs++}`,a=K(D("div"));a.dataset.blob=e.blob.hash,a.dataset.media=r,a.style.cssText=`${Xe};visibility:hidden`;let d=this.container.getBoundingClientRect(),l={x:d.left,y:d.top,w:d.width||window.innerWidth,h:d.height||window.innerHeight},c=Rt(e),p=c!==void 0&&this.shown?.kind==="native"&&n.capability.animates&&n.capability.layers>=2,m=p?[{property:"opacity",keyframes:[{t:0,v:0},{t:c,v:1}]}]:[],y={slide:e,kind:"native",el:a,mediaId:r,fadesIn:p,ready:Promise.resolve()},A=this.options.fit??"contain";return y.ready=n.prepare({mediaId:r,blob:e.blob.hash,contentType:e.blob.contentType,box:l,z:p?1:0,loop:e.loop,muted:!1,fit:A,...p?{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})),i=K(D("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 r of this.endListeners)r(e)}),i.addEventListener("error",()=>{if(this.shown?.el===i)for(let r of this.endListeners)r(e,`video: ${i.error?.message??"error"}`)});let o=new Promise((r,a)=>{if(i.readyState>=2)return r();i.addEventListener("loadeddata",()=>r(),{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:o}}item(e){this.options.onItem?.(e);for(let n of this.itemListeners)n(e)}releaseHeld(){let e=this.held;this.held=null,e?.length&&setTimeout(()=>{for(let n of e)this.item(n)},0)}fill(){let e=this.options.fit==="stretch"?"fill":this.options.fit??"contain";return Xe.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 Rt(t){if(t.transition?.type==="crossfade")return Math.max(0,Math.min(t.transition.durationMs??1e3,t.durationMs/2))}var Rs=t=>new Promise(e=>setTimeout(e,t));function Nt(t,e,n,s){return new Promise(i=>{let o=Date.now(),r=!1,a=()=>{r||(r=!0,t.style.opacity=n===1?"":String(n),i())};t.style.opacity=String(e);let d=()=>{if(r)return;let l=Math.min(1,(Date.now()-o)/s);if(l>=1)return a();t.style.opacity=String(e+(n-e)*l),requestAnimationFrame(d)};requestAnimationFrame(d),setTimeout(a,s+250)})}function Ge(t){t.play().catch(()=>(t.muted=!0,t.play())).catch(()=>{})}function H(t){return new Promise((e,n)=>{let s=!1,i=()=>{if(!s){s=!0;try{t(),e()}catch(o){n(o)}}};requestAnimationFrame(i),setTimeout(i,250)})}var re={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 Ot=Symbol.for("wyndlass.app.attach");var F=class extends Error{constructor(n,s){super(`the app could not run (${n})`);h(this,"reason",n);h(this,"error",s)}};function _(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 oe(t){let e=t?.id;if(typeof e!="string"||e==="")return!0;for(let n=0;n<$t.length;n++)if(e[n]!==$t[n])return!1;return!0}var $t="com.wyndlass.";function Os(t=typeof navigator>"u"?"":navigator.userAgent){let e=/Chrom(?:e|ium)\/(\d+)/.exec(t);return e?Number(e[1]):void 0}function Dt(t,e=re.apiVersion,n=Os()){return!(t?.playerApi!==void 0&&t.playerApi>e||t?.webView!==void 0&&n!==void 0&&t.webView>n)}function $s(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 Qe=new Map;function Ds(){let t=kt(8),e="";for(let n=0;n<8;n++)e+=js[t[n]%26];return e}var js="abcdefghijklmnopqrstuvwxyz",Fs=0;function jt(t,e,n){let s=Qe.get(t);if(!s){let i=je.make([e],"text/javascript");s=import(i).then(o=>Hs(o,n),o=>{throw o instanceof F?o:new F("load",_(o))}).finally(()=>je.revoke(i)),Qe.set(t,s),s.catch(()=>Qe.delete(t))}return s}function Hs(t,e){let n=t.default;if(typeof n=="function"&&n.prototype instanceof HTMLElement){let s=n.prototype[Ot];if(typeof s!="function")throw new F("shape");let i=class extends n{},o=`${e?.element??"wl-app"}-${Ds()}${++Fs}`;try{He.define(o,i)}catch(r){throw new F("shape",_(r))}return{tag:o,shape:"class",attach:(r,a)=>{vt(s,r,[a])}}}if(oe(e)&&typeof t.element=="string"&&He.get(t.element))return{tag:t.element,shape:"legacy"};throw new F("shape")}var Bs=3,Us=6e4,Ae=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:$s(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<Us),this.faults.push(n),this.faults.length>=Bs&&this.stop(_(e))}},qs=24*3600*1e3,Me=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(),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),o=this.inflight.get(i);if(o)return o;let r=this.o.fetch??fetch,a=(async()=>{let d=this.stored(i),l=d?JSON.parse(d):void 0;if(l&&Date.parse(l.expiresAt)>this.now())return this.dress(l,!1);let c=this.url(`/v0/${encodeURIComponent(e)}?${s}`);try{if(!c)throw new Error("no data service");let p=await r(c);if(!p.ok)throw new Error(`the data service answered ${p.status}`);let m=await p.text();return this.keep(i,m),this.dress(JSON.parse(m),!1)}catch(p){if(l&&Date.parse(l.expiresAt)+qs>this.now())return this.dress(l,!0);throw p}})().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 Ft="wyndlass.frame";function Ut(t,e){return!!t&&(t.apps?t.apps(e):!oe(e))}var _s=new Set(["load","shape","unsupported","error","late","overran"]),Ht=50,Bt=250,et=class{constructor(e,n,s,i){h(this,"frame",e);h(this,"port",n);h(this,"o",i);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 i=this.told;if(i&&(i.running?Math.abs(e-(i.t+(n-i.at)))<=Ht:e===i.t)){i.running&&this.watch();return}let o=!!s&&n-s.at<Bt&&e>s.t&&Math.abs(e-s.t-(n-s.at))<=Ht;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"})}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(){clearTimeout(this.quiet),this.port.close();for(let e of this.pending.values())e();this.pending.clear()}heard(e){e.type==="paging"?this.pages=_t(e.paging):e.type==="hooked"&&typeof e.id=="number"?(this.pending.get(e.id)?.(),this.pending.delete(e.id)):e.type==="stopped"&&this.stop(Wt(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}))},Bt)}};async function qt(t,e,n,s,i,o,r,a,d,l){let c=t.appInfo??n.info,p;try{p=new URL(d.frames).origin}catch{return l("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(M=>{m.addEventListener("load",()=>M(!0),{once:!0}),setTimeout(()=>M(!1),o)});m.src=`${p}/`,e.append(m);let A=(M,w)=>(m.remove(),l(M,w));if(!await y||!m.contentWindow)return A("load");let{port1:f,port2:k}=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:Vs(t.props??{},d),snapshots:Ks(t,s),deadlineMs:o};return new Promise(M=>{let w,T=!1,N=G=>{T||(T=!0,clearTimeout(j),M(G))},j=setTimeout(()=>{w?(N({app:w,late:!0}),w.update(i.now())):(f.close(),N(A("load")))},o+1e3),U=!1;f.onmessage=G=>{let x=G.data;if(!(!x||typeof x!="object")){if(x.type==="ask"){U&&Ws(x,s,f);return}if(w){x.type==="ready"?(N({app:w,late:x.late===!0}),w.update(i.now())):w.heard(x);return}x.type==="hello"&&!U?(U=!0,f.postMessage(b,[b.bundle.bytes.buffer])):x.type==="made"&&Array.isArray(x.hooks)?(w=new et(m,f,{type:"made",hooks:x.hooks.filter(C=>C==="enter"||C==="exit"),paging:_t(x.paging)},{onStop:a}),r(w)):x.type==="failed"&&(f.close(),N(A(_s.has(x.reason)?x.reason:"error",Wt(x.error))))}},m.contentWindow.postMessage({type:Ft},"*",[k])})}async function Ws(t,e,n){if(typeof t.id!="number")return;let s=(i,o=[])=>{try{n.postMessage(i,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,zs(t.params))});else if(t.what==="image"&&typeof t.path=="string"){let i=await e.data.imageBlob(t.path),o=new Uint8Array(await i.arrayBuffer());s({type:"answer",id:t.id,value:{bytes:o,type:i.type}},[o.buffer])}else throw new TypeError("not a question")}catch(i){s({type:"answer",id:t.id,error:_(i)??"Error"})}}function zs(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 _t(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 Wt(t){return typeof t=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(t)?t:void 0}function Vs(t,e){let n=new Set;for(let i of Object.values(t)){let o=i?.family;i&&typeof i=="object"&&typeof o=="string"&&n.add(o)}let s=[];for(let i of e.fonts??[]){let o=n.has(i.family)?e.font?.(i.blob):void 0;o&&s.push({family:i.family,weight:i.weight,style:i.style,blob:i.blob,bytes:o.slice()})}return s}function Ks(t,e){let n=new Set;t.binding?.table&&n.add(t.binding.table);for(let i of Object.values(t.props??{}))typeof i=="string"&&/^tbl_[0-9a-z]{26}$/.test(i)&&n.add(i);let s={};for(let i of n){let o=e.snapshot?.(i);o&&(s[i]=o)}return s}function zt(t){let e=te?.setStyle??((n,s,i,o)=>n.style.setProperty(s,i,o));e(t,"contain","strict","important"),e(t,"overflow","clip","important")}var Vt=t=>!!(t?.filter?.length||t?.sort||t?.limit),Zs=t=>t==null||t==="";function Js(t,e){if(!Zs(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 Ys(t,e){let n=Array.from(t),s=Array.from(e);for(let i=0;i<n.length&&i<s.length;i++){let o=n[i].codePointAt(0)-s[i].codePointAt(0);if(o!==0)return o}return n.length-s.length}function Xs(t,e,n,s,i){let o=t,r=Array.isArray(o?.rows)?o.rows:[],a=Array.isArray(o?.columns)?o.columns:void 0,d=l=>a?.find(c=>c.key===l)?.type??"text";for(let l of e.filter??[]){if(a&&!a.some(m=>m.key===l.column))return[];let c=l.value;if(c!==null&&typeof c=="object"){let m=c;if(c=ke(n,s,m.screen,m.key),c===void 0)return[]}let p=d(l.column);r=r.filter(m=>Pt(m[l.column],l.op,c,p,i,s))}if(e.sort){let{column:l}=e.sort,c=d(l),p=e.sort.order==="desc"?-1:1;r=r.map((m,y)=>({row:m,i:y,key:Js(m[l],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 A=typeof m.key=="number"&&typeof y.key=="number"?m.key-y.key:Ys(String(m.key),String(y.key));return A===0?m.i-y.i:A<0?-p:p}).map(m=>m.row)}return e.limit?r.slice(0,e.limit):r}function Kt(t,e,n,s,i){return!t||typeof t!="object"?t:{...t,rows:Xs(t,e,n,s,i)}}function Gs(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 Jt(t,e,n,s=[]){let i=D("div");if(i.dataset.background="",i.style.cssText="position:absolute;inset:0;pointer-events:none",i.style.background=Gs(e),s.length){let o=[`M0 0H${n.width}V${n.height}H0Z`,...s.map(d=>`M${d.x} ${d.y}H${d.x+d.w}V${d.y+d.h}H${d.x}Z`)].join(""),r=`<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(r)}")`;i.dataset.holes=String(s.length);for(let[d,l]of[["maskImage",a],["maskSize","100% 100%"],["maskRepeat","no-repeat"]])i.style[d]=l,i.style[`webkit${d[0].toUpperCase()}${d.slice(1)}`]=l}return t.prepend(i),i}function Yt(t,e=t.frame){let n=D("div");return n.dataset.element=t.id,n.style.cssText="position:absolute;box-sizing:border-box",Qs(n,e),n}function Qs(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 Xt(t,e,n){if(e.type==="text"){let s=e.style??{},i=Gt(n);t.textContent=e.bind?ze(e.bind,i):Ve(e.text??"",i),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"&&ei(e)?(t.style.opacity=e.opacity!==void 0?String(e.opacity):"",t.append(ti(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 Gt(t){return{screen:t?.screen??null,timeZone:t?.timeZone,tables:new Proxy({},{get:(e,n)=>typeof n=="string"?t?.snapshot?.(n):void 0})}}var ei=t=>t.shape==="line"||t.shape==="arrow"||t.shape==="polygon";function ti(t){let e=ye("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),r=(t.points?.length?t.points:t.shape==="polygon"?[[.5,0],[1,1],[0,1]]:[[0,.5],[1,.5]]).map(([c,p])=>[c*n,p*s]),a=t.stroke?.color?.value??"#000000",d=t.stroke?.dash==="dashed"?`${i*3} ${i*2}`:t.stroke?.dash==="dotted"?`0 ${i*2}`:"",l=ye(t.shape==="polygon"?"polygon":"polyline");if(l.setAttribute("points",r.map(c=>`${c[0]},${c[1]}`).join(" ")),l.setAttribute("fill",t.shape==="polygon"?t.fill?.value??"none":"none"),i&&(l.setAttribute("stroke",a),l.setAttribute("stroke-width",String(i)),l.setAttribute("stroke-linecap",t.stroke?.dash==="dotted"?"round":"butt"),l.setAttribute("stroke-linejoin","round"),d&&l.setAttribute("stroke-dasharray",d)),e.append(l),t.shape==="arrow"&&r.length>=2){let[c,p]=[r[r.length-2],r[r.length-1]],m=Math.atan2(p[1]-c[1],p[0]-c[0]),y=Math.max(10,i*3.5),A=k=>`${p[0]-y*Math.cos(m)+k*y*.5*Math.sin(m)},${p[1]-y*Math.sin(m)-k*y*.5*Math.cos(m)}`;l.setAttribute("points",[...r.slice(0,-1),[p[0]-y*.8*Math.cos(m),p[1]-y*.8*Math.sin(m)]].map(k=>`${k[0]},${k[1]}`).join(" "));let f=ye("polygon");f.setAttribute("points",`${p[0]},${p[1]} ${A(1)} ${A(-1)}`),f.setAttribute("fill",a),e.append(f)}return e}async function Qt(t,e,n,s,i,o,r,a=()=>{},d){let l=t.appInfo??n.info;zt(e),l?.id&&(e.dataset.app=l.id);let c=(x,C)=>(e.dataset.appFailed=x,{failed:x,...C?{error:C}:{}});if(!Dt(l?.requires))return c("unsupported");let p=s.appHost;if(p&&!p.custom&&!oe(l))return c("unsupported");if(Ut(d,l))return qt(t,e,n,s,i,o,r,a,d,c);let m=t.app;if(p?.held?.(m))return e.dataset.appHeld="",{held:!0};await p?.mounting?.(m,l?.id);let y=!1,A=()=>{y||(y=!0,p?.unmounted?.(m))},f;try{f=await jt(n.hash,n.bytes,l)}catch(x){return A(),x instanceof F?c(x.reason,x.error):c("load")}let k=f.tag,b=l?.id?s.controllerFor?.({id:l.id,instance:t.id,capability:l.player??"read"}):void 0,M,w=new Promise(x=>{M=x}),T,N={app:l?.id??t.app.id,element:k,props:St(t.props??{},Gt(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:(x,C)=>s.data?s.data.get(x,C):Promise.reject(new Error("no data service")),kept:(x,C)=>s.data?.kept?.(x,C),image:x=>s.data?s.data.image(x):Promise.reject(new Error("no data service")),snapshot:x=>{let C=s.snapshot?.(x)??null;if(!C||t.binding?.table!==x||!Vt(t.binding))return C;let Q=Kt(C,t.binding,s.screen,N.timeZone,i.now());return T?.from===C&&T.rows.length===Q.rows.length&&T.rows.every((Cn,Rn)=>Cn===Q.rows[Rn])?T.snapshot:(T={from:C,rows:Q.rows,snapshot:Q},Q)},...t.binding?{binding:t.binding}:{},...t.sensors?.includes("impressions")&&s.impressions?.measuring?{impressions:{now:()=>s.impressions.now(),on:x=>s.impressions.on(x)}}:{},...b?{controller:b}:{}},j;try{j=D(k),f.shape==="class"?f.attach(j,N):j.wyndlass=N}catch(x){return b?.dispose(),A(),c("error",_(x))}j.style.cssText="display:block;width:100%;height:100%",p?.contained?.(e,j);let U=new Ae(j,{onStop:a,dispose:()=>{b?.dispose(),A()}});e.append(j),r(U);let G=await Promise.race([w.then(()=>!1),new Promise(x=>setTimeout(()=>x(!0),o))]);return U.update(N.now()),{app:U,late:G}}var Zt=new Set;async function en(t,e){for(let n of t){let s=`${n.family}/${n.weight??400}/${n.style??"normal"}/${n.blob}`,i=e(n.blob);if(!(Zt.has(s)||!i||typeof FontFace>"u"))try{let o=new FontFace(n.family,i,{weight:String(n.weight??400),style:n.style??"normal"});document.fonts.add(await o.load()),Zt.add(s)}catch{}}}function ae(t){let e=[],n=null;for(let s of t){let i=s.start,o=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:o,endMs:o+s.durationMs},e.push(n)}return{clips:e,autoDurationMs:e.reduce((s,i)=>Math.max(s,i.endMs),0)}}var ni=new Set(["x","y","scaleX","scaleY","rotation","opacity","reveal"]);function si(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 i=t.slice(0,-1).filter(o=>o.type==="shape"&&o.clip!==!1);if(i.some(o=>o.shape!=="rectangle"||(o.radius??0)>0))return s("clipped-to-shape");if(i.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(r=>ni.has(r))))return s("animated")}return{path:"native"}}var ii={fade:["opacity"],slide:["x","opacity"],scale:["scaleX","scaleY","opacity"],pulse:["scaleX","scaleY"],loop:["scaleX","scaleY"],wipe:["reveal"]};function tn(t,e,n,s){let i=e&&t.overrides?.[e]||{},o=new Map;for(let p of t.animation?.clips??[]){let m=[...p.preset?ii[p.preset]??[]:[],...(p.lanes??[]).map(y=>y.property)];o.set(p.element,[...o.get(p.element)??[],...m])}let r=p=>p.type==="library"&&!!p.source&&!!n[p.source.item.id]?.video,a=p=>!r(p)&&!(p.type==="shape"&&!p.fill&&!(p.stroke?.width??0)),d=[],l=(p,m,y,A)=>{for(let f of p){let k=i[f.id];if(k?.hidden??f.hidden??!1)continue;let b=k?.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:o.get(f.id)??[],...f.type==="shape"?{shape:f.shape,radius:f.radius,clip:f.clip}:{}};d.push({e:f,box:M,chain:[...y,w],ancestors:A}),f.type==="shape"&&l(f.children??[],M,[...y,w],[...A,f])}};l(t.elements,{x:0,y:0},[],[]);let c=(p,m)=>p.x<m.x+m.w&&m.x<p.x+p.w&&p.y<m.y+m.h&&m.y<p.y+p.h;return d.flatMap((p,m)=>{if(!r(p.e))return[];let y=d.slice(0,m).some(A=>a(A.e)&&c(A.box,p.box));return[{element:p.e.id,path:si(p.chain,{pageBelow:y},s),box:p.box}]})}var ri=[0,0,1,1];function tt(t,e){if(e<=0)return 0;if(e>=1)return 1;let[n,s,i,o]=t;if(n===s&&i===o)return e;let r=3*n,a=3*(i-n)-r,d=1-r-a,l=3*s,c=3*(o-s)-l,p=1-l-c,m=w=>((d*w+a)*w+r)*w,y=w=>((p*w+c)*w+l)*w,A=w=>(3*d*w+2*a)*w+r,f=1e-7,k=e;for(let w=0;w<8;w++){let T=m(k)-e;if(Math.abs(T)<f)return y(k);let N=A(k);if(Math.abs(N)<1e-6)break;k-=T/N}let b=0,M=1;for(k=e;b<M;){let w=m(k);if(Math.abs(w-e)<f||(e>w?b=k:M=k,k=(M-b)/2+b,M-b<f))break}return y(k)}function Ee(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 o=n[i],r=n[i+1];return o.v+(r.v-o.v)*tt(o.easing??ri,(e-o.t)/(r.t-o.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]=Ee(i,n);return s}var de={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 sn(t){if(!t)return de.ease;if(de[t])return de[t];let n=/^cubic-bezier\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\)$/.exec(t)?.slice(1).map(Number);return n&&n.every(Number.isFinite)?n:de.ease}function oi(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 an={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})},zo=Object.keys(an);var ai={x:t=>t.x,y:t=>t.y,scaleX:()=>1,scaleY:()=>1,rotation:()=>0,opacity:()=>1,reveal:()=>1,chars:()=>1,count:()=>1},rn=1e3,di=de["ease-in-out"];function dn(t,e){let n=ae(t).clips,s=new Map,i=new Set,o=a=>{let d=s.get(a);return d||s.set(a,d={keys:new Map,colour:null,loops:[],tickers:[]}),d},r=(a,d,l)=>{let c=o(a).keys,p=c.get(d)??[];c.set(d,p),p.push(l)};t.forEach((a,d)=>{let l=e.get(a.element);if(!l)return;let{startMs:c,endMs:p}=n[d],m=sn(a.easing);if(a.lanes?.length){for(let f of a.lanes)for(let k of f.keyframes){let b={t:c+k.at,easing:sn(k.easing??a.easing)};if(f.property==="color"){let M=oi(k.value);if(!M)continue;let w=o(a.element);w.colour??(w.colour=[[],[],[],[]]),M.forEach((T,N)=>w.colour[N].push({...b,v:T}))}else r(a.element,f.property,{...b,v:Number(k.value)})}return}let y=a.preset??"fade";if(a.kind==="emphasis"){y==="pulse"?(r(a.element,"pulse",{t:c,v:1,easing:m}),r(a.element,"pulse",{t:(c+p)/2,v:1.05,easing:m}),r(a.element,"pulse",{t:p,v:1})):y==="loop"?o(a.element).loops.push({startMs:c,endMs:p}):y==="ticker"?o(a.element).tickers.push({startMs:c,endMs:p}):i.add(y);return}let A=an[y];if(!A){i.add(y);return}for(let[f,k]of Object.entries(A(l))){let b=ai[f](l),[M,w]=a.kind==="enter"?[k,b]:[b,k];r(a.element,f,{t:c,v:M,easing:m}),r(a.element,f,{t:p,v:w})}});for(let a of s.values()){for(let d of a.keys.values())d.sort((l,c)=>l.t-c.t);for(let d of a.colour??[])d.sort((l,c)=>l.t-c.t)}return{motions:s,unplayed:[...i].sort()}}var li=["x","y","scaleX","scaleY","rotation","opacity"];function ln(t,e,n,s=!1){if(s)return pi(t,e,n);let i=(d,l)=>{let c=t?.keys.get(d);return c?Ee({property:"x",keyframes:c},n):l},o=nn(e,li.flatMap(d=>t?.keys.get(d)?[{property:d,keyframes:t.keys.get(d)}]:[]),n),r=i("pulse",1);for(let d of t?.loops??[])if(n>=d.startMs&&n<d.endMs){let l=(n-d.startMs)%rn/rn;r*=1+.05*tt(di,l<.5?l*2:2-l*2)}let a=t?.tickers.find(d=>n>=d.startMs&&n<d.endMs);return{...o,reveal:i("reveal",1),chars:i("chars",1),count:i("count",1),pulse:r,scroll:a?(n-a.startMs)/(a.endMs-a.startMs):null,color:t?.colour?t.colour.map(d=>Ee({property:"x",keyframes:d},n)):null}}function on(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 pi(t,e,n){let s=(i,o)=>{let r=t?.keys.get(i);return r?on(r,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(i=>on(i,n)):null}}function ci(t,e){let n=Array.from(t);return e>=1?t:n.slice(0,Math.max(0,Math.round(e*n.length))).join("")}function ui(t,e){return e>=1?t:t.replace(/\d+(?:\.\d+)?/g,n=>(Number(n)*Math.max(0,e)).toFixed((n.split(".")[1]??"").length))}function pn(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 cn(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(o=>Math.round(o)).join(",")},${n.color[3]})`:null;if(e.type==="text"&&s!==void 0){let o=ui(ci(s,n.chars),n.count);if(n.scroll!==null){let r=t.querySelector("[data-ticker]");r||(r=document.createElement("span"),r.dataset.ticker="",r.style.cssText="display:inline-block;white-space:nowrap;will-change:transform",t.replaceChildren(r),t.style.overflow="hidden"),r.textContent!==o&&(r.textContent=o);let a=e.frame.w,d=r.scrollWidth;r.style.transform=`translateX(${a-n.scroll*(a+d)}px)`}else(t.textContent!==o||t.querySelector("[data-ticker]"))&&(t.textContent=o,t.style.overflow="");i&&(t.style.color=i)}else if(e.type==="shape"&&i){let o=t.querySelector("polygon, polyline");o&&e.shape==="polygon"?o.setAttribute("fill",i):o||(t.style.background=i)}}function hi(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 un(t,e,n,s){let i=parseInt((await We(_e(`${t}
2
+ "use strict";(()=>{var On=Object.defineProperty;var $n=(t,e,n)=>e in t?On(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var h=(t,e,n)=>$n(t,typeof e!="symbol"?e+"":e,n);var wt=Reflect.apply,Ne=Object.getOwnPropertyDescriptor,fe=Object.getPrototypeOf,R=globalThis,v=(t,e,n)=>wt(t,e,n),O=(t,e)=>t?Ne(t,e)?.get:void 0,Oe=(t,e)=>t?Ne(t,e)?.set:void 0,P=t=>R[t]?.prototype,vt=(t,e,n)=>wt(t,e,n);var ji=Date.now,Fi=new TextEncoder,Hi=new TextDecoder,Bi=TextEncoder.prototype.encode,Ui=TextDecoder.prototype.decode;var qi=O(fe(Uint8Array.prototype),"length");var Dn=Uint8Array,jn=t=>new Dn(t),Fn=[];for(let t=0;t<256;t++)Fn[t]=(t<16?"0":"")+t.toString(16);var Hn=Object.create(null);for(let t=0;t<64;t++)Hn["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[t]]=t;var lt=R.crypto?.subtle,$e=lt?fe(lt):void 0,Re=R.crypto,Bn=Re?fe(Re).getRandomValues:void 0,_i=$e?.digest,Wi=$e?.importKey,zi=$e?.sign;var kt=t=>v(Bn,Re,[jn(t)]),Vi={setTimeout:R.setTimeout,clearTimeout:R.clearTimeout,setInterval:R.setInterval,clearInterval:R.clearInterval};var Ki=R.fetch;var ne=P("MessagePort"),Zi=ne&&ne.postMessage,Ji=Oe(ne,"onmessage"),Yi=ne&&ne.start,De=P("MessageEvent"),Xi=O(De,"data"),Gi=O(De,"ports"),Qi=O(De,"source");var xt=P("EventTarget"),er=xt?.addEventListener,tr=xt?.removeEventListener;var nr=R.Worker,ue=P("Worker"),sr=ue&&ue.postMessage,ir=Oe(ue,"onmessage"),rr=Oe(ue,"onerror");var pt=R.Blob,he=R.URL,ct=he?.createObjectURL,Un=he?.revokeObjectURL,je=pt&&ct?{make:(t,e)=>v(ct,he,[new pt(t,{type:e})]),revoke:t=>v(Un,he,[t])}:void 0,ee=R.customElements,Fe=ee?fe(ee):void 0,qn=Fe?.define,_n=Fe?.get,He=ee&&Fe?{define:(t,e)=>v(qn,ee,[t,e]),get:t=>v(_n,ee,[t])}:void 0,At=R.document,me=P("Document"),Wn=me?.createElement,zn=me?.createElementNS,Vn=WeakSet.prototype.add,or=WeakSet.prototype.has,Be=new WeakSet,Kn=new WeakSet,ge=(t,e)=>(v(Vn,t,[e]),e);function D(t){return ge(Be,v(Wn,At,[t]))}var ye=t=>ge(Be,v(zn,At,["http://www.w3.org/2000/svg",t]));var K=t=>ge(Kn,t);var se=P("Node"),Ue=P("Element"),be=P("HTMLElement"),Z=t=>O(se,t),ut=Z("parentNode"),Zn=Z("firstChild"),Jn=Z("lastChild"),Yn=Z("nextSibling"),Xn=Z("nodeType"),Gn=Z("childNodes"),Qn=O(Ue,"localName"),es=se?.appendChild,ts=se?.insertBefore,ns=se?.removeChild,_=Ue,ss=_?.getAttribute,is=_?.getAttributeNames,rs=_?.setAttribute,os=_?.removeAttribute,as=_?.matches,ds=_?.attachShadow,ls=_?.querySelectorAll,ps=P("HTMLDialogElement")?.close,cs=O(P("NodeList"),"length"),us=P("NodeList")?.item,we=P("MutationRecord"),hs=O(we,"type"),ms=O(we,"target"),fs=O(we,"addedNodes"),gs=O(we,"removedNodes"),ht=R.MutationObserver,ys=P("MutationObserver")?.observe,Mt=me?Ne(me,"adoptedStyleSheets"):void 0,mt=Mt?.get,ft=Mt?.set,bs=R.requestAnimationFrame,gt=O(be,"style"),ve=P("CSSStyleDeclaration"),ws=ve?.getPropertyValue,vs=ve?.getPropertyPriority,ks=ve?.setProperty,yt=be?.showPopover,bt=be?.hidePopover,xs=O(P("Event"),"target"),As=P("Event")?.stopImmediatePropagation,ce=t=>{let e=[];for(let n=0,s=v(cs,t,[]);n<s;n++)e[n]=v(us,t,[n]);return e},te=ht&&se&&Ue&&be&&ve?{parent:t=>v(ut,t,[]),first:t=>v(Zn,t,[]),last:t=>v(Jn,t,[]),next:t=>v(Yn,t,[]),isElement:t=>v(Xn,t,[])===1,name:t=>v(Qn,t,[]),children:t=>ce(v(Gn,t,[])),append:(t,e)=>v(es,t,[e]),insert:(t,e,n)=>v(ts,t,[e,n]),remove:t=>{let e=v(ut,t,[]);e&&v(ns,e,[t])},attribute:(t,e)=>v(ss,t,[e]),attributes:t=>v(is,t,[]),setAttribute:(t,e,n)=>v(rs,t,[e,n]),removeAttribute:(t,e)=>v(os,t,[e]),matches:(t,e)=>v(as,t,[e]),all:(t,e)=>ce(v(ls,t,[e])),closeDialog:t=>v(ps,t,[]),shadow:t=>v(ds,t,[{mode:"closed"}]),style:(t,e)=>{let n=v(gt,t,[]);return[v(ws,n,[e]),v(vs,n,[e])]},setStyle:(t,e,n,s="")=>v(ks,v(gt,t,[]),[e,n,s]),observer:t=>new ht(t),observe:(t,e,n)=>v(ys,t,[e,n]),record:t=>({type:v(hs,t,[]),target:v(ms,t,[]),added:ce(v(fs,t,[])),removed:ce(v(gs,t,[]))}),adopted:mt&&ft?{count:t=>v(mt,t,[]).length,clear:t=>v(ft,t,[[]])}:void 0,frame:t=>v(bs,globalThis,[t]),popover:yt&&bt?{show:t=>v(yt,t,[]),hide:t=>v(bt,t,[])}:void 0,target:t=>v(xs,t,[]),stop:t=>v(As,t,[])}:void 0;function qe(t){if(ge(Be,t),te)for(let e of te.children(t))te.isElement(e)&&qe(e);return t}var _e=t=>new TextEncoder().encode(t);function Ms(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 We(t){return Ms(await crypto.subtle.digest("SHA-256",t))}var Es=["name","type","tags","location","site","district","region","organization","path","timeZone"],Ss=["text","date","currency","truncate"],Et={site:"SITE",district:"DISTRICT",region:"REGION",organization:"ORGANIZATION"};function ke(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(o=>o.name).join(" \u203A "):void 0;case"timeZone":return e||void 0;default:return Et[n]?[...i].reverse().find(o=>o.kind===Et[n])?.name:void 0}}function Ts(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 ze(t,e){return(t.source==="screen"?ke(e.screen,e.timeZone,t.field,t.key):Ts(e.tables?.[t.table]?.rows?.[t.row??0]?.[t.column],t.format))??t.fallback??""}function Ps(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"),i=n.find(o=>!o[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}:{}}:Es.includes(e[1])?{source:"screen",field:e[1],...s!==void 0?{fallback:s}:{}}:null:i&&!Ss.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 Ve(t,e){return t.replace(/\{{2}([^{}]*)\}{2}/g,(n,s)=>{let i=Ps(s);return i?ze(i,e):n})}function St(t,e){return Object.fromEntries(Object.entries(t).map(([n,s])=>[n,typeof s=="string"?Ve(s,e):s]))}var Ke=t=>t==null||t==="";function Pt(t,e,n,s,i,o){return Ls(t,e,n,s,{now:i,timeZone:o})}function Ls(t,e,n,s,i){if(n===null&&(e==="eq"||e==="ne"))return e==="eq"?Ke(t):!Ke(t);if(Ke(t)||n===null||n===void 0)return!1;switch(s){case"number":case"currency":{let o=Number(t),r=Number(n);return typeof n!="boolean"&&n!==""&&Number.isFinite(o)&&Number.isFinite(r)&&Ze(e,o-r)}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"?Is(i.now,i.timeZone).date:String(n),r=String(t).slice(0,10);return/^\d{4}-\d{2}-\d{2}$/.test(o)&&Ze(e,r<o?-1:r>o?1:0)}case"datetime":{let o=Date.parse(String(t)),r=n==="now"?i.now:Date.parse(String(n));return!Number.isNaN(o)&&!Number.isNaN(r)&&Ze(e,o-r)}default:{let o=String(t).toLowerCase(),r=String(n).toLowerCase();return e==="eq"?o===r:e==="ne"?o!==r:e==="contains"?o.includes(r):!1}}}function Ze(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 Tt=new Map;function Is(t,e){let n=Tt.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"}),Tt.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 Lt=(t,e)=>!t||(t.from===void 0||t.from<=e)&&(t.until===void 0||e<t.until);var ie=class{constructor(e,n,s,i,o){h(this,"renderer",e);h(this,"wrap",i);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 Je=class extends Error{constructor(n,s){super(s);h(this,"code",n);this.name="MediaError"}};function Ye(t){return t instanceof Je?{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 It=t=>t.blob.contentType.startsWith("video/");var Xe="position:absolute;inset:0;width:100%;height:100%;object-fit:contain",Rs=1,xe=class{constructor(e,n={}){h(this,"container",e);h(this,"options",n);h(this,"prepared",new Map);h(this,"shown",null);h(this,"endListeners",new Set);h(this,"itemListeners",new Set);h(this,"appListeners",new Set);h(this,"held",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((i,o)=>{let r=this.shown;if(r?.mediaId===i)for(let a of this.endListeners)a(r.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(i){return 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){await this.prepare(e);let n=this.prepared.get(e);if(!n)throw new Error("the slide was released before it was shown");this.prepared.delete(e);let s=this.shown,i=this.options.media,o=s?Rt(e):void 0;if(n.kind==="layout"&&o===void 0){await H(()=>{s?this.container.insertBefore(n.el,s.el):this.container.append(n.el),this.shown=n,this.shownHash=e.blob.hash}),this.held=[],await n.view.start().catch(()=>{});let r=Promise.resolve();return await H(()=>{this.shown===n&&(n.el.style.visibility="",s?.el.remove(),i&&this.paint("transparent"),i&&s?.mediaId&&(r=i.show([],[s.mediaId],Date.now())))}),await r.catch(()=>{}),s&&this.dispose(s),this.releaseHeld(),"cut"}if(o!==void 0&&i&&n.kind==="native"&&s.kind==="native"){if(n.fadesIn&&!n.queued){let r=Promise.resolve();return await H(()=>{n.el.style.visibility="",this.container.insertBefore(n.el,s.el),r=i.show([n.mediaId],[],Date.now()),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{}),Ns(o).then(async()=>{await i.show([],[s.mediaId],Date.now()).catch(()=>{}),s.el.remove(),this.dispose(s)}),"crossfade"}}else if(o!==void 0&&i&&n.kind==="native"){let r=Promise.resolve();return await H(()=>{n.el.style.visibility="",this.container.insertBefore(n.el,s.el),r=i.show([n.mediaId],[],Date.now()),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{}),this.paint("transparent"),Nt(s.el,1,0,o).then(()=>{s.el.remove(),this.dispose(s)}),"crossfade"}else if(o!==void 0)return await H(()=>{n.el.style.visibility="",n.el.style.opacity="0",this.container.append(n.el),n.kind==="video"&&Ge(n.el),this.shown=n,this.shownHash=e.blob.hash}),n.view&&(this.held=[],n.view.start().then(()=>this.releaseHeld())),Nt(n.el,0,1,o).then(async()=>{s.el.remove(),this.shown===n&&this.paint(i?"#000":""),i&&s.mediaId&&await i.show([],[s.mediaId],Date.now()).catch(()=>{}),this.dispose(s)}),"crossfade";if(i&&n.kind==="native"){let r=Promise.resolve();await H(()=>{n.el.style.visibility="",s?this.container.insertBefore(n.el,s.el):this.container.prepend(n.el),r=i.show([n.mediaId],s?.mediaId?[s.mediaId]:[],Date.now()),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{}),await H(()=>{this.shown===n&&(s?.el.remove(),this.paint("transparent"))})}else{let r=Promise.resolve();await H(()=>{n.el.style.visibility="",n.el.parentNode!==this.container&&this.container.append(n.el),s?.el.remove(),this.paint(i?"#000":""),i&&s?.mediaId&&(r=i.show([],[s.mediaId],Date.now())),n.kind==="video"&&Ge(n.el),this.shown=n,this.shownHash=e.blob.hash}),await r.catch(()=>{})}return s&&this.dispose(s),"cut"}paint(e){this.options.background?this.options.background(e):this.container.style.background=e}standby(){let e=this.shown;this.shown=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"?Ge(e.el):e?.mediaId&&this.options.media?.control(e.mediaId,"play").catch(()=>{})}make(e){if(e.layout){let{doc:r,source:a,untilPass:l}=e.layout,d=K(D("div"));d.dataset.blob=e.blob.hash,d.style.cssText=`${Xe};visibility:hidden`,this.container.append(d);let u={slide:e,kind:"layout",el:d,ready:Promise.resolve()},p=y=>this.options.path?`${this.options.path}/${y}`:y,m=String(++this.drawn);return u.view=new J(r,a,d,{media:this.options.media,path:this.options.path,endsWith:l?p(l):void 0,onItem:y=>{let A={...y,slide:y.slide?`${m}.${y.slide}`:m};this.held?this.held.push(A):this.item(A)},onPassEnd:y=>{if(l&&y===p(l)&&this.shown===u){for(let A of this.endListeners)A(e);return"hold"}return this.options.onPassEnd?.(y)},onApp:y=>this.app(y)}),u.ready=u.view.ready,u}if(!It(e)){if(!e.bytes&&!e.url)throw new Error(`no bytes for ${e.blob.hash}`);let r=e.bytes?URL.createObjectURL(new Blob([e.bytes],{type:e.blob.contentType})):void 0,a=K(D("img"));return a.src=r??e.url,a.alt="",a.dataset.blob=e.blob.hash,a.style.cssText=this.fill(),{slide:e,kind:"image",el:a,objectUrl:r,ready:a.decode()}}let n=this.options.media;if(n){let r=`m-${Rs++}`,a=K(D("div"));a.dataset.blob=e.blob.hash,a.dataset.media=r,a.style.cssText=`${Xe};visibility:hidden`;let l=this.container.getBoundingClientRect(),d={x:l.left,y:l.top,w:l.width||window.innerWidth,h:l.height||window.innerHeight},u=Rt(e),p=u!==void 0&&this.shown?.kind==="native"&&n.capability.animates&&n.capability.layers>=2,m=p?[{property:"opacity",keyframes:[{t:0,v:0},{t:u,v:1}]}]:[],y={slide:e,kind:"native",el:a,mediaId:r,fadesIn:p,ready:Promise.resolve()},A=this.options.fit??"contain";return y.ready=n.prepare({mediaId:r,blob:e.blob.hash,contentType:e.blob.contentType,box:d,z:p?1:0,loop:e.loop,muted:!1,fit:A,...p?{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})),i=K(D("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 r of this.endListeners)r(e)}),i.addEventListener("error",()=>{if(this.shown?.el===i)for(let r of this.endListeners)r(e,`video: ${i.error?.message??"error"}`)});let o=new Promise((r,a)=>{if(i.readyState>=2)return r();i.addEventListener("loadeddata",()=>r(),{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:o}}item(e){this.options.onItem?.(e);for(let n of this.itemListeners)n(e)}releaseHeld(){let e=this.held;this.held=null,e?.length&&setTimeout(()=>{for(let n of e)this.item(n)},0)}fill(){let e=this.options.fit==="stretch"?"fill":this.options.fit??"contain";return Xe.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 Rt(t){if(t.transition?.type==="crossfade")return Math.max(0,Math.min(t.transition.durationMs??1e3,t.durationMs/2))}var Ns=t=>new Promise(e=>setTimeout(e,t));function Nt(t,e,n,s){return new Promise(i=>{let o=Date.now(),r=!1,a=()=>{r||(r=!0,t.style.opacity=n===1?"":String(n),i())};t.style.opacity=String(e);let l=()=>{if(r)return;let d=Math.min(1,(Date.now()-o)/s);if(d>=1)return a();t.style.opacity=String(e+(n-e)*d),requestAnimationFrame(l)};requestAnimationFrame(l),setTimeout(a,s+250)})}function Ge(t){t.play().catch(()=>(t.muted=!0,t.play())).catch(()=>{})}function H(t){return new Promise((e,n)=>{let s=!1,i=()=>{if(!s){s=!0;try{t(),e()}catch(o){n(o)}}};requestAnimationFrame(i),setTimeout(i,250)})}var re={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 Ot=Symbol.for("wyndlass.app.attach");var F=class extends Error{constructor(n,s){super(`the app could not run (${n})`);h(this,"reason",n);h(this,"error",s)}};function W(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 oe(t){let e=t?.id;if(typeof e!="string"||e==="")return!0;for(let n=0;n<$t.length;n++)if(e[n]!==$t[n])return!1;return!0}var $t="com.wyndlass.";function $s(t=typeof navigator>"u"?"":navigator.userAgent){let e=/Chrom(?:e|ium)\/(\d+)/.exec(t);return e?Number(e[1]):void 0}function Dt(t,e=re.apiVersion,n=$s()){return!(t?.playerApi!==void 0&&t.playerApi>e||t?.webView!==void 0&&n!==void 0&&t.webView>n)}function Ds(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 Qe=new Map;function js(){let t=kt(8),e="";for(let n=0;n<8;n++)e+=Fs[t[n]%26];return e}var Fs="abcdefghijklmnopqrstuvwxyz",Hs=0;function jt(t,e,n){let s=Qe.get(t);if(!s){let i=je.make([e],"text/javascript");s=import(i).then(o=>Bs(o,n),o=>{throw o instanceof F?o:new F("load",W(o))}).finally(()=>je.revoke(i)),Qe.set(t,s),s.catch(()=>Qe.delete(t))}return s}function Bs(t,e){let n=t.default;if(typeof n=="function"&&n.prototype instanceof HTMLElement){let s=n.prototype[Ot];if(typeof s!="function")throw new F("shape");let i=class extends n{},o=`${e?.element??"wl-app"}-${js()}${++Hs}`;try{He.define(o,i)}catch(r){throw new F("shape",W(r))}return{tag:o,shape:"class",attach:(r,a)=>{vt(s,r,[a])}}}if(oe(e)&&typeof t.element=="string"&&He.get(t.element))return{tag:t.element,shape:"legacy"};throw new F("shape")}var Us=3,qs=6e4,Ae=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:Ds(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<qs),this.faults.push(n),this.faults.length>=Us&&this.stop(W(e))}},_s=24*3600*1e3,Me=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(),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),o=this.inflight.get(i);if(o)return o;let r=this.o.fetch??fetch,a=(async()=>{let l=this.stored(i),d=l?JSON.parse(l):void 0;if(d&&Date.parse(d.expiresAt)>this.now())return this.dress(d,!1);let u=this.url(`/v0/${encodeURIComponent(e)}?${s}`);try{if(!u)throw new Error("no data service");let p=await r(u);if(!p.ok)throw new Error(`the data service answered ${p.status}`);let m=await p.text();return this.keep(i,m),this.dress(JSON.parse(m),!1)}catch(p){if(d&&Date.parse(d.expiresAt)+_s>this.now())return this.dress(d,!0);throw p}})().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 Ft="wyndlass.frame";function Ut(t,e){return!!t&&(t.apps?t.apps(e):!oe(e))}var Ws=new Set(["load","shape","unsupported","error","late","overran"]),Ht=50,Bt=250,et=class{constructor(e,n,s,i){h(this,"frame",e);h(this,"port",n);h(this,"o",i);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 i=this.told;if(i&&(i.running?Math.abs(e-(i.t+(n-i.at)))<=Ht:e===i.t)){i.running&&this.watch();return}let o=!!s&&n-s.at<Bt&&e>s.t&&Math.abs(e-s.t-(n-s.at))<=Ht;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"})}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(){clearTimeout(this.quiet),this.port.close();for(let e of this.pending.values())e();this.pending.clear()}heard(e){e.type==="paging"?this.pages=_t(e.paging):e.type==="hooked"&&typeof e.id=="number"?(this.pending.get(e.id)?.(),this.pending.delete(e.id)):e.type==="stopped"&&this.stop(Wt(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}))},Bt)}};async function qt(t,e,n,s,i,o,r,a,l,d){let u=t.appInfo??n.info,p;try{p=new URL(l.frames).origin}catch{return d("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 y=new Promise(M=>{m.addEventListener("load",()=>M(!0),{once:!0}),setTimeout(()=>M(!1),o)});m.src=`${p}/`,e.append(m);let A=(M,w)=>(m.remove(),d(M,w));if(!await y||!m.contentWindow)return A("load");let{port1:f,port2:k}=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:Ks(t.props??{},l),snapshots:Zs(t,s),deadlineMs:o};return new Promise(M=>{let w,T=!1,N=G=>{T||(T=!0,clearTimeout(j),M(G))},j=setTimeout(()=>{w?(N({app:w,late:!0}),w.update(i.now())):(f.close(),N(A("load")))},o+1e3),q=!1;f.onmessage=G=>{let x=G.data;if(!(!x||typeof x!="object")){if(x.type==="ask"){q&&zs(x,s,f);return}if(w){x.type==="ready"?(N({app:w,late:x.late===!0}),w.update(i.now())):w.heard(x);return}x.type==="hello"&&!q?(q=!0,f.postMessage(b,[b.bundle.bytes.buffer])):x.type==="made"&&Array.isArray(x.hooks)?(w=new et(m,f,{type:"made",hooks:x.hooks.filter(C=>C==="enter"||C==="exit"),paging:_t(x.paging)},{onStop:a}),r(w)):x.type==="failed"&&(f.close(),N(A(Ws.has(x.reason)?x.reason:"error",Wt(x.error))))}},m.contentWindow.postMessage({type:Ft},"*",[k])})}async function zs(t,e,n){if(typeof t.id!="number")return;let s=(i,o=[])=>{try{n.postMessage(i,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,Vs(t.params))});else if(t.what==="image"&&typeof t.path=="string"){let i=await e.data.imageBlob(t.path),o=new Uint8Array(await i.arrayBuffer());s({type:"answer",id:t.id,value:{bytes:o,type:i.type}},[o.buffer])}else throw new TypeError("not a question")}catch(i){s({type:"answer",id:t.id,error:W(i)??"Error"})}}function Vs(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 _t(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 Wt(t){return typeof t=="string"&&/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(t)?t:void 0}function Ks(t,e){let n=new Set;for(let i of Object.values(t)){let o=i?.family;i&&typeof i=="object"&&typeof o=="string"&&n.add(o)}let s=[];for(let i of e.fonts??[]){let o=n.has(i.family)?e.font?.(i.blob):void 0;o&&s.push({family:i.family,weight:i.weight,style:i.style,blob:i.blob,bytes:o.slice()})}return s}function Zs(t,e){let n=new Set;t.binding?.table&&n.add(t.binding.table);for(let i of Object.values(t.props??{}))typeof i=="string"&&/^tbl_[0-9a-z]{26}$/.test(i)&&n.add(i);let s={};for(let i of n){let o=e.snapshot?.(i);o&&(s[i]=o)}return s}function zt(t){let e=te?.setStyle??((n,s,i,o)=>n.style.setProperty(s,i,o));e(t,"contain","strict","important"),e(t,"overflow","clip","important")}var Vt=t=>!!(t?.filter?.length||t?.sort||t?.limit),Js=t=>t==null||t==="";function Ys(t,e){if(!Js(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 Xs(t,e){let n=Array.from(t),s=Array.from(e);for(let i=0;i<n.length&&i<s.length;i++){let o=n[i].codePointAt(0)-s[i].codePointAt(0);if(o!==0)return o}return n.length-s.length}function Gs(t,e,n,s,i){let o=t,r=Array.isArray(o?.rows)?o.rows:[],a=Array.isArray(o?.columns)?o.columns:void 0,l=d=>a?.find(u=>u.key===d)?.type??"text";for(let d of e.filter??[]){if(a&&!a.some(m=>m.key===d.column))return[];let u=d.value;if(u!==null&&typeof u=="object"){let m=u;if(u=ke(n,s,m.screen,m.key),u===void 0)return[]}let p=l(d.column);r=r.filter(m=>Pt(m[d.column],d.op,u,p,i,s))}if(e.sort){let{column:d}=e.sort,u=l(d),p=e.sort.order==="desc"?-1:1;r=r.map((m,y)=>({row:m,i:y,key:Ys(m[d],u)})).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 A=typeof m.key=="number"&&typeof y.key=="number"?m.key-y.key:Xs(String(m.key),String(y.key));return A===0?m.i-y.i:A<0?-p:p}).map(m=>m.row)}return e.limit?r.slice(0,e.limit):r}function Kt(t,e,n,s,i){return!t||typeof t!="object"?t:{...t,rows:Gs(t,e,n,s,i)}}function Qs(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 Jt(t,e,n,s=[]){let i=D("div");if(i.dataset.background="",i.style.cssText="position:absolute;inset:0;pointer-events:none",i.style.background=Qs(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(""),r=`<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(r)}")`;i.dataset.holes=String(s.length);for(let[l,d]of[["maskImage",a],["maskSize","100% 100%"],["maskRepeat","no-repeat"]])i.style[l]=d,i.style[`webkit${l[0].toUpperCase()}${l.slice(1)}`]=d}return t.prepend(i),i}function Yt(t,e=t.frame){let n=D("div");return n.dataset.element=t.id,n.style.cssText="position:absolute;box-sizing:border-box",ei(n,e),n}function ei(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 Xt(t,e,n){if(e.type==="text"){let s=e.style??{},i=Gt(n);t.textContent=e.bind?ze(e.bind,i):Ve(e.text??"",i),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"&&ti(e)?(t.style.opacity=e.opacity!==void 0?String(e.opacity):"",t.append(ni(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 Gt(t){return{screen:t?.screen??null,timeZone:t?.timeZone,tables:new Proxy({},{get:(e,n)=>typeof n=="string"?t?.snapshot?.(n):void 0})}}var ti=t=>t.shape==="line"||t.shape==="arrow"||t.shape==="polygon";function ni(t){let e=ye("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),r=(t.points?.length?t.points:t.shape==="polygon"?[[.5,0],[1,1],[0,1]]:[[0,.5],[1,.5]]).map(([u,p])=>[u*n,p*s]),a=t.stroke?.color?.value??"#000000",l=t.stroke?.dash==="dashed"?`${i*3} ${i*2}`:t.stroke?.dash==="dotted"?`0 ${i*2}`:"",d=ye(t.shape==="polygon"?"polygon":"polyline");if(d.setAttribute("points",r.map(u=>`${u[0]},${u[1]}`).join(" ")),d.setAttribute("fill",t.shape==="polygon"?t.fill?.value??"none":"none"),i&&(d.setAttribute("stroke",a),d.setAttribute("stroke-width",String(i)),d.setAttribute("stroke-linecap",t.stroke?.dash==="dotted"?"round":"butt"),d.setAttribute("stroke-linejoin","round"),l&&d.setAttribute("stroke-dasharray",l)),e.append(d),t.shape==="arrow"&&r.length>=2){let[u,p]=[r[r.length-2],r[r.length-1]],m=Math.atan2(p[1]-u[1],p[0]-u[0]),y=Math.max(10,i*3.5),A=k=>`${p[0]-y*Math.cos(m)+k*y*.5*Math.sin(m)},${p[1]-y*Math.sin(m)-k*y*.5*Math.cos(m)}`;d.setAttribute("points",[...r.slice(0,-1),[p[0]-y*.8*Math.cos(m),p[1]-y*.8*Math.sin(m)]].map(k=>`${k[0]},${k[1]}`).join(" "));let f=ye("polygon");f.setAttribute("points",`${p[0]},${p[1]} ${A(1)} ${A(-1)}`),f.setAttribute("fill",a),e.append(f)}return e}async function Qt(t,e,n,s,i,o,r,a=()=>{},l){let d=t.appInfo??n.info;zt(e),d?.id&&(e.dataset.app=d.id);let u=(x,C)=>(e.dataset.appFailed=x,{failed:x,...C?{error:C}:{}});if(!Dt(d?.requires))return u("unsupported");let p=s.appHost;if(p&&!p.custom&&!oe(d))return u("unsupported");if(Ut(l,d))return qt(t,e,n,s,i,o,r,a,l,u);let m=t.app;if(p?.held?.(m))return e.dataset.appHeld="",{held:!0};await p?.mounting?.(m,d?.id);let y=!1,A=()=>{y||(y=!0,p?.unmounted?.(m))},f;try{f=await jt(n.hash,n.bytes,d)}catch(x){return A(),x instanceof F?u(x.reason,x.error):u("load")}let k=f.tag,b=d?.id?s.controllerFor?.({id:d.id,instance:t.id,capability:d.player??"read"}):void 0,M,w=new Promise(x=>{M=x}),T,N={app:d?.id??t.app.id,element:k,props:St(t.props??{},Gt(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:(x,C)=>s.data?s.data.get(x,C):Promise.reject(new Error("no data service")),kept:(x,C)=>s.data?.kept?.(x,C),image:x=>s.data?s.data.image(x):Promise.reject(new Error("no data service")),snapshot:x=>{let C=s.snapshot?.(x)??null;if(!C||t.binding?.table!==x||!Vt(t.binding))return C;let Q=Kt(C,t.binding,s.screen,N.timeZone,i.now());return T?.from===C&&T.rows.length===Q.rows.length&&T.rows.every((Rn,Nn)=>Rn===Q.rows[Nn])?T.snapshot:(T={from:C,rows:Q.rows,snapshot:Q},Q)},...t.binding?{binding:t.binding}:{},...t.sensors?.includes("impressions")&&s.impressions?.measuring?{impressions:{now:()=>s.impressions.now(),on:x=>s.impressions.on(x)}}:{},...b?{controller:b}:{}},j;try{j=D(k),f.shape==="class"?f.attach(j,N):j.wyndlass=N}catch(x){return b?.dispose(),A(),u("error",W(x))}j.style.cssText="display:block;width:100%;height:100%",p?.contained?.(e,j);let q=new Ae(j,{onStop:a,dispose:()=>{b?.dispose(),A()}});e.append(j),r(q);let G=await Promise.race([w.then(()=>!1),new Promise(x=>setTimeout(()=>x(!0),o))]);return q.update(N.now()),{app:q,late:G}}var Zt=new Set;async function en(t,e){for(let n of t){let s=`${n.family}/${n.weight??400}/${n.style??"normal"}/${n.blob}`,i=e(n.blob);if(!(Zt.has(s)||!i||typeof FontFace>"u"))try{let o=new FontFace(n.family,i,{weight:String(n.weight??400),style:n.style??"normal"});document.fonts.add(await o.load()),Zt.add(s)}catch{}}}function ae(t){let e=[],n=null;for(let s of t){let i=s.start,o=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:o,endMs:o+s.durationMs},e.push(n)}return{clips:e,autoDurationMs:e.reduce((s,i)=>Math.max(s,i.endMs),0)}}var si=new Set(["x","y","scaleX","scaleY","rotation","opacity","reveal"]);function ii(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 i=t.slice(0,-1).filter(o=>o.type==="shape"&&o.clip!==!1);if(i.some(o=>o.shape!=="rectangle"||(o.radius??0)>0))return s("clipped-to-shape");if(i.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(r=>si.has(r))))return s("animated")}return{path:"native"}}var ri={fade:["opacity"],slide:["x","opacity"],scale:["scaleX","scaleY","opacity"],pulse:["scaleX","scaleY"],loop:["scaleX","scaleY"],wipe:["reveal"]};function tn(t,e,n,s){let i=e&&t.overrides?.[e]||{},o=new Map;for(let p of t.animation?.clips??[]){let m=[...p.preset?ri[p.preset]??[]:[],...(p.lanes??[]).map(y=>y.property)];o.set(p.element,[...o.get(p.element)??[],...m])}let r=p=>p.type==="library"&&!!p.source&&!!n[p.source.item.id]?.video,a=p=>!r(p)&&!(p.type==="shape"&&!p.fill&&!(p.stroke?.width??0)),l=[],d=(p,m,y,A)=>{for(let f of p){let k=i[f.id];if(k?.hidden??f.hidden??!1)continue;let b=k?.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:o.get(f.id)??[],...f.type==="shape"?{shape:f.shape,radius:f.radius,clip:f.clip}:{}};l.push({e:f,box:M,chain:[...y,w],ancestors:A}),f.type==="shape"&&d(f.children??[],M,[...y,w],[...A,f])}};d(t.elements,{x:0,y:0},[],[]);let u=(p,m)=>p.x<m.x+m.w&&m.x<p.x+p.w&&p.y<m.y+m.h&&m.y<p.y+p.h;return l.flatMap((p,m)=>{if(!r(p.e))return[];let y=l.slice(0,m).some(A=>a(A.e)&&u(A.box,p.box));return[{element:p.e.id,path:ii(p.chain,{pageBelow:y},s),box:p.box}]})}var oi=[0,0,1,1];function tt(t,e){if(e<=0)return 0;if(e>=1)return 1;let[n,s,i,o]=t;if(n===s&&i===o)return e;let r=3*n,a=3*(i-n)-r,l=1-r-a,d=3*s,u=3*(o-s)-d,p=1-d-u,m=w=>((l*w+a)*w+r)*w,y=w=>((p*w+u)*w+d)*w,A=w=>(3*l*w+2*a)*w+r,f=1e-7,k=e;for(let w=0;w<8;w++){let T=m(k)-e;if(Math.abs(T)<f)return y(k);let N=A(k);if(Math.abs(N)<1e-6)break;k-=T/N}let b=0,M=1;for(k=e;b<M;){let w=m(k);if(Math.abs(w-e)<f||(e>w?b=k:M=k,k=(M-b)/2+b,M-b<f))break}return y(k)}function Ee(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 o=n[i],r=n[i+1];return o.v+(r.v-o.v)*tt(o.easing??oi,(e-o.t)/(r.t-o.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]=Ee(i,n);return s}var de={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 sn(t){if(!t)return de.ease;if(de[t])return de[t];let n=/^cubic-bezier\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\)$/.exec(t)?.slice(1).map(Number);return n&&n.every(Number.isFinite)?n:de.ease}function ai(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 an={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})},Zo=Object.keys(an);var di={x:t=>t.x,y:t=>t.y,scaleX:()=>1,scaleY:()=>1,rotation:()=>0,opacity:()=>1,reveal:()=>1,chars:()=>1,count:()=>1},rn=1e3,li=de["ease-in-out"];function dn(t,e){let n=ae(t).clips,s=new Map,i=new Set,o=a=>{let l=s.get(a);return l||s.set(a,l={keys:new Map,colour:null,loops:[],tickers:[]}),l},r=(a,l,d)=>{let u=o(a).keys,p=u.get(l)??[];u.set(l,p),p.push(d)};t.forEach((a,l)=>{let d=e.get(a.element);if(!d)return;let{startMs:u,endMs:p}=n[l],m=sn(a.easing);if(a.lanes?.length){for(let f of a.lanes)for(let k of f.keyframes){let b={t:u+k.at,easing:sn(k.easing??a.easing)};if(f.property==="color"){let M=ai(k.value);if(!M)continue;let w=o(a.element);w.colour??(w.colour=[[],[],[],[]]),M.forEach((T,N)=>w.colour[N].push({...b,v:T}))}else r(a.element,f.property,{...b,v:Number(k.value)})}return}let y=a.preset??"fade";if(a.kind==="emphasis"){y==="pulse"?(r(a.element,"pulse",{t:u,v:1,easing:m}),r(a.element,"pulse",{t:(u+p)/2,v:1.05,easing:m}),r(a.element,"pulse",{t:p,v:1})):y==="loop"?o(a.element).loops.push({startMs:u,endMs:p}):y==="ticker"?o(a.element).tickers.push({startMs:u,endMs:p}):i.add(y);return}let A=an[y];if(!A){i.add(y);return}for(let[f,k]of Object.entries(A(d))){let b=di[f](d),[M,w]=a.kind==="enter"?[k,b]:[b,k];r(a.element,f,{t:u,v:M,easing:m}),r(a.element,f,{t:p,v:w})}});for(let a of s.values()){for(let l of a.keys.values())l.sort((d,u)=>d.t-u.t);for(let l of a.colour??[])l.sort((d,u)=>d.t-u.t)}return{motions:s,unplayed:[...i].sort()}}var pi=["x","y","scaleX","scaleY","rotation","opacity"];function ln(t,e,n,s=!1){if(s)return ci(t,e,n);let i=(l,d)=>{let u=t?.keys.get(l);return u?Ee({property:"x",keyframes:u},n):d},o=nn(e,pi.flatMap(l=>t?.keys.get(l)?[{property:l,keyframes:t.keys.get(l)}]:[]),n),r=i("pulse",1);for(let l of t?.loops??[])if(n>=l.startMs&&n<l.endMs){let d=(n-l.startMs)%rn/rn;r*=1+.05*tt(li,d<.5?d*2:2-d*2)}let a=t?.tickers.find(l=>n>=l.startMs&&n<l.endMs);return{...o,reveal:i("reveal",1),chars:i("chars",1),count:i("count",1),pulse:r,scroll:a?(n-a.startMs)/(a.endMs-a.startMs):null,color:t?.colour?t.colour.map(l=>Ee({property:"x",keyframes:l},n)):null}}function on(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 ci(t,e,n){let s=(i,o)=>{let r=t?.keys.get(i);return r?on(r,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(i=>on(i,n)):null}}function ui(t,e){let n=Array.from(t);return e>=1?t:n.slice(0,Math.max(0,Math.round(e*n.length))).join("")}function hi(t,e){return e>=1?t:t.replace(/\d+(?:\.\d+)?/g,n=>(Number(n)*Math.max(0,e)).toFixed((n.split(".")[1]??"").length))}function pn(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 cn(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(o=>Math.round(o)).join(",")},${n.color[3]})`:null;if(e.type==="text"&&s!==void 0){let o=hi(ui(s,n.chars),n.count);if(n.scroll!==null){let r=t.querySelector("[data-ticker]");r||(r=document.createElement("span"),r.dataset.ticker="",r.style.cssText="display:inline-block;white-space:nowrap;will-change:transform",t.replaceChildren(r),t.style.overflow="hidden"),r.textContent!==o&&(r.textContent=o);let a=e.frame.w,l=r.scrollWidth;r.style.transform=`translateX(${a-n.scroll*(a+l)}px)`}else(t.textContent!==o||t.querySelector("[data-ticker]"))&&(t.textContent=o,t.style.overflow="");i&&(t.style.color=i)}else if(e.type==="shape"&&i){let o=t.querySelector("polygon, polyline");o&&e.shape==="polygon"?o.setAttribute("fill",i):o||(t.style.background=i)}}function mi(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 un(t,e,n,s){let i=parseInt((await We(_e(`${t}
3
3
  ${e}
4
- ${n}`))).slice(0,8),16),o=hi(i),r=Array.from({length:s},(a,d)=>d);for(let a=s-1;a>0;a--){let d=Math.floor(o()*(a+1));[r[a],r[d]]=[r[d],r[a]]}return r}var mi=250,fi=1e3;function Ct(t,e){let n=t.animation?.duration;if(n?.kind==="fixed")return{durationMs:n.ms};if(n?.kind==="untilPlaylistEnds"){let s=fn(t.elements,n.element);return{durationMs:(s?.source?.kind==="playlist"?e.playlist(s.source.item)??[]:s?.source?[{item:s.source.item}]:[]).reduce((r,a)=>r+(e.slide(a,{imageDurationMs:s?.playback?.imageDurationMs})?.durationMs??0),0)||1e4,untilPass:n.element}}return{durationMs:ae(t.animation?.clips??[]).autoDurationMs}}function mn(t,e,n=0){let s={},i=o=>{for(let r of o){if(r.type==="library"&&r.source){let a=r.source.kind==="playlist"?e.playlist(r.source.item)??[]:[{item:r.source.item}];s[r.source.item.id]={video:a.some(d=>{let l=e.slide(d);if(!l)return!1;if(l.blob.contentType.startsWith("video/"))return!0;let c=l.layout;return!!c&&n<4&&Object.values(mn(c.doc,c.source,n+1)).some(p=>p.video)})}}r.children&&i(r.children)}};return i(t.elements),s}function fn(t,e){for(let n of t){if(n.id===e)return n;let s=n.children&&fn(n.children,e);if(s)return s}}var J=class{constructor(e,n,s,i={}){h(this,"source",n);h(this,"o",i);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,"reduced",typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches);let o=s.clientWidth||window.innerWidth,r=s.clientHeight||window.innerHeight,a=!e.profiles[0].width,d=a?{...e.profiles[0],width:o,height:r}:e.profiles[0];a&&(e={...e,elements:e.elements.map(b=>b.frame.w?b:{...b,frame:{x:0,y:0,w:o,h:r}})});let l=Math.min(o/d.width,r/d.height);this.el=D("div"),this.el.dataset.layout=d.id,this.el.style.cssText=`position:absolute;left:${(o-d.width*l)/2}px;top:${(r-d.height*l)/2}px;width:${d.width}px;height:${d.height}px;transform:scale(${l});transform-origin:0 0;overflow:hidden`,s.append(this.el),this.doc=e;let c=new Map,p=b=>{for(let M of b)c.set(M.id,M.frame),M.children&&p(M.children)};p(e.elements);let m=dn(e.animation?.clips??[],c);this.motions=m.motions;let y=new Set(m.unplayed.map(b=>`preset ${b}`)),A=[this.loadFonts()],f=i.media?tn(e,void 0,mn(e,n),i.media.capability):[];this.native=new Set(f.filter(b=>b.path.path==="native").map(b=>b.element));let k=(b,M)=>{for(let w of b){if(w.hidden)continue;let T=this.element(w,y,A);M.append(T),w.children?.length&&w.type==="shape"&&k(w.children,T)}};k(e.elements,this.el),e.background&&Jt(this.el,e.background,d,f.filter(b=>this.native.has(b.element)).map(b=>b.box)),this.unplayed=[...y].sort(),this.ready=Promise.all(A).then(()=>{})}path(e){return this.o.path?`${this.o.path}/${e}`:e}element(e,n,s){let i=Yt(e);Xt(i,e,this.source);let o=this.motions.get(e.id);if(o){let r={el:i,e,motion:o,text:e.type==="text"?i.textContent??"":void 0};this.animated.push(r),this.place(r,0)}if(e.type==="library"&&e.source){let r=e.source.kind==="playlist"?this.source.playlist(e.source.item)??[]:[{item:e.source.item}],a=new nt(i,r,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 d of a.unplayed)n.add(d)}else if(e.type==="app"){let r=e.app?this.source.app?.(e.app):null;r?s.push(this.mountApp(e,i,r)):n.add(`app ${e.app?.id??e.id}`)}return i}place(e,n){cn(e.el,e.e,ln(e.motion,e.e.frame,n,this.reduced),e.text);let s=e.e.type==="text"?e.el.firstElementChild:null;s&&qe(s)}loadFonts(){return en(this.doc.fonts??[],e=>this.source.font(e))}async mountApp(e,n,s){let i=this.path(e.id),o=e.app,r=(e.appInfo??s.info)?.id,a={now:()=>this.heldAt??Date.now(),startedAt:()=>this.startedAt||Date.now()},d=(p,m)=>this.o.onApp?.({type:"app.failed",element:i,item:o,...r?{app:r}:{},reason:p,...m?{error:m}:{}}),l=this.o.isolate?{...this.o.isolate,fonts:this.doc.fonts,font:p=>this.source.font(p)}:void 0,c=await Qt(e,n,s,this.source,a,this.o.appDeadlineMs??5e3,p=>{this.disposed?p.dispose():this.apps.push({app:p,box:n,path:i,id:e.id,item:o})},p=>d("error",p),l);if(!("held"in c)){if("failed"in c){d(c.failed,c.error);return}c.late&&(this.late.push(i),this.o.onAppLate?.(i,o.id),d("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 o of this.animated)this.place(o,i);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=ae(n).clips,i=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches;for(let o of this.apps){let a=n.map((f,k)=>({c:f,t:s[k]})).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 d=o.box,l=this.animated.findIndex(f=>f.el===d);l>=0&&(this.animated.splice(l,1),Object.assign(d.style,{opacity:"",transform:"",clipPath:""}));let c=(f,k,b)=>this.hook(o,f.kind,{startAt:k,preset:f.preset??"fade",durationMs:f.durationMs,easing:f.easing,delayMs:0,...f.staggerMs?{staggerMs:f.staggerMs}:{},...b!==void 0?{page:b}:{},reducedMotion:i},d);for(let{c:f,t:k}of a)c(f,e+k.startMs);let p=o.app.paging();if(!p)continue;let m=a.find(f=>f.c.kind==="enter")?.c,y=a.find(f=>f.c.kind==="exit")?.c,A=pn(p.count,p.ms,Ct(this.doc,this.source).durationMs);for(let f=1;f<A.length;f++){let k=e+A[f].startMs;y&&c(y,k-y.durationMs,A[f-1].page),m&&c(m,k,A[f].page)}}}hook(e,n,s,i){let o=!1;e.app.hook(n,s).finally(()=>{o=!0});let r=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"&&(i.style.visibility="hidden"))},Math.max(0,r+mi-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.el.remove()}},hn=t=>Math.min(Math.max(0,t),2**31-1),nt=class{constructor(e,n,s,i,o,r,a){h(this,"region",e);h(this,"playback",s);h(this,"source",i);h(this,"path",o);h(this,"o",r);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 xe(e,{media:r.media,fit:s.fit,path:o,onItem:r.onItem,onPassEnd:r.onPassEnd,onApp:r.onApp}),s.transition==="slide"&&this.unplayed.push("transition slide");let d=s.transition==="fade"?{type:"crossfade"}:void 0,l=n.map(c=>i.slide(c,{imageDurationMs:s.imageDurationMs,transition:d,region:!0})).filter(c=>!!c);this.slides=l.length===1&&l[0].untilEnd&&(s.onEnd??"loop")==="loop"?[{...l[0],untilEnd:!1,loop:!0}]:l,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 un(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=>Lt(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()},hn(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,...Ye(s)}),this.o.onItem?.({type:"item.end",element:this.path,item:e.item,blob:e.blob.hash,endedAt:Date.now(),reason:"error"}),this.schedule(fi);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 ie(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")},hn(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 st=t=>t!=null&&t!==""&&!(Array.isArray(t)&&t.length===0);function gn(t,e,n,s=[]){let i=t[n];if(!i)return!1;if(!i.when)return!0;if(s.includes(n))return!1;let o=r=>String(r);for(let[r,a]of Object.entries(i.when)){if(!t[r]||r===n)return!1;let l=gn(t,e,r,[...s,n])?e[r]!==void 0?e[r]:t[r].default:void 0,c=Array.isArray(l)?l.map(o):st(l)?[o(l)]:[];if(a.set!==void 0&&a.set!==st(l)||a.anyOf&&!(st(l)&&!Array.isArray(l)?a.anyOf.map(o).includes(o(l)):c.some(p=>a.anyOf.map(o).includes(p)))||a.allOf&&!a.allOf.map(o).every(p=>c.includes(p))||a.noneOf&&c.some(p=>a.noneOf.map(o).includes(p)))return!1}return!0}function yn(t,e){return Object.keys(t).filter(n=>gn(t,e,n))}var da=re.apiVersion,bn=new Map(re.commands.map(t=>[t.name,t]));var W=class extends Error{constructor(n,s){super(s);h(this,"code",n)}};function wn(t,e){let n=e.capability??"read",s={kind:"app",app:e.id,instance:e.instance},i=new Set,o=!1,r=async(a,d={})=>{if(o)throw new W("NOT_ALLOWED","This app has been removed from the screen.");let l=bn.get(a);if(!l)throw new W("UNKNOWN",`There is no command ${a}.`);if(l.apps==="none")throw new W("NOT_ALLOWED",`Apps cannot call ${a}.`);if(l.apps==="control"&&n!=="control")throw new W("NOT_ALLOWED",`${a} needs capabilities.player: control in ${e.id}'s definition.`);let c=await t.call(a,d,s);if(c.ok)return c.result;if(c.code==="PREVIEW")return{applied:!1,reason:"preview"};throw new W(c.code,c.message)};return{app:e.id,instance:e.instance,capability:n,status:()=>t.status(),get:a=>t.status()[a],on(a,d){if(o)return()=>{};let l=t.on(a,d),c=()=>{l(),i.delete(c)};return i.add(c),c},time:()=>r("time.now"),call:r,play:()=>r("player.play"),pause:()=>r("player.pause"),stop:()=>r("player.stop"),next:()=>r("player.next"),previous:()=>r("player.previous"),finish:()=>r("app.finish"),dispose(){o=!0;for(let a of[...i])a()}}}var vn=["none","fade","scale","slide-up","slide-left"],Se=[["1920 \xD7 1080",1920,1080],["1080 \xD7 1920",1080,1920],["3840 \xD7 2160",3840,2160]],gi=[.25,.5,1,2,4],pe=3e4,En=5e3,yi={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:[]},I={frames:"",tables:{},controller:{status:{},events:{}}},B={people:new Set,player:new Map},Ce=[],rt=new Map,S=null,ot=null,at=null,Sn=-1,V=null,le=0,X={wall:0,t:0},Te=0,Pe=[],$=t=>document.getElementById(t),kn=$("stage"),bi=$("controls"),xn=$("report");function g(t,e={},...n){let s=document.createElement(t);for(let[i,o]of Object.entries(e))o==null||o===!1||(i.startsWith("on")&&typeof o=="function"?s.addEventListener(i.slice(2),o):i==="value"||i in s&&typeof o!="string"?s[i]=o:s.setAttribute(i,o===!0?"":String(o)));for(let i of n)i!=null&&s.append(i);return s}var wi=0;function E(t,e,n=!1){return e.id||(e.id=`c${++wi}`),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 z(t,e,n){let s=g("select",{onchange:()=>n(s.value)},...t.map(i=>{let[o,r]=Array.isArray(i)?i:[i,i];return g("option",{value:o,selected:o===e},r)}));return s}async function An(){let[t,e,n,s]=await Promise.all([fetch("/app.json").then(r=>r.json()),fetch("/app.js"),fetch("/samples.json").then(r=>r.json()),fetch("/config.json").then(r=>r.json())]);I=s;for(let[r,a]of Object.entries(I.tables))u.tables.has(dt(r))||Tn(r,a);S=t,Sn=Number(e.headers.get("x-preview-version")??-1),at=e.ok?null:await e.text(),ot=e.ok?new Uint8Array(await e.arrayBuffer()):null;let i=S.params??{},o={};for(let[r,a]of Object.entries(i))o[r]=u.touched.has(r)?u.props[r]:a.default;u.props=o;for(let[r,a]of Object.entries(n))r in u.samples||(u.samples[r]=a);Pn(),document.title=`${S.name}: Wyndlass app preview`,$("title").textContent=S.name,$("subtitle").textContent=`${S.id} ${S.version}`}var dt=t=>`tbl_${(t.replace(/\.(json|csv)$/i,"").toLowerCase().replace(/[^a-z0-9]+/g,"")||"table").slice(0,26).padEnd(26,"0")}`;function vi(t){let e=[],n=[],s="",i=!1;for(let o=0;o<t.length;o++){let r=t[o];if(i){r==='"'&&t[o+1]==='"'?(s+='"',o++):r==='"'?i=!1:s+=r;continue}r==='"'?i=!0:r===","?(n.push(s),s=""):r===`
4
+ ${n}`))).slice(0,8),16),o=mi(i),r=Array.from({length:s},(a,l)=>l);for(let a=s-1;a>0;a--){let l=Math.floor(o()*(a+1));[r[a],r[l]]=[r[l],r[a]]}return r}var fi=250,gi=1e3;function Ct(t,e){let n=t.animation?.duration;if(n?.kind==="fixed")return{durationMs:n.ms};if(n?.kind==="untilPlaylistEnds"){let s=fn(t.elements,n.element);return{durationMs:(s?.source?.kind==="playlist"?e.playlist(s.source.item)??[]:s?.source?[{item:s.source.item}]:[]).reduce((r,a)=>r+(e.slide(a,{imageDurationMs:s?.playback?.imageDurationMs})?.durationMs??0),0)||1e4,untilPass:n.element}}return{durationMs:ae(t.animation?.clips??[]).autoDurationMs}}function mn(t,e,n=0){let s={},i=o=>{for(let r of o){if(r.type==="library"&&r.source){let a=r.source.kind==="playlist"?e.playlist(r.source.item)??[]:[{item:r.source.item}];s[r.source.item.id]={video:a.some(l=>{let d=e.slide(l);if(!d)return!1;if(d.blob.contentType.startsWith("video/"))return!0;let u=d.layout;return!!u&&n<4&&Object.values(mn(u.doc,u.source,n+1)).some(p=>p.video)})}}r.children&&i(r.children)}};return i(t.elements),s}function fn(t,e){for(let n of t){if(n.id===e)return n;let s=n.children&&fn(n.children,e);if(s)return s}}var J=class{constructor(e,n,s,i={}){h(this,"source",n);h(this,"o",i);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,"reduced",typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches);let o=s.clientWidth||window.innerWidth,r=s.clientHeight||window.innerHeight,a=!e.profiles[0].width,l=a?{...e.profiles[0],width:o,height:r}:e.profiles[0];a&&(e={...e,elements:e.elements.map(b=>b.frame.w?b:{...b,frame:{x:0,y:0,w:o,h:r}})});let d=Math.min(o/l.width,r/l.height);this.el=D("div"),this.el.dataset.layout=l.id,this.el.style.cssText=`position:absolute;left:${(o-l.width*d)/2}px;top:${(r-l.height*d)/2}px;width:${l.width}px;height:${l.height}px;transform:scale(${d});transform-origin:0 0;overflow:hidden`,s.append(this.el),this.doc=e;let u=new Map,p=b=>{for(let M of b)u.set(M.id,M.frame),M.children&&p(M.children)};p(e.elements);let m=dn(e.animation?.clips??[],u);this.motions=m.motions;let y=new Set(m.unplayed.map(b=>`preset ${b}`)),A=[this.loadFonts()],f=i.media?tn(e,void 0,mn(e,n),i.media.capability):[];this.native=new Set(f.filter(b=>b.path.path==="native").map(b=>b.element));let k=(b,M)=>{for(let w of b){if(w.hidden)continue;let T=this.element(w,y,A);M.append(T),w.children?.length&&w.type==="shape"&&k(w.children,T)}};k(e.elements,this.el),e.background&&Jt(this.el,e.background,l,f.filter(b=>this.native.has(b.element)).map(b=>b.box)),this.unplayed=[...y].sort(),this.ready=Promise.all(A).then(()=>{})}path(e){return this.o.path?`${this.o.path}/${e}`:e}element(e,n,s){let i=Yt(e);Xt(i,e,this.source);let o=this.motions.get(e.id);if(o){let r={el:i,e,motion:o,text:e.type==="text"?i.textContent??"":void 0};this.animated.push(r),this.place(r,0)}if(e.type==="library"&&e.source){let r=e.source.kind==="playlist"?this.source.playlist(e.source.item)??[]:[{item:e.source.item}],a=new nt(i,r,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 r=e.app?this.source.app?.(e.app):null;r?s.push(this.mountApp(e,i,r)):n.add(`app ${e.app?.id??e.id}`)}return i}place(e,n){cn(e.el,e.e,ln(e.motion,e.e.frame,n,this.reduced),e.text);let s=e.e.type==="text"?e.el.firstElementChild:null;s&&qe(s)}loadFonts(){return en(this.doc.fonts??[],e=>this.source.font(e))}async mountApp(e,n,s){let i=this.path(e.id),o=e.app,r=(e.appInfo??s.info)?.id,a={now:()=>this.heldAt??Date.now(),startedAt:()=>this.startedAt||Date.now()},l=(p,m)=>this.o.onApp?.({type:"app.failed",element:i,item:o,...r?{app:r}:{},reason:p,...m?{error:m}:{}}),d=this.o.isolate?{...this.o.isolate,fonts:this.doc.fonts,font:p=>this.source.font(p)}:void 0,u=await Qt(e,n,s,this.source,a,this.o.appDeadlineMs??5e3,p=>{this.disposed?p.dispose():this.apps.push({app:p,box:n,path:i,id:e.id,item:o})},p=>l("error",p),d);if(!("held"in u)){if("failed"in u){l(u.failed,u.error);return}u.late&&(this.late.push(i),this.o.onAppLate?.(i,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(),i=s-this.startedAt;for(let o of this.animated)this.place(o,i);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=ae(n).clips,i=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches;for(let o of this.apps){let a=n.map((f,k)=>({c:f,t:s[k]})).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,d=this.animated.findIndex(f=>f.el===l);d>=0&&(this.animated.splice(d,1),Object.assign(l.style,{opacity:"",transform:"",clipPath:""}));let u=(f,k,b)=>this.hook(o,f.kind,{startAt:k,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:k}of a)u(f,e+k.startMs);let p=o.app.paging();if(!p)continue;let m=a.find(f=>f.c.kind==="enter")?.c,y=a.find(f=>f.c.kind==="exit")?.c,A=pn(p.count,p.ms,Ct(this.doc,this.source).durationMs);for(let f=1;f<A.length;f++){let k=e+A[f].startMs;y&&u(y,k-y.durationMs,A[f-1].page),m&&u(m,k,A[f].page)}}}hook(e,n,s,i){let o=!1;e.app.hook(n,s).finally(()=>{o=!0});let r=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"&&(i.style.visibility="hidden"))},Math.max(0,r+fi-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.el.remove()}},hn=t=>Math.min(Math.max(0,t),2**31-1),nt=class{constructor(e,n,s,i,o,r,a){h(this,"region",e);h(this,"playback",s);h(this,"source",i);h(this,"path",o);h(this,"o",r);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 xe(e,{media:r.media,fit:s.fit,path:o,onItem:r.onItem,onPassEnd:r.onPassEnd,onApp:r.onApp}),s.transition==="slide"&&this.unplayed.push("transition slide");let l=s.transition==="fade"?{type:"crossfade"}:void 0,d=n.map(u=>i.slide(u,{imageDurationMs:s.imageDurationMs,transition:l,region:!0})).filter(u=>!!u);this.slides=d.length===1&&d[0].untilEnd&&(s.onEnd??"loop")==="loop"?[{...d[0],untilEnd:!1,loop:!0}]:d,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 un(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=>Lt(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()},hn(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,...Ye(s)}),this.o.onItem?.({type:"item.end",element:this.path,item:e.item,blob:e.blob.hash,endedAt:Date.now(),reason:"error"}),this.schedule(gi);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 ie(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")},hn(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 st=t=>t!=null&&t!==""&&!(Array.isArray(t)&&t.length===0);function gn(t,e,n,s=[]){let i=t[n];if(!i)return!1;if(!i.when)return!0;if(s.includes(n))return!1;let o=r=>String(r);for(let[r,a]of Object.entries(i.when)){if(!t[r]||r===n)return!1;let d=gn(t,e,r,[...s,n])?e[r]!==void 0?e[r]:t[r].default:void 0,u=Array.isArray(d)?d.map(o):st(d)?[o(d)]:[];if(a.set!==void 0&&a.set!==st(d)||a.anyOf&&!(st(d)&&!Array.isArray(d)?a.anyOf.map(o).includes(o(d)):u.some(p=>a.anyOf.map(o).includes(p)))||a.allOf&&!a.allOf.map(o).every(p=>u.includes(p))||a.noneOf&&u.some(p=>a.noneOf.map(o).includes(p)))return!1}return!0}function yn(t,e){return Object.keys(t).filter(n=>gn(t,e,n))}var ca=re.apiVersion,bn=new Map(re.commands.map(t=>[t.name,t]));var z=class extends Error{constructor(n,s){super(s);h(this,"code",n)}};function wn(t,e){let n=e.capability??"read",s={kind:"app",app:e.id,instance:e.instance},i=new Set,o=!1,r=async(a,l={})=>{if(o)throw new z("NOT_ALLOWED","This app has been removed from the screen.");let d=bn.get(a);if(!d)throw new z("UNKNOWN",`There is no command ${a}.`);if(d.apps==="none")throw new z("NOT_ALLOWED",`Apps cannot call ${a}.`);if(d.apps==="control"&&n!=="control")throw new z("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 z(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(o)return()=>{};let d=t.on(a,l),u=()=>{d(),i.delete(u)};return i.add(u),u},time:()=>r("time.now"),call:r,play:()=>r("player.play"),pause:()=>r("player.pause"),stop:()=>r("player.stop"),next:()=>r("player.next"),previous:()=>r("player.previous"),finish:()=>r("app.finish"),dispose(){o=!0;for(let a of[...i])a()}}}var vn=["none","fade","scale","slide-up","slide-left"],Se=[["1920 \xD7 1080",1920,1080],["1080 \xD7 1920",1080,1920],["3840 \xD7 2160",3840,2160]],yi=[.25,.5,1,2,4],pe=3e4,En=5e3,bi={id:"med_preview",version:1},c={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:[]},I={frames:"",tables:{},controller:{status:{},events:{}}},U={people:new Set,player:new Map},Ce=[],rt=new Map,S=null,ot=null,at=null,Sn=-1,V=null,le=0,X={wall:0,t:0},Te=0,Pe=[],$=t=>document.getElementById(t),kn=$("stage"),wi=$("controls"),xn=$("report");function g(t,e={},...n){let s=document.createElement(t);for(let[i,o]of Object.entries(e))o==null||o===!1||(i.startsWith("on")&&typeof o=="function"?s.addEventListener(i.slice(2),o):i==="value"||i in s&&typeof o!="string"?s[i]=o:s.setAttribute(i,o===!0?"":String(o)));for(let i of n)i!=null&&s.append(i);return s}var vi=0;function E(t,e,n=!1){return e.id||(e.id=`c${++vi}`),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 B(t,e,n){let s=g("select",{onchange:()=>n(s.value)},...t.map(i=>{let[o,r]=Array.isArray(i)?i:[i,i];return g("option",{value:o,selected:o===e},r)}));return s}async function An(){let[t,e,n,s]=await Promise.all([fetch("/app.json").then(r=>r.json()),fetch("/app.js"),fetch("/samples.json").then(r=>r.json()),fetch("/config.json").then(r=>r.json())]);I=s;for(let[r,a]of Object.entries(I.tables))c.tables.has(dt(r))||Tn(r,a);S=t,Sn=Number(e.headers.get("x-preview-version")??-1),at=e.ok?null:await e.text(),ot=e.ok?new Uint8Array(await e.arrayBuffer()):null;let i=S.params??{},o={};for(let[r,a]of Object.entries(i))o[r]=c.touched.has(r)?c.props[r]:a.default;c.props=o;for(let[r,a]of Object.entries(n))r in c.samples||(c.samples[r]=a);Pn(),document.title=`${S.name}: Wyndlass app preview`,$("title").textContent=S.name,$("subtitle").textContent=`${S.id} ${S.version}`}var dt=t=>`tbl_${(t.replace(/\.(json|csv)$/i,"").toLowerCase().replace(/[^a-z0-9]+/g,"")||"table").slice(0,26).padEnd(26,"0")}`;function ki(t){let e=[],n=[],s="",i=!1;for(let o=0;o<t.length;o++){let r=t[o];if(i){r==='"'&&t[o+1]==='"'?(s+='"',o++):r==='"'?i=!1:s+=r;continue}r==='"'?i=!0:r===","?(n.push(s),s=""):r===`
5
5
  `||r==="\r"?(r==="\r"&&t[o+1]===`
6
- `&&o++,n.push(s),e.push(n),n=[],s=""):s+=r}return(s||n.length)&&(n.push(s),e.push(n)),e.filter(o=>o.some(r=>r!==""))}function ki(t,e){let n=dt(t),s=(o,r)=>({table:n,version:1,rows:r,columns:o.map(a=>({key:a,label:a,type:r.length&&r.every(d=>d[a]===""||d[a]===void 0||Number.isFinite(Number(d[a])))?"number":"text"}))});if(/\.csv$/i.test(t)){let[o=[],...r]=vi(e),a=o.map(c=>c.trim()),d=r.map(c=>Object.fromEntries(a.map((p,m)=>[p,c[m]??""]))),l=s(a,d);for(let c of l.columns)if(c.type==="number")for(let p of d)p[c.key]!==""&&(p[c.key]=Number(p[c.key]));return l}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(o=>Object.keys(o)))],i);throw new Error(`${t} is not a table: a snapshot, an array of rows, or CSV`)}function Tn(t,e){try{u.tables.set(dt(t),ki(t,e)),rt.delete(t)}catch(n){rt.set(t,String(n.message))}}function Pn(){let t=[...u.tables.keys()][0];if(!(!t||!S))for(let[e,n]of Object.entries(S.params??{}))n.type==="datatable"&&!u.props[e]&&(u.props[e]=t,u.touched.add(e))}function xi(){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 B.people.add(t),()=>{B.people.delete(t)}}}}function it(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 B.people)s([n]);$("people-count").textContent=`${u.people.length} in view`}var Ai={status:()=>I.controller.status,on(t,e){let n=B.player.get(t)??new Set;return n.add(e),B.player.set(t,n),()=>{n.delete(e)}},async call(t,e,n){return Ce.push(`controller: ${n.app??"the app"} called ${t}, not applied (a preview)`),Y({}),{ok:!1,code:"PREVIEW",message:"a preview"}}},Mi={time:"time.now",play:"player.play",pause:"player.pause",stop:"player.stop",next:"player.next",previous:"player.previous",finish:"app.finish"};function Ei(t){let e=s=>i=>{throw Ce.push(`controller: ${s} refused, ${i.code??"error"}: ${i.message}`),Y({}),i},n={...t,call:(s,i)=>t.call(s,i).catch(e(s))};for(let[s,i]of Object.entries(Mi))n[s]=()=>t[s]().catch(e(i));return n}function Si(t){for(let e of[t.type,"*"])for(let n of B.player.get(e)??[])n(t)}function Ti(){return new Me({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 Pi(){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:pe-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:yi,props:u.props,...S.slots&&u.tables.size?{binding:{table:[...u.tables.keys()][0]}}:{},...S.capabilities?.sensors?{sensors:S.capabilities.sensors}:{},appInfo:{id:S.id,element:S.element,player:S.capabilities?.player==="control"?"control":"read"}}],animation:{duration:{kind:"fixed",ms:pe},clips:t}}}async function Le(){let t=++le;if(cancelAnimationFrame(Te),V?.dispose(),V=null,kn.replaceChildren(),Pe.length=0,Ce.length=0,!S||!ot){Y({building:!0});return}let e={};try{e=JSON.parse(u.screen.fields||"{}")}catch{}let n=ot,s={deviceId:"preview",slide:()=>null,playlist:()=>null,font:()=>{},app:()=>({hash:`preview-${le}`,bytes:n}),data:Ti(),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,...I.frames?{}:{...S.capabilities?.sensors?.includes("impressions")?{impressions:xi()}:{},controllerFor:a=>Ei(wn(Ai,a))}};B.people.clear(),B.player.clear();let i=performance.now(),o=!1,r=new J(Pi(),s,kn,{appDeadlineMs:En,...I.frames?{isolate:{frames:I.frames,apps:()=>!0}}:{},onAppLate:()=>{o=!0},onApp:a=>{t===le&&(Pe.push(`app.failed: ${a.reason}${a.error?` (${a.error})`:""}`),Y({}))}});V=r,Y({waiting:!0}),await r.ready,t===le&&(Y({readyMs:o?void 0:Math.round(performance.now()-i),late:o}),await r.start(Date.now()-u.t),t===le&&(r.seek(u.t),X={wall:Date.now(),t:u.t},Li(),Ii()))}function Li(){cancelAnimationFrame(Te);let t=()=>{if(V){if(u.playing){if(u.t=X.t+(Date.now()-X.wall)*u.speed,u.t>=pe){u.t=0,Le();return}V.seek(u.t)}$("clock-seek").value=String(Math.round(u.t)),$("clock-time").textContent=`${(u.t/1e3).toFixed(1)} s`,Te=requestAnimationFrame(t)}};Te=requestAnimationFrame(t)}function Ii(){let t=$("pages"),e=V?.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:()=>Ln(s*e.ms)},`Page ${s+1}`)))):g("p",{"data-testid":"pages"},"One page"))}function Ln(t){u.t=Math.max(0,Math.min(pe-1,t)),X={wall:Date.now(),t:u.t},V?.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 ${En/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=xn.querySelector('[data-testid="ready"]');n&&e.push(n)}for(let n of Pe)e.push(g("span",{class:"failed","data-testid":"failure"},n));I.frames&&Pe.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 Ce.slice(-5))e.push(g("span",{"data-testid":"command"},n));xn.replaceChildren(...e)}function Ci(t,e){let n=u.props[t],s=o=>{u.props[t]=o,u.touched.add(t),In(),L()},i=e.label??t;if(e.type==="boolean")return E(i,g("input",{type:"checkbox",checked:n===!0,onchange:o=>s(o.target.checked)}),!0);if(e.type==="enum"){let o=(e.values??[]).map(r=>r&&typeof r=="object"?[String(r.value),String(r.label??r.value)]:String(r));return E(i,z(o,String(n??""),s))}if(e.type==="number")return E(i,g("input",{type:"number",value:n===void 0?"":String(n),min:e.min,max:e.max,step:e.step??"any",onchange:o=>{let r=o.target.value;s(r===""?void 0:Number(r))}}));if(["string","text","color","url","datetime","duration","secret"].includes(e.type)){let o=e.type==="text"?g("textarea",{value:String(n??""),onchange:r=>s(r.target.value)}):g("input",{type:"text",value:String(n??""),placeholder:e.type==="color"?"#rrggbb or #rrggbbaa":void 0,onchange:r=>s(r.target.value)});return E(i,o)}return e.type==="datatable"?E(i,z(["",...u.tables.keys()],String(n??""),s)):E(`${i} (JSON)`,g("textarea",{value:n===void 0?"":JSON.stringify(n,null,2),onchange:o=>{let r=o.target.value.trim();try{s(r?JSON.parse(r):void 0)}catch{s(r)}}}))}function In(){let t=$("params"),e=S?.params??{},n=new Set(yn(e,u.props));t.replaceChildren(...Object.entries(e).filter(([s])=>n.has(s)).map(([s,i])=>Ci(s,i))),t.children.length||t.append(g("p",{},"No params."))}var Mn;function L(){clearTimeout(Mn),Mn=setTimeout(()=>{Le()},150)}function Ie(){let t=!Se.some(([,r,a])=>r===u.width&&a===u.height),e=g("input",{type:"number",value:String(u.width),min:64,max:7680,onchange:r=>{u.width=Number(r.target.value)||1920,L()}}),n=g("input",{type:"number",value:String(u.height),min:64,max:7680,onchange:r=>{u.height=Number(r.target.value)||1080,L()}}),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)),X={wall:Date.now(),t:u.t}}},u.playing?"Pause":"Play"),i=g("input",{id:"clock-seek",type:"range",min:0,max:pe,step:100,value:String(u.t),oninput:r=>Ln(Number(r.target.value))}),o=[g("h2",{},"Screen"),E("Size",z([...Se.map(([r])=>r),"Custom"],t?"Custom":Se.find(([,r,a])=>r===u.width&&a===u.height)[0],r=>{let a=Se.find(([d])=>d===r);a&&(u.width=a[1],u.height=a[2]),Ie(),L()})),t?g("div",{class:"row"},E("Width",e),E("Height",n)):null,g("div",{class:"row"},E("Time zone",g("input",{type:"text",value:u.timeZone,onchange:r=>{u.timeZone=r.target.value||"UTC",L()}})),E("Locale",g("input",{type:"text",value:u.locale,onchange:r=>{u.locale=r.target.value||"en-US",L()}}))),E("Screen's name",g("input",{type:"text",value:u.screen.name,onchange:r=>{u.screen.name=r.target.value,L()}})),g("div",{class:"row"},E("Latitude",g("input",{type:"number",step:"any",value:String(u.screen.lat),onchange:r=>{u.screen.lat=Number(r.target.value),L()}})),E("Longitude",g("input",{type:"number",step:"any",value:String(u.screen.lon),onchange:r=>{u.screen.lon=Number(r.target.value),L()}}))),E("Screen's fields (JSON)",g("textarea",{value:u.screen.fields,onchange:r=>{u.screen.fields=r.target.value,L()}})),g("h2",{},"Clock"),g("div",{class:"row"},s,E("Speed",z(gi.map(r=>[String(r),`${r}\xD7`]),String(u.speed),r=>{X={wall:Date.now(),t:u.t},u.speed=Number(r)})),g("span",{id:"clock-time"},"0.0 s")),E("Time in the layout",i),g("h2",{},"Enter and exit"),g("div",{class:"row"},E("Enter",z(vn,u.enter,r=>{u.enter=r,L()})),E("Exit",z(vn,u.exit,r=>{u.exit=r,L()}))),E("Each lasts (ms)",g("input",{type:"number",min:0,max:5e3,step:100,value:String(u.clipMs),onchange:r=>{u.clipMs=Number(r.target.value)||0,L()}})),g("div",{id:"pages"}),g("h2",{},"Params"),g("div",{id:"params"}),I.frames?g("p",{"data-testid":"framed"},`In a frame on ${I.frames}, as in the CMS: no storage, cookies, parent page, controller or impressions.`):null,g("h2",{},"Tables"),...[...u.tables.values()].map(r=>g("p",{"data-testid":"table"},`${r.table}: ${r.rows.length} rows, ${r.columns.map(a=>a.key).join(", ")}`)),...[...rt].map(([r,a])=>g("p",{class:"failed","data-testid":"table-error"},`${r}: ${a}`)),E("Add a table (JSON or CSV)",g("input",{type:"file",accept:".json,.csv",onchange:async r=>{let a=r.target.files?.[0];a&&(Tn(a.name,await a.text()),Pn(),Ie(),L())}})),...S?.capabilities?.sensors?.includes("impressions")&&!I.frames?[g("h2",{},"People at the screen"),g("div",{class:"row"},g("button",{type:"button",onclick:()=>it("enter")},"Someone arrives"),g("button",{type:"button",onclick:()=>it("look")},"Someone looks"),g("button",{type:"button",onclick:()=>it("leave")},"Someone leaves")),g("p",{id:"people-count"},`${u.people.length} in view`)]:[],...I.frames?[]:[g("h2",{},"The player's controller"),g("p",{},`The app may ${S?.capabilities?.player==="control"?"read it and call its commands":"read it (capabilities.player: read)"}. Commands are not applied here.`),...Object.keys(I.controller.events).length?[E("Event",z(Object.keys(I.controller.events),Object.keys(I.controller.events)[0],r=>{$("event-json").value=JSON.stringify(I.controller.events[r],null,2)})),E("Its JSON",g("textarea",{id:"event-json",rows:6,value:JSON.stringify(Object.values(I.controller.events)[0],null,2)})),g("button",{type:"button",onclick:()=>{try{Si(JSON.parse($("event-json").value))}catch{}}},"Send to the app")]:[]],g("h2",{},"Data"),...Object.keys(u.samples).map(r=>E(`${r} answer's data (JSON)`,g("textarea",{"data-source":r,value:JSON.stringify(u.samples[r],null,2),rows:8,onchange:a=>{try{u.samples[r]=JSON.parse(a.target.value),L()}catch{}}}))),Object.keys(u.samples).length?null:g("p",{},"The app declares no data source with a sample (weather, news or calendar).")];bi.replaceChildren(...o.filter(r=>r!==null)),In()}async function Ri(){await An(),Ie(),await Le();let t=new EventSource("/events"),e=()=>{An().then(()=>(Ie(),Le()))};t.addEventListener("hello",n=>{JSON.parse(n.data).version!==Sn&&e()}),t.addEventListener("reload",e),window.addEventListener("resize",()=>L())}Ri();})();
6
+ `&&o++,n.push(s),e.push(n),n=[],s=""):s+=r}return(s||n.length)&&(n.push(s),e.push(n)),e.filter(o=>o.some(r=>r!==""))}function xi(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(o=>o.toLowerCase()===s);i++)s=`${n}_${i}`;return e.add(s),s}function Ai(t,e){let n=dt(t),s=(o,r)=>({table:n,version:1,rows:r,columns:o.map(({key:a,label:l})=>({key:a,label:l,type:r.length&&r.every(d=>d[a]===""||d[a]===void 0||Number.isFinite(Number(d[a])))?"number":"text"}))});if(/\.csv$/i.test(t)){let[o=[],...r]=ki(e),a=new Set,l=o.map(p=>({label:p.trim(),key:xi(p.trim()||"column",a)})),d=r.map(p=>Object.fromEntries(l.map((m,y)=>[m.key,p[y]??""]))),u=s(l,d);for(let p of u.columns)if(p.type==="number")for(let m of d)m[p.key]!==""&&(m[p.key]=Number(m[p.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(o=>Object.keys(o)))].map(o=>({key:o,label:o})),i);throw new Error(`${t} is not a table: a snapshot, an array of rows, or CSV`)}function Tn(t,e){try{c.tables.set(dt(t),Ai(t,e)),rt.delete(t)}catch(n){rt.set(t,String(n.message))}}function Pn(){let t=[...c.tables.keys()][0];if(!(!t||!S))for(let[e,n]of Object.entries(S.params??{}))n.type==="datatable"&&!c.props[e]&&(c.props[e]=t,c.touched.add(e))}function Mi(){return{measuring:!0,now:()=>[{source:"preview",present:c.people.length,longestDwellS:c.people.length?Math.round((Date.now()-Math.min(...c.people))/1e3):0}],on(t){return U.people.add(t),()=>{U.people.delete(t)}}}}function it(t){if(t==="enter"&&c.people.push(Date.now()),t==="leave"&&!c.people.length)return;let e=t==="leave"?c.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 U.people)s([n]);$("people-count").textContent=`${c.people.length} in view`}var Ei={status:()=>I.controller.status,on(t,e){let n=U.player.get(t)??new Set;return n.add(e),U.player.set(t,n),()=>{n.delete(e)}},async call(t,e,n){return Ce.push(`controller: ${n.app??"the app"} called ${t}, not applied (a preview)`),Y({}),{ok:!1,code:"PREVIEW",message:"a preview"}}},Si={time:"time.now",play:"player.play",pause:"player.pause",stop:"player.stop",next:"player.next",previous:"player.previous",finish:"app.finish"};function Ti(t){let e=s=>i=>{throw Ce.push(`controller: ${s} refused, ${i.code??"error"}: ${i.message}`),Y({}),i},n={...t,call:(s,i)=>t.call(s,i).catch(e(s))};for(let[s,i]of Object.entries(Si))n[s]=()=>t[s]().catch(e(i));return n}function Pi(t){for(let e of[t.type,"*"])for(let n of U.player.get(e)??[])n(t)}function Li(){return new Me({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 c.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:c.samples[n]}))})})}function Ii(){let t=[...c.enter!=="none"?[{element:"app",kind:"enter",preset:c.enter,start:{kind:"at",ms:0},durationMs:c.clipMs,easing:"ease-out"}]:[],...c.exit!=="none"?[{element:"app",kind:"exit",preset:c.exit,start:{kind:"at",ms:pe-c.clipMs},durationMs:c.clipMs,easing:"ease-in"}]:[]];return{profiles:[{id:"preview",width:c.width,height:c.height}],elements:[{type:"app",id:"app",frame:{x:0,y:0,w:c.width,h:c.height},app:bi,props:c.props,...S.slots&&c.tables.size?{binding:{table:[...c.tables.keys()][0]}}:{},...S.capabilities?.sensors?{sensors:S.capabilities.sensors}:{},appInfo:{id:S.id,element:S.element,player:S.capabilities?.player==="control"?"control":"read"}}],animation:{duration:{kind:"fixed",ms:pe},clips:t}}}async function Le(){let t=++le;if(cancelAnimationFrame(Te),V?.dispose(),V=null,kn.replaceChildren(),Pe.length=0,Ce.length=0,!S||!ot){Y({building:!0});return}let e={};try{e=JSON.parse(c.screen.fields||"{}")}catch{}let n=ot,s={deviceId:"preview",slide:()=>null,playlist:()=>null,font:()=>{},app:()=>({hash:`preview-${le}`,bytes:n}),data:Li(),place:{lat:c.screen.lat,lon:c.screen.lon},screen:{name:c.screen.name,type:"preview",tags:[],path:[{name:"Preview",kind:"organization"}],fields:e},timeZone:c.timeZone,locale:c.locale,preview:!1,snapshot:a=>c.tables.get(a)??null,...I.frames?{}:{...S.capabilities?.sensors?.includes("impressions")?{impressions:Mi()}:{},controllerFor:a=>Ti(wn(Ei,a))}};U.people.clear(),U.player.clear();let i=performance.now(),o=!1,r=new J(Ii(),s,kn,{appDeadlineMs:En,...I.frames?{isolate:{frames:I.frames,apps:()=>!0}}:{},onAppLate:()=>{o=!0},onApp:a=>{t===le&&(Pe.push(`app.failed: ${a.reason}${a.error?` (${a.error})`:""}`),Y({}))}});V=r,Y({waiting:!0}),await r.ready,t===le&&(Y({readyMs:o?void 0:Math.round(performance.now()-i),late:o}),await r.start(Date.now()-c.t),t===le&&(r.seek(c.t),X={wall:Date.now(),t:c.t},Ci(),Ri()))}function Ci(){cancelAnimationFrame(Te);let t=()=>{if(V){if(c.playing){if(c.t=X.t+(Date.now()-X.wall)*c.speed,c.t>=pe){c.t=0,Le();return}V.seek(c.t)}$("clock-seek").value=String(Math.round(c.t)),$("clock-time").textContent=`${(c.t/1e3).toFixed(1)} s`,Te=requestAnimationFrame(t)}};Te=requestAnimationFrame(t)}function Ri(){let t=$("pages"),e=V?.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:()=>Ln(s*e.ms)},`Page ${s+1}`)))):g("p",{"data-testid":"pages"},"One page"))}function Ln(t){c.t=Math.max(0,Math.min(pe-1,t)),X={wall:Date.now(),t:c.t},V?.seek(c.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 ${En/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=xn.querySelector('[data-testid="ready"]');n&&e.push(n)}for(let n of Pe)e.push(g("span",{class:"failed","data-testid":"failure"},n));I.frames&&Pe.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 Ce.slice(-5))e.push(g("span",{"data-testid":"command"},n));xn.replaceChildren(...e)}function Ni(){let t=Object.entries(S?.params??{}).find(([,n])=>n.type==="datatable")?.[0],e=S?.slots?[...c.tables.keys()][0]:t?c.props[t]:void 0;return typeof e=="string"?c.tables.get(e):void 0}var In=t=>t.label&&t.label!==t.key?`${t.label} (${t.key})`:t.key;function Oi(t,e){let n=c.props[t],s=o=>{c.props[t]=o,c.touched.add(t),Cn(),L()},i=e.label??t;if(e.type==="boolean")return E(i,g("input",{type:"checkbox",checked:n===!0,onchange:o=>s(o.target.checked)}),!0);if(e.type==="enum"){let o=(e.values??[]).map(r=>r&&typeof r=="object"?[String(r.value),String(r.label??r.value)]:String(r));return E(i,B(o,String(n??""),s))}if(e.type==="number")return E(i,g("input",{type:"number",value:n===void 0?"":String(n),min:e.min,max:e.max,step:e.step??"any",onchange:o=>{let r=o.target.value;s(r===""?void 0:Number(r))}}));if(["string","text","color","url","datetime","duration","secret"].includes(e.type)){let o=e.type==="text"?g("textarea",{value:String(n??""),onchange:r=>s(r.target.value)}):g("input",{type:"text",value:String(n??""),placeholder:e.type==="color"?"#rrggbb or #rrggbbaa":void 0,onchange:r=>s(r.target.value)});return E(i,o)}return e.type==="datatable"?E(i,B(["",...c.tables.keys()],String(n??""),s)):e.type==="column"?E(i,B(["",...(Ni()?.columns??[]).map(o=>[o.key,In(o)])],String(n??""),s)):E(`${i} (JSON)`,g("textarea",{value:n===void 0?"":JSON.stringify(n,null,2),onchange:o=>{let r=o.target.value.trim();try{s(r?JSON.parse(r):void 0)}catch{s(r)}}}))}function Cn(){let t=$("params"),e=S?.params??{},n=new Set(yn(e,c.props));t.replaceChildren(...Object.entries(e).filter(([s])=>n.has(s)).map(([s,i])=>Oi(s,i))),t.children.length||t.append(g("p",{},"No params."))}var Mn;function L(){clearTimeout(Mn),Mn=setTimeout(()=>{Le()},150)}function Ie(){let t=!Se.some(([,r,a])=>r===c.width&&a===c.height),e=g("input",{type:"number",value:String(c.width),min:64,max:7680,onchange:r=>{c.width=Number(r.target.value)||1920,L()}}),n=g("input",{type:"number",value:String(c.height),min:64,max:7680,onchange:r=>{c.height=Number(r.target.value)||1080,L()}}),s=g("button",{type:"button","aria-pressed":String(!c.playing),onclick:()=>{c.playing=!c.playing,s.textContent=c.playing?"Pause":"Play",s.setAttribute("aria-pressed",String(!c.playing)),X={wall:Date.now(),t:c.t}}},c.playing?"Pause":"Play"),i=g("input",{id:"clock-seek",type:"range",min:0,max:pe,step:100,value:String(c.t),oninput:r=>Ln(Number(r.target.value))}),o=[g("h2",{},"Screen"),E("Size",B([...Se.map(([r])=>r),"Custom"],t?"Custom":Se.find(([,r,a])=>r===c.width&&a===c.height)[0],r=>{let a=Se.find(([l])=>l===r);a&&(c.width=a[1],c.height=a[2]),Ie(),L()})),t?g("div",{class:"row"},E("Width",e),E("Height",n)):null,g("div",{class:"row"},E("Time zone",g("input",{type:"text",value:c.timeZone,onchange:r=>{c.timeZone=r.target.value||"UTC",L()}})),E("Locale",g("input",{type:"text",value:c.locale,onchange:r=>{c.locale=r.target.value||"en-US",L()}}))),E("Screen's name",g("input",{type:"text",value:c.screen.name,onchange:r=>{c.screen.name=r.target.value,L()}})),g("div",{class:"row"},E("Latitude",g("input",{type:"number",step:"any",value:String(c.screen.lat),onchange:r=>{c.screen.lat=Number(r.target.value),L()}})),E("Longitude",g("input",{type:"number",step:"any",value:String(c.screen.lon),onchange:r=>{c.screen.lon=Number(r.target.value),L()}}))),E("Screen's fields (JSON)",g("textarea",{value:c.screen.fields,onchange:r=>{c.screen.fields=r.target.value,L()}})),g("h2",{},"Clock"),g("div",{class:"row"},s,E("Speed",B(yi.map(r=>[String(r),`${r}\xD7`]),String(c.speed),r=>{X={wall:Date.now(),t:c.t},c.speed=Number(r)})),g("span",{id:"clock-time"},"0.0 s")),E("Time in the layout",i),g("h2",{},"Enter and exit"),g("div",{class:"row"},E("Enter",B(vn,c.enter,r=>{c.enter=r,L()})),E("Exit",B(vn,c.exit,r=>{c.exit=r,L()}))),E("Each lasts (ms)",g("input",{type:"number",min:0,max:5e3,step:100,value:String(c.clipMs),onchange:r=>{c.clipMs=Number(r.target.value)||0,L()}})),g("div",{id:"pages"}),g("h2",{},"Params"),g("div",{id:"params"}),I.frames?g("p",{"data-testid":"framed"},`In a frame on ${I.frames}, as in the CMS: no storage, cookies, parent page, controller or impressions.`):null,g("h2",{},"Tables"),...[...c.tables.values()].map(r=>g("p",{"data-testid":"table"},`${r.table}: ${r.rows.length} rows, ${r.columns.map(In).join(", ")}`)),...[...rt].map(([r,a])=>g("p",{class:"failed","data-testid":"table-error"},`${r}: ${a}`)),E("Add a table (JSON or CSV)",g("input",{type:"file",accept:".json,.csv",onchange:async r=>{let a=r.target.files?.[0];a&&(Tn(a.name,await a.text()),Pn(),Ie(),L())}})),...S?.capabilities?.sensors?.includes("impressions")&&!I.frames?[g("h2",{},"People at the screen"),g("div",{class:"row"},g("button",{type:"button",onclick:()=>it("enter")},"Someone arrives"),g("button",{type:"button",onclick:()=>it("look")},"Someone looks"),g("button",{type:"button",onclick:()=>it("leave")},"Someone leaves")),g("p",{id:"people-count"},`${c.people.length} in view`)]:[],...I.frames?[]:[g("h2",{},"The player's controller"),g("p",{},`The app may ${S?.capabilities?.player==="control"?"read it and call its commands":"read it (capabilities.player: read)"}. Commands are not applied here.`),...Object.keys(I.controller.events).length?[E("Event",B(Object.keys(I.controller.events),Object.keys(I.controller.events)[0],r=>{$("event-json").value=JSON.stringify(I.controller.events[r],null,2)})),E("Its JSON",g("textarea",{id:"event-json",rows:6,value:JSON.stringify(Object.values(I.controller.events)[0],null,2)})),g("button",{type:"button",onclick:()=>{try{Pi(JSON.parse($("event-json").value))}catch{}}},"Send to the app")]:[]],g("h2",{},"Data"),...Object.keys(c.samples).map(r=>E(`${r} answer's data (JSON)`,g("textarea",{"data-source":r,value:JSON.stringify(c.samples[r],null,2),rows:8,onchange:a=>{try{c.samples[r]=JSON.parse(a.target.value),L()}catch{}}}))),Object.keys(c.samples).length?null:g("p",{},"The app declares no data source with a sample (weather, news or calendar).")];wi.replaceChildren(...o.filter(r=>r!==null)),Cn()}async function $i(){await An(),Ie(),await Le();let t=new EventSource("/events"),e=()=>{An().then(()=>(Ie(),Le()))};t.addEventListener("hello",n=>{JSON.parse(n.data).version!==Sn&&e()}),t.addEventListener("reload",e),window.addEventListener("resize",()=>L())}$i();})();
package/dist/react.d.ts CHANGED
@@ -47,6 +47,6 @@ export declare function useData<T = unknown>(source: string, params: Params, eve
47
47
  answer?: DataAnswer<T>;
48
48
  error?: Error;
49
49
  };
50
- /** A data table's snapshot (null without one), read again each frame the layout draws: a bound table's rows change with time. */
50
+ /** A data table's snapshot, as snapshot() gives it (null when the screen has none), read again each frame the layout draws: a bound table's rows change with time. */
51
51
  export declare function useSnapshot(table: string): unknown | null;
52
52
  export {};
package/dist/react.js CHANGED
@@ -141,7 +141,7 @@ export function useData(source, params, everyMs = 10 * 60000) {
141
141
  }, [app, key, everyMs]);
142
142
  return state.key === key ? { answer: state.answer, error: state.error } : { answer: kept(app, source, params) };
143
143
  }
144
- /** A data table's snapshot (null without one), read again each frame the layout draws: a bound table's rows change with time. */
144
+ /** A data table's snapshot, as snapshot() gives it (null when the screen has none), read again each frame the layout draws: a bound table's rows change with time. */
145
145
  export function useSnapshot(table) {
146
146
  const [app] = useBridge();
147
147
  useNow();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wyndlass/app-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
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",
@@ -33,7 +33,8 @@ Use the `react` template unless the person asks for plain TypeScript (`vanilla`)
33
33
  - Run `npm run typecheck` and `npm run check` after each change, and fix what they say.
34
34
  - Start `npm run preview` in the background. It serves `http://127.0.0.1:5199/` on this computer only, and draws the app again on every save.
35
35
  - **Ask the person to look,** at the screen size they gave and at the other orientation: under **Screen**, set **Size** to 1920 × 1080, then 1080 × 1920. Ask them to play the clock and to pause it. Change what they ask for.
36
- - **Before importing,** run `npm run preview -- --frame` once and ask them to look again. In the CMS an app runs in a sandboxed frame with no storage, cookies or parent page. An app that fails there works on screens but not in the designer.
36
+ - **Before importing,** run `npm run preview -- --frame` once and ask them to look again. In the CMS an app runs in a sandboxed frame with no storage, cookies or parent page. An app that fails there works on screens but not in the designer. The frame is served from a second port: use a regular browser for this check, since a browser built into an agent's app may block that port (`net::ERR_BLOCKED_BY_CLIENT`), and the app then reports `app.failed: load`.
37
+ - **Tables in the preview** are keyed as Wyndlass keys a table's columns: from their labels, lowercased, with underscores (a CSV header `Now serving` is the column `now_serving`). A `column` param holds that key, as it will on screens.
37
38
 
38
39
  ## 4. Pack and check
39
40
 
@@ -58,10 +59,12 @@ Follow [references/mcp.md](references/mcp.md):
58
59
 
59
60
  ## 6. Place it
60
61
 
61
- Read `guide.read` with topic `layouts`, sections `elements` and `apps`. Then, at a place the person names:
62
- - `layout.save` with the app's item from `app.list` (`{"type": "app", "id": …, "frame": …, "app": {"id": "med_…"}, "props": …}`), in a new layout or one they choose (`layout.get` first);
62
+ Read `guide.read` with topic `layouts`, sections `elements` and `apps`: its answer is the sections' text. Then, at a place the person names:
63
+ - `layout.save` with the app's item from `app.list`, in a new layout or one they choose (`layout.get` first). An app element is `{"type": "app", "id": "queue", "frame": {"x": 0, "y": 0, "w": 1920, "h": 1080}, "app": {"id": "med_…"}, "props": {…}}`. Its `props` are the app's params as `app.json` types them: a color param is a plain `"#RRGGBB"`, unlike a layout element's own colors (`{"value": "#RRGGBB"}`); a `datatable` param is the table's id (`tbl_…`); a `column` param is a column's key, from `datatable.get`.
63
64
  - `layout.check`, and tell them what it says.
64
65
 
66
+ A table named in a `datatable` param reaches the app on screens as it is: the app needs no `binding` for it. A `binding` is for an app with `slots`, or to choose rows (a filter, a sort, a limit) — the layouts guide's apps section.
67
+
65
68
  A held version can be placed and previewed. Screens play it only once it is approved and checked.
66
69
 
67
70
  ## 7. Schedule, only with the person's yes
@@ -27,7 +27,7 @@ A paged app also defines `paging()`, returning `{count, ms}`, so the layout can
27
27
  - `data(this, source, params)`: the data service's answer, a promise. Only for sources `app.json`'s `data` lists;
28
28
  - `kept(this, source, params)`: the answer the screen last kept for the same request, at once, or `undefined`. Draw it while `data` asks again, so the app is ready without the network;
29
29
  - `image(this, path)`: a picture a data answer names, as a URL the app can draw;
30
- - `snapshot(this, table)`: a data table's rows, as the layout's binding chooses them, or `null`;
30
+ - `snapshot(this, table)`: the rows of a table the layout names, in a `datatable` param or in the element's `binding`. Where a binding chooses rows (a filter, a sort, a limit), only those. `null` when the screen has no snapshot of that table. A `datatable` param needs no binding;
31
31
  - `controllerOf(this)`: the player's controller, as `capabilities.player` allows; absent in the designer and previews;
32
32
  - `impressionsOf(this)`: the people at the screen, for an app whose definition declares the `impressions` sensor;
33
33
  - `contextOf(this)`: the rest of the context (the screen's `place` and facts, `preview`).
@@ -43,14 +43,14 @@ A paged app also defines `paging()`, returning `{count, ms}`, so the layout can
43
43
  - `useNow()`: the layout's clock, drawn again at each of its frames;
44
44
  - `usePaging(count, ms)`: the page showing now. It also tells the host the pages;
45
45
  - `useData(source, params)`: `{answer, error}`. The kept answer at once, then the service's, asked again every 10 minutes;
46
- - `useSnapshot(table)`: a data table's rows.
46
+ - `useSnapshot(table)`: a data table's rows, as `snapshot` gives them, read again each frame.
47
47
 
48
48
  ## The definition, `app.json`
49
49
 
50
50
  Valid against `node_modules/@wyndlass/app-sdk/protocol/app-definition.schema.json`.
51
51
  - **Required:** `id` (reverse-domain, in the organization's own domain, never `com.wyndlass.`), `version` (semver), `name`, `element` (lowercase, with a hyphen).
52
52
  - `description`.
53
- - **`params`:** what a person sets in the designer. Each has a `type` (`string`, `text`, `number`, `boolean`, `enum`, `color`, `font`, `media`, `location`, `datetime`, `duration`, `url`, `datatable`, `column`, `json`), and may have a `label`, `default`, `values` (an enum's choices, or suggestions), `group`, `required`, `min`, `max`, `step`, `help`, `advanced` and `when` (the params it depends on). A `url` param's values and default must be `https`.
53
+ - **`params`:** what a person sets in the designer. Each has a `type` (`string`, `text`, `number`, `boolean`, `enum`, `color`, `font`, `media`, `location`, `datetime`, `duration`, `url`, `datatable`, `column`, `json`), and may have a `label`, `default`, `values` (an enum's choices, or suggestions), `group`, `required`, `min`, `max`, `step`, `help`, `advanced` and `when` (the params it depends on). A `url` param's values and default must be `https`. A `datatable` param's value is a table's id (`tbl_…`), and a `column` param's a column's key. Wyndlass makes a column's key from its label when the table is made: lowercased, other characters an underscore (`Now serving` is `now_serving`); `datatable.get` lists them. A `color` param's value is a plain string, `"#RRGGBB"`.
54
54
  - **`data`:** the data sources it reads: `weather`, `news`, `image`, `calendar`. Imported apps may read no others.
55
55
  - **`capabilities`:**
56
56
  - `player`: `read` (the default) or `control` (playback, audio and display commands);
@@ -4,6 +4,8 @@ Everything that touches Wyndlass goes through the person's own MCP connection, a
4
4
 
5
5
  Tool names below are the MCP's. A client may show them with a prefix of its own (such as `mcp__wyndlass__app_import`).
6
6
 
7
+ **Each answer's words** are its text, and the same text is `answer` in its structured result. Some clients show only the structured result: read `answer` there. It has the next steps, the CMS's links, a refusal's reason, and a guide's sections.
8
+
7
9
  ## Before importing
8
10
 
9
11
  - **`whoami`:** who you act as, the organization, and which toolsets this connection has. If `app.prepareImport` is missing: the import tools are listed only while imported apps are on at the organization's top place. An Owner or Admin turns them on in the CMS, under **Settings**, **Imported apps**. Tell the person; don't look for another way in.
@@ -30,7 +32,7 @@ It answers `<zip>: uploaded (<n> bytes). Import it with app.import.` Never read
30
32
  `{node, upload}`: the same place, and the upload's id. It answers one of:
31
33
  - **"Imported <id> <version> as med_…, version <n>."** `med_…` is the app's item, and `<n>` the item's version. Then what is next:
32
34
  - "It is approved with its import": a later version that asks for nothing more than the approved one before it. Screens play it once its checks pass;
33
- - "It is held for review": an app's first version, a version that asks for more (player control, a new sensor, audio, a new network host), or one the place's media review holds. It gives the CMS link to the app.
35
+ - "It is held for review": an app's first version, a version that asks for more (player control, a new sensor, audio, a new network host), or one the place's media review holds. Its words end with the CMS's link to the app, for the person who approves it.
34
36
  - **"The workspace has <id> <version> already, with these bytes":** nothing new was made. It says where that version stands.
35
37
  - **A refusal:**
36
38
  - "… was imported already, with other bytes. A version never changes": raise `version` in `app.json`, pack, and start again at step 1;
@@ -49,9 +51,14 @@ Lists Wyndlass's apps, then the organization's own: each with its item (`med_…
49
51
 
50
52
  ## 5. Place it: `layout.save` and `layout.check`
51
53
 
52
- First `guide.read` with topic `layouts`, sections `elements` and `apps`: the layout document, the app element, and its props.
54
+ First `guide.read` with topic `layouts`, sections `elements` and `apps`: the layout document, the app element, and its props. Its answer is the sections' text.
53
55
 
54
- - **An app element:** `{"type": "app", "id": "queue", "frame": {…}, "app": {"id": "med_…"}, "props": {…}}`, with the item from `app.list`. `props` are the definition's params; leave one out for its default. An imported app needs no `app.use`.
56
+ - **An app element:** `{"type": "app", "id": "queue", "frame": {"x": 0, "y": 0, "w": 1920, "h": 1080}, "app": {"id": "med_…"}, "props": {…}}`, with the item from `app.list`. An imported app needs no `app.use`.
57
+ - **Its `props`** are the definition's params, as `app.json` types them; leave one out for its default:
58
+ - a `color` param is a plain string, `"#RRGGBB"`. A layout element's own colors are objects, `{"value": "#RRGGBB"}`;
59
+ - a `datatable` param is a table's id (`tbl_…`). The app reads that table's rows on screens with no `binding`. A `binding` (`{"table": "tbl_…", …}`) is for an app with `slots`, or to choose rows: the layouts guide's apps section;
60
+ - a `column` param is a column's key, as `datatable.get` lists it.
61
+ - **A data table for the app:** `datatable.create` with `node`, `name` and `columns` (each a `label` and a `type`). Wyndlass makes each column's key from its label (`Number` is `number`, `Now serving` is `now_serving`) and answers them. Then add rows with `datatable.rows`, each row's `values` keyed by those keys, never by the labels.
55
62
  - **A new layout:** `layout.save` with `node` (a place the person names), `name` and `document`.
56
63
  - **A change to a layout:** `layout.get`, then `layout.save` with `media`, the whole document and `expectedVersion`.
57
64
  - **`dryRun: true`** checks a document without saving it.