diff --git a/public/config.json b/public/config.json index df321dc..4d2f9ea 100644 --- a/public/config.json +++ b/public/config.json @@ -1,7 +1,7 @@ { "general": { "language": "en_us", - "llm_provider": "openai", + "llm_provider": "local_browser", "persist_api_keys_non_localhost": false, "openai": { "api_key": "", diff --git a/public/mediapipe/genai_bundle.mjs b/public/mediapipe/genai_bundle.mjs new file mode 100644 index 0000000..50e2f1a --- /dev/null +++ b/public/mediapipe/genai_bundle.mjs @@ -0,0 +1,2 @@ +var t="undefined"!=typeof self?self:{};function e(e,n){t:{for(var r=["CLOSURE_FLAGS"],i=t,o=0;o>6|192;else{if(e>=55296&&e<=57343){if(e<=56319&&i=56320&&o<=57343){e=1024*(e-55296)+o-56320+65536,r[n++]=e>>18|240,r[n++]=e>>12&63|128,r[n++]=e>>6&63|128,r[n++]=63&e|128;continue}i--}e=65533}r[n++]=e>>12|224,r[n++]=e>>6&63|128}r[n++]=63&e|128}}t=n===r.length?r:r.subarray(0,n)}return t}var o,s=e(610401301,!1),a=e(748402147,!0);function u(){var e=t.navigator;return e&&(e=e.userAgent)?e:""}const c=t.navigator;o=c&&c.userAgentData||null;const l={};let h=null;function f(t){const e=t.length;let n=3*e/4;n%3?n=Math.floor(n):-1!="=.".indexOf(t[e-1])&&(n=-1!="=.".indexOf(t[e-2])?n-2:n-1);const r=new Uint8Array(n);let i=0;return function(t,e){function n(e){for(;r>4),64!=i&&(e(r<<4&240|i>>2),64!=o&&e(i<<6&192|o))}}(t,(function(t){r[i++]=t})),i!==n?r.subarray(0,i):r}function d(){if(!h){h={};var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""),e=["+/=","+/","-_=","-_.","-_"];for(let n=0;n<5;n++){const r=t.concat(e[n].split(""));l[n]=r;for(let t=0;t0)&&(-1!=u().indexOf("Trident")||-1!=u().indexOf("MSIE")))&&"function"==typeof btoa;const g=/[-_.]/g,_={"-":"+",_:"/",".":"="};function y(t){return _[t]||""}function w(t){if(!m)return f(t);t=g.test(t)?t.replace(g,y):t,t=atob(t);const e=new Uint8Array(t.length);for(let n=0;n=n||(r[e]=i+1,L(e=Error(),"incident"),function(e){t.setTimeout((()=>{throw e}),0)}(e))}}function j(){return"function"==typeof BigInt}var k="function"==typeof Symbol&&"symbol"==typeof Symbol();function U(t,e,n=!1){return"function"==typeof Symbol&&"symbol"==typeof Symbol()?n&&Symbol.for&&t?Symbol.for(t):null!=t?Symbol(t):Symbol():e}var x=U("jas",void 0,!0),B=U(void 0,"1oa"),N=U(void 0,"0ubsb"),F=U(void 0,"0actk"),R=U("m_m","pa",!0);const D={ha:{value:0,configurable:!0,writable:!0,enumerable:!1}},C=Object.defineProperties,M=k?x:"ha";var V;const G=[];function z(t,e){k||M in t||C(t,D),t[M]|=e}function W(t,e){k||M in t||C(t,D),t[M]=e}W(G,7),V=Object.freeze(G);var H={};function $(t,e){return void 0===e?t.i!==q&&!!(2&(0|t.m[M])):!!(2&e)&&t.i!==q}const q={};var K=Object.freeze({});function Y(t){return t.oa=!0,t}var J=Y((t=>"number"==typeof t)),X=Y((t=>"string"==typeof t)),Q=Y((t=>"boolean"==typeof t)),Z="function"==typeof t.BigInt&&"bigint"==typeof t.BigInt(0),tt=Y((t=>Z?t>=nt&&t<=it:"-"===t[0]?ot(t,et):ot(t,rt)));const et=Number.MIN_SAFE_INTEGER.toString(),nt=Z?BigInt(Number.MIN_SAFE_INTEGER):void 0,rt=Number.MAX_SAFE_INTEGER.toString(),it=Z?BigInt(Number.MAX_SAFE_INTEGER):void 0;function ot(t,e){if(t.length>e.length)return!1;if(t.lengthi)return!1;if(r>>0;at=e,ut=(t-e)/4294967296>>>0}function lt(t){if(t<0){ct(-t);const[e,n]=mt(at,ut);at=e>>>0,ut=n>>>0}else ct(t)}function ht(t,e){const n=4294967296*e+(t>>>0);return Number.isSafeInteger(n)?n:ft(t,e)}function ft(t,e){if(t>>>=0,(e>>>=0)<=2097151)var n=""+(4294967296*e+t);else j()?n=""+(BigInt(e)<>>24|e<<8))+6710656*(e=e>>16&65535),n+=8147497*e,e*=2,t>=1e7&&(n+=t/1e7>>>0,t%=1e7),n>=1e7&&(e+=n/1e7>>>0,n%=1e7),n=e+dt(n)+dt(t));return n}function dt(t){return t=String(t),"0000000".slice(t.length)+t}function pt(t){if(t.length<16)lt(Number(t));else if(j())t=BigInt(t),at=Number(t&BigInt(4294967295))>>>0,ut=Number(t>>BigInt(32)&BigInt(4294967295));else{const e=+("-"===t[0]);ut=at=0;const n=t.length;for(let r=e,i=(n-e)%6+e;i<=n;r=i,i+=6){const e=Number(t.slice(r,i));ut*=1e6,at=1e6*at+e,at>=4294967296&&(ut+=Math.trunc(at/4294967296),ut>>>=0,at>>>=0)}if(e){const[t,e]=mt(at,ut);at=t,ut=e}}}function mt(t,e){return e=~e,t?t=1+~t:e+=1,[t,e]}function gt(t){return Array.prototype.slice.call(t)}const _t="function"==typeof BigInt?BigInt.asIntN:void 0,yt="function"==typeof BigInt?BigInt.asUintN:void 0,wt=Number.isSafeInteger,vt=Number.isFinite,bt=Math.trunc;function St(t){if(null!=t&&"number"!=typeof t)throw Error(`Value of float/double field must be a number, found ${typeof t}: ${t}`);return t}function Et(t){return null==t||"number"==typeof t?t:"NaN"===t||"Infinity"===t||"-Infinity"===t?Number(t):void 0}function At(t){if(null!=t&&"boolean"!=typeof t){var e=typeof t;throw Error(`Expected boolean but got ${"object"!=e?e:t?Array.isArray(t)?"array":e:"null"}: ${t}`)}return t}function It(t){return null==t||"boolean"==typeof t?t:"number"==typeof t?!!t:void 0}const Tt=/^-?([1-9][0-9]*|0)(\.[0-9]+)?$/;function Lt(t){switch(typeof t){case"bigint":return!0;case"number":return vt(t);case"string":return Tt.test(t);default:return!1}}function Pt(t){if("number"!=typeof t)throw P("int32");if(!vt(t))throw P("int32");return 0|t}function Ot(t){return null==t?t:Pt(t)}function jt(t){if(null==t)return t;if("string"==typeof t&&t)t=+t;else if("number"!=typeof t)return;return vt(t)?0|t:void 0}function kt(t){if(null==t)return t;if("string"==typeof t&&t)t=+t;else if("number"!=typeof t)return;return vt(t)?t>>>0:void 0}function Ut(t){return null==t||"string"==typeof t?t:void 0}function xt(t,e,n){if(null!=t&&t[R]===H)return t;if(Array.isArray(t)){var r=0|t[M];return(n=r|32&n|2&n)!==r&&W(t,n),new e(t)}}function Bt(t,e,n,r){var i=void 0!==r;r=!!r;const o=[];var s=t.length;let a,u=4294967295,c=!1;const l=!!(64&e),h=l?128&e?0:-1:void 0;for(1&e||(a=s&&t[s-1],null!=a&&"object"==typeof a&&a.constructor===Object?u=--s:a=void 0,!l||128&e||i||(c=!0,u=u-h+h)),e=void 0,i=0;i=u){const t=i-h;(e??={})[t]=s}else o[i]=s}if(a)for(let i in a){if(null==(t=a[i])||null==(t=n(t,r)))continue;let c;s=+i,l&&!Number.isNaN(s)&&(c=s+h)>2];o=n[(3&o)<<4|s>>4],s=n[(15&s)<<2|a>>6],a=n[63&a],r[c++]=u+o+s+a}switch(u=0,a=i,e.length-t){case 2:a=n[(15&(u=e[t+1]))<<2]||i;case 1:e=e[t],r[c]=n[e>>2]+n[(3&e)<<4|u>>4]+a+i}e=r.join("")}t=t.i=e}return t}return}return t}let Ft,Rt;function Dt(t){return Bt(t=t.m,0|t[M],Nt)}function Ct(t,e,n,r=0){if(null==t){var i=32;n?(t=[n],i|=128):t=[],e&&(i=-16760833&i|(1023&e)<<14)}else{if(!Array.isArray(t))throw Error("narr");if(i=0|t[M],a&&1&i)throw Error("rfarr");if(2048&i&&!(2&i)&&function(){if(a)throw Error("carr");O(F,5)}(),256&i)throw Error("farr");if(64&i)return(i|r)!==i&&W(t,i|r),t;if(n&&(i|=128,n!==t[0]))throw Error("mid");t:{i|=64;var o=(n=t).length;if(o){var s=o-1;const t=n[s];if(null!=t&&"object"==typeof t&&t.constructor===Object){if((s-=e=128&i?0:-1)>=1024)throw Error("pvtlmt");for(var u in t)(o=+u)1024)throw Error("spvt");i=-16760833&i|(1023&u)<<14}}}return W(t,64|i|r),t}function Mt(t,e){if("object"!=typeof t)return t;if(Array.isArray(t)){var n=0|t[M];return 0===t.length&&1&n?t=void 0:2&n||(!e||4096&n||16&n?t=Gt(t,n,!1,e&&!(16&n)):(z(t,34),4&n&&Object.freeze(t))),t}return null!=t&&t[R]===H?$(t,n=0|(e=t.m)[M])?t:$t(t,e,n)?Vt(t,e):Gt(e,n):t instanceof E?t:void 0}function Vt(t,e,n){return t=new t.constructor(e),n&&(t.i=q),t.o=q,t}function Gt(t,e,n,r){return r??=!!(34&e),t=Bt(t,e,Mt,r),r=32,n&&(r|=2),W(t,e=16769217&e|r),t}function zt(t){if(t.i!==q)return!1;var e=t.m;return z(e=Gt(e,0|e[M]),2048),t.m=e,t.i=void 0,t.o=void 0,!0}function Wt(t){if(!zt(t)&&$(t,0|t.m[M]))throw Error()}function Ht(t,e){void 0===e&&(e=0|t[M]),32&e&&!(4096&e)&&W(t,4096|e)}function $t(t,e,n){return!!(2&n)||!(!(32&n)||4096&n)&&(W(e,2|n),t.i=q,!0)}function qt(t,e,n){if(null!==(t=Kt(t.m,e,void 0,n)))return t}function Kt(t,e,n,r){if(-1===e)return null;const i=e+(n?0:-1),o=t.length-1;let s,a;if(!(o<1+(n?0:-1))){if(i>=o)if(s=t[o],null!=s&&"object"==typeof s&&s.constructor===Object)n=s[e],a=!0;else{if(i!==o)return;n=s}else n=t[i];if(r&&null!=n){if(null==(r=r(n)))return r;if(!Object.is(r,n))return a?s[e]=r:t[i]=r,r}return n}}function Yt(t,e,n){Wt(t),Jt(t=t.m,0|t[M],e,n)}function Jt(t,e,n,r,i){const o=n+(i?0:-1);var s=t.length-1;if(s>=1+(i?0:-1)&&o>=s){const i=t[s];if(null!=i&&"object"==typeof i&&i.constructor===Object)return i[n]=r,e}return o<=s?(t[o]=r,e):(void 0!==r&&(n>=(s=(e??=0|t[M])>>14&1023||536870912)?null!=r&&(t[s+(i?0:-1)]={[n]:r}):t[o]=r),e)}function Xt(t,e,n,r,i){let o=t.m,s=0|o[M];r=$(t,s)?1:r,i=!!i||3===r,2===r&&zt(t)&&(o=t.m,s=0|o[M]);let a=(t=Zt(o,e))===V?7:0|t[M],u=te(a,s);var c=!(4&u);if(c){4&u&&(t=gt(t),a=0,u=ce(u,s),s=Jt(o,s,e,t));let r=0,i=0;for(;r{const r=xt(t,n,e);return i=r!==t&&null!=r,r}))))return i&&!$(r)&&Ht(t,e),r}(r,i,e,n),null==e)return e;if(i=0|r[M],!$(t,i)){var o,s=e;const a=s.m,u=0|a[M];(o=$(s,u)?$t(s,a,u)?Vt(s,a,!0):new s.constructor(Gt(a,u,!1)):s)!==e&&(zt(t)&&(r=t.m,i=0|r[M]),i=Jt(r,i,n,e=o),Ht(r,i))}return e}function ae(t){return null==t&&(t=void 0),t}function ue(t,e,n){return Yt(t,e,n=ae(n)),n&&!$(n)&&Ht(t.m),t}function ce(t,e){return-273&(2&e?2|t:-3&t)}function le(t,e,n,r){var i=r;Wt(t);var o=r=t.m,s=0|r[M];const a=$(t,s)?1:2;2===a&&zt(t)&&(s=0|(o=t.m)[M]);let u=(t=Zt(o,e))===V?7:0|t[M];var c=te(u,s);const l=!(4&c);if(l){var h=t,f=s;const e=!!(2&c);e&&(f|=2);let r=!e,i=!0,o=0,a=0;for(;o>>=0}Yt(t,e,n)}function pe(t,e,n){if(null!=n&&"string"!=typeof n)throw Error();re(t,e,n,"")}function me(t,e,n){if(Wt(t),e=(t=Xt(t,e,Ut,2,!0)).push,"string"!=typeof n)throw Error();e.call(t,n)}var ge=class{constructor(t,e,n){if(this.buffer=t,n&&!e)throw Error()}};function _e(t){if("string"==typeof t)return new ge(w(t),!0);if(Array.isArray(t))return new ge(new Uint8Array(t),!0);if(t.constructor===Uint8Array)return new ge(t,!1);if(t.constructor===ArrayBuffer)return t=new Uint8Array(t),new ge(t,!1);if(t.constructor===E){T(b);var e=t.i;return e=(null==(e=null==e||v(e)?e:"string"==typeof e?w(e):null)?e:t.i=e)||new Uint8Array(0),new ge(e,!0,t)}if(t instanceof Uint8Array)return t=t.constructor===Uint8Array?t:new Uint8Array(t.buffer,t.byteOffset,t.byteLength),new ge(t,!1);throw Error()}function ye(t){return t?/^\d+$/.test(t)?(pt(t),new we(at,ut)):null:ve||=new we(0,0)}var we=class{constructor(t,e){this.j=t>>>0,this.i=e>>>0}};let ve;function be(t){return t?/^-?\d+$/.test(t)?(pt(t),new Se(at,ut)):null:Ee||=new Se(0,0)}var Se=class{constructor(t,e){this.j=t>>>0,this.i=e>>>0}};let Ee;function Ae(t,e,n){for(;n>0||e>127;)t.i.push(127&e|128),e=(e>>>7|n<<25)>>>0,n>>>=7;t.i.push(e)}function Ie(t,e){for(;e>127;)t.i.push(127&e|128),e>>>=7;t.i.push(e)}function Te(t,e){if(e>=0)Ie(t,e);else{for(let n=0;n<9;n++)t.i.push(127&e|128),e>>=7;t.i.push(1)}}function Le(t,e){0!==e.length&&(t.l.push(e),t.j+=e.length)}function Pe(t,e,n){Ie(t.i,8*e+n)}function Oe(t,e){return Pe(t,e,2),e=t.i.end(),Le(t,e),e.push(t.j),e}function je(t,e){var n=e.pop();for(n=t.j+t.i.length()-n;n>127;)e.push(127&n|128),n>>>=7,t.j++;e.push(n),t.j++}function ke(t,e,n){Pe(t,e,2),Ie(t.i,n.length),Le(t,t.i.end()),Le(t,n)}function Ue(){const t=class{constructor(){throw Error()}};return Object.setPrototypeOf(t,t.prototype),t}var xe=Ue(),Be=Ue(),Ne=Ue(),Fe=Ue(),Re=Ue(),De=Ue(),Ce=Ue(),Me=Ue(),Ve=Ue(),Ge=Ue(),ze=class{constructor(t,e){this.m=Ct(t,e,void 0,2048)}toJSON(){return Dt(this)}};ze.prototype[R]=H,ze.prototype.toString=function(){return this.m.toString()};var We=class{constructor(t,e){this.i=t,t=xe,this.j=!!t&&e===t||!1}};function He(t,e,n,r,i){null!=(e=Ze(e,r))&&(n=Oe(t,n),i(e,t),je(t,n))}const $e=new We(He,xe),qe=new We(He,xe);var Ke=Symbol(),Ye=Symbol();let Je,Xe;function Qe(t){var e=tn,n=en,r=t[Ke];if(r)return r;(r={}).na=t,r.W=function(t){switch(typeof t){case"boolean":return Ft||=[0,void 0,!0];case"number":return t>0?void 0:0===t?Rt||=[0,void 0]:[-t,void 0];case"string":return[0,t];case"object":return t}}(t[0]);var i=t[1];let o=1;i&&i.constructor===Object&&(r.ca=i,"function"==typeof(i=t[++o])&&(r.ia=!0,Je??=i,Xe??=t[o+1],i=t[o+=2]));const s={};for(;i&&Array.isArray(i)&&i.length&&"number"==typeof i[0]&&i[0]>0;){for(var a=0;as(t,e,n,o||=Qe(r).W,i||=nn(r))}function nn(t){let e=t[Ye];if(!e){const n=Qe(t);e=(t,e)=>rn(t,e,n),t[Ye]=e}return e}function rn(t,e,n){!function(t,e,n){const r=128&e?0:-1,i=t.length;var o;(o=!!i)&&(o=null!=(o=t[i-1])&&"object"==typeof o&&o.constructor===Object);const s=i+(o?-1:0);for(e=128&e?1:0;e{if(null!=r){var i=function(t,e){var n=t[e];if(n)return n;if((n=t.ca)&&(n=n[e])){var r=(n=Array.isArray(n)?n[0]instanceof We?n:[qe,n]:[n,void 0])[0].i;if(n=n[1]){const e=nn(n),i=Qe(n).W;n=t.ia?Xe(i,e):(t,n,o)=>r(t,n,o,i,e)}else n=r;return t[e]=n}}(n,t);i?i(e,r,t):t<500||O(N,3)}}))}var on,sn=0,an=sn;if(X(an)){if(!/^\s*(?:-?[1-9]\d*|0)?\s*$/.test(an))throw Error(String(an))}else if((on=J(an))&&(on=!Number.isSafeInteger(an)),on)throw Error(String(an));function un(t,e){if(Array.isArray(e)){var n=0|e[M];if(4&n)return e;for(var r=0,i=0;r>>0&255),t.i.push(e>>>8&255),t.i.push(e>>>16&255),t.i.push(e>>>24&255))}function hn(t,e,n){null!=(e=jt(e))&&null!=e&&(Pe(t,n,0),Te(t.i,e))}function fn(t,e,n){null!=(e=It(e))&&(Pe(t,n,0),t.i.i.push(e?1:0))}function dn(t,e,n){null!=(e=Ut(e))&&ke(t,n,i(e))}function pn(t,e,n,r,i){null!=(e=Ze(e,r))&&(n=Oe(t,n),i(e,t),je(t,n))}function mn(t,e,n){null!=(e=kt(e))&&null!=e&&(Pe(t,n,0),Ie(t.i,e))}function gn(t,e,n){null!=(e=jt(e))&&(e=parseInt(e,10),Pe(t,n,0),Te(t.i,e))}Z||(sn=Q(sn)?sn?"1":"0":X(sn)?sn.trim()||"0":String(sn));var _n,yn=cn(ln,Me),wn=cn(ln,Me),vn=cn((function(t,e,n){if(e=function(t){if(null==t)return t;var e=typeof t;if("bigint"===e)return String(_t(64,t));if(Lt(t)){if("string"===e){if(e=bt(Number(t)),wt(e))t=String(e);else if(-1!==(e=t.indexOf("."))&&(t=t.substring(0,e)),e=t.length,!("-"===t[0]?e<20||20===e&&t<="-9223372036854775808":e<19||19===e&&t<="9223372036854775807"))if(pt(t),t=at,2147483648&(e=ut))if(j())t=""+(BigInt(0|e)<>>0));else{const[n,r]=mt(t,e);t="-"+ft(n,r)}else t=ft(t,e);return t}if("number"===e){if(t=bt(t),!wt(t)){lt(t),e=at;var n=ut;(t=2147483648&n)&&(n=~n>>>0,0==(e=1+~e>>>0)&&(n=n+1>>>0)),t="number"==typeof(e=ht(e,n))?t?-e:e:t?"-"+e:e}return t}}}(e),null!=e){if("string"==typeof e)be(e);if(null!=e)switch(Pe(t,n,0),typeof e){case"number":t=t.i,lt(e),Ae(t,at,ut);break;case"bigint":n=BigInt.asUintN(64,e),n=new Se(Number(n&BigInt(4294967295)),Number(n>>BigInt(32))),Ae(t.i,n.j,n.i);break;default:n=be(e),Ae(t.i,n.j,n.i)}}}),De),bn=cn((function(t,e,n){if(e=function(t){if(null==t)return t;var e=typeof t;if("bigint"===e)return String(yt(64,t));if(Lt(t)){if("string"===e)return e=bt(Number(t)),wt(e)&&e>=0?t=String(e):(-1!==(e=t.indexOf("."))&&(t=t.substring(0,e)),(e="-"!==t[0]&&((e=t.length)<20||20===e&&t<="18446744073709551615"))||(pt(t),t=ft(at,ut))),t;if("number"===e)return(t=bt(t))>=0&&wt(t)||(lt(t),t=ht(at,ut)),t}}(e),null!=e){if("string"==typeof e)ye(e);if(null!=e)switch(Pe(t,n,0),typeof e){case"number":t=t.i,lt(e),Ae(t,at,ut);break;case"bigint":n=BigInt.asUintN(64,e),n=new we(Number(n&BigInt(4294967295)),Number(n>>BigInt(32))),Ae(t.i,n.j,n.i);break;default:n=ye(e),Ae(t.i,n.j,n.i)}}}),Ce),Sn=cn(hn,Fe);_n=new We((function(t,e,n){if(null!=(e=un(jt,e))&&e.length){n=Oe(t,n);for(let n=0;nt;t=Gn.createPolicy("goog#html",{createHTML:e,createScript:e,createScriptURL:e})}catch(t){}return t}()),t=(e=Vn)?e.createScriptURL(t):t,new class{constructor(t){this.i=t}toString(){return this.i+""}}(t)}function Wn(t,...e){if(0===e.length)return zn(t[0]);let n=t[0];for(let r=0;r{if(e.cache.length>0)r.enqueue(e.cache.shift());else{var{value:i,done:o}=await t.read();i&&(n.active&&n.cache.push(i),e.active&&r.enqueue(i)),o&&r.close()}})),await i},cancel(){e.active=!1,e.cache.length=0,n.active||t.cancel()}})}var n={cache:[],active:!0};const r={cache:[],active:!0};let i=Promise.resolve();const o=e(n,r);return n=e(r,n),[o.getReader(),n.getReader()]}async function ar(t,e){const n=new Uint8Array(e);let r=0;for(;r{const e=(new TextEncoder).encode("TFL3").length;return t=await ar(t,e+4),"TFL3"===new TextDecoder("utf-8").decode(t.subarray(4,e+4))}],[1,async t=>80===(t=await ar(t,6))[4]&&75===t[5]]];function cr(){var t=navigator;return"undefined"!=typeof OffscreenCanvas&&(!function(t=navigator){return(t=t.userAgent).includes("Safari")&&!t.includes("Chrome")}(t)||!!((t=t.userAgent.match(/Version\/([\d]+).*Safari/))&&t.length>=1&&Number(t[1])>=17))}async function lr(t){if("function"!=typeof importScripts){const e=document.createElement("script");return e.src=t.toString(),e.crossOrigin="anonymous",new Promise(((t,n)=>{e.addEventListener("load",(()=>{t()}),!1),e.addEventListener("error",(t=>{n(t)}),!1),document.body.appendChild(e)}))}try{importScripts(t.toString())}catch(e){if(!(e instanceof TypeError))throw e;await self.import(t.toString())}}function hr(t,e,n){t.o||console.error("No wasm multistream support detected: ensure dependency inclusion of :gl_graph_runner_internal_multi_input target"),n(e=t.h.stringToNewUTF8(e)),t.h._free(e)}function fr(t,e,n){t.o||console.error("No wasm multistream support detected: ensure dependency inclusion of :gl_graph_runner_internal_multi_input target");const r=new Uint32Array(e.length);for(let n=0;n>2),n(e);for(const e of r)t.h._free(e);t.h._free(e)}function dr(t,e,n){t.h.simpleListeners=t.h.simpleListeners||{},t.h.simpleListeners[e]=n}function pr(t,e,n){let r=[];t.h.simpleListeners=t.h.simpleListeners||{},t.h.simpleListeners[e]=(t,e,i)=>{e?(n(r,i),r=[]):r.push(t)}}const mr=(gr=class{constructor(t,e){this.l=!0,this.h=t,this.i=null,this.j=0,this.o="function"==typeof this.h._addIntToInputStream,void 0!==e?this.h.canvas=e:cr()?this.h.canvas=new OffscreenCanvas(1,1):(console.warn("OffscreenCanvas not supported and GraphRunner constructor glCanvas parameter is undefined. Creating backup canvas."),this.h.canvas=document.createElement("canvas"))}async initializeGraph(t){const e=await(await fetch(t)).arrayBuffer();t=!(t.endsWith(".pbtxt")||t.endsWith(".textproto")),this.setGraph(new Uint8Array(e),t)}setGraphFromString(t){this.setGraph((new TextEncoder).encode(t),!1)}setGraph(t,e){const n=t.length,r=this.h._malloc(n);this.h.HEAPU8.set(t,r),e?this.h._changeBinaryGraph(n,r):this.h._changeTextGraph(n,r),this.h._free(r)}configureAudio(t,e,n,r,i){this.h._configureAudio||console.warn('Attempting to use configureAudio without support for input audio. Is build dep ":gl_graph_runner_audio" missing?'),hr(this,r||"input_audio",(r=>{hr(this,i=i||"audio_header",(i=>{this.h._configureAudio(r,i,t,e??0,n)}))}))}setAutoResizeCanvas(t){this.l=t}setAutoRenderToScreen(t){this.h._setAutoRenderToScreen(t)}setGpuBufferVerticalFlip(t){this.h.gpuOriginForWebTexturesIsBottomLeft=t}attachErrorListener(t){this.h.errorListener=t}attachEmptyPacketListener(t,e){this.h.emptyPacketListeners=this.h.emptyPacketListeners||{},this.h.emptyPacketListeners[t]=e}addAudioToStream(t,e,n){this.addAudioToStreamWithShape(t,0,0,e,n)}addAudioToStreamWithShape(t,e,n,r,i){const o=4*t.length;this.j!==o&&(this.i&&this.h._free(this.i),this.i=this.h._malloc(o),this.j=o),this.h.HEAPF32.set(t,this.i/4),hr(this,r,(t=>{this.h._addAudioToInputStream(this.i,e,n,t,i)}))}addGpuBufferToStream(t,e,n){hr(this,e,(e=>{if(!this.h.canvas)throw Error("No OpenGL canvas configured.");e?this.h._bindTextureToStream(e):this.h._bindTextureToCanvas();const r=this.h.canvas.getContext("webgl2")||this.h.canvas.getContext("webgl");if(!r)throw Error("Failed to obtain WebGL context from the provided canvas. `getContext()` should only be invoked with `webgl` or `webgl2`.");this.h.gpuOriginForWebTexturesIsBottomLeft&&r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!0),r.texImage2D(r.TEXTURE_2D,0,r.RGBA,r.RGBA,r.UNSIGNED_BYTE,t),this.h.gpuOriginForWebTexturesIsBottomLeft&&r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!1);const[i,o]=void 0!==t.videoWidth?[t.videoWidth,t.videoHeight]:void 0!==t.naturalWidth?[t.naturalWidth,t.naturalHeight]:void 0!==t.displayWidth?[t.displayWidth,t.displayHeight]:[t.width,t.height];!this.l||i===this.h.canvas.width&&o===this.h.canvas.height||(this.h.canvas.width=i,this.h.canvas.height=o);const[s,a]=[i,o];this.h._addBoundTextureToStream(e,s,a,n)}))}addBoolToStream(t,e,n){hr(this,e,(e=>{this.h._addBoolToInputStream(t,e,n)}))}addDoubleToStream(t,e,n){hr(this,e,(e=>{this.h._addDoubleToInputStream(t,e,n)}))}addFloatToStream(t,e,n){hr(this,e,(e=>{this.h._addFloatToInputStream(t,e,n)}))}addIntToStream(t,e,n){hr(this,e,(e=>{this.h._addIntToInputStream(t,e,n)}))}addUintToStream(t,e,n){hr(this,e,(e=>{this.h._addUintToInputStream(t,e,n)}))}addStringToStream(t,e,n){hr(this,e,(e=>{hr(this,t,(t=>{this.h._addStringToInputStream(t,e,n)}))}))}addStringRecordToStream(t,e,n){hr(this,e,(e=>{fr(this,Object.keys(t),(r=>{fr(this,Object.values(t),(i=>{this.h._addFlatHashMapToInputStream(r,i,Object.keys(t).length,e,n)}))}))}))}addProtoToStream(t,e,n,r){hr(this,n,(n=>{hr(this,e,(e=>{const i=this.h._malloc(t.length);this.h.HEAPU8.set(t,i),this.h._addProtoToInputStream(i,t.length,e,n,r),this.h._free(i)}))}))}addEmptyPacketToStream(t,e){hr(this,t,(t=>{this.h._addEmptyPacketToInputStream(t,e)}))}addBoolVectorToStream(t,e,n){hr(this,e,(e=>{const r=this.h._allocateBoolVector(t.length);if(!r)throw Error("Unable to allocate new bool vector on heap.");for(const e of t)this.h._addBoolVectorEntry(r,e);this.h._addBoolVectorToInputStream(r,e,n)}))}addDoubleVectorToStream(t,e,n){hr(this,e,(e=>{const r=this.h._allocateDoubleVector(t.length);if(!r)throw Error("Unable to allocate new double vector on heap.");for(const e of t)this.h._addDoubleVectorEntry(r,e);this.h._addDoubleVectorToInputStream(r,e,n)}))}addFloatVectorToStream(t,e,n){hr(this,e,(e=>{const r=this.h._allocateFloatVector(t.length);if(!r)throw Error("Unable to allocate new float vector on heap.");for(const e of t)this.h._addFloatVectorEntry(r,e);this.h._addFloatVectorToInputStream(r,e,n)}))}addIntVectorToStream(t,e,n){hr(this,e,(e=>{const r=this.h._allocateIntVector(t.length);if(!r)throw Error("Unable to allocate new int vector on heap.");for(const e of t)this.h._addIntVectorEntry(r,e);this.h._addIntVectorToInputStream(r,e,n)}))}addUintVectorToStream(t,e,n){hr(this,e,(e=>{const r=this.h._allocateUintVector(t.length);if(!r)throw Error("Unable to allocate new unsigned int vector on heap.");for(const e of t)this.h._addUintVectorEntry(r,e);this.h._addUintVectorToInputStream(r,e,n)}))}addStringVectorToStream(t,e,n){hr(this,e,(e=>{const r=this.h._allocateStringVector(t.length);if(!r)throw Error("Unable to allocate new string vector on heap.");for(const e of t)hr(this,e,(t=>{this.h._addStringVectorEntry(r,t)}));this.h._addStringVectorToInputStream(r,e,n)}))}addBoolToInputSidePacket(t,e){hr(this,e,(e=>{this.h._addBoolToInputSidePacket(t,e)}))}addDoubleToInputSidePacket(t,e){hr(this,e,(e=>{this.h._addDoubleToInputSidePacket(t,e)}))}addFloatToInputSidePacket(t,e){hr(this,e,(e=>{this.h._addFloatToInputSidePacket(t,e)}))}addIntToInputSidePacket(t,e){hr(this,e,(e=>{this.h._addIntToInputSidePacket(t,e)}))}addUintToInputSidePacket(t,e){hr(this,e,(e=>{this.h._addUintToInputSidePacket(t,e)}))}addStringToInputSidePacket(t,e){hr(this,e,(e=>{hr(this,t,(t=>{this.h._addStringToInputSidePacket(t,e)}))}))}addProtoToInputSidePacket(t,e,n){hr(this,n,(n=>{hr(this,e,(e=>{const r=this.h._malloc(t.length);this.h.HEAPU8.set(t,r),this.h._addProtoToInputSidePacket(r,t.length,e,n),this.h._free(r)}))}))}addBoolVectorToInputSidePacket(t,e){hr(this,e,(e=>{const n=this.h._allocateBoolVector(t.length);if(!n)throw Error("Unable to allocate new bool vector on heap.");for(const e of t)this.h._addBoolVectorEntry(n,e);this.h._addBoolVectorToInputSidePacket(n,e)}))}addDoubleVectorToInputSidePacket(t,e){hr(this,e,(e=>{const n=this.h._allocateDoubleVector(t.length);if(!n)throw Error("Unable to allocate new double vector on heap.");for(const e of t)this.h._addDoubleVectorEntry(n,e);this.h._addDoubleVectorToInputSidePacket(n,e)}))}addFloatVectorToInputSidePacket(t,e){hr(this,e,(e=>{const n=this.h._allocateFloatVector(t.length);if(!n)throw Error("Unable to allocate new float vector on heap.");for(const e of t)this.h._addFloatVectorEntry(n,e);this.h._addFloatVectorToInputSidePacket(n,e)}))}addIntVectorToInputSidePacket(t,e){hr(this,e,(e=>{const n=this.h._allocateIntVector(t.length);if(!n)throw Error("Unable to allocate new int vector on heap.");for(const e of t)this.h._addIntVectorEntry(n,e);this.h._addIntVectorToInputSidePacket(n,e)}))}addUintVectorToInputSidePacket(t,e){hr(this,e,(e=>{const n=this.h._allocateUintVector(t.length);if(!n)throw Error("Unable to allocate new unsigned int vector on heap.");for(const e of t)this.h._addUintVectorEntry(n,e);this.h._addUintVectorToInputSidePacket(n,e)}))}addStringVectorToInputSidePacket(t,e){hr(this,e,(e=>{const n=this.h._allocateStringVector(t.length);if(!n)throw Error("Unable to allocate new string vector on heap.");for(const e of t)hr(this,e,(t=>{this.h._addStringVectorEntry(n,t)}));this.h._addStringVectorToInputSidePacket(n,e)}))}attachBoolListener(t,e){dr(this,t,e),hr(this,t,(t=>{this.h._attachBoolListener(t)}))}attachBoolVectorListener(t,e){pr(this,t,e),hr(this,t,(t=>{this.h._attachBoolVectorListener(t)}))}attachIntListener(t,e){dr(this,t,e),hr(this,t,(t=>{this.h._attachIntListener(t)}))}attachIntVectorListener(t,e){pr(this,t,e),hr(this,t,(t=>{this.h._attachIntVectorListener(t)}))}attachUintListener(t,e){dr(this,t,e),hr(this,t,(t=>{this.h._attachUintListener(t)}))}attachUintVectorListener(t,e){pr(this,t,e),hr(this,t,(t=>{this.h._attachUintVectorListener(t)}))}attachDoubleListener(t,e){dr(this,t,e),hr(this,t,(t=>{this.h._attachDoubleListener(t)}))}attachDoubleVectorListener(t,e){pr(this,t,e),hr(this,t,(t=>{this.h._attachDoubleVectorListener(t)}))}attachFloatListener(t,e){dr(this,t,e),hr(this,t,(t=>{this.h._attachFloatListener(t)}))}attachFloatVectorListener(t,e){pr(this,t,e),hr(this,t,(t=>{this.h._attachFloatVectorListener(t)}))}attachStringListener(t,e){dr(this,t,e),hr(this,t,(t=>{this.h._attachStringListener(t)}))}attachStringVectorListener(t,e){pr(this,t,e),hr(this,t,(t=>{this.h._attachStringVectorListener(t)}))}attachProtoListener(t,e,n){dr(this,t,e),hr(this,t,(t=>{this.h._attachProtoListener(t,n||!1)}))}attachProtoVectorListener(t,e,n){pr(this,t,e),hr(this,t,(t=>{this.h._attachProtoVectorListener(t,n||!1)}))}attachAudioListener(t,e,n){this.h._attachAudioListener||console.warn('Attempting to use attachAudioListener without support for output audio. Is build dep ":gl_graph_runner_audio_out" missing?'),dr(this,t,((t,n)=>{t=new Float32Array(t.buffer,t.byteOffset,t.length/4),e(t,n)})),hr(this,t,(t=>{this.h._attachAudioListener(t,n||!1)}))}finishProcessing(){this.h._waitUntilIdle()}closeGraph(){this.h._closeGraph(),this.h.simpleListeners=void 0,this.h.emptyPacketListeners=void 0}},class extends gr{ka(){this.h._registerModelResourcesGraphService()}});var gr;async function _r(t,e){const n=await(async(t,e,n)=>{var r=ri;if(t&&await lr(t),!self.ModuleFactory)throw Error("ModuleFactory not set.");if(e&&(await lr(e),!self.ModuleFactory))throw Error("ModuleFactory not set.");return self.Module&&n&&((t=self.Module).locateFile=n.locateFile,n.mainScriptUrlOrBlob&&(t.mainScriptUrlOrBlob=n.mainScriptUrlOrBlob)),n=await self.ModuleFactory(self.Module||n),self.ModuleFactory=self.Module=void 0,new r(n,null)})(t.wasmLoaderPath,t.assetLoaderPath,{locateFile:e=>e.endsWith(".wasm")?t.wasmBinaryPath.toString():t.assetBinaryPath&&e.endsWith(".data")?t.assetBinaryPath.toString():e});return await n.N(e),n}async function yr(t,e){return _r(t,e)}function wr(t){try{const e=t.J.length;if(1===e)throw Error(t.J[0].message);if(e>1)throw Error("Encountered multiple errors: "+t.J.map((t=>t.message)).join(", "))}finally{t.J=[]}}function vr(t,e){t.I=Math.max(t.I,e)}var br=class{constructor(t){this.j=t,this.J=[],this.I=0,this.j.setAutoRenderToScreen(!1)}setGraph(t,e){this.j.attachErrorListener(((t,e)=>{this.J.push(Error(e))})),this.j.ka(),this.j.setGraph(t,e),wr(this)}finishProcessing(){this.j.finishProcessing(),wr(this)}close(){this.j.closeGraph()}};br.prototype.close=br.prototype.close;var Sr=class extends ze{constructor(t){super(t)}j(){return jt(qt(this,2))??0}};function Er(t,e){ue(t,1,e)}var Ar=class extends ze{constructor(t){super(t)}},Ir=[0,Fn,An,wn,-1,Sn];function Tr(t,e,n,r){if(void 0!==t.data){var i=new Uint8Array(t.data.buffer,e,n);return 1===r&&function(t,e,n){t.i.push([e,n]),t.i.sort(((t,e)=>t[0]-e[0])),e=0;for(const[r,i]of t.i){const t=i;(n=r)<=e&&(e=Math.max(e,n+t))}e===t.length&&(t.data=void 0)}(t,e,n),i}}Sr.prototype.l=Rn(Ir);class Lr{constructor(t){this.i=[],this.data=t,this.length=t.length}}function Pr(t,e){return new jr((async()=>{const{value:e,done:n}=await t.read();return n?void 0:e}),e)}async function Or(t,e,n,r,i){if(2===i)return t.i=[],t.j=()=>Promise.resolve(void 0),setTimeout((()=>{t.l()}),0),Promise.resolve(0);for(;t.size>>0;let s=0;for(let a=0;a=u.length){n-=u.length;continue}const c=Math.min(r,u.length-n);if(void 0===(n=Tr(u,n,c,i)))throw Error("Data has already been released.");if(e.HEAPU8.set(n,o+s),n=0,s+=c,0===(r-=c))break}if(0!==r)throw Error("Data not found.");return Promise.resolve(o)}var jr=class{constructor(t,e){this.i=[],this.j=t,this.l=e}get size(){let t=0;for(let e=0;e>>0,this.o=this.h.HEAPU8,this.i=!!this.j}get offset(){if(!this.i)throw Error("WasmFileReference has been freed.");return this.j}get size(){if(!this.i)throw Error("WasmFileReference has been freed.");return this.l}set(t,e){this.o.set(t,this.j+(e??0))}},Fr=class extends ze{constructor(t){super(t)}};Fr.prototype.j=Rn([0,jn,2,En,An,Ln]);var Rr=class extends ze{constructor(t){super(t)}},Dr=class extends ze{constructor(t){super(t)}},Cr=class extends ze{constructor(t){super(t)}},Mr=class extends ze{constructor(t){super(t)}},Vr=[0,An,-6,1,An,1,[0,Ln,Fn,-2],[0,Ln,wn],Fn,-2,[0,Ln,-1,Fn,wn,Nn,Sn,Tn,-1],1,Ln,An,Sn,-1,[0,Fn,An],Ln,-1,yn,An,-5,yn,-1,[0,Sn,yn],Sn,Tn,[0,Sn,-2],yn,[0,An],[0,An,-4],Tn,Sn,-2,Tn,-1,wn,yn,Tn,An,-1,1,Ln,An],Gr=[0,jn,-2],zr=[0,[4,6],Vr,An,1,In,En,kn,On,Gr,Sn,[0,[0,An,-1,Un,[0,An,[0,An,-1],-1,[0,Fn,-1],Ln],Ln,-2,An,-1],[0,An,-1,Ln],Vr,Ln,An,[0,An],-1],Pn,-3,[0,An,Ln],Vr,[0,Gr,-2],_n];Mr.prototype.j=Rn([0,jn,8,[0,Ln,-6],1,An,1,An,[0,Un,[0,jn,bn,-1,Fn],zr,An],[0,An,Ln,-3],1,Fn,1,zr,1,An,5,Fn,_n,1,Ir,Ln,An,Ln]);var Wr=class extends ze{constructor(t){super(t)}},Hr=class extends ze{constructor(t){super(t)}},$r=[2,4];Hr.prototype.j=Rn([0,$r,An,kn,An,xn,[0,1,jn]]);const qr=function(t){return class extends t{constructor(){super(...arguments),this.P=!1,this.F=this.H=0}M(){if(this.P)throw Error("Cannot process because LLM inference engine is currently loading or processing.");this.P=!0}L(){this.P=!1}async createLlmInferenceEngine(t,e){this.M();try{const n=Pr(t,(()=>{}));await this.h.createLlmInferenceEngine(he(e,2)??512,se(e,Sr,3)?.j()??40,It(qt(e,6))??!1??!1,he(e,7)??0,It(qt(e,8))??!1??!1,((t,e,r)=>Or(n,this.h,t,e,r)))}finally{this.L()}}async ba(t,e){this.M();try{await this.ma(t),await this.h.ccall("CreateLlmInferenceEngineConverted","void",["number","number","boolean"],[he(e,2)??512,se(e,Sr,3)?.j()??40,It(qt(e,6))??!1??!1],{async:!0})}finally{this.L()}}V(){this.M();try{const t=this.h;t.ccall("DeleteLlmInferenceEngine","void",[],[],{async:!1}),this.H&&(t._FreeSession(this.H),this.F===this.H&&(this.F=0),this.H=0),this.F&&(t._FreeSession(this.F),this.F=0)}finally{this.L()}}async R(t,e,n){this.M();try{const r=[],i=this.h;i._userProgressListener=(t,e)=>{t&&r.push(t),n&&n(t,e)};const o=e.l(),s=o.length,a=this.h._malloc(s);this.h.HEAPU8.set(o,a);const u=t.some(Ur),c=t.some(kr);i.ccallNum=i.ccall;const l=await i.ccallNum("MakeSessionForPredict","number",["number","number","boolean","boolean"],[a,s,c,u],{async:!0});e=[];for(const n of t)if("string"==typeof n)hr(this,n,(t=>{i._AddTextQueryChunk(l,t)}));else if(kr(n)){const{image:t,width:r,height:o}=await this.fa(n.imageSource),s="undefined"!=typeof OffscreenCanvas?new OffscreenCanvas(r,o):document.createElement("canvas");s.width=r,s.height=o;const a=s.getContext("2d");a.drawImage(t,0,0);const u=a.getImageData(0,0,r,o),c=this.h._malloc(u.width*u.height*4);this.h.HEAPU8.set(u.data,c),i._AddImageQueryChunk(l,c,u.width,u.height),e.push(c)}else{if(!Ur(n))throw Error("Unsupported PromptPart type in query.");{const t=await this.ea(n.audioSource),r=this.h._malloc(t.audioSamples.byteLength);this.h.HEAPF32.set(t.audioSamples,r/4),i._AddAudioQueryChunk(l,t.audioSampleRateHz,r,t.audioSamples.length),e.push(r)}}await i.ccall("PredictSession","void",["number"],[l],{async:!0}),t=!0,c&&0===this.F&&(this.F=l,t=!1),u&&0===this.H&&(this.H=l,t=!1),t&&i._FreeSession(l);for(const t of e)this.h._free(t);return e.length=0,n&&n("",!0),this.h._free(a),i._userProgressListener=void 0,r.join("")}finally{this.L()}}S(t){this.M();let e=0,n="";for(const r of t)"string"==typeof r?n+=r:kr(r)?e+=260:Ur(r)&&console.warn("sizeInTokens is not yet implemented for audio; audio tokens will not be counted");try{let t;return hr(this,n,(e=>{t=this.h._GetSizeInTokens(e)})),e+t}finally{this.L()}}async ma(t){t=await async function(t){const e=[];for(var n=0;;){const{done:r,value:i}=await t.read();if(r)break;e.push(i),n+=i.length}if(0===e.length)return new Uint8Array(0);if(1===e.length)return e[0];t=new Uint8Array(n),n=0;for(const r of e)t.set(r,n),n+=r.length;return t}(t);try{this.h.FS_unlink("llm.task")}catch{}this.h.FS_createDataFile("/","llm.task",t,!0,!1,!1)}async fa(t){if("string"==typeof t){const e=new Image;e.src=t,e.crossOrigin="Anonymous";try{await e.decode()}catch{throw Error(`Image from URL ${t} failed to load`)}return{image:e,width:e.naturalWidth,height:e.naturalHeight}}if(t instanceof HTMLImageElement){try{await t.decode()}catch{throw Error("Image from HTMLImageElement failed to load")}return{image:t,width:t.naturalWidth,height:t.naturalHeight}}return t instanceof HTMLVideoElement?{image:t,width:t.videoWidth,height:t.videoHeight}:t instanceof VideoFrame?{image:t,width:t.displayWidth,height:t.displayHeight}:{image:t,width:t.width,height:t.height}}async ea(t){if("string"==typeof t){const e=await fetch(t);if(!e.ok)throw Error(`Audio fetch for ${t} had error: ${e.status}`);return t=await e.arrayBuffer(),{audioSamples:(t=await new AudioContext({sampleRate:16e3}).decodeAudioData(t)).getChannelData(0),audioSampleRateHz:t.sampleRate}}return"object"==typeof t&&null!=t&&"audioSamples"in t&&"audioSampleRateHz"in t?t:{audioSamples:t.getChannelData(0),audioSampleRateHz:t.sampleRate}}}}(function(t){const e=class extends t{static async la(t,n){let r;n||=await e.X();const i=[];for(const e of t?.requiredFeatures??[])n.features.has(e)?i.push(e):console.warn(`WebGPU feature ${e} is not supported.`);t={...t,requiredFeatures:i};try{r=await n.requestDevice(t)}catch(t){throw console.error("Unable to initialize WebGPU with the requested features."),t}return(t=r).adapterInfo||(t.adapterInfo=n.info),r}static async X(t){if(!(t=await navigator.gpu.requestAdapter(t)))throw Error("Unable to request adapter from navigator.gpu; Ensure WebGPU is enabled.");return t}ga(t){if(e)"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement&&(e.id="canvas_webgpu");else var e=new OffscreenCanvas(1,1);e.getContext("webgpu").configure({device:t,format:navigator.gpu.getPreferredCanvasFormat()}),this.h.preinitializedWebGPUDevice=t}aa(){return this.h.ccall("closeGraph","void",[],[],{async:!0})}};return e}(function(t){return class extends t{addStreamingReaderToInputSidePacket(t,e){this.h.addStreamingReaderToInputSidePacket(((e,n,r)=>Or(t,this.h,e,n,r)),e)}}}(function(t){return class extends t{Y(t,e){hr(this,"lora_model_ref_in",(n=>{this.h._addRawDataSpanToInputStream(t.offset,t.size,n,e)}))}}}(class extends mr{}))));class Kr extends qr{}var Yr=class{constructor(t){this.j=t,this.i=Jr,Jr++}},Jr=1;class Xr{constructor(){let t,e;this.promise=new Promise(((n,r)=>{t=n,e=r})),this.resolve=t,this.reject=e}}function Qr(t){return 1===t?1:t+t%2}async function Zr(){const t=await Kr.X({powerPreference:"high-performance"});var e=t.limits.maxBufferSize;const n=t.limits.maxStorageBufferBindingSize;return e<524550144&&console.warn(`This WebGPU device is unable to execute most LLM tasks, because the required maxBufferSize is usually at least 524550144, but your device only supports maxBufferSize of ${e}`),n<524550144&&console.warn(`The WebGPU device is unable to execute LLM tasks, because the required maxStorageBufferBindingSize is usually at least 524550144, but your device only supports maxStorageBufferBindingSize of ${n}`),e={requiredFeatures:["shader-f16"],requiredLimits:{maxStorageBufferBindingSize:n,maxBufferSize:e,maxStorageBuffersPerShaderStage:t.limits.maxStorageBuffersPerShaderStage}},t.features.has("subgroups")&&(console.warn("Experimental Chromium WGSL subgroup support detected. Enabling this feature in the inference engine."),e.requiredFeatures=["shader-f16","subgroups"]),Kr.la(e,t)}function ti(t){if(t.D.length>0){const e=[...t.D];if(t.D.length=0,!t.o)throw e;t.o.reject(e),t.o=void 0}}function ei(t){const e=function(t){const e=new Zn;me(e,10,"text_in"),me(e,10,"token_cost_in"),me(e,10,"lora_model_id_to_apply_in"),me(e,10,"lora_model_ref_in"),me(e,10,"lora_model_id_to_load_in"),me(e,16,"streaming_reader"),me(e,15,"text_out"),me(e,15,"text_end"),me(e,15,"token_cost_out");var n=new Kn;pe(n,2,"TokenizerInputBuildCalculator"),me(n,3,"PROMPT:text_in"),me(n,3,"LORA_ID:lora_model_id_to_apply_in"),me(n,4,"prompt"),Qn(e,n),pe(n=new Kn,2,"ModelDataCalculator"),me(n,6,"MODEL_DATA:__side_packet_1"),me(n,6,"MODEL_TYPE:model_type"),me(n,5,"READ_DATA_FN:streaming_reader"),me(n,3,"LORA_MODEL_SPAN:lora_model_ref_in"),me(n,3,"LORA_MODEL_ID:lora_model_id_to_load_in"),me(n,4,"LORA_DATA:lora_model_data"),Qn(e,n),pe(n=new Kn,2,"Gpt2UnicodeMappingCalculator"),me(n,5,"MODEL_TYPE:model_type"),me(n,6,"BYTES_TO_UNICODE_MAPPING:tokenizer_mapping"),Qn(e,n),pe(n=new Cn,1,"type.googleapis.com/odml.infra.proto.TokenizerCalculatorOptions");var r=new Hr,i=he(t.i,2);fe(r,1,i),pe(i=new Wr,2,"spm_vocab_model"),i=ae(i);t:{Wt(r);var o=r.m,s=0|o[M];if(null==i){var a=ie(o);if(4!==oe(a,o,s))break t;a.set($r,0)}else{const t=ie(a=o),e=oe(t,a,s);4!==e&&(e&&(s=Jt(a,s,e)),t.set($r,4))}Jt(o,s,4,i)}return i&&!$(i)&&Ht(r.m),fe(r,3,2),Dn(n,r.j()),pe(r=new Kn,2,"TokenizerCalculator"),le(r,8,Cn,n),me(r,5,"MODEL_DATA:__side_packet_1"),me(r,3,"PROMPT_AND_INPUT_OPTIONS:prompt"),me(r,5,"BYTES_TO_UNICODE_MAPPING:tokenizer_mapping"),me(r,6,"PROCESSOR_GETTER:__input_side_1"),me(r,4,"IDS_AND_INPUT_OPTIONS:__stream_0"),Qn(e,r),pe(n=new Cn,1,"type.googleapis.com/odml.infra.proto.LlmGpuCalculatorOptions"),fe(r=new Mr,12,3),pe(r,1,"llm.tflite"),fe(r,14,0),i=Qr(he(t.i,5)),fe(r,22,i),i=se(t.i,Sr,3),ue(r,31,i),re(i=new Rr,1,At(!0),!1),null!=It(qt(t.i,6))&&(It(qt(t.i,6))??!1)&&re(i,1,At(!1),!1),re(i,2,At(!0),!1),re(i,5,At(!0),!1),ue(r,10,i),i=Xt(t.i,4,jt,void 0===K?2:4),ne(r,29,i),i=new Cr,fe(o=new Dr,1,1),a=he(t.i,2),fe(o,2,a),ue(i,1,o),ue(r,20,i),Dn(n,r.j()),pe(r=new Kn,2,"LlmGpuCalculator"),le(r,8,Cn,n),me(r,3,"IDS_AND_INPUT_OPTIONS:__stream_0"),me(r,3,"FINISH:finish"),me(r,3,"LORA_DATA:lora_model_data"),me(r,5,"MODEL_DATA:__side_packet_1"),me(r,4,"DECODED_IDS:__stream_3"),me(r,4,"OUTPUT_END:__stream_4"),pe(n=new $n,1,"FINISH"),re(n,2,At(!0),!1),le(r,13,$n,n),Qn(e,r),pe(n=new Kn,2,"IsPacketPresentCalculator"),me(n,3,"__stream_4"),me(n,4,"text_end"),Qn(e,n),pe(n=new Cn,1,"type.googleapis.com/odml.infra.proto.DetokenizerCalculatorOptions"),r=new Fr,t=Qr(he(t.i,5)),fe(r,5,t),me(r,4,""),me(r,4,"<|endoftext|>"),Dn(n,r.j()),pe(t=new Kn,2,"DetokenizerCalculator"),le(t,8,Cn,n),me(t,3,"IDS_AND_INPUT_OPTIONS:__stream_3"),me(t,5,"PROCESSOR_GETTER:__input_side_1"),me(t,5,"BYTES_TO_UNICODE_MAPPING:tokenizer_mapping"),me(t,5,"MODEL_DATA:__side_packet_1"),me(t,4,"FINISH_AND_INPUT_OPTIONS:finish"),me(t,4,"WORDS:text_out"),Qn(e,t),pe(t=new Kn,2,"TokenCostCalculator"),me(t,3,"PROMPT:token_cost_in"),me(t,5,"PROCESSOR_GETTER:__input_side_1"),me(t,5,"BYTES_TO_UNICODE_MAPPING:tokenizer_mapping"),me(t,4,"NUM_TOKENS:token_cost_out"),Qn(e,t),e}(t);t.j.attachStringVectorListener("text_out",((e,n)=>{e=function(t,e){return null==t||0===t.length?[]:t.map((t=>(t=(t=t.replaceAll("▁"," ")).replaceAll("<0x0A>","\n"),e&&(t=t.trimStart()),t.split("\\[eod\\]",1)[0])))}(e,0===t.G.length),e.forEach(((e,n)=>{nhe(t.i,5)&&e.pop(),t.A(e,!1)):t.A(e[0],!1)),vr(t,n)})),t.j.attachEmptyPacketListener("text_out",(e=>{vr(t,e)})),t.j.attachBoolListener("text_end",((e,n)=>{vr(t,n);try{ti(t)}catch(e){throw t.l=!1,e}if(t.o&&(t.o.resolve(t.G.map((t=>t.join("")))),t.o=void 0),t.A)if(t.B){for(e=[],n=0;n{t.l=!1,t.B=void 0,vr(t,e),ti(t),t.o&&(t.o.resolve(t.G.map((t=>t.join("")))),t.o=void 0)})),t.j.attachIntListener("token_cost_out",((e,n)=>{t.T=e,vr(t,n)})),t.U&&t.j.addStreamingReaderToInputSidePacket(t.U,"streaming_reader");const n=e.j();return t.C?.removeEventListener("uncapturederror",t.K),t.j.aa().then((()=>{t.C?.addEventListener("uncapturederror",t.K),t.D.length=0,t.setGraph(new Uint8Array(n),!0),t.finishProcessing()}))}function ni(t,e,n,r){if(t.A="function"==typeof n?n:r,(r=(e=Array.isArray(e)?e:[e]).filter((t=>kr(t))).length)>0&&(null==kt(qt(t.i,7))||he(t.i,7)Ur(t))).length)>0&&(null==It(qt(t.i,8))||!It(qt(t.i,8))))throw Error(`supportAudio was not enabled, but the query included ${r} audio chunks.`);if(t.v){if(t.B&&he(t.i,5)>1)throw Error("Multi-response generation is not supported for converted LLM models (.task format) yet, nor is it supported for multimodality. Please use the .bin format without multimodality or request only one response.");if(n instanceof Yr)throw Error("LoRA is not supported for converted LLM models (.task format) yet, nor is it supported for multimodality. Please use the .bin format without multimodality to use LoRA.");return t.j.h.LLM_CANCEL_FLAG=void 0,t.j.R(e,t.u,((e,n)=>{0===t.D.length&&t.A&&(t.B?t.A([e],n):t.A(e,n))})).then((e=>(ti(t),[e])))}if(t.l)throw Error("Previous invocation or loading is still ongoing.");for(t.l=!0,t.j.h.LLM_CANCEL_FLAG=void 0,t.G.length=0,r=0;r{if((t=t.error).message.match(/exceeds the max buffer size limit/))throw Error(`Failed to run this LLM model because it requires a buffer size that exceeds the maximum size your device supports, but you could try a smaller LLM model or different device.\nWebGPU throws: "${t.message}"`);if(t.message.match(/is larger than the maximum storage buffer binding size/))throw Error(`Failed to run this LLM model because it requires a storage buffer binding size that exceeds the maximum size your device supports, but you could try a smaller LLM model or different device.\nWebGPU throws: "${t.message}"`);this.D.push(t)},this.i=new Ar,Er(this.i,new tr),this.u=new Sr,ue(this.i,3,this.u),de(this.i,2,512),t=this.u,!vt(2))throw P("enum");re(t,1,2,0),fe(this.u,2,40),re(this.u,3,St(1),0),Yt(this.u,5,Ot(0)),re(this.u,4,St(.8),0),de(this.i,5,1)}async N(t){if(this.l)throw Error("Cannot set options while loading or processing.");if(t.baseOptions?.modelAssetPath&&t.baseOptions?.modelAssetBuffer)throw Error("Cannot set both baseOptions.modelAssetPath and baseOptions.modelAssetBuffer");let e;const n=new Promise((t=>{e=t}));if(t.baseOptions?.modelAssetPath){var r=await fetch(t.baseOptions.modelAssetPath.toString());if(!r.ok)throw Error(`Failed to fetch model: ${t.baseOptions.modelAssetPath} (${r.status})`);if(!r.body)throw Error(`Failed to fetch model: ${t.baseOptions.modelAssetPath} (no body)`);r=r.body.getReader()}else t.baseOptions?.modelAssetBuffer instanceof Uint8Array?r=function(t){return new ReadableStream({start(){},async pull(e){e.enqueue(t),e.close()}})}(t.baseOptions.modelAssetBuffer).getReader():t.baseOptions?.modelAssetBuffer instanceof ReadableStreamDefaultReader?(r=t.baseOptions.modelAssetBuffer,t.baseOptions.modelAssetBuffer=void 0):e();if(!r)throw Error("No model asset provided.");{const[n,s]=sr(r);this.O=1===await async function(t){const e=[];let n;for(const[i,o]of ur){const s=i;var r=o;[t,n]=sr(t),r=await r(n),await n.cancel(),r&&e.push(s)}if(await t.cancel(),0===e.length)throw Error("No model format matched.");if(1===e.length)return e[0];throw Error(`Multiple model formats matched: ${e}`)}(s);var i="maxNumImages"in t&&t.maxNumImages?t.maxNumImages:0;de(this.i,7,i);var o="supportAudio"in t&&!!t.supportAudio;Yt(this.i,8,At(o)),this.O||i>0||o?(this.v=!0,r=n):(this.v=!1,this.U=Pr(n,e))}if(t.baseOptions?.gpuOptions?.device&&(this.C&&this.C.removeEventListener("uncapturederror",this.K),this.C=t.baseOptions.gpuOptions.device,this.j.ga(this.C),this.C.addEventListener("uncapturederror",this.K)),"maxTokens"in t&&de(this.i,2,t.maxTokens??512),"topK"in t&&fe(this.u,2,t.topK??40),"temperature"in t&&re(this.u,4,St(t.temperature??.8),0),"randomSeed"in t&&Yt(this.u,5,Ot(t.randomSeed??0)),"loraRanks"in t&&function(t,e){ne(t,4,e)}(this.i,t.loraRanks??[]),"numResponses"in t){if((i=t.numResponses??1)<1)throw Error("'numResponses' must be at least 1.");if(this.v&&i>1)throw Error("'numResponses > 1' is not supported for converted LLM models yet, and is also not supported with multimodality.");de(this.i,5,i),o=se(this.i,Sr,3),i>1&&o&&(o.j()<=1||(qt(o,4,Et)??0)<=0)&&console.warn("To generate multiple responses, it is expected topK > 1 and temperature > 0; otherwise, all the generated responses may be the same.")}return"forceF32"in t&&void 0!==t.forceF32&&Yt(this.i,6,At(t.forceF32)),this.v?(this.j.V(),this.O?this.j.ba(r,this.i).then((()=>{ti(this)})):this.j.createLlmInferenceEngine(r,this.i).then((()=>{ti(this)}))):(this.l=!0,t=ei(this).then((()=>{})),Promise.all([n,t]).then((()=>{this.l=!1,ti(this)})))}get baseOptions(){return se(this.i,tr,1)}set baseOptions(t){Er(this.i,t)}get isIdle(){return!this.l&&!this.o}R(t,e,n){return he(this.i,5)>1&&console.warn("'numResponses' is set larger than 1 and this function only returns the first response, so we recommend either using 'generateResponses()' to obtain multiple responses, or else setting 'numResponses' to 1 for better performance."),this.B=!1,ni(this,t,e,n).then((t=>t[0]))}da(t,e,n){return this.B=!0,ni(this,t,e,n)}S(t){if(t=Array.isArray(t)?t:[t],this.v)return this.j.S(t);if(this.l)throw Error("Previous invocation or loading is still ongoing.");if(t.some(kr))throw Error("sizeInTokens requires maxNumImages > 0 for images.");if(t.some(Ur))throw Error("sizeInTokens requires supportAudio for audio.");return t=t.join(""),this.l=!0,this.T=void 0,this.j.addStringToStream(t,"token_cost_in",this.I+1),this.finishProcessing(),this.l=!1,this.T}Z(){const t=this.j.h;(this.v||this.l)&&(t.LLM_CANCEL_FLAG=1)}async ja(t){if(this.v)throw Error("LoRA is not supported for converted LLM models (.task format) yet, nor is it supported for multimodality. Please use the old format (.bin) without multimodality to use LoRA.");if(this.l)throw Error("Cannot load LoRA model while loading or processing.");if(this.l=!0,t instanceof Uint8Array){var e=new Nr(this.j.h,t.length);e.set(t),t=e}else t=t instanceof Blob?await async function(t,e){return xr(t,e.stream(),e.size)}(this.j.h,t):await async function(t,e){e=await fetch(e.toString());const n=Number(e.headers.get("content-length"));if(!e.body)throw Error("Response body is not available.");if(!n)throw Error("File size is 0.");return xr(t,e.body,n)}(this.j.h,t);e=new Yr(this);const n=this.I+1;return this.j.Y(t,n),this.j.addUintToStream(e.i,"lora_model_id_to_load_in",n),this.finishProcessing(),Br(t),vr(this,n),this.l=!1,e}close(){this.v&&this.j.V(),this.C?.removeEventListener("uncapturederror",this.K),super.close()}};ri.prototype.loadLoraModel=ri.prototype.ja,ri.prototype.cancelProcessing=ri.prototype.Z,ri.prototype.sizeInTokens=ri.prototype.S,ri.prototype.generateResponses=ri.prototype.da,ri.prototype.generateResponse=ri.prototype.R,ri.prototype.setOptions=ri.prototype.N,ri.createWebGpuDevice=Zr,ri.createFromModelPath=async function(t,e){return yr(t,e={baseOptions:{gpuOptions:{device:await Zr()},modelAssetPath:e}})},ri.createFromModelBuffer=async function(t,e){return yr(t,e={baseOptions:{gpuOptions:{device:await Zr()},modelAssetBuffer:e}})},ri.createFromOptions=async function(t,e){if(!e.baseOptions?.gpuOptions?.device){const t=await Zr();e.baseOptions=e.baseOptions??{},e.baseOptions.gpuOptions=e?.baseOptions?.gpuOptions??{},e.baseOptions.gpuOptions.device=t}return yr(t,e)};export{or as FilesetResolver,ri as LlmInference,br as TaskRunner}; +//# sourceMappingURL=genai_bundle_mjs.js.map diff --git a/public/mediapipe/wasm/genai_wasm_internal.js b/public/mediapipe/wasm/genai_wasm_internal.js new file mode 100644 index 0000000..c43175d --- /dev/null +++ b/public/mediapipe/wasm/genai_wasm_internal.js @@ -0,0 +1,9035 @@ +// This code implements the `-sMODULARIZE` settings by taking the generated +// JS program code (INNER_JS_CODE) and wrapping it in a factory function. + +// Single threaded MINIMAL_RUNTIME programs do not need access to +// document.currentScript, so a simple export declaration is enough. +var ModuleFactory = (() => { + // When MODULARIZE this JS may be executed later, + // after document.currentScript is gone, so we save it. + // In EXPORT_ES6 mode we can just use 'import.meta.url'. + var _scriptName = globalThis.document?.currentScript?.src; + return async function(moduleArg = {}) { + var moduleRtn; + +// include: shell.js +// include: minimum_runtime_check.js +// end include: minimum_runtime_check.js +// The Module object: Our interface to the outside world. We import +// and export values on it. There are various ways Module can be used: +// 1. Not defined. We create it here +// 2. A function parameter, function(moduleArg) => Promise +// 3. pre-run appended it, var Module = {}; ..generated code.. +// 4. External script tag defines var Module. +// We need to check if Module already exists (e.g. case 3 above). +// Substitution will be replaced with actual code on later stage of the build, +// this way Closure Compiler will not mangle it (e.g. case 4. above). +// Note that if you want to run closure, and also to use Module +// after the generated code, you will need to define var Module = {}; +// before the code. Then that object will be used in the code, and you +// can continue to use Module afterwards as well. +var Module = moduleArg; + +// Determine the runtime environment we are in. You can customize this by +// setting the ENVIRONMENT setting at compile time (see settings.js). +// Attempt to auto-detect the environment +var ENVIRONMENT_IS_WEB = !!globalThis.window; + +var ENVIRONMENT_IS_WORKER = !!globalThis.WorkerGlobalScope; + +// N.b. Electron.js environment is simultaneously a NODE-environment, but +// also a web environment. +var ENVIRONMENT_IS_NODE = globalThis.process?.versions?.node && globalThis.process?.type != "renderer"; + +// --pre-jses are emitted after the Module integration code, so that they can +// refer to Module (if they choose; they can also define Module) +var arguments_ = []; + +var thisProgram = "./this.program"; + +var quit_ = (status, toThrow) => { + throw toThrow; +}; + +if (typeof __filename != "undefined") { + // Node + _scriptName = __filename; +} else if (ENVIRONMENT_IS_WORKER) { + _scriptName = self.location.href; +} + +// `/` should be present at the end if `scriptDirectory` is not empty +var scriptDirectory = ""; + +function locateFile(path) { + if (Module["locateFile"]) { + return Module["locateFile"](path, scriptDirectory); + } + return scriptDirectory + path; +} + +// Hooks that are implemented differently in different runtime environments. +var readAsync, readBinary; + +if (ENVIRONMENT_IS_NODE) { + // These modules will usually be used on Node.js. Load them eagerly to avoid + // the complexity of lazy-loading. + var fs = require("node:fs"); + scriptDirectory = __dirname + "/"; + // include: node_shell_read.js + readBinary = filename => { + // We need to re-wrap `file://` strings to URLs. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename); + return ret; + }; + readAsync = async (filename, binary = true) => { + // See the comment in the `readBinary` function. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename, binary ? undefined : "utf8"); + return ret; + }; + // end include: node_shell_read.js + if (process.argv.length > 1) { + thisProgram = process.argv[1].replace(/\\/g, "/"); + } + arguments_ = process.argv.slice(2); + quit_ = (status, toThrow) => { + process.exitCode = status; + throw toThrow; + }; +} else // Note that this includes Node.js workers when relevant (pthreads is enabled). +// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and +// ENVIRONMENT_IS_NODE. +if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + try { + scriptDirectory = new URL(".", _scriptName).href; + } catch {} + { + // include: web_or_worker_shell_read.js + if (ENVIRONMENT_IS_WORKER) { + readBinary = url => { + var xhr = new XMLHttpRequest; + xhr.open("GET", url, false); + xhr.responseType = "arraybuffer"; + xhr.send(null); + return new Uint8Array(/** @type{!ArrayBuffer} */ (xhr.response)); + }; + } + readAsync = async url => { + // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. + // See https://github.com/github/fetch/pull/92#issuecomment-140665932 + // Cordova or Electron apps are typically loaded from a file:// url. + // So use XHR on webview if URL is a file URL. + if (isFileURI(url)) { + return new Promise((resolve, reject) => { + var xhr = new XMLHttpRequest; + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + xhr.onload = () => { + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { + // file URLs can return 0 + resolve(xhr.response); + return; + } + reject(xhr.status); + }; + xhr.onerror = reject; + xhr.send(null); + }); + } + var response = await fetch(url, { + credentials: "same-origin" + }); + if (response.ok) { + return response.arrayBuffer(); + } + throw new Error(response.status + " : " + response.url); + }; + } +} else {} + +var out = console.log.bind(console); + +var err = console.error.bind(console); + +// end include: shell.js +// include: preamble.js +// === Preamble library stuff === +// Documentation for the public APIs defined in this file must be updated in: +// site/source/docs/api_reference/preamble.js.rst +// A prebuilt local version of the documentation is available at: +// site/build/text/docs/api_reference/preamble.js.txt +// You can also build docs locally as HTML or other formats in site/ +// An online HTML version (which may be of a different version of Emscripten) +// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html +var wasmBinary; + +// Wasm globals +//======================================== +// Runtime essentials +//======================================== +// whether we are quitting the application. no code should run after this. +// set in exit() and abort() +var ABORT = false; + +// set by exit() and abort(). Passed to 'onExit' handler. +// NOTE: This is also used as the process return code in shell environments +// but only when noExitRuntime is false. +var EXITSTATUS; + +// In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we +// don't define it at all in release modes. This matches the behaviour of +// MINIMAL_RUNTIME. +// TODO(sbc): Make this the default even without STRICT enabled. +/** @type {function(*, string=)} */ function assert(condition, text) { + if (!condition) { + // This build was created without ASSERTIONS defined. `assert()` should not + // ever be called in this configuration but in case there are callers in + // the wild leave this simple abort() implementation here for now. + abort(text); + } +} + +/** + * Indicates whether filename is delivered via file protocol (as opposed to http/https) + * @noinline + */ var isFileURI = filename => filename.startsWith("file://"); + +// include: runtime_common.js +// include: runtime_stack_check.js +// end include: runtime_stack_check.js +// include: runtime_exceptions.js +// end include: runtime_exceptions.js +// include: runtime_debug.js +// end include: runtime_debug.js +var readyPromiseResolve, readyPromiseReject; + +// Memory management +var /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Int16Array} */ HEAP16, /** @type {!Uint16Array} */ HEAPU16, /** @type {!Int32Array} */ HEAP32, /** @type {!Uint32Array} */ HEAPU32, /** @type {!Float32Array} */ HEAPF32, /** @type {!Float64Array} */ HEAPF64; + +var runtimeInitialized = false; + +function updateMemoryViews() { + var b = wasmMemory.buffer; + HEAP8 = new Int8Array(b); + HEAP16 = new Int16Array(b); + Module["HEAPU8"] = HEAPU8 = new Uint8Array(b); + HEAPU16 = new Uint16Array(b); + HEAP32 = new Int32Array(b); + Module["HEAPU32"] = HEAPU32 = new Uint32Array(b); + Module["HEAPF32"] = HEAPF32 = new Float32Array(b); + Module["HEAPF64"] = HEAPF64 = new Float64Array(b); +} + +// include: memoryprofiler.js +// end include: memoryprofiler.js +// end include: runtime_common.js +function preRun() { + if (Module["preRun"]) { + if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ]; + while (Module["preRun"].length) { + addOnPreRun(Module["preRun"].shift()); + } + } + // Begin ATPRERUNS hooks + callRuntimeCallbacks(onPreRuns); +} + +function initRuntime() { + runtimeInitialized = true; + // Begin ATINITS hooks + if (!Module["noFSInit"] && !FS.initialized) FS.init(); + TTY.init(); + // End ATINITS hooks + wasmExports["tc"](); + // Begin ATPOSTCTORS hooks + FS.ignorePermissions = false; +} + +function postRun() { + // PThreads reuse the runtime from the main thread. + if (Module["postRun"]) { + if (typeof Module["postRun"] == "function") Module["postRun"] = [ Module["postRun"] ]; + while (Module["postRun"].length) { + addOnPostRun(Module["postRun"].shift()); + } + } + // Begin ATPOSTRUNS hooks + callRuntimeCallbacks(onPostRuns); +} + +/** @param {string|number=} what */ function abort(what) { + Module["onAbort"]?.(what); + what = "Aborted(" + what + ")"; + // TODO(sbc): Should we remove printing and leave it up to whoever + // catches the exception? + err(what); + ABORT = true; + what += ". Build with -sASSERTIONS for more info."; + // Use a wasm runtime error, because a JS error might be seen as a foreign + // exception, which means we'd run destructors on it. We need the error to + // simply make the program stop. + // FIXME This approach does not work in Wasm EH because it currently does not assume + // all RuntimeErrors are from traps; it decides whether a RuntimeError is from + // a trap or not based on a hidden field within the object. So at the moment + // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that + // allows this in the wasm spec. + // Suppress closure compiler warning here. Closure compiler's builtin extern + // definition for WebAssembly.RuntimeError claims it takes no arguments even + // though it can. + // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. + /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); + readyPromiseReject?.(e); + // Throw the error whether or not MODULARIZE is set because abort is used + // in code paths apart from instantiation where an exception is expected + // to be thrown when abort is called. + throw e; +} + +var wasmBinaryFile; + +function findWasmBinary() { + return locateFile("genai_wasm_internal.wasm"); +} + +function getBinarySync(file) { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + // Throwing a plain string here, even though it not normally advisable since + // this gets turning into an `abort` in instantiateArrayBuffer. + throw "both async and sync fetching of the wasm failed"; +} + +async function getWasmBinary(binaryFile) { + // If we don't have the binary yet, load it asynchronously using readAsync. + if (!wasmBinary) { + // Fetch the binary using readAsync + try { + var response = await readAsync(binaryFile); + return new Uint8Array(response); + } catch {} + } + // Otherwise, getBinarySync should be able to get it synchronously + return getBinarySync(binaryFile); +} + +async function instantiateArrayBuffer(binaryFile, imports) { + try { + var binary = await getWasmBinary(binaryFile); + var instance = await WebAssembly.instantiate(binary, imports); + return instance; + } catch (reason) { + err(`failed to asynchronously prepare wasm: ${reason}`); + abort(reason); + } +} + +async function instantiateAsync(binary, binaryFile, imports) { + if (!binary && !isFileURI(binaryFile) && !ENVIRONMENT_IS_NODE) { + try { + var response = fetch(binaryFile, { + credentials: "same-origin" + }); + var instantiationResult = await WebAssembly.instantiateStreaming(response, imports); + return instantiationResult; + } catch (reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err(`wasm streaming compile failed: ${reason}`); + err("falling back to ArrayBuffer instantiation"); + } + } + return instantiateArrayBuffer(binaryFile, imports); +} + +function getWasmImports() { + // prepare imports + var imports = { + "a": wasmImports + }; + return imports; +} + +// Create the wasm instance. +// Receives the wasm imports, returns the exports. +async function createWasm() { + // Load the wasm module and create an instance of using native support in the JS engine. + // handle a generated wasm instance, receiving its exports and + // performing other necessary setup + /** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) { + wasmExports = instance.exports; + wasmExports = Asyncify.instrumentWasmExports(wasmExports); + wasmExports = applySignatureConversions(wasmExports); + assignWasmExports(wasmExports); + updateMemoryViews(); + return wasmExports; + } + // Prefer streaming instantiation if available. + function receiveInstantiationResult(result) { + // 'result' is a ResultObject object which has both the module and instance. + // receiveInstance() will swap in the exports (to Module.asm) so they can be called + // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. + // When the regression is fixed, can restore the above PTHREADS-enabled path. + return receiveInstance(result["instance"]); + } + var info = getWasmImports(); + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback + // to manually instantiate the Wasm module themselves. This allows pages to + // run the instantiation parallel to any other async startup actions they are + // performing. + // Also pthreads and wasm workers initialize the wasm instance through this + // path. + if (Module["instantiateWasm"]) { + return new Promise((resolve, reject) => { + Module["instantiateWasm"](info, (inst, mod) => { + resolve(receiveInstance(inst, mod)); + }); + }); + } + wasmBinaryFile ??= findWasmBinary(); + var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); + var exports = receiveInstantiationResult(result); + return exports; +} + +// Globals used by JS i64 conversions (see makeSetValue) +var tempDouble; + +var tempI64; + +// end include: preamble.js +// Begin JS library code +var handleException = e => { + // Certain exception types we do not treat as errors since they are used for + // internal control flow. + // 1. ExitStatus, which is thrown by exit() + // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others + // that wish to return to JS event loop. + if (e instanceof ExitStatus || e == "unwind") { + return EXITSTATUS; + } + quit_(1, e); +}; + +class ExitStatus { + name="ExitStatus"; + constructor(status) { + this.message = `Program terminated with exit(${status})`; + this.status = status; + } +} + +var runtimeKeepaliveCounter = 0; + +var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; + +var _proc_exit = code => { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + Module["onExit"]?.(code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); +}; + +/** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => { + EXITSTATUS = status; + _proc_exit(status); +}; + +var _exit = exitJS; + +var maybeExit = () => { + if (!keepRuntimeAlive()) { + try { + _exit(EXITSTATUS); + } catch (e) { + handleException(e); + } + } +}; + +var callUserCallback = func => { + if (ABORT) { + return; + } + try { + return func(); + } catch (e) { + handleException(e); + } finally { + maybeExit(); + } +}; + +function getFullscreenElement() { + return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.webkitCurrentFullScreenElement || document.msFullscreenElement; +} + +/** @param {number=} timeout */ var safeSetTimeout = (func, timeout) => setTimeout(() => { + callUserCallback(func); +}, timeout); + +var warnOnce = text => { + warnOnce.shown ||= {}; + if (!warnOnce.shown[text]) { + warnOnce.shown[text] = 1; + if (ENVIRONMENT_IS_NODE) text = "warning: " + text; + err(text); + } +}; + +var preloadPlugins = []; + +var Browser = { + useWebGL: false, + isFullscreen: false, + pointerLock: false, + moduleContextCreatedCallbacks: [], + workers: [], + preloadedImages: {}, + preloadedAudios: {}, + getCanvas: () => Module["canvas"], + init() { + if (Browser.initted) return; + Browser.initted = true; + // Support for plugins that can process preloaded files. You can add more of these to + // your app by creating and appending to preloadPlugins. + // Each plugin is asked if it can handle a file based on the file's name. If it can, + // it is given the file's raw data. When it is done, it calls a callback with the file's + // (possibly modified) data. For example, a plugin might decompress a file, or it + // might create some side data structure for use later (like an Image element, etc.). + var imagePlugin = {}; + imagePlugin["canHandle"] = name => !Module["noImageDecoding"] && /\.(jpg|jpeg|png|bmp|webp)$/i.test(name); + imagePlugin["handle"] = async (byteArray, name) => { + var b = new Blob([ byteArray ], { + type: Browser.getMimetype(name) + }); + if (b.size !== byteArray.length) { + // Safari bug #118630 + // Safari's Blob can only take an ArrayBuffer + b = new Blob([ (new Uint8Array(byteArray)).buffer ], { + type: Browser.getMimetype(name) + }); + } + var url = URL.createObjectURL(b); + return new Promise((resolve, reject) => { + var img = new Image; + img.onload = () => { + var canvas = /** @type {!HTMLCanvasElement} */ (document.createElement("canvas")); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); + Browser.preloadedImages[name] = canvas; + URL.revokeObjectURL(url); + resolve(byteArray); + }; + img.onerror = event => { + err(`Image ${url} could not be decoded`); + reject(); + }; + img.src = url; + }); + }; + preloadPlugins.push(imagePlugin); + var audioPlugin = {}; + audioPlugin["canHandle"] = name => !Module["noAudioDecoding"] && name.slice(-4) in { + ".ogg": 1, + ".wav": 1, + ".mp3": 1 + }; + audioPlugin["handle"] = async (byteArray, name) => new Promise((resolve, reject) => { + var done = false; + function finish(audio) { + if (done) return; + done = true; + Browser.preloadedAudios[name] = audio; + resolve(byteArray); + } + var b = new Blob([ byteArray ], { + type: Browser.getMimetype(name) + }); + var url = URL.createObjectURL(b); + // XXX we never revoke this! + var audio = new Audio; + audio.addEventListener("canplaythrough", () => finish(audio), false); + // use addEventListener due to chromium bug 124926 + audio.onerror = event => { + if (done) return; + err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`); + function encode64(data) { + var BASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var PAD = "="; + var ret = ""; + var leftchar = 0; + var leftbits = 0; + for (var i = 0; i < data.length; i++) { + leftchar = (leftchar << 8) | data[i]; + leftbits += 8; + while (leftbits >= 6) { + var curr = (leftchar >> (leftbits - 6)) & 63; + leftbits -= 6; + ret += BASE[curr]; + } + } + if (leftbits == 2) { + ret += BASE[(leftchar & 3) << 4]; + ret += PAD + PAD; + } else if (leftbits == 4) { + ret += BASE[(leftchar & 15) << 2]; + ret += PAD; + } + return ret; + } + audio.src = "data:audio/x-" + name.slice(-3) + ";base64," + encode64(byteArray); + finish(audio); + }; + audio.src = url; + // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror + safeSetTimeout(() => { + finish(audio); + }, 1e4); + }); + preloadPlugins.push(audioPlugin); + // Canvas event setup + function pointerLockChange() { + var canvas = Browser.getCanvas(); + Browser.pointerLock = document.pointerLockElement === canvas; + } + var canvas = Browser.getCanvas(); + if (canvas) { + // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module + // Module['forcedAspectRatio'] = 4 / 3; + document.addEventListener("pointerlockchange", pointerLockChange, false); + if (Module["elementPointerLock"]) { + canvas.addEventListener("click", ev => { + if (!Browser.pointerLock && Browser.getCanvas().requestPointerLock) { + Browser.getCanvas().requestPointerLock(); + ev.preventDefault(); + } + }, false); + } + } + }, + createContext(/** @type {HTMLCanvasElement} */ canvas, useWebGL, setInModule, webGLContextAttributes) { + if (useWebGL && Module["ctx"] && canvas == Browser.getCanvas()) return Module["ctx"]; + // no need to recreate GL context if it's already been created for this canvas. + var ctx; + var contextHandle; + if (useWebGL) { + // For GLES2/desktop GL compatibility, adjust a few defaults to be different to WebGL defaults, so that they align better with the desktop defaults. + var contextAttributes = { + antialias: false, + alpha: false, + majorVersion: (typeof WebGL2RenderingContext != "undefined") ? 2 : 1 + }; + if (webGLContextAttributes) { + for (var attribute in webGLContextAttributes) { + contextAttributes[attribute] = webGLContextAttributes[attribute]; + } + } + // This check of existence of GL is here to satisfy Closure compiler, which yells if variable GL is referenced below but GL object is not + // actually compiled in because application is not doing any GL operations. TODO: Ideally if GL is not being used, this function + // Browser.createContext() should not even be emitted. + if (typeof GL != "undefined") { + contextHandle = GL.createContext(canvas, contextAttributes); + if (contextHandle) { + ctx = GL.getContext(contextHandle).GLctx; + } + } + } else { + ctx = canvas.getContext("2d"); + } + if (!ctx) return null; + if (setInModule) { + Module["ctx"] = ctx; + if (useWebGL) GL.makeContextCurrent(contextHandle); + Browser.useWebGL = useWebGL; + Browser.moduleContextCreatedCallbacks.forEach(callback => callback()); + Browser.init(); + } + return ctx; + }, + fullscreenHandlersInstalled: false, + lockPointer: undefined, + resizeCanvas: undefined, + requestFullscreen(lockPointer, resizeCanvas) { + Browser.lockPointer = lockPointer; + Browser.resizeCanvas = resizeCanvas; + if (typeof Browser.lockPointer == "undefined") Browser.lockPointer = true; + if (typeof Browser.resizeCanvas == "undefined") Browser.resizeCanvas = false; + var canvas = Browser.getCanvas(); + function fullscreenChange() { + Browser.isFullscreen = false; + var canvasContainer = canvas.parentNode; + if (getFullscreenElement() === canvasContainer) { + canvas.exitFullscreen = Browser.exitFullscreen; + if (Browser.lockPointer) canvas.requestPointerLock(); + Browser.isFullscreen = true; + if (Browser.resizeCanvas) { + Browser.setFullscreenCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } else { + // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen + canvasContainer.parentNode.insertBefore(canvas, canvasContainer); + canvasContainer.parentNode.removeChild(canvasContainer); + if (Browser.resizeCanvas) { + Browser.setWindowedCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } + Module["onFullScreen"]?.(Browser.isFullscreen); + Module["onFullscreen"]?.(Browser.isFullscreen); + } + if (!Browser.fullscreenHandlersInstalled) { + Browser.fullscreenHandlersInstalled = true; + document.addEventListener("fullscreenchange", fullscreenChange, false); + document.addEventListener("mozfullscreenchange", fullscreenChange, false); + document.addEventListener("webkitfullscreenchange", fullscreenChange, false); + document.addEventListener("MSFullscreenChange", fullscreenChange, false); + } + // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root + var canvasContainer = document.createElement("div"); + canvas.parentNode.insertBefore(canvasContainer, canvas); + canvasContainer.appendChild(canvas); + // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size) + canvasContainer.requestFullscreen = canvasContainer["requestFullscreen"] || canvasContainer["mozRequestFullScreen"] || canvasContainer["msRequestFullscreen"] || (canvasContainer["webkitRequestFullscreen"] ? () => canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]) : null) || (canvasContainer["webkitRequestFullScreen"] ? () => canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]) : null); + canvasContainer.requestFullscreen(); + }, + exitFullscreen() { + // This is workaround for chrome. Trying to exit from fullscreen + // not in fullscreen state will cause "TypeError: Document not active" + // in chrome. See https://github.com/emscripten-core/emscripten/pull/8236 + if (!Browser.isFullscreen) { + return false; + } + var CFS = document["exitFullscreen"] || document["cancelFullScreen"] || document["mozCancelFullScreen"] || document["msExitFullscreen"] || document["webkitCancelFullScreen"] || (() => {}); + CFS.apply(document, []); + return true; + }, + safeSetTimeout(func, timeout) { + // Legacy function, this is used by the SDL2 port so we need to keep it + // around at least until that is updated. + // See https://github.com/libsdl-org/SDL/pull/6304 + return safeSetTimeout(func, timeout); + }, + getMimetype(name) { + return { + "jpg": "image/jpeg", + "jpeg": "image/jpeg", + "png": "image/png", + "bmp": "image/bmp", + "ogg": "audio/ogg", + "wav": "audio/wav", + "mp3": "audio/mpeg" + }[name.slice(name.lastIndexOf(".") + 1)]; + }, + getUserMedia(func) { + window.getUserMedia ||= navigator["getUserMedia"] || navigator["mozGetUserMedia"]; + window.getUserMedia(func); + }, + getMovementX(event) { + return event["movementX"] || event["mozMovementX"] || event["webkitMovementX"] || 0; + }, + getMovementY(event) { + return event["movementY"] || event["mozMovementY"] || event["webkitMovementY"] || 0; + }, + getMouseWheelDelta(event) { + var delta = 0; + switch (event.type) { + case "DOMMouseScroll": + // 3 lines make up a step + delta = event.detail / 3; + break; + + case "mousewheel": + // 120 units make up a step + delta = event.wheelDelta / 120; + break; + + case "wheel": + delta = event.deltaY; + switch (event.deltaMode) { + case 0: + // DOM_DELTA_PIXEL: 100 pixels make up a step + delta /= 100; + break; + + case 1: + // DOM_DELTA_LINE: 3 lines make up a step + delta /= 3; + break; + + case 2: + // DOM_DELTA_PAGE: A page makes up 80 steps + delta *= 80; + break; + + default: + abort("unrecognized mouse wheel delta mode: " + event.deltaMode); + } + break; + + default: + abort("unrecognized mouse wheel event: " + event.type); + } + return delta; + }, + mouseX: 0, + mouseY: 0, + mouseMovementX: 0, + mouseMovementY: 0, + touches: {}, + lastTouches: {}, + calculateMouseCoords(pageX, pageY) { + // Calculate the movement based on the changes + // in the coordinates. + var canvas = Browser.getCanvas(); + var rect = canvas.getBoundingClientRect(); + // Neither .scrollX or .pageXOffset are defined in a spec, but + // we prefer .scrollX because it is currently in a spec draft. + // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/) + var scrollX = ((typeof window.scrollX != "undefined") ? window.scrollX : window.pageXOffset); + var scrollY = ((typeof window.scrollY != "undefined") ? window.scrollY : window.pageYOffset); + var adjustedX = pageX - (scrollX + rect.left); + var adjustedY = pageY - (scrollY + rect.top); + // the canvas might be CSS-scaled compared to its backbuffer; + // SDL-using content will want mouse coordinates in terms + // of backbuffer units. + adjustedX = adjustedX * (canvas.width / rect.width); + adjustedY = adjustedY * (canvas.height / rect.height); + return { + x: adjustedX, + y: adjustedY + }; + }, + setMouseCoords(pageX, pageY) { + const {x, y} = Browser.calculateMouseCoords(pageX, pageY); + Browser.mouseMovementX = x - Browser.mouseX; + Browser.mouseMovementY = y - Browser.mouseY; + Browser.mouseX = x; + Browser.mouseY = y; + }, + calculateMouseEvent(event) { + // event should be mousemove, mousedown or mouseup + if (Browser.pointerLock) { + // When the pointer is locked, calculate the coordinates + // based on the movement of the mouse. + // Workaround for Firefox bug 764498 + if (event.type != "mousemove" && ("mozMovementX" in event)) { + Browser.mouseMovementX = Browser.mouseMovementY = 0; + } else { + Browser.mouseMovementX = Browser.getMovementX(event); + Browser.mouseMovementY = Browser.getMovementY(event); + } + // add the mouse delta to the current absolute mouse position + Browser.mouseX += Browser.mouseMovementX; + Browser.mouseY += Browser.mouseMovementY; + } else { + if (event.type === "touchstart" || event.type === "touchend" || event.type === "touchmove") { + var touch = event.touch; + if (touch === undefined) { + return; + } + var coords = Browser.calculateMouseCoords(touch.pageX, touch.pageY); + if (event.type === "touchstart") { + Browser.lastTouches[touch.identifier] = coords; + Browser.touches[touch.identifier] = coords; + } else if (event.type === "touchend" || event.type === "touchmove") { + var last = Browser.touches[touch.identifier]; + last ||= coords; + Browser.lastTouches[touch.identifier] = last; + Browser.touches[touch.identifier] = coords; + } + return; + } + Browser.setMouseCoords(event.pageX, event.pageY); + } + }, + resizeListeners: [], + updateResizeListeners() { + var canvas = Browser.getCanvas(); + Browser.resizeListeners.forEach(listener => listener(canvas.width, canvas.height)); + }, + setCanvasSize(width, height, noUpdates) { + var canvas = Browser.getCanvas(); + Browser.updateCanvasDimensions(canvas, width, height); + if (!noUpdates) Browser.updateResizeListeners(); + }, + windowedWidth: 0, + windowedHeight: 0, + setFullscreenCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen) >>> 2) >>> 0]; + flags = flags | 8388608; + // set SDL_FULLSCREEN flag + HEAP32[((SDL.screen) >>> 2) >>> 0] = flags; + } + Browser.updateCanvasDimensions(Browser.getCanvas()); + Browser.updateResizeListeners(); + }, + setWindowedCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen) >>> 2) >>> 0]; + flags = flags & ~8388608; + // clear SDL_FULLSCREEN flag + HEAP32[((SDL.screen) >>> 2) >>> 0] = flags; + } + Browser.updateCanvasDimensions(Browser.getCanvas()); + Browser.updateResizeListeners(); + }, + updateCanvasDimensions(canvas, wNative, hNative) { + if (wNative && hNative) { + canvas.widthNative = wNative; + canvas.heightNative = hNative; + } else { + wNative = canvas.widthNative; + hNative = canvas.heightNative; + } + var w = wNative; + var h = hNative; + if (Module["forcedAspectRatio"] > 0) { + if (w / h < Module["forcedAspectRatio"]) { + w = Math.round(h * Module["forcedAspectRatio"]); + } else { + h = Math.round(w / Module["forcedAspectRatio"]); + } + } + if ((getFullscreenElement() === canvas.parentNode) && (typeof screen != "undefined")) { + var factor = Math.min(screen.width / w, screen.height / h); + w = Math.round(w * factor); + h = Math.round(h * factor); + } + if (Browser.resizeCanvas) { + if (canvas.width != w) canvas.width = w; + if (canvas.height != h) canvas.height = h; + if (typeof canvas.style != "undefined") { + canvas.style.removeProperty("width"); + canvas.style.removeProperty("height"); + } + } else { + if (canvas.width != wNative) canvas.width = wNative; + if (canvas.height != hNative) canvas.height = hNative; + if (typeof canvas.style != "undefined") { + if (w != wNative || h != hNative) { + canvas.style.setProperty("width", w + "px", "important"); + canvas.style.setProperty("height", h + "px", "important"); + } else { + canvas.style.removeProperty("width"); + canvas.style.removeProperty("height"); + } + } + } + } +}; + +var callRuntimeCallbacks = callbacks => { + while (callbacks.length > 0) { + // Pass the module as the first argument. + callbacks.shift()(Module); + } +}; + +var onPostRuns = []; + +var addOnPostRun = cb => onPostRuns.push(cb); + +var onPreRuns = []; + +var addOnPreRun = cb => onPreRuns.push(cb); + +var dynCalls = {}; + +var dynCallLegacy = (sig, ptr, args) => { + sig = sig.replace(/p/g, "i"); + var f = dynCalls[sig]; + return f(ptr, ...args); +}; + +var dynCall = (sig, ptr, args = [], promising = false) => { + var rtn = dynCallLegacy(sig, ptr, args); + function convert(rtn) { + return sig[0] == "p" ? rtn >>> 0 : rtn; + } + return convert(rtn); +}; + +var noExitRuntime = true; + +var stackRestore = val => __emscripten_stack_restore(val); + +var stackSave = () => _emscripten_stack_get_current(); + +class ExceptionInfo { + // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. + constructor(excPtr) { + this.excPtr = excPtr; + this.ptr = excPtr - 24; + } + set_type(type) { + HEAPU32[(((this.ptr) + (4)) >>> 2) >>> 0] = type; + } + get_type() { + return HEAPU32[(((this.ptr) + (4)) >>> 2) >>> 0]; + } + set_destructor(destructor) { + HEAPU32[(((this.ptr) + (8)) >>> 2) >>> 0] = destructor; + } + get_destructor() { + return HEAPU32[(((this.ptr) + (8)) >>> 2) >>> 0]; + } + set_caught(caught) { + caught = caught ? 1 : 0; + HEAP8[(this.ptr) + (12) >>> 0] = caught; + } + get_caught() { + return HEAP8[(this.ptr) + (12) >>> 0] != 0; + } + set_rethrown(rethrown) { + rethrown = rethrown ? 1 : 0; + HEAP8[(this.ptr) + (13) >>> 0] = rethrown; + } + get_rethrown() { + return HEAP8[(this.ptr) + (13) >>> 0] != 0; + } + // Initialize native structure fields. Should be called once after allocated. + init(type, destructor) { + this.set_adjusted_ptr(0); + this.set_type(type); + this.set_destructor(destructor); + } + set_adjusted_ptr(adjustedPtr) { + HEAPU32[(((this.ptr) + (16)) >>> 2) >>> 0] = adjustedPtr; + } + get_adjusted_ptr() { + return HEAPU32[(((this.ptr) + (16)) >>> 2) >>> 0]; + } +} + +var exceptionLast = 0; + +var uncaughtExceptionCount = 0; + +var convertI32PairToI53Checked = (lo, hi) => ((hi + 2097152) >>> 0 < 4194305 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; + +function ___cxa_throw(ptr, type, destructor) { + ptr >>>= 0; + type >>>= 0; + destructor >>>= 0; + var info = new ExceptionInfo(ptr); + // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception. + info.init(type, destructor); + exceptionLast = ptr; + uncaughtExceptionCount++; + throw exceptionLast; +} + +function __Unwind_RaiseException(ex) { + ex >>>= 0; + err("Warning: _Unwind_RaiseException is not correctly implemented"); + return ___cxa_throw(ex, 0, 0); +} + +var PATH = { + isAbs: path => path.charAt(0) === "/", + splitPath: filename => { + var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + }, + normalizeArray: (parts, allowAboveRoot) => { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === ".") { + parts.splice(i, 1); + } else if (last === "..") { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (;up; up--) { + parts.unshift(".."); + } + } + return parts; + }, + normalize: path => { + var isAbsolute = PATH.isAbs(path), trailingSlash = path.slice(-1) === "/"; + // Normalize the path + path = PATH.normalizeArray(path.split("/").filter(p => !!p), !isAbsolute).join("/"); + if (!path && !isAbsolute) { + path = "."; + } + if (path && trailingSlash) { + path += "/"; + } + return (isAbsolute ? "/" : "") + path; + }, + dirname: path => { + var result = PATH.splitPath(path), root = result[0], dir = result[1]; + if (!root && !dir) { + // No dirname whatsoever + return "."; + } + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.slice(0, -1); + } + return root + dir; + }, + basename: path => path && path.match(/([^\/]+|\/)\/*$/)[1], + join: (...paths) => PATH.normalize(paths.join("/")), + join2: (l, r) => PATH.normalize(l + "/" + r) +}; + +var initRandomFill = () => { + // This block is not needed on v19+ since crypto.getRandomValues is builtin + if (ENVIRONMENT_IS_NODE) { + var nodeCrypto = require("node:crypto"); + return view => nodeCrypto.randomFillSync(view); + } + return view => crypto.getRandomValues(view); +}; + +var randomFill = view => { + // Lazily init on the first invocation. + (randomFill = initRandomFill())(view); +}; + +var PATH_FS = { + resolve: (...args) => { + var resolvedPath = "", resolvedAbsolute = false; + for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? args[i] : FS.cwd(); + // Skip empty and invalid entries + if (typeof path != "string") { + throw new TypeError("Arguments to path.resolve must be strings"); + } else if (!path) { + return ""; + } + resolvedPath = path + "/" + resolvedPath; + resolvedAbsolute = PATH.isAbs(path); + } + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(p => !!p), !resolvedAbsolute).join("/"); + return ((resolvedAbsolute ? "/" : "") + resolvedPath) || "."; + }, + relative: (from, to) => { + from = PATH_FS.resolve(from).slice(1); + to = PATH_FS.resolve(to).slice(1); + function trim(arr) { + var start = 0; + for (;start < arr.length; start++) { + if (arr[start] !== "") break; + } + var end = arr.length - 1; + for (;end >= 0; end--) { + if (arr[end] !== "") break; + } + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + var fromParts = trim(from.split("/")); + var toParts = trim(to.split("/")); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push(".."); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join("/"); + } +}; + +var UTF8Decoder = new TextDecoder; + +var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => { + var maxIdx = idx + maxBytesToRead; + if (ignoreNul) return maxIdx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on + // null terminator by itself. + // As a tiny code save trick, compare idx against maxIdx using a negation, + // so that maxBytesToRead=undefined/NaN means Infinity. + while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx; + return idx; +}; + +/** + * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given + * array that contains uint8 values, returns a copy of that string as a + * Javascript String object. + * heapOrArray is either a regular array, or a JavaScript typed array view. + * @param {number=} idx + * @param {number=} maxBytesToRead + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead, ignoreNul) => { + idx >>>= 0; + var endPtr = findStringEnd(heapOrArray, idx, maxBytesToRead, ignoreNul); + return UTF8Decoder.decode(heapOrArray.buffer ? heapOrArray.subarray(idx, endPtr) : new Uint8Array(heapOrArray.slice(idx, endPtr))); +}; + +var FS_stdin_getChar_buffer = []; + +var lengthBytesUTF8 = str => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); + // possibly a lead surrogate + if (c <= 127) { + len++; + } else if (c <= 2047) { + len += 2; + } else if (c >= 55296 && c <= 57343) { + len += 4; + ++i; + } else { + len += 3; + } + } + return len; +}; + +var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { + outIdx >>>= 0; + // Parameter maxBytesToWrite is not optional. Negative values, 0, null, + // undefined and false each don't write out any bytes. + if (!(maxBytesToWrite > 0)) return 0; + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description + // and https://www.ietf.org/rfc/rfc2279.txt + // and https://tools.ietf.org/html/rfc3629 + var u = str.codePointAt(i); + if (u <= 127) { + if (outIdx >= endIdx) break; + heap[outIdx++ >>> 0] = u; + } else if (u <= 2047) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++ >>> 0] = 192 | (u >> 6); + heap[outIdx++ >>> 0] = 128 | (u & 63); + } else if (u <= 65535) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++ >>> 0] = 224 | (u >> 12); + heap[outIdx++ >>> 0] = 128 | ((u >> 6) & 63); + heap[outIdx++ >>> 0] = 128 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++ >>> 0] = 240 | (u >> 18); + heap[outIdx++ >>> 0] = 128 | ((u >> 12) & 63); + heap[outIdx++ >>> 0] = 128 | ((u >> 6) & 63); + heap[outIdx++ >>> 0] = 128 | (u & 63); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + i++; + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx >>> 0] = 0; + return outIdx - startIdx; +}; + +/** @type {function(string, boolean=, number=)} */ var intArrayFromString = (stringy, dontAddNull, length) => { + var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); + if (dontAddNull) u8array.length = numBytesWritten; + return u8array; +}; + +var FS_stdin_getChar = () => { + if (!FS_stdin_getChar_buffer.length) { + var result = null; + if (ENVIRONMENT_IS_NODE) { + // we will read data by chunks of BUFSIZE + var BUFSIZE = 256; + var buf = Buffer.alloc(BUFSIZE); + var bytesRead = 0; + // For some reason we must suppress a closure warning here, even though + // fd definitely exists on process.stdin, and is even the proper way to + // get the fd of stdin, + // https://github.com/nodejs/help/issues/2136#issuecomment-523649904 + // This started to happen after moving this logic out of library_tty.js, + // so it is related to the surrounding code in some unclear manner. + /** @suppress {missingProperties} */ var fd = process.stdin.fd; + try { + bytesRead = fs.readSync(fd, buf, 0, BUFSIZE); + } catch (e) { + // Cross-platform differences: on Windows, reading EOF throws an + // exception, but on other OSes, reading EOF returns 0. Uniformize + // behavior by treating the EOF exception to return 0. + if (e.toString().includes("EOF")) bytesRead = 0; else throw e; + } + if (bytesRead > 0) { + result = buf.slice(0, bytesRead).toString("utf-8"); + } + } else if (globalThis.window?.prompt) { + // Browser. + result = window.prompt("Input: "); + // returns null on cancel + if (result !== null) { + result += "\n"; + } + } else {} + if (!result) { + return null; + } + FS_stdin_getChar_buffer = intArrayFromString(result, true); + } + return FS_stdin_getChar_buffer.shift(); +}; + +var TTY = { + ttys: [], + init() {}, + shutdown() {}, + register(dev, ops) { + TTY.ttys[dev] = { + input: [], + output: [], + ops + }; + FS.registerDevice(dev, TTY.stream_ops); + }, + stream_ops: { + open(stream) { + var tty = TTY.ttys[stream.node.rdev]; + if (!tty) { + throw new FS.ErrnoError(43); + } + stream.tty = tty; + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + stream.tty.ops.fsync(stream.tty); + }, + fsync(stream) { + stream.tty.ops.fsync(stream.tty); + }, + read(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.get_char) { + throw new FS.ErrnoError(60); + } + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = stream.tty.ops.get_char(stream.tty); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.put_char) { + throw new FS.ErrnoError(60); + } + try { + for (var i = 0; i < length; i++) { + stream.tty.ops.put_char(stream.tty, buffer[offset + i]); + } + } catch (e) { + throw new FS.ErrnoError(29); + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + } + }, + default_tty_ops: { + get_char(tty) { + return FS_stdin_getChar(); + }, + put_char(tty, val) { + if (val === null || val === 10) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output?.length > 0) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } + }, + ioctl_tcgets(tty) { + // typical setting + return { + c_iflag: 25856, + c_oflag: 5, + c_cflag: 191, + c_lflag: 35387, + c_cc: [ 3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + }; + }, + ioctl_tcsets(tty, optional_actions, data) { + // currently just ignore + return 0; + }, + ioctl_tiocgwinsz(tty) { + return [ 24, 80 ]; + } + }, + default_tty1_ops: { + put_char(tty, val) { + if (val === null || val === 10) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output?.length > 0) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } + } + } +}; + +var zeroMemory = (ptr, size) => HEAPU8.fill(0, ptr, ptr + size); + +var alignMemory = (size, alignment) => Math.ceil(size / alignment) * alignment; + +var mmapAlloc = size => { + size = alignMemory(size, 65536); + var ptr = _emscripten_builtin_memalign(65536, size); + if (ptr) zeroMemory(ptr, size); + return ptr; +}; + +var MEMFS = { + ops_table: null, + mount(mount) { + return MEMFS.createNode(null, "/", 16895, 0); + }, + createNode(parent, name, mode, dev) { + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { + // not supported + throw new FS.ErrnoError(63); + } + MEMFS.ops_table ||= { + dir: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + lookup: MEMFS.node_ops.lookup, + mknod: MEMFS.node_ops.mknod, + rename: MEMFS.node_ops.rename, + unlink: MEMFS.node_ops.unlink, + rmdir: MEMFS.node_ops.rmdir, + readdir: MEMFS.node_ops.readdir, + symlink: MEMFS.node_ops.symlink + }, + stream: { + llseek: MEMFS.stream_ops.llseek + } + }, + file: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: { + llseek: MEMFS.stream_ops.llseek, + read: MEMFS.stream_ops.read, + write: MEMFS.stream_ops.write, + mmap: MEMFS.stream_ops.mmap, + msync: MEMFS.stream_ops.msync + } + }, + link: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink + }, + stream: {} + }, + chrdev: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: FS.chrdev_stream_ops + } + }; + var node = FS.createNode(parent, name, mode, dev); + if (FS.isDir(node.mode)) { + node.node_ops = MEMFS.ops_table.dir.node; + node.stream_ops = MEMFS.ops_table.dir.stream; + node.contents = {}; + } else if (FS.isFile(node.mode)) { + node.node_ops = MEMFS.ops_table.file.node; + node.stream_ops = MEMFS.ops_table.file.stream; + node.usedBytes = 0; + // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity. + // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred + // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size + // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. + node.contents = null; + } else if (FS.isLink(node.mode)) { + node.node_ops = MEMFS.ops_table.link.node; + node.stream_ops = MEMFS.ops_table.link.stream; + } else if (FS.isChrdev(node.mode)) { + node.node_ops = MEMFS.ops_table.chrdev.node; + node.stream_ops = MEMFS.ops_table.chrdev.stream; + } + node.atime = node.mtime = node.ctime = Date.now(); + // add the new node to the parent + if (parent) { + parent.contents[name] = node; + parent.atime = parent.mtime = parent.ctime = node.atime; + } + return node; + }, + getFileDataAsTypedArray(node) { + if (!node.contents) return new Uint8Array(0); + if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); + // Make sure to not return excess unused bytes. + return new Uint8Array(node.contents); + }, + expandFileStorage(node, newCapacity) { + var prevCapacity = node.contents ? node.contents.length : 0; + if (prevCapacity >= newCapacity) return; + // No need to expand, the storage was already large enough. + // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. + // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to + // avoid overshooting the allocation cap by a very large margin. + var CAPACITY_DOUBLING_MAX = 1024 * 1024; + newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>> 0); + if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); + // At minimum allocate 256b for each file when expanding. + var oldContents = node.contents; + node.contents = new Uint8Array(newCapacity); + // Allocate new storage. + if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); + }, + resizeFileStorage(node, newSize) { + if (node.usedBytes == newSize) return; + if (newSize == 0) { + node.contents = null; + // Fully decommit when requesting a resize to zero. + node.usedBytes = 0; + } else { + var oldContents = node.contents; + node.contents = new Uint8Array(newSize); + // Allocate new storage. + if (oldContents) { + node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); + } + node.usedBytes = newSize; + } + }, + node_ops: { + getattr(node) { + var attr = {}; + // device numbers reuse inode numbers. + attr.dev = FS.isChrdev(node.mode) ? node.id : 1; + attr.ino = node.id; + attr.mode = node.mode; + attr.nlink = 1; + attr.uid = 0; + attr.gid = 0; + attr.rdev = node.rdev; + if (FS.isDir(node.mode)) { + attr.size = 4096; + } else if (FS.isFile(node.mode)) { + attr.size = node.usedBytes; + } else if (FS.isLink(node.mode)) { + attr.size = node.link.length; + } else { + attr.size = 0; + } + attr.atime = new Date(node.atime); + attr.mtime = new Date(node.mtime); + attr.ctime = new Date(node.ctime); + // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize), + // but this is not required by the standard. + attr.blksize = 4096; + attr.blocks = Math.ceil(attr.size / attr.blksize); + return attr; + }, + setattr(node, attr) { + for (const key of [ "mode", "atime", "mtime", "ctime" ]) { + if (attr[key] != null) { + node[key] = attr[key]; + } + } + if (attr.size !== undefined) { + MEMFS.resizeFileStorage(node, attr.size); + } + }, + lookup(parent, name) { + // This error may happen quite a bit. To avoid overhead we reuse it (and + // suffer a lack of stack info). + if (!MEMFS.doesNotExistError) { + MEMFS.doesNotExistError = new FS.ErrnoError(44); + /** @suppress {checkTypes} */ MEMFS.doesNotExistError.stack = ""; + } + throw MEMFS.doesNotExistError; + }, + mknod(parent, name, mode, dev) { + return MEMFS.createNode(parent, name, mode, dev); + }, + rename(old_node, new_dir, new_name) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + if (new_node) { + if (FS.isDir(old_node.mode)) { + // if we're overwriting a directory at new_name, make sure it's empty. + for (var i in new_node.contents) { + throw new FS.ErrnoError(55); + } + } + FS.hashRemoveNode(new_node); + } + // do the internal rewiring + delete old_node.parent.contents[old_node.name]; + new_dir.contents[new_name] = old_node; + old_node.name = new_name; + new_dir.ctime = new_dir.mtime = old_node.parent.ctime = old_node.parent.mtime = Date.now(); + }, + unlink(parent, name) { + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + rmdir(parent, name) { + var node = FS.lookupNode(parent, name); + for (var i in node.contents) { + throw new FS.ErrnoError(55); + } + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + readdir(node) { + return [ ".", "..", ...Object.keys(node.contents) ]; + }, + symlink(parent, newname, oldpath) { + var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); + node.link = oldpath; + return node; + }, + readlink(node) { + if (!FS.isLink(node.mode)) { + throw new FS.ErrnoError(28); + } + return node.link; + } + }, + stream_ops: { + read(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= stream.node.usedBytes) return 0; + var size = Math.min(stream.node.usedBytes - position, length); + if (size > 8 && contents.subarray) { + // non-trivial, and typed array + buffer.set(contents.subarray(position, position + size), offset); + } else { + for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i]; + } + return size; + }, + write(stream, buffer, offset, length, position, canOwn) { + // If the buffer is located in main memory (HEAP), and if + // memory can grow, we can't hold on to references of the + // memory buffer, as they may get invalidated. That means we + // need to copy its contents. + if (buffer.buffer === HEAP8.buffer) { + canOwn = false; + } + if (!length) return 0; + var node = stream.node; + node.mtime = node.ctime = Date.now(); + if (buffer.subarray && (!node.contents || node.contents.subarray)) { + // This write is from a typed array to a typed array? + if (canOwn) { + node.contents = buffer.subarray(offset, offset + length); + node.usedBytes = length; + return length; + } else if (node.usedBytes === 0 && position === 0) { + // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data. + node.contents = buffer.slice(offset, offset + length); + node.usedBytes = length; + return length; + } else if (position + length <= node.usedBytes) { + // Writing to an already allocated and used subrange of the file? + node.contents.set(buffer.subarray(offset, offset + length), position); + return length; + } + } + // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. + MEMFS.expandFileStorage(node, position + length); + if (node.contents.subarray && buffer.subarray) { + // Use typed array write which is available. + node.contents.set(buffer.subarray(offset, offset + length), position); + } else { + for (var i = 0; i < length; i++) { + node.contents[position + i] = buffer[offset + i]; + } + } + node.usedBytes = Math.max(node.usedBytes, position + length); + return length; + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + position += stream.node.usedBytes; + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, + mmap(stream, length, position, prot, flags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + var ptr; + var allocated; + var contents = stream.node.contents; + // Only make a new copy when MAP_PRIVATE is specified. + if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) { + // We can't emulate MAP_SHARED when the file is not backed by the + // buffer we're mapping to (e.g. the HEAP buffer). + allocated = false; + ptr = contents.byteOffset; + } else { + allocated = true; + ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + if (contents) { + // Try to avoid unnecessary slices. + if (position > 0 || position + length < contents.length) { + if (contents.subarray) { + contents = contents.subarray(position, position + length); + } else { + contents = Array.prototype.slice.call(contents, position, position + length); + } + } + HEAP8.set(contents, ptr >>> 0); + } + } + return { + ptr, + allocated + }; + }, + msync(stream, buffer, offset, length, mmapFlags) { + MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); + // should we check if bytesWritten and length are the same? + return 0; + } + } +}; + +var FS_modeStringToFlags = str => { + var flagModes = { + "r": 0, + "r+": 2, + "w": 512 | 64 | 1, + "w+": 512 | 64 | 2, + "a": 1024 | 64 | 1, + "a+": 1024 | 64 | 2 + }; + var flags = flagModes[str]; + if (typeof flags == "undefined") { + throw new Error(`Unknown file open mode: ${str}`); + } + return flags; +}; + +var FS_getMode = (canRead, canWrite) => { + var mode = 0; + if (canRead) mode |= 292 | 73; + if (canWrite) mode |= 146; + return mode; +}; + +var asyncLoad = async url => { + var arrayBuffer = await readAsync(url); + return new Uint8Array(arrayBuffer); +}; + +var FS_createDataFile = (...args) => FS.createDataFile(...args); + +var getUniqueRunDependency = id => id; + +var runDependencies = 0; + +var dependenciesFulfilled = null; + +var removeRunDependency = id => { + runDependencies--; + Module["monitorRunDependencies"]?.(runDependencies); + if (runDependencies == 0) { + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); + } + } +}; + +var addRunDependency = id => { + runDependencies++; + Module["monitorRunDependencies"]?.(runDependencies); +}; + +var FS_handledByPreloadPlugin = async (byteArray, fullname) => { + // Ensure plugins are ready. + if (typeof Browser != "undefined") Browser.init(); + for (var plugin of preloadPlugins) { + if (plugin["canHandle"](fullname)) { + return plugin["handle"](byteArray, fullname); + } + } + // If no plugin handled this file then return the original/unmodified + // byteArray. + return byteArray; +}; + +var FS_preloadFile = async (parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish) => { + // TODO we should allow people to just pass in a complete filename instead + // of parent and name being that we just join them anyways + var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; + var dep = getUniqueRunDependency(`cp ${fullname}`); + // might have several active requests for the same fullname + addRunDependency(dep); + try { + var byteArray = url; + if (typeof url == "string") { + byteArray = await asyncLoad(url); + } + byteArray = await FS_handledByPreloadPlugin(byteArray, fullname); + preFinish?.(); + if (!dontCreateFile) { + FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); + } + } finally { + removeRunDependency(dep); + } +}; + +var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { + FS_preloadFile(parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish).then(onload).catch(onerror); +}; + +var FS = { + root: null, + mounts: [], + devices: {}, + streams: [], + nextInode: 1, + nameTable: null, + currentPath: "/", + initialized: false, + ignorePermissions: true, + filesystems: null, + syncFSRequests: 0, + ErrnoError: class { + name="ErrnoError"; + // We set the `name` property to be able to identify `FS.ErrnoError` + // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway. + // - when using PROXYFS, an error can come from an underlying FS + // as different FS objects have their own FS.ErrnoError each, + // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs. + // we'll use the reliable test `err.name == "ErrnoError"` instead + constructor(errno) { + this.errno = errno; + } + }, + FSStream: class { + shared={}; + get object() { + return this.node; + } + set object(val) { + this.node = val; + } + get isRead() { + return (this.flags & 2097155) !== 1; + } + get isWrite() { + return (this.flags & 2097155) !== 0; + } + get isAppend() { + return (this.flags & 1024); + } + get flags() { + return this.shared.flags; + } + set flags(val) { + this.shared.flags = val; + } + get position() { + return this.shared.position; + } + set position(val) { + this.shared.position = val; + } + }, + FSNode: class { + node_ops={}; + stream_ops={}; + readMode=292 | 73; + writeMode=146; + mounted=null; + constructor(parent, name, mode, rdev) { + if (!parent) { + parent = this; + } + this.parent = parent; + this.mount = parent.mount; + this.id = FS.nextInode++; + this.name = name; + this.mode = mode; + this.rdev = rdev; + this.atime = this.mtime = this.ctime = Date.now(); + } + get read() { + return (this.mode & this.readMode) === this.readMode; + } + set read(val) { + val ? this.mode |= this.readMode : this.mode &= ~this.readMode; + } + get write() { + return (this.mode & this.writeMode) === this.writeMode; + } + set write(val) { + val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode; + } + get isFolder() { + return FS.isDir(this.mode); + } + get isDevice() { + return FS.isChrdev(this.mode); + } + }, + lookupPath(path, opts = {}) { + if (!path) { + throw new FS.ErrnoError(44); + } + opts.follow_mount ??= true; + if (!PATH.isAbs(path)) { + path = FS.cwd() + "/" + path; + } + // limit max consecutive symlinks to 40 (SYMLOOP_MAX). + linkloop: for (var nlinks = 0; nlinks < 40; nlinks++) { + // split the absolute path + var parts = path.split("/").filter(p => !!p); + // start at the root + var current = FS.root; + var current_path = "/"; + for (var i = 0; i < parts.length; i++) { + var islast = (i === parts.length - 1); + if (islast && opts.parent) { + // stop resolving + break; + } + if (parts[i] === ".") { + continue; + } + if (parts[i] === "..") { + current_path = PATH.dirname(current_path); + if (FS.isRoot(current)) { + path = current_path + "/" + parts.slice(i + 1).join("/"); + // We're making progress here, don't let many consecutive ..'s + // lead to ELOOP + nlinks--; + continue linkloop; + } else { + current = current.parent; + } + continue; + } + current_path = PATH.join2(current_path, parts[i]); + try { + current = FS.lookupNode(current, parts[i]); + } catch (e) { + // if noent_okay is true, suppress a ENOENT in the last component + // and return an object with an undefined node. This is needed for + // resolving symlinks in the path when creating a file. + if ((e?.errno === 44) && islast && opts.noent_okay) { + return { + path: current_path + }; + } + throw e; + } + // jump to the mount's root node if this is a mountpoint + if (FS.isMountpoint(current) && (!islast || opts.follow_mount)) { + current = current.mounted.root; + } + // by default, lookupPath will not follow a symlink if it is the final path component. + // setting opts.follow = true will override this behavior. + if (FS.isLink(current.mode) && (!islast || opts.follow)) { + if (!current.node_ops.readlink) { + throw new FS.ErrnoError(52); + } + var link = current.node_ops.readlink(current); + if (!PATH.isAbs(link)) { + link = PATH.dirname(current_path) + "/" + link; + } + path = link + "/" + parts.slice(i + 1).join("/"); + continue linkloop; + } + } + return { + path: current_path, + node: current + }; + } + throw new FS.ErrnoError(32); + }, + getPath(node) { + var path; + while (true) { + if (FS.isRoot(node)) { + var mount = node.mount.mountpoint; + if (!path) return mount; + return mount[mount.length - 1] !== "/" ? `${mount}/${path}` : mount + path; + } + path = path ? `${node.name}/${path}` : node.name; + node = node.parent; + } + }, + hashName(parentid, name) { + var hash = 0; + for (var i = 0; i < name.length; i++) { + hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; + } + return ((parentid + hash) >>> 0) % FS.nameTable.length; + }, + hashAddNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; + }, + hashRemoveNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; + } else { + var current = FS.nameTable[hash]; + while (current) { + if (current.name_next === node) { + current.name_next = node.name_next; + break; + } + current = current.name_next; + } + } + }, + lookupNode(parent, name) { + var errCode = FS.mayLookup(parent); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + var hash = FS.hashName(parent.id, name); + for (var node = FS.nameTable[hash]; node; node = node.name_next) { + var nodeName = node.name; + if (node.parent.id === parent.id && nodeName === name) { + return node; + } + } + // if we failed to find it in the cache, call into the VFS + return FS.lookup(parent, name); + }, + createNode(parent, name, mode, rdev) { + var node = new FS.FSNode(parent, name, mode, rdev); + FS.hashAddNode(node); + return node; + }, + destroyNode(node) { + FS.hashRemoveNode(node); + }, + isRoot(node) { + return node === node.parent; + }, + isMountpoint(node) { + return !!node.mounted; + }, + isFile(mode) { + return (mode & 61440) === 32768; + }, + isDir(mode) { + return (mode & 61440) === 16384; + }, + isLink(mode) { + return (mode & 61440) === 40960; + }, + isChrdev(mode) { + return (mode & 61440) === 8192; + }, + isBlkdev(mode) { + return (mode & 61440) === 24576; + }, + isFIFO(mode) { + return (mode & 61440) === 4096; + }, + isSocket(mode) { + return (mode & 49152) === 49152; + }, + flagsToPermissionString(flag) { + var perms = [ "r", "w", "rw" ][flag & 3]; + if ((flag & 512)) { + perms += "w"; + } + return perms; + }, + nodePermissions(node, perms) { + if (FS.ignorePermissions) { + return 0; + } + // return 0 if any user, group or owner bits are set. + if (perms.includes("r") && !(node.mode & 292)) { + return 2; + } + if (perms.includes("w") && !(node.mode & 146)) { + return 2; + } + if (perms.includes("x") && !(node.mode & 73)) { + return 2; + } + return 0; + }, + mayLookup(dir) { + if (!FS.isDir(dir.mode)) return 54; + var errCode = FS.nodePermissions(dir, "x"); + if (errCode) return errCode; + if (!dir.node_ops.lookup) return 2; + return 0; + }, + mayCreate(dir, name) { + if (!FS.isDir(dir.mode)) { + return 54; + } + try { + var node = FS.lookupNode(dir, name); + return 20; + } catch (e) {} + return FS.nodePermissions(dir, "wx"); + }, + mayDelete(dir, name, isdir) { + var node; + try { + node = FS.lookupNode(dir, name); + } catch (e) { + return e.errno; + } + var errCode = FS.nodePermissions(dir, "wx"); + if (errCode) { + return errCode; + } + if (isdir) { + if (!FS.isDir(node.mode)) { + return 54; + } + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { + return 10; + } + } else if (FS.isDir(node.mode)) { + return 31; + } + return 0; + }, + mayOpen(node, flags) { + if (!node) { + return 44; + } + if (FS.isLink(node.mode)) { + return 32; + } + var mode = FS.flagsToPermissionString(flags); + if (FS.isDir(node.mode)) { + // opening for write + // TODO: check for O_SEARCH? (== search for dir only) + if (mode !== "r" || (flags & (512 | 64))) { + return 31; + } + } + return FS.nodePermissions(node, mode); + }, + checkOpExists(op, err) { + if (!op) { + throw new FS.ErrnoError(err); + } + return op; + }, + MAX_OPEN_FDS: 4096, + nextfd() { + for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { + if (!FS.streams[fd]) { + return fd; + } + } + throw new FS.ErrnoError(33); + }, + getStreamChecked(fd) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + return stream; + }, + getStream: fd => FS.streams[fd], + createStream(stream, fd = -1) { + // clone it, so we can return an instance of FSStream + stream = Object.assign(new FS.FSStream, stream); + if (fd == -1) { + fd = FS.nextfd(); + } + stream.fd = fd; + FS.streams[fd] = stream; + return stream; + }, + closeStream(fd) { + FS.streams[fd] = null; + }, + dupStream(origStream, fd = -1) { + var stream = FS.createStream(origStream, fd); + stream.stream_ops?.dup?.(stream); + return stream; + }, + doSetAttr(stream, node, attr) { + var setattr = stream?.stream_ops.setattr; + var arg = setattr ? stream : node; + setattr ??= node.node_ops.setattr; + FS.checkOpExists(setattr, 63); + setattr(arg, attr); + }, + chrdev_stream_ops: { + open(stream) { + var device = FS.getDevice(stream.node.rdev); + // override node's stream ops with the device's + stream.stream_ops = device.stream_ops; + // forward the open call + stream.stream_ops.open?.(stream); + }, + llseek() { + throw new FS.ErrnoError(70); + } + }, + major: dev => ((dev) >> 8), + minor: dev => ((dev) & 255), + makedev: (ma, mi) => ((ma) << 8 | (mi)), + registerDevice(dev, ops) { + FS.devices[dev] = { + stream_ops: ops + }; + }, + getDevice: dev => FS.devices[dev], + getMounts(mount) { + var mounts = []; + var check = [ mount ]; + while (check.length) { + var m = check.pop(); + mounts.push(m); + check.push(...m.mounts); + } + return mounts; + }, + syncfs(populate, callback) { + if (typeof populate == "function") { + callback = populate; + populate = false; + } + FS.syncFSRequests++; + if (FS.syncFSRequests > 1) { + err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`); + } + var mounts = FS.getMounts(FS.root.mount); + var completed = 0; + function doCallback(errCode) { + FS.syncFSRequests--; + return callback(errCode); + } + function done(errCode) { + if (errCode) { + if (!done.errored) { + done.errored = true; + return doCallback(errCode); + } + return; + } + if (++completed >= mounts.length) { + doCallback(null); + } + } + // sync all mounts + for (var mount of mounts) { + if (mount.type.syncfs) { + mount.type.syncfs(mount, populate, done); + } else { + done(null); + } + } + }, + mount(type, opts, mountpoint) { + var root = mountpoint === "/"; + var pseudo = !mountpoint; + var node; + if (root && FS.root) { + throw new FS.ErrnoError(10); + } else if (!root && !pseudo) { + var lookup = FS.lookupPath(mountpoint, { + follow_mount: false + }); + mountpoint = lookup.path; + // use the absolute path + node = lookup.node; + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + if (!FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + } + var mount = { + type, + opts, + mountpoint, + mounts: [] + }; + // create a root node for the fs + var mountRoot = type.mount(mount); + mountRoot.mount = mount; + mount.root = mountRoot; + if (root) { + FS.root = mountRoot; + } else if (node) { + // set as a mountpoint + node.mounted = mount; + // add the new mount to the current mount's children + if (node.mount) { + node.mount.mounts.push(mount); + } + } + return mountRoot; + }, + unmount(mountpoint) { + var lookup = FS.lookupPath(mountpoint, { + follow_mount: false + }); + if (!FS.isMountpoint(lookup.node)) { + throw new FS.ErrnoError(28); + } + // destroy the nodes for this mount, and all its child mounts + var node = lookup.node; + var mount = node.mounted; + var mounts = FS.getMounts(mount); + for (var [hash, current] of Object.entries(FS.nameTable)) { + while (current) { + var next = current.name_next; + if (mounts.includes(current.mount)) { + FS.destroyNode(current); + } + current = next; + } + } + // no longer a mountpoint + node.mounted = null; + // remove this mount from the child mounts + var idx = node.mount.mounts.indexOf(mount); + node.mount.mounts.splice(idx, 1); + }, + lookup(parent, name) { + return parent.node_ops.lookup(parent, name); + }, + mknod(path, mode, dev) { + var lookup = FS.lookupPath(path, { + parent: true + }); + var parent = lookup.node; + var name = PATH.basename(path); + if (!name) { + throw new FS.ErrnoError(28); + } + if (name === "." || name === "..") { + throw new FS.ErrnoError(20); + } + var errCode = FS.mayCreate(parent, name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.mknod) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.mknod(parent, name, mode, dev); + }, + statfs(path) { + return FS.statfsNode(FS.lookupPath(path, { + follow: true + }).node); + }, + statfsStream(stream) { + // We keep a separate statfsStream function because noderawfs overrides + // it. In noderawfs, stream.node is sometimes null. Instead, we need to + // look at stream.path. + return FS.statfsNode(stream.node); + }, + statfsNode(node) { + // NOTE: None of the defaults here are true. We're just returning safe and + // sane values. Currently nodefs and rawfs replace these defaults, + // other file systems leave them alone. + var rtn = { + bsize: 4096, + frsize: 4096, + blocks: 1e6, + bfree: 5e5, + bavail: 5e5, + files: FS.nextInode, + ffree: FS.nextInode - 1, + fsid: 42, + flags: 2, + namelen: 255 + }; + if (node.node_ops.statfs) { + Object.assign(rtn, node.node_ops.statfs(node.mount.opts.root)); + } + return rtn; + }, + create(path, mode = 438) { + mode &= 4095; + mode |= 32768; + return FS.mknod(path, mode, 0); + }, + mkdir(path, mode = 511) { + mode &= 511 | 512; + mode |= 16384; + return FS.mknod(path, mode, 0); + }, + mkdirTree(path, mode) { + var dirs = path.split("/"); + var d = ""; + for (var dir of dirs) { + if (!dir) continue; + if (d || PATH.isAbs(path)) d += "/"; + d += dir; + try { + FS.mkdir(d, mode); + } catch (e) { + if (e.errno != 20) throw e; + } + } + }, + mkdev(path, mode, dev) { + if (typeof dev == "undefined") { + dev = mode; + mode = 438; + } + mode |= 8192; + return FS.mknod(path, mode, dev); + }, + symlink(oldpath, newpath) { + if (!PATH_FS.resolve(oldpath)) { + throw new FS.ErrnoError(44); + } + var lookup = FS.lookupPath(newpath, { + parent: true + }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var newname = PATH.basename(newpath); + var errCode = FS.mayCreate(parent, newname); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.symlink) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.symlink(parent, newname, oldpath); + }, + rename(old_path, new_path) { + var old_dirname = PATH.dirname(old_path); + var new_dirname = PATH.dirname(new_path); + var old_name = PATH.basename(old_path); + var new_name = PATH.basename(new_path); + // parents must exist + var lookup, old_dir, new_dir; + // let the errors from non existent directories percolate up + lookup = FS.lookupPath(old_path, { + parent: true + }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { + parent: true + }); + new_dir = lookup.node; + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); + // need to be part of the same mount + if (old_dir.mount !== new_dir.mount) { + throw new FS.ErrnoError(75); + } + // source must exist + var old_node = FS.lookupNode(old_dir, old_name); + // old path should not be an ancestor of the new path + var relative = PATH_FS.relative(old_path, new_dirname); + if (relative.charAt(0) !== ".") { + throw new FS.ErrnoError(28); + } + // new path should not be an ancestor of the old path + relative = PATH_FS.relative(new_path, old_dirname); + if (relative.charAt(0) !== ".") { + throw new FS.ErrnoError(55); + } + // see if the new path already exists + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + // early out if nothing needs to change + if (old_node === new_node) { + return; + } + // we'll need to delete the old entry + var isdir = FS.isDir(old_node.mode); + var errCode = FS.mayDelete(old_dir, old_name, isdir); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + // need delete permissions if we'll be overwriting. + // need create permissions if new doesn't already exist. + errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!old_dir.node_ops.rename) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) { + throw new FS.ErrnoError(10); + } + // if we are going to change the parent, check write permissions + if (new_dir !== old_dir) { + errCode = FS.nodePermissions(old_dir, "w"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // remove the node from the lookup hash + FS.hashRemoveNode(old_node); + // do the underlying fs rename + try { + old_dir.node_ops.rename(old_node, new_dir, new_name); + // update old node (we do this here to avoid each backend + // needing to) + old_node.parent = new_dir; + } catch (e) { + throw e; + } finally { + // add the node back to the hash (in case node_ops.rename + // changed its name) + FS.hashAddNode(old_node); + } + }, + rmdir(path) { + var lookup = FS.lookupPath(path, { + parent: true + }); + var parent = lookup.node; + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, true); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.rmdir) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.rmdir(parent, name); + FS.destroyNode(node); + }, + readdir(path) { + var lookup = FS.lookupPath(path, { + follow: true + }); + var node = lookup.node; + var readdir = FS.checkOpExists(node.node_ops.readdir, 54); + return readdir(node); + }, + unlink(path) { + var lookup = FS.lookupPath(path, { + parent: true + }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, false); + if (errCode) { + // According to POSIX, we should map EISDIR to EPERM, but + // we instead do what Linux does (and we must, as we use + // the musl linux libc). + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.unlink) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.unlink(parent, name); + FS.destroyNode(node); + }, + readlink(path) { + var lookup = FS.lookupPath(path); + var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(44); + } + if (!link.node_ops.readlink) { + throw new FS.ErrnoError(28); + } + return link.node_ops.readlink(link); + }, + stat(path, dontFollow) { + var lookup = FS.lookupPath(path, { + follow: !dontFollow + }); + var node = lookup.node; + var getattr = FS.checkOpExists(node.node_ops.getattr, 63); + return getattr(node); + }, + fstat(fd) { + var stream = FS.getStreamChecked(fd); + var node = stream.node; + var getattr = stream.stream_ops.getattr; + var arg = getattr ? stream : node; + getattr ??= node.node_ops.getattr; + FS.checkOpExists(getattr, 63); + return getattr(arg); + }, + lstat(path) { + return FS.stat(path, true); + }, + doChmod(stream, node, mode, dontFollow) { + FS.doSetAttr(stream, node, { + mode: (mode & 4095) | (node.mode & ~4095), + ctime: Date.now(), + dontFollow + }); + }, + chmod(path, mode, dontFollow) { + var node; + if (typeof path == "string") { + var lookup = FS.lookupPath(path, { + follow: !dontFollow + }); + node = lookup.node; + } else { + node = path; + } + FS.doChmod(null, node, mode, dontFollow); + }, + lchmod(path, mode) { + FS.chmod(path, mode, true); + }, + fchmod(fd, mode) { + var stream = FS.getStreamChecked(fd); + FS.doChmod(stream, stream.node, mode, false); + }, + doChown(stream, node, dontFollow) { + FS.doSetAttr(stream, node, { + timestamp: Date.now(), + dontFollow + }); + }, + chown(path, uid, gid, dontFollow) { + var node; + if (typeof path == "string") { + var lookup = FS.lookupPath(path, { + follow: !dontFollow + }); + node = lookup.node; + } else { + node = path; + } + FS.doChown(null, node, dontFollow); + }, + lchown(path, uid, gid) { + FS.chown(path, uid, gid, true); + }, + fchown(fd, uid, gid) { + var stream = FS.getStreamChecked(fd); + FS.doChown(stream, stream.node, false); + }, + doTruncate(stream, node, len) { + if (FS.isDir(node.mode)) { + throw new FS.ErrnoError(31); + } + if (!FS.isFile(node.mode)) { + throw new FS.ErrnoError(28); + } + var errCode = FS.nodePermissions(node, "w"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.doSetAttr(stream, node, { + size: len, + timestamp: Date.now() + }); + }, + truncate(path, len) { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path == "string") { + var lookup = FS.lookupPath(path, { + follow: true + }); + node = lookup.node; + } else { + node = path; + } + FS.doTruncate(null, node, len); + }, + ftruncate(fd, len) { + var stream = FS.getStreamChecked(fd); + if (len < 0 || (stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(28); + } + FS.doTruncate(stream, stream.node, len); + }, + utime(path, atime, mtime) { + var lookup = FS.lookupPath(path, { + follow: true + }); + var node = lookup.node; + var setattr = FS.checkOpExists(node.node_ops.setattr, 63); + setattr(node, { + atime, + mtime + }); + }, + open(path, flags, mode = 438) { + if (path === "") { + throw new FS.ErrnoError(44); + } + flags = typeof flags == "string" ? FS_modeStringToFlags(flags) : flags; + if ((flags & 64)) { + mode = (mode & 4095) | 32768; + } else { + mode = 0; + } + var node; + var isDirPath; + if (typeof path == "object") { + node = path; + } else { + isDirPath = path.endsWith("/"); + // noent_okay makes it so that if the final component of the path + // doesn't exist, lookupPath returns `node: undefined`. `path` will be + // updated to point to the target of all symlinks. + var lookup = FS.lookupPath(path, { + follow: !(flags & 131072), + noent_okay: true + }); + node = lookup.node; + path = lookup.path; + } + // perhaps we need to create the node + var created = false; + if ((flags & 64)) { + if (node) { + // if O_CREAT and O_EXCL are set, error out if the node already exists + if ((flags & 128)) { + throw new FS.ErrnoError(20); + } + } else if (isDirPath) { + throw new FS.ErrnoError(31); + } else { + // node doesn't exist, try to create it + // Ignore the permission bits here to ensure we can `open` this new + // file below. We use chmod below to apply the permissions once the + // file is open. + node = FS.mknod(path, mode | 511, 0); + created = true; + } + } + if (!node) { + throw new FS.ErrnoError(44); + } + // can't truncate a device + if (FS.isChrdev(node.mode)) { + flags &= ~512; + } + // if asked only for a directory, then this must be one + if ((flags & 65536) && !FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + // check permissions, if this is not a file we just created now (it is ok to + // create and write to a file with read-only permissions; it is read-only + // for later use) + if (!created) { + var errCode = FS.mayOpen(node, flags); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // do truncation if necessary + if ((flags & 512) && !created) { + FS.truncate(node, 0); + } + // we've already handled these, don't pass down to the underlying vfs + flags &= ~(128 | 512 | 131072); + // register the stream with the filesystem + var stream = FS.createStream({ + node, + path: FS.getPath(node), + // we want the absolute path to the node + flags, + seekable: true, + position: 0, + stream_ops: node.stream_ops, + // used by the file family libc calls (fopen, fwrite, ferror, etc.) + ungotten: [], + error: false + }); + // call the new stream's open function + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + if (created) { + FS.chmod(node, mode & 511); + } + return stream; + }, + close(stream) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (stream.getdents) stream.getdents = null; + // free readdir state + try { + if (stream.stream_ops.close) { + stream.stream_ops.close(stream); + } + } catch (e) { + throw e; + } finally { + FS.closeStream(stream.fd); + } + stream.fd = null; + }, + isClosed(stream) { + return stream.fd === null; + }, + llseek(stream, offset, whence) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (!stream.seekable || !stream.stream_ops.llseek) { + throw new FS.ErrnoError(70); + } + if (whence != 0 && whence != 1 && whence != 2) { + throw new FS.ErrnoError(28); + } + stream.position = stream.stream_ops.llseek(stream, offset, whence); + stream.ungotten = []; + return stream.position; + }, + read(stream, buffer, offset, length, position) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.read) { + throw new FS.ErrnoError(28); + } + var seeking = typeof position != "undefined"; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position); + if (!seeking) stream.position += bytesRead; + return bytesRead; + }, + write(stream, buffer, offset, length, position, canOwn) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.write) { + throw new FS.ErrnoError(28); + } + if (stream.seekable && stream.flags & 1024) { + // seek to the end before writing in append mode + FS.llseek(stream, 0, 2); + } + var seeking = typeof position != "undefined"; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); + if (!seeking) stream.position += bytesWritten; + return bytesWritten; + }, + mmap(stream, length, position, prot, flags) { + // User requests writing to file (prot & PROT_WRITE != 0). + // Checking if we have permissions to write to the file unless + // MAP_PRIVATE flag is set. According to POSIX spec it is possible + // to write to file opened in read-only mode with MAP_PRIVATE flag, + // as all modifications will be visible only in the memory of + // the current process. + if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) { + throw new FS.ErrnoError(2); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(2); + } + if (!stream.stream_ops.mmap) { + throw new FS.ErrnoError(43); + } + if (!length) { + throw new FS.ErrnoError(28); + } + return stream.stream_ops.mmap(stream, length, position, prot, flags); + }, + msync(stream, buffer, offset, length, mmapFlags) { + if (!stream.stream_ops.msync) { + return 0; + } + return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags); + }, + ioctl(stream, cmd, arg) { + if (!stream.stream_ops.ioctl) { + throw new FS.ErrnoError(59); + } + return stream.stream_ops.ioctl(stream, cmd, arg); + }, + readFile(path, opts = {}) { + opts.flags = opts.flags || 0; + opts.encoding = opts.encoding || "binary"; + if (opts.encoding !== "utf8" && opts.encoding !== "binary") { + abort(`Invalid encoding type "${opts.encoding}"`); + } + var stream = FS.open(path, opts.flags); + var stat = FS.stat(path); + var length = stat.size; + var buf = new Uint8Array(length); + FS.read(stream, buf, 0, length, 0); + if (opts.encoding === "utf8") { + buf = UTF8ArrayToString(buf); + } + FS.close(stream); + return buf; + }, + writeFile(path, data, opts = {}) { + opts.flags = opts.flags || 577; + var stream = FS.open(path, opts.flags, opts.mode); + if (typeof data == "string") { + data = new Uint8Array(intArrayFromString(data, true)); + } + if (ArrayBuffer.isView(data)) { + FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); + } else { + abort("Unsupported data type"); + } + FS.close(stream); + }, + cwd: () => FS.currentPath, + chdir(path) { + var lookup = FS.lookupPath(path, { + follow: true + }); + if (lookup.node === null) { + throw new FS.ErrnoError(44); + } + if (!FS.isDir(lookup.node.mode)) { + throw new FS.ErrnoError(54); + } + var errCode = FS.nodePermissions(lookup.node, "x"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.currentPath = lookup.path; + }, + createDefaultDirectories() { + FS.mkdir("/tmp"); + FS.mkdir("/home"); + FS.mkdir("/home/web_user"); + }, + createDefaultDevices() { + // create /dev + FS.mkdir("/dev"); + // setup /dev/null + FS.registerDevice(FS.makedev(1, 3), { + read: () => 0, + write: (stream, buffer, offset, length, pos) => length, + llseek: () => 0 + }); + FS.mkdev("/dev/null", FS.makedev(1, 3)); + // setup /dev/tty and /dev/tty1 + // stderr needs to print output using err() rather than out() + // so we register a second tty just for it. + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); + FS.mkdev("/dev/tty", FS.makedev(5, 0)); + FS.mkdev("/dev/tty1", FS.makedev(6, 0)); + // setup /dev/[u]random + // use a buffer to avoid overhead of individual crypto calls per byte + var randomBuffer = new Uint8Array(1024), randomLeft = 0; + var randomByte = () => { + if (randomLeft === 0) { + randomFill(randomBuffer); + randomLeft = randomBuffer.byteLength; + } + return randomBuffer[--randomLeft]; + }; + FS.createDevice("/dev", "random", randomByte); + FS.createDevice("/dev", "urandom", randomByte); + // we're not going to emulate the actual shm device, + // just create the tmp dirs that reside in it commonly + FS.mkdir("/dev/shm"); + FS.mkdir("/dev/shm/tmp"); + }, + createSpecialDirectories() { + // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the + // name of the stream for fd 6 (see test_unistd_ttyname) + FS.mkdir("/proc"); + var proc_self = FS.mkdir("/proc/self"); + FS.mkdir("/proc/self/fd"); + FS.mount({ + mount() { + var node = FS.createNode(proc_self, "fd", 16895, 73); + node.stream_ops = { + llseek: MEMFS.stream_ops.llseek + }; + node.node_ops = { + lookup(parent, name) { + var fd = +name; + var stream = FS.getStreamChecked(fd); + var ret = { + parent: null, + mount: { + mountpoint: "fake" + }, + node_ops: { + readlink: () => stream.path + }, + id: fd + 1 + }; + ret.parent = ret; + // make it look like a simple root node + return ret; + }, + readdir() { + return Array.from(FS.streams.entries()).filter(([k, v]) => v).map(([k, v]) => k.toString()); + } + }; + return node; + } + }, {}, "/proc/self/fd"); + }, + createStandardStreams(input, output, error) { + // TODO deprecate the old functionality of a single + // input / output callback and that utilizes FS.createDevice + // and instead require a unique set of stream ops + // by default, we symlink the standard streams to the + // default tty devices. however, if the standard streams + // have been overwritten we create a unique device for + // them instead. + if (input) { + FS.createDevice("/dev", "stdin", input); + } else { + FS.symlink("/dev/tty", "/dev/stdin"); + } + if (output) { + FS.createDevice("/dev", "stdout", null, output); + } else { + FS.symlink("/dev/tty", "/dev/stdout"); + } + if (error) { + FS.createDevice("/dev", "stderr", null, error); + } else { + FS.symlink("/dev/tty1", "/dev/stderr"); + } + // open default streams for the stdin, stdout and stderr devices + var stdin = FS.open("/dev/stdin", 0); + var stdout = FS.open("/dev/stdout", 1); + var stderr = FS.open("/dev/stderr", 1); + }, + staticInit() { + FS.nameTable = new Array(4096); + FS.mount(MEMFS, {}, "/"); + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + FS.createSpecialDirectories(); + FS.filesystems = { + "MEMFS": MEMFS + }; + }, + init(input, output, error) { + FS.initialized = true; + // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here + input ??= Module["stdin"]; + output ??= Module["stdout"]; + error ??= Module["stderr"]; + FS.createStandardStreams(input, output, error); + }, + quit() { + FS.initialized = false; + // force-flush all streams, so we get musl std streams printed out + // close all of our streams + for (var stream of FS.streams) { + if (stream) { + FS.close(stream); + } + } + }, + findObject(path, dontResolveLastLink) { + var ret = FS.analyzePath(path, dontResolveLastLink); + if (!ret.exists) { + return null; + } + return ret.object; + }, + analyzePath(path, dontResolveLastLink) { + // operate from within the context of the symlink's target + try { + var lookup = FS.lookupPath(path, { + follow: !dontResolveLastLink + }); + path = lookup.path; + } catch (e) {} + var ret = { + isRoot: false, + exists: false, + error: 0, + name: null, + path: null, + object: null, + parentExists: false, + parentPath: null, + parentObject: null + }; + try { + var lookup = FS.lookupPath(path, { + parent: true + }); + ret.parentExists = true; + ret.parentPath = lookup.path; + ret.parentObject = lookup.node; + ret.name = PATH.basename(path); + lookup = FS.lookupPath(path, { + follow: !dontResolveLastLink + }); + ret.exists = true; + ret.path = lookup.path; + ret.object = lookup.node; + ret.name = lookup.node.name; + ret.isRoot = lookup.path === "/"; + } catch (e) { + ret.error = e.errno; + } + return ret; + }, + createPath(parent, path, canRead, canWrite) { + parent = typeof parent == "string" ? parent : FS.getPath(parent); + var parts = path.split("/").reverse(); + while (parts.length) { + var part = parts.pop(); + if (!part) continue; + var current = PATH.join2(parent, part); + try { + FS.mkdir(current); + } catch (e) { + if (e.errno != 20) throw e; + } + parent = current; + } + return current; + }, + createFile(parent, name, properties, canRead, canWrite) { + var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name); + var mode = FS_getMode(canRead, canWrite); + return FS.create(path, mode); + }, + createDataFile(parent, name, data, canRead, canWrite, canOwn) { + var path = name; + if (parent) { + parent = typeof parent == "string" ? parent : FS.getPath(parent); + path = name ? PATH.join2(parent, name) : parent; + } + var mode = FS_getMode(canRead, canWrite); + var node = FS.create(path, mode); + if (data) { + if (typeof data == "string") { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); + data = arr; + } + // make sure we can write to the file + FS.chmod(node, mode | 146); + var stream = FS.open(node, 577); + FS.write(stream, data, 0, data.length, 0, canOwn); + FS.close(stream); + FS.chmod(node, mode); + } + }, + createDevice(parent, name, input, output) { + var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name); + var mode = FS_getMode(!!input, !!output); + FS.createDevice.major ??= 64; + var dev = FS.makedev(FS.createDevice.major++, 0); + // Create a fake device that a set of stream ops to emulate + // the old behavior. + FS.registerDevice(dev, { + open(stream) { + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + if (output?.buffer?.length) { + output(10); + } + }, + read(stream, buffer, offset, length, pos) { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = input(); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + for (var i = 0; i < length; i++) { + try { + output(buffer[offset + i]); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + } + }); + return FS.mkdev(path, mode, dev); + }, + forceLoadFile(obj) { + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; + if (globalThis.XMLHttpRequest) { + abort("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); + } else { + // Command-line. + try { + obj.contents = readBinary(obj.url); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + }, + createLazyFile(parent, name, url, canRead, canWrite) { + // Lazy chunked Uint8Array (implements get and length from Uint8Array). + // Actual getting is abstracted away for eventual reuse. + class LazyUint8Array { + lengthKnown=false; + chunks=[]; + // Loaded chunks. Index is the chunk number + get(idx) { + if (idx > this.length - 1 || idx < 0) { + return undefined; + } + var chunkOffset = idx % this.chunkSize; + var chunkNum = (idx / this.chunkSize) | 0; + return this.getter(chunkNum)[chunkOffset]; + } + setDataGetter(getter) { + this.getter = getter; + } + cacheLength() { + // Find length + var xhr = new XMLHttpRequest; + xhr.open("HEAD", url, false); + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); + var datalength = Number(xhr.getResponseHeader("Content-length")); + var header; + var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; + var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; + var chunkSize = 1024 * 1024; + // Chunk size in bytes + if (!hasByteServing) chunkSize = datalength; + // Function to get a range from the remote URL. + var doXHR = (from, to) => { + if (from > to) abort("invalid range (" + from + ", " + to + ") or no bytes requested!"); + if (to > datalength - 1) abort("only " + datalength + " bytes available! programmer error!"); + // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. + var xhr = new XMLHttpRequest; + xhr.open("GET", url, false); + if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); + // Some hints to the browser that we want binary data. + xhr.responseType = "arraybuffer"; + if (xhr.overrideMimeType) { + xhr.overrideMimeType("text/plain; charset=x-user-defined"); + } + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); + if (xhr.response !== undefined) { + return new Uint8Array(/** @type{Array} */ (xhr.response || [])); + } + return intArrayFromString(xhr.responseText || "", true); + }; + var lazyArray = this; + lazyArray.setDataGetter(chunkNum => { + var start = chunkNum * chunkSize; + var end = (chunkNum + 1) * chunkSize - 1; + // including this byte + end = Math.min(end, datalength - 1); + // if datalength-1 is selected, this is the last block + if (typeof lazyArray.chunks[chunkNum] == "undefined") { + lazyArray.chunks[chunkNum] = doXHR(start, end); + } + if (typeof lazyArray.chunks[chunkNum] == "undefined") abort("doXHR failed!"); + return lazyArray.chunks[chunkNum]; + }); + if (usesGzip || !datalength) { + // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length + chunkSize = datalength = 1; + // this will force getter(0)/doXHR do download the whole file + datalength = this.getter(0).length; + chunkSize = datalength; + out("LazyFiles on gzip forces download of the whole file when length is accessed"); + } + this._length = datalength; + this._chunkSize = chunkSize; + this.lengthKnown = true; + } + get length() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + } + get chunkSize() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + } + } + if (globalThis.XMLHttpRequest) { + if (!ENVIRONMENT_IS_WORKER) abort("Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc"); + var lazyArray = new LazyUint8Array; + var properties = { + isDevice: false, + contents: lazyArray + }; + } else { + var properties = { + isDevice: false, + url + }; + } + var node = FS.createFile(parent, name, properties, canRead, canWrite); + // This is a total hack, but I want to get this lazy file code out of the + // core of MEMFS. If we want to keep this lazy file concept I feel it should + // be its own thin LAZYFS proxying calls to MEMFS. + if (properties.contents) { + node.contents = properties.contents; + } else if (properties.url) { + node.contents = null; + node.url = properties.url; + } + // Add a function that defers querying the file size until it is asked the first time. + Object.defineProperties(node, { + usedBytes: { + get: function() { + return this.contents.length; + } + } + }); + // override each stream op with one that tries to force load the lazy file first + var stream_ops = {}; + for (const [key, fn] of Object.entries(node.stream_ops)) { + stream_ops[key] = (...args) => { + FS.forceLoadFile(node); + return fn(...args); + }; + } + function writeChunks(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= contents.length) return 0; + var size = Math.min(contents.length - position, length); + if (contents.slice) { + // normal array + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents[position + i]; + } + } else { + for (var i = 0; i < size; i++) { + // LazyUint8Array from sync binary XHR + buffer[offset + i] = contents.get(position + i); + } + } + return size; + } + // use a custom read function + stream_ops.read = (stream, buffer, offset, length, position) => { + FS.forceLoadFile(node); + return writeChunks(stream, buffer, offset, length, position); + }; + // use a custom mmap function + stream_ops.mmap = (stream, length, position, prot, flags) => { + FS.forceLoadFile(node); + var ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + writeChunks(stream, HEAP8, ptr, length, position); + return { + ptr, + allocated: true + }; + }; + node.stream_ops = stream_ops; + return node; + } +}; + +/** + * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the + * emscripten HEAP, returns a copy of that string as a Javascript String object. + * + * @param {number} ptr + * @param {number=} maxBytesToRead - An optional length that specifies the + * maximum number of bytes to read. You can omit this parameter to scan the + * string until the first 0 byte. If maxBytesToRead is passed, and the string + * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the + * string will cut short at that byte index. + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => { + ptr >>>= 0; + if (!ptr) return ""; + var end = findStringEnd(HEAPU8, ptr, maxBytesToRead, ignoreNul); + return UTF8Decoder.decode(HEAPU8.subarray(ptr >>> 0, end >>> 0)); +}; + +var SYSCALLS = { + calculateAt(dirfd, path, allowEmpty) { + if (PATH.isAbs(path)) { + return path; + } + // relative path + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = SYSCALLS.getStreamFromFD(dirfd); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44); + } + return dir; + } + return dir + "/" + path; + }, + writeStat(buf, stat) { + HEAPU32[((buf) >>> 2) >>> 0] = stat.dev; + HEAPU32[(((buf) + (4)) >>> 2) >>> 0] = stat.mode; + HEAPU32[(((buf) + (8)) >>> 2) >>> 0] = stat.nlink; + HEAPU32[(((buf) + (12)) >>> 2) >>> 0] = stat.uid; + HEAPU32[(((buf) + (16)) >>> 2) >>> 0] = stat.gid; + HEAPU32[(((buf) + (20)) >>> 2) >>> 0] = stat.rdev; + (tempI64 = [ stat.size >>> 0, (tempDouble = stat.size, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (24)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (28)) >>> 2) >>> 0] = tempI64[1]); + HEAP32[(((buf) + (32)) >>> 2) >>> 0] = 4096; + HEAP32[(((buf) + (36)) >>> 2) >>> 0] = stat.blocks; + var atime = stat.atime.getTime(); + var mtime = stat.mtime.getTime(); + var ctime = stat.ctime.getTime(); + (tempI64 = [ Math.floor(atime / 1e3) >>> 0, (tempDouble = Math.floor(atime / 1e3), + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (40)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (44)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (48)) >>> 2) >>> 0] = (atime % 1e3) * 1e3 * 1e3; + (tempI64 = [ Math.floor(mtime / 1e3) >>> 0, (tempDouble = Math.floor(mtime / 1e3), + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (56)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (60)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (64)) >>> 2) >>> 0] = (mtime % 1e3) * 1e3 * 1e3; + (tempI64 = [ Math.floor(ctime / 1e3) >>> 0, (tempDouble = Math.floor(ctime / 1e3), + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (72)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (76)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (80)) >>> 2) >>> 0] = (ctime % 1e3) * 1e3 * 1e3; + (tempI64 = [ stat.ino >>> 0, (tempDouble = stat.ino, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (88)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (92)) >>> 2) >>> 0] = tempI64[1]); + return 0; + }, + writeStatFs(buf, stats) { + HEAPU32[(((buf) + (4)) >>> 2) >>> 0] = stats.bsize; + HEAPU32[(((buf) + (60)) >>> 2) >>> 0] = stats.bsize; + (tempI64 = [ stats.blocks >>> 0, (tempDouble = stats.blocks, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (8)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (12)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.bfree >>> 0, (tempDouble = stats.bfree, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (16)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (20)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.bavail >>> 0, (tempDouble = stats.bavail, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (24)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (28)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.files >>> 0, (tempDouble = stats.files, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (32)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (36)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.ffree >>> 0, (tempDouble = stats.ffree, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (40)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (44)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (48)) >>> 2) >>> 0] = stats.fsid; + HEAPU32[(((buf) + (64)) >>> 2) >>> 0] = stats.flags; + // ST_NOSUID + HEAPU32[(((buf) + (56)) >>> 2) >>> 0] = stats.namelen; + }, + doMsync(addr, stream, len, flags, offset) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (flags & 2) { + // MAP_PRIVATE calls need not to be synced back to underlying fs + return 0; + } + var buffer = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer, offset, len, flags); + }, + getStreamFromFD(fd) { + var stream = FS.getStreamChecked(fd); + return stream; + }, + varargs: undefined, + getStr(ptr) { + var ret = UTF8ToString(ptr); + return ret; + } +}; + +function ___syscall_dup(fd) { + try { + var old = SYSCALLS.getStreamFromFD(fd); + return FS.dupStream(old).fd; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_faccessat(dirfd, path, amode, flags) { + path >>>= 0; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (amode & ~7) { + // need a valid mode + return -28; + } + var lookup = FS.lookupPath(path, { + follow: true + }); + var node = lookup.node; + if (!node) { + return -44; + } + var perms = ""; + if (amode & 4) perms += "r"; + if (amode & 2) perms += "w"; + if (amode & 1) perms += "x"; + if (perms && FS.nodePermissions(node, perms)) { + return -2; + } + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var syscallGetVarargI = () => { + // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. + var ret = HEAP32[((+SYSCALLS.varargs) >>> 2) >>> 0]; + SYSCALLS.varargs += 4; + return ret; +}; + +var syscallGetVarargP = syscallGetVarargI; + +function ___syscall_fcntl64(fd, cmd, varargs) { + varargs >>>= 0; + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: + { + var arg = syscallGetVarargI(); + if (arg < 0) { + return -28; + } + while (FS.streams[arg]) { + arg++; + } + var newStream; + newStream = FS.dupStream(stream, arg); + return newStream.fd; + } + + case 1: + case 2: + return 0; + + // FD_CLOEXEC makes no sense for a single process. + case 3: + return stream.flags; + + case 4: + { + var arg = syscallGetVarargI(); + stream.flags |= arg; + return 0; + } + + case 12: + { + var arg = syscallGetVarargP(); + var offset = 0; + // We're always unlocked. + HEAP16[(((arg) + (offset)) >>> 1) >>> 0] = 2; + return 0; + } + + case 13: + case 14: + // Pretend that the locking is successful. These are process-level locks, + // and Emscripten programs are a single process. If we supported linking a + // filesystem between programs, we'd need to do more here. + // See https://github.com/emscripten-core/emscripten/issues/23697 + return 0; + } + return -28; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_fstat64(fd, buf) { + buf >>>= 0; + try { + return SYSCALLS.writeStat(buf, FS.fstat(fd)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_ftruncate64(fd, length_low, length_high) { + var length = convertI32PairToI53Checked(length_low, length_high); + try { + if (isNaN(length)) return -61; + FS.ftruncate(fd, length); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var stringToUTF8 = (str, outPtr, maxBytesToWrite) => stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + +function ___syscall_getcwd(buf, size) { + buf >>>= 0; + size >>>= 0; + try { + if (size === 0) return -28; + var cwd = FS.cwd(); + var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; + if (size < cwdLengthInBytes) return -68; + stringToUTF8(cwd, buf, size); + return cwdLengthInBytes; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_getdents64(fd, dirp, count) { + dirp >>>= 0; + count >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + stream.getdents ||= FS.readdir(stream.path); + var struct_size = 280; + var pos = 0; + var off = FS.llseek(stream, 0, 1); + var startIdx = Math.floor(off / struct_size); + var endIdx = Math.min(stream.getdents.length, startIdx + Math.floor(count / struct_size)); + for (var idx = startIdx; idx < endIdx; idx++) { + var id; + var type; + var name = stream.getdents[idx]; + if (name === ".") { + id = stream.node.id; + type = 4; + } else if (name === "..") { + var lookup = FS.lookupPath(stream.path, { + parent: true + }); + id = lookup.node.id; + type = 4; + } else { + var child; + try { + child = FS.lookupNode(stream.node, name); + } catch (e) { + // If the entry is not a directory, file, or symlink, nodefs + // lookupNode will raise EINVAL. Skip these and continue. + if (e?.errno === 28) { + continue; + } + throw e; + } + id = child.id; + type = FS.isChrdev(child.mode) ? 2 : // character device. + FS.isDir(child.mode) ? 4 : // directory + FS.isLink(child.mode) ? 10 : // symbolic link. + 8; + } + (tempI64 = [ id >>> 0, (tempDouble = id, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[((dirp + pos) >>> 2) >>> 0] = tempI64[0], HEAP32[(((dirp + pos) + (4)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ (idx + 1) * struct_size >>> 0, (tempDouble = (idx + 1) * struct_size, + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((dirp + pos) + (8)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((dirp + pos) + (12)) >>> 2) >>> 0] = tempI64[1]); + HEAP16[(((dirp + pos) + (16)) >>> 1) >>> 0] = 280; + HEAP8[(dirp + pos) + (18) >>> 0] = type; + stringToUTF8(name, dirp + pos + 19, 256); + pos += struct_size; + } + FS.llseek(stream, idx * struct_size, 0); + return pos; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_ioctl(fd, op, varargs) { + varargs >>>= 0; + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (op) { + case 21509: + { + if (!stream.tty) return -59; + return 0; + } + + case 21505: + { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcgets) { + var termios = stream.tty.ops.ioctl_tcgets(stream); + var argp = syscallGetVarargP(); + HEAP32[((argp) >>> 2) >>> 0] = termios.c_iflag || 0; + HEAP32[(((argp) + (4)) >>> 2) >>> 0] = termios.c_oflag || 0; + HEAP32[(((argp) + (8)) >>> 2) >>> 0] = termios.c_cflag || 0; + HEAP32[(((argp) + (12)) >>> 2) >>> 0] = termios.c_lflag || 0; + for (var i = 0; i < 32; i++) { + HEAP8[(argp + i) + (17) >>> 0] = termios.c_cc[i] || 0; + } + return 0; + } + return 0; + } + + case 21510: + case 21511: + case 21512: + { + if (!stream.tty) return -59; + return 0; + } + + case 21506: + case 21507: + case 21508: + { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcsets) { + var argp = syscallGetVarargP(); + var c_iflag = HEAP32[((argp) >>> 2) >>> 0]; + var c_oflag = HEAP32[(((argp) + (4)) >>> 2) >>> 0]; + var c_cflag = HEAP32[(((argp) + (8)) >>> 2) >>> 0]; + var c_lflag = HEAP32[(((argp) + (12)) >>> 2) >>> 0]; + var c_cc = []; + for (var i = 0; i < 32; i++) { + c_cc.push(HEAP8[(argp + i) + (17) >>> 0]); + } + return stream.tty.ops.ioctl_tcsets(stream.tty, op, { + c_iflag, + c_oflag, + c_cflag, + c_lflag, + c_cc + }); + } + return 0; + } + + case 21519: + { + if (!stream.tty) return -59; + var argp = syscallGetVarargP(); + HEAP32[((argp) >>> 2) >>> 0] = 0; + return 0; + } + + case 21520: + { + if (!stream.tty) return -59; + return -28; + } + + case 21537: + case 21531: + { + var argp = syscallGetVarargP(); + return FS.ioctl(stream, op, argp); + } + + case 21523: + { + // TODO: in theory we should write to the winsize struct that gets + // passed in, but for now musl doesn't read anything on it + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tiocgwinsz) { + var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty); + var argp = syscallGetVarargP(); + HEAP16[((argp) >>> 1) >>> 0] = winsize[0]; + HEAP16[(((argp) + (2)) >>> 1) >>> 0] = winsize[1]; + } + return 0; + } + + case 21524: + { + // TODO: technically, this ioctl call should change the window size. + // but, since emscripten doesn't have any concept of a terminal window + // yet, we'll just silently throw it away as we do TIOCGWINSZ + if (!stream.tty) return -59; + return 0; + } + + case 21515: + { + if (!stream.tty) return -59; + return 0; + } + + default: + return -28; + } + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_lstat64(path, buf) { + path >>>= 0; + buf >>>= 0; + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.writeStat(buf, FS.lstat(path)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_mkdirat(dirfd, path, mode) { + path >>>= 0; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + FS.mkdir(path, mode, 0); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_newfstatat(dirfd, path, buf, flags) { + path >>>= 0; + buf >>>= 0; + try { + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + var allowEmpty = flags & 4096; + flags = flags & (~6400); + path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); + return SYSCALLS.writeStat(buf, nofollow ? FS.lstat(path) : FS.stat(path)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_openat(dirfd, path, flags, varargs) { + path >>>= 0; + varargs >>>= 0; + SYSCALLS.varargs = varargs; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + var mode = varargs ? syscallGetVarargI() : 0; + return FS.open(path, flags, mode).fd; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_stat64(path, buf) { + path >>>= 0; + buf >>>= 0; + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.writeStat(buf, FS.stat(path)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var __abort_js = () => abort(""); + +function __embind_register_bigint(primitiveType, name, size, minRange, maxRange) { + primitiveType >>>= 0; + name >>>= 0; + size >>>= 0; +} + +var AsciiToString = ptr => { + ptr >>>= 0; + var str = ""; + while (1) { + var ch = HEAPU8[ptr++ >>> 0]; + if (!ch) return str; + str += String.fromCharCode(ch); + } +}; + +var awaitingDependencies = {}; + +var registeredTypes = {}; + +var typeDependencies = {}; + +var BindingError = class BindingError extends Error { + constructor(message) { + super(message); + this.name = "BindingError"; + } +}; + +var throwBindingError = message => { + throw new BindingError(message); +}; + +/** @param {Object=} options */ function sharedRegisterType(rawType, registeredInstance, options = {}) { + var name = registeredInstance.name; + if (!rawType) { + throwBindingError(`type "${name}" must have a positive integer typeid pointer`); + } + if (registeredTypes.hasOwnProperty(rawType)) { + if (options.ignoreDuplicateRegistrations) { + return; + } else { + throwBindingError(`Cannot register type '${name}' twice`); + } + } + registeredTypes[rawType] = registeredInstance; + delete typeDependencies[rawType]; + if (awaitingDependencies.hasOwnProperty(rawType)) { + var callbacks = awaitingDependencies[rawType]; + delete awaitingDependencies[rawType]; + callbacks.forEach(cb => cb()); + } +} + +/** @param {Object=} options */ function registerType(rawType, registeredInstance, options = {}) { + return sharedRegisterType(rawType, registeredInstance, options); +} + +/** @suppress {globalThis} */ function __embind_register_bool(rawType, name, trueValue, falseValue) { + rawType >>>= 0; + name >>>= 0; + name = AsciiToString(name); + registerType(rawType, { + name, + fromWireType: function(wt) { + // ambiguous emscripten ABI: sometimes return values are + // true or false, and sometimes integers (0 or 1) + return !!wt; + }, + toWireType: function(destructors, o) { + return o ? trueValue : falseValue; + }, + readValueFromPointer: function(pointer) { + return this.fromWireType(HEAPU8[pointer >>> 0]); + }, + destructorFunction: null + }); +} + +var emval_freelist = []; + +var emval_handles = [ 0, 1, , 1, null, 1, true, 1, false, 1 ]; + +function __emval_decref(handle) { + handle >>>= 0; + if (handle > 9 && 0 === --emval_handles[handle + 1]) { + emval_handles[handle] = undefined; + emval_freelist.push(handle); + } +} + +var Emval = { + toValue: handle => { + if (!handle) { + throwBindingError(`Cannot use deleted val. handle = ${handle}`); + } + return emval_handles[handle]; + }, + toHandle: value => { + switch (value) { + case undefined: + return 2; + + case null: + return 4; + + case true: + return 6; + + case false: + return 8; + + default: + { + const handle = emval_freelist.pop() || emval_handles.length; + emval_handles[handle] = value; + emval_handles[handle + 1] = 1; + return handle; + } + } + } +}; + +/** @suppress {globalThis} */ function readPointer(pointer) { + return this.fromWireType(HEAPU32[((pointer) >>> 2) >>> 0]); +} + +var EmValType = { + name: "emscripten::val", + fromWireType: handle => { + var rv = Emval.toValue(handle); + __emval_decref(handle); + return rv; + }, + toWireType: (destructors, value) => Emval.toHandle(value), + readValueFromPointer: readPointer, + destructorFunction: null +}; + +function __embind_register_emval(rawType) { + rawType >>>= 0; + return registerType(rawType, EmValType); +} + +var floatReadValueFromPointer = (name, width) => { + switch (width) { + case 4: + return function(pointer) { + return this.fromWireType(HEAPF32[((pointer) >>> 2) >>> 0]); + }; + + case 8: + return function(pointer) { + return this.fromWireType(HEAPF64[((pointer) >>> 3) >>> 0]); + }; + + default: + throw new TypeError(`invalid float width (${width}): ${name}`); + } +}; + +var __embind_register_float = function(rawType, name, size) { + rawType >>>= 0; + name >>>= 0; + size >>>= 0; + name = AsciiToString(name); + registerType(rawType, { + name, + fromWireType: value => value, + toWireType: (destructors, value) => value, + readValueFromPointer: floatReadValueFromPointer(name, size), + destructorFunction: null + }); +}; + +var createNamedFunction = (name, func) => Object.defineProperty(func, "name", { + value: name +}); + +var runDestructors = destructors => { + while (destructors.length) { + var ptr = destructors.pop(); + var del = destructors.pop(); + del(ptr); + } +}; + +function usesDestructorStack(argTypes) { + // Skip return value at index 0 - it's not deleted here. + for (var i = 1; i < argTypes.length; ++i) { + // The type does not define a destructor function - must use dynamic stack + if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { + return true; + } + } + return false; +} + +var runAndAbortIfError = func => { + try { + return func(); + } catch (e) { + abort(e); + } +}; + +var runtimeKeepalivePush = () => { + runtimeKeepaliveCounter += 1; +}; + +var runtimeKeepalivePop = () => { + runtimeKeepaliveCounter -= 1; +}; + +var Asyncify = { + instrumentWasmImports(imports) { + var importPattern = /^(ReadBufferDataJs|WaitUntilCompletedJs|WaitUntilPipelineCreatedJs|invoke_.*|__asyncjs__.*)$/; + for (let [x, original] of Object.entries(imports)) { + if (typeof original == "function") { + let isAsyncifyImport = original.isAsync || importPattern.test(x); + } + } + }, + instrumentFunction(original) { + var wrapper = (...args) => { + Asyncify.exportCallStack.push(original); + try { + return original(...args); + } finally { + if (!ABORT) { + var top = Asyncify.exportCallStack.pop(); + Asyncify.maybeStopUnwind(); + } + } + }; + Asyncify.funcWrappers.set(original, wrapper); + return wrapper; + }, + instrumentWasmExports(exports) { + var ret = {}; + for (let [x, original] of Object.entries(exports)) { + if (typeof original == "function") { + var wrapper = Asyncify.instrumentFunction(original); + ret[x] = wrapper; + } else { + ret[x] = original; + } + } + return ret; + }, + State: { + Normal: 0, + Unwinding: 1, + Rewinding: 2, + Disabled: 3 + }, + state: 0, + StackSize: 4096, + currData: null, + handleSleepReturnValue: 0, + exportCallStack: [], + callstackFuncToId: new Map, + callStackIdToFunc: new Map, + funcWrappers: new Map, + callStackId: 0, + asyncPromiseHandlers: null, + sleepCallbacks: [], + getCallStackId(func) { + if (!Asyncify.callstackFuncToId.has(func)) { + var id = Asyncify.callStackId++; + Asyncify.callstackFuncToId.set(func, id); + Asyncify.callStackIdToFunc.set(id, func); + } + return Asyncify.callstackFuncToId.get(func); + }, + maybeStopUnwind() { + if (Asyncify.currData && Asyncify.state === Asyncify.State.Unwinding && Asyncify.exportCallStack.length === 0) { + // We just finished unwinding. + // Be sure to set the state before calling any other functions to avoid + // possible infinite recursion here (For example in debug pthread builds + // the dbg() function itself can call back into WebAssembly to get the + // current pthread_self() pointer). + Asyncify.state = Asyncify.State.Normal; + // Keep the runtime alive so that a re-wind can be done later. + runAndAbortIfError(_asyncify_stop_unwind); + if (typeof Fibers != "undefined") { + Fibers.trampoline(); + } + } + }, + whenDone() { + return new Promise((resolve, reject) => { + Asyncify.asyncPromiseHandlers = { + resolve, + reject + }; + }); + }, + allocateData() { + // An asyncify data structure has three fields: + // 0 current stack pos + // 4 max stack pos + // 8 id of function at bottom of the call stack (callStackIdToFunc[id] == wasm func) + // The Asyncify ABI only interprets the first two fields, the rest is for the runtime. + // We also embed a stack in the same memory region here, right next to the structure. + // This struct is also defined as asyncify_data_t in emscripten/fiber.h + var ptr = _malloc(12 + Asyncify.StackSize); + Asyncify.setDataHeader(ptr, ptr + 12, Asyncify.StackSize); + Asyncify.setDataRewindFunc(ptr); + return ptr; + }, + setDataHeader(ptr, stack, stackSize) { + HEAPU32[((ptr) >>> 2) >>> 0] = stack; + HEAPU32[(((ptr) + (4)) >>> 2) >>> 0] = stack + stackSize; + }, + setDataRewindFunc(ptr) { + var bottomOfCallStack = Asyncify.exportCallStack[0]; + var rewindId = Asyncify.getCallStackId(bottomOfCallStack); + HEAP32[(((ptr) + (8)) >>> 2) >>> 0] = rewindId; + }, + getDataRewindFunc(ptr) { + var id = HEAP32[(((ptr) + (8)) >>> 2) >>> 0]; + var func = Asyncify.callStackIdToFunc.get(id); + return func; + }, + doRewind(ptr) { + var original = Asyncify.getDataRewindFunc(ptr); + var func = Asyncify.funcWrappers.get(original); + // Once we have rewound and the stack we no longer need to artificially + // keep the runtime alive. + return callUserCallback(func); + }, + handleSleep(startAsync) { + if (ABORT) return; + if (Asyncify.state === Asyncify.State.Normal) { + // Prepare to sleep. Call startAsync, and see what happens: + // if the code decided to call our callback synchronously, + // then no async operation was in fact begun, and we don't + // need to do anything. + var reachedCallback = false; + var reachedAfterCallback = false; + startAsync((handleSleepReturnValue = 0) => { + if (ABORT) return; + Asyncify.handleSleepReturnValue = handleSleepReturnValue; + reachedCallback = true; + if (!reachedAfterCallback) { + // We are happening synchronously, so no need for async. + return; + } + Asyncify.state = Asyncify.State.Rewinding; + runAndAbortIfError(() => _asyncify_start_rewind(Asyncify.currData)); + if (typeof MainLoop != "undefined" && MainLoop.func) { + MainLoop.resume(); + } + var asyncWasmReturnValue, isError = false; + try { + asyncWasmReturnValue = Asyncify.doRewind(Asyncify.currData); + } catch (err) { + asyncWasmReturnValue = err; + isError = true; + } + // Track whether the return value was handled by any promise handlers. + var handled = false; + if (!Asyncify.currData) { + // All asynchronous execution has finished. + // `asyncWasmReturnValue` now contains the final + // return value of the exported async WASM function. + // Note: `asyncWasmReturnValue` is distinct from + // `Asyncify.handleSleepReturnValue`. + // `Asyncify.handleSleepReturnValue` contains the return + // value of the last C function to have executed + // `Asyncify.handleSleep()`, whereas `asyncWasmReturnValue` + // contains the return value of the exported WASM function + // that may have called C functions that + // call `Asyncify.handleSleep()`. + var asyncPromiseHandlers = Asyncify.asyncPromiseHandlers; + if (asyncPromiseHandlers) { + Asyncify.asyncPromiseHandlers = null; + (isError ? asyncPromiseHandlers.reject : asyncPromiseHandlers.resolve)(asyncWasmReturnValue); + handled = true; + } + } + if (isError && !handled) { + // If there was an error and it was not handled by now, we have no choice but to + // rethrow that error into the global scope where it can be caught only by + // `onerror` or `onunhandledpromiserejection`. + throw asyncWasmReturnValue; + } + }); + reachedAfterCallback = true; + if (!reachedCallback) { + // A true async operation was begun; start a sleep. + Asyncify.state = Asyncify.State.Unwinding; + // TODO: reuse, don't alloc/free every sleep + Asyncify.currData = Asyncify.allocateData(); + if (typeof MainLoop != "undefined" && MainLoop.func) { + MainLoop.pause(); + } + runAndAbortIfError(() => _asyncify_start_unwind(Asyncify.currData)); + } + } else if (Asyncify.state === Asyncify.State.Rewinding) { + // Stop a resume. + Asyncify.state = Asyncify.State.Normal; + runAndAbortIfError(_asyncify_stop_rewind); + _free(Asyncify.currData); + Asyncify.currData = null; + // Call all sleep callbacks now that the sleep-resume is all done. + Asyncify.sleepCallbacks.forEach(callUserCallback); + } else { + abort(`invalid state: ${Asyncify.state}`); + } + return Asyncify.handleSleepReturnValue; + }, + handleAsync: startAsync => Asyncify.handleSleep(async wakeUp => { + // TODO: add error handling as a second param when handleSleep implements it. + wakeUp(await startAsync()); + }) +}; + +function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, /** boolean= */ isAsync) { + // humanName: a human-readable string name for the function to be generated. + // argTypes: An array that contains the embind type objects for all types in the function signature. + // argTypes[0] is the type object for the function return value. + // argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method. + // argTypes[2...] are the actual function parameters. + // classType: The embind type object for the class to be bound, or null if this is not a method of a class. + // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. + // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. + // isAsync: Optional. If true, returns an async function. Async bindings are only supported with JSPI. + var argCount = argTypes.length; + if (argCount < 2) { + throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); + } + var isClassMethodFunc = (argTypes[1] !== null && classType !== null); + // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. + // TODO: This omits argument count check - enable only at -O3 or similar. + // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { + // return FUNCTION_TABLE[fn]; + // } + // Determine if we need to use a dynamic stack to store the destructors for the function parameters. + // TODO: Remove this completely once all function invokers are being dynamically generated. + var needsDestructorStack = usesDestructorStack(argTypes); + var returns = !argTypes[0].isVoid; + var expectedArgCount = argCount - 2; + var argsWired = new Array(expectedArgCount); + var invokerFuncArgs = []; + var destructors = []; + var invokerFn = function(...args) { + destructors.length = 0; + var thisWired; + invokerFuncArgs.length = isClassMethodFunc ? 2 : 1; + invokerFuncArgs[0] = cppTargetFunc; + if (isClassMethodFunc) { + thisWired = argTypes[1].toWireType(destructors, this); + invokerFuncArgs[1] = thisWired; + } + for (var i = 0; i < expectedArgCount; ++i) { + argsWired[i] = argTypes[i + 2].toWireType(destructors, args[i]); + invokerFuncArgs.push(argsWired[i]); + } + var rv = cppInvokerFunc(...invokerFuncArgs); + function onDone(rv) { + if (needsDestructorStack) { + runDestructors(destructors); + } else { + for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; i++) { + var param = i === 1 ? thisWired : argsWired[i - 2]; + if (argTypes[i].destructorFunction !== null) { + argTypes[i].destructorFunction(param); + } + } + } + if (returns) { + return argTypes[0].fromWireType(rv); + } + } + if (Asyncify.currData) { + return Asyncify.whenDone().then(onDone); + } + return onDone(rv); + }; + return createNamedFunction(humanName, invokerFn); +} + +var ensureOverloadTable = (proto, methodName, humanName) => { + if (undefined === proto[methodName].overloadTable) { + var prevFunc = proto[methodName]; + // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. + proto[methodName] = function(...args) { + // TODO This check can be removed in -O3 level "unsafe" optimizations. + if (!proto[methodName].overloadTable.hasOwnProperty(args.length)) { + throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`); + } + return proto[methodName].overloadTable[args.length].apply(this, args); + }; + // Move the previous function into the overload table. + proto[methodName].overloadTable = []; + proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } +}; + +/** @param {number=} numArguments */ var exposePublicSymbol = (name, value, numArguments) => { + if (Module.hasOwnProperty(name)) { + if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) { + throwBindingError(`Cannot register public name '${name}' twice`); + } + // We are exposing a function with the same name as an existing function. Create an overload table and a function selector + // that routes between the two. + ensureOverloadTable(Module, name, name); + if (Module[name].overloadTable.hasOwnProperty(numArguments)) { + throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`); + } + // Add the new function into the overload table. + Module[name].overloadTable[numArguments] = value; + } else { + Module[name] = value; + Module[name].argCount = numArguments; + } +}; + +var heap32VectorToArray = (count, firstElement) => { + var array = []; + for (var i = 0; i < count; i++) { + // TODO(https://github.com/emscripten-core/emscripten/issues/17310): + // Find a way to hoist the `>> 2` or `>> 3` out of this loop. + array.push(HEAPU32[(((firstElement) + (i * 4)) >>> 2) >>> 0]); + } + return array; +}; + +var InternalError = class InternalError extends Error { + constructor(message) { + super(message); + this.name = "InternalError"; + } +}; + +var throwInternalError = message => { + throw new InternalError(message); +}; + +/** @param {number=} numArguments */ var replacePublicSymbol = (name, value, numArguments) => { + if (!Module.hasOwnProperty(name)) { + throwInternalError("Replacing nonexistent public symbol"); + } + // If there's an overload table for this symbol, replace the symbol in the overload table instead. + if (undefined !== Module[name].overloadTable && undefined !== numArguments) { + Module[name].overloadTable[numArguments] = value; + } else { + Module[name] = value; + Module[name].argCount = numArguments; + } +}; + +var getDynCaller = (sig, ptr, promising = false) => (...args) => dynCall(sig, ptr, args, promising); + +var embind__requireFunction = (signature, rawFunction, isAsync = false) => { + signature = AsciiToString(signature); + function makeDynCaller() { + return getDynCaller(signature, rawFunction); + } + var fp = makeDynCaller(); + if (typeof fp != "function") { + throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`); + } + return fp; +}; + +class UnboundTypeError extends Error {} + +var getTypeName = type => { + var ptr = ___getTypeName(type); + var rv = AsciiToString(ptr); + _free(ptr); + return rv; +}; + +var throwUnboundTypeError = (message, types) => { + var unboundTypes = []; + var seen = {}; + function visit(type) { + if (seen[type]) { + return; + } + if (registeredTypes[type]) { + return; + } + if (typeDependencies[type]) { + typeDependencies[type].forEach(visit); + return; + } + unboundTypes.push(type); + seen[type] = true; + } + types.forEach(visit); + throw new UnboundTypeError(`${message}: ` + unboundTypes.map(getTypeName).join([ ", " ])); +}; + +var whenDependentTypesAreResolved = (myTypes, dependentTypes, getTypeConverters) => { + myTypes.forEach(type => typeDependencies[type] = dependentTypes); + function onComplete(typeConverters) { + var myTypeConverters = getTypeConverters(typeConverters); + if (myTypeConverters.length !== myTypes.length) { + throwInternalError("Mismatched type converter count"); + } + for (var i = 0; i < myTypes.length; ++i) { + registerType(myTypes[i], myTypeConverters[i]); + } + } + var typeConverters = new Array(dependentTypes.length); + var unregisteredTypes = []; + var registered = 0; + for (let [i, dt] of dependentTypes.entries()) { + if (registeredTypes.hasOwnProperty(dt)) { + typeConverters[i] = registeredTypes[dt]; + } else { + unregisteredTypes.push(dt); + if (!awaitingDependencies.hasOwnProperty(dt)) { + awaitingDependencies[dt] = []; + } + awaitingDependencies[dt].push(() => { + typeConverters[i] = registeredTypes[dt]; + ++registered; + if (registered === unregisteredTypes.length) { + onComplete(typeConverters); + } + }); + } + } + if (0 === unregisteredTypes.length) { + onComplete(typeConverters); + } +}; + +var getFunctionName = signature => { + signature = signature.trim(); + const argsIndex = signature.indexOf("("); + if (argsIndex === -1) return signature; + return signature.slice(0, argsIndex); +}; + +function __embind_register_function(name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync, isNonnullReturn) { + name >>>= 0; + rawArgTypesAddr >>>= 0; + signature >>>= 0; + rawInvoker >>>= 0; + fn >>>= 0; + var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + name = AsciiToString(name); + name = getFunctionName(name); + rawInvoker = embind__requireFunction(signature, rawInvoker, isAsync); + exposePublicSymbol(name, function() { + throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes); + }, argCount - 1); + whenDependentTypesAreResolved([], argTypes, argTypes => { + var invokerArgsArray = [ argTypes[0], null ].concat(argTypes.slice(1)); + replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null, rawInvoker, fn, isAsync), argCount - 1); + return []; + }); +} + +var integerReadValueFromPointer = (name, width, signed) => { + // integers are quite common, so generate very specialized functions + switch (width) { + case 1: + return signed ? pointer => HEAP8[pointer >>> 0] : pointer => HEAPU8[pointer >>> 0]; + + case 2: + return signed ? pointer => HEAP16[((pointer) >>> 1) >>> 0] : pointer => HEAPU16[((pointer) >>> 1) >>> 0]; + + case 4: + return signed ? pointer => HEAP32[((pointer) >>> 2) >>> 0] : pointer => HEAPU32[((pointer) >>> 2) >>> 0]; + + default: + throw new TypeError(`invalid integer width (${width}): ${name}`); + } +}; + +/** @suppress {globalThis} */ var __embind_register_integer = function(primitiveType, name, size, minRange, maxRange) { + primitiveType >>>= 0; + name >>>= 0; + size >>>= 0; + name = AsciiToString(name); + const isUnsignedType = minRange === 0; + let fromWireType = value => value; + if (isUnsignedType) { + var bitshift = 32 - 8 * size; + fromWireType = value => (value << bitshift) >>> bitshift; + maxRange = fromWireType(maxRange); + } + registerType(primitiveType, { + name, + fromWireType, + toWireType: (destructors, value) => value, + readValueFromPointer: integerReadValueFromPointer(name, size, minRange !== 0), + destructorFunction: null + }); +}; + +function __embind_register_memory_view(rawType, dataTypeIndex, name) { + rawType >>>= 0; + name >>>= 0; + var typeMapping = [ Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + var TA = typeMapping[dataTypeIndex]; + function decodeMemoryView(handle) { + var size = HEAPU32[((handle) >>> 2) >>> 0]; + var data = HEAPU32[(((handle) + (4)) >>> 2) >>> 0]; + return new TA(HEAP8.buffer, data, size); + } + name = AsciiToString(name); + registerType(rawType, { + name, + fromWireType: decodeMemoryView, + readValueFromPointer: decodeMemoryView + }, { + ignoreDuplicateRegistrations: true + }); +} + +function __embind_register_std_string(rawType, name) { + rawType >>>= 0; + name >>>= 0; + name = AsciiToString(name); + var stdStringIsUTF8 = true; + registerType(rawType, { + name, + // For some method names we use string keys here since they are part of + // the public/external API and/or used by the runtime-generated code. + fromWireType(value) { + var length = HEAPU32[((value) >>> 2) >>> 0]; + var payload = value + 4; + var str; + if (stdStringIsUTF8) { + str = UTF8ToString(payload, length, true); + } else { + str = ""; + for (var i = 0; i < length; ++i) { + str += String.fromCharCode(HEAPU8[payload + i >>> 0]); + } + } + _free(value); + return str; + }, + toWireType(destructors, value) { + if (value instanceof ArrayBuffer) { + value = new Uint8Array(value); + } + var length; + var valueIsOfTypeString = (typeof value == "string"); + // We accept `string` or array views with single byte elements + if (!(valueIsOfTypeString || (ArrayBuffer.isView(value) && value.BYTES_PER_ELEMENT == 1))) { + throwBindingError("Cannot pass non-string to std::string"); + } + if (stdStringIsUTF8 && valueIsOfTypeString) { + length = lengthBytesUTF8(value); + } else { + length = value.length; + } + // assumes POINTER_SIZE alignment + var base = _malloc(4 + length + 1); + var ptr = base + 4; + HEAPU32[((base) >>> 2) >>> 0] = length; + if (valueIsOfTypeString) { + if (stdStringIsUTF8) { + stringToUTF8(value, ptr, length + 1); + } else { + for (var i = 0; i < length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode > 255) { + _free(base); + throwBindingError("String has UTF-16 code units that do not fit in 8 bits"); + } + HEAPU8[ptr + i >>> 0] = charCode; + } + } + } else { + HEAPU8.set(value, ptr >>> 0); + } + if (destructors !== null) { + destructors.push(_free, base); + } + return base; + }, + readValueFromPointer: readPointer, + destructorFunction(ptr) { + _free(ptr); + } + }); +} + +var UTF16Decoder = new TextDecoder("utf-16le"); + +var UTF16ToString = (ptr, maxBytesToRead, ignoreNul) => { + var idx = ((ptr) >>> 1); + var endIdx = findStringEnd(HEAPU16, idx, maxBytesToRead / 2, ignoreNul); + return UTF16Decoder.decode(HEAPU16.subarray(idx >>> 0, endIdx >>> 0)); +}; + +var stringToUTF16 = (str, outPtr, maxBytesToWrite) => { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + maxBytesToWrite ??= 2147483647; + if (maxBytesToWrite < 2) return 0; + maxBytesToWrite -= 2; + // Null terminator. + var startPtr = outPtr; + var numCharsToWrite = (maxBytesToWrite < str.length * 2) ? (maxBytesToWrite / 2) : str.length; + for (var i = 0; i < numCharsToWrite; ++i) { + // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. + var codeUnit = str.charCodeAt(i); + // possibly a lead surrogate + HEAP16[((outPtr) >>> 1) >>> 0] = codeUnit; + outPtr += 2; + } + // Null-terminate the pointer to the HEAP. + HEAP16[((outPtr) >>> 1) >>> 0] = 0; + return outPtr - startPtr; +}; + +var lengthBytesUTF16 = str => str.length * 2; + +var UTF32ToString = (ptr, maxBytesToRead, ignoreNul) => { + var str = ""; + var startIdx = ((ptr) >>> 2); + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + for (var i = 0; !(i >= maxBytesToRead / 4); i++) { + var utf32 = HEAPU32[startIdx + i >>> 0]; + if (!utf32 && !ignoreNul) break; + str += String.fromCodePoint(utf32); + } + return str; +}; + +var stringToUTF32 = (str, outPtr, maxBytesToWrite) => { + outPtr >>>= 0; + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + maxBytesToWrite ??= 2147483647; + if (maxBytesToWrite < 4) return 0; + var startPtr = outPtr; + var endPtr = startPtr + maxBytesToWrite - 4; + for (var i = 0; i < str.length; ++i) { + var codePoint = str.codePointAt(i); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + if (codePoint > 65535) { + i++; + } + HEAP32[((outPtr) >>> 2) >>> 0] = codePoint; + outPtr += 4; + if (outPtr + 4 > endPtr) break; + } + // Null-terminate the pointer to the HEAP. + HEAP32[((outPtr) >>> 2) >>> 0] = 0; + return outPtr - startPtr; +}; + +var lengthBytesUTF32 = str => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var codePoint = str.codePointAt(i); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + if (codePoint > 65535) { + i++; + } + len += 4; + } + return len; +}; + +function __embind_register_std_wstring(rawType, charSize, name) { + rawType >>>= 0; + charSize >>>= 0; + name >>>= 0; + name = AsciiToString(name); + var decodeString, encodeString, lengthBytesUTF; + if (charSize === 2) { + decodeString = UTF16ToString; + encodeString = stringToUTF16; + lengthBytesUTF = lengthBytesUTF16; + } else { + decodeString = UTF32ToString; + encodeString = stringToUTF32; + lengthBytesUTF = lengthBytesUTF32; + } + registerType(rawType, { + name, + fromWireType: value => { + // Code mostly taken from _embind_register_std_string fromWireType + var length = HEAPU32[((value) >>> 2) >>> 0]; + var str = decodeString(value + 4, length * charSize, true); + _free(value); + return str; + }, + toWireType: (destructors, value) => { + if (!(typeof value == "string")) { + throwBindingError(`Cannot pass non-string to C++ string type ${name}`); + } + // assumes POINTER_SIZE alignment + var length = lengthBytesUTF(value); + var ptr = _malloc(4 + length + charSize); + HEAPU32[((ptr) >>> 2) >>> 0] = length / charSize; + encodeString(value, ptr + 4, length + charSize); + if (destructors !== null) { + destructors.push(_free, ptr); + } + return ptr; + }, + readValueFromPointer: readPointer, + destructorFunction(ptr) { + _free(ptr); + } + }); +} + +var __embind_register_void = function(rawType, name) { + rawType >>>= 0; + name >>>= 0; + name = AsciiToString(name); + registerType(rawType, { + isVoid: true, + // void return values can be optimized out sometimes + name, + fromWireType: () => undefined, + // TODO: assert if anything else is given? + toWireType: (destructors, o) => undefined + }); +}; + +var emval_methodCallers = []; + +var emval_addMethodCaller = caller => { + var id = emval_methodCallers.length; + emval_methodCallers.push(caller); + return id; +}; + +var requireRegisteredType = (rawType, humanName) => { + var impl = registeredTypes[rawType]; + if (undefined === impl) { + throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`); + } + return impl; +}; + +var emval_lookupTypes = (argCount, argTypes) => { + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + a[i] = requireRegisteredType(HEAPU32[(((argTypes) + (i * 4)) >>> 2) >>> 0], `parameter ${i}`); + } + return a; +}; + +var emval_returnValue = (toReturnWire, destructorsRef, handle) => { + var destructors = []; + var result = toReturnWire(destructors, handle); + if (destructors.length) { + // void, primitives and any other types w/o destructors don't need to allocate a handle + HEAPU32[((destructorsRef) >>> 2) >>> 0] = Emval.toHandle(destructors); + } + return result; +}; + +var emval_symbols = {}; + +var getStringOrSymbol = address => { + var symbol = emval_symbols[address]; + if (symbol === undefined) { + return AsciiToString(address); + } + return symbol; +}; + +var __emval_create_invoker = function(argCount, argTypesPtr, kind) { + argTypesPtr >>>= 0; + var GenericWireTypeSize = 8; + var [retType, ...argTypes] = emval_lookupTypes(argCount, argTypesPtr); + var toReturnWire = retType.toWireType.bind(retType); + var argFromPtr = argTypes.map(type => type.readValueFromPointer.bind(type)); + argCount--; + // remove the extracted return type + var argN = new Array(argCount); + var invokerFunction = (handle, methodName, destructorsRef, args) => { + var offset = 0; + for (var i = 0; i < argCount; ++i) { + argN[i] = argFromPtr[i](args + offset); + offset += GenericWireTypeSize; + } + var rv; + switch (kind) { + case 0: + rv = Emval.toValue(handle).apply(null, argN); + break; + + case 2: + rv = Reflect.construct(Emval.toValue(handle), argN); + break; + + case 3: + // no-op, just return the argument + rv = argN[0]; + break; + + case 1: + rv = Emval.toValue(handle)[getStringOrSymbol(methodName)](...argN); + break; + } + return emval_returnValue(toReturnWire, destructorsRef, rv); + }; + var functionName = `methodCaller<(${argTypes.map(t => t.name)}) => ${retType.name}>`; + return emval_addMethodCaller(createNamedFunction(functionName, invokerFunction)); +}; + +function __emval_incref(handle) { + handle >>>= 0; + if (handle > 9) { + emval_handles[handle + 1] += 1; + } +} + +function __emval_invoke(caller, handle, methodName, destructorsRef, args) { + caller >>>= 0; + handle >>>= 0; + methodName >>>= 0; + destructorsRef >>>= 0; + args >>>= 0; + return emval_methodCallers[caller](handle, methodName, destructorsRef, args); +} + +function __emval_run_destructors(handle) { + handle >>>= 0; + var destructors = Emval.toValue(handle); + runDestructors(destructors); + __emval_decref(handle); +} + +function __gmtime_js(time_low, time_high, tmPtr) { + var time = convertI32PairToI53Checked(time_low, time_high); + tmPtr >>>= 0; + var date = new Date(time * 1e3); + HEAP32[((tmPtr) >>> 2) >>> 0] = date.getUTCSeconds(); + HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0] = date.getUTCMinutes(); + HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0] = date.getUTCHours(); + HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0] = date.getUTCDate(); + HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0] = date.getUTCMonth(); + HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] = date.getUTCFullYear() - 1900; + HEAP32[(((tmPtr) + (24)) >>> 2) >>> 0] = date.getUTCDay(); + var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); + var yday = ((date.getTime() - start) / (1e3 * 60 * 60 * 24)) | 0; + HEAP32[(((tmPtr) + (28)) >>> 2) >>> 0] = yday; +} + +var isLeapYear = year => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + +var MONTH_DAYS_LEAP_CUMULATIVE = [ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 ]; + +var MONTH_DAYS_REGULAR_CUMULATIVE = [ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ]; + +var ydayFromDate = date => { + var leap = isLeapYear(date.getFullYear()); + var monthDaysCumulative = (leap ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE); + var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; + // -1 since it's days since Jan 1 + return yday; +}; + +function __localtime_js(time_low, time_high, tmPtr) { + var time = convertI32PairToI53Checked(time_low, time_high); + tmPtr >>>= 0; + var date = new Date(time * 1e3); + HEAP32[((tmPtr) >>> 2) >>> 0] = date.getSeconds(); + HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0] = date.getMinutes(); + HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0] = date.getHours(); + HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0] = date.getDate(); + HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0] = date.getMonth(); + HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] = date.getFullYear() - 1900; + HEAP32[(((tmPtr) + (24)) >>> 2) >>> 0] = date.getDay(); + var yday = ydayFromDate(date) | 0; + HEAP32[(((tmPtr) + (28)) >>> 2) >>> 0] = yday; + HEAP32[(((tmPtr) + (36)) >>> 2) >>> 0] = -(date.getTimezoneOffset() * 60); + // Attention: DST is in December in South, and some regions don't have DST at all. + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset)) | 0; + HEAP32[(((tmPtr) + (32)) >>> 2) >>> 0] = dst; +} + +var setTempRet0 = val => __emscripten_tempret_set(val); + +var __mktime_js = function(tmPtr) { + tmPtr >>>= 0; + var ret = (() => { + var date = new Date(HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] + 1900, HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0], HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0], HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0], HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0], HEAP32[((tmPtr) >>> 2) >>> 0], 0); + // There's an ambiguous hour when the time goes back; the tm_isdst field is + // used to disambiguate it. Date() basically guesses, so we fix it up if it + // guessed wrong, or fill in tm_isdst with the guess if it's -1. + var dst = HEAP32[(((tmPtr) + (32)) >>> 2) >>> 0]; + var guessedOffset = date.getTimezoneOffset(); + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dstOffset = Math.min(winterOffset, summerOffset); + // DST is in December in South + if (dst < 0) { + // Attention: some regions don't have DST at all. + HEAP32[(((tmPtr) + (32)) >>> 2) >>> 0] = Number(summerOffset != winterOffset && dstOffset == guessedOffset); + } else if ((dst > 0) != (dstOffset == guessedOffset)) { + var nonDstOffset = Math.max(winterOffset, summerOffset); + var trueOffset = dst > 0 ? dstOffset : nonDstOffset; + // Don't try setMinutes(date.getMinutes() + ...) -- it's messed up. + date.setTime(date.getTime() + (trueOffset - guessedOffset) * 6e4); + } + HEAP32[(((tmPtr) + (24)) >>> 2) >>> 0] = date.getDay(); + var yday = ydayFromDate(date) | 0; + HEAP32[(((tmPtr) + (28)) >>> 2) >>> 0] = yday; + // To match expected behavior, update fields from date + HEAP32[((tmPtr) >>> 2) >>> 0] = date.getSeconds(); + HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0] = date.getMinutes(); + HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0] = date.getHours(); + HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0] = date.getDate(); + HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0] = date.getMonth(); + HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] = date.getYear(); + var timeMs = date.getTime(); + if (isNaN(timeMs)) { + return -1; + } + // Return time in microseconds + return timeMs / 1e3; + })(); + return (setTempRet0((tempDouble = ret, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0)), + ret >>> 0); +}; + +function __mmap_js(len, prot, flags, fd, offset_low, offset_high, allocated, addr) { + len >>>= 0; + var offset = convertI32PairToI53Checked(offset_low, offset_high); + allocated >>>= 0; + addr >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var res = FS.mmap(stream, len, offset, prot, flags); + var ptr = res.ptr; + HEAP32[((allocated) >>> 2) >>> 0] = res.allocated; + HEAPU32[((addr) >>> 2) >>> 0] = ptr; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function __munmap_js(addr, len, prot, flags, fd, offset_low, offset_high) { + addr >>>= 0; + len >>>= 0; + var offset = convertI32PairToI53Checked(offset_low, offset_high); + try { + var stream = SYSCALLS.getStreamFromFD(fd); + if (prot & 2) { + SYSCALLS.doMsync(addr, stream, len, flags, offset); + } + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var __tzset_js = function(timezone, daylight, std_name, dst_name) { + timezone >>>= 0; + daylight >>>= 0; + std_name >>>= 0; + dst_name >>>= 0; + // TODO: Use (malleable) environment variables instead of system settings. + var currentYear = (new Date).getFullYear(); + var winter = new Date(currentYear, 0, 1); + var summer = new Date(currentYear, 6, 1); + var winterOffset = winter.getTimezoneOffset(); + var summerOffset = summer.getTimezoneOffset(); + // Local standard timezone offset. Local standard time is not adjusted for + // daylight savings. This code uses the fact that getTimezoneOffset returns + // a greater value during Standard Time versus Daylight Saving Time (DST). + // Thus it determines the expected output during Standard Time, and it + // compares whether the output of the given date the same (Standard) or less + // (DST). + var stdTimezoneOffset = Math.max(winterOffset, summerOffset); + // timezone is specified as seconds west of UTC ("The external variable + // `timezone` shall be set to the difference, in seconds, between + // Coordinated Universal Time (UTC) and local standard time."), the same + // as returned by stdTimezoneOffset. + // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html + HEAPU32[((timezone) >>> 2) >>> 0] = stdTimezoneOffset * 60; + HEAP32[((daylight) >>> 2) >>> 0] = Number(winterOffset != summerOffset); + var extractZone = timezoneOffset => { + // Why inverse sign? + // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset + var sign = timezoneOffset >= 0 ? "-" : "+"; + var absOffset = Math.abs(timezoneOffset); + var hours = String(Math.floor(absOffset / 60)).padStart(2, "0"); + var minutes = String(absOffset % 60).padStart(2, "0"); + return `UTC${sign}${hours}${minutes}`; + }; + var winterName = extractZone(winterOffset); + var summerName = extractZone(summerOffset); + if (summerOffset < winterOffset) { + // Northern hemisphere + stringToUTF8(winterName, std_name, 17); + stringToUTF8(summerName, dst_name, 17); + } else { + stringToUTF8(winterName, dst_name, 17); + stringToUTF8(summerName, std_name, 17); + } +}; + +var _emscripten_get_now = () => performance.now(); + +var _emscripten_date_now = () => Date.now(); + +var nowIsMonotonic = 1; + +var checkWasiClock = clock_id => clock_id >= 0 && clock_id <= 3; + +function _clock_time_get(clk_id, ignored_precision_low, ignored_precision_high, ptime) { + var ignored_precision = convertI32PairToI53Checked(ignored_precision_low, ignored_precision_high); + ptime >>>= 0; + if (!checkWasiClock(clk_id)) { + return 28; + } + var now; + // all wasi clocks but realtime are monotonic + if (clk_id === 0) { + now = _emscripten_date_now(); + } else if (nowIsMonotonic) { + now = _emscripten_get_now(); + } else { + return 52; + } + // "now" is in ms, and wasi times are in ns. + var nsec = Math.round(now * 1e3 * 1e3); + (tempI64 = [ nsec >>> 0, (tempDouble = nsec, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[((ptime) >>> 2) >>> 0] = tempI64[0], HEAP32[(((ptime) + (4)) >>> 2) >>> 0] = tempI64[1]); + return 0; +} + +var readEmAsmArgsArray = []; + +var readEmAsmArgs = (sigPtr, buf) => { + readEmAsmArgsArray.length = 0; + var ch; + // Most arguments are i32s, so shift the buffer pointer so it is a plain + // index into HEAP32. + while (ch = HEAPU8[sigPtr++ >>> 0]) { + // Floats are always passed as doubles, so all types except for 'i' + // are 8 bytes and require alignment. + var wide = (ch != 105); + wide &= (ch != 112); + buf += wide && (buf % 8) ? 4 : 0; + readEmAsmArgsArray.push(// Special case for pointers under wasm64 or CAN_ADDRESS_2GB mode. + ch == 112 ? HEAPU32[((buf) >>> 2) >>> 0] : ch == 105 ? HEAP32[((buf) >>> 2) >>> 0] : HEAPF64[((buf) >>> 3) >>> 0]); + buf += wide ? 8 : 4; + } + return readEmAsmArgsArray; +}; + +var runEmAsmFunction = (code, sigPtr, argbuf) => { + var args = readEmAsmArgs(sigPtr, argbuf); + return ASM_CONSTS[code](...args); +}; + +function _emscripten_asm_const_int(code, sigPtr, argbuf) { + code >>>= 0; + sigPtr >>>= 0; + argbuf >>>= 0; + return runEmAsmFunction(code, sigPtr, argbuf); +} + +function _emscripten_errn(str, len) { + str >>>= 0; + len >>>= 0; + return err(UTF8ToString(str, len)); +} + +var getHeapMax = () => // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate +// full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side +// for any code that deals with heap sizes, which would require special +// casing all heap size related code to treat 0 specially. +4294901760; + +function _emscripten_get_heap_max() { + return getHeapMax(); +} + +var _emscripten_has_asyncify = () => 1; + +function _emscripten_outn(str, len) { + str >>>= 0; + len >>>= 0; + return out(UTF8ToString(str, len)); +} + +var UNWIND_CACHE = {}; + +var stringToNewUTF8 = str => { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8(str, ret, size); + return ret; +}; + +/** @returns {number} */ var convertFrameToPC = frame => { + var match; + if (match = /\bwasm-function\[\d+\]:(0x[0-9a-f]+)/.exec(frame)) { + // Wasm engines give the binary offset directly, so we use that as return address + return +match[1]; + } else if (match = /:(\d+):\d+(?:\)|$)/.exec(frame)) { + // If we are in js, we can use the js line number as the "return address". + // This should work for wasm2js. We tag the high bit to distinguish this + // from wasm addresses. + return 2147483648 | +match[1]; + } + // return 0 if we can't find any + return 0; +}; + +var saveInUnwindCache = callstack => { + for (var line of callstack) { + var pc = convertFrameToPC(line); + if (pc) { + UNWIND_CACHE[pc] = line; + } + } +}; + +var jsStackTrace = () => (new Error).stack.toString(); + +function _emscripten_stack_snapshot() { + var callstack = jsStackTrace().split("\n"); + if (callstack[0] == "Error") { + callstack.shift(); + } + saveInUnwindCache(callstack); + // Caches the stack snapshot so that emscripten_stack_unwind_buffer() can + // unwind from this spot. + UNWIND_CACHE.last_addr = convertFrameToPC(callstack[3]); + UNWIND_CACHE.last_stack = callstack; + return UNWIND_CACHE.last_addr; +} + +function _emscripten_pc_get_function(pc) { + pc >>>= 0; + var frame = UNWIND_CACHE[pc]; + if (!frame) return 0; + var name; + var match; + // First try to match foo.wasm.sym files explcitly. e.g. + // at test_return_address.wasm.main (wasm://wasm/test_return_address.wasm-0012cc2a:wasm-function[26]:0x9f3 + // Then match JS symbols which don't include that module name: + // at invokeEntryPoint (.../test_return_address.js:1500:42) + // Finally match firefox format: + // Object._main@http://server.com:4324:12' + if (match = /^\s+at .*\.wasm\.(.*) \(.*\)$/.exec(frame)) { + name = match[1]; + } else if (match = /^\s+at (.*) \(.*\)$/.exec(frame)) { + name = match[1]; + } else if (match = /^(.+?)@/.exec(frame)) { + name = match[1]; + } else { + return 0; + } + _free(_emscripten_pc_get_function.ret ?? 0); + _emscripten_pc_get_function.ret = stringToNewUTF8(name); + return _emscripten_pc_get_function.ret; +} + +var growMemory = size => { + var oldHeapSize = wasmMemory.buffer.byteLength; + var pages = ((size - oldHeapSize + 65535) / 65536) | 0; + try { + // round size grow request up to wasm page size (fixed 64KB per spec) + wasmMemory.grow(pages); + // .grow() takes a delta compared to the previous size + updateMemoryViews(); + return 1; + } catch (e) {} +}; + +function _emscripten_resize_heap(requestedSize) { + requestedSize >>>= 0; + var oldSize = HEAPU8.length; + // With multithreaded builds, races can happen (another thread might increase the size + // in between), so return a failure, and let the caller retry. + // Memory resize rules: + // 1. Always increase heap size to at least the requested size, rounded up + // to next page multiple. + // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap + // geometrically: increase the heap size according to + // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most + // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB). + // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap + // linearly: increase the heap size by at least + // MEMORY_GROWTH_LINEAR_STEP bytes. + // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by + // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest + // 4. If we were unable to allocate as much memory, it may be due to + // over-eager decision to excessively reserve due to (3) above. + // Hence if an allocation fails, cut down on the amount of excess + // growth, in an attempt to succeed to perform a smaller allocation. + // A limit is set for how much we can grow. We should not exceed that + // (the wasm binary specifies it, so if we tried, we'd fail anyhow). + var maxHeapSize = getHeapMax(); + if (requestedSize > maxHeapSize) { + return false; + } + // Loop through potential heap size increases. If we attempt a too eager + // reservation that fails, cut down on the attempted size and reserve a + // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + .2 / cutDown); + // ensure geometric growth + // but limit overreserving (default to capping at +96MB overgrowth at most) + overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296); + var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)); + var replacement = growMemory(newSize); + if (replacement) { + return true; + } + } + return false; +} + +function _emscripten_stack_unwind_buffer(addr, buffer, count) { + addr >>>= 0; + buffer >>>= 0; + var stack; + if (UNWIND_CACHE.last_addr == addr) { + stack = UNWIND_CACHE.last_stack; + } else { + stack = jsStackTrace().split("\n"); + if (stack[0] == "Error") { + stack.shift(); + } + saveInUnwindCache(stack); + } + var offset = 3; + while (stack[offset] && convertFrameToPC(stack[offset]) != addr) { + ++offset; + } + for (var i = 0; i < count && stack[i + offset]; ++i) { + HEAP32[(((buffer) + (i * 4)) >>> 2) >>> 0] = convertFrameToPC(stack[i + offset]); + } + return i; +} + +var GLctx; + +var webgl_enable_ANGLE_instanced_arrays = ctx => { + // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension("ANGLE_instanced_arrays"); + // Because this extension is a core function in WebGL 2, assign the extension entry points in place of + // where the core functions will reside in WebGL 2. This way the calling code can call these without + // having to dynamically branch depending if running against WebGL 1 or WebGL 2. + if (ext) { + ctx["vertexAttribDivisor"] = (index, divisor) => ext["vertexAttribDivisorANGLE"](index, divisor); + ctx["drawArraysInstanced"] = (mode, first, count, primcount) => ext["drawArraysInstancedANGLE"](mode, first, count, primcount); + ctx["drawElementsInstanced"] = (mode, count, type, indices, primcount) => ext["drawElementsInstancedANGLE"](mode, count, type, indices, primcount); + return 1; + } +}; + +var webgl_enable_OES_vertex_array_object = ctx => { + // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension("OES_vertex_array_object"); + if (ext) { + ctx["createVertexArray"] = () => ext["createVertexArrayOES"](); + ctx["deleteVertexArray"] = vao => ext["deleteVertexArrayOES"](vao); + ctx["bindVertexArray"] = vao => ext["bindVertexArrayOES"](vao); + ctx["isVertexArray"] = vao => ext["isVertexArrayOES"](vao); + return 1; + } +}; + +var webgl_enable_WEBGL_draw_buffers = ctx => { + // Extension available in WebGL 1 from Firefox 28 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension("WEBGL_draw_buffers"); + if (ext) { + ctx["drawBuffers"] = (n, bufs) => ext["drawBuffersWEBGL"](n, bufs); + return 1; + } +}; + +var webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance = ctx => // Closure is expected to be allowed to minify the '.dibvbi' property, so not accessing it quoted. +!!(ctx.dibvbi = ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance")); + +var webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance = ctx => !!(ctx.mdibvbi = ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance")); + +var webgl_enable_EXT_polygon_offset_clamp = ctx => !!(ctx.extPolygonOffsetClamp = ctx.getExtension("EXT_polygon_offset_clamp")); + +var webgl_enable_EXT_clip_control = ctx => !!(ctx.extClipControl = ctx.getExtension("EXT_clip_control")); + +var webgl_enable_WEBGL_polygon_mode = ctx => !!(ctx.webglPolygonMode = ctx.getExtension("WEBGL_polygon_mode")); + +var webgl_enable_WEBGL_multi_draw = ctx => // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted. +!!(ctx.multiDrawWebgl = ctx.getExtension("WEBGL_multi_draw")); + +var getEmscriptenSupportedExtensions = ctx => { + // Restrict the list of advertised extensions to those that we actually + // support. + var supportedExtensions = [ // WebGL 1 extensions + "ANGLE_instanced_arrays", "EXT_blend_minmax", "EXT_disjoint_timer_query", "EXT_frag_depth", "EXT_shader_texture_lod", "EXT_sRGB", "OES_element_index_uint", "OES_fbo_render_mipmap", "OES_standard_derivatives", "OES_texture_float", "OES_texture_half_float", "OES_texture_half_float_linear", "OES_vertex_array_object", "WEBGL_color_buffer_float", "WEBGL_depth_texture", "WEBGL_draw_buffers", // WebGL 2 extensions + "EXT_color_buffer_float", "EXT_conservative_depth", "EXT_disjoint_timer_query_webgl2", "EXT_texture_norm16", "NV_shader_noperspective_interpolation", "WEBGL_clip_cull_distance", // WebGL 1 and WebGL 2 extensions + "EXT_clip_control", "EXT_color_buffer_half_float", "EXT_depth_clamp", "EXT_float_blend", "EXT_polygon_offset_clamp", "EXT_texture_compression_bptc", "EXT_texture_compression_rgtc", "EXT_texture_filter_anisotropic", "KHR_parallel_shader_compile", "OES_texture_float_linear", "WEBGL_blend_func_extended", "WEBGL_compressed_texture_astc", "WEBGL_compressed_texture_etc", "WEBGL_compressed_texture_etc1", "WEBGL_compressed_texture_s3tc", "WEBGL_compressed_texture_s3tc_srgb", "WEBGL_debug_renderer_info", "WEBGL_debug_shaders", "WEBGL_lose_context", "WEBGL_multi_draw", "WEBGL_polygon_mode" ]; + // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. + return (ctx.getSupportedExtensions() || []).filter(ext => supportedExtensions.includes(ext)); +}; + +var registerPreMainLoop = f => { + // Does nothing unless $MainLoop is included/used. + typeof MainLoop != "undefined" && MainLoop.preMainLoop.push(f); +}; + +var GL = { + counter: 1, + buffers: [], + mappedBuffers: {}, + programs: [], + framebuffers: [], + renderbuffers: [], + textures: [], + shaders: [], + vaos: [], + contexts: [], + offscreenCanvases: {}, + queries: [], + samplers: [], + transformFeedbacks: [], + syncs: [], + byteSizeByTypeRoot: 5120, + byteSizeByType: [ 1, 1, 2, 2, 4, 4, 4, 2, 3, 4, 8 ], + stringCache: {}, + stringiCache: {}, + unpackAlignment: 4, + unpackRowLength: 0, + recordError: errorCode => { + if (!GL.lastError) { + GL.lastError = errorCode; + } + }, + getNewId: table => { + var ret = GL.counter++; + for (var i = table.length; i < ret; i++) { + table[i] = null; + } + // Skip over any non-null elements that might have been created by + // glBindBuffer. + while (table[ret]) { + ret = GL.counter++; + } + return ret; + }, + genObject: (n, buffers, createFunction, objectTable) => { + for (var i = 0; i < n; i++) { + var buffer = GLctx[createFunction](); + var id = buffer && GL.getNewId(objectTable); + if (buffer) { + buffer.name = id; + objectTable[id] = buffer; + } else { + GL.recordError(1282); + } + HEAP32[(((buffers) + (i * 4)) >>> 2) >>> 0] = id; + } + }, + MAX_TEMP_BUFFER_SIZE: 2097152, + numTempVertexBuffersPerSize: 64, + log2ceilLookup: i => 32 - Math.clz32(i === 0 ? 0 : i - 1), + generateTempBuffers: (quads, context) => { + var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE); + context.tempVertexBufferCounters1 = []; + context.tempVertexBufferCounters2 = []; + context.tempVertexBufferCounters1.length = context.tempVertexBufferCounters2.length = largestIndex + 1; + context.tempVertexBuffers1 = []; + context.tempVertexBuffers2 = []; + context.tempVertexBuffers1.length = context.tempVertexBuffers2.length = largestIndex + 1; + context.tempIndexBuffers = []; + context.tempIndexBuffers.length = largestIndex + 1; + for (var i = 0; i <= largestIndex; ++i) { + context.tempIndexBuffers[i] = null; + // Created on-demand + context.tempVertexBufferCounters1[i] = context.tempVertexBufferCounters2[i] = 0; + var ringbufferLength = GL.numTempVertexBuffersPerSize; + context.tempVertexBuffers1[i] = []; + context.tempVertexBuffers2[i] = []; + var ringbuffer1 = context.tempVertexBuffers1[i]; + var ringbuffer2 = context.tempVertexBuffers2[i]; + ringbuffer1.length = ringbuffer2.length = ringbufferLength; + for (var j = 0; j < ringbufferLength; ++j) { + ringbuffer1[j] = ringbuffer2[j] = null; + } + } + if (quads) { + // GL_QUAD indexes can be precalculated + context.tempQuadIndexBuffer = GLctx.createBuffer(); + context.GLctx.bindBuffer(34963, context.tempQuadIndexBuffer); + var numIndexes = GL.MAX_TEMP_BUFFER_SIZE >> 1; + var quadIndexes = new Uint16Array(numIndexes); + var i = 0, v = 0; + while (1) { + quadIndexes[i++] = v; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 1; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 2; + if (i >= numIndexes) break; + quadIndexes[i++] = v; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 2; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 3; + if (i >= numIndexes) break; + v += 4; + } + context.GLctx.bufferData(34963, quadIndexes, 35044); + context.GLctx.bindBuffer(34963, null); + } + }, + getTempVertexBuffer: sizeBytes => { + var idx = GL.log2ceilLookup(sizeBytes); + var ringbuffer = GL.currentContext.tempVertexBuffers1[idx]; + var nextFreeBufferIndex = GL.currentContext.tempVertexBufferCounters1[idx]; + GL.currentContext.tempVertexBufferCounters1[idx] = (GL.currentContext.tempVertexBufferCounters1[idx] + 1) & (GL.numTempVertexBuffersPerSize - 1); + var vbo = ringbuffer[nextFreeBufferIndex]; + if (vbo) { + return vbo; + } + var prevVBO = GLctx.getParameter(34964); + ringbuffer[nextFreeBufferIndex] = GLctx.createBuffer(); + GLctx.bindBuffer(34962, ringbuffer[nextFreeBufferIndex]); + GLctx.bufferData(34962, 1 << idx, 35048); + GLctx.bindBuffer(34962, prevVBO); + return ringbuffer[nextFreeBufferIndex]; + }, + getTempIndexBuffer: sizeBytes => { + var idx = GL.log2ceilLookup(sizeBytes); + var ibo = GL.currentContext.tempIndexBuffers[idx]; + if (ibo) { + return ibo; + } + var prevIBO = GLctx.getParameter(34965); + GL.currentContext.tempIndexBuffers[idx] = GLctx.createBuffer(); + GLctx.bindBuffer(34963, GL.currentContext.tempIndexBuffers[idx]); + GLctx.bufferData(34963, 1 << idx, 35048); + GLctx.bindBuffer(34963, prevIBO); + return GL.currentContext.tempIndexBuffers[idx]; + }, + newRenderingFrameStarted: () => { + if (!GL.currentContext) { + return; + } + var vb = GL.currentContext.tempVertexBuffers1; + GL.currentContext.tempVertexBuffers1 = GL.currentContext.tempVertexBuffers2; + GL.currentContext.tempVertexBuffers2 = vb; + vb = GL.currentContext.tempVertexBufferCounters1; + GL.currentContext.tempVertexBufferCounters1 = GL.currentContext.tempVertexBufferCounters2; + GL.currentContext.tempVertexBufferCounters2 = vb; + var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE); + for (var i = 0; i <= largestIndex; ++i) { + GL.currentContext.tempVertexBufferCounters1[i] = 0; + } + }, + getSource: (shader, count, string, length) => { + var source = ""; + for (var i = 0; i < count; ++i) { + var len = length ? HEAPU32[(((length) + (i * 4)) >>> 2) >>> 0] : undefined; + source += UTF8ToString(HEAPU32[(((string) + (i * 4)) >>> 2) >>> 0], len); + } + return source; + }, + calcBufLength: (size, type, stride, count) => { + if (stride > 0) { + return count * stride; + } + var typeSize = GL.byteSizeByType[type - GL.byteSizeByTypeRoot]; + return size * typeSize * count; + }, + usedTempBuffers: [], + preDrawHandleClientVertexAttribBindings: count => { + GL.resetBufferBinding = false; + // TODO: initial pass to detect ranges we need to upload, might not need + // an upload per attrib + for (var i = 0; i < GL.currentContext.maxVertexAttribs; ++i) { + var cb = GL.currentContext.clientBuffers[i]; + if (!cb.clientside || !cb.enabled) continue; + GL.resetBufferBinding = true; + var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count); + var buf = GL.getTempVertexBuffer(size); + GLctx.bindBuffer(34962, buf); + GLctx.bufferSubData(34962, 0, HEAPU8.subarray(cb.ptr >>> 0, cb.ptr + size >>> 0)); + cb.vertexAttribPointerAdaptor.call(GLctx, i, cb.size, cb.type, cb.normalized, cb.stride, 0); + } + }, + postDrawHandleClientVertexAttribBindings: () => { + if (GL.resetBufferBinding) { + GLctx.bindBuffer(34962, GL.buffers[GLctx.currentArrayBufferBinding]); + } + }, + createContext: (/** @type {HTMLCanvasElement} */ canvas, webGLContextAttributes) => { + // BUG: Workaround Safari WebGL issue: After successfully acquiring WebGL + // context on a canvas, calling .getContext() will always return that + // context independent of which 'webgl' or 'webgl2' + // context version was passed. See: + // https://webkit.org/b/222758 + // and: + // https://github.com/emscripten-core/emscripten/issues/13295. + // TODO: Once the bug is fixed and shipped in Safari, adjust the Safari + // version field in above check. + if (!canvas.getContextSafariWebGL2Fixed) { + canvas.getContextSafariWebGL2Fixed = canvas.getContext; + /** @type {function(this:HTMLCanvasElement, string, (Object|null)=): (Object|null)} */ function fixedGetContext(ver, attrs) { + var gl = canvas.getContextSafariWebGL2Fixed(ver, attrs); + return ((ver == "webgl") == (gl instanceof WebGLRenderingContext)) ? gl : null; + } + canvas.getContext = fixedGetContext; + } + var ctx = (webGLContextAttributes.majorVersion > 1) ? canvas.getContext("webgl2", webGLContextAttributes) : canvas.getContext("webgl", webGLContextAttributes); + if (!ctx) return 0; + var handle = GL.registerContext(ctx, webGLContextAttributes); + return handle; + }, + registerContext: (ctx, webGLContextAttributes) => { + // without pthreads a context is just an integer ID + var handle = GL.getNewId(GL.contexts); + var context = { + handle, + attributes: webGLContextAttributes, + version: webGLContextAttributes.majorVersion, + GLctx: ctx + }; + // Store the created context object so that we can access the context + // given a canvas without having to pass the parameters again. + if (ctx.canvas) ctx.canvas.GLctxObject = context; + GL.contexts[handle] = context; + if (typeof webGLContextAttributes.enableExtensionsByDefault == "undefined" || webGLContextAttributes.enableExtensionsByDefault) { + GL.initExtensions(context); + } + context.maxVertexAttribs = context.GLctx.getParameter(34921); + context.clientBuffers = []; + for (var i = 0; i < context.maxVertexAttribs; i++) { + context.clientBuffers[i] = { + enabled: false, + clientside: false, + size: 0, + type: 0, + normalized: 0, + stride: 0, + ptr: 0, + vertexAttribPointerAdaptor: null + }; + } + GL.generateTempBuffers(false, context); + return handle; + }, + makeContextCurrent: contextHandle => { + // Active Emscripten GL layer context object. + GL.currentContext = GL.contexts[contextHandle]; + // Active WebGL context object. + Module["ctx"] = GLctx = GL.currentContext?.GLctx; + return !(contextHandle && !GLctx); + }, + getContext: contextHandle => GL.contexts[contextHandle], + deleteContext: contextHandle => { + if (GL.currentContext === GL.contexts[contextHandle]) { + GL.currentContext = null; + } + if (typeof JSEvents == "object") { + // Release all JS event handlers on the DOM element that the GL context is + // associated with since the context is now deleted. + JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); + } + // Make sure the canvas object no longer refers to the context object so + // there are no GC surprises. + if (GL.contexts[contextHandle]?.GLctx.canvas) { + GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; + } + GL.contexts[contextHandle] = null; + }, + initExtensions: context => { + // If this function is called without a specific context object, init the + // extensions of the currently active context. + context ||= GL.currentContext; + if (context.initExtensionsDone) return; + context.initExtensionsDone = true; + var GLctx = context.GLctx; + // Detect the presence of a few extensions manually, since the GL interop + // layer itself will need to know if they exist. + // Extensions that are available in both WebGL 1 and WebGL 2 + webgl_enable_WEBGL_multi_draw(GLctx); + webgl_enable_EXT_polygon_offset_clamp(GLctx); + webgl_enable_EXT_clip_control(GLctx); + webgl_enable_WEBGL_polygon_mode(GLctx); + // Extensions that are only available in WebGL 1 (the calls will be no-ops + // if called on a WebGL 2 context active) + webgl_enable_ANGLE_instanced_arrays(GLctx); + webgl_enable_OES_vertex_array_object(GLctx); + webgl_enable_WEBGL_draw_buffers(GLctx); + // Extensions that are available from WebGL >= 2 (no-op if called on a WebGL 1 context active) + webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx); + webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx); + // On WebGL 2, EXT_disjoint_timer_query is replaced with an alternative + // that's based on core APIs, and exposes only the queryCounterEXT() + // entrypoint. + if (context.version >= 2) { + GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query_webgl2"); + } + // However, Firefox exposes the WebGL 1 version on WebGL 2 as well and + // thus we look for the WebGL 1 version again if the WebGL 2 version + // isn't present. https://bugzil.la/1328882 + if (context.version < 2 || !GLctx.disjointTimerQueryExt) { + GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query"); + } + for (var ext of getEmscriptenSupportedExtensions(GLctx)) { + // WEBGL_lose_context, WEBGL_debug_renderer_info and WEBGL_debug_shaders + // are not enabled by default. + if (!ext.includes("lose_context") && !ext.includes("debug")) { + // Call .getExtension() to enable that extension permanently. + GLctx.getExtension(ext); + } + } + } +}; + +var webglPowerPreferences = [ "default", "low-power", "high-performance" ]; + +/** @type {Object} */ var specialHTMLTargets = [ 0, globalThis.document ?? 0, globalThis.window ?? 0 ]; + +var findEventTarget = target => { + // The sensible "default" target varies between events, but use window as the default + // since DOM events mostly can default to that. Specific callback registrations + // override their own defaults. + if (!target) return window; + if (typeof target == "number") target = specialHTMLTargets[target] || UTF8ToString(target); + if (target === "#window") return window; else if (target === "#document") return document; else if (target === "#screen") return screen; else if (target === "#canvas") return Module["canvas"]; else if (typeof target == "string") return globalThis.document?.getElementById(target); + return target; +}; + +var findCanvasEventTarget = target => { + if (typeof target == "number") target = UTF8ToString(target); + if (!target || target === "#canvas") { + if (typeof GL != "undefined" && GL.offscreenCanvases["canvas"]) return GL.offscreenCanvases["canvas"]; + // TODO: Remove this line, target '#canvas' should refer only to Module['canvas'], not to GL.offscreenCanvases['canvas'] - but need stricter tests to be able to remove this line. + return Module["canvas"]; + } + if (typeof GL != "undefined" && GL.offscreenCanvases[target]) return GL.offscreenCanvases[target]; + return findEventTarget(target); +}; + +function _emscripten_webgl_do_create_context(target, attributes) { + target >>>= 0; + attributes >>>= 0; + var attr32 = ((attributes) >>> 2); + var powerPreference = HEAP32[attr32 + (8 >> 2) >>> 0]; + var contextAttributes = { + "alpha": !!HEAP8[attributes + 0 >>> 0], + "depth": !!HEAP8[attributes + 1 >>> 0], + "stencil": !!HEAP8[attributes + 2 >>> 0], + "antialias": !!HEAP8[attributes + 3 >>> 0], + "premultipliedAlpha": !!HEAP8[attributes + 4 >>> 0], + "preserveDrawingBuffer": !!HEAP8[attributes + 5 >>> 0], + "powerPreference": webglPowerPreferences[powerPreference], + "failIfMajorPerformanceCaveat": !!HEAP8[attributes + 12 >>> 0], + // The following are not predefined WebGL context attributes in the WebGL specification, so the property names can be minified by Closure. + majorVersion: HEAP32[attr32 + (16 >> 2) >>> 0], + minorVersion: HEAP32[attr32 + (20 >> 2) >>> 0], + enableExtensionsByDefault: HEAP8[attributes + 24 >>> 0], + explicitSwapControl: HEAP8[attributes + 25 >>> 0], + proxyContextToMainThread: HEAP32[attr32 + (28 >> 2) >>> 0], + renderViaOffscreenBackBuffer: HEAP8[attributes + 32 >>> 0] + }; + var canvas = findCanvasEventTarget(target); + if (!canvas) { + return 0; + } + if (contextAttributes.explicitSwapControl) { + return 0; + } + var contextHandle = GL.createContext(canvas, contextAttributes); + return contextHandle; +} + +var _emscripten_webgl_create_context = _emscripten_webgl_do_create_context; + +function _emscripten_webgl_destroy_context(contextHandle) { + contextHandle >>>= 0; + if (GL.currentContext == contextHandle) GL.currentContext = 0; + GL.deleteContext(contextHandle); +} + +function _emscripten_webgl_get_context_attributes(c, a) { + c >>>= 0; + a >>>= 0; + if (!a) return -5; + c = GL.contexts[c]; + if (!c) return -3; + var t = c.GLctx?.getContextAttributes(); + if (!t) return -3; + HEAP8[a >>> 0] = t.alpha; + HEAP8[(a) + (1) >>> 0] = t.depth; + HEAP8[(a) + (2) >>> 0] = t.stencil; + HEAP8[(a) + (3) >>> 0] = t.antialias; + HEAP8[(a) + (4) >>> 0] = t.premultipliedAlpha; + HEAP8[(a) + (5) >>> 0] = t.preserveDrawingBuffer; + var power = t["powerPreference"] && webglPowerPreferences.indexOf(t["powerPreference"]); + HEAP32[(((a) + (8)) >>> 2) >>> 0] = power; + HEAP8[(a) + (12) >>> 0] = t.failIfMajorPerformanceCaveat; + HEAP32[(((a) + (16)) >>> 2) >>> 0] = c.version; + HEAP32[(((a) + (20)) >>> 2) >>> 0] = 0; + HEAP8[(a) + (24) >>> 0] = c.attributes.enableExtensionsByDefault; + return 0; +} + +function _emscripten_webgl_do_get_current_context() { + return GL.currentContext ? GL.currentContext.handle : 0; +} + +var _emscripten_webgl_get_current_context = _emscripten_webgl_do_get_current_context; + +function _emscripten_webgl_make_context_current(contextHandle) { + contextHandle >>>= 0; + var success = GL.makeContextCurrent(contextHandle); + return success ? 0 : -5; +} + +var stackAlloc = sz => __emscripten_stack_alloc(sz); + +var stringToUTF8OnStack = str => { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8(str, ret, size); + return ret; +}; + +var writeI53ToI64 = (ptr, num) => { + HEAPU32[((ptr) >>> 2) >>> 0] = num; + var lower = HEAPU32[((ptr) >>> 2) >>> 0]; + HEAPU32[(((ptr) + (4)) >>> 2) >>> 0] = (num - lower) / 4294967296; +}; + +var readI53FromI64 = ptr => HEAPU32[((ptr) >>> 2) >>> 0] + HEAP32[(((ptr) + (4)) >>> 2) >>> 0] * 4294967296; + +var WebGPU = { + Internals: { + jsObjects: [], + jsObjectInsert: (ptr, jsObject) => { + ptr >>>= 0; + WebGPU.Internals.jsObjects[ptr] = jsObject; + }, + bufferOnUnmaps: [], + futures: [], + futureInsert: (futureId, promise) => { + WebGPU.Internals.futures[futureId] = new Promise(resolve => promise.finally(() => resolve(futureId))); + } + }, + getJsObject: ptr => { + if (!ptr) return undefined; + ptr >>>= 0; + return WebGPU.Internals.jsObjects[ptr]; + }, + importJsAdapter: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateAdapter(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsBindGroup: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateBindGroup(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsBindGroupLayout: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateBindGroupLayout(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsBuffer: (buffer, parentPtr = 0) => { + // At the moment, we do not allow importing pending buffers. + assert(buffer.mapState === "unmapped"); + var bufferPtr = _emwgpuImportBuffer(parentPtr); + WebGPU.Internals.jsObjectInsert(bufferPtr, buffer); + return bufferPtr; + }, + importJsCommandBuffer: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateCommandBuffer(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsCommandEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateCommandEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsComputePassEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateComputePassEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsComputePipeline: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateComputePipeline(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsDevice: (device, parentPtr = 0) => { + var queuePtr = _emwgpuCreateQueue(parentPtr); + var devicePtr = _emwgpuCreateDevice(parentPtr, queuePtr); + WebGPU.Internals.jsObjectInsert(queuePtr, device.queue); + WebGPU.Internals.jsObjectInsert(devicePtr, device); + return devicePtr; + }, + importJsExternalTexture: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateExternalTexture(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsPipelineLayout: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreatePipelineLayout(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsQuerySet: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateQuerySet(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsQueue: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateQueue(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderBundle: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderBundle(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderBundleEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderBundleEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderPassEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderPassEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderPipeline: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderPipeline(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsSampler: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateSampler(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsShaderModule: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateShaderModule(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsSurface: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateSurface(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsTexture: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateTexture(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsTextureView: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateTextureView(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + errorCallback: (callback, type, message, userdata) => { + var sp = stackSave(); + var messagePtr = stringToUTF8OnStack(message); + ((a1, a2, a3) => dynCall_viii(callback, a1, a2, a3))(type, messagePtr, userdata); + stackRestore(sp); + }, + iterateExtensions: (root, handlers) => { + for (var ptr = HEAPU32[((root) >>> 2) >>> 0]; ptr; ptr = HEAPU32[((ptr) >>> 2) >>> 0]) { + var sType = HEAP32[(((ptr) + (4)) >>> 2) >>> 0]; + // This will crash if there's no handler indicating either a bogus + // sType, or one we haven't implemented yet. + var handler = handlers[sType](ptr); + } + }, + setStringView: (ptr, data, length) => { + HEAPU32[((ptr) >>> 2) >>> 0] = data; + HEAPU32[(((ptr) + (4)) >>> 2) >>> 0] = length; + }, + makeStringFromStringView: stringViewPtr => { + var ptr = HEAPU32[((stringViewPtr) >>> 2) >>> 0]; + var length = HEAPU32[(((stringViewPtr) + (4)) >>> 2) >>> 0]; + // UTF8ToString stops at the first null terminator character in the + // string regardless of the length. + return UTF8ToString(ptr, length); + }, + makeStringFromOptionalStringView: stringViewPtr => { + var ptr = HEAPU32[((stringViewPtr) >>> 2) >>> 0]; + var length = HEAPU32[(((stringViewPtr) + (4)) >>> 2) >>> 0]; + // If we don't have a valid string pointer, just return undefined when + // optional. + if (!ptr) { + if (length === 0) { + return ""; + } + return undefined; + } + // UTF8ToString stops at the first null terminator character in the + // string regardless of the length. + return UTF8ToString(ptr, length); + }, + makeColor: ptr => ({ + "r": HEAPF64[((ptr) >>> 3) >>> 0], + "g": HEAPF64[(((ptr) + (8)) >>> 3) >>> 0], + "b": HEAPF64[(((ptr) + (16)) >>> 3) >>> 0], + "a": HEAPF64[(((ptr) + (24)) >>> 3) >>> 0] + }), + makeExtent3D: ptr => ({ + "width": HEAPU32[((ptr) >>> 2) >>> 0], + "height": HEAPU32[(((ptr) + (4)) >>> 2) >>> 0], + "depthOrArrayLayers": HEAPU32[(((ptr) + (8)) >>> 2) >>> 0] + }), + makeOrigin3D: ptr => ({ + "x": HEAPU32[((ptr) >>> 2) >>> 0], + "y": HEAPU32[(((ptr) + (4)) >>> 2) >>> 0], + "z": HEAPU32[(((ptr) + (8)) >>> 2) >>> 0] + }), + makeTexelCopyTextureInfo: ptr => ({ + "texture": WebGPU.getJsObject(HEAPU32[((ptr) >>> 2) >>> 0]), + "mipLevel": HEAPU32[(((ptr) + (4)) >>> 2) >>> 0], + "origin": WebGPU.makeOrigin3D(ptr + 8), + "aspect": WebGPU.TextureAspect[HEAP32[(((ptr) + (20)) >>> 2) >>> 0]] + }), + makeTexelCopyBufferLayout: ptr => { + var bytesPerRow = HEAPU32[(((ptr) + (8)) >>> 2) >>> 0]; + var rowsPerImage = HEAPU32[(((ptr) + (12)) >>> 2) >>> 0]; + return { + "offset": readI53FromI64(ptr), + "bytesPerRow": bytesPerRow === 4294967295 ? undefined : bytesPerRow, + "rowsPerImage": rowsPerImage === 4294967295 ? undefined : rowsPerImage + }; + }, + makeTexelCopyBufferInfo: ptr => { + var layoutPtr = ptr + 0; + var bufferCopyView = WebGPU.makeTexelCopyBufferLayout(layoutPtr); + bufferCopyView["buffer"] = WebGPU.getJsObject(HEAPU32[(((ptr) + (16)) >>> 2) >>> 0]); + return bufferCopyView; + }, + makePassTimestampWrites: ptr => { + if (ptr === 0) return undefined; + return { + "querySet": WebGPU.getJsObject(HEAPU32[(((ptr) + (4)) >>> 2) >>> 0]), + "beginningOfPassWriteIndex": HEAPU32[(((ptr) + (8)) >>> 2) >>> 0], + "endOfPassWriteIndex": HEAPU32[(((ptr) + (12)) >>> 2) >>> 0] + }; + }, + makePipelineConstants: (constantCount, constantsPtr) => { + if (!constantCount) return; + var constants = {}; + for (var i = 0; i < constantCount; ++i) { + var entryPtr = constantsPtr + 24 * i; + var key = WebGPU.makeStringFromStringView(entryPtr + 4); + constants[key] = HEAPF64[(((entryPtr) + (16)) >>> 3) >>> 0]; + } + return constants; + }, + makePipelineLayout: layoutPtr => { + if (!layoutPtr) return "auto"; + return WebGPU.getJsObject(layoutPtr); + }, + makeComputeState: ptr => { + if (!ptr) return undefined; + var desc = { + "module": WebGPU.getJsObject(HEAPU32[(((ptr) + (4)) >>> 2) >>> 0]), + "constants": WebGPU.makePipelineConstants(HEAPU32[(((ptr) + (16)) >>> 2) >>> 0], HEAPU32[(((ptr) + (20)) >>> 2) >>> 0]), + "entryPoint": WebGPU.makeStringFromOptionalStringView(ptr + 8) + }; + return desc; + }, + makeComputePipelineDesc: descriptor => { + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "layout": WebGPU.makePipelineLayout(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]), + "compute": WebGPU.makeComputeState(descriptor + 16) + }; + return desc; + }, + makeRenderPipelineDesc: descriptor => { + function makePrimitiveState(psPtr) { + if (!psPtr) return undefined; + return { + "topology": WebGPU.PrimitiveTopology[HEAP32[(((psPtr) + (4)) >>> 2) >>> 0]], + "stripIndexFormat": WebGPU.IndexFormat[HEAP32[(((psPtr) + (8)) >>> 2) >>> 0]], + "frontFace": WebGPU.FrontFace[HEAP32[(((psPtr) + (12)) >>> 2) >>> 0]], + "cullMode": WebGPU.CullMode[HEAP32[(((psPtr) + (16)) >>> 2) >>> 0]], + "unclippedDepth": !!(HEAPU32[(((psPtr) + (20)) >>> 2) >>> 0]) + }; + } + function makeBlendComponent(bdPtr) { + if (!bdPtr) return undefined; + return { + "operation": WebGPU.BlendOperation[HEAP32[((bdPtr) >>> 2) >>> 0]], + "srcFactor": WebGPU.BlendFactor[HEAP32[(((bdPtr) + (4)) >>> 2) >>> 0]], + "dstFactor": WebGPU.BlendFactor[HEAP32[(((bdPtr) + (8)) >>> 2) >>> 0]] + }; + } + function makeBlendState(bsPtr) { + if (!bsPtr) return undefined; + return { + "alpha": makeBlendComponent(bsPtr + 12), + "color": makeBlendComponent(bsPtr + 0) + }; + } + function makeColorState(csPtr) { + var format = WebGPU.TextureFormat[HEAP32[(((csPtr) + (4)) >>> 2) >>> 0]]; + return format ? { + "format": format, + "blend": makeBlendState(HEAPU32[(((csPtr) + (8)) >>> 2) >>> 0]), + "writeMask": HEAPU32[(((csPtr) + (16)) >>> 2) >>> 0] + } : undefined; + } + function makeColorStates(count, csArrayPtr) { + var states = []; + for (var i = 0; i < count; ++i) { + states.push(makeColorState(csArrayPtr + 24 * i)); + } + return states; + } + function makeStencilStateFace(ssfPtr) { + return { + "compare": WebGPU.CompareFunction[HEAP32[((ssfPtr) >>> 2) >>> 0]], + "failOp": WebGPU.StencilOperation[HEAP32[(((ssfPtr) + (4)) >>> 2) >>> 0]], + "depthFailOp": WebGPU.StencilOperation[HEAP32[(((ssfPtr) + (8)) >>> 2) >>> 0]], + "passOp": WebGPU.StencilOperation[HEAP32[(((ssfPtr) + (12)) >>> 2) >>> 0]] + }; + } + function makeDepthStencilState(dssPtr) { + if (!dssPtr) return undefined; + return { + "format": WebGPU.TextureFormat[HEAP32[(((dssPtr) + (4)) >>> 2) >>> 0]], + "depthWriteEnabled": !!(HEAPU32[(((dssPtr) + (8)) >>> 2) >>> 0]), + "depthCompare": WebGPU.CompareFunction[HEAP32[(((dssPtr) + (12)) >>> 2) >>> 0]], + "stencilFront": makeStencilStateFace(dssPtr + 16), + "stencilBack": makeStencilStateFace(dssPtr + 32), + "stencilReadMask": HEAPU32[(((dssPtr) + (48)) >>> 2) >>> 0], + "stencilWriteMask": HEAPU32[(((dssPtr) + (52)) >>> 2) >>> 0], + "depthBias": HEAP32[(((dssPtr) + (56)) >>> 2) >>> 0], + "depthBiasSlopeScale": HEAPF32[(((dssPtr) + (60)) >>> 2) >>> 0], + "depthBiasClamp": HEAPF32[(((dssPtr) + (64)) >>> 2) >>> 0] + }; + } + function makeVertexAttribute(vaPtr) { + return { + "format": WebGPU.VertexFormat[HEAP32[(((vaPtr) + (4)) >>> 2) >>> 0]], + "offset": readI53FromI64((vaPtr) + (8)), + "shaderLocation": HEAPU32[(((vaPtr) + (16)) >>> 2) >>> 0] + }; + } + function makeVertexAttributes(count, vaArrayPtr) { + var vas = []; + for (var i = 0; i < count; ++i) { + vas.push(makeVertexAttribute(vaArrayPtr + i * 24)); + } + return vas; + } + function makeVertexBuffer(vbPtr) { + if (!vbPtr) return undefined; + var stepMode = WebGPU.VertexStepMode[HEAP32[(((vbPtr) + (4)) >>> 2) >>> 0]]; + var attributeCount = HEAPU32[(((vbPtr) + (16)) >>> 2) >>> 0]; + if (!stepMode && !attributeCount) { + return null; + } + return { + "arrayStride": readI53FromI64((vbPtr) + (8)), + "stepMode": stepMode, + "attributes": makeVertexAttributes(attributeCount, HEAPU32[(((vbPtr) + (20)) >>> 2) >>> 0]) + }; + } + function makeVertexBuffers(count, vbArrayPtr) { + if (!count) return undefined; + var vbs = []; + for (var i = 0; i < count; ++i) { + vbs.push(makeVertexBuffer(vbArrayPtr + i * 24)); + } + return vbs; + } + function makeVertexState(viPtr) { + if (!viPtr) return undefined; + var desc = { + "module": WebGPU.getJsObject(HEAPU32[(((viPtr) + (4)) >>> 2) >>> 0]), + "constants": WebGPU.makePipelineConstants(HEAPU32[(((viPtr) + (16)) >>> 2) >>> 0], HEAPU32[(((viPtr) + (20)) >>> 2) >>> 0]), + "buffers": makeVertexBuffers(HEAPU32[(((viPtr) + (24)) >>> 2) >>> 0], HEAPU32[(((viPtr) + (28)) >>> 2) >>> 0]), + "entryPoint": WebGPU.makeStringFromOptionalStringView(viPtr + 8) + }; + return desc; + } + function makeMultisampleState(msPtr) { + if (!msPtr) return undefined; + return { + "count": HEAPU32[(((msPtr) + (4)) >>> 2) >>> 0], + "mask": HEAPU32[(((msPtr) + (8)) >>> 2) >>> 0], + "alphaToCoverageEnabled": !!(HEAPU32[(((msPtr) + (12)) >>> 2) >>> 0]) + }; + } + function makeFragmentState(fsPtr) { + if (!fsPtr) return undefined; + var desc = { + "module": WebGPU.getJsObject(HEAPU32[(((fsPtr) + (4)) >>> 2) >>> 0]), + "constants": WebGPU.makePipelineConstants(HEAPU32[(((fsPtr) + (16)) >>> 2) >>> 0], HEAPU32[(((fsPtr) + (20)) >>> 2) >>> 0]), + "targets": makeColorStates(HEAPU32[(((fsPtr) + (24)) >>> 2) >>> 0], HEAPU32[(((fsPtr) + (28)) >>> 2) >>> 0]), + "entryPoint": WebGPU.makeStringFromOptionalStringView(fsPtr + 8) + }; + return desc; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "layout": WebGPU.makePipelineLayout(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]), + "vertex": makeVertexState(descriptor + 16), + "primitive": makePrimitiveState(descriptor + 48), + "depthStencil": makeDepthStencilState(HEAPU32[(((descriptor) + (72)) >>> 2) >>> 0]), + "multisample": makeMultisampleState(descriptor + 76), + "fragment": makeFragmentState(HEAPU32[(((descriptor) + (92)) >>> 2) >>> 0]) + }; + return desc; + }, + fillLimitStruct: (limits, limitsOutPtr) => { + var nextInChainPtr = HEAPU32[((limitsOutPtr) >>> 2) >>> 0]; + function setLimitValueU32(name, basePtr, limitOffset, fallbackValue = 0) { + var limitValue = limits[name] ?? fallbackValue; + HEAPU32[(((basePtr) + (limitOffset)) >>> 2) >>> 0] = limitValue; + } + function setLimitValueU64(name, basePtr, limitOffset, fallbackValue = 0) { + var limitValue = limits[name] ?? fallbackValue; + // Limits are integer-valued JS `Number`s, so they fit in 'i53'. + writeI53ToI64((basePtr) + (limitOffset), limitValue); + } + setLimitValueU32("maxTextureDimension1D", limitsOutPtr, 4); + setLimitValueU32("maxTextureDimension2D", limitsOutPtr, 8); + setLimitValueU32("maxTextureDimension3D", limitsOutPtr, 12); + setLimitValueU32("maxTextureArrayLayers", limitsOutPtr, 16); + setLimitValueU32("maxBindGroups", limitsOutPtr, 20); + setLimitValueU32("maxBindGroupsPlusVertexBuffers", limitsOutPtr, 24); + setLimitValueU32("maxBindingsPerBindGroup", limitsOutPtr, 28); + setLimitValueU32("maxDynamicUniformBuffersPerPipelineLayout", limitsOutPtr, 32); + setLimitValueU32("maxDynamicStorageBuffersPerPipelineLayout", limitsOutPtr, 36); + setLimitValueU32("maxSampledTexturesPerShaderStage", limitsOutPtr, 40); + setLimitValueU32("maxSamplersPerShaderStage", limitsOutPtr, 44); + setLimitValueU32("maxStorageBuffersPerShaderStage", limitsOutPtr, 48); + setLimitValueU32("maxStorageTexturesPerShaderStage", limitsOutPtr, 52); + setLimitValueU32("maxUniformBuffersPerShaderStage", limitsOutPtr, 56); + setLimitValueU32("minUniformBufferOffsetAlignment", limitsOutPtr, 80); + setLimitValueU32("minStorageBufferOffsetAlignment", limitsOutPtr, 84); + setLimitValueU64("maxUniformBufferBindingSize", limitsOutPtr, 64); + setLimitValueU64("maxStorageBufferBindingSize", limitsOutPtr, 72); + setLimitValueU32("maxVertexBuffers", limitsOutPtr, 88); + setLimitValueU64("maxBufferSize", limitsOutPtr, 96); + setLimitValueU32("maxVertexAttributes", limitsOutPtr, 104); + setLimitValueU32("maxVertexBufferArrayStride", limitsOutPtr, 108); + setLimitValueU32("maxInterStageShaderVariables", limitsOutPtr, 112); + setLimitValueU32("maxColorAttachments", limitsOutPtr, 116); + setLimitValueU32("maxColorAttachmentBytesPerSample", limitsOutPtr, 120); + setLimitValueU32("maxComputeWorkgroupStorageSize", limitsOutPtr, 124); + setLimitValueU32("maxComputeInvocationsPerWorkgroup", limitsOutPtr, 128); + setLimitValueU32("maxComputeWorkgroupSizeX", limitsOutPtr, 132); + setLimitValueU32("maxComputeWorkgroupSizeY", limitsOutPtr, 136); + setLimitValueU32("maxComputeWorkgroupSizeZ", limitsOutPtr, 140); + setLimitValueU32("maxComputeWorkgroupsPerDimension", limitsOutPtr, 144); + // Note this limit is new and won't be present in all browsers for a while. Fall back to 0. + setLimitValueU32("maxImmediateSize", limitsOutPtr, 148); + if (nextInChainPtr !== 0) { + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var compatibilityModeLimitsPtr = nextInChainPtr; + // Note these limits are new and won't be present in all browsers for a while. Fall back to exposing the PerShaderStage limit. + setLimitValueU32("maxStorageBuffersInVertexStage", compatibilityModeLimitsPtr, 8, limits.maxStorageBuffersPerShaderStage); + setLimitValueU32("maxStorageBuffersInFragmentStage", compatibilityModeLimitsPtr, 16, limits.maxStorageBuffersPerShaderStage); + setLimitValueU32("maxStorageTexturesInVertexStage", compatibilityModeLimitsPtr, 12, limits.maxStorageTexturesPerShaderStage); + setLimitValueU32("maxStorageTexturesInFragmentStage", compatibilityModeLimitsPtr, 20, limits.maxStorageTexturesPerShaderStage); + } + }, + fillAdapterInfoStruct: (info, infoStruct) => { + // Populate subgroup limits. + HEAPU32[(((infoStruct) + (52)) >>> 2) >>> 0] = info.subgroupMinSize; + HEAPU32[(((infoStruct) + (56)) >>> 2) >>> 0] = info.subgroupMaxSize; + // Append all the strings together to condense into a single malloc. + var strs = info.vendor + info.architecture + info.device + info.description; + var strPtr = stringToNewUTF8(strs); + var vendorLen = lengthBytesUTF8(info.vendor); + WebGPU.setStringView(infoStruct + 4, strPtr, vendorLen); + strPtr += vendorLen; + var architectureLen = lengthBytesUTF8(info.architecture); + WebGPU.setStringView(infoStruct + 12, strPtr, architectureLen); + strPtr += architectureLen; + var deviceLen = lengthBytesUTF8(info.device); + WebGPU.setStringView(infoStruct + 20, strPtr, deviceLen); + strPtr += deviceLen; + var descriptionLen = lengthBytesUTF8(info.description); + WebGPU.setStringView(infoStruct + 28, strPtr, descriptionLen); + strPtr += descriptionLen; + HEAP32[(((infoStruct) + (36)) >>> 2) >>> 0] = 2; + var adapterType = info.isFallbackAdapter ? 3 : 4; + HEAP32[(((infoStruct) + (40)) >>> 2) >>> 0] = adapterType; + HEAPU32[(((infoStruct) + (44)) >>> 2) >>> 0] = 0; + HEAPU32[(((infoStruct) + (48)) >>> 2) >>> 0] = 0; + }, + AddressMode: [ , "clamp-to-edge", "repeat", "mirror-repeat" ], + BlendFactor: [ , "zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", "src1", "one-minus-src1", "src1-alpha", "one-minus-src1-alpha" ], + BlendOperation: [ , "add", "subtract", "reverse-subtract", "min", "max" ], + BufferBindingType: [ , , "uniform", "storage", "read-only-storage" ], + BufferMapState: [ , "unmapped", "pending", "mapped" ], + CompareFunction: [ , "never", "less", "equal", "less-equal", "greater", "not-equal", "greater-equal", "always" ], + CompilationInfoRequestStatus: [ , "success", "callback-cancelled" ], + ComponentSwizzle: [ , "0", "1", "r", "g", "b", "a" ], + CompositeAlphaMode: [ , "opaque", "premultiplied", "unpremultiplied", "inherit" ], + CullMode: [ , "none", "front", "back" ], + ErrorFilter: [ , "validation", "out-of-memory", "internal" ], + FeatureLevel: [ , "compatibility", "core" ], + FeatureName: { + 1: "core-features-and-limits", + 2: "depth-clip-control", + 3: "depth32float-stencil8", + 4: "texture-compression-bc", + 5: "texture-compression-bc-sliced-3d", + 6: "texture-compression-etc2", + 7: "texture-compression-astc", + 8: "texture-compression-astc-sliced-3d", + 9: "timestamp-query", + 10: "indirect-first-instance", + 11: "shader-f16", + 12: "rg11b10ufloat-renderable", + 13: "bgra8unorm-storage", + 14: "float32-filterable", + 15: "float32-blendable", + 16: "clip-distances", + 17: "dual-source-blending", + 18: "subgroups", + 19: "texture-formats-tier1", + 20: "texture-formats-tier2", + 21: "primitive-index", + 22: "texture-component-swizzle", + 327692: "chromium-experimental-unorm16-texture-formats", + 327729: "chromium-experimental-multi-draw-indirect" + }, + FilterMode: [ , "nearest", "linear" ], + FrontFace: [ , "ccw", "cw" ], + IndexFormat: [ , "uint16", "uint32" ], + InstanceFeatureName: [ , "timed-wait-any", "shader-source-spirv", "multiple-devices-per-adapter" ], + LoadOp: [ , "load", "clear" ], + MipmapFilterMode: [ , "nearest", "linear" ], + OptionalBool: [ "false", "true" ], + PowerPreference: [ , "low-power", "high-performance" ], + PredefinedColorSpace: [ , "srgb", "display-p3" ], + PrimitiveTopology: [ , "point-list", "line-list", "line-strip", "triangle-list", "triangle-strip" ], + QueryType: [ , "occlusion", "timestamp" ], + SamplerBindingType: [ , , "filtering", "non-filtering", "comparison" ], + Status: [ , "success", "error" ], + StencilOperation: [ , "keep", "zero", "replace", "invert", "increment-clamp", "decrement-clamp", "increment-wrap", "decrement-wrap" ], + StorageTextureAccess: [ , , "write-only", "read-only", "read-write" ], + StoreOp: [ , "store", "discard" ], + SurfaceGetCurrentTextureStatus: [ , "success-optimal", "success-suboptimal", "timeout", "outdated", "lost", "error" ], + TextureAspect: [ , "all", "stencil-only", "depth-only" ], + TextureDimension: [ , "1d", "2d", "3d" ], + TextureFormat: [ , "r8unorm", "r8snorm", "r8uint", "r8sint", "r16unorm", "r16snorm", "r16uint", "r16sint", "r16float", "rg8unorm", "rg8snorm", "rg8uint", "rg8sint", "r32float", "r32uint", "r32sint", "rg16unorm", "rg16snorm", "rg16uint", "rg16sint", "rg16float", "rgba8unorm", "rgba8unorm-srgb", "rgba8snorm", "rgba8uint", "rgba8sint", "bgra8unorm", "bgra8unorm-srgb", "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", "rgb9e5ufloat", "rg32float", "rg32uint", "rg32sint", "rgba16unorm", "rgba16snorm", "rgba16uint", "rgba16sint", "rgba16float", "rgba32float", "rgba32uint", "rgba32sint", "stencil8", "depth16unorm", "depth24plus", "depth24plus-stencil8", "depth32float", "depth32float-stencil8", "bc1-rgba-unorm", "bc1-rgba-unorm-srgb", "bc2-rgba-unorm", "bc2-rgba-unorm-srgb", "bc3-rgba-unorm", "bc3-rgba-unorm-srgb", "bc4-r-unorm", "bc4-r-snorm", "bc5-rg-unorm", "bc5-rg-snorm", "bc6h-rgb-ufloat", "bc6h-rgb-float", "bc7-rgba-unorm", "bc7-rgba-unorm-srgb", "etc2-rgb8unorm", "etc2-rgb8unorm-srgb", "etc2-rgb8a1unorm", "etc2-rgb8a1unorm-srgb", "etc2-rgba8unorm", "etc2-rgba8unorm-srgb", "eac-r11unorm", "eac-r11snorm", "eac-rg11unorm", "eac-rg11snorm", "astc-4x4-unorm", "astc-4x4-unorm-srgb", "astc-5x4-unorm", "astc-5x4-unorm-srgb", "astc-5x5-unorm", "astc-5x5-unorm-srgb", "astc-6x5-unorm", "astc-6x5-unorm-srgb", "astc-6x6-unorm", "astc-6x6-unorm-srgb", "astc-8x5-unorm", "astc-8x5-unorm-srgb", "astc-8x6-unorm", "astc-8x6-unorm-srgb", "astc-8x8-unorm", "astc-8x8-unorm-srgb", "astc-10x5-unorm", "astc-10x5-unorm-srgb", "astc-10x6-unorm", "astc-10x6-unorm-srgb", "astc-10x8-unorm", "astc-10x8-unorm-srgb", "astc-10x10-unorm", "astc-10x10-unorm-srgb", "astc-12x10-unorm", "astc-12x10-unorm-srgb", "astc-12x12-unorm", "astc-12x12-unorm-srgb" ], + TextureSampleType: [ , , "float", "unfilterable-float", "depth", "sint", "uint" ], + TextureViewDimension: [ , "1d", "2d", "2d-array", "cube", "cube-array", "3d" ], + ToneMappingMode: [ , "standard", "extended" ], + VertexFormat: [ , "uint8", "uint8x2", "uint8x4", "sint8", "sint8x2", "sint8x4", "unorm8", "unorm8x2", "unorm8x4", "snorm8", "snorm8x2", "snorm8x4", "uint16", "uint16x2", "uint16x4", "sint16", "sint16x2", "sint16x4", "unorm16", "unorm16x2", "unorm16x4", "snorm16", "snorm16x2", "snorm16x4", "float16", "float16x2", "float16x4", "float32", "float32x2", "float32x3", "float32x4", "uint32", "uint32x2", "uint32x3", "uint32x4", "sint32", "sint32x2", "sint32x3", "sint32x4", "unorm10-10-10-2", "unorm8x4-bgra" ], + VertexStepMode: [ , "vertex", "instance" ], + WGSLLanguageFeatureName: [ , "readonly_and_readwrite_storage_textures", "packed_4x8_integer_dot_product", "unrestricted_pointer_parameters", "pointer_composite_access", "uniform_buffer_standard_layout", "subgroup_id", "texture_and_sampler_let", "subgroup_uniformity", "texture_formats_tier1" ] +}; + +function _emscripten_webgpu_get_device() { + if (WebGPU.preinitializedDeviceId === undefined) { + WebGPU.preinitializedDeviceId = WebGPU.importJsDevice(Module["preinitializedWebGPUDevice"]); + // Some users depend on this keeping the device alive, so we add an + // additional reference when we first initialize it. + _wgpuDeviceAddRef(WebGPU.preinitializedDeviceId); + } + _wgpuDeviceAddRef(WebGPU.preinitializedDeviceId); + return WebGPU.preinitializedDeviceId; +} + +function _emwgpuBufferDestroy(bufferPtr) { + bufferPtr >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + var onUnmap = WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + if (onUnmap) { + for (var i = 0; i < onUnmap.length; ++i) { + onUnmap[i](); + } + delete WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + } + buffer.destroy(); +} + +function _emwgpuBufferGetMappedRange(bufferPtr, offset, size) { + bufferPtr >>>= 0; + offset >>>= 0; + size >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + if (size == 4294967295) size = undefined; + var mapped; + try { + mapped = buffer.getMappedRange(offset, size); + } catch (ex) { + return 0; + } + var data = _memalign(16, mapped.byteLength); + HEAPU8.fill(0, data, mapped.byteLength); + WebGPU.Internals.bufferOnUnmaps[bufferPtr].push(() => { + new Uint8Array(mapped).set(HEAPU8.subarray(data >>> 0, data + mapped.byteLength >>> 0)); + _free(data); + }); + return data; +} + +function _emwgpuBufferUnmap(bufferPtr) { + bufferPtr >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + var onUnmap = WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + if (!onUnmap) { + // Already unmapped + return; + } + for (var i = 0; i < onUnmap.length; ++i) { + onUnmap[i](); + } + delete WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + buffer.unmap(); +} + +function _emwgpuBufferWriteMappedRange(bufferPtr, offset, data, size) { + bufferPtr >>>= 0; + offset >>>= 0; + data >>>= 0; + size >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + var mapped; + try { + mapped = buffer.getMappedRange(offset, size); + } catch (ex) { + return 2; + } + new Uint8Array(mapped).set(HEAPU8.subarray(data >>> 0, data + size >>> 0)); + return 1; +} + +function _emwgpuDelete(ptr) { + ptr >>>= 0; + delete WebGPU.Internals.jsObjects[ptr]; +} + +function _emwgpuDeviceCreateBuffer(devicePtr, descriptor, bufferPtr) { + devicePtr >>>= 0; + descriptor >>>= 0; + bufferPtr >>>= 0; + var mappedAtCreation = !!(HEAPU32[(((descriptor) + (32)) >>> 2) >>> 0]); + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "usage": HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0], + "size": readI53FromI64((descriptor) + (24)), + "mappedAtCreation": mappedAtCreation + }; + var device = WebGPU.getJsObject(devicePtr); + var buffer; + try { + buffer = device.createBuffer(desc); + } catch (ex) { + // The only exception should be RangeError if mapping at creation ran out of memory. + return false; + } + WebGPU.Internals.jsObjectInsert(bufferPtr, buffer); + if (mappedAtCreation) { + WebGPU.Internals.bufferOnUnmaps[bufferPtr] = []; + } + return true; +} + +var _emwgpuDeviceCreateComputePipelineAsync = function(devicePtr, futureId_low, futureId_high, descriptor, pipelinePtr) { + devicePtr >>>= 0; + var futureId = convertI32PairToI53Checked(futureId_low, futureId_high); + descriptor >>>= 0; + pipelinePtr >>>= 0; + var desc = WebGPU.makeComputePipelineDesc(descriptor); + var device = WebGPU.getJsObject(devicePtr); + // createComputePipelineAsync + WebGPU.Internals.futureInsert(futureId, device.createComputePipelineAsync(desc).then(pipeline => { + // createComputePipelineAsync fulfilled + callUserCallback(() => { + WebGPU.Internals.jsObjectInsert(pipelinePtr, pipeline); + _emwgpuOnCreateComputePipelineCompleted(futureId, 1, pipelinePtr, 0); + }); + }, pipelineError => { + // createComputePipelineAsync rejected + callUserCallback(() => { + var sp = stackSave(); + var messagePtr = stringToUTF8OnStack(pipelineError.message); + var status = pipelineError.reason === "validation" ? 3 : pipelineError.reason === "internal" ? 4 : 0; + _emwgpuOnCreateComputePipelineCompleted(futureId, status, pipelinePtr, messagePtr); + stackRestore(sp); + }); + })); +}; + +function _emwgpuDeviceCreateShaderModule(devicePtr, descriptor, shaderModulePtr) { + devicePtr >>>= 0; + descriptor >>>= 0; + shaderModulePtr >>>= 0; + var nextInChainPtr = HEAPU32[((descriptor) >>> 2) >>> 0]; + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "code": "" + }; + switch (sType) { + case 2: + { + desc["code"] = WebGPU.makeStringFromStringView(nextInChainPtr + 8); + break; + } + } + var device = WebGPU.getJsObject(devicePtr); + WebGPU.Internals.jsObjectInsert(shaderModulePtr, device.createShaderModule(desc)); +} + +var _emwgpuDeviceDestroy = devicePtr => { + const device = WebGPU.getJsObject(devicePtr); + // Remove the onuncapturederror handler which holds a pointer to the WGPUDevice. + device.onuncapturederror = null; + device.destroy(); +}; + +var _emwgpuQueueOnSubmittedWorkDone = function(queuePtr, futureId_low, futureId_high) { + queuePtr >>>= 0; + var futureId = convertI32PairToI53Checked(futureId_low, futureId_high); + var queue = WebGPU.getJsObject(queuePtr); + // onSubmittedWorkDone + WebGPU.Internals.futureInsert(futureId, queue.onSubmittedWorkDone().then(() => { + // onSubmittedWorkDone fulfilled (assumed not to reject) + callUserCallback(() => { + _emwgpuOnWorkDoneCompleted(futureId, 1); + }); + })); +}; + +var _emwgpuWaitAny = function(futurePtr, futureCount, timeoutMSPtr) { + futurePtr >>>= 0; + futureCount >>>= 0; + timeoutMSPtr >>>= 0; + return Asyncify.handleAsync(async () => { + var promises = []; + if (timeoutMSPtr) { + var timeoutMS = HEAP32[((timeoutMSPtr) >>> 2) >>> 0]; + promises.length = futureCount + 1; + promises[futureCount] = new Promise(resolve => setTimeout(resolve, timeoutMS, 0)); + } else { + promises.length = futureCount; + } + for (var i = 0; i < futureCount; ++i) { + // If any FutureID is not tracked, it means it must be done. + var futureId = readI53FromI64((futurePtr + i * 8)); + if (!(futureId in WebGPU.Internals.futures)) { + return futureId; + } + promises[i] = WebGPU.Internals.futures[futureId]; + } + const firstResolvedFuture = await Promise.race(promises); + delete WebGPU.Internals.futures[firstResolvedFuture]; + return firstResolvedFuture; + }); +}; + +_emwgpuWaitAny.isAsync = true; + +var ENV = {}; + +var getExecutableName = () => thisProgram || "./this.program"; + +var getEnvStrings = () => { + if (!getEnvStrings.strings) { + // Default values. + // Browser language detection #8751 + var lang = (globalThis.navigator?.language ?? "C").replace("-", "_") + ".UTF-8"; + var env = { + "USER": "web_user", + "LOGNAME": "web_user", + "PATH": "/", + "PWD": "/", + "HOME": "/home/web_user", + "LANG": lang, + "_": getExecutableName() + }; + // Apply the user-provided values, if any. + for (var x in ENV) { + // x is a key in ENV; if ENV[x] is undefined, that means it was + // explicitly set to be so. We allow user code to do that to + // force variables with default values to remain unset. + if (ENV[x] === undefined) delete env[x]; else env[x] = ENV[x]; + } + var strings = []; + for (var x in env) { + strings.push(`${x}=${env[x]}`); + } + getEnvStrings.strings = strings; + } + return getEnvStrings.strings; +}; + +function _environ_get(__environ, environ_buf) { + __environ >>>= 0; + environ_buf >>>= 0; + var bufSize = 0; + var envp = 0; + for (var string of getEnvStrings()) { + var ptr = environ_buf + bufSize; + HEAPU32[(((__environ) + (envp)) >>> 2) >>> 0] = ptr; + bufSize += stringToUTF8(string, ptr, Infinity) + 1; + envp += 4; + } + return 0; +} + +function _environ_sizes_get(penviron_count, penviron_buf_size) { + penviron_count >>>= 0; + penviron_buf_size >>>= 0; + var strings = getEnvStrings(); + HEAPU32[((penviron_count) >>> 2) >>> 0] = strings.length; + var bufSize = 0; + for (var string of strings) { + bufSize += lengthBytesUTF8(string) + 1; + } + HEAPU32[((penviron_buf_size) >>> 2) >>> 0] = bufSize; + return 0; +} + +function _fd_close(fd) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + FS.close(stream); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +/** @param {number=} offset */ var doReadv = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov) >>> 2) >>> 0]; + var len = HEAPU32[(((iov) + (4)) >>> 2) >>> 0]; + iov += 8; + var curr = FS.read(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) break; + // nothing more to read + if (typeof offset != "undefined") { + offset += curr; + } + } + return ret; +}; + +function _fd_pread(fd, iov, iovcnt, offset_low, offset_high, pnum) { + iov >>>= 0; + iovcnt >>>= 0; + var offset = convertI32PairToI53Checked(offset_low, offset_high); + pnum >>>= 0; + try { + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt, offset); + HEAPU32[((pnum) >>> 2) >>> 0] = num; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +function _fd_read(fd, iov, iovcnt, pnum) { + iov >>>= 0; + iovcnt >>>= 0; + pnum >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt); + HEAPU32[((pnum) >>> 2) >>> 0] = num; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { + var offset = convertI32PairToI53Checked(offset_low, offset_high); + newOffset >>>= 0; + try { + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + FS.llseek(stream, offset, whence); + (tempI64 = [ stream.position >>> 0, (tempDouble = stream.position, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[((newOffset) >>> 2) >>> 0] = tempI64[0], HEAP32[(((newOffset) + (4)) >>> 2) >>> 0] = tempI64[1]); + if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; + // reset readdir state + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +/** @param {number=} offset */ var doWritev = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov) >>> 2) >>> 0]; + var len = HEAPU32[(((iov) + (4)) >>> 2) >>> 0]; + iov += 8; + var curr = FS.write(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) { + // No more space to write. + break; + } + if (typeof offset != "undefined") { + offset += curr; + } + } + return ret; +}; + +function _fd_write(fd, iov, iovcnt, pnum) { + iov >>>= 0; + iovcnt >>>= 0; + pnum >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doWritev(stream, iov, iovcnt); + HEAPU32[((pnum) >>> 2) >>> 0] = num; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +var _emscripten_glActiveTexture = x0 => GLctx.activeTexture(x0); + +var _glActiveTexture = _emscripten_glActiveTexture; + +var _emscripten_glAttachShader = (program, shader) => { + GLctx.attachShader(GL.programs[program], GL.shaders[shader]); +}; + +var _glAttachShader = _emscripten_glAttachShader; + +function _emscripten_glBindAttribLocation(program, index, name) { + name >>>= 0; + GLctx.bindAttribLocation(GL.programs[program], index, UTF8ToString(name)); +} + +var _glBindAttribLocation = _emscripten_glBindAttribLocation; + +var _emscripten_glBindBuffer = (target, buffer) => { + // Calling glBindBuffer with an unknown buffer will implicitly create a + // new one. Here we bypass `GL.counter` and directly using the ID passed + // in. + if (buffer && !GL.buffers[buffer]) { + var b = GLctx.createBuffer(); + b.name = buffer; + GL.buffers[buffer] = b; + } + if (target == 34962) { + GLctx.currentArrayBufferBinding = buffer; + } else if (target == 34963) { + GLctx.currentElementArrayBufferBinding = buffer; + } + if (target == 35051) { + // In WebGL 2 glReadPixels entry point, we need to use a different WebGL 2 + // API function call when a buffer is bound to + // GL_PIXEL_PACK_BUFFER_BINDING point, so must keep track whether that + // binding point is non-null to know what is the proper API function to + // call. + GLctx.currentPixelPackBufferBinding = buffer; + } else if (target == 35052) { + // In WebGL 2 gl(Compressed)Tex(Sub)Image[23]D entry points, we need to + // use a different WebGL 2 API function call when a buffer is bound to + // GL_PIXEL_UNPACK_BUFFER_BINDING point, so must keep track whether that + // binding point is non-null to know what is the proper API function to + // call. + GLctx.currentPixelUnpackBufferBinding = buffer; + } + GLctx.bindBuffer(target, GL.buffers[buffer]); +}; + +var _glBindBuffer = _emscripten_glBindBuffer; + +var _emscripten_glBindFramebuffer = (target, framebuffer) => { + GLctx.bindFramebuffer(target, GL.framebuffers[framebuffer]); +}; + +var _glBindFramebuffer = _emscripten_glBindFramebuffer; + +var _emscripten_glBindTexture = (target, texture) => { + GLctx.bindTexture(target, GL.textures[texture]); +}; + +var _glBindTexture = _emscripten_glBindTexture; + +function _emscripten_glBufferData(target, size, data, usage) { + size >>>= 0; + data >>>= 0; + // N.b. here first form specifies a heap subarray, second form an integer + // size, so the ?: code here is polymorphic. It is advised to avoid + // randomly mixing both uses in calling code, to avoid any potential JS + // engine JIT issues. + GLctx.bufferData(target, data ? HEAPU8.subarray(data >>> 0, data + size >>> 0) : size, usage); +} + +var _glBufferData = _emscripten_glBufferData; + +var convertI32PairToI53 = (lo, hi) => (lo >>> 0) + hi * 4294967296; + +function _emscripten_glClientWaitSync(sync, flags, timeout_low, timeout_high) { + sync >>>= 0; + // WebGL2 vs GLES3 differences: in GLES3, the timeout parameter is a uint64, where 0xFFFFFFFFFFFFFFFFULL means GL_TIMEOUT_IGNORED. + // In JS, there's no 64-bit value types, so instead timeout is taken to be signed, and GL_TIMEOUT_IGNORED is given value -1. + // Inherently the value accepted in the timeout is lossy, and can't take in arbitrary u64 bit pattern (but most likely doesn't matter) + // See https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.15 + var timeout = convertI32PairToI53(timeout_low, timeout_high); + return GLctx.clientWaitSync(GL.syncs[sync], flags, timeout); +} + +var _glClientWaitSync = _emscripten_glClientWaitSync; + +var _emscripten_glCompileShader = shader => { + GLctx.compileShader(GL.shaders[shader]); +}; + +var _glCompileShader = _emscripten_glCompileShader; + +var _emscripten_glCreateProgram = () => { + var id = GL.getNewId(GL.programs); + var program = GLctx.createProgram(); + // Store additional information needed for each shader program: + program.name = id; + // Lazy cache results of + // glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) + program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0; + program.uniformIdCounter = 1; + GL.programs[id] = program; + return id; +}; + +var _glCreateProgram = _emscripten_glCreateProgram; + +var _emscripten_glCreateShader = shaderType => { + var id = GL.getNewId(GL.shaders); + GL.shaders[id] = GLctx.createShader(shaderType); + return id; +}; + +var _glCreateShader = _emscripten_glCreateShader; + +function _emscripten_glDeleteFramebuffers(n, framebuffers) { + framebuffers >>>= 0; + for (var i = 0; i < n; ++i) { + var id = HEAP32[(((framebuffers) + (i * 4)) >>> 2) >>> 0]; + var framebuffer = GL.framebuffers[id]; + if (!framebuffer) continue; + // GL spec: "glDeleteFramebuffers silently ignores 0s and names that do not correspond to existing framebuffer objects". + GLctx.deleteFramebuffer(framebuffer); + framebuffer.name = 0; + GL.framebuffers[id] = null; + } +} + +var _glDeleteFramebuffers = _emscripten_glDeleteFramebuffers; + +var _emscripten_glDeleteProgram = id => { + if (!id) return; + var program = GL.programs[id]; + if (!program) { + // glDeleteProgram actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(1281); + return; + } + GLctx.deleteProgram(program); + program.name = 0; + GL.programs[id] = null; +}; + +var _glDeleteProgram = _emscripten_glDeleteProgram; + +var _emscripten_glDeleteShader = id => { + if (!id) return; + var shader = GL.shaders[id]; + if (!shader) { + // glDeleteShader actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(1281); + return; + } + GLctx.deleteShader(shader); + GL.shaders[id] = null; +}; + +var _glDeleteShader = _emscripten_glDeleteShader; + +function _emscripten_glDeleteSync(id) { + id >>>= 0; + if (!id) return; + var sync = GL.syncs[id]; + if (!sync) { + // glDeleteSync signals an error when deleting a nonexisting object, unlike some other GL delete functions. + GL.recordError(1281); + return; + } + GLctx.deleteSync(sync); + sync.name = 0; + GL.syncs[id] = null; +} + +var _glDeleteSync = _emscripten_glDeleteSync; + +function _emscripten_glDeleteTextures(n, textures) { + textures >>>= 0; + for (var i = 0; i < n; i++) { + var id = HEAP32[(((textures) + (i * 4)) >>> 2) >>> 0]; + var texture = GL.textures[id]; + // GL spec: "glDeleteTextures silently ignores 0s and names that do not + // correspond to existing textures". + if (!texture) continue; + GLctx.deleteTexture(texture); + texture.name = 0; + GL.textures[id] = null; + } +} + +var _glDeleteTextures = _emscripten_glDeleteTextures; + +var _emscripten_glDetachShader = (program, shader) => { + GLctx.detachShader(GL.programs[program], GL.shaders[shader]); +}; + +var _glDetachShader = _emscripten_glDetachShader; + +var _emscripten_glDisableVertexAttribArray = index => { + var cb = GL.currentContext.clientBuffers[index]; + cb.enabled = false; + GLctx.disableVertexAttribArray(index); +}; + +var _glDisableVertexAttribArray = _emscripten_glDisableVertexAttribArray; + +var _emscripten_glDrawArrays = (mode, first, count) => { + // bind any client-side buffers + GL.preDrawHandleClientVertexAttribBindings(first + count); + GLctx.drawArrays(mode, first, count); + GL.postDrawHandleClientVertexAttribBindings(); +}; + +var _glDrawArrays = _emscripten_glDrawArrays; + +var _emscripten_glEnableVertexAttribArray = index => { + var cb = GL.currentContext.clientBuffers[index]; + cb.enabled = true; + GLctx.enableVertexAttribArray(index); +}; + +var _glEnableVertexAttribArray = _emscripten_glEnableVertexAttribArray; + +function _emscripten_glFenceSync(condition, flags) { + var sync = GLctx.fenceSync(condition, flags); + if (sync) { + var id = GL.getNewId(GL.syncs); + sync.name = id; + GL.syncs[id] = sync; + return id; + } + return 0; +} + +var _glFenceSync = _emscripten_glFenceSync; + +var _emscripten_glFinish = () => GLctx.finish(); + +var _glFinish = _emscripten_glFinish; + +var _emscripten_glFramebufferTexture2D = (target, attachment, textarget, texture, level) => { + GLctx.framebufferTexture2D(target, attachment, textarget, GL.textures[texture], level); +}; + +var _glFramebufferTexture2D = _emscripten_glFramebufferTexture2D; + +function _emscripten_glGenBuffers(n, buffers) { + buffers >>>= 0; + GL.genObject(n, buffers, "createBuffer", GL.buffers); +} + +var _glGenBuffers = _emscripten_glGenBuffers; + +function _emscripten_glGenFramebuffers(n, ids) { + ids >>>= 0; + GL.genObject(n, ids, "createFramebuffer", GL.framebuffers); +} + +var _glGenFramebuffers = _emscripten_glGenFramebuffers; + +function _emscripten_glGenTextures(n, textures) { + textures >>>= 0; + GL.genObject(n, textures, "createTexture", GL.textures); +} + +var _glGenTextures = _emscripten_glGenTextures; + +var _emscripten_glGetError = () => { + var error = GLctx.getError() || GL.lastError; + GL.lastError = 0; + return error; +}; + +var _glGetError = _emscripten_glGetError; + +var webglGetExtensions = () => { + var exts = getEmscriptenSupportedExtensions(GLctx); + exts = exts.concat(exts.map(e => "GL_" + e)); + return exts; +}; + +var emscriptenWebGLGet = (name_, p, type) => { + // Guard against user passing a null pointer. + // Note that GLES2 spec does not say anything about how passing a null + // pointer should be treated. Testing on desktop core GL 3, the application + // crashes on glGetIntegerv to a null pointer, but better to report an error + // instead of doing anything random. + if (!p) { + GL.recordError(1281); + return; + } + var ret = undefined; + switch (name_) { + // Handle a few trivial GLES values + case 36346: + // GL_SHADER_COMPILER + ret = 1; + break; + + case 36344: + // GL_SHADER_BINARY_FORMATS + if (type != 0 && type != 1) { + GL.recordError(1280); + } + // Do not write anything to the out pointer, since no binary formats are + // supported. + return; + + case 34814: + // GL_NUM_PROGRAM_BINARY_FORMATS + case 36345: + // GL_NUM_SHADER_BINARY_FORMATS + ret = 0; + break; + + case 34466: + // GL_NUM_COMPRESSED_TEXTURE_FORMATS + // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete + // since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be + // queried for length), so implement it ourselves to allow C++ GLES2 + // code to get the length. + var formats = GLctx.getParameter(34467); + ret = formats ? formats.length : 0; + break; + + case 33309: + // GL_NUM_EXTENSIONS + if (GL.currentContext.version < 2) { + // Calling GLES3/WebGL2 function with a GLES2/WebGL1 context + GL.recordError(1282); + return; + } + ret = webglGetExtensions().length; + break; + + case 33307: + // GL_MAJOR_VERSION + case 33308: + // GL_MINOR_VERSION + if (GL.currentContext.version < 2) { + GL.recordError(1280); + // GL_INVALID_ENUM + return; + } + ret = name_ == 33307 ? 3 : 0; + // return version 3.0 + break; + } + if (ret === undefined) { + var result = GLctx.getParameter(name_); + switch (typeof result) { + case "number": + ret = result; + break; + + case "boolean": + ret = result ? 1 : 0; + break; + + case "string": + GL.recordError(1280); + // GL_INVALID_ENUM + return; + + case "object": + if (result === null) { + // null is a valid result for some (e.g., which buffer is bound - + // perhaps nothing is bound), but otherwise can mean an invalid + // name_, which we need to report as an error + switch (name_) { + case 34964: + // ARRAY_BUFFER_BINDING + case 35725: + // CURRENT_PROGRAM + case 34965: + // ELEMENT_ARRAY_BUFFER_BINDING + case 36006: + // FRAMEBUFFER_BINDING or DRAW_FRAMEBUFFER_BINDING + case 36007: + // RENDERBUFFER_BINDING + case 32873: + // TEXTURE_BINDING_2D + case 34229: + // WebGL 2 GL_VERTEX_ARRAY_BINDING, or WebGL 1 extension OES_vertex_array_object GL_VERTEX_ARRAY_BINDING_OES + case 36662: + // COPY_READ_BUFFER_BINDING or COPY_READ_BUFFER + case 36663: + // COPY_WRITE_BUFFER_BINDING or COPY_WRITE_BUFFER + case 35053: + // PIXEL_PACK_BUFFER_BINDING + case 35055: + // PIXEL_UNPACK_BUFFER_BINDING + case 36010: + // READ_FRAMEBUFFER_BINDING + case 35097: + // SAMPLER_BINDING + case 35869: + // TEXTURE_BINDING_2D_ARRAY + case 32874: + // TEXTURE_BINDING_3D + case 36389: + // TRANSFORM_FEEDBACK_BINDING + case 35983: + // TRANSFORM_FEEDBACK_BUFFER_BINDING + case 35368: + // UNIFORM_BUFFER_BINDING + case 34068: + { + // TEXTURE_BINDING_CUBE_MAP + ret = 0; + break; + } + + default: + { + GL.recordError(1280); + // GL_INVALID_ENUM + return; + } + } + } else if (result instanceof Float32Array || result instanceof Uint32Array || result instanceof Int32Array || result instanceof Array) { + for (var i = 0; i < result.length; ++i) { + switch (type) { + case 0: + HEAP32[(((p) + (i * 4)) >>> 2) >>> 0] = result[i]; + break; + + case 2: + HEAPF32[(((p) + (i * 4)) >>> 2) >>> 0] = result[i]; + break; + + case 4: + HEAP8[(p) + (i) >>> 0] = result[i] ? 1 : 0; + break; + } + } + return; + } else { + try { + ret = result.name | 0; + } catch (e) { + GL.recordError(1280); + // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`); + return; + } + } + break; + + default: + GL.recordError(1280); + // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof (result)}!`); + return; + } + } + switch (type) { + case 1: + writeI53ToI64(p, ret); + break; + + case 0: + HEAP32[((p) >>> 2) >>> 0] = ret; + break; + + case 2: + HEAPF32[((p) >>> 2) >>> 0] = ret; + break; + + case 4: + HEAP8[p >>> 0] = ret ? 1 : 0; + break; + } +}; + +function _emscripten_glGetIntegerv(name_, p) { + p >>>= 0; + return emscriptenWebGLGet(name_, p, 0); +} + +var _glGetIntegerv = _emscripten_glGetIntegerv; + +function _emscripten_glGetString(name_) { + var ret = GL.stringCache[name_]; + if (!ret) { + switch (name_) { + case 7939: + ret = stringToNewUTF8(webglGetExtensions().join(" ")); + break; + + case 7936: + case 7937: + case 37445: + case 37446: + var s = GLctx.getParameter(name_); + if (!s) { + GL.recordError(1280); + } + ret = s ? stringToNewUTF8(s) : 0; + break; + + case 7938: + var webGLVersion = GLctx.getParameter(7938); + // return GLES version string corresponding to the version of the WebGL context + var glVersion = `OpenGL ES 2.0 (${webGLVersion})`; + if (GL.currentContext.version >= 2) glVersion = `OpenGL ES 3.0 (${webGLVersion})`; + ret = stringToNewUTF8(glVersion); + break; + + case 35724: + var glslVersion = GLctx.getParameter(35724); + // extract the version number 'N.M' from the string 'WebGL GLSL ES N.M ...' + var ver_re = /^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/; + var ver_num = glslVersion.match(ver_re); + if (ver_num !== null) { + if (ver_num[1].length == 3) ver_num[1] = ver_num[1] + "0"; + // ensure minor version has 2 digits + glslVersion = `OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`; + } + ret = stringToNewUTF8(glslVersion); + break; + + default: + GL.recordError(1280); + } + GL.stringCache[name_] = ret; + } + return ret; +} + +var _glGetString = _emscripten_glGetString; + +/** @suppress {checkTypes} */ var jstoi_q = str => parseInt(str); + +/** @noinline */ var webglGetLeftBracePos = name => name.slice(-1) == "]" && name.lastIndexOf("["); + +var webglPrepareUniformLocationsBeforeFirstUse = program => { + var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation + uniformSizeAndIdsByName = program.uniformSizeAndIdsByName, // Maps name -> [uniform array length, GLuint] + i, j; + // On the first time invocation of glGetUniformLocation on this shader program: + // initialize cache data structures and discover which uniforms are arrays. + if (!uniformLocsById) { + // maps GLint integer locations to WebGLUniformLocations + program.uniformLocsById = uniformLocsById = {}; + // maps integer locations back to uniform name strings, so that we can lazily fetch uniform array locations + program.uniformArrayNamesById = {}; + var numActiveUniforms = GLctx.getProgramParameter(program, 35718); + for (i = 0; i < numActiveUniforms; ++i) { + var u = GLctx.getActiveUniform(program, i); + var nm = u.name; + var sz = u.size; + var lb = webglGetLeftBracePos(nm); + var arrayName = lb > 0 ? nm.slice(0, lb) : nm; + // Assign a new location. + var id = program.uniformIdCounter; + program.uniformIdCounter += sz; + // Eagerly get the location of the uniformArray[0] base element. + // The remaining indices >0 will be left for lazy evaluation to + // improve performance. Those may never be needed to fetch, if the + // application fills arrays always in full starting from the first + // element of the array. + uniformSizeAndIdsByName[arrayName] = [ sz, id ]; + // Store placeholder integers in place that highlight that these + // >0 index locations are array indices pending population. + for (j = 0; j < sz; ++j) { + uniformLocsById[id] = j; + program.uniformArrayNamesById[id++] = arrayName; + } + } + } +}; + +function _emscripten_glGetUniformLocation(program, name) { + name >>>= 0; + name = UTF8ToString(name); + if (program = GL.programs[program]) { + webglPrepareUniformLocationsBeforeFirstUse(program); + var uniformLocsById = program.uniformLocsById; + // Maps GLuint -> WebGLUniformLocation + var arrayIndex = 0; + var uniformBaseName = name; + // Invariant: when populating integer IDs for uniform locations, we must + // maintain the precondition that arrays reside in contiguous addresses, + // i.e. for a 'vec4 colors[10];', colors[4] must be at location + // colors[0]+4. However, user might call glGetUniformLocation(program, + // "colors") for an array, so we cannot discover based on the user input + // arguments whether the uniform we are dealing with is an array. The only + // way to discover which uniforms are arrays is to enumerate over all the + // active uniforms in the program. + var leftBrace = webglGetLeftBracePos(name); + // If user passed an array accessor "[index]", parse the array index off the accessor. + if (leftBrace > 0) { + arrayIndex = jstoi_q(name.slice(leftBrace + 1)) >>> 0; + // "index]", coerce parseInt(']') with >>>0 to treat "foo[]" as "foo[0]" and foo[-1] as unsigned out-of-bounds. + uniformBaseName = name.slice(0, leftBrace); + } + // Have we cached the location of this uniform before? + // A pair [array length, GLint of the uniform location] + var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; + // If a uniform with this name exists, and if its index is within the + // array limits (if it's even an array), query the WebGLlocation, or + // return an existing cached location. + if (sizeAndId && arrayIndex < sizeAndId[0]) { + arrayIndex += sizeAndId[1]; + // Add the base location of the uniform to the array index offset. + if ((uniformLocsById[arrayIndex] = uniformLocsById[arrayIndex] || GLctx.getUniformLocation(program, name))) { + return arrayIndex; + } + } + } else { + // N.b. we are currently unable to distinguish between GL program IDs that + // never existed vs GL program IDs that have been deleted, so report + // GL_INVALID_VALUE in both cases. + GL.recordError(1281); + } + return -1; +} + +var _glGetUniformLocation = _emscripten_glGetUniformLocation; + +var _emscripten_glLinkProgram = program => { + program = GL.programs[program]; + GLctx.linkProgram(program); + // Invalidate earlier computed uniform->ID mappings, those have now become stale + program.uniformLocsById = 0; + // Mark as null-like so that glGetUniformLocation() knows to populate this again. + program.uniformSizeAndIdsByName = {}; +}; + +var _glLinkProgram = _emscripten_glLinkProgram; + +var _emscripten_glPixelStorei = (pname, param) => { + if (pname == 3317) { + GL.unpackAlignment = param; + } else if (pname == 3314) { + GL.unpackRowLength = param; + } + GLctx.pixelStorei(pname, param); +}; + +var _glPixelStorei = _emscripten_glPixelStorei; + +var computeUnpackAlignedImageSize = (width, height, sizePerPixel) => { + function roundedToNextMultipleOf(x, y) { + return (x + y - 1) & -y; + } + var plainRowSize = (GL.unpackRowLength || width) * sizePerPixel; + var alignedRowSize = roundedToNextMultipleOf(plainRowSize, GL.unpackAlignment); + return height * alignedRowSize; +}; + +var colorChannelsInGlTextureFormat = format => { + // Micro-optimizations for size: map format to size by subtracting smallest + // enum value (0x1902) from all values first. Also omit the most common + // size value (1) from the list, which is assumed by formats not on the + // list. + var colorChannels = { + // 0x1902 /* GL_DEPTH_COMPONENT */ - 0x1902: 1, + // 0x1906 /* GL_ALPHA */ - 0x1902: 1, + 5: 3, + 6: 4, + // 0x1909 /* GL_LUMINANCE */ - 0x1902: 1, + 8: 2, + 29502: 3, + 29504: 4, + // 0x1903 /* GL_RED */ - 0x1902: 1, + 26917: 2, + 26918: 2, + // 0x8D94 /* GL_RED_INTEGER */ - 0x1902: 1, + 29846: 3, + 29847: 4 + }; + return colorChannels[format - 6402] || 1; +}; + +var heapObjectForWebGLType = type => { + // Micro-optimization for size: Subtract lowest GL enum number (0x1400/* GL_BYTE */) from type to compare + // smaller values for the heap, for shorter generated code size. + // Also the type HEAPU16 is not tested for explicitly, but any unrecognized type will return out HEAPU16. + // (since most types are HEAPU16) + type -= 5120; + if (type == 0) return HEAP8; + if (type == 1) return HEAPU8; + if (type == 2) return HEAP16; + if (type == 4) return HEAP32; + if (type == 6) return HEAPF32; + if (type == 5 || type == 28922 || type == 28520 || type == 30779 || type == 30782) return HEAPU32; + return HEAPU16; +}; + +var toTypedArrayIndex = (pointer, heap) => pointer >>> (31 - Math.clz32(heap.BYTES_PER_ELEMENT)); + +var emscriptenWebGLGetTexPixelData = (type, format, width, height, pixels, internalFormat) => { + var heap = heapObjectForWebGLType(type); + var sizePerPixel = colorChannelsInGlTextureFormat(format) * heap.BYTES_PER_ELEMENT; + var bytes = computeUnpackAlignedImageSize(width, height, sizePerPixel); + return heap.subarray(toTypedArrayIndex(pixels, heap) >>> 0, toTypedArrayIndex(pixels + bytes, heap) >>> 0); +}; + +function _emscripten_glReadPixels(x, y, width, height, format, type, pixels) { + pixels >>>= 0; + if (GL.currentContext.version >= 2) { + if (GLctx.currentPixelPackBufferBinding) { + GLctx.readPixels(x, y, width, height, format, type, pixels); + return; + } + } + var pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, format); + if (!pixelData) { + GL.recordError(1280); + return; + } + GLctx.readPixels(x, y, width, height, format, type, pixelData); +} + +var _glReadPixels = _emscripten_glReadPixels; + +function _emscripten_glShaderSource(shader, count, string, length) { + string >>>= 0; + length >>>= 0; + var source = GL.getSource(shader, count, string, length); + GLctx.shaderSource(GL.shaders[shader], source); +} + +var _glShaderSource = _emscripten_glShaderSource; + +function _emscripten_glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels) { + pixels >>>= 0; + if (GL.currentContext.version >= 2) { + if (GLctx.currentPixelUnpackBufferBinding) { + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels); + return; + } + } + var pixelData = pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null; + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixelData); +} + +var _glTexImage2D = _emscripten_glTexImage2D; + +var _emscripten_glTexParameteri = (x0, x1, x2) => GLctx.texParameteri(x0, x1, x2); + +var _glTexParameteri = _emscripten_glTexParameteri; + +var _emscripten_glTexStorage2D = (x0, x1, x2, x3, x4) => GLctx.texStorage2D(x0, x1, x2, x3, x4); + +var _glTexStorage2D = _emscripten_glTexStorage2D; + +var webglGetUniformLocation = location => { + var p = GLctx.currentProgram; + if (p) { + var webglLoc = p.uniformLocsById[location]; + // p.uniformLocsById[location] stores either an integer, or a + // WebGLUniformLocation. + // If an integer, we have not yet bound the location, so do it now. The + // integer value specifies the array index we should bind to. + if (typeof webglLoc == "number") { + p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? `[${webglLoc}]` : "")); + } + // Else an already cached WebGLUniformLocation, return it. + return webglLoc; + } else { + GL.recordError(1282); + } +}; + +var _emscripten_glUniform1i = (location, v0) => { + GLctx.uniform1i(webglGetUniformLocation(location), v0); +}; + +var _glUniform1i = _emscripten_glUniform1i; + +var _emscripten_glUseProgram = program => { + program = GL.programs[program]; + GLctx.useProgram(program); + // Record the currently active program so that we can access the uniform + // mapping table of that program. + GLctx.currentProgram = program; +}; + +var _glUseProgram = _emscripten_glUseProgram; + +function _emscripten_glVertexAttribPointer(index, size, type, normalized, stride, ptr) { + ptr >>>= 0; + var cb = GL.currentContext.clientBuffers[index]; + if (!GLctx.currentArrayBufferBinding) { + cb.size = size; + cb.type = type; + cb.normalized = normalized; + cb.stride = stride; + cb.ptr = ptr; + cb.clientside = true; + cb.vertexAttribPointerAdaptor = function(index, size, type, normalized, stride, ptr) { + this.vertexAttribPointer(index, size, type, normalized, stride, ptr); + }; + return; + } + cb.clientside = false; + GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr); +} + +var _glVertexAttribPointer = _emscripten_glVertexAttribPointer; + +var _emscripten_glViewport = (x0, x1, x2, x3) => GLctx.viewport(x0, x1, x2, x3); + +var _glViewport = _emscripten_glViewport; + +function _random_get(buffer, size) { + buffer >>>= 0; + size >>>= 0; + try { + randomFill(HEAPU8.subarray(buffer >>> 0, buffer + size >>> 0)); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +var _wgpuBufferGetSize = function(bufferPtr) { + bufferPtr >>>= 0; + var ret = (() => { + var buffer = WebGPU.getJsObject(bufferPtr); + // 64-bit + return buffer.size; + })(); + return (setTempRet0((tempDouble = ret, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0)), + ret >>> 0); +}; + +var _wgpuBufferGetUsage = function(bufferPtr) { + bufferPtr >>>= 0; + var ret = (() => { + var buffer = WebGPU.getJsObject(bufferPtr); + return buffer.usage; + })(); + return (setTempRet0((tempDouble = ret, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0)), + ret >>> 0); +}; + +function _wgpuCommandEncoderBeginComputePass(encoderPtr, descriptor) { + encoderPtr >>>= 0; + descriptor >>>= 0; + var desc; + if (descriptor) { + desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "timestampWrites": WebGPU.makePassTimestampWrites(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]) + }; + } + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var ptr = _emwgpuCreateComputePassEncoder(0); + WebGPU.Internals.jsObjectInsert(ptr, commandEncoder.beginComputePass(desc)); + return ptr; +} + +function _wgpuCommandEncoderCopyBufferToBuffer(encoderPtr, srcPtr, srcOffset_low, srcOffset_high, dstPtr, dstOffset_low, dstOffset_high, size_low, size_high) { + encoderPtr >>>= 0; + srcPtr >>>= 0; + var srcOffset = convertI32PairToI53Checked(srcOffset_low, srcOffset_high); + dstPtr >>>= 0; + var dstOffset = convertI32PairToI53Checked(dstOffset_low, dstOffset_high); + var size = convertI32PairToI53Checked(size_low, size_high); + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var src = WebGPU.getJsObject(srcPtr); + var dst = WebGPU.getJsObject(dstPtr); + commandEncoder.copyBufferToBuffer(src, srcOffset, dst, dstOffset, size); +} + +function _wgpuCommandEncoderCopyTextureToBuffer(encoderPtr, srcPtr, dstPtr, copySizePtr) { + encoderPtr >>>= 0; + srcPtr >>>= 0; + dstPtr >>>= 0; + copySizePtr >>>= 0; + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var copySize = WebGPU.makeExtent3D(copySizePtr); + commandEncoder.copyTextureToBuffer(WebGPU.makeTexelCopyTextureInfo(srcPtr), WebGPU.makeTexelCopyBufferInfo(dstPtr), copySize); +} + +function _wgpuCommandEncoderCopyTextureToTexture(encoderPtr, srcPtr, dstPtr, copySizePtr) { + encoderPtr >>>= 0; + srcPtr >>>= 0; + dstPtr >>>= 0; + copySizePtr >>>= 0; + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var copySize = WebGPU.makeExtent3D(copySizePtr); + commandEncoder.copyTextureToTexture(WebGPU.makeTexelCopyTextureInfo(srcPtr), WebGPU.makeTexelCopyTextureInfo(dstPtr), copySize); +} + +function _wgpuCommandEncoderFinish(encoderPtr, descriptor) { + encoderPtr >>>= 0; + descriptor >>>= 0; + // TODO: Use the descriptor. + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var ptr = _emwgpuCreateCommandBuffer(0); + WebGPU.Internals.jsObjectInsert(ptr, commandEncoder.finish()); + return ptr; +} + +function _wgpuCommandEncoderResolveQuerySet(encoderPtr, querySetPtr, firstQuery, queryCount, destinationPtr, destinationOffset_low, destinationOffset_high) { + encoderPtr >>>= 0; + querySetPtr >>>= 0; + destinationPtr >>>= 0; + var destinationOffset = convertI32PairToI53Checked(destinationOffset_low, destinationOffset_high); + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var querySet = WebGPU.getJsObject(querySetPtr); + var destination = WebGPU.getJsObject(destinationPtr); + commandEncoder.resolveQuerySet(querySet, firstQuery, queryCount, destination, destinationOffset); +} + +function _wgpuComputePassEncoderDispatchWorkgroups(passPtr, x, y, z) { + passPtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + pass.dispatchWorkgroups(x, y, z); +} + +function _wgpuComputePassEncoderEnd(passPtr) { + passPtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + pass.end(); +} + +function _wgpuComputePassEncoderSetBindGroup(passPtr, groupIndex, groupPtr, dynamicOffsetCount, dynamicOffsetsPtr) { + passPtr >>>= 0; + groupPtr >>>= 0; + dynamicOffsetCount >>>= 0; + dynamicOffsetsPtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + var group = WebGPU.getJsObject(groupPtr); + if (dynamicOffsetCount == 0) { + pass.setBindGroup(groupIndex, group); + } else { + pass.setBindGroup(groupIndex, group, HEAPU32, ((dynamicOffsetsPtr) >>> 2), dynamicOffsetCount); + } +} + +function _wgpuComputePassEncoderSetPipeline(passPtr, pipelinePtr) { + passPtr >>>= 0; + pipelinePtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + var pipeline = WebGPU.getJsObject(pipelinePtr); + pass.setPipeline(pipeline); +} + +var _wgpuDeviceCreateBindGroup = function(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + function makeEntry(entryPtr) { + var bufferPtr = HEAPU32[(((entryPtr) + (8)) >>> 2) >>> 0]; + var samplerPtr = HEAPU32[(((entryPtr) + (32)) >>> 2) >>> 0]; + var textureViewPtr = HEAPU32[(((entryPtr) + (36)) >>> 2) >>> 0]; + var externalTexturePtr = 0; + WebGPU.iterateExtensions(entryPtr, { + 14: ptr => { + externalTexturePtr = HEAPU32[(((ptr) + (8)) >>> 2) >>> 0]; + } + }); + var resource; + if (bufferPtr) { + // Note the sentinel UINT64_MAX will be read as -1. + var size = readI53FromI64((entryPtr) + (24)); + if (size == -1) size = undefined; + resource = { + "buffer": WebGPU.getJsObject(bufferPtr), + "offset": readI53FromI64((entryPtr) + (16)), + "size": size + }; + } else { + resource = WebGPU.getJsObject(samplerPtr || textureViewPtr || externalTexturePtr); + } + return { + "binding": HEAPU32[(((entryPtr) + (4)) >>> 2) >>> 0], + "resource": resource + }; + } + function makeEntries(count, entriesPtrs) { + var entries = []; + for (var i = 0; i < count; ++i) { + entries.push(makeEntry(entriesPtrs + 40 * i)); + } + return entries; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "layout": WebGPU.getJsObject(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]), + "entries": makeEntries(HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0], HEAPU32[(((descriptor) + (20)) >>> 2) >>> 0]) + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateBindGroup(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createBindGroup(desc)); + return ptr; +}; + +function _wgpuDeviceCreateBindGroupLayout(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + function makeBufferEntry(substructPtr) { + var typeInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!typeInt) return undefined; + return { + "type": WebGPU.BufferBindingType[typeInt], + "hasDynamicOffset": !!(HEAPU32[(((substructPtr) + (8)) >>> 2) >>> 0]), + "minBindingSize": readI53FromI64((substructPtr) + (16)) + }; + } + function makeSamplerEntry(substructPtr) { + var typeInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!typeInt) return undefined; + return { + "type": WebGPU.SamplerBindingType[typeInt] + }; + } + function makeTextureEntry(substructPtr) { + var sampleTypeInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!sampleTypeInt) return undefined; + return { + "sampleType": WebGPU.TextureSampleType[sampleTypeInt], + "viewDimension": WebGPU.TextureViewDimension[HEAP32[(((substructPtr) + (8)) >>> 2) >>> 0]], + "multisampled": !!(HEAPU32[(((substructPtr) + (12)) >>> 2) >>> 0]) + }; + } + function makeStorageTextureEntry(substructPtr) { + var accessInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!accessInt) return undefined; + return { + "access": WebGPU.StorageTextureAccess[accessInt], + "format": WebGPU.TextureFormat[HEAP32[(((substructPtr) + (8)) >>> 2) >>> 0]], + "viewDimension": WebGPU.TextureViewDimension[HEAP32[(((substructPtr) + (12)) >>> 2) >>> 0]] + }; + } + function makeEntry(entryPtr) { + var entry = { + "binding": HEAPU32[(((entryPtr) + (4)) >>> 2) >>> 0], + "visibility": HEAPU32[(((entryPtr) + (8)) >>> 2) >>> 0], + "buffer": makeBufferEntry(entryPtr + 24), + "sampler": makeSamplerEntry(entryPtr + 48), + "texture": makeTextureEntry(entryPtr + 56), + "storageTexture": makeStorageTextureEntry(entryPtr + 72) + }; + WebGPU.iterateExtensions(entryPtr, { + 13: ptr => { + entry["externalTexture"] = {}; + } + }); + return entry; + } + function makeEntries(count, entriesPtrs) { + var entries = []; + for (var i = 0; i < count; ++i) { + entries.push(makeEntry(entriesPtrs + 88 * i)); + } + return entries; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "entries": makeEntries(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0], HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0]) + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateBindGroupLayout(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createBindGroupLayout(desc)); + return ptr; +} + +function _wgpuDeviceCreateCommandEncoder(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var desc; + if (descriptor) { + desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4) + }; + } + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateCommandEncoder(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createCommandEncoder(desc)); + return ptr; +} + +function _wgpuDeviceCreateComputePipeline(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var desc = WebGPU.makeComputePipelineDesc(descriptor); + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateComputePipeline(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createComputePipeline(desc)); + return ptr; +} + +function _wgpuDeviceCreatePipelineLayout(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var bglCount = HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]; + var bglPtr = HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0]; + var bgls = []; + for (var i = 0; i < bglCount; ++i) { + bgls.push(WebGPU.getJsObject(HEAPU32[(((bglPtr) + (4 * i)) >>> 2) >>> 0])); + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "bindGroupLayouts": bgls + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreatePipelineLayout(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createPipelineLayout(desc)); + return ptr; +} + +function _wgpuDeviceCreateQuerySet(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var desc = { + "type": WebGPU.QueryType[HEAP32[(((descriptor) + (12)) >>> 2) >>> 0]], + "count": HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0] + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateQuerySet(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createQuerySet(desc)); + return ptr; +} + +function _wgpuDeviceCreateTexture(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var nextInChainPtr = HEAPU32[((descriptor) >>> 2) >>> 0]; + var textureBindingViewDimension; + if (nextInChainPtr !== 0) { + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var textureBindingViewDimensionDescriptor = nextInChainPtr; + textureBindingViewDimension = WebGPU.TextureViewDimension[HEAP32[(((textureBindingViewDimensionDescriptor) + (8)) >>> 2) >>> 0]]; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "size": WebGPU.makeExtent3D(descriptor + 28), + "mipLevelCount": HEAPU32[(((descriptor) + (44)) >>> 2) >>> 0], + "sampleCount": HEAPU32[(((descriptor) + (48)) >>> 2) >>> 0], + "dimension": WebGPU.TextureDimension[HEAP32[(((descriptor) + (24)) >>> 2) >>> 0]], + "format": WebGPU.TextureFormat[HEAP32[(((descriptor) + (40)) >>> 2) >>> 0]], + "usage": HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0], + "textureBindingViewDimension": textureBindingViewDimension + }; + var viewFormatCount = HEAPU32[(((descriptor) + (52)) >>> 2) >>> 0]; + if (viewFormatCount) { + var viewFormatsPtr = HEAPU32[(((descriptor) + (56)) >>> 2) >>> 0]; + // viewFormatsPtr pointer to an array of TextureFormat which is an enum of size uint32_t + desc["viewFormats"] = Array.from(HEAP32.subarray((((viewFormatsPtr) >>> 2)) >>> 0, ((viewFormatsPtr + viewFormatCount * 4) >>> 2) >>> 0), format => WebGPU.TextureFormat[format]); + } + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateTexture(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createTexture(desc)); + return ptr; +} + +function _wgpuDeviceGetAdapterInfo(devicePtr, adapterInfo) { + devicePtr >>>= 0; + adapterInfo >>>= 0; + var device = WebGPU.getJsObject(devicePtr); + WebGPU.fillAdapterInfoStruct(device.adapterInfo, adapterInfo); + return 1; +} + +function _wgpuDeviceGetLimits(devicePtr, limitsOutPtr) { + devicePtr >>>= 0; + limitsOutPtr >>>= 0; + var device = WebGPU.getJsObject(devicePtr); + WebGPU.fillLimitStruct(device.limits, limitsOutPtr); + return 1; +} + +function _wgpuDeviceHasFeature(devicePtr, featureEnumValue) { + devicePtr >>>= 0; + var device = WebGPU.getJsObject(devicePtr); + return device.features.has(WebGPU.FeatureName[featureEnumValue]); +} + +var _wgpuQueueSubmit = function(queuePtr, commandCount, commands) { + queuePtr >>>= 0; + commandCount >>>= 0; + commands >>>= 0; + var queue = WebGPU.getJsObject(queuePtr); + var cmds = Array.from(HEAP32.subarray((((commands) >>> 2)) >>> 0, ((commands + commandCount * 4) >>> 2) >>> 0), id => WebGPU.getJsObject(id)); + queue.submit(cmds); +}; + +function _wgpuQueueWriteBuffer(queuePtr, bufferPtr, bufferOffset_low, bufferOffset_high, data, size) { + queuePtr >>>= 0; + bufferPtr >>>= 0; + var bufferOffset = convertI32PairToI53Checked(bufferOffset_low, bufferOffset_high); + data >>>= 0; + size >>>= 0; + var queue = WebGPU.getJsObject(queuePtr); + var buffer = WebGPU.getJsObject(bufferPtr); + // There is a size limitation for ArrayBufferView. Work around by passing in a subarray + // instead of the whole heap. crbug.com/1201109 + var subarray = HEAPU8.subarray(data >>> 0, data + size >>> 0); + queue.writeBuffer(buffer, bufferOffset, subarray, 0, size); +} + +function _wgpuQueueWriteTexture(queuePtr, destinationPtr, data, dataSize, dataLayoutPtr, writeSizePtr) { + queuePtr >>>= 0; + destinationPtr >>>= 0; + data >>>= 0; + dataSize >>>= 0; + dataLayoutPtr >>>= 0; + writeSizePtr >>>= 0; + var queue = WebGPU.getJsObject(queuePtr); + var destination = WebGPU.makeTexelCopyTextureInfo(destinationPtr); + var dataLayout = WebGPU.makeTexelCopyBufferLayout(dataLayoutPtr); + var writeSize = WebGPU.makeExtent3D(writeSizePtr); + // This subarray isn't strictly necessary, but helps work around an issue + // where Chromium makes a copy of the entire heap. crbug.com/1134457 + var subarray = HEAPU8.subarray(data >>> 0, data + dataSize >>> 0); + queue.writeTexture(destination, subarray, dataLayout, writeSize); +} + +function _wgpuTextureCreateView(texturePtr, descriptor) { + texturePtr >>>= 0; + descriptor >>>= 0; + var desc; + if (descriptor) { + var swizzle; + var nextInChainPtr = HEAPU32[((descriptor) >>> 2) >>> 0]; + if (nextInChainPtr !== 0) { + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var swizzleDescriptor = nextInChainPtr; + var swizzlePtr = swizzleDescriptor + 8; + var r = WebGPU.ComponentSwizzle[HEAP32[((swizzlePtr) >>> 2) >>> 0]] || "r"; + var g = WebGPU.ComponentSwizzle[HEAP32[(((swizzlePtr) + (4)) >>> 2) >>> 0]] || "g"; + var b = WebGPU.ComponentSwizzle[HEAP32[(((swizzlePtr) + (8)) >>> 2) >>> 0]] || "b"; + var a = WebGPU.ComponentSwizzle[HEAP32[(((swizzlePtr) + (12)) >>> 2) >>> 0]] || "a"; + swizzle = `${r}${g}${b}${a}`; + } + var mipLevelCount = HEAPU32[(((descriptor) + (24)) >>> 2) >>> 0]; + var arrayLayerCount = HEAPU32[(((descriptor) + (32)) >>> 2) >>> 0]; + desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "format": WebGPU.TextureFormat[HEAP32[(((descriptor) + (12)) >>> 2) >>> 0]], + "dimension": WebGPU.TextureViewDimension[HEAP32[(((descriptor) + (16)) >>> 2) >>> 0]], + "baseMipLevel": HEAPU32[(((descriptor) + (20)) >>> 2) >>> 0], + "mipLevelCount": mipLevelCount === 4294967295 ? undefined : mipLevelCount, + "baseArrayLayer": HEAPU32[(((descriptor) + (28)) >>> 2) >>> 0], + "arrayLayerCount": arrayLayerCount === 4294967295 ? undefined : arrayLayerCount, + "aspect": WebGPU.TextureAspect[HEAP32[(((descriptor) + (36)) >>> 2) >>> 0]], + "usage": HEAPU32[(((descriptor) + (40)) >>> 2) >>> 0], + "swizzle": swizzle + }; + } + var texture = WebGPU.getJsObject(texturePtr); + var ptr = _emwgpuCreateTextureView(0); + WebGPU.Internals.jsObjectInsert(ptr, texture.createView(desc)); + return ptr; +} + +function _wgpuTextureDestroy(texturePtr) { + texturePtr >>>= 0; + WebGPU.getJsObject(texturePtr).destroy(); +} + +function _wgpuTextureGetDepthOrArrayLayers(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + return texture.depthOrArrayLayers; +} + +function _wgpuTextureGetFormat(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + // Should return the enum integer instead of string. + return WebGPU.TextureFormat.indexOf(texture.format); +} + +function _wgpuTextureGetHeight(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + return texture.height; +} + +function _wgpuTextureGetWidth(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + return texture.width; +} + +var getCFunc = ident => { + var func = Module["_" + ident]; + // closure exported function + return func; +}; + +var writeArrayToMemory = (array, buffer) => { + HEAP8.set(array, buffer >>> 0); +}; + +/** + * @param {string|null=} returnType + * @param {Array=} argTypes + * @param {Array=} args + * @param {Object=} opts + */ var ccall = (ident, returnType, argTypes, args, opts) => { + // For fast lookup of conversion functions + var toC = { + "string": str => { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { + // null string + ret = stringToUTF8OnStack(str); + } + return ret; + }, + "array": arr => { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + } + }; + function convertReturnValue(ret) { + if (returnType === "string") { + return UTF8ToString(ret); + } + if (returnType === "pointer") return ret >>> 0; + if (returnType === "boolean") return Boolean(ret); + return ret; + } + var func = getCFunc(ident); + var cArgs = []; + var stack = 0; + if (args) { + for (var i = 0; i < args.length; i++) { + var converter = toC[argTypes[i]]; + if (converter) { + if (stack === 0) stack = stackSave(); + cArgs[i] = converter(args[i]); + } else { + cArgs[i] = args[i]; + } + } + } + // Data for a previous async operation that was in flight before us. + var previousAsync = Asyncify.currData; + var ret = func(...cArgs); + function onDone(ret) { + runtimeKeepalivePop(); + if (stack !== 0) stackRestore(stack); + return convertReturnValue(ret); + } + var asyncMode = opts?.async; + // Keep the runtime alive through all calls. Note that this call might not be + // async, but for simplicity we push and pop in all calls. + runtimeKeepalivePush(); + if (Asyncify.currData != previousAsync) { + // This is a new async operation. The wasm is paused and has unwound its stack. + // We need to return a Promise that resolves the return value + // once the stack is rewound and execution finishes. + return Asyncify.whenDone().then(onDone); + } + ret = onDone(ret); + // If this is an async ccall, ensure we return a promise + if (asyncMode) return Promise.resolve(ret); + return ret; +}; + +var FS_createPath = (...args) => FS.createPath(...args); + +var FS_unlink = (...args) => FS.unlink(...args); + +var FS_createLazyFile = (...args) => FS.createLazyFile(...args); + +var FS_createDevice = (...args) => FS.createDevice(...args); + +FS.createPreloadedFile = FS_createPreloadedFile; + +FS.preloadFile = FS_preloadFile; + +FS.staticInit(); + +// Signal GL rendering layer that processing of a new frame is about to +// start. This helps it optimize VBO double-buffering and reduce GPU stalls. +registerPreMainLoop(() => GL.newRenderingFrameStarted()); + +// End JS library code +// include: postlibrary.js +// This file is included after the automatically-generated JS library code +// but before the wasm module is created. +{ + // Begin ATMODULES hooks + if (Module["preloadPlugins"]) preloadPlugins = Module["preloadPlugins"]; + if (Module["noExitRuntime"]) noExitRuntime = Module["noExitRuntime"]; + if (Module["print"]) out = Module["print"]; + if (Module["printErr"]) err = Module["printErr"]; + if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; + // End ATMODULES hooks + if (Module["arguments"]) arguments_ = Module["arguments"]; + if (Module["thisProgram"]) thisProgram = Module["thisProgram"]; + if (Module["preInit"]) { + if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ]; + while (Module["preInit"].length > 0) { + Module["preInit"].shift()(); + } + } +} + +// Begin runtime exports +Module["addRunDependency"] = addRunDependency; + +Module["removeRunDependency"] = removeRunDependency; + +Module["ccall"] = ccall; + +Module["stringToNewUTF8"] = stringToNewUTF8; + +Module["FS_preloadFile"] = FS_preloadFile; + +Module["FS_unlink"] = FS_unlink; + +Module["FS_createPath"] = FS_createPath; + +Module["FS_createDevice"] = FS_createDevice; + +Module["FS_createDataFile"] = FS_createDataFile; + +Module["FS_createLazyFile"] = FS_createLazyFile; + +// End runtime exports +// Begin JS library exports +// End JS library exports +// end include: postlibrary.js +var ASM_CONSTS = { + 2019768: () => !!Module["preinitializedWebGPUDevice"], + 2019819: () => { + const retVal = Module.LLM_CANCEL_FLAG; + Module.LLM_CANCEL_FLAG = undefined; + return retVal || 0; + }, + 2019918: $0 => { + const device = WebGPU.getJsObject($0); + return device.features.has("subgroups"); + }, + 2020002: () => !!Module["preinitializedWebGPUDevice"], + 2020053: () => { + specialHTMLTargets["#canvas"] = Module.canvas; + } +}; + +function __asyncjs__InvokeReadDataFn(fn, offset, size, mode) { + return Asyncify.handleAsync(async () => await Emval.toValue(fn)(offset, size, mode)); +} + +function JsProgressListener(text, done) { + Module._userProgressListener(UTF8ToString(text), done); +} + +function DefaultErrorReporter(message) { + throw new Error(UTF8ToString(message)); +} + +function ThrowError(val_handle) { + const error = Emval.toValue(val_handle); + throw error; +} + +function JsOnEmptyPacketListener(output_stream_name, timestamp) { + Module._wrapEmptyPacketListenerOutput(output_stream_name, timestamp); +} + +function JsOnVectorFinishedListener(output_stream_name, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, undefined, true, timestamp); +} + +function JsOnSimpleListenerBool(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerBool(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerInt(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerInt(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerUint(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerUint(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerDouble(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerDouble(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerFloat(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerFloat(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerString(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, UTF8ToString(out_data), timestamp); +} + +function JsOnVectorListenerString(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, UTF8ToString(out_data), false, timestamp); +} + +function JsOnVectorListenerProto(output_stream_name, proto_ptr, proto_size, make_deep_copy, timestamp) { + const newProtoArray = make_deep_copy ? Module.HEAPU8.slice(proto_ptr, proto_ptr + proto_size) : new Uint8Array(Module.HEAPU8.buffer, proto_ptr, proto_size); + Module._wrapSimpleListenerOutput(output_stream_name, newProtoArray, false, timestamp); +} + +function JsWrapSimpleListeners() { + if (!Module._wrapSimpleListenerOutput) { + Module._wrapSimpleListenerOutput = (outputStreamName, ...args) => { + if (Module.simpleListeners) { + const streamName = UTF8ToString(outputStreamName); + if (Module.simpleListeners[streamName]) { + Module.simpleListeners[streamName](...args); + } + } + }; + } + if (!Module._wrapEmptyPacketListenerOutput) { + Module._wrapEmptyPacketListenerOutput = (outputStreamName, timestamp) => { + if (Module.emptyPacketListeners) { + const streamName = UTF8ToString(outputStreamName); + if (Module.emptyPacketListeners[streamName]) { + Module.emptyPacketListeners[streamName](timestamp); + } + } + }; + } +} + +function JsOnSimpleListenerBinaryArray(output_stream_name, binary_ptr, binary_size, make_deep_copy, timestamp) { + const newProtoArray = make_deep_copy ? Module.HEAPU8.slice(binary_ptr, binary_ptr + binary_size) : new Uint8Array(Module.HEAPU8.buffer, binary_ptr, binary_size); + Module._wrapSimpleListenerOutput(output_stream_name, newProtoArray, timestamp); +} + +function __asyncjs__CallReadDataFn(fn, offset, size, mode) { + return Asyncify.handleAsync(async () => await Emval.toValue(fn)(offset, size, mode)); +} + +function __asyncjs__mediapipe_map_buffer_jspi(buffer_handle, data) { + return Asyncify.handleAsync(async () => { + const buffer = WebGPU.getJsObject(buffer_handle); + if ("mapSync" in buffer) { + buffer.mapSync(GPUMapMode.READ); + } else { + await buffer.mapAsync(GPUMapMode.READ); + } + const mapped = buffer.getMappedRange(); + HEAPU8.set(new Uint8Array(mapped), data >>> 0); + buffer.unmap(); + }); +} + +function JsGetDeviceMinSubgroupSize(deviceId) { + const device = WebGPU.getJsObject(deviceId); + return device.adapterInfo.subgroupMinSize || device.limits.minSubgroupSize; +} + +function JsGetDeviceMaxSubgroupSize(deviceId) { + const device = WebGPU.getJsObject(deviceId); + return device.adapterInfo.subgroupMaxSize || device.limits.maxSubgroupSize; +} + +function __asyncjs__ReadBufferDataJs(buffer_handle, data_ptr) { + return Asyncify.handleAsync(async () => { + const gpuReadBuffer = WebGPU.getJsObject(buffer_handle); + await gpuReadBuffer.mapAsync(GPUMapMode.READ); + const arrayBuffer = gpuReadBuffer.getMappedRange(); + const u8view = new Uint8Array(arrayBuffer); + HEAPU8.set(u8view, data_ptr >>> 0 >>> 0); + gpuReadBuffer.unmap(); + }); +} + +function GetAdapterArchitecture() { + const device = Module["preinitializedWebGPUDevice"]; + const architecture = device.adapterInfo ? device.adapterInfo.architecture : "Unknown"; + return stringToNewUTF8(architecture); +} + +function GetAdapterDescription() { + const device = Module["preinitializedWebGPUDevice"]; + const description = device.adapterInfo ? device.adapterInfo.description : "Unknown"; + return stringToNewUTF8(description); +} + +function GetAdapterDeviceName() { + const device = Module["preinitializedWebGPUDevice"]; + const deviceName = device.adapterInfo ? device.adapterInfo.device : "Unknown"; + return stringToNewUTF8(deviceName); +} + +function GetAdapterVendor() { + const device = Module["preinitializedWebGPUDevice"]; + const vendor = device.adapterInfo ? device.adapterInfo.vendor : "Unknown"; + return stringToNewUTF8(vendor); +} + +function hardware_concurrency() { + var concurrency = 1; + try { + concurrency = self.navigator.hardwareConcurrency; + } catch (e) {} + return concurrency; +} + +function JsWrapErrorListener(code, message) { + if (Module.errorListener) { + const stringMessage = UTF8ToString(message); + Module.errorListener(code, stringMessage); + } +} + +function UseBottomLeftGpuOrigin() { + return (Module && Module.gpuOriginForWebTexturesIsBottomLeft); +} + +function custom_emscripten_dbgn(str, len) { + if (typeof (dbg) !== "undefined") { + dbg(UTF8ToString(str, len)); + } else { + if (typeof (custom_dbg) === "undefined") { + function custom_dbg(text) { + console.warn.apply(console, arguments); + } + } + custom_dbg(UTF8ToString(str, len)); + } +} + +// Imports from the Wasm binary. +var _free, _CreateLlmInferenceEngineConverted, _DeleteLlmInferenceEngine, _MakeSessionForPredict, _AddTextQueryChunk, _AddImageQueryChunk, _AddAudioQueryChunk, _malloc, _PredictSession, _FreeSession, _GetSizeInTokens, _wgpuDeviceAddRef, _registerModelResourcesGraphService, _bindTextureToStream, _addBoundTextureToStream, _addDoubleToInputStream, _addFloatToInputStream, _addBoolToInputStream, _addIntToInputStream, _addUintToInputStream, _addStringToInputStream, _addRawDataSpanToInputStream, _allocateBoolVector, _allocateFloatVector, _allocateDoubleVector, _allocateIntVector, _allocateUintVector, _allocateStringVector, _addBoolVectorEntry, _addFloatVectorEntry, _addDoubleVectorEntry, _addIntVectorEntry, _addUintVectorEntry, _addStringVectorEntry, _addBoolVectorToInputStream, _addFloatVectorToInputStream, _addDoubleVectorToInputStream, _addIntVectorToInputStream, _addUintVectorToInputStream, _addStringVectorToInputStream, _addFlatHashMapToInputStream, _addProtoToInputStream, _addEmptyPacketToInputStream, _addBoolToInputSidePacket, _addDoubleToInputSidePacket, _addFloatToInputSidePacket, _addIntToInputSidePacket, _addUintToInputSidePacket, _addStringToInputSidePacket, _addRawDataSpanToInputSidePacket, _addProtoToInputSidePacket, _addBoolVectorToInputSidePacket, _addDoubleVectorToInputSidePacket, _addFloatVectorToInputSidePacket, _addIntVectorToInputSidePacket, _addUintVectorToInputSidePacket, _addStringVectorToInputSidePacket, _attachBoolListener, _attachBoolVectorListener, _attachDoubleListener, _attachDoubleVectorListener, _attachFloatListener, _attachFloatVectorListener, _attachIntListener, _attachIntVectorListener, _attachUintListener, _attachUintVectorListener, _attachStringListener, _attachStringVectorListener, _attachProtoListener, _attachProtoVectorListener, _getGraphConfig, ___getTypeName, _emwgpuCreateBindGroup, _emwgpuCreateBindGroupLayout, _emwgpuCreateCommandBuffer, _emwgpuCreateCommandEncoder, _emwgpuCreateComputePassEncoder, _emwgpuCreateComputePipeline, _emwgpuCreateExternalTexture, _emwgpuCreatePipelineLayout, _emwgpuCreateQuerySet, _emwgpuCreateRenderBundle, _emwgpuCreateRenderBundleEncoder, _emwgpuCreateRenderPassEncoder, _emwgpuCreateRenderPipeline, _emwgpuCreateSampler, _emwgpuCreateSurface, _emwgpuCreateTexture, _emwgpuCreateTextureView, _emwgpuCreateAdapter, _emwgpuImportBuffer, _emwgpuCreateDevice, _emwgpuCreateQueue, _emwgpuCreateShaderModule, _emwgpuOnCreateComputePipelineCompleted, _emwgpuOnWorkDoneCompleted, _clearSubgraphs, _pushBinarySubgraph, _pushTextSubgraph, _changeBinaryGraph, _changeTextGraph, _processGl, _process, _bindTextureToCanvas, _requestShaderRefreshOnGraphChange, _waitUntilIdle, _closeGraph, _setAutoRenderToScreen, _emscripten_builtin_memalign, _memalign, __emscripten_tempret_set, __emscripten_stack_restore, __emscripten_stack_alloc, _emscripten_stack_get_current, dynCall_vii, dynCall_viiiiiii, dynCall_viiiiii, dynCall_v, dynCall_ii, dynCall_vi, dynCall_iiiii, dynCall_iii, dynCall_viii, dynCall_i, dynCall_ji, dynCall_iiii, dynCall_viiii, dynCall_viiiii, dynCall_jii, dynCall_iiiijij, dynCall_ff, dynCall_did, dynCall_iiiiiii, dynCall_iiiiii, dynCall_iiiiiiiiiii, dynCall_iiiiiiiiiiii, dynCall_viji, dynCall_vijiii, dynCall_iiiiiiiii, dynCall_viiiiiiii, dynCall_iiiif, dynCall_viiiiiiiiiiiiiii, dynCall_viff, dynCall_viiffii, dynCall_viiffi, dynCall_viiiiiiiiii, dynCall_fi, dynCall_viiffff, dynCall_viiiiij, dynCall_vij, dynCall_viiiiiffii, dynCall_vif, dynCall_ddd, dynCall_dddd, dynCall_idd, dynCall_di, dynCall_jiiiijiiiii, dynCall_viiij, dynCall_viid, dynCall_vidd, dynCall_vifd, dynCall_viiiiiiiiiii, dynCall_iiif, dynCall_jiii, dynCall_viijj, dynCall_iiiiiiii, dynCall_iiiiiiiiii, dynCall_iij, dynCall_iiiijj, dynCall_viiijjj, dynCall_fff, dynCall_viifii, dynCall_fii, dynCall_jjj, dynCall_fiii, dynCall_viiiiiiiii, dynCall_viiiffii, dynCall_iiiiiffi, dynCall_viiiiiff, dynCall_viiiiiiiiiiiii, dynCall_viiiiiiiiiiii, dynCall_viiiiiiiiiiiiiiiii, dynCall_iifff, dynCall_iiff, dynCall_iiifiii, dynCall_iiffi, dynCall_iiffii, dynCall_viiiiiiiiiiiiii, dynCall_iif, dynCall_viijii, dynCall_iiiji, dynCall_viiif, dynCall_viiifiii, dynCall_fiif, dynCall_iiiifi, dynCall_iiiifiii, dynCall_iiifi, dynCall_viiiif, dynCall_viiiifii, dynCall_dii, dynCall_vifi, dynCall_vidi, dynCall_viiiji, dynCall_viiji, dynCall_vijjj, dynCall_vj, dynCall_viij, dynCall_jiji, dynCall_iidiiii, dynCall_iiiiij, dynCall_iiiiid, dynCall_iiiiijj, dynCall_iiiiiijj, _asyncify_start_unwind, _asyncify_stop_unwind, _asyncify_start_rewind, _asyncify_stop_rewind, memory, _kVersionStampBuildChangelistStr, _kVersionStampCitcSnapshotStr, _kVersionStampCitcWorkspaceIdStr, _kVersionStampSourceUriStr, _kVersionStampBuildClientStr, _kVersionStampBuildClientMintStatusStr, _kVersionStampBuildCompilerStr, _kVersionStampBuildDateTimePstStr, _kVersionStampBuildDepotPathStr, _kVersionStampBuildIdStr, _kVersionStampBuildInfoStr, _kVersionStampBuildLabelStr, _kVersionStampBuildTargetStr, _kVersionStampBuildTimestampStr, _kVersionStampBuildToolStr, _kVersionStampG3BuildTargetStr, _kVersionStampVerifiableStr, _kVersionStampBuildFdoTypeStr, _kVersionStampBuildBaselineChangelistStr, _kVersionStampBuildLtoTypeStr, _kVersionStampBuildPropellerTypeStr, _kVersionStampBuildPghoTypeStr, _kVersionStampBuildUsernameStr, _kVersionStampBuildHostnameStr, _kVersionStampBuildDirectoryStr, _kVersionStampBuildChangelistInt, _kVersionStampCitcSnapshotInt, _kVersionStampBuildClientMintStatusInt, _kVersionStampBuildTimestampInt, _kVersionStampVerifiableInt, _kVersionStampBuildCoverageEnabledInt, _kVersionStampBuildBaselineChangelistInt, _kVersionStampPrecookedTimestampStr, _kVersionStampPrecookedClientInfoStr, __indirect_function_table, wasmMemory; + +function assignWasmExports(wasmExports) { + _free = Module["_free"] = wasmExports["ad"]; + _CreateLlmInferenceEngineConverted = Module["_CreateLlmInferenceEngineConverted"] = wasmExports["bd"]; + _DeleteLlmInferenceEngine = Module["_DeleteLlmInferenceEngine"] = wasmExports["cd"]; + _MakeSessionForPredict = Module["_MakeSessionForPredict"] = wasmExports["dd"]; + _AddTextQueryChunk = Module["_AddTextQueryChunk"] = wasmExports["ed"]; + _AddImageQueryChunk = Module["_AddImageQueryChunk"] = wasmExports["fd"]; + _AddAudioQueryChunk = Module["_AddAudioQueryChunk"] = wasmExports["gd"]; + _malloc = Module["_malloc"] = wasmExports["hd"]; + _PredictSession = Module["_PredictSession"] = wasmExports["id"]; + _FreeSession = Module["_FreeSession"] = wasmExports["jd"]; + _GetSizeInTokens = Module["_GetSizeInTokens"] = wasmExports["kd"]; + _wgpuDeviceAddRef = wasmExports["ld"]; + _registerModelResourcesGraphService = Module["_registerModelResourcesGraphService"] = wasmExports["md"]; + _bindTextureToStream = Module["_bindTextureToStream"] = wasmExports["nd"]; + _addBoundTextureToStream = Module["_addBoundTextureToStream"] = wasmExports["od"]; + _addDoubleToInputStream = Module["_addDoubleToInputStream"] = wasmExports["pd"]; + _addFloatToInputStream = Module["_addFloatToInputStream"] = wasmExports["qd"]; + _addBoolToInputStream = Module["_addBoolToInputStream"] = wasmExports["rd"]; + _addIntToInputStream = Module["_addIntToInputStream"] = wasmExports["sd"]; + _addUintToInputStream = Module["_addUintToInputStream"] = wasmExports["td"]; + _addStringToInputStream = Module["_addStringToInputStream"] = wasmExports["ud"]; + _addRawDataSpanToInputStream = Module["_addRawDataSpanToInputStream"] = wasmExports["vd"]; + _allocateBoolVector = Module["_allocateBoolVector"] = wasmExports["wd"]; + _allocateFloatVector = Module["_allocateFloatVector"] = wasmExports["xd"]; + _allocateDoubleVector = Module["_allocateDoubleVector"] = wasmExports["yd"]; + _allocateIntVector = Module["_allocateIntVector"] = wasmExports["zd"]; + _allocateUintVector = Module["_allocateUintVector"] = wasmExports["Ad"]; + _allocateStringVector = Module["_allocateStringVector"] = wasmExports["Bd"]; + _addBoolVectorEntry = Module["_addBoolVectorEntry"] = wasmExports["Cd"]; + _addFloatVectorEntry = Module["_addFloatVectorEntry"] = wasmExports["Dd"]; + _addDoubleVectorEntry = Module["_addDoubleVectorEntry"] = wasmExports["Ed"]; + _addIntVectorEntry = Module["_addIntVectorEntry"] = wasmExports["Fd"]; + _addUintVectorEntry = Module["_addUintVectorEntry"] = wasmExports["Gd"]; + _addStringVectorEntry = Module["_addStringVectorEntry"] = wasmExports["Hd"]; + _addBoolVectorToInputStream = Module["_addBoolVectorToInputStream"] = wasmExports["Id"]; + _addFloatVectorToInputStream = Module["_addFloatVectorToInputStream"] = wasmExports["Jd"]; + _addDoubleVectorToInputStream = Module["_addDoubleVectorToInputStream"] = wasmExports["Kd"]; + _addIntVectorToInputStream = Module["_addIntVectorToInputStream"] = wasmExports["Ld"]; + _addUintVectorToInputStream = Module["_addUintVectorToInputStream"] = wasmExports["Md"]; + _addStringVectorToInputStream = Module["_addStringVectorToInputStream"] = wasmExports["Nd"]; + _addFlatHashMapToInputStream = Module["_addFlatHashMapToInputStream"] = wasmExports["Od"]; + _addProtoToInputStream = Module["_addProtoToInputStream"] = wasmExports["Pd"]; + _addEmptyPacketToInputStream = Module["_addEmptyPacketToInputStream"] = wasmExports["Qd"]; + _addBoolToInputSidePacket = Module["_addBoolToInputSidePacket"] = wasmExports["Rd"]; + _addDoubleToInputSidePacket = Module["_addDoubleToInputSidePacket"] = wasmExports["Sd"]; + _addFloatToInputSidePacket = Module["_addFloatToInputSidePacket"] = wasmExports["Td"]; + _addIntToInputSidePacket = Module["_addIntToInputSidePacket"] = wasmExports["Ud"]; + _addUintToInputSidePacket = Module["_addUintToInputSidePacket"] = wasmExports["Vd"]; + _addStringToInputSidePacket = Module["_addStringToInputSidePacket"] = wasmExports["Wd"]; + _addRawDataSpanToInputSidePacket = Module["_addRawDataSpanToInputSidePacket"] = wasmExports["Xd"]; + _addProtoToInputSidePacket = Module["_addProtoToInputSidePacket"] = wasmExports["Yd"]; + _addBoolVectorToInputSidePacket = Module["_addBoolVectorToInputSidePacket"] = wasmExports["Zd"]; + _addDoubleVectorToInputSidePacket = Module["_addDoubleVectorToInputSidePacket"] = wasmExports["_d"]; + _addFloatVectorToInputSidePacket = Module["_addFloatVectorToInputSidePacket"] = wasmExports["$d"]; + _addIntVectorToInputSidePacket = Module["_addIntVectorToInputSidePacket"] = wasmExports["ae"]; + _addUintVectorToInputSidePacket = Module["_addUintVectorToInputSidePacket"] = wasmExports["be"]; + _addStringVectorToInputSidePacket = Module["_addStringVectorToInputSidePacket"] = wasmExports["ce"]; + _attachBoolListener = Module["_attachBoolListener"] = wasmExports["de"]; + _attachBoolVectorListener = Module["_attachBoolVectorListener"] = wasmExports["ee"]; + _attachDoubleListener = Module["_attachDoubleListener"] = wasmExports["fe"]; + _attachDoubleVectorListener = Module["_attachDoubleVectorListener"] = wasmExports["ge"]; + _attachFloatListener = Module["_attachFloatListener"] = wasmExports["he"]; + _attachFloatVectorListener = Module["_attachFloatVectorListener"] = wasmExports["ie"]; + _attachIntListener = Module["_attachIntListener"] = wasmExports["je"]; + _attachIntVectorListener = Module["_attachIntVectorListener"] = wasmExports["ke"]; + _attachUintListener = Module["_attachUintListener"] = wasmExports["le"]; + _attachUintVectorListener = Module["_attachUintVectorListener"] = wasmExports["me"]; + _attachStringListener = Module["_attachStringListener"] = wasmExports["ne"]; + _attachStringVectorListener = Module["_attachStringVectorListener"] = wasmExports["oe"]; + _attachProtoListener = Module["_attachProtoListener"] = wasmExports["pe"]; + _attachProtoVectorListener = Module["_attachProtoVectorListener"] = wasmExports["qe"]; + _getGraphConfig = Module["_getGraphConfig"] = wasmExports["re"]; + ___getTypeName = wasmExports["se"]; + _emwgpuCreateBindGroup = wasmExports["te"]; + _emwgpuCreateBindGroupLayout = wasmExports["ue"]; + _emwgpuCreateCommandBuffer = wasmExports["ve"]; + _emwgpuCreateCommandEncoder = wasmExports["we"]; + _emwgpuCreateComputePassEncoder = wasmExports["xe"]; + _emwgpuCreateComputePipeline = wasmExports["ye"]; + _emwgpuCreateExternalTexture = wasmExports["ze"]; + _emwgpuCreatePipelineLayout = wasmExports["Ae"]; + _emwgpuCreateQuerySet = wasmExports["Be"]; + _emwgpuCreateRenderBundle = wasmExports["Ce"]; + _emwgpuCreateRenderBundleEncoder = wasmExports["De"]; + _emwgpuCreateRenderPassEncoder = wasmExports["Ee"]; + _emwgpuCreateRenderPipeline = wasmExports["Fe"]; + _emwgpuCreateSampler = wasmExports["Ge"]; + _emwgpuCreateSurface = wasmExports["He"]; + _emwgpuCreateTexture = wasmExports["Ie"]; + _emwgpuCreateTextureView = wasmExports["Je"]; + _emwgpuCreateAdapter = wasmExports["Ke"]; + _emwgpuImportBuffer = wasmExports["Le"]; + _emwgpuCreateDevice = wasmExports["Me"]; + _emwgpuCreateQueue = wasmExports["Ne"]; + _emwgpuCreateShaderModule = wasmExports["Oe"]; + _emwgpuOnCreateComputePipelineCompleted = wasmExports["Pe"]; + _emwgpuOnWorkDoneCompleted = wasmExports["Qe"]; + _clearSubgraphs = Module["_clearSubgraphs"] = wasmExports["Re"]; + _pushBinarySubgraph = Module["_pushBinarySubgraph"] = wasmExports["Se"]; + _pushTextSubgraph = Module["_pushTextSubgraph"] = wasmExports["Te"]; + _changeBinaryGraph = Module["_changeBinaryGraph"] = wasmExports["Ue"]; + _changeTextGraph = Module["_changeTextGraph"] = wasmExports["Ve"]; + _processGl = Module["_processGl"] = wasmExports["We"]; + _process = Module["_process"] = wasmExports["Xe"]; + _bindTextureToCanvas = Module["_bindTextureToCanvas"] = wasmExports["Ye"]; + _requestShaderRefreshOnGraphChange = Module["_requestShaderRefreshOnGraphChange"] = wasmExports["Ze"]; + _waitUntilIdle = Module["_waitUntilIdle"] = wasmExports["_e"]; + _closeGraph = Module["_closeGraph"] = wasmExports["$e"]; + _setAutoRenderToScreen = Module["_setAutoRenderToScreen"] = wasmExports["af"]; + _emscripten_builtin_memalign = wasmExports["bf"]; + _memalign = wasmExports["cf"]; + __emscripten_tempret_set = wasmExports["df"]; + __emscripten_stack_restore = wasmExports["ef"]; + __emscripten_stack_alloc = wasmExports["ff"]; + _emscripten_stack_get_current = wasmExports["gf"]; + dynCall_vii = dynCalls["vii"] = wasmExports["hf"]; + dynCall_viiiiiii = dynCalls["viiiiiii"] = wasmExports["jf"]; + dynCall_viiiiii = dynCalls["viiiiii"] = wasmExports["kf"]; + dynCall_v = dynCalls["v"] = wasmExports["lf"]; + dynCall_ii = dynCalls["ii"] = wasmExports["mf"]; + dynCall_vi = dynCalls["vi"] = wasmExports["nf"]; + dynCall_iiiii = dynCalls["iiiii"] = wasmExports["of"]; + dynCall_iii = dynCalls["iii"] = wasmExports["pf"]; + dynCall_viii = dynCalls["viii"] = wasmExports["qf"]; + dynCall_i = dynCalls["i"] = wasmExports["rf"]; + dynCall_ji = dynCalls["ji"] = wasmExports["sf"]; + dynCall_iiii = dynCalls["iiii"] = wasmExports["tf"]; + dynCall_viiii = dynCalls["viiii"] = wasmExports["uf"]; + dynCall_viiiii = dynCalls["viiiii"] = wasmExports["vf"]; + dynCall_jii = dynCalls["jii"] = wasmExports["wf"]; + dynCall_iiiijij = dynCalls["iiiijij"] = wasmExports["xf"]; + dynCall_ff = dynCalls["ff"] = wasmExports["yf"]; + dynCall_did = dynCalls["did"] = wasmExports["zf"]; + dynCall_iiiiiii = dynCalls["iiiiiii"] = wasmExports["Af"]; + dynCall_iiiiii = dynCalls["iiiiii"] = wasmExports["Bf"]; + dynCall_iiiiiiiiiii = dynCalls["iiiiiiiiiii"] = wasmExports["Cf"]; + dynCall_iiiiiiiiiiii = dynCalls["iiiiiiiiiiii"] = wasmExports["Df"]; + dynCall_viji = dynCalls["viji"] = wasmExports["Ef"]; + dynCall_vijiii = dynCalls["vijiii"] = wasmExports["Ff"]; + dynCall_iiiiiiiii = dynCalls["iiiiiiiii"] = wasmExports["Gf"]; + dynCall_viiiiiiii = dynCalls["viiiiiiii"] = wasmExports["Hf"]; + dynCall_iiiif = dynCalls["iiiif"] = wasmExports["If"]; + dynCall_viiiiiiiiiiiiiii = dynCalls["viiiiiiiiiiiiiii"] = wasmExports["Jf"]; + dynCall_viff = dynCalls["viff"] = wasmExports["Kf"]; + dynCall_viiffii = dynCalls["viiffii"] = wasmExports["Lf"]; + dynCall_viiffi = dynCalls["viiffi"] = wasmExports["Mf"]; + dynCall_viiiiiiiiii = dynCalls["viiiiiiiiii"] = wasmExports["Nf"]; + dynCall_fi = dynCalls["fi"] = wasmExports["Of"]; + dynCall_viiffff = dynCalls["viiffff"] = wasmExports["Pf"]; + dynCall_viiiiij = dynCalls["viiiiij"] = wasmExports["Qf"]; + dynCall_vij = dynCalls["vij"] = wasmExports["Rf"]; + dynCall_viiiiiffii = dynCalls["viiiiiffii"] = wasmExports["Sf"]; + dynCall_vif = dynCalls["vif"] = wasmExports["Tf"]; + dynCall_ddd = dynCalls["ddd"] = wasmExports["Uf"]; + dynCall_dddd = dynCalls["dddd"] = wasmExports["Vf"]; + dynCall_idd = dynCalls["idd"] = wasmExports["Wf"]; + dynCall_di = dynCalls["di"] = wasmExports["Xf"]; + dynCall_jiiiijiiiii = dynCalls["jiiiijiiiii"] = wasmExports["Yf"]; + dynCall_viiij = dynCalls["viiij"] = wasmExports["Zf"]; + dynCall_viid = dynCalls["viid"] = wasmExports["_f"]; + dynCall_vidd = dynCalls["vidd"] = wasmExports["$f"]; + dynCall_vifd = dynCalls["vifd"] = wasmExports["ag"]; + dynCall_viiiiiiiiiii = dynCalls["viiiiiiiiiii"] = wasmExports["bg"]; + dynCall_iiif = dynCalls["iiif"] = wasmExports["cg"]; + dynCall_jiii = dynCalls["jiii"] = wasmExports["dg"]; + dynCall_viijj = dynCalls["viijj"] = wasmExports["eg"]; + dynCall_iiiiiiii = dynCalls["iiiiiiii"] = wasmExports["fg"]; + dynCall_iiiiiiiiii = dynCalls["iiiiiiiiii"] = wasmExports["gg"]; + dynCall_iij = dynCalls["iij"] = wasmExports["hg"]; + dynCall_iiiijj = dynCalls["iiiijj"] = wasmExports["ig"]; + dynCall_viiijjj = dynCalls["viiijjj"] = wasmExports["jg"]; + dynCall_fff = dynCalls["fff"] = wasmExports["kg"]; + dynCall_viifii = dynCalls["viifii"] = wasmExports["lg"]; + dynCall_fii = dynCalls["fii"] = wasmExports["mg"]; + dynCall_jjj = dynCalls["jjj"] = wasmExports["ng"]; + dynCall_fiii = dynCalls["fiii"] = wasmExports["og"]; + dynCall_viiiiiiiii = dynCalls["viiiiiiiii"] = wasmExports["pg"]; + dynCall_viiiffii = dynCalls["viiiffii"] = wasmExports["qg"]; + dynCall_iiiiiffi = dynCalls["iiiiiffi"] = wasmExports["rg"]; + dynCall_viiiiiff = dynCalls["viiiiiff"] = wasmExports["sg"]; + dynCall_viiiiiiiiiiiii = dynCalls["viiiiiiiiiiiii"] = wasmExports["tg"]; + dynCall_viiiiiiiiiiii = dynCalls["viiiiiiiiiiii"] = wasmExports["ug"]; + dynCall_viiiiiiiiiiiiiiiii = dynCalls["viiiiiiiiiiiiiiiii"] = wasmExports["vg"]; + dynCall_iifff = dynCalls["iifff"] = wasmExports["wg"]; + dynCall_iiff = dynCalls["iiff"] = wasmExports["xg"]; + dynCall_iiifiii = dynCalls["iiifiii"] = wasmExports["yg"]; + dynCall_iiffi = dynCalls["iiffi"] = wasmExports["zg"]; + dynCall_iiffii = dynCalls["iiffii"] = wasmExports["Ag"]; + dynCall_viiiiiiiiiiiiii = dynCalls["viiiiiiiiiiiiii"] = wasmExports["Bg"]; + dynCall_iif = dynCalls["iif"] = wasmExports["Cg"]; + dynCall_viijii = dynCalls["viijii"] = wasmExports["Dg"]; + dynCall_iiiji = dynCalls["iiiji"] = wasmExports["Eg"]; + dynCall_viiif = dynCalls["viiif"] = wasmExports["Fg"]; + dynCall_viiifiii = dynCalls["viiifiii"] = wasmExports["Gg"]; + dynCall_fiif = dynCalls["fiif"] = wasmExports["Hg"]; + dynCall_iiiifi = dynCalls["iiiifi"] = wasmExports["Ig"]; + dynCall_iiiifiii = dynCalls["iiiifiii"] = wasmExports["Jg"]; + dynCall_iiifi = dynCalls["iiifi"] = wasmExports["Kg"]; + dynCall_viiiif = dynCalls["viiiif"] = wasmExports["Lg"]; + dynCall_viiiifii = dynCalls["viiiifii"] = wasmExports["Mg"]; + dynCall_dii = dynCalls["dii"] = wasmExports["Ng"]; + dynCall_vifi = dynCalls["vifi"] = wasmExports["Og"]; + dynCall_vidi = dynCalls["vidi"] = wasmExports["Pg"]; + dynCall_viiiji = dynCalls["viiiji"] = wasmExports["Qg"]; + dynCall_viiji = dynCalls["viiji"] = wasmExports["Rg"]; + dynCall_vijjj = dynCalls["vijjj"] = wasmExports["Sg"]; + dynCall_vj = dynCalls["vj"] = wasmExports["Tg"]; + dynCall_viij = dynCalls["viij"] = wasmExports["Ug"]; + dynCall_jiji = dynCalls["jiji"] = wasmExports["Vg"]; + dynCall_iidiiii = dynCalls["iidiiii"] = wasmExports["Wg"]; + dynCall_iiiiij = dynCalls["iiiiij"] = wasmExports["Xg"]; + dynCall_iiiiid = dynCalls["iiiiid"] = wasmExports["Yg"]; + dynCall_iiiiijj = dynCalls["iiiiijj"] = wasmExports["Zg"]; + dynCall_iiiiiijj = dynCalls["iiiiiijj"] = wasmExports["_g"]; + _asyncify_start_unwind = wasmExports["$g"]; + _asyncify_stop_unwind = wasmExports["ah"]; + _asyncify_start_rewind = wasmExports["bh"]; + _asyncify_stop_rewind = wasmExports["ch"]; + memory = wasmMemory = wasmExports["sc"]; + _kVersionStampBuildChangelistStr = Module["_kVersionStampBuildChangelistStr"] = (wasmExports["uc"].value) >>> 0; + _kVersionStampCitcSnapshotStr = Module["_kVersionStampCitcSnapshotStr"] = (wasmExports["vc"].value) >>> 0; + _kVersionStampCitcWorkspaceIdStr = Module["_kVersionStampCitcWorkspaceIdStr"] = (wasmExports["wc"].value) >>> 0; + _kVersionStampSourceUriStr = Module["_kVersionStampSourceUriStr"] = (wasmExports["xc"].value) >>> 0; + _kVersionStampBuildClientStr = Module["_kVersionStampBuildClientStr"] = (wasmExports["yc"].value) >>> 0; + _kVersionStampBuildClientMintStatusStr = Module["_kVersionStampBuildClientMintStatusStr"] = (wasmExports["zc"].value) >>> 0; + _kVersionStampBuildCompilerStr = Module["_kVersionStampBuildCompilerStr"] = (wasmExports["Ac"].value) >>> 0; + _kVersionStampBuildDateTimePstStr = Module["_kVersionStampBuildDateTimePstStr"] = (wasmExports["Bc"].value) >>> 0; + _kVersionStampBuildDepotPathStr = Module["_kVersionStampBuildDepotPathStr"] = (wasmExports["Cc"].value) >>> 0; + _kVersionStampBuildIdStr = Module["_kVersionStampBuildIdStr"] = (wasmExports["Dc"].value) >>> 0; + _kVersionStampBuildInfoStr = Module["_kVersionStampBuildInfoStr"] = (wasmExports["Ec"].value) >>> 0; + _kVersionStampBuildLabelStr = Module["_kVersionStampBuildLabelStr"] = (wasmExports["Fc"].value) >>> 0; + _kVersionStampBuildTargetStr = Module["_kVersionStampBuildTargetStr"] = (wasmExports["Gc"].value) >>> 0; + _kVersionStampBuildTimestampStr = Module["_kVersionStampBuildTimestampStr"] = (wasmExports["Hc"].value) >>> 0; + _kVersionStampBuildToolStr = Module["_kVersionStampBuildToolStr"] = (wasmExports["Ic"].value) >>> 0; + _kVersionStampG3BuildTargetStr = Module["_kVersionStampG3BuildTargetStr"] = (wasmExports["Jc"].value) >>> 0; + _kVersionStampVerifiableStr = Module["_kVersionStampVerifiableStr"] = (wasmExports["Kc"].value) >>> 0; + _kVersionStampBuildFdoTypeStr = Module["_kVersionStampBuildFdoTypeStr"] = (wasmExports["Lc"].value) >>> 0; + _kVersionStampBuildBaselineChangelistStr = Module["_kVersionStampBuildBaselineChangelistStr"] = (wasmExports["Mc"].value) >>> 0; + _kVersionStampBuildLtoTypeStr = Module["_kVersionStampBuildLtoTypeStr"] = (wasmExports["Nc"].value) >>> 0; + _kVersionStampBuildPropellerTypeStr = Module["_kVersionStampBuildPropellerTypeStr"] = (wasmExports["Oc"].value) >>> 0; + _kVersionStampBuildPghoTypeStr = Module["_kVersionStampBuildPghoTypeStr"] = (wasmExports["Pc"].value) >>> 0; + _kVersionStampBuildUsernameStr = Module["_kVersionStampBuildUsernameStr"] = (wasmExports["Qc"].value) >>> 0; + _kVersionStampBuildHostnameStr = Module["_kVersionStampBuildHostnameStr"] = (wasmExports["Rc"].value) >>> 0; + _kVersionStampBuildDirectoryStr = Module["_kVersionStampBuildDirectoryStr"] = (wasmExports["Sc"].value) >>> 0; + _kVersionStampBuildChangelistInt = Module["_kVersionStampBuildChangelistInt"] = (wasmExports["Tc"].value) >>> 0; + _kVersionStampCitcSnapshotInt = Module["_kVersionStampCitcSnapshotInt"] = (wasmExports["Uc"].value) >>> 0; + _kVersionStampBuildClientMintStatusInt = Module["_kVersionStampBuildClientMintStatusInt"] = (wasmExports["Vc"].value) >>> 0; + _kVersionStampBuildTimestampInt = Module["_kVersionStampBuildTimestampInt"] = (wasmExports["Wc"].value) >>> 0; + _kVersionStampVerifiableInt = Module["_kVersionStampVerifiableInt"] = (wasmExports["Xc"].value) >>> 0; + _kVersionStampBuildCoverageEnabledInt = Module["_kVersionStampBuildCoverageEnabledInt"] = (wasmExports["Yc"].value) >>> 0; + _kVersionStampBuildBaselineChangelistInt = Module["_kVersionStampBuildBaselineChangelistInt"] = (wasmExports["Zc"].value) >>> 0; + _kVersionStampPrecookedTimestampStr = Module["_kVersionStampPrecookedTimestampStr"] = (wasmExports["_c"].value) >>> 0; + _kVersionStampPrecookedClientInfoStr = Module["_kVersionStampPrecookedClientInfoStr"] = (wasmExports["$c"].value) >>> 0; + __indirect_function_table = wasmExports["__indirect_function_table"]; +} + +var wasmImports = { + /** @export */ qc: DefaultErrorReporter, + /** @export */ pc: GetAdapterArchitecture, + /** @export */ oc: GetAdapterDescription, + /** @export */ nc: GetAdapterDeviceName, + /** @export */ mc: GetAdapterVendor, + /** @export */ kc: JsGetDeviceMaxSubgroupSize, + /** @export */ jc: JsGetDeviceMinSubgroupSize, + /** @export */ ic: JsOnEmptyPacketListener, + /** @export */ ma: JsOnSimpleListenerBinaryArray, + /** @export */ hc: JsOnSimpleListenerBool, + /** @export */ gc: JsOnSimpleListenerDouble, + /** @export */ fc: JsOnSimpleListenerFloat, + /** @export */ ec: JsOnSimpleListenerInt, + /** @export */ dc: JsOnSimpleListenerString, + /** @export */ cc: JsOnSimpleListenerUint, + /** @export */ p: JsOnVectorFinishedListener, + /** @export */ bc: JsOnVectorListenerBool, + /** @export */ ac: JsOnVectorListenerDouble, + /** @export */ $b: JsOnVectorListenerFloat, + /** @export */ _b: JsOnVectorListenerInt, + /** @export */ Zb: JsOnVectorListenerProto, + /** @export */ Yb: JsOnVectorListenerString, + /** @export */ Xb: JsOnVectorListenerUint, + /** @export */ la: JsProgressListener, + /** @export */ K: JsWrapErrorListener, + /** @export */ g: JsWrapSimpleListeners, + /** @export */ Wb: ThrowError, + /** @export */ ka: UseBottomLeftGpuOrigin, + /** @export */ Vb: __Unwind_RaiseException, + /** @export */ rc: __asyncjs__CallReadDataFn, + /** @export */ lc: __asyncjs__InvokeReadDataFn, + /** @export */ J: __asyncjs__ReadBufferDataJs, + /** @export */ Ea: __asyncjs__mediapipe_map_buffer_jspi, + /** @export */ Ub: ___syscall_dup, + /** @export */ Tb: ___syscall_faccessat, + /** @export */ ja: ___syscall_fcntl64, + /** @export */ Sb: ___syscall_fstat64, + /** @export */ Va: ___syscall_ftruncate64, + /** @export */ Rb: ___syscall_getcwd, + /** @export */ Qb: ___syscall_getdents64, + /** @export */ Pb: ___syscall_ioctl, + /** @export */ Ob: ___syscall_lstat64, + /** @export */ Nb: ___syscall_mkdirat, + /** @export */ Mb: ___syscall_newfstatat, + /** @export */ ia: ___syscall_openat, + /** @export */ Lb: ___syscall_stat64, + /** @export */ Gb: __abort_js, + /** @export */ Ra: __embind_register_bigint, + /** @export */ Fb: __embind_register_bool, + /** @export */ Eb: __embind_register_emval, + /** @export */ ga: __embind_register_float, + /** @export */ x: __embind_register_function, + /** @export */ n: __embind_register_integer, + /** @export */ e: __embind_register_memory_view, + /** @export */ Db: __embind_register_std_string, + /** @export */ I: __embind_register_std_wstring, + /** @export */ Cb: __embind_register_void, + /** @export */ fa: __emval_create_invoker, + /** @export */ l: __emval_decref, + /** @export */ o: __emval_incref, + /** @export */ ea: __emval_invoke, + /** @export */ da: __emval_run_destructors, + /** @export */ Qa: __gmtime_js, + /** @export */ Pa: __localtime_js, + /** @export */ Oa: __mktime_js, + /** @export */ Na: __mmap_js, + /** @export */ Ma: __munmap_js, + /** @export */ Bb: __tzset_js, + /** @export */ Ua: _clock_time_get, + /** @export */ Ab: custom_emscripten_dbgn, + /** @export */ s: _emscripten_asm_const_int, + /** @export */ H: _emscripten_errn, + /** @export */ zb: _emscripten_get_heap_max, + /** @export */ d: _emscripten_get_now, + /** @export */ ca: _emscripten_has_asyncify, + /** @export */ yb: _emscripten_outn, + /** @export */ xb: _emscripten_pc_get_function, + /** @export */ wb: _emscripten_resize_heap, + /** @export */ ba: _emscripten_stack_snapshot, + /** @export */ vb: _emscripten_stack_unwind_buffer, + /** @export */ ub: _emscripten_webgl_create_context, + /** @export */ tb: _emscripten_webgl_destroy_context, + /** @export */ sb: _emscripten_webgl_get_context_attributes, + /** @export */ r: _emscripten_webgl_get_current_context, + /** @export */ rb: _emscripten_webgl_make_context_current, + /** @export */ aa: _emscripten_webgpu_get_device, + /** @export */ qb: _emwgpuBufferDestroy, + /** @export */ pb: _emwgpuBufferGetMappedRange, + /** @export */ ob: _emwgpuBufferUnmap, + /** @export */ nb: _emwgpuBufferWriteMappedRange, + /** @export */ f: _emwgpuDelete, + /** @export */ mb: _emwgpuDeviceCreateBuffer, + /** @export */ La: _emwgpuDeviceCreateComputePipelineAsync, + /** @export */ lb: _emwgpuDeviceCreateShaderModule, + /** @export */ kb: _emwgpuDeviceDestroy, + /** @export */ Ka: _emwgpuQueueOnSubmittedWorkDone, + /** @export */ jb: _emwgpuWaitAny, + /** @export */ Kb: _environ_get, + /** @export */ Jb: _environ_sizes_get, + /** @export */ ib: _exit, + /** @export */ z: _fd_close, + /** @export */ Ta: _fd_pread, + /** @export */ ha: _fd_read, + /** @export */ Sa: _fd_seek, + /** @export */ y: _fd_write, + /** @export */ G: _glActiveTexture, + /** @export */ $: _glAttachShader, + /** @export */ hb: _glBindAttribLocation, + /** @export */ m: _glBindBuffer, + /** @export */ w: _glBindFramebuffer, + /** @export */ k: _glBindTexture, + /** @export */ F: _glBufferData, + /** @export */ q: _glClientWaitSync, + /** @export */ gb: _glCompileShader, + /** @export */ fb: _glCreateProgram, + /** @export */ eb: _glCreateShader, + /** @export */ _: _glDeleteFramebuffers, + /** @export */ db: _glDeleteProgram, + /** @export */ Z: _glDeleteShader, + /** @export */ v: _glDeleteSync, + /** @export */ Y: _glDeleteTextures, + /** @export */ X: _glDetachShader, + /** @export */ W: _glDisableVertexAttribArray, + /** @export */ cb: _glDrawArrays, + /** @export */ V: _glEnableVertexAttribArray, + /** @export */ U: _glFenceSync, + /** @export */ u: _glFinish, + /** @export */ E: _glFramebufferTexture2D, + /** @export */ T: _glGenBuffers, + /** @export */ bb: _glGenFramebuffers, + /** @export */ D: _glGenTextures, + /** @export */ t: _glGetError, + /** @export */ S: _glGetIntegerv, + /** @export */ C: _glGetString, + /** @export */ ab: _glGetUniformLocation, + /** @export */ $a: _glLinkProgram, + /** @export */ B: _glPixelStorei, + /** @export */ R: _glReadPixels, + /** @export */ _a: _glShaderSource, + /** @export */ Za: _glTexImage2D, + /** @export */ j: _glTexParameteri, + /** @export */ Q: _glTexStorage2D, + /** @export */ Ya: _glUniform1i, + /** @export */ Xa: _glUseProgram, + /** @export */ P: _glVertexAttribPointer, + /** @export */ Wa: _glViewport, + /** @export */ A: hardware_concurrency, + /** @export */ Ib: _proc_exit, + /** @export */ Hb: _random_get, + /** @export */ Ja: _wgpuBufferGetSize, + /** @export */ Ia: _wgpuBufferGetUsage, + /** @export */ i: _wgpuCommandEncoderBeginComputePass, + /** @export */ Ha: _wgpuCommandEncoderCopyBufferToBuffer, + /** @export */ O: _wgpuCommandEncoderCopyTextureToBuffer, + /** @export */ Da: _wgpuCommandEncoderCopyTextureToTexture, + /** @export */ c: _wgpuCommandEncoderFinish, + /** @export */ Ga: _wgpuCommandEncoderResolveQuerySet, + /** @export */ N: _wgpuComputePassEncoderDispatchWorkgroups, + /** @export */ h: _wgpuComputePassEncoderEnd, + /** @export */ Ca: _wgpuComputePassEncoderSetBindGroup, + /** @export */ M: _wgpuComputePassEncoderSetPipeline, + /** @export */ Ba: _wgpuDeviceCreateBindGroup, + /** @export */ Aa: _wgpuDeviceCreateBindGroupLayout, + /** @export */ b: _wgpuDeviceCreateCommandEncoder, + /** @export */ za: _wgpuDeviceCreateComputePipeline, + /** @export */ ya: _wgpuDeviceCreatePipelineLayout, + /** @export */ xa: _wgpuDeviceCreateQuerySet, + /** @export */ wa: _wgpuDeviceCreateTexture, + /** @export */ L: _wgpuDeviceGetAdapterInfo, + /** @export */ va: _wgpuDeviceGetLimits, + /** @export */ ua: _wgpuDeviceHasFeature, + /** @export */ a: _wgpuQueueSubmit, + /** @export */ Fa: _wgpuQueueWriteBuffer, + /** @export */ ta: _wgpuQueueWriteTexture, + /** @export */ sa: _wgpuTextureCreateView, + /** @export */ ra: _wgpuTextureDestroy, + /** @export */ qa: _wgpuTextureGetDepthOrArrayLayers, + /** @export */ pa: _wgpuTextureGetFormat, + /** @export */ oa: _wgpuTextureGetHeight, + /** @export */ na: _wgpuTextureGetWidth +}; + +// Argument name here must shadow the `wasmExports` global so +// that it is recognised by metadce and minify-import-export-names +// passes. +function applySignatureConversions(wasmExports) { + // First, make a copy of the incoming exports object + wasmExports = Object.assign({}, wasmExports); + var makeWrapper_pp = f => a0 => f(a0) >>> 0; + var makeWrapper_ppp = f => (a0, a1) => f(a0, a1) >>> 0; + var makeWrapper_p = f => () => f() >>> 0; + wasmExports["hd"] = makeWrapper_pp(wasmExports["hd"]); + wasmExports["se"] = makeWrapper_pp(wasmExports["se"]); + wasmExports["bf"] = makeWrapper_ppp(wasmExports["bf"]); + wasmExports["cf"] = makeWrapper_ppp(wasmExports["cf"]); + wasmExports["ff"] = makeWrapper_pp(wasmExports["ff"]); + wasmExports["gf"] = makeWrapper_p(wasmExports["gf"]); + return wasmExports; +} + +// include: postamble.js +// === Auto-generated postamble setup entry stuff === +function run() { + if (runDependencies > 0) { + dependenciesFulfilled = run; + return; + } + preRun(); + // a preRun added a dependency, run will be called later + if (runDependencies > 0) { + dependenciesFulfilled = run; + return; + } + function doRun() { + // run may have just been called through dependencies being fulfilled just in this very frame, + // or while the async setStatus time below was happening + Module["calledRun"] = true; + if (ABORT) return; + initRuntime(); + readyPromiseResolve?.(Module); + Module["onRuntimeInitialized"]?.(); + postRun(); + } + if (Module["setStatus"]) { + Module["setStatus"]("Running..."); + setTimeout(() => { + setTimeout(() => Module["setStatus"](""), 1); + doRun(); + }, 1); + } else { + doRun(); + } +} + +var wasmExports; + +// In modularize mode the generated code is within a factory function so we +// can use await here (since it's not top-level-await). +wasmExports = await (createWasm()); + +run(); + +// end include: postamble.js +// include: postamble_modularize.js +// In MODULARIZE mode we wrap the generated code in a factory function +// and return either the Module itself, or a promise of the module. +// We assign to the `moduleRtn` global here and configure closure to see +// this as an extern so it won't get minified. +if (runtimeInitialized) { + moduleRtn = Module; +} else { + // Set up the promise that indicates the Module is initialized + moduleRtn = new Promise((resolve, reject) => { + readyPromiseResolve = resolve; + readyPromiseReject = reject; + }); +} + + + return moduleRtn; + }; +})(); + +// Export using a UMD style export, or ES6 exports if selected +if (typeof exports === 'object' && typeof module === 'object') { + module.exports = ModuleFactory; + // This default export looks redundant, but it allows TS to import this + // commonjs style module. + module.exports.default = ModuleFactory; +} else if (typeof define === 'function' && define['amd']) + define([], () => ModuleFactory); + diff --git a/public/mediapipe/wasm/genai_wasm_internal.wasm b/public/mediapipe/wasm/genai_wasm_internal.wasm new file mode 100644 index 0000000..6de050b Binary files /dev/null and b/public/mediapipe/wasm/genai_wasm_internal.wasm differ diff --git a/public/mediapipe/wasm/genai_wasm_module_internal.js b/public/mediapipe/wasm/genai_wasm_module_internal.js new file mode 100644 index 0000000..9f8921c --- /dev/null +++ b/public/mediapipe/wasm/genai_wasm_module_internal.js @@ -0,0 +1,9031 @@ +// This code implements the `-sMODULARIZE` settings by taking the generated +// JS program code (INNER_JS_CODE) and wrapping it in a factory function. + +// When targeting node and ES6 we use `await import ..` in the generated code +// so the outer function needs to be marked as async. +async function ModuleFactory(moduleArg = {}) { + var moduleRtn; + +// include: shell.js +// include: minimum_runtime_check.js +// end include: minimum_runtime_check.js +// The Module object: Our interface to the outside world. We import +// and export values on it. There are various ways Module can be used: +// 1. Not defined. We create it here +// 2. A function parameter, function(moduleArg) => Promise +// 3. pre-run appended it, var Module = {}; ..generated code.. +// 4. External script tag defines var Module. +// We need to check if Module already exists (e.g. case 3 above). +// Substitution will be replaced with actual code on later stage of the build, +// this way Closure Compiler will not mangle it (e.g. case 4. above). +// Note that if you want to run closure, and also to use Module +// after the generated code, you will need to define var Module = {}; +// before the code. Then that object will be used in the code, and you +// can continue to use Module afterwards as well. +var Module = moduleArg; + +// Determine the runtime environment we are in. You can customize this by +// setting the ENVIRONMENT setting at compile time (see settings.js). +// Attempt to auto-detect the environment +var ENVIRONMENT_IS_WEB = !!globalThis.window; + +var ENVIRONMENT_IS_WORKER = !!globalThis.WorkerGlobalScope; + +// N.b. Electron.js environment is simultaneously a NODE-environment, but +// also a web environment. +var ENVIRONMENT_IS_NODE = globalThis.process?.versions?.node && globalThis.process?.type != "renderer"; + +if (ENVIRONMENT_IS_NODE) { + // When building an ES module `require` is not normally available. + // We need to use `createRequire()` to construct the require()` function. + const {createRequire} = await import("node:module"); + /** @suppress{duplicate} */ var require = createRequire(import.meta.url); +} + +// --pre-jses are emitted after the Module integration code, so that they can +// refer to Module (if they choose; they can also define Module) +var arguments_ = []; + +var thisProgram = "./this.program"; + +var quit_ = (status, toThrow) => { + throw toThrow; +}; + +var _scriptName = import.meta.url; + +// `/` should be present at the end if `scriptDirectory` is not empty +var scriptDirectory = ""; + +function locateFile(path) { + if (Module["locateFile"]) { + return Module["locateFile"](path, scriptDirectory); + } + return scriptDirectory + path; +} + +// Hooks that are implemented differently in different runtime environments. +var readAsync, readBinary; + +if (ENVIRONMENT_IS_NODE) { + // These modules will usually be used on Node.js. Load them eagerly to avoid + // the complexity of lazy-loading. + var fs = require("node:fs"); + if (_scriptName.startsWith("file:")) { + scriptDirectory = require("node:path").dirname(require("node:url").fileURLToPath(_scriptName)) + "/"; + } + // include: node_shell_read.js + readBinary = filename => { + // We need to re-wrap `file://` strings to URLs. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename); + return ret; + }; + readAsync = async (filename, binary = true) => { + // See the comment in the `readBinary` function. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename, binary ? undefined : "utf8"); + return ret; + }; + // end include: node_shell_read.js + if (process.argv.length > 1) { + thisProgram = process.argv[1].replace(/\\/g, "/"); + } + arguments_ = process.argv.slice(2); + quit_ = (status, toThrow) => { + process.exitCode = status; + throw toThrow; + }; +} else // Note that this includes Node.js workers when relevant (pthreads is enabled). +// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and +// ENVIRONMENT_IS_NODE. +if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + try { + scriptDirectory = new URL(".", _scriptName).href; + } catch {} + { + // include: web_or_worker_shell_read.js + if (ENVIRONMENT_IS_WORKER) { + readBinary = url => { + var xhr = new XMLHttpRequest; + xhr.open("GET", url, false); + xhr.responseType = "arraybuffer"; + xhr.send(null); + return new Uint8Array(/** @type{!ArrayBuffer} */ (xhr.response)); + }; + } + readAsync = async url => { + // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. + // See https://github.com/github/fetch/pull/92#issuecomment-140665932 + // Cordova or Electron apps are typically loaded from a file:// url. + // So use XHR on webview if URL is a file URL. + if (isFileURI(url)) { + return new Promise((resolve, reject) => { + var xhr = new XMLHttpRequest; + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + xhr.onload = () => { + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { + // file URLs can return 0 + resolve(xhr.response); + return; + } + reject(xhr.status); + }; + xhr.onerror = reject; + xhr.send(null); + }); + } + var response = await fetch(url, { + credentials: "same-origin" + }); + if (response.ok) { + return response.arrayBuffer(); + } + throw new Error(response.status + " : " + response.url); + }; + } +} else {} + +var out = console.log.bind(console); + +var err = console.error.bind(console); + +// end include: shell.js +// include: preamble.js +// === Preamble library stuff === +// Documentation for the public APIs defined in this file must be updated in: +// site/source/docs/api_reference/preamble.js.rst +// A prebuilt local version of the documentation is available at: +// site/build/text/docs/api_reference/preamble.js.txt +// You can also build docs locally as HTML or other formats in site/ +// An online HTML version (which may be of a different version of Emscripten) +// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html +var wasmBinary; + +// Wasm globals +//======================================== +// Runtime essentials +//======================================== +// whether we are quitting the application. no code should run after this. +// set in exit() and abort() +var ABORT = false; + +// set by exit() and abort(). Passed to 'onExit' handler. +// NOTE: This is also used as the process return code in shell environments +// but only when noExitRuntime is false. +var EXITSTATUS; + +// In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we +// don't define it at all in release modes. This matches the behaviour of +// MINIMAL_RUNTIME. +// TODO(sbc): Make this the default even without STRICT enabled. +/** @type {function(*, string=)} */ function assert(condition, text) { + if (!condition) { + // This build was created without ASSERTIONS defined. `assert()` should not + // ever be called in this configuration but in case there are callers in + // the wild leave this simple abort() implementation here for now. + abort(text); + } +} + +/** + * Indicates whether filename is delivered via file protocol (as opposed to http/https) + * @noinline + */ var isFileURI = filename => filename.startsWith("file://"); + +// include: runtime_common.js +// include: runtime_stack_check.js +// end include: runtime_stack_check.js +// include: runtime_exceptions.js +// end include: runtime_exceptions.js +// include: runtime_debug.js +// end include: runtime_debug.js +var readyPromiseResolve, readyPromiseReject; + +// Memory management +var /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Int16Array} */ HEAP16, /** @type {!Uint16Array} */ HEAPU16, /** @type {!Int32Array} */ HEAP32, /** @type {!Uint32Array} */ HEAPU32, /** @type {!Float32Array} */ HEAPF32, /** @type {!Float64Array} */ HEAPF64; + +var runtimeInitialized = false; + +function updateMemoryViews() { + var b = wasmMemory.buffer; + HEAP8 = new Int8Array(b); + HEAP16 = new Int16Array(b); + Module["HEAPU8"] = HEAPU8 = new Uint8Array(b); + HEAPU16 = new Uint16Array(b); + HEAP32 = new Int32Array(b); + Module["HEAPU32"] = HEAPU32 = new Uint32Array(b); + Module["HEAPF32"] = HEAPF32 = new Float32Array(b); + Module["HEAPF64"] = HEAPF64 = new Float64Array(b); +} + +// include: memoryprofiler.js +// end include: memoryprofiler.js +// end include: runtime_common.js +function preRun() { + if (Module["preRun"]) { + if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ]; + while (Module["preRun"].length) { + addOnPreRun(Module["preRun"].shift()); + } + } + // Begin ATPRERUNS hooks + callRuntimeCallbacks(onPreRuns); +} + +function initRuntime() { + runtimeInitialized = true; + // Begin ATINITS hooks + if (!Module["noFSInit"] && !FS.initialized) FS.init(); + TTY.init(); + // End ATINITS hooks + wasmExports["tc"](); + // Begin ATPOSTCTORS hooks + FS.ignorePermissions = false; +} + +function postRun() { + // PThreads reuse the runtime from the main thread. + if (Module["postRun"]) { + if (typeof Module["postRun"] == "function") Module["postRun"] = [ Module["postRun"] ]; + while (Module["postRun"].length) { + addOnPostRun(Module["postRun"].shift()); + } + } + // Begin ATPOSTRUNS hooks + callRuntimeCallbacks(onPostRuns); +} + +/** @param {string|number=} what */ function abort(what) { + Module["onAbort"]?.(what); + what = "Aborted(" + what + ")"; + // TODO(sbc): Should we remove printing and leave it up to whoever + // catches the exception? + err(what); + ABORT = true; + what += ". Build with -sASSERTIONS for more info."; + // Use a wasm runtime error, because a JS error might be seen as a foreign + // exception, which means we'd run destructors on it. We need the error to + // simply make the program stop. + // FIXME This approach does not work in Wasm EH because it currently does not assume + // all RuntimeErrors are from traps; it decides whether a RuntimeError is from + // a trap or not based on a hidden field within the object. So at the moment + // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that + // allows this in the wasm spec. + // Suppress closure compiler warning here. Closure compiler's builtin extern + // definition for WebAssembly.RuntimeError claims it takes no arguments even + // though it can. + // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. + /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); + readyPromiseReject?.(e); + // Throw the error whether or not MODULARIZE is set because abort is used + // in code paths apart from instantiation where an exception is expected + // to be thrown when abort is called. + throw e; +} + +var wasmBinaryFile; + +function findWasmBinary() { + if (Module["locateFile"]) { + return locateFile("genai_wasm_module_internal.wasm"); + } + // Use bundler-friendly `new URL(..., import.meta.url)` pattern; works in browsers too. + return new URL("genai_wasm_module_internal.wasm", import.meta.url).href; +} + +function getBinarySync(file) { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + // Throwing a plain string here, even though it not normally advisable since + // this gets turning into an `abort` in instantiateArrayBuffer. + throw "both async and sync fetching of the wasm failed"; +} + +async function getWasmBinary(binaryFile) { + // If we don't have the binary yet, load it asynchronously using readAsync. + if (!wasmBinary) { + // Fetch the binary using readAsync + try { + var response = await readAsync(binaryFile); + return new Uint8Array(response); + } catch {} + } + // Otherwise, getBinarySync should be able to get it synchronously + return getBinarySync(binaryFile); +} + +async function instantiateArrayBuffer(binaryFile, imports) { + try { + var binary = await getWasmBinary(binaryFile); + var instance = await WebAssembly.instantiate(binary, imports); + return instance; + } catch (reason) { + err(`failed to asynchronously prepare wasm: ${reason}`); + abort(reason); + } +} + +async function instantiateAsync(binary, binaryFile, imports) { + if (!binary && !isFileURI(binaryFile) && !ENVIRONMENT_IS_NODE) { + try { + var response = fetch(binaryFile, { + credentials: "same-origin" + }); + var instantiationResult = await WebAssembly.instantiateStreaming(response, imports); + return instantiationResult; + } catch (reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err(`wasm streaming compile failed: ${reason}`); + err("falling back to ArrayBuffer instantiation"); + } + } + return instantiateArrayBuffer(binaryFile, imports); +} + +function getWasmImports() { + // prepare imports + var imports = { + "a": wasmImports + }; + return imports; +} + +// Create the wasm instance. +// Receives the wasm imports, returns the exports. +async function createWasm() { + // Load the wasm module and create an instance of using native support in the JS engine. + // handle a generated wasm instance, receiving its exports and + // performing other necessary setup + /** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) { + wasmExports = instance.exports; + wasmExports = Asyncify.instrumentWasmExports(wasmExports); + wasmExports = applySignatureConversions(wasmExports); + assignWasmExports(wasmExports); + updateMemoryViews(); + return wasmExports; + } + // Prefer streaming instantiation if available. + function receiveInstantiationResult(result) { + // 'result' is a ResultObject object which has both the module and instance. + // receiveInstance() will swap in the exports (to Module.asm) so they can be called + // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. + // When the regression is fixed, can restore the above PTHREADS-enabled path. + return receiveInstance(result["instance"]); + } + var info = getWasmImports(); + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback + // to manually instantiate the Wasm module themselves. This allows pages to + // run the instantiation parallel to any other async startup actions they are + // performing. + // Also pthreads and wasm workers initialize the wasm instance through this + // path. + if (Module["instantiateWasm"]) { + return new Promise((resolve, reject) => { + Module["instantiateWasm"](info, (inst, mod) => { + resolve(receiveInstance(inst, mod)); + }); + }); + } + wasmBinaryFile ??= findWasmBinary(); + var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); + var exports = receiveInstantiationResult(result); + return exports; +} + +// Globals used by JS i64 conversions (see makeSetValue) +var tempDouble; + +var tempI64; + +// end include: preamble.js +// Begin JS library code +var handleException = e => { + // Certain exception types we do not treat as errors since they are used for + // internal control flow. + // 1. ExitStatus, which is thrown by exit() + // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others + // that wish to return to JS event loop. + if (e instanceof ExitStatus || e == "unwind") { + return EXITSTATUS; + } + quit_(1, e); +}; + +class ExitStatus { + name="ExitStatus"; + constructor(status) { + this.message = `Program terminated with exit(${status})`; + this.status = status; + } +} + +var runtimeKeepaliveCounter = 0; + +var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; + +var _proc_exit = code => { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + Module["onExit"]?.(code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); +}; + +/** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => { + EXITSTATUS = status; + _proc_exit(status); +}; + +var _exit = exitJS; + +var maybeExit = () => { + if (!keepRuntimeAlive()) { + try { + _exit(EXITSTATUS); + } catch (e) { + handleException(e); + } + } +}; + +var callUserCallback = func => { + if (ABORT) { + return; + } + try { + return func(); + } catch (e) { + handleException(e); + } finally { + maybeExit(); + } +}; + +function getFullscreenElement() { + return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.webkitCurrentFullScreenElement || document.msFullscreenElement; +} + +/** @param {number=} timeout */ var safeSetTimeout = (func, timeout) => setTimeout(() => { + callUserCallback(func); +}, timeout); + +var warnOnce = text => { + warnOnce.shown ||= {}; + if (!warnOnce.shown[text]) { + warnOnce.shown[text] = 1; + if (ENVIRONMENT_IS_NODE) text = "warning: " + text; + err(text); + } +}; + +var preloadPlugins = []; + +var Browser = { + useWebGL: false, + isFullscreen: false, + pointerLock: false, + moduleContextCreatedCallbacks: [], + workers: [], + preloadedImages: {}, + preloadedAudios: {}, + getCanvas: () => Module["canvas"], + init() { + if (Browser.initted) return; + Browser.initted = true; + // Support for plugins that can process preloaded files. You can add more of these to + // your app by creating and appending to preloadPlugins. + // Each plugin is asked if it can handle a file based on the file's name. If it can, + // it is given the file's raw data. When it is done, it calls a callback with the file's + // (possibly modified) data. For example, a plugin might decompress a file, or it + // might create some side data structure for use later (like an Image element, etc.). + var imagePlugin = {}; + imagePlugin["canHandle"] = name => !Module["noImageDecoding"] && /\.(jpg|jpeg|png|bmp|webp)$/i.test(name); + imagePlugin["handle"] = async (byteArray, name) => { + var b = new Blob([ byteArray ], { + type: Browser.getMimetype(name) + }); + if (b.size !== byteArray.length) { + // Safari bug #118630 + // Safari's Blob can only take an ArrayBuffer + b = new Blob([ (new Uint8Array(byteArray)).buffer ], { + type: Browser.getMimetype(name) + }); + } + var url = URL.createObjectURL(b); + return new Promise((resolve, reject) => { + var img = new Image; + img.onload = () => { + var canvas = /** @type {!HTMLCanvasElement} */ (document.createElement("canvas")); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); + Browser.preloadedImages[name] = canvas; + URL.revokeObjectURL(url); + resolve(byteArray); + }; + img.onerror = event => { + err(`Image ${url} could not be decoded`); + reject(); + }; + img.src = url; + }); + }; + preloadPlugins.push(imagePlugin); + var audioPlugin = {}; + audioPlugin["canHandle"] = name => !Module["noAudioDecoding"] && name.slice(-4) in { + ".ogg": 1, + ".wav": 1, + ".mp3": 1 + }; + audioPlugin["handle"] = async (byteArray, name) => new Promise((resolve, reject) => { + var done = false; + function finish(audio) { + if (done) return; + done = true; + Browser.preloadedAudios[name] = audio; + resolve(byteArray); + } + var b = new Blob([ byteArray ], { + type: Browser.getMimetype(name) + }); + var url = URL.createObjectURL(b); + // XXX we never revoke this! + var audio = new Audio; + audio.addEventListener("canplaythrough", () => finish(audio), false); + // use addEventListener due to chromium bug 124926 + audio.onerror = event => { + if (done) return; + err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`); + function encode64(data) { + var BASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var PAD = "="; + var ret = ""; + var leftchar = 0; + var leftbits = 0; + for (var i = 0; i < data.length; i++) { + leftchar = (leftchar << 8) | data[i]; + leftbits += 8; + while (leftbits >= 6) { + var curr = (leftchar >> (leftbits - 6)) & 63; + leftbits -= 6; + ret += BASE[curr]; + } + } + if (leftbits == 2) { + ret += BASE[(leftchar & 3) << 4]; + ret += PAD + PAD; + } else if (leftbits == 4) { + ret += BASE[(leftchar & 15) << 2]; + ret += PAD; + } + return ret; + } + audio.src = "data:audio/x-" + name.slice(-3) + ";base64," + encode64(byteArray); + finish(audio); + }; + audio.src = url; + // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror + safeSetTimeout(() => { + finish(audio); + }, 1e4); + }); + preloadPlugins.push(audioPlugin); + // Canvas event setup + function pointerLockChange() { + var canvas = Browser.getCanvas(); + Browser.pointerLock = document.pointerLockElement === canvas; + } + var canvas = Browser.getCanvas(); + if (canvas) { + // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module + // Module['forcedAspectRatio'] = 4 / 3; + document.addEventListener("pointerlockchange", pointerLockChange, false); + if (Module["elementPointerLock"]) { + canvas.addEventListener("click", ev => { + if (!Browser.pointerLock && Browser.getCanvas().requestPointerLock) { + Browser.getCanvas().requestPointerLock(); + ev.preventDefault(); + } + }, false); + } + } + }, + createContext(/** @type {HTMLCanvasElement} */ canvas, useWebGL, setInModule, webGLContextAttributes) { + if (useWebGL && Module["ctx"] && canvas == Browser.getCanvas()) return Module["ctx"]; + // no need to recreate GL context if it's already been created for this canvas. + var ctx; + var contextHandle; + if (useWebGL) { + // For GLES2/desktop GL compatibility, adjust a few defaults to be different to WebGL defaults, so that they align better with the desktop defaults. + var contextAttributes = { + antialias: false, + alpha: false, + majorVersion: (typeof WebGL2RenderingContext != "undefined") ? 2 : 1 + }; + if (webGLContextAttributes) { + for (var attribute in webGLContextAttributes) { + contextAttributes[attribute] = webGLContextAttributes[attribute]; + } + } + // This check of existence of GL is here to satisfy Closure compiler, which yells if variable GL is referenced below but GL object is not + // actually compiled in because application is not doing any GL operations. TODO: Ideally if GL is not being used, this function + // Browser.createContext() should not even be emitted. + if (typeof GL != "undefined") { + contextHandle = GL.createContext(canvas, contextAttributes); + if (contextHandle) { + ctx = GL.getContext(contextHandle).GLctx; + } + } + } else { + ctx = canvas.getContext("2d"); + } + if (!ctx) return null; + if (setInModule) { + Module["ctx"] = ctx; + if (useWebGL) GL.makeContextCurrent(contextHandle); + Browser.useWebGL = useWebGL; + Browser.moduleContextCreatedCallbacks.forEach(callback => callback()); + Browser.init(); + } + return ctx; + }, + fullscreenHandlersInstalled: false, + lockPointer: undefined, + resizeCanvas: undefined, + requestFullscreen(lockPointer, resizeCanvas) { + Browser.lockPointer = lockPointer; + Browser.resizeCanvas = resizeCanvas; + if (typeof Browser.lockPointer == "undefined") Browser.lockPointer = true; + if (typeof Browser.resizeCanvas == "undefined") Browser.resizeCanvas = false; + var canvas = Browser.getCanvas(); + function fullscreenChange() { + Browser.isFullscreen = false; + var canvasContainer = canvas.parentNode; + if (getFullscreenElement() === canvasContainer) { + canvas.exitFullscreen = Browser.exitFullscreen; + if (Browser.lockPointer) canvas.requestPointerLock(); + Browser.isFullscreen = true; + if (Browser.resizeCanvas) { + Browser.setFullscreenCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } else { + // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen + canvasContainer.parentNode.insertBefore(canvas, canvasContainer); + canvasContainer.parentNode.removeChild(canvasContainer); + if (Browser.resizeCanvas) { + Browser.setWindowedCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } + Module["onFullScreen"]?.(Browser.isFullscreen); + Module["onFullscreen"]?.(Browser.isFullscreen); + } + if (!Browser.fullscreenHandlersInstalled) { + Browser.fullscreenHandlersInstalled = true; + document.addEventListener("fullscreenchange", fullscreenChange, false); + document.addEventListener("mozfullscreenchange", fullscreenChange, false); + document.addEventListener("webkitfullscreenchange", fullscreenChange, false); + document.addEventListener("MSFullscreenChange", fullscreenChange, false); + } + // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root + var canvasContainer = document.createElement("div"); + canvas.parentNode.insertBefore(canvasContainer, canvas); + canvasContainer.appendChild(canvas); + // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size) + canvasContainer.requestFullscreen = canvasContainer["requestFullscreen"] || canvasContainer["mozRequestFullScreen"] || canvasContainer["msRequestFullscreen"] || (canvasContainer["webkitRequestFullscreen"] ? () => canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]) : null) || (canvasContainer["webkitRequestFullScreen"] ? () => canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]) : null); + canvasContainer.requestFullscreen(); + }, + exitFullscreen() { + // This is workaround for chrome. Trying to exit from fullscreen + // not in fullscreen state will cause "TypeError: Document not active" + // in chrome. See https://github.com/emscripten-core/emscripten/pull/8236 + if (!Browser.isFullscreen) { + return false; + } + var CFS = document["exitFullscreen"] || document["cancelFullScreen"] || document["mozCancelFullScreen"] || document["msExitFullscreen"] || document["webkitCancelFullScreen"] || (() => {}); + CFS.apply(document, []); + return true; + }, + safeSetTimeout(func, timeout) { + // Legacy function, this is used by the SDL2 port so we need to keep it + // around at least until that is updated. + // See https://github.com/libsdl-org/SDL/pull/6304 + return safeSetTimeout(func, timeout); + }, + getMimetype(name) { + return { + "jpg": "image/jpeg", + "jpeg": "image/jpeg", + "png": "image/png", + "bmp": "image/bmp", + "ogg": "audio/ogg", + "wav": "audio/wav", + "mp3": "audio/mpeg" + }[name.slice(name.lastIndexOf(".") + 1)]; + }, + getUserMedia(func) { + window.getUserMedia ||= navigator["getUserMedia"] || navigator["mozGetUserMedia"]; + window.getUserMedia(func); + }, + getMovementX(event) { + return event["movementX"] || event["mozMovementX"] || event["webkitMovementX"] || 0; + }, + getMovementY(event) { + return event["movementY"] || event["mozMovementY"] || event["webkitMovementY"] || 0; + }, + getMouseWheelDelta(event) { + var delta = 0; + switch (event.type) { + case "DOMMouseScroll": + // 3 lines make up a step + delta = event.detail / 3; + break; + + case "mousewheel": + // 120 units make up a step + delta = event.wheelDelta / 120; + break; + + case "wheel": + delta = event.deltaY; + switch (event.deltaMode) { + case 0: + // DOM_DELTA_PIXEL: 100 pixels make up a step + delta /= 100; + break; + + case 1: + // DOM_DELTA_LINE: 3 lines make up a step + delta /= 3; + break; + + case 2: + // DOM_DELTA_PAGE: A page makes up 80 steps + delta *= 80; + break; + + default: + abort("unrecognized mouse wheel delta mode: " + event.deltaMode); + } + break; + + default: + abort("unrecognized mouse wheel event: " + event.type); + } + return delta; + }, + mouseX: 0, + mouseY: 0, + mouseMovementX: 0, + mouseMovementY: 0, + touches: {}, + lastTouches: {}, + calculateMouseCoords(pageX, pageY) { + // Calculate the movement based on the changes + // in the coordinates. + var canvas = Browser.getCanvas(); + var rect = canvas.getBoundingClientRect(); + // Neither .scrollX or .pageXOffset are defined in a spec, but + // we prefer .scrollX because it is currently in a spec draft. + // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/) + var scrollX = ((typeof window.scrollX != "undefined") ? window.scrollX : window.pageXOffset); + var scrollY = ((typeof window.scrollY != "undefined") ? window.scrollY : window.pageYOffset); + var adjustedX = pageX - (scrollX + rect.left); + var adjustedY = pageY - (scrollY + rect.top); + // the canvas might be CSS-scaled compared to its backbuffer; + // SDL-using content will want mouse coordinates in terms + // of backbuffer units. + adjustedX = adjustedX * (canvas.width / rect.width); + adjustedY = adjustedY * (canvas.height / rect.height); + return { + x: adjustedX, + y: adjustedY + }; + }, + setMouseCoords(pageX, pageY) { + const {x, y} = Browser.calculateMouseCoords(pageX, pageY); + Browser.mouseMovementX = x - Browser.mouseX; + Browser.mouseMovementY = y - Browser.mouseY; + Browser.mouseX = x; + Browser.mouseY = y; + }, + calculateMouseEvent(event) { + // event should be mousemove, mousedown or mouseup + if (Browser.pointerLock) { + // When the pointer is locked, calculate the coordinates + // based on the movement of the mouse. + // Workaround for Firefox bug 764498 + if (event.type != "mousemove" && ("mozMovementX" in event)) { + Browser.mouseMovementX = Browser.mouseMovementY = 0; + } else { + Browser.mouseMovementX = Browser.getMovementX(event); + Browser.mouseMovementY = Browser.getMovementY(event); + } + // add the mouse delta to the current absolute mouse position + Browser.mouseX += Browser.mouseMovementX; + Browser.mouseY += Browser.mouseMovementY; + } else { + if (event.type === "touchstart" || event.type === "touchend" || event.type === "touchmove") { + var touch = event.touch; + if (touch === undefined) { + return; + } + var coords = Browser.calculateMouseCoords(touch.pageX, touch.pageY); + if (event.type === "touchstart") { + Browser.lastTouches[touch.identifier] = coords; + Browser.touches[touch.identifier] = coords; + } else if (event.type === "touchend" || event.type === "touchmove") { + var last = Browser.touches[touch.identifier]; + last ||= coords; + Browser.lastTouches[touch.identifier] = last; + Browser.touches[touch.identifier] = coords; + } + return; + } + Browser.setMouseCoords(event.pageX, event.pageY); + } + }, + resizeListeners: [], + updateResizeListeners() { + var canvas = Browser.getCanvas(); + Browser.resizeListeners.forEach(listener => listener(canvas.width, canvas.height)); + }, + setCanvasSize(width, height, noUpdates) { + var canvas = Browser.getCanvas(); + Browser.updateCanvasDimensions(canvas, width, height); + if (!noUpdates) Browser.updateResizeListeners(); + }, + windowedWidth: 0, + windowedHeight: 0, + setFullscreenCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen) >>> 2) >>> 0]; + flags = flags | 8388608; + // set SDL_FULLSCREEN flag + HEAP32[((SDL.screen) >>> 2) >>> 0] = flags; + } + Browser.updateCanvasDimensions(Browser.getCanvas()); + Browser.updateResizeListeners(); + }, + setWindowedCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen) >>> 2) >>> 0]; + flags = flags & ~8388608; + // clear SDL_FULLSCREEN flag + HEAP32[((SDL.screen) >>> 2) >>> 0] = flags; + } + Browser.updateCanvasDimensions(Browser.getCanvas()); + Browser.updateResizeListeners(); + }, + updateCanvasDimensions(canvas, wNative, hNative) { + if (wNative && hNative) { + canvas.widthNative = wNative; + canvas.heightNative = hNative; + } else { + wNative = canvas.widthNative; + hNative = canvas.heightNative; + } + var w = wNative; + var h = hNative; + if (Module["forcedAspectRatio"] > 0) { + if (w / h < Module["forcedAspectRatio"]) { + w = Math.round(h * Module["forcedAspectRatio"]); + } else { + h = Math.round(w / Module["forcedAspectRatio"]); + } + } + if ((getFullscreenElement() === canvas.parentNode) && (typeof screen != "undefined")) { + var factor = Math.min(screen.width / w, screen.height / h); + w = Math.round(w * factor); + h = Math.round(h * factor); + } + if (Browser.resizeCanvas) { + if (canvas.width != w) canvas.width = w; + if (canvas.height != h) canvas.height = h; + if (typeof canvas.style != "undefined") { + canvas.style.removeProperty("width"); + canvas.style.removeProperty("height"); + } + } else { + if (canvas.width != wNative) canvas.width = wNative; + if (canvas.height != hNative) canvas.height = hNative; + if (typeof canvas.style != "undefined") { + if (w != wNative || h != hNative) { + canvas.style.setProperty("width", w + "px", "important"); + canvas.style.setProperty("height", h + "px", "important"); + } else { + canvas.style.removeProperty("width"); + canvas.style.removeProperty("height"); + } + } + } + } +}; + +var callRuntimeCallbacks = callbacks => { + while (callbacks.length > 0) { + // Pass the module as the first argument. + callbacks.shift()(Module); + } +}; + +var onPostRuns = []; + +var addOnPostRun = cb => onPostRuns.push(cb); + +var onPreRuns = []; + +var addOnPreRun = cb => onPreRuns.push(cb); + +var dynCalls = {}; + +var dynCallLegacy = (sig, ptr, args) => { + sig = sig.replace(/p/g, "i"); + var f = dynCalls[sig]; + return f(ptr, ...args); +}; + +var dynCall = (sig, ptr, args = [], promising = false) => { + var rtn = dynCallLegacy(sig, ptr, args); + function convert(rtn) { + return sig[0] == "p" ? rtn >>> 0 : rtn; + } + return convert(rtn); +}; + +var noExitRuntime = true; + +var stackRestore = val => __emscripten_stack_restore(val); + +var stackSave = () => _emscripten_stack_get_current(); + +class ExceptionInfo { + // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. + constructor(excPtr) { + this.excPtr = excPtr; + this.ptr = excPtr - 24; + } + set_type(type) { + HEAPU32[(((this.ptr) + (4)) >>> 2) >>> 0] = type; + } + get_type() { + return HEAPU32[(((this.ptr) + (4)) >>> 2) >>> 0]; + } + set_destructor(destructor) { + HEAPU32[(((this.ptr) + (8)) >>> 2) >>> 0] = destructor; + } + get_destructor() { + return HEAPU32[(((this.ptr) + (8)) >>> 2) >>> 0]; + } + set_caught(caught) { + caught = caught ? 1 : 0; + HEAP8[(this.ptr) + (12) >>> 0] = caught; + } + get_caught() { + return HEAP8[(this.ptr) + (12) >>> 0] != 0; + } + set_rethrown(rethrown) { + rethrown = rethrown ? 1 : 0; + HEAP8[(this.ptr) + (13) >>> 0] = rethrown; + } + get_rethrown() { + return HEAP8[(this.ptr) + (13) >>> 0] != 0; + } + // Initialize native structure fields. Should be called once after allocated. + init(type, destructor) { + this.set_adjusted_ptr(0); + this.set_type(type); + this.set_destructor(destructor); + } + set_adjusted_ptr(adjustedPtr) { + HEAPU32[(((this.ptr) + (16)) >>> 2) >>> 0] = adjustedPtr; + } + get_adjusted_ptr() { + return HEAPU32[(((this.ptr) + (16)) >>> 2) >>> 0]; + } +} + +var exceptionLast = 0; + +var uncaughtExceptionCount = 0; + +var convertI32PairToI53Checked = (lo, hi) => ((hi + 2097152) >>> 0 < 4194305 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; + +function ___cxa_throw(ptr, type, destructor) { + ptr >>>= 0; + type >>>= 0; + destructor >>>= 0; + var info = new ExceptionInfo(ptr); + // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception. + info.init(type, destructor); + exceptionLast = ptr; + uncaughtExceptionCount++; + throw exceptionLast; +} + +function __Unwind_RaiseException(ex) { + ex >>>= 0; + err("Warning: _Unwind_RaiseException is not correctly implemented"); + return ___cxa_throw(ex, 0, 0); +} + +var PATH = { + isAbs: path => path.charAt(0) === "/", + splitPath: filename => { + var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + }, + normalizeArray: (parts, allowAboveRoot) => { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === ".") { + parts.splice(i, 1); + } else if (last === "..") { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (;up; up--) { + parts.unshift(".."); + } + } + return parts; + }, + normalize: path => { + var isAbsolute = PATH.isAbs(path), trailingSlash = path.slice(-1) === "/"; + // Normalize the path + path = PATH.normalizeArray(path.split("/").filter(p => !!p), !isAbsolute).join("/"); + if (!path && !isAbsolute) { + path = "."; + } + if (path && trailingSlash) { + path += "/"; + } + return (isAbsolute ? "/" : "") + path; + }, + dirname: path => { + var result = PATH.splitPath(path), root = result[0], dir = result[1]; + if (!root && !dir) { + // No dirname whatsoever + return "."; + } + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.slice(0, -1); + } + return root + dir; + }, + basename: path => path && path.match(/([^\/]+|\/)\/*$/)[1], + join: (...paths) => PATH.normalize(paths.join("/")), + join2: (l, r) => PATH.normalize(l + "/" + r) +}; + +var initRandomFill = () => { + // This block is not needed on v19+ since crypto.getRandomValues is builtin + if (ENVIRONMENT_IS_NODE) { + var nodeCrypto = require("node:crypto"); + return view => nodeCrypto.randomFillSync(view); + } + return view => crypto.getRandomValues(view); +}; + +var randomFill = view => { + // Lazily init on the first invocation. + (randomFill = initRandomFill())(view); +}; + +var PATH_FS = { + resolve: (...args) => { + var resolvedPath = "", resolvedAbsolute = false; + for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? args[i] : FS.cwd(); + // Skip empty and invalid entries + if (typeof path != "string") { + throw new TypeError("Arguments to path.resolve must be strings"); + } else if (!path) { + return ""; + } + resolvedPath = path + "/" + resolvedPath; + resolvedAbsolute = PATH.isAbs(path); + } + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(p => !!p), !resolvedAbsolute).join("/"); + return ((resolvedAbsolute ? "/" : "") + resolvedPath) || "."; + }, + relative: (from, to) => { + from = PATH_FS.resolve(from).slice(1); + to = PATH_FS.resolve(to).slice(1); + function trim(arr) { + var start = 0; + for (;start < arr.length; start++) { + if (arr[start] !== "") break; + } + var end = arr.length - 1; + for (;end >= 0; end--) { + if (arr[end] !== "") break; + } + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + var fromParts = trim(from.split("/")); + var toParts = trim(to.split("/")); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push(".."); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join("/"); + } +}; + +var UTF8Decoder = new TextDecoder; + +var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => { + var maxIdx = idx + maxBytesToRead; + if (ignoreNul) return maxIdx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on + // null terminator by itself. + // As a tiny code save trick, compare idx against maxIdx using a negation, + // so that maxBytesToRead=undefined/NaN means Infinity. + while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx; + return idx; +}; + +/** + * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given + * array that contains uint8 values, returns a copy of that string as a + * Javascript String object. + * heapOrArray is either a regular array, or a JavaScript typed array view. + * @param {number=} idx + * @param {number=} maxBytesToRead + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead, ignoreNul) => { + idx >>>= 0; + var endPtr = findStringEnd(heapOrArray, idx, maxBytesToRead, ignoreNul); + return UTF8Decoder.decode(heapOrArray.buffer ? heapOrArray.subarray(idx, endPtr) : new Uint8Array(heapOrArray.slice(idx, endPtr))); +}; + +var FS_stdin_getChar_buffer = []; + +var lengthBytesUTF8 = str => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); + // possibly a lead surrogate + if (c <= 127) { + len++; + } else if (c <= 2047) { + len += 2; + } else if (c >= 55296 && c <= 57343) { + len += 4; + ++i; + } else { + len += 3; + } + } + return len; +}; + +var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { + outIdx >>>= 0; + // Parameter maxBytesToWrite is not optional. Negative values, 0, null, + // undefined and false each don't write out any bytes. + if (!(maxBytesToWrite > 0)) return 0; + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description + // and https://www.ietf.org/rfc/rfc2279.txt + // and https://tools.ietf.org/html/rfc3629 + var u = str.codePointAt(i); + if (u <= 127) { + if (outIdx >= endIdx) break; + heap[outIdx++ >>> 0] = u; + } else if (u <= 2047) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++ >>> 0] = 192 | (u >> 6); + heap[outIdx++ >>> 0] = 128 | (u & 63); + } else if (u <= 65535) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++ >>> 0] = 224 | (u >> 12); + heap[outIdx++ >>> 0] = 128 | ((u >> 6) & 63); + heap[outIdx++ >>> 0] = 128 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++ >>> 0] = 240 | (u >> 18); + heap[outIdx++ >>> 0] = 128 | ((u >> 12) & 63); + heap[outIdx++ >>> 0] = 128 | ((u >> 6) & 63); + heap[outIdx++ >>> 0] = 128 | (u & 63); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + i++; + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx >>> 0] = 0; + return outIdx - startIdx; +}; + +/** @type {function(string, boolean=, number=)} */ var intArrayFromString = (stringy, dontAddNull, length) => { + var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); + if (dontAddNull) u8array.length = numBytesWritten; + return u8array; +}; + +var FS_stdin_getChar = () => { + if (!FS_stdin_getChar_buffer.length) { + var result = null; + if (ENVIRONMENT_IS_NODE) { + // we will read data by chunks of BUFSIZE + var BUFSIZE = 256; + var buf = Buffer.alloc(BUFSIZE); + var bytesRead = 0; + // For some reason we must suppress a closure warning here, even though + // fd definitely exists on process.stdin, and is even the proper way to + // get the fd of stdin, + // https://github.com/nodejs/help/issues/2136#issuecomment-523649904 + // This started to happen after moving this logic out of library_tty.js, + // so it is related to the surrounding code in some unclear manner. + /** @suppress {missingProperties} */ var fd = process.stdin.fd; + try { + bytesRead = fs.readSync(fd, buf, 0, BUFSIZE); + } catch (e) { + // Cross-platform differences: on Windows, reading EOF throws an + // exception, but on other OSes, reading EOF returns 0. Uniformize + // behavior by treating the EOF exception to return 0. + if (e.toString().includes("EOF")) bytesRead = 0; else throw e; + } + if (bytesRead > 0) { + result = buf.slice(0, bytesRead).toString("utf-8"); + } + } else if (globalThis.window?.prompt) { + // Browser. + result = window.prompt("Input: "); + // returns null on cancel + if (result !== null) { + result += "\n"; + } + } else {} + if (!result) { + return null; + } + FS_stdin_getChar_buffer = intArrayFromString(result, true); + } + return FS_stdin_getChar_buffer.shift(); +}; + +var TTY = { + ttys: [], + init() {}, + shutdown() {}, + register(dev, ops) { + TTY.ttys[dev] = { + input: [], + output: [], + ops + }; + FS.registerDevice(dev, TTY.stream_ops); + }, + stream_ops: { + open(stream) { + var tty = TTY.ttys[stream.node.rdev]; + if (!tty) { + throw new FS.ErrnoError(43); + } + stream.tty = tty; + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + stream.tty.ops.fsync(stream.tty); + }, + fsync(stream) { + stream.tty.ops.fsync(stream.tty); + }, + read(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.get_char) { + throw new FS.ErrnoError(60); + } + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = stream.tty.ops.get_char(stream.tty); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.put_char) { + throw new FS.ErrnoError(60); + } + try { + for (var i = 0; i < length; i++) { + stream.tty.ops.put_char(stream.tty, buffer[offset + i]); + } + } catch (e) { + throw new FS.ErrnoError(29); + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + } + }, + default_tty_ops: { + get_char(tty) { + return FS_stdin_getChar(); + }, + put_char(tty, val) { + if (val === null || val === 10) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output?.length > 0) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } + }, + ioctl_tcgets(tty) { + // typical setting + return { + c_iflag: 25856, + c_oflag: 5, + c_cflag: 191, + c_lflag: 35387, + c_cc: [ 3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + }; + }, + ioctl_tcsets(tty, optional_actions, data) { + // currently just ignore + return 0; + }, + ioctl_tiocgwinsz(tty) { + return [ 24, 80 ]; + } + }, + default_tty1_ops: { + put_char(tty, val) { + if (val === null || val === 10) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output?.length > 0) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } + } + } +}; + +var zeroMemory = (ptr, size) => HEAPU8.fill(0, ptr, ptr + size); + +var alignMemory = (size, alignment) => Math.ceil(size / alignment) * alignment; + +var mmapAlloc = size => { + size = alignMemory(size, 65536); + var ptr = _emscripten_builtin_memalign(65536, size); + if (ptr) zeroMemory(ptr, size); + return ptr; +}; + +var MEMFS = { + ops_table: null, + mount(mount) { + return MEMFS.createNode(null, "/", 16895, 0); + }, + createNode(parent, name, mode, dev) { + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { + // not supported + throw new FS.ErrnoError(63); + } + MEMFS.ops_table ||= { + dir: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + lookup: MEMFS.node_ops.lookup, + mknod: MEMFS.node_ops.mknod, + rename: MEMFS.node_ops.rename, + unlink: MEMFS.node_ops.unlink, + rmdir: MEMFS.node_ops.rmdir, + readdir: MEMFS.node_ops.readdir, + symlink: MEMFS.node_ops.symlink + }, + stream: { + llseek: MEMFS.stream_ops.llseek + } + }, + file: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: { + llseek: MEMFS.stream_ops.llseek, + read: MEMFS.stream_ops.read, + write: MEMFS.stream_ops.write, + mmap: MEMFS.stream_ops.mmap, + msync: MEMFS.stream_ops.msync + } + }, + link: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink + }, + stream: {} + }, + chrdev: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: FS.chrdev_stream_ops + } + }; + var node = FS.createNode(parent, name, mode, dev); + if (FS.isDir(node.mode)) { + node.node_ops = MEMFS.ops_table.dir.node; + node.stream_ops = MEMFS.ops_table.dir.stream; + node.contents = {}; + } else if (FS.isFile(node.mode)) { + node.node_ops = MEMFS.ops_table.file.node; + node.stream_ops = MEMFS.ops_table.file.stream; + node.usedBytes = 0; + // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity. + // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred + // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size + // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. + node.contents = null; + } else if (FS.isLink(node.mode)) { + node.node_ops = MEMFS.ops_table.link.node; + node.stream_ops = MEMFS.ops_table.link.stream; + } else if (FS.isChrdev(node.mode)) { + node.node_ops = MEMFS.ops_table.chrdev.node; + node.stream_ops = MEMFS.ops_table.chrdev.stream; + } + node.atime = node.mtime = node.ctime = Date.now(); + // add the new node to the parent + if (parent) { + parent.contents[name] = node; + parent.atime = parent.mtime = parent.ctime = node.atime; + } + return node; + }, + getFileDataAsTypedArray(node) { + if (!node.contents) return new Uint8Array(0); + if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); + // Make sure to not return excess unused bytes. + return new Uint8Array(node.contents); + }, + expandFileStorage(node, newCapacity) { + var prevCapacity = node.contents ? node.contents.length : 0; + if (prevCapacity >= newCapacity) return; + // No need to expand, the storage was already large enough. + // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. + // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to + // avoid overshooting the allocation cap by a very large margin. + var CAPACITY_DOUBLING_MAX = 1024 * 1024; + newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>> 0); + if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); + // At minimum allocate 256b for each file when expanding. + var oldContents = node.contents; + node.contents = new Uint8Array(newCapacity); + // Allocate new storage. + if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); + }, + resizeFileStorage(node, newSize) { + if (node.usedBytes == newSize) return; + if (newSize == 0) { + node.contents = null; + // Fully decommit when requesting a resize to zero. + node.usedBytes = 0; + } else { + var oldContents = node.contents; + node.contents = new Uint8Array(newSize); + // Allocate new storage. + if (oldContents) { + node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); + } + node.usedBytes = newSize; + } + }, + node_ops: { + getattr(node) { + var attr = {}; + // device numbers reuse inode numbers. + attr.dev = FS.isChrdev(node.mode) ? node.id : 1; + attr.ino = node.id; + attr.mode = node.mode; + attr.nlink = 1; + attr.uid = 0; + attr.gid = 0; + attr.rdev = node.rdev; + if (FS.isDir(node.mode)) { + attr.size = 4096; + } else if (FS.isFile(node.mode)) { + attr.size = node.usedBytes; + } else if (FS.isLink(node.mode)) { + attr.size = node.link.length; + } else { + attr.size = 0; + } + attr.atime = new Date(node.atime); + attr.mtime = new Date(node.mtime); + attr.ctime = new Date(node.ctime); + // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize), + // but this is not required by the standard. + attr.blksize = 4096; + attr.blocks = Math.ceil(attr.size / attr.blksize); + return attr; + }, + setattr(node, attr) { + for (const key of [ "mode", "atime", "mtime", "ctime" ]) { + if (attr[key] != null) { + node[key] = attr[key]; + } + } + if (attr.size !== undefined) { + MEMFS.resizeFileStorage(node, attr.size); + } + }, + lookup(parent, name) { + // This error may happen quite a bit. To avoid overhead we reuse it (and + // suffer a lack of stack info). + if (!MEMFS.doesNotExistError) { + MEMFS.doesNotExistError = new FS.ErrnoError(44); + /** @suppress {checkTypes} */ MEMFS.doesNotExistError.stack = ""; + } + throw MEMFS.doesNotExistError; + }, + mknod(parent, name, mode, dev) { + return MEMFS.createNode(parent, name, mode, dev); + }, + rename(old_node, new_dir, new_name) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + if (new_node) { + if (FS.isDir(old_node.mode)) { + // if we're overwriting a directory at new_name, make sure it's empty. + for (var i in new_node.contents) { + throw new FS.ErrnoError(55); + } + } + FS.hashRemoveNode(new_node); + } + // do the internal rewiring + delete old_node.parent.contents[old_node.name]; + new_dir.contents[new_name] = old_node; + old_node.name = new_name; + new_dir.ctime = new_dir.mtime = old_node.parent.ctime = old_node.parent.mtime = Date.now(); + }, + unlink(parent, name) { + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + rmdir(parent, name) { + var node = FS.lookupNode(parent, name); + for (var i in node.contents) { + throw new FS.ErrnoError(55); + } + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + readdir(node) { + return [ ".", "..", ...Object.keys(node.contents) ]; + }, + symlink(parent, newname, oldpath) { + var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); + node.link = oldpath; + return node; + }, + readlink(node) { + if (!FS.isLink(node.mode)) { + throw new FS.ErrnoError(28); + } + return node.link; + } + }, + stream_ops: { + read(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= stream.node.usedBytes) return 0; + var size = Math.min(stream.node.usedBytes - position, length); + if (size > 8 && contents.subarray) { + // non-trivial, and typed array + buffer.set(contents.subarray(position, position + size), offset); + } else { + for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i]; + } + return size; + }, + write(stream, buffer, offset, length, position, canOwn) { + // If the buffer is located in main memory (HEAP), and if + // memory can grow, we can't hold on to references of the + // memory buffer, as they may get invalidated. That means we + // need to copy its contents. + if (buffer.buffer === HEAP8.buffer) { + canOwn = false; + } + if (!length) return 0; + var node = stream.node; + node.mtime = node.ctime = Date.now(); + if (buffer.subarray && (!node.contents || node.contents.subarray)) { + // This write is from a typed array to a typed array? + if (canOwn) { + node.contents = buffer.subarray(offset, offset + length); + node.usedBytes = length; + return length; + } else if (node.usedBytes === 0 && position === 0) { + // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data. + node.contents = buffer.slice(offset, offset + length); + node.usedBytes = length; + return length; + } else if (position + length <= node.usedBytes) { + // Writing to an already allocated and used subrange of the file? + node.contents.set(buffer.subarray(offset, offset + length), position); + return length; + } + } + // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. + MEMFS.expandFileStorage(node, position + length); + if (node.contents.subarray && buffer.subarray) { + // Use typed array write which is available. + node.contents.set(buffer.subarray(offset, offset + length), position); + } else { + for (var i = 0; i < length; i++) { + node.contents[position + i] = buffer[offset + i]; + } + } + node.usedBytes = Math.max(node.usedBytes, position + length); + return length; + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + position += stream.node.usedBytes; + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, + mmap(stream, length, position, prot, flags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + var ptr; + var allocated; + var contents = stream.node.contents; + // Only make a new copy when MAP_PRIVATE is specified. + if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) { + // We can't emulate MAP_SHARED when the file is not backed by the + // buffer we're mapping to (e.g. the HEAP buffer). + allocated = false; + ptr = contents.byteOffset; + } else { + allocated = true; + ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + if (contents) { + // Try to avoid unnecessary slices. + if (position > 0 || position + length < contents.length) { + if (contents.subarray) { + contents = contents.subarray(position, position + length); + } else { + contents = Array.prototype.slice.call(contents, position, position + length); + } + } + HEAP8.set(contents, ptr >>> 0); + } + } + return { + ptr, + allocated + }; + }, + msync(stream, buffer, offset, length, mmapFlags) { + MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); + // should we check if bytesWritten and length are the same? + return 0; + } + } +}; + +var FS_modeStringToFlags = str => { + var flagModes = { + "r": 0, + "r+": 2, + "w": 512 | 64 | 1, + "w+": 512 | 64 | 2, + "a": 1024 | 64 | 1, + "a+": 1024 | 64 | 2 + }; + var flags = flagModes[str]; + if (typeof flags == "undefined") { + throw new Error(`Unknown file open mode: ${str}`); + } + return flags; +}; + +var FS_getMode = (canRead, canWrite) => { + var mode = 0; + if (canRead) mode |= 292 | 73; + if (canWrite) mode |= 146; + return mode; +}; + +var asyncLoad = async url => { + var arrayBuffer = await readAsync(url); + return new Uint8Array(arrayBuffer); +}; + +var FS_createDataFile = (...args) => FS.createDataFile(...args); + +var getUniqueRunDependency = id => id; + +var runDependencies = 0; + +var dependenciesFulfilled = null; + +var removeRunDependency = id => { + runDependencies--; + Module["monitorRunDependencies"]?.(runDependencies); + if (runDependencies == 0) { + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); + } + } +}; + +var addRunDependency = id => { + runDependencies++; + Module["monitorRunDependencies"]?.(runDependencies); +}; + +var FS_handledByPreloadPlugin = async (byteArray, fullname) => { + // Ensure plugins are ready. + if (typeof Browser != "undefined") Browser.init(); + for (var plugin of preloadPlugins) { + if (plugin["canHandle"](fullname)) { + return plugin["handle"](byteArray, fullname); + } + } + // If no plugin handled this file then return the original/unmodified + // byteArray. + return byteArray; +}; + +var FS_preloadFile = async (parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish) => { + // TODO we should allow people to just pass in a complete filename instead + // of parent and name being that we just join them anyways + var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; + var dep = getUniqueRunDependency(`cp ${fullname}`); + // might have several active requests for the same fullname + addRunDependency(dep); + try { + var byteArray = url; + if (typeof url == "string") { + byteArray = await asyncLoad(url); + } + byteArray = await FS_handledByPreloadPlugin(byteArray, fullname); + preFinish?.(); + if (!dontCreateFile) { + FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); + } + } finally { + removeRunDependency(dep); + } +}; + +var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { + FS_preloadFile(parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish).then(onload).catch(onerror); +}; + +var FS = { + root: null, + mounts: [], + devices: {}, + streams: [], + nextInode: 1, + nameTable: null, + currentPath: "/", + initialized: false, + ignorePermissions: true, + filesystems: null, + syncFSRequests: 0, + ErrnoError: class { + name="ErrnoError"; + // We set the `name` property to be able to identify `FS.ErrnoError` + // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway. + // - when using PROXYFS, an error can come from an underlying FS + // as different FS objects have their own FS.ErrnoError each, + // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs. + // we'll use the reliable test `err.name == "ErrnoError"` instead + constructor(errno) { + this.errno = errno; + } + }, + FSStream: class { + shared={}; + get object() { + return this.node; + } + set object(val) { + this.node = val; + } + get isRead() { + return (this.flags & 2097155) !== 1; + } + get isWrite() { + return (this.flags & 2097155) !== 0; + } + get isAppend() { + return (this.flags & 1024); + } + get flags() { + return this.shared.flags; + } + set flags(val) { + this.shared.flags = val; + } + get position() { + return this.shared.position; + } + set position(val) { + this.shared.position = val; + } + }, + FSNode: class { + node_ops={}; + stream_ops={}; + readMode=292 | 73; + writeMode=146; + mounted=null; + constructor(parent, name, mode, rdev) { + if (!parent) { + parent = this; + } + this.parent = parent; + this.mount = parent.mount; + this.id = FS.nextInode++; + this.name = name; + this.mode = mode; + this.rdev = rdev; + this.atime = this.mtime = this.ctime = Date.now(); + } + get read() { + return (this.mode & this.readMode) === this.readMode; + } + set read(val) { + val ? this.mode |= this.readMode : this.mode &= ~this.readMode; + } + get write() { + return (this.mode & this.writeMode) === this.writeMode; + } + set write(val) { + val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode; + } + get isFolder() { + return FS.isDir(this.mode); + } + get isDevice() { + return FS.isChrdev(this.mode); + } + }, + lookupPath(path, opts = {}) { + if (!path) { + throw new FS.ErrnoError(44); + } + opts.follow_mount ??= true; + if (!PATH.isAbs(path)) { + path = FS.cwd() + "/" + path; + } + // limit max consecutive symlinks to 40 (SYMLOOP_MAX). + linkloop: for (var nlinks = 0; nlinks < 40; nlinks++) { + // split the absolute path + var parts = path.split("/").filter(p => !!p); + // start at the root + var current = FS.root; + var current_path = "/"; + for (var i = 0; i < parts.length; i++) { + var islast = (i === parts.length - 1); + if (islast && opts.parent) { + // stop resolving + break; + } + if (parts[i] === ".") { + continue; + } + if (parts[i] === "..") { + current_path = PATH.dirname(current_path); + if (FS.isRoot(current)) { + path = current_path + "/" + parts.slice(i + 1).join("/"); + // We're making progress here, don't let many consecutive ..'s + // lead to ELOOP + nlinks--; + continue linkloop; + } else { + current = current.parent; + } + continue; + } + current_path = PATH.join2(current_path, parts[i]); + try { + current = FS.lookupNode(current, parts[i]); + } catch (e) { + // if noent_okay is true, suppress a ENOENT in the last component + // and return an object with an undefined node. This is needed for + // resolving symlinks in the path when creating a file. + if ((e?.errno === 44) && islast && opts.noent_okay) { + return { + path: current_path + }; + } + throw e; + } + // jump to the mount's root node if this is a mountpoint + if (FS.isMountpoint(current) && (!islast || opts.follow_mount)) { + current = current.mounted.root; + } + // by default, lookupPath will not follow a symlink if it is the final path component. + // setting opts.follow = true will override this behavior. + if (FS.isLink(current.mode) && (!islast || opts.follow)) { + if (!current.node_ops.readlink) { + throw new FS.ErrnoError(52); + } + var link = current.node_ops.readlink(current); + if (!PATH.isAbs(link)) { + link = PATH.dirname(current_path) + "/" + link; + } + path = link + "/" + parts.slice(i + 1).join("/"); + continue linkloop; + } + } + return { + path: current_path, + node: current + }; + } + throw new FS.ErrnoError(32); + }, + getPath(node) { + var path; + while (true) { + if (FS.isRoot(node)) { + var mount = node.mount.mountpoint; + if (!path) return mount; + return mount[mount.length - 1] !== "/" ? `${mount}/${path}` : mount + path; + } + path = path ? `${node.name}/${path}` : node.name; + node = node.parent; + } + }, + hashName(parentid, name) { + var hash = 0; + for (var i = 0; i < name.length; i++) { + hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; + } + return ((parentid + hash) >>> 0) % FS.nameTable.length; + }, + hashAddNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; + }, + hashRemoveNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; + } else { + var current = FS.nameTable[hash]; + while (current) { + if (current.name_next === node) { + current.name_next = node.name_next; + break; + } + current = current.name_next; + } + } + }, + lookupNode(parent, name) { + var errCode = FS.mayLookup(parent); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + var hash = FS.hashName(parent.id, name); + for (var node = FS.nameTable[hash]; node; node = node.name_next) { + var nodeName = node.name; + if (node.parent.id === parent.id && nodeName === name) { + return node; + } + } + // if we failed to find it in the cache, call into the VFS + return FS.lookup(parent, name); + }, + createNode(parent, name, mode, rdev) { + var node = new FS.FSNode(parent, name, mode, rdev); + FS.hashAddNode(node); + return node; + }, + destroyNode(node) { + FS.hashRemoveNode(node); + }, + isRoot(node) { + return node === node.parent; + }, + isMountpoint(node) { + return !!node.mounted; + }, + isFile(mode) { + return (mode & 61440) === 32768; + }, + isDir(mode) { + return (mode & 61440) === 16384; + }, + isLink(mode) { + return (mode & 61440) === 40960; + }, + isChrdev(mode) { + return (mode & 61440) === 8192; + }, + isBlkdev(mode) { + return (mode & 61440) === 24576; + }, + isFIFO(mode) { + return (mode & 61440) === 4096; + }, + isSocket(mode) { + return (mode & 49152) === 49152; + }, + flagsToPermissionString(flag) { + var perms = [ "r", "w", "rw" ][flag & 3]; + if ((flag & 512)) { + perms += "w"; + } + return perms; + }, + nodePermissions(node, perms) { + if (FS.ignorePermissions) { + return 0; + } + // return 0 if any user, group or owner bits are set. + if (perms.includes("r") && !(node.mode & 292)) { + return 2; + } + if (perms.includes("w") && !(node.mode & 146)) { + return 2; + } + if (perms.includes("x") && !(node.mode & 73)) { + return 2; + } + return 0; + }, + mayLookup(dir) { + if (!FS.isDir(dir.mode)) return 54; + var errCode = FS.nodePermissions(dir, "x"); + if (errCode) return errCode; + if (!dir.node_ops.lookup) return 2; + return 0; + }, + mayCreate(dir, name) { + if (!FS.isDir(dir.mode)) { + return 54; + } + try { + var node = FS.lookupNode(dir, name); + return 20; + } catch (e) {} + return FS.nodePermissions(dir, "wx"); + }, + mayDelete(dir, name, isdir) { + var node; + try { + node = FS.lookupNode(dir, name); + } catch (e) { + return e.errno; + } + var errCode = FS.nodePermissions(dir, "wx"); + if (errCode) { + return errCode; + } + if (isdir) { + if (!FS.isDir(node.mode)) { + return 54; + } + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { + return 10; + } + } else if (FS.isDir(node.mode)) { + return 31; + } + return 0; + }, + mayOpen(node, flags) { + if (!node) { + return 44; + } + if (FS.isLink(node.mode)) { + return 32; + } + var mode = FS.flagsToPermissionString(flags); + if (FS.isDir(node.mode)) { + // opening for write + // TODO: check for O_SEARCH? (== search for dir only) + if (mode !== "r" || (flags & (512 | 64))) { + return 31; + } + } + return FS.nodePermissions(node, mode); + }, + checkOpExists(op, err) { + if (!op) { + throw new FS.ErrnoError(err); + } + return op; + }, + MAX_OPEN_FDS: 4096, + nextfd() { + for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { + if (!FS.streams[fd]) { + return fd; + } + } + throw new FS.ErrnoError(33); + }, + getStreamChecked(fd) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + return stream; + }, + getStream: fd => FS.streams[fd], + createStream(stream, fd = -1) { + // clone it, so we can return an instance of FSStream + stream = Object.assign(new FS.FSStream, stream); + if (fd == -1) { + fd = FS.nextfd(); + } + stream.fd = fd; + FS.streams[fd] = stream; + return stream; + }, + closeStream(fd) { + FS.streams[fd] = null; + }, + dupStream(origStream, fd = -1) { + var stream = FS.createStream(origStream, fd); + stream.stream_ops?.dup?.(stream); + return stream; + }, + doSetAttr(stream, node, attr) { + var setattr = stream?.stream_ops.setattr; + var arg = setattr ? stream : node; + setattr ??= node.node_ops.setattr; + FS.checkOpExists(setattr, 63); + setattr(arg, attr); + }, + chrdev_stream_ops: { + open(stream) { + var device = FS.getDevice(stream.node.rdev); + // override node's stream ops with the device's + stream.stream_ops = device.stream_ops; + // forward the open call + stream.stream_ops.open?.(stream); + }, + llseek() { + throw new FS.ErrnoError(70); + } + }, + major: dev => ((dev) >> 8), + minor: dev => ((dev) & 255), + makedev: (ma, mi) => ((ma) << 8 | (mi)), + registerDevice(dev, ops) { + FS.devices[dev] = { + stream_ops: ops + }; + }, + getDevice: dev => FS.devices[dev], + getMounts(mount) { + var mounts = []; + var check = [ mount ]; + while (check.length) { + var m = check.pop(); + mounts.push(m); + check.push(...m.mounts); + } + return mounts; + }, + syncfs(populate, callback) { + if (typeof populate == "function") { + callback = populate; + populate = false; + } + FS.syncFSRequests++; + if (FS.syncFSRequests > 1) { + err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`); + } + var mounts = FS.getMounts(FS.root.mount); + var completed = 0; + function doCallback(errCode) { + FS.syncFSRequests--; + return callback(errCode); + } + function done(errCode) { + if (errCode) { + if (!done.errored) { + done.errored = true; + return doCallback(errCode); + } + return; + } + if (++completed >= mounts.length) { + doCallback(null); + } + } + // sync all mounts + for (var mount of mounts) { + if (mount.type.syncfs) { + mount.type.syncfs(mount, populate, done); + } else { + done(null); + } + } + }, + mount(type, opts, mountpoint) { + var root = mountpoint === "/"; + var pseudo = !mountpoint; + var node; + if (root && FS.root) { + throw new FS.ErrnoError(10); + } else if (!root && !pseudo) { + var lookup = FS.lookupPath(mountpoint, { + follow_mount: false + }); + mountpoint = lookup.path; + // use the absolute path + node = lookup.node; + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + if (!FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + } + var mount = { + type, + opts, + mountpoint, + mounts: [] + }; + // create a root node for the fs + var mountRoot = type.mount(mount); + mountRoot.mount = mount; + mount.root = mountRoot; + if (root) { + FS.root = mountRoot; + } else if (node) { + // set as a mountpoint + node.mounted = mount; + // add the new mount to the current mount's children + if (node.mount) { + node.mount.mounts.push(mount); + } + } + return mountRoot; + }, + unmount(mountpoint) { + var lookup = FS.lookupPath(mountpoint, { + follow_mount: false + }); + if (!FS.isMountpoint(lookup.node)) { + throw new FS.ErrnoError(28); + } + // destroy the nodes for this mount, and all its child mounts + var node = lookup.node; + var mount = node.mounted; + var mounts = FS.getMounts(mount); + for (var [hash, current] of Object.entries(FS.nameTable)) { + while (current) { + var next = current.name_next; + if (mounts.includes(current.mount)) { + FS.destroyNode(current); + } + current = next; + } + } + // no longer a mountpoint + node.mounted = null; + // remove this mount from the child mounts + var idx = node.mount.mounts.indexOf(mount); + node.mount.mounts.splice(idx, 1); + }, + lookup(parent, name) { + return parent.node_ops.lookup(parent, name); + }, + mknod(path, mode, dev) { + var lookup = FS.lookupPath(path, { + parent: true + }); + var parent = lookup.node; + var name = PATH.basename(path); + if (!name) { + throw new FS.ErrnoError(28); + } + if (name === "." || name === "..") { + throw new FS.ErrnoError(20); + } + var errCode = FS.mayCreate(parent, name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.mknod) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.mknod(parent, name, mode, dev); + }, + statfs(path) { + return FS.statfsNode(FS.lookupPath(path, { + follow: true + }).node); + }, + statfsStream(stream) { + // We keep a separate statfsStream function because noderawfs overrides + // it. In noderawfs, stream.node is sometimes null. Instead, we need to + // look at stream.path. + return FS.statfsNode(stream.node); + }, + statfsNode(node) { + // NOTE: None of the defaults here are true. We're just returning safe and + // sane values. Currently nodefs and rawfs replace these defaults, + // other file systems leave them alone. + var rtn = { + bsize: 4096, + frsize: 4096, + blocks: 1e6, + bfree: 5e5, + bavail: 5e5, + files: FS.nextInode, + ffree: FS.nextInode - 1, + fsid: 42, + flags: 2, + namelen: 255 + }; + if (node.node_ops.statfs) { + Object.assign(rtn, node.node_ops.statfs(node.mount.opts.root)); + } + return rtn; + }, + create(path, mode = 438) { + mode &= 4095; + mode |= 32768; + return FS.mknod(path, mode, 0); + }, + mkdir(path, mode = 511) { + mode &= 511 | 512; + mode |= 16384; + return FS.mknod(path, mode, 0); + }, + mkdirTree(path, mode) { + var dirs = path.split("/"); + var d = ""; + for (var dir of dirs) { + if (!dir) continue; + if (d || PATH.isAbs(path)) d += "/"; + d += dir; + try { + FS.mkdir(d, mode); + } catch (e) { + if (e.errno != 20) throw e; + } + } + }, + mkdev(path, mode, dev) { + if (typeof dev == "undefined") { + dev = mode; + mode = 438; + } + mode |= 8192; + return FS.mknod(path, mode, dev); + }, + symlink(oldpath, newpath) { + if (!PATH_FS.resolve(oldpath)) { + throw new FS.ErrnoError(44); + } + var lookup = FS.lookupPath(newpath, { + parent: true + }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var newname = PATH.basename(newpath); + var errCode = FS.mayCreate(parent, newname); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.symlink) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.symlink(parent, newname, oldpath); + }, + rename(old_path, new_path) { + var old_dirname = PATH.dirname(old_path); + var new_dirname = PATH.dirname(new_path); + var old_name = PATH.basename(old_path); + var new_name = PATH.basename(new_path); + // parents must exist + var lookup, old_dir, new_dir; + // let the errors from non existent directories percolate up + lookup = FS.lookupPath(old_path, { + parent: true + }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { + parent: true + }); + new_dir = lookup.node; + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); + // need to be part of the same mount + if (old_dir.mount !== new_dir.mount) { + throw new FS.ErrnoError(75); + } + // source must exist + var old_node = FS.lookupNode(old_dir, old_name); + // old path should not be an ancestor of the new path + var relative = PATH_FS.relative(old_path, new_dirname); + if (relative.charAt(0) !== ".") { + throw new FS.ErrnoError(28); + } + // new path should not be an ancestor of the old path + relative = PATH_FS.relative(new_path, old_dirname); + if (relative.charAt(0) !== ".") { + throw new FS.ErrnoError(55); + } + // see if the new path already exists + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + // early out if nothing needs to change + if (old_node === new_node) { + return; + } + // we'll need to delete the old entry + var isdir = FS.isDir(old_node.mode); + var errCode = FS.mayDelete(old_dir, old_name, isdir); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + // need delete permissions if we'll be overwriting. + // need create permissions if new doesn't already exist. + errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!old_dir.node_ops.rename) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) { + throw new FS.ErrnoError(10); + } + // if we are going to change the parent, check write permissions + if (new_dir !== old_dir) { + errCode = FS.nodePermissions(old_dir, "w"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // remove the node from the lookup hash + FS.hashRemoveNode(old_node); + // do the underlying fs rename + try { + old_dir.node_ops.rename(old_node, new_dir, new_name); + // update old node (we do this here to avoid each backend + // needing to) + old_node.parent = new_dir; + } catch (e) { + throw e; + } finally { + // add the node back to the hash (in case node_ops.rename + // changed its name) + FS.hashAddNode(old_node); + } + }, + rmdir(path) { + var lookup = FS.lookupPath(path, { + parent: true + }); + var parent = lookup.node; + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, true); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.rmdir) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.rmdir(parent, name); + FS.destroyNode(node); + }, + readdir(path) { + var lookup = FS.lookupPath(path, { + follow: true + }); + var node = lookup.node; + var readdir = FS.checkOpExists(node.node_ops.readdir, 54); + return readdir(node); + }, + unlink(path) { + var lookup = FS.lookupPath(path, { + parent: true + }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, false); + if (errCode) { + // According to POSIX, we should map EISDIR to EPERM, but + // we instead do what Linux does (and we must, as we use + // the musl linux libc). + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.unlink) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.unlink(parent, name); + FS.destroyNode(node); + }, + readlink(path) { + var lookup = FS.lookupPath(path); + var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(44); + } + if (!link.node_ops.readlink) { + throw new FS.ErrnoError(28); + } + return link.node_ops.readlink(link); + }, + stat(path, dontFollow) { + var lookup = FS.lookupPath(path, { + follow: !dontFollow + }); + var node = lookup.node; + var getattr = FS.checkOpExists(node.node_ops.getattr, 63); + return getattr(node); + }, + fstat(fd) { + var stream = FS.getStreamChecked(fd); + var node = stream.node; + var getattr = stream.stream_ops.getattr; + var arg = getattr ? stream : node; + getattr ??= node.node_ops.getattr; + FS.checkOpExists(getattr, 63); + return getattr(arg); + }, + lstat(path) { + return FS.stat(path, true); + }, + doChmod(stream, node, mode, dontFollow) { + FS.doSetAttr(stream, node, { + mode: (mode & 4095) | (node.mode & ~4095), + ctime: Date.now(), + dontFollow + }); + }, + chmod(path, mode, dontFollow) { + var node; + if (typeof path == "string") { + var lookup = FS.lookupPath(path, { + follow: !dontFollow + }); + node = lookup.node; + } else { + node = path; + } + FS.doChmod(null, node, mode, dontFollow); + }, + lchmod(path, mode) { + FS.chmod(path, mode, true); + }, + fchmod(fd, mode) { + var stream = FS.getStreamChecked(fd); + FS.doChmod(stream, stream.node, mode, false); + }, + doChown(stream, node, dontFollow) { + FS.doSetAttr(stream, node, { + timestamp: Date.now(), + dontFollow + }); + }, + chown(path, uid, gid, dontFollow) { + var node; + if (typeof path == "string") { + var lookup = FS.lookupPath(path, { + follow: !dontFollow + }); + node = lookup.node; + } else { + node = path; + } + FS.doChown(null, node, dontFollow); + }, + lchown(path, uid, gid) { + FS.chown(path, uid, gid, true); + }, + fchown(fd, uid, gid) { + var stream = FS.getStreamChecked(fd); + FS.doChown(stream, stream.node, false); + }, + doTruncate(stream, node, len) { + if (FS.isDir(node.mode)) { + throw new FS.ErrnoError(31); + } + if (!FS.isFile(node.mode)) { + throw new FS.ErrnoError(28); + } + var errCode = FS.nodePermissions(node, "w"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.doSetAttr(stream, node, { + size: len, + timestamp: Date.now() + }); + }, + truncate(path, len) { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path == "string") { + var lookup = FS.lookupPath(path, { + follow: true + }); + node = lookup.node; + } else { + node = path; + } + FS.doTruncate(null, node, len); + }, + ftruncate(fd, len) { + var stream = FS.getStreamChecked(fd); + if (len < 0 || (stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(28); + } + FS.doTruncate(stream, stream.node, len); + }, + utime(path, atime, mtime) { + var lookup = FS.lookupPath(path, { + follow: true + }); + var node = lookup.node; + var setattr = FS.checkOpExists(node.node_ops.setattr, 63); + setattr(node, { + atime, + mtime + }); + }, + open(path, flags, mode = 438) { + if (path === "") { + throw new FS.ErrnoError(44); + } + flags = typeof flags == "string" ? FS_modeStringToFlags(flags) : flags; + if ((flags & 64)) { + mode = (mode & 4095) | 32768; + } else { + mode = 0; + } + var node; + var isDirPath; + if (typeof path == "object") { + node = path; + } else { + isDirPath = path.endsWith("/"); + // noent_okay makes it so that if the final component of the path + // doesn't exist, lookupPath returns `node: undefined`. `path` will be + // updated to point to the target of all symlinks. + var lookup = FS.lookupPath(path, { + follow: !(flags & 131072), + noent_okay: true + }); + node = lookup.node; + path = lookup.path; + } + // perhaps we need to create the node + var created = false; + if ((flags & 64)) { + if (node) { + // if O_CREAT and O_EXCL are set, error out if the node already exists + if ((flags & 128)) { + throw new FS.ErrnoError(20); + } + } else if (isDirPath) { + throw new FS.ErrnoError(31); + } else { + // node doesn't exist, try to create it + // Ignore the permission bits here to ensure we can `open` this new + // file below. We use chmod below to apply the permissions once the + // file is open. + node = FS.mknod(path, mode | 511, 0); + created = true; + } + } + if (!node) { + throw new FS.ErrnoError(44); + } + // can't truncate a device + if (FS.isChrdev(node.mode)) { + flags &= ~512; + } + // if asked only for a directory, then this must be one + if ((flags & 65536) && !FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + // check permissions, if this is not a file we just created now (it is ok to + // create and write to a file with read-only permissions; it is read-only + // for later use) + if (!created) { + var errCode = FS.mayOpen(node, flags); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // do truncation if necessary + if ((flags & 512) && !created) { + FS.truncate(node, 0); + } + // we've already handled these, don't pass down to the underlying vfs + flags &= ~(128 | 512 | 131072); + // register the stream with the filesystem + var stream = FS.createStream({ + node, + path: FS.getPath(node), + // we want the absolute path to the node + flags, + seekable: true, + position: 0, + stream_ops: node.stream_ops, + // used by the file family libc calls (fopen, fwrite, ferror, etc.) + ungotten: [], + error: false + }); + // call the new stream's open function + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + if (created) { + FS.chmod(node, mode & 511); + } + return stream; + }, + close(stream) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (stream.getdents) stream.getdents = null; + // free readdir state + try { + if (stream.stream_ops.close) { + stream.stream_ops.close(stream); + } + } catch (e) { + throw e; + } finally { + FS.closeStream(stream.fd); + } + stream.fd = null; + }, + isClosed(stream) { + return stream.fd === null; + }, + llseek(stream, offset, whence) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (!stream.seekable || !stream.stream_ops.llseek) { + throw new FS.ErrnoError(70); + } + if (whence != 0 && whence != 1 && whence != 2) { + throw new FS.ErrnoError(28); + } + stream.position = stream.stream_ops.llseek(stream, offset, whence); + stream.ungotten = []; + return stream.position; + }, + read(stream, buffer, offset, length, position) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.read) { + throw new FS.ErrnoError(28); + } + var seeking = typeof position != "undefined"; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position); + if (!seeking) stream.position += bytesRead; + return bytesRead; + }, + write(stream, buffer, offset, length, position, canOwn) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.write) { + throw new FS.ErrnoError(28); + } + if (stream.seekable && stream.flags & 1024) { + // seek to the end before writing in append mode + FS.llseek(stream, 0, 2); + } + var seeking = typeof position != "undefined"; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); + if (!seeking) stream.position += bytesWritten; + return bytesWritten; + }, + mmap(stream, length, position, prot, flags) { + // User requests writing to file (prot & PROT_WRITE != 0). + // Checking if we have permissions to write to the file unless + // MAP_PRIVATE flag is set. According to POSIX spec it is possible + // to write to file opened in read-only mode with MAP_PRIVATE flag, + // as all modifications will be visible only in the memory of + // the current process. + if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) { + throw new FS.ErrnoError(2); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(2); + } + if (!stream.stream_ops.mmap) { + throw new FS.ErrnoError(43); + } + if (!length) { + throw new FS.ErrnoError(28); + } + return stream.stream_ops.mmap(stream, length, position, prot, flags); + }, + msync(stream, buffer, offset, length, mmapFlags) { + if (!stream.stream_ops.msync) { + return 0; + } + return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags); + }, + ioctl(stream, cmd, arg) { + if (!stream.stream_ops.ioctl) { + throw new FS.ErrnoError(59); + } + return stream.stream_ops.ioctl(stream, cmd, arg); + }, + readFile(path, opts = {}) { + opts.flags = opts.flags || 0; + opts.encoding = opts.encoding || "binary"; + if (opts.encoding !== "utf8" && opts.encoding !== "binary") { + abort(`Invalid encoding type "${opts.encoding}"`); + } + var stream = FS.open(path, opts.flags); + var stat = FS.stat(path); + var length = stat.size; + var buf = new Uint8Array(length); + FS.read(stream, buf, 0, length, 0); + if (opts.encoding === "utf8") { + buf = UTF8ArrayToString(buf); + } + FS.close(stream); + return buf; + }, + writeFile(path, data, opts = {}) { + opts.flags = opts.flags || 577; + var stream = FS.open(path, opts.flags, opts.mode); + if (typeof data == "string") { + data = new Uint8Array(intArrayFromString(data, true)); + } + if (ArrayBuffer.isView(data)) { + FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); + } else { + abort("Unsupported data type"); + } + FS.close(stream); + }, + cwd: () => FS.currentPath, + chdir(path) { + var lookup = FS.lookupPath(path, { + follow: true + }); + if (lookup.node === null) { + throw new FS.ErrnoError(44); + } + if (!FS.isDir(lookup.node.mode)) { + throw new FS.ErrnoError(54); + } + var errCode = FS.nodePermissions(lookup.node, "x"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.currentPath = lookup.path; + }, + createDefaultDirectories() { + FS.mkdir("/tmp"); + FS.mkdir("/home"); + FS.mkdir("/home/web_user"); + }, + createDefaultDevices() { + // create /dev + FS.mkdir("/dev"); + // setup /dev/null + FS.registerDevice(FS.makedev(1, 3), { + read: () => 0, + write: (stream, buffer, offset, length, pos) => length, + llseek: () => 0 + }); + FS.mkdev("/dev/null", FS.makedev(1, 3)); + // setup /dev/tty and /dev/tty1 + // stderr needs to print output using err() rather than out() + // so we register a second tty just for it. + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); + FS.mkdev("/dev/tty", FS.makedev(5, 0)); + FS.mkdev("/dev/tty1", FS.makedev(6, 0)); + // setup /dev/[u]random + // use a buffer to avoid overhead of individual crypto calls per byte + var randomBuffer = new Uint8Array(1024), randomLeft = 0; + var randomByte = () => { + if (randomLeft === 0) { + randomFill(randomBuffer); + randomLeft = randomBuffer.byteLength; + } + return randomBuffer[--randomLeft]; + }; + FS.createDevice("/dev", "random", randomByte); + FS.createDevice("/dev", "urandom", randomByte); + // we're not going to emulate the actual shm device, + // just create the tmp dirs that reside in it commonly + FS.mkdir("/dev/shm"); + FS.mkdir("/dev/shm/tmp"); + }, + createSpecialDirectories() { + // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the + // name of the stream for fd 6 (see test_unistd_ttyname) + FS.mkdir("/proc"); + var proc_self = FS.mkdir("/proc/self"); + FS.mkdir("/proc/self/fd"); + FS.mount({ + mount() { + var node = FS.createNode(proc_self, "fd", 16895, 73); + node.stream_ops = { + llseek: MEMFS.stream_ops.llseek + }; + node.node_ops = { + lookup(parent, name) { + var fd = +name; + var stream = FS.getStreamChecked(fd); + var ret = { + parent: null, + mount: { + mountpoint: "fake" + }, + node_ops: { + readlink: () => stream.path + }, + id: fd + 1 + }; + ret.parent = ret; + // make it look like a simple root node + return ret; + }, + readdir() { + return Array.from(FS.streams.entries()).filter(([k, v]) => v).map(([k, v]) => k.toString()); + } + }; + return node; + } + }, {}, "/proc/self/fd"); + }, + createStandardStreams(input, output, error) { + // TODO deprecate the old functionality of a single + // input / output callback and that utilizes FS.createDevice + // and instead require a unique set of stream ops + // by default, we symlink the standard streams to the + // default tty devices. however, if the standard streams + // have been overwritten we create a unique device for + // them instead. + if (input) { + FS.createDevice("/dev", "stdin", input); + } else { + FS.symlink("/dev/tty", "/dev/stdin"); + } + if (output) { + FS.createDevice("/dev", "stdout", null, output); + } else { + FS.symlink("/dev/tty", "/dev/stdout"); + } + if (error) { + FS.createDevice("/dev", "stderr", null, error); + } else { + FS.symlink("/dev/tty1", "/dev/stderr"); + } + // open default streams for the stdin, stdout and stderr devices + var stdin = FS.open("/dev/stdin", 0); + var stdout = FS.open("/dev/stdout", 1); + var stderr = FS.open("/dev/stderr", 1); + }, + staticInit() { + FS.nameTable = new Array(4096); + FS.mount(MEMFS, {}, "/"); + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + FS.createSpecialDirectories(); + FS.filesystems = { + "MEMFS": MEMFS + }; + }, + init(input, output, error) { + FS.initialized = true; + // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here + input ??= Module["stdin"]; + output ??= Module["stdout"]; + error ??= Module["stderr"]; + FS.createStandardStreams(input, output, error); + }, + quit() { + FS.initialized = false; + // force-flush all streams, so we get musl std streams printed out + // close all of our streams + for (var stream of FS.streams) { + if (stream) { + FS.close(stream); + } + } + }, + findObject(path, dontResolveLastLink) { + var ret = FS.analyzePath(path, dontResolveLastLink); + if (!ret.exists) { + return null; + } + return ret.object; + }, + analyzePath(path, dontResolveLastLink) { + // operate from within the context of the symlink's target + try { + var lookup = FS.lookupPath(path, { + follow: !dontResolveLastLink + }); + path = lookup.path; + } catch (e) {} + var ret = { + isRoot: false, + exists: false, + error: 0, + name: null, + path: null, + object: null, + parentExists: false, + parentPath: null, + parentObject: null + }; + try { + var lookup = FS.lookupPath(path, { + parent: true + }); + ret.parentExists = true; + ret.parentPath = lookup.path; + ret.parentObject = lookup.node; + ret.name = PATH.basename(path); + lookup = FS.lookupPath(path, { + follow: !dontResolveLastLink + }); + ret.exists = true; + ret.path = lookup.path; + ret.object = lookup.node; + ret.name = lookup.node.name; + ret.isRoot = lookup.path === "/"; + } catch (e) { + ret.error = e.errno; + } + return ret; + }, + createPath(parent, path, canRead, canWrite) { + parent = typeof parent == "string" ? parent : FS.getPath(parent); + var parts = path.split("/").reverse(); + while (parts.length) { + var part = parts.pop(); + if (!part) continue; + var current = PATH.join2(parent, part); + try { + FS.mkdir(current); + } catch (e) { + if (e.errno != 20) throw e; + } + parent = current; + } + return current; + }, + createFile(parent, name, properties, canRead, canWrite) { + var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name); + var mode = FS_getMode(canRead, canWrite); + return FS.create(path, mode); + }, + createDataFile(parent, name, data, canRead, canWrite, canOwn) { + var path = name; + if (parent) { + parent = typeof parent == "string" ? parent : FS.getPath(parent); + path = name ? PATH.join2(parent, name) : parent; + } + var mode = FS_getMode(canRead, canWrite); + var node = FS.create(path, mode); + if (data) { + if (typeof data == "string") { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); + data = arr; + } + // make sure we can write to the file + FS.chmod(node, mode | 146); + var stream = FS.open(node, 577); + FS.write(stream, data, 0, data.length, 0, canOwn); + FS.close(stream); + FS.chmod(node, mode); + } + }, + createDevice(parent, name, input, output) { + var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name); + var mode = FS_getMode(!!input, !!output); + FS.createDevice.major ??= 64; + var dev = FS.makedev(FS.createDevice.major++, 0); + // Create a fake device that a set of stream ops to emulate + // the old behavior. + FS.registerDevice(dev, { + open(stream) { + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + if (output?.buffer?.length) { + output(10); + } + }, + read(stream, buffer, offset, length, pos) { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = input(); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + for (var i = 0; i < length; i++) { + try { + output(buffer[offset + i]); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + } + }); + return FS.mkdev(path, mode, dev); + }, + forceLoadFile(obj) { + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; + if (globalThis.XMLHttpRequest) { + abort("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); + } else { + // Command-line. + try { + obj.contents = readBinary(obj.url); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + }, + createLazyFile(parent, name, url, canRead, canWrite) { + // Lazy chunked Uint8Array (implements get and length from Uint8Array). + // Actual getting is abstracted away for eventual reuse. + class LazyUint8Array { + lengthKnown=false; + chunks=[]; + // Loaded chunks. Index is the chunk number + get(idx) { + if (idx > this.length - 1 || idx < 0) { + return undefined; + } + var chunkOffset = idx % this.chunkSize; + var chunkNum = (idx / this.chunkSize) | 0; + return this.getter(chunkNum)[chunkOffset]; + } + setDataGetter(getter) { + this.getter = getter; + } + cacheLength() { + // Find length + var xhr = new XMLHttpRequest; + xhr.open("HEAD", url, false); + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); + var datalength = Number(xhr.getResponseHeader("Content-length")); + var header; + var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; + var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; + var chunkSize = 1024 * 1024; + // Chunk size in bytes + if (!hasByteServing) chunkSize = datalength; + // Function to get a range from the remote URL. + var doXHR = (from, to) => { + if (from > to) abort("invalid range (" + from + ", " + to + ") or no bytes requested!"); + if (to > datalength - 1) abort("only " + datalength + " bytes available! programmer error!"); + // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. + var xhr = new XMLHttpRequest; + xhr.open("GET", url, false); + if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); + // Some hints to the browser that we want binary data. + xhr.responseType = "arraybuffer"; + if (xhr.overrideMimeType) { + xhr.overrideMimeType("text/plain; charset=x-user-defined"); + } + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); + if (xhr.response !== undefined) { + return new Uint8Array(/** @type{Array} */ (xhr.response || [])); + } + return intArrayFromString(xhr.responseText || "", true); + }; + var lazyArray = this; + lazyArray.setDataGetter(chunkNum => { + var start = chunkNum * chunkSize; + var end = (chunkNum + 1) * chunkSize - 1; + // including this byte + end = Math.min(end, datalength - 1); + // if datalength-1 is selected, this is the last block + if (typeof lazyArray.chunks[chunkNum] == "undefined") { + lazyArray.chunks[chunkNum] = doXHR(start, end); + } + if (typeof lazyArray.chunks[chunkNum] == "undefined") abort("doXHR failed!"); + return lazyArray.chunks[chunkNum]; + }); + if (usesGzip || !datalength) { + // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length + chunkSize = datalength = 1; + // this will force getter(0)/doXHR do download the whole file + datalength = this.getter(0).length; + chunkSize = datalength; + out("LazyFiles on gzip forces download of the whole file when length is accessed"); + } + this._length = datalength; + this._chunkSize = chunkSize; + this.lengthKnown = true; + } + get length() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + } + get chunkSize() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + } + } + if (globalThis.XMLHttpRequest) { + if (!ENVIRONMENT_IS_WORKER) abort("Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc"); + var lazyArray = new LazyUint8Array; + var properties = { + isDevice: false, + contents: lazyArray + }; + } else { + var properties = { + isDevice: false, + url + }; + } + var node = FS.createFile(parent, name, properties, canRead, canWrite); + // This is a total hack, but I want to get this lazy file code out of the + // core of MEMFS. If we want to keep this lazy file concept I feel it should + // be its own thin LAZYFS proxying calls to MEMFS. + if (properties.contents) { + node.contents = properties.contents; + } else if (properties.url) { + node.contents = null; + node.url = properties.url; + } + // Add a function that defers querying the file size until it is asked the first time. + Object.defineProperties(node, { + usedBytes: { + get: function() { + return this.contents.length; + } + } + }); + // override each stream op with one that tries to force load the lazy file first + var stream_ops = {}; + for (const [key, fn] of Object.entries(node.stream_ops)) { + stream_ops[key] = (...args) => { + FS.forceLoadFile(node); + return fn(...args); + }; + } + function writeChunks(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= contents.length) return 0; + var size = Math.min(contents.length - position, length); + if (contents.slice) { + // normal array + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents[position + i]; + } + } else { + for (var i = 0; i < size; i++) { + // LazyUint8Array from sync binary XHR + buffer[offset + i] = contents.get(position + i); + } + } + return size; + } + // use a custom read function + stream_ops.read = (stream, buffer, offset, length, position) => { + FS.forceLoadFile(node); + return writeChunks(stream, buffer, offset, length, position); + }; + // use a custom mmap function + stream_ops.mmap = (stream, length, position, prot, flags) => { + FS.forceLoadFile(node); + var ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + writeChunks(stream, HEAP8, ptr, length, position); + return { + ptr, + allocated: true + }; + }; + node.stream_ops = stream_ops; + return node; + } +}; + +/** + * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the + * emscripten HEAP, returns a copy of that string as a Javascript String object. + * + * @param {number} ptr + * @param {number=} maxBytesToRead - An optional length that specifies the + * maximum number of bytes to read. You can omit this parameter to scan the + * string until the first 0 byte. If maxBytesToRead is passed, and the string + * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the + * string will cut short at that byte index. + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => { + ptr >>>= 0; + if (!ptr) return ""; + var end = findStringEnd(HEAPU8, ptr, maxBytesToRead, ignoreNul); + return UTF8Decoder.decode(HEAPU8.subarray(ptr >>> 0, end >>> 0)); +}; + +var SYSCALLS = { + calculateAt(dirfd, path, allowEmpty) { + if (PATH.isAbs(path)) { + return path; + } + // relative path + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = SYSCALLS.getStreamFromFD(dirfd); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44); + } + return dir; + } + return dir + "/" + path; + }, + writeStat(buf, stat) { + HEAPU32[((buf) >>> 2) >>> 0] = stat.dev; + HEAPU32[(((buf) + (4)) >>> 2) >>> 0] = stat.mode; + HEAPU32[(((buf) + (8)) >>> 2) >>> 0] = stat.nlink; + HEAPU32[(((buf) + (12)) >>> 2) >>> 0] = stat.uid; + HEAPU32[(((buf) + (16)) >>> 2) >>> 0] = stat.gid; + HEAPU32[(((buf) + (20)) >>> 2) >>> 0] = stat.rdev; + (tempI64 = [ stat.size >>> 0, (tempDouble = stat.size, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (24)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (28)) >>> 2) >>> 0] = tempI64[1]); + HEAP32[(((buf) + (32)) >>> 2) >>> 0] = 4096; + HEAP32[(((buf) + (36)) >>> 2) >>> 0] = stat.blocks; + var atime = stat.atime.getTime(); + var mtime = stat.mtime.getTime(); + var ctime = stat.ctime.getTime(); + (tempI64 = [ Math.floor(atime / 1e3) >>> 0, (tempDouble = Math.floor(atime / 1e3), + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (40)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (44)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (48)) >>> 2) >>> 0] = (atime % 1e3) * 1e3 * 1e3; + (tempI64 = [ Math.floor(mtime / 1e3) >>> 0, (tempDouble = Math.floor(mtime / 1e3), + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (56)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (60)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (64)) >>> 2) >>> 0] = (mtime % 1e3) * 1e3 * 1e3; + (tempI64 = [ Math.floor(ctime / 1e3) >>> 0, (tempDouble = Math.floor(ctime / 1e3), + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (72)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (76)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (80)) >>> 2) >>> 0] = (ctime % 1e3) * 1e3 * 1e3; + (tempI64 = [ stat.ino >>> 0, (tempDouble = stat.ino, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (88)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (92)) >>> 2) >>> 0] = tempI64[1]); + return 0; + }, + writeStatFs(buf, stats) { + HEAPU32[(((buf) + (4)) >>> 2) >>> 0] = stats.bsize; + HEAPU32[(((buf) + (60)) >>> 2) >>> 0] = stats.bsize; + (tempI64 = [ stats.blocks >>> 0, (tempDouble = stats.blocks, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (8)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (12)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.bfree >>> 0, (tempDouble = stats.bfree, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (16)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (20)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.bavail >>> 0, (tempDouble = stats.bavail, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (24)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (28)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.files >>> 0, (tempDouble = stats.files, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (32)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (36)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ stats.ffree >>> 0, (tempDouble = stats.ffree, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((buf) + (40)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((buf) + (44)) >>> 2) >>> 0] = tempI64[1]); + HEAPU32[(((buf) + (48)) >>> 2) >>> 0] = stats.fsid; + HEAPU32[(((buf) + (64)) >>> 2) >>> 0] = stats.flags; + // ST_NOSUID + HEAPU32[(((buf) + (56)) >>> 2) >>> 0] = stats.namelen; + }, + doMsync(addr, stream, len, flags, offset) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (flags & 2) { + // MAP_PRIVATE calls need not to be synced back to underlying fs + return 0; + } + var buffer = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer, offset, len, flags); + }, + getStreamFromFD(fd) { + var stream = FS.getStreamChecked(fd); + return stream; + }, + varargs: undefined, + getStr(ptr) { + var ret = UTF8ToString(ptr); + return ret; + } +}; + +function ___syscall_dup(fd) { + try { + var old = SYSCALLS.getStreamFromFD(fd); + return FS.dupStream(old).fd; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_faccessat(dirfd, path, amode, flags) { + path >>>= 0; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (amode & ~7) { + // need a valid mode + return -28; + } + var lookup = FS.lookupPath(path, { + follow: true + }); + var node = lookup.node; + if (!node) { + return -44; + } + var perms = ""; + if (amode & 4) perms += "r"; + if (amode & 2) perms += "w"; + if (amode & 1) perms += "x"; + if (perms && FS.nodePermissions(node, perms)) { + return -2; + } + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var syscallGetVarargI = () => { + // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. + var ret = HEAP32[((+SYSCALLS.varargs) >>> 2) >>> 0]; + SYSCALLS.varargs += 4; + return ret; +}; + +var syscallGetVarargP = syscallGetVarargI; + +function ___syscall_fcntl64(fd, cmd, varargs) { + varargs >>>= 0; + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: + { + var arg = syscallGetVarargI(); + if (arg < 0) { + return -28; + } + while (FS.streams[arg]) { + arg++; + } + var newStream; + newStream = FS.dupStream(stream, arg); + return newStream.fd; + } + + case 1: + case 2: + return 0; + + // FD_CLOEXEC makes no sense for a single process. + case 3: + return stream.flags; + + case 4: + { + var arg = syscallGetVarargI(); + stream.flags |= arg; + return 0; + } + + case 12: + { + var arg = syscallGetVarargP(); + var offset = 0; + // We're always unlocked. + HEAP16[(((arg) + (offset)) >>> 1) >>> 0] = 2; + return 0; + } + + case 13: + case 14: + // Pretend that the locking is successful. These are process-level locks, + // and Emscripten programs are a single process. If we supported linking a + // filesystem between programs, we'd need to do more here. + // See https://github.com/emscripten-core/emscripten/issues/23697 + return 0; + } + return -28; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_fstat64(fd, buf) { + buf >>>= 0; + try { + return SYSCALLS.writeStat(buf, FS.fstat(fd)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_ftruncate64(fd, length_low, length_high) { + var length = convertI32PairToI53Checked(length_low, length_high); + try { + if (isNaN(length)) return -61; + FS.ftruncate(fd, length); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var stringToUTF8 = (str, outPtr, maxBytesToWrite) => stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + +function ___syscall_getcwd(buf, size) { + buf >>>= 0; + size >>>= 0; + try { + if (size === 0) return -28; + var cwd = FS.cwd(); + var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; + if (size < cwdLengthInBytes) return -68; + stringToUTF8(cwd, buf, size); + return cwdLengthInBytes; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_getdents64(fd, dirp, count) { + dirp >>>= 0; + count >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + stream.getdents ||= FS.readdir(stream.path); + var struct_size = 280; + var pos = 0; + var off = FS.llseek(stream, 0, 1); + var startIdx = Math.floor(off / struct_size); + var endIdx = Math.min(stream.getdents.length, startIdx + Math.floor(count / struct_size)); + for (var idx = startIdx; idx < endIdx; idx++) { + var id; + var type; + var name = stream.getdents[idx]; + if (name === ".") { + id = stream.node.id; + type = 4; + } else if (name === "..") { + var lookup = FS.lookupPath(stream.path, { + parent: true + }); + id = lookup.node.id; + type = 4; + } else { + var child; + try { + child = FS.lookupNode(stream.node, name); + } catch (e) { + // If the entry is not a directory, file, or symlink, nodefs + // lookupNode will raise EINVAL. Skip these and continue. + if (e?.errno === 28) { + continue; + } + throw e; + } + id = child.id; + type = FS.isChrdev(child.mode) ? 2 : // character device. + FS.isDir(child.mode) ? 4 : // directory + FS.isLink(child.mode) ? 10 : // symbolic link. + 8; + } + (tempI64 = [ id >>> 0, (tempDouble = id, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[((dirp + pos) >>> 2) >>> 0] = tempI64[0], HEAP32[(((dirp + pos) + (4)) >>> 2) >>> 0] = tempI64[1]); + (tempI64 = [ (idx + 1) * struct_size >>> 0, (tempDouble = (idx + 1) * struct_size, + (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[(((dirp + pos) + (8)) >>> 2) >>> 0] = tempI64[0], HEAP32[(((dirp + pos) + (12)) >>> 2) >>> 0] = tempI64[1]); + HEAP16[(((dirp + pos) + (16)) >>> 1) >>> 0] = 280; + HEAP8[(dirp + pos) + (18) >>> 0] = type; + stringToUTF8(name, dirp + pos + 19, 256); + pos += struct_size; + } + FS.llseek(stream, idx * struct_size, 0); + return pos; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_ioctl(fd, op, varargs) { + varargs >>>= 0; + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (op) { + case 21509: + { + if (!stream.tty) return -59; + return 0; + } + + case 21505: + { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcgets) { + var termios = stream.tty.ops.ioctl_tcgets(stream); + var argp = syscallGetVarargP(); + HEAP32[((argp) >>> 2) >>> 0] = termios.c_iflag || 0; + HEAP32[(((argp) + (4)) >>> 2) >>> 0] = termios.c_oflag || 0; + HEAP32[(((argp) + (8)) >>> 2) >>> 0] = termios.c_cflag || 0; + HEAP32[(((argp) + (12)) >>> 2) >>> 0] = termios.c_lflag || 0; + for (var i = 0; i < 32; i++) { + HEAP8[(argp + i) + (17) >>> 0] = termios.c_cc[i] || 0; + } + return 0; + } + return 0; + } + + case 21510: + case 21511: + case 21512: + { + if (!stream.tty) return -59; + return 0; + } + + case 21506: + case 21507: + case 21508: + { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcsets) { + var argp = syscallGetVarargP(); + var c_iflag = HEAP32[((argp) >>> 2) >>> 0]; + var c_oflag = HEAP32[(((argp) + (4)) >>> 2) >>> 0]; + var c_cflag = HEAP32[(((argp) + (8)) >>> 2) >>> 0]; + var c_lflag = HEAP32[(((argp) + (12)) >>> 2) >>> 0]; + var c_cc = []; + for (var i = 0; i < 32; i++) { + c_cc.push(HEAP8[(argp + i) + (17) >>> 0]); + } + return stream.tty.ops.ioctl_tcsets(stream.tty, op, { + c_iflag, + c_oflag, + c_cflag, + c_lflag, + c_cc + }); + } + return 0; + } + + case 21519: + { + if (!stream.tty) return -59; + var argp = syscallGetVarargP(); + HEAP32[((argp) >>> 2) >>> 0] = 0; + return 0; + } + + case 21520: + { + if (!stream.tty) return -59; + return -28; + } + + case 21537: + case 21531: + { + var argp = syscallGetVarargP(); + return FS.ioctl(stream, op, argp); + } + + case 21523: + { + // TODO: in theory we should write to the winsize struct that gets + // passed in, but for now musl doesn't read anything on it + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tiocgwinsz) { + var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty); + var argp = syscallGetVarargP(); + HEAP16[((argp) >>> 1) >>> 0] = winsize[0]; + HEAP16[(((argp) + (2)) >>> 1) >>> 0] = winsize[1]; + } + return 0; + } + + case 21524: + { + // TODO: technically, this ioctl call should change the window size. + // but, since emscripten doesn't have any concept of a terminal window + // yet, we'll just silently throw it away as we do TIOCGWINSZ + if (!stream.tty) return -59; + return 0; + } + + case 21515: + { + if (!stream.tty) return -59; + return 0; + } + + default: + return -28; + } + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_lstat64(path, buf) { + path >>>= 0; + buf >>>= 0; + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.writeStat(buf, FS.lstat(path)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_mkdirat(dirfd, path, mode) { + path >>>= 0; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + FS.mkdir(path, mode, 0); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_newfstatat(dirfd, path, buf, flags) { + path >>>= 0; + buf >>>= 0; + try { + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + var allowEmpty = flags & 4096; + flags = flags & (~6400); + path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); + return SYSCALLS.writeStat(buf, nofollow ? FS.lstat(path) : FS.stat(path)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_openat(dirfd, path, flags, varargs) { + path >>>= 0; + varargs >>>= 0; + SYSCALLS.varargs = varargs; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + var mode = varargs ? syscallGetVarargI() : 0; + return FS.open(path, flags, mode).fd; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function ___syscall_stat64(path, buf) { + path >>>= 0; + buf >>>= 0; + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.writeStat(buf, FS.stat(path)); + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var __abort_js = () => abort(""); + +function __embind_register_bigint(primitiveType, name, size, minRange, maxRange) { + primitiveType >>>= 0; + name >>>= 0; + size >>>= 0; +} + +var AsciiToString = ptr => { + ptr >>>= 0; + var str = ""; + while (1) { + var ch = HEAPU8[ptr++ >>> 0]; + if (!ch) return str; + str += String.fromCharCode(ch); + } +}; + +var awaitingDependencies = {}; + +var registeredTypes = {}; + +var typeDependencies = {}; + +var BindingError = class BindingError extends Error { + constructor(message) { + super(message); + this.name = "BindingError"; + } +}; + +var throwBindingError = message => { + throw new BindingError(message); +}; + +/** @param {Object=} options */ function sharedRegisterType(rawType, registeredInstance, options = {}) { + var name = registeredInstance.name; + if (!rawType) { + throwBindingError(`type "${name}" must have a positive integer typeid pointer`); + } + if (registeredTypes.hasOwnProperty(rawType)) { + if (options.ignoreDuplicateRegistrations) { + return; + } else { + throwBindingError(`Cannot register type '${name}' twice`); + } + } + registeredTypes[rawType] = registeredInstance; + delete typeDependencies[rawType]; + if (awaitingDependencies.hasOwnProperty(rawType)) { + var callbacks = awaitingDependencies[rawType]; + delete awaitingDependencies[rawType]; + callbacks.forEach(cb => cb()); + } +} + +/** @param {Object=} options */ function registerType(rawType, registeredInstance, options = {}) { + return sharedRegisterType(rawType, registeredInstance, options); +} + +/** @suppress {globalThis} */ function __embind_register_bool(rawType, name, trueValue, falseValue) { + rawType >>>= 0; + name >>>= 0; + name = AsciiToString(name); + registerType(rawType, { + name, + fromWireType: function(wt) { + // ambiguous emscripten ABI: sometimes return values are + // true or false, and sometimes integers (0 or 1) + return !!wt; + }, + toWireType: function(destructors, o) { + return o ? trueValue : falseValue; + }, + readValueFromPointer: function(pointer) { + return this.fromWireType(HEAPU8[pointer >>> 0]); + }, + destructorFunction: null + }); +} + +var emval_freelist = []; + +var emval_handles = [ 0, 1, , 1, null, 1, true, 1, false, 1 ]; + +function __emval_decref(handle) { + handle >>>= 0; + if (handle > 9 && 0 === --emval_handles[handle + 1]) { + emval_handles[handle] = undefined; + emval_freelist.push(handle); + } +} + +var Emval = { + toValue: handle => { + if (!handle) { + throwBindingError(`Cannot use deleted val. handle = ${handle}`); + } + return emval_handles[handle]; + }, + toHandle: value => { + switch (value) { + case undefined: + return 2; + + case null: + return 4; + + case true: + return 6; + + case false: + return 8; + + default: + { + const handle = emval_freelist.pop() || emval_handles.length; + emval_handles[handle] = value; + emval_handles[handle + 1] = 1; + return handle; + } + } + } +}; + +/** @suppress {globalThis} */ function readPointer(pointer) { + return this.fromWireType(HEAPU32[((pointer) >>> 2) >>> 0]); +} + +var EmValType = { + name: "emscripten::val", + fromWireType: handle => { + var rv = Emval.toValue(handle); + __emval_decref(handle); + return rv; + }, + toWireType: (destructors, value) => Emval.toHandle(value), + readValueFromPointer: readPointer, + destructorFunction: null +}; + +function __embind_register_emval(rawType) { + rawType >>>= 0; + return registerType(rawType, EmValType); +} + +var floatReadValueFromPointer = (name, width) => { + switch (width) { + case 4: + return function(pointer) { + return this.fromWireType(HEAPF32[((pointer) >>> 2) >>> 0]); + }; + + case 8: + return function(pointer) { + return this.fromWireType(HEAPF64[((pointer) >>> 3) >>> 0]); + }; + + default: + throw new TypeError(`invalid float width (${width}): ${name}`); + } +}; + +var __embind_register_float = function(rawType, name, size) { + rawType >>>= 0; + name >>>= 0; + size >>>= 0; + name = AsciiToString(name); + registerType(rawType, { + name, + fromWireType: value => value, + toWireType: (destructors, value) => value, + readValueFromPointer: floatReadValueFromPointer(name, size), + destructorFunction: null + }); +}; + +var createNamedFunction = (name, func) => Object.defineProperty(func, "name", { + value: name +}); + +var runDestructors = destructors => { + while (destructors.length) { + var ptr = destructors.pop(); + var del = destructors.pop(); + del(ptr); + } +}; + +function usesDestructorStack(argTypes) { + // Skip return value at index 0 - it's not deleted here. + for (var i = 1; i < argTypes.length; ++i) { + // The type does not define a destructor function - must use dynamic stack + if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { + return true; + } + } + return false; +} + +var runAndAbortIfError = func => { + try { + return func(); + } catch (e) { + abort(e); + } +}; + +var runtimeKeepalivePush = () => { + runtimeKeepaliveCounter += 1; +}; + +var runtimeKeepalivePop = () => { + runtimeKeepaliveCounter -= 1; +}; + +var Asyncify = { + instrumentWasmImports(imports) { + var importPattern = /^(ReadBufferDataJs|WaitUntilCompletedJs|WaitUntilPipelineCreatedJs|invoke_.*|__asyncjs__.*)$/; + for (let [x, original] of Object.entries(imports)) { + if (typeof original == "function") { + let isAsyncifyImport = original.isAsync || importPattern.test(x); + } + } + }, + instrumentFunction(original) { + var wrapper = (...args) => { + Asyncify.exportCallStack.push(original); + try { + return original(...args); + } finally { + if (!ABORT) { + var top = Asyncify.exportCallStack.pop(); + Asyncify.maybeStopUnwind(); + } + } + }; + Asyncify.funcWrappers.set(original, wrapper); + return wrapper; + }, + instrumentWasmExports(exports) { + var ret = {}; + for (let [x, original] of Object.entries(exports)) { + if (typeof original == "function") { + var wrapper = Asyncify.instrumentFunction(original); + ret[x] = wrapper; + } else { + ret[x] = original; + } + } + return ret; + }, + State: { + Normal: 0, + Unwinding: 1, + Rewinding: 2, + Disabled: 3 + }, + state: 0, + StackSize: 4096, + currData: null, + handleSleepReturnValue: 0, + exportCallStack: [], + callstackFuncToId: new Map, + callStackIdToFunc: new Map, + funcWrappers: new Map, + callStackId: 0, + asyncPromiseHandlers: null, + sleepCallbacks: [], + getCallStackId(func) { + if (!Asyncify.callstackFuncToId.has(func)) { + var id = Asyncify.callStackId++; + Asyncify.callstackFuncToId.set(func, id); + Asyncify.callStackIdToFunc.set(id, func); + } + return Asyncify.callstackFuncToId.get(func); + }, + maybeStopUnwind() { + if (Asyncify.currData && Asyncify.state === Asyncify.State.Unwinding && Asyncify.exportCallStack.length === 0) { + // We just finished unwinding. + // Be sure to set the state before calling any other functions to avoid + // possible infinite recursion here (For example in debug pthread builds + // the dbg() function itself can call back into WebAssembly to get the + // current pthread_self() pointer). + Asyncify.state = Asyncify.State.Normal; + // Keep the runtime alive so that a re-wind can be done later. + runAndAbortIfError(_asyncify_stop_unwind); + if (typeof Fibers != "undefined") { + Fibers.trampoline(); + } + } + }, + whenDone() { + return new Promise((resolve, reject) => { + Asyncify.asyncPromiseHandlers = { + resolve, + reject + }; + }); + }, + allocateData() { + // An asyncify data structure has three fields: + // 0 current stack pos + // 4 max stack pos + // 8 id of function at bottom of the call stack (callStackIdToFunc[id] == wasm func) + // The Asyncify ABI only interprets the first two fields, the rest is for the runtime. + // We also embed a stack in the same memory region here, right next to the structure. + // This struct is also defined as asyncify_data_t in emscripten/fiber.h + var ptr = _malloc(12 + Asyncify.StackSize); + Asyncify.setDataHeader(ptr, ptr + 12, Asyncify.StackSize); + Asyncify.setDataRewindFunc(ptr); + return ptr; + }, + setDataHeader(ptr, stack, stackSize) { + HEAPU32[((ptr) >>> 2) >>> 0] = stack; + HEAPU32[(((ptr) + (4)) >>> 2) >>> 0] = stack + stackSize; + }, + setDataRewindFunc(ptr) { + var bottomOfCallStack = Asyncify.exportCallStack[0]; + var rewindId = Asyncify.getCallStackId(bottomOfCallStack); + HEAP32[(((ptr) + (8)) >>> 2) >>> 0] = rewindId; + }, + getDataRewindFunc(ptr) { + var id = HEAP32[(((ptr) + (8)) >>> 2) >>> 0]; + var func = Asyncify.callStackIdToFunc.get(id); + return func; + }, + doRewind(ptr) { + var original = Asyncify.getDataRewindFunc(ptr); + var func = Asyncify.funcWrappers.get(original); + // Once we have rewound and the stack we no longer need to artificially + // keep the runtime alive. + return callUserCallback(func); + }, + handleSleep(startAsync) { + if (ABORT) return; + if (Asyncify.state === Asyncify.State.Normal) { + // Prepare to sleep. Call startAsync, and see what happens: + // if the code decided to call our callback synchronously, + // then no async operation was in fact begun, and we don't + // need to do anything. + var reachedCallback = false; + var reachedAfterCallback = false; + startAsync((handleSleepReturnValue = 0) => { + if (ABORT) return; + Asyncify.handleSleepReturnValue = handleSleepReturnValue; + reachedCallback = true; + if (!reachedAfterCallback) { + // We are happening synchronously, so no need for async. + return; + } + Asyncify.state = Asyncify.State.Rewinding; + runAndAbortIfError(() => _asyncify_start_rewind(Asyncify.currData)); + if (typeof MainLoop != "undefined" && MainLoop.func) { + MainLoop.resume(); + } + var asyncWasmReturnValue, isError = false; + try { + asyncWasmReturnValue = Asyncify.doRewind(Asyncify.currData); + } catch (err) { + asyncWasmReturnValue = err; + isError = true; + } + // Track whether the return value was handled by any promise handlers. + var handled = false; + if (!Asyncify.currData) { + // All asynchronous execution has finished. + // `asyncWasmReturnValue` now contains the final + // return value of the exported async WASM function. + // Note: `asyncWasmReturnValue` is distinct from + // `Asyncify.handleSleepReturnValue`. + // `Asyncify.handleSleepReturnValue` contains the return + // value of the last C function to have executed + // `Asyncify.handleSleep()`, whereas `asyncWasmReturnValue` + // contains the return value of the exported WASM function + // that may have called C functions that + // call `Asyncify.handleSleep()`. + var asyncPromiseHandlers = Asyncify.asyncPromiseHandlers; + if (asyncPromiseHandlers) { + Asyncify.asyncPromiseHandlers = null; + (isError ? asyncPromiseHandlers.reject : asyncPromiseHandlers.resolve)(asyncWasmReturnValue); + handled = true; + } + } + if (isError && !handled) { + // If there was an error and it was not handled by now, we have no choice but to + // rethrow that error into the global scope where it can be caught only by + // `onerror` or `onunhandledpromiserejection`. + throw asyncWasmReturnValue; + } + }); + reachedAfterCallback = true; + if (!reachedCallback) { + // A true async operation was begun; start a sleep. + Asyncify.state = Asyncify.State.Unwinding; + // TODO: reuse, don't alloc/free every sleep + Asyncify.currData = Asyncify.allocateData(); + if (typeof MainLoop != "undefined" && MainLoop.func) { + MainLoop.pause(); + } + runAndAbortIfError(() => _asyncify_start_unwind(Asyncify.currData)); + } + } else if (Asyncify.state === Asyncify.State.Rewinding) { + // Stop a resume. + Asyncify.state = Asyncify.State.Normal; + runAndAbortIfError(_asyncify_stop_rewind); + _free(Asyncify.currData); + Asyncify.currData = null; + // Call all sleep callbacks now that the sleep-resume is all done. + Asyncify.sleepCallbacks.forEach(callUserCallback); + } else { + abort(`invalid state: ${Asyncify.state}`); + } + return Asyncify.handleSleepReturnValue; + }, + handleAsync: startAsync => Asyncify.handleSleep(async wakeUp => { + // TODO: add error handling as a second param when handleSleep implements it. + wakeUp(await startAsync()); + }) +}; + +function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, /** boolean= */ isAsync) { + // humanName: a human-readable string name for the function to be generated. + // argTypes: An array that contains the embind type objects for all types in the function signature. + // argTypes[0] is the type object for the function return value. + // argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method. + // argTypes[2...] are the actual function parameters. + // classType: The embind type object for the class to be bound, or null if this is not a method of a class. + // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. + // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. + // isAsync: Optional. If true, returns an async function. Async bindings are only supported with JSPI. + var argCount = argTypes.length; + if (argCount < 2) { + throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); + } + var isClassMethodFunc = (argTypes[1] !== null && classType !== null); + // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. + // TODO: This omits argument count check - enable only at -O3 or similar. + // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { + // return FUNCTION_TABLE[fn]; + // } + // Determine if we need to use a dynamic stack to store the destructors for the function parameters. + // TODO: Remove this completely once all function invokers are being dynamically generated. + var needsDestructorStack = usesDestructorStack(argTypes); + var returns = !argTypes[0].isVoid; + var expectedArgCount = argCount - 2; + var argsWired = new Array(expectedArgCount); + var invokerFuncArgs = []; + var destructors = []; + var invokerFn = function(...args) { + destructors.length = 0; + var thisWired; + invokerFuncArgs.length = isClassMethodFunc ? 2 : 1; + invokerFuncArgs[0] = cppTargetFunc; + if (isClassMethodFunc) { + thisWired = argTypes[1].toWireType(destructors, this); + invokerFuncArgs[1] = thisWired; + } + for (var i = 0; i < expectedArgCount; ++i) { + argsWired[i] = argTypes[i + 2].toWireType(destructors, args[i]); + invokerFuncArgs.push(argsWired[i]); + } + var rv = cppInvokerFunc(...invokerFuncArgs); + function onDone(rv) { + if (needsDestructorStack) { + runDestructors(destructors); + } else { + for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; i++) { + var param = i === 1 ? thisWired : argsWired[i - 2]; + if (argTypes[i].destructorFunction !== null) { + argTypes[i].destructorFunction(param); + } + } + } + if (returns) { + return argTypes[0].fromWireType(rv); + } + } + if (Asyncify.currData) { + return Asyncify.whenDone().then(onDone); + } + return onDone(rv); + }; + return createNamedFunction(humanName, invokerFn); +} + +var ensureOverloadTable = (proto, methodName, humanName) => { + if (undefined === proto[methodName].overloadTable) { + var prevFunc = proto[methodName]; + // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. + proto[methodName] = function(...args) { + // TODO This check can be removed in -O3 level "unsafe" optimizations. + if (!proto[methodName].overloadTable.hasOwnProperty(args.length)) { + throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`); + } + return proto[methodName].overloadTable[args.length].apply(this, args); + }; + // Move the previous function into the overload table. + proto[methodName].overloadTable = []; + proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } +}; + +/** @param {number=} numArguments */ var exposePublicSymbol = (name, value, numArguments) => { + if (Module.hasOwnProperty(name)) { + if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) { + throwBindingError(`Cannot register public name '${name}' twice`); + } + // We are exposing a function with the same name as an existing function. Create an overload table and a function selector + // that routes between the two. + ensureOverloadTable(Module, name, name); + if (Module[name].overloadTable.hasOwnProperty(numArguments)) { + throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`); + } + // Add the new function into the overload table. + Module[name].overloadTable[numArguments] = value; + } else { + Module[name] = value; + Module[name].argCount = numArguments; + } +}; + +var heap32VectorToArray = (count, firstElement) => { + var array = []; + for (var i = 0; i < count; i++) { + // TODO(https://github.com/emscripten-core/emscripten/issues/17310): + // Find a way to hoist the `>> 2` or `>> 3` out of this loop. + array.push(HEAPU32[(((firstElement) + (i * 4)) >>> 2) >>> 0]); + } + return array; +}; + +var InternalError = class InternalError extends Error { + constructor(message) { + super(message); + this.name = "InternalError"; + } +}; + +var throwInternalError = message => { + throw new InternalError(message); +}; + +/** @param {number=} numArguments */ var replacePublicSymbol = (name, value, numArguments) => { + if (!Module.hasOwnProperty(name)) { + throwInternalError("Replacing nonexistent public symbol"); + } + // If there's an overload table for this symbol, replace the symbol in the overload table instead. + if (undefined !== Module[name].overloadTable && undefined !== numArguments) { + Module[name].overloadTable[numArguments] = value; + } else { + Module[name] = value; + Module[name].argCount = numArguments; + } +}; + +var getDynCaller = (sig, ptr, promising = false) => (...args) => dynCall(sig, ptr, args, promising); + +var embind__requireFunction = (signature, rawFunction, isAsync = false) => { + signature = AsciiToString(signature); + function makeDynCaller() { + return getDynCaller(signature, rawFunction); + } + var fp = makeDynCaller(); + if (typeof fp != "function") { + throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`); + } + return fp; +}; + +class UnboundTypeError extends Error {} + +var getTypeName = type => { + var ptr = ___getTypeName(type); + var rv = AsciiToString(ptr); + _free(ptr); + return rv; +}; + +var throwUnboundTypeError = (message, types) => { + var unboundTypes = []; + var seen = {}; + function visit(type) { + if (seen[type]) { + return; + } + if (registeredTypes[type]) { + return; + } + if (typeDependencies[type]) { + typeDependencies[type].forEach(visit); + return; + } + unboundTypes.push(type); + seen[type] = true; + } + types.forEach(visit); + throw new UnboundTypeError(`${message}: ` + unboundTypes.map(getTypeName).join([ ", " ])); +}; + +var whenDependentTypesAreResolved = (myTypes, dependentTypes, getTypeConverters) => { + myTypes.forEach(type => typeDependencies[type] = dependentTypes); + function onComplete(typeConverters) { + var myTypeConverters = getTypeConverters(typeConverters); + if (myTypeConverters.length !== myTypes.length) { + throwInternalError("Mismatched type converter count"); + } + for (var i = 0; i < myTypes.length; ++i) { + registerType(myTypes[i], myTypeConverters[i]); + } + } + var typeConverters = new Array(dependentTypes.length); + var unregisteredTypes = []; + var registered = 0; + for (let [i, dt] of dependentTypes.entries()) { + if (registeredTypes.hasOwnProperty(dt)) { + typeConverters[i] = registeredTypes[dt]; + } else { + unregisteredTypes.push(dt); + if (!awaitingDependencies.hasOwnProperty(dt)) { + awaitingDependencies[dt] = []; + } + awaitingDependencies[dt].push(() => { + typeConverters[i] = registeredTypes[dt]; + ++registered; + if (registered === unregisteredTypes.length) { + onComplete(typeConverters); + } + }); + } + } + if (0 === unregisteredTypes.length) { + onComplete(typeConverters); + } +}; + +var getFunctionName = signature => { + signature = signature.trim(); + const argsIndex = signature.indexOf("("); + if (argsIndex === -1) return signature; + return signature.slice(0, argsIndex); +}; + +function __embind_register_function(name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync, isNonnullReturn) { + name >>>= 0; + rawArgTypesAddr >>>= 0; + signature >>>= 0; + rawInvoker >>>= 0; + fn >>>= 0; + var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + name = AsciiToString(name); + name = getFunctionName(name); + rawInvoker = embind__requireFunction(signature, rawInvoker, isAsync); + exposePublicSymbol(name, function() { + throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes); + }, argCount - 1); + whenDependentTypesAreResolved([], argTypes, argTypes => { + var invokerArgsArray = [ argTypes[0], null ].concat(argTypes.slice(1)); + replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null, rawInvoker, fn, isAsync), argCount - 1); + return []; + }); +} + +var integerReadValueFromPointer = (name, width, signed) => { + // integers are quite common, so generate very specialized functions + switch (width) { + case 1: + return signed ? pointer => HEAP8[pointer >>> 0] : pointer => HEAPU8[pointer >>> 0]; + + case 2: + return signed ? pointer => HEAP16[((pointer) >>> 1) >>> 0] : pointer => HEAPU16[((pointer) >>> 1) >>> 0]; + + case 4: + return signed ? pointer => HEAP32[((pointer) >>> 2) >>> 0] : pointer => HEAPU32[((pointer) >>> 2) >>> 0]; + + default: + throw new TypeError(`invalid integer width (${width}): ${name}`); + } +}; + +/** @suppress {globalThis} */ var __embind_register_integer = function(primitiveType, name, size, minRange, maxRange) { + primitiveType >>>= 0; + name >>>= 0; + size >>>= 0; + name = AsciiToString(name); + const isUnsignedType = minRange === 0; + let fromWireType = value => value; + if (isUnsignedType) { + var bitshift = 32 - 8 * size; + fromWireType = value => (value << bitshift) >>> bitshift; + maxRange = fromWireType(maxRange); + } + registerType(primitiveType, { + name, + fromWireType, + toWireType: (destructors, value) => value, + readValueFromPointer: integerReadValueFromPointer(name, size, minRange !== 0), + destructorFunction: null + }); +}; + +function __embind_register_memory_view(rawType, dataTypeIndex, name) { + rawType >>>= 0; + name >>>= 0; + var typeMapping = [ Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + var TA = typeMapping[dataTypeIndex]; + function decodeMemoryView(handle) { + var size = HEAPU32[((handle) >>> 2) >>> 0]; + var data = HEAPU32[(((handle) + (4)) >>> 2) >>> 0]; + return new TA(HEAP8.buffer, data, size); + } + name = AsciiToString(name); + registerType(rawType, { + name, + fromWireType: decodeMemoryView, + readValueFromPointer: decodeMemoryView + }, { + ignoreDuplicateRegistrations: true + }); +} + +function __embind_register_std_string(rawType, name) { + rawType >>>= 0; + name >>>= 0; + name = AsciiToString(name); + var stdStringIsUTF8 = true; + registerType(rawType, { + name, + // For some method names we use string keys here since they are part of + // the public/external API and/or used by the runtime-generated code. + fromWireType(value) { + var length = HEAPU32[((value) >>> 2) >>> 0]; + var payload = value + 4; + var str; + if (stdStringIsUTF8) { + str = UTF8ToString(payload, length, true); + } else { + str = ""; + for (var i = 0; i < length; ++i) { + str += String.fromCharCode(HEAPU8[payload + i >>> 0]); + } + } + _free(value); + return str; + }, + toWireType(destructors, value) { + if (value instanceof ArrayBuffer) { + value = new Uint8Array(value); + } + var length; + var valueIsOfTypeString = (typeof value == "string"); + // We accept `string` or array views with single byte elements + if (!(valueIsOfTypeString || (ArrayBuffer.isView(value) && value.BYTES_PER_ELEMENT == 1))) { + throwBindingError("Cannot pass non-string to std::string"); + } + if (stdStringIsUTF8 && valueIsOfTypeString) { + length = lengthBytesUTF8(value); + } else { + length = value.length; + } + // assumes POINTER_SIZE alignment + var base = _malloc(4 + length + 1); + var ptr = base + 4; + HEAPU32[((base) >>> 2) >>> 0] = length; + if (valueIsOfTypeString) { + if (stdStringIsUTF8) { + stringToUTF8(value, ptr, length + 1); + } else { + for (var i = 0; i < length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode > 255) { + _free(base); + throwBindingError("String has UTF-16 code units that do not fit in 8 bits"); + } + HEAPU8[ptr + i >>> 0] = charCode; + } + } + } else { + HEAPU8.set(value, ptr >>> 0); + } + if (destructors !== null) { + destructors.push(_free, base); + } + return base; + }, + readValueFromPointer: readPointer, + destructorFunction(ptr) { + _free(ptr); + } + }); +} + +var UTF16Decoder = new TextDecoder("utf-16le"); + +var UTF16ToString = (ptr, maxBytesToRead, ignoreNul) => { + var idx = ((ptr) >>> 1); + var endIdx = findStringEnd(HEAPU16, idx, maxBytesToRead / 2, ignoreNul); + return UTF16Decoder.decode(HEAPU16.subarray(idx >>> 0, endIdx >>> 0)); +}; + +var stringToUTF16 = (str, outPtr, maxBytesToWrite) => { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + maxBytesToWrite ??= 2147483647; + if (maxBytesToWrite < 2) return 0; + maxBytesToWrite -= 2; + // Null terminator. + var startPtr = outPtr; + var numCharsToWrite = (maxBytesToWrite < str.length * 2) ? (maxBytesToWrite / 2) : str.length; + for (var i = 0; i < numCharsToWrite; ++i) { + // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. + var codeUnit = str.charCodeAt(i); + // possibly a lead surrogate + HEAP16[((outPtr) >>> 1) >>> 0] = codeUnit; + outPtr += 2; + } + // Null-terminate the pointer to the HEAP. + HEAP16[((outPtr) >>> 1) >>> 0] = 0; + return outPtr - startPtr; +}; + +var lengthBytesUTF16 = str => str.length * 2; + +var UTF32ToString = (ptr, maxBytesToRead, ignoreNul) => { + var str = ""; + var startIdx = ((ptr) >>> 2); + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + for (var i = 0; !(i >= maxBytesToRead / 4); i++) { + var utf32 = HEAPU32[startIdx + i >>> 0]; + if (!utf32 && !ignoreNul) break; + str += String.fromCodePoint(utf32); + } + return str; +}; + +var stringToUTF32 = (str, outPtr, maxBytesToWrite) => { + outPtr >>>= 0; + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + maxBytesToWrite ??= 2147483647; + if (maxBytesToWrite < 4) return 0; + var startPtr = outPtr; + var endPtr = startPtr + maxBytesToWrite - 4; + for (var i = 0; i < str.length; ++i) { + var codePoint = str.codePointAt(i); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + if (codePoint > 65535) { + i++; + } + HEAP32[((outPtr) >>> 2) >>> 0] = codePoint; + outPtr += 4; + if (outPtr + 4 > endPtr) break; + } + // Null-terminate the pointer to the HEAP. + HEAP32[((outPtr) >>> 2) >>> 0] = 0; + return outPtr - startPtr; +}; + +var lengthBytesUTF32 = str => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var codePoint = str.codePointAt(i); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + if (codePoint > 65535) { + i++; + } + len += 4; + } + return len; +}; + +function __embind_register_std_wstring(rawType, charSize, name) { + rawType >>>= 0; + charSize >>>= 0; + name >>>= 0; + name = AsciiToString(name); + var decodeString, encodeString, lengthBytesUTF; + if (charSize === 2) { + decodeString = UTF16ToString; + encodeString = stringToUTF16; + lengthBytesUTF = lengthBytesUTF16; + } else { + decodeString = UTF32ToString; + encodeString = stringToUTF32; + lengthBytesUTF = lengthBytesUTF32; + } + registerType(rawType, { + name, + fromWireType: value => { + // Code mostly taken from _embind_register_std_string fromWireType + var length = HEAPU32[((value) >>> 2) >>> 0]; + var str = decodeString(value + 4, length * charSize, true); + _free(value); + return str; + }, + toWireType: (destructors, value) => { + if (!(typeof value == "string")) { + throwBindingError(`Cannot pass non-string to C++ string type ${name}`); + } + // assumes POINTER_SIZE alignment + var length = lengthBytesUTF(value); + var ptr = _malloc(4 + length + charSize); + HEAPU32[((ptr) >>> 2) >>> 0] = length / charSize; + encodeString(value, ptr + 4, length + charSize); + if (destructors !== null) { + destructors.push(_free, ptr); + } + return ptr; + }, + readValueFromPointer: readPointer, + destructorFunction(ptr) { + _free(ptr); + } + }); +} + +var __embind_register_void = function(rawType, name) { + rawType >>>= 0; + name >>>= 0; + name = AsciiToString(name); + registerType(rawType, { + isVoid: true, + // void return values can be optimized out sometimes + name, + fromWireType: () => undefined, + // TODO: assert if anything else is given? + toWireType: (destructors, o) => undefined + }); +}; + +var emval_methodCallers = []; + +var emval_addMethodCaller = caller => { + var id = emval_methodCallers.length; + emval_methodCallers.push(caller); + return id; +}; + +var requireRegisteredType = (rawType, humanName) => { + var impl = registeredTypes[rawType]; + if (undefined === impl) { + throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`); + } + return impl; +}; + +var emval_lookupTypes = (argCount, argTypes) => { + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + a[i] = requireRegisteredType(HEAPU32[(((argTypes) + (i * 4)) >>> 2) >>> 0], `parameter ${i}`); + } + return a; +}; + +var emval_returnValue = (toReturnWire, destructorsRef, handle) => { + var destructors = []; + var result = toReturnWire(destructors, handle); + if (destructors.length) { + // void, primitives and any other types w/o destructors don't need to allocate a handle + HEAPU32[((destructorsRef) >>> 2) >>> 0] = Emval.toHandle(destructors); + } + return result; +}; + +var emval_symbols = {}; + +var getStringOrSymbol = address => { + var symbol = emval_symbols[address]; + if (symbol === undefined) { + return AsciiToString(address); + } + return symbol; +}; + +var __emval_create_invoker = function(argCount, argTypesPtr, kind) { + argTypesPtr >>>= 0; + var GenericWireTypeSize = 8; + var [retType, ...argTypes] = emval_lookupTypes(argCount, argTypesPtr); + var toReturnWire = retType.toWireType.bind(retType); + var argFromPtr = argTypes.map(type => type.readValueFromPointer.bind(type)); + argCount--; + // remove the extracted return type + var argN = new Array(argCount); + var invokerFunction = (handle, methodName, destructorsRef, args) => { + var offset = 0; + for (var i = 0; i < argCount; ++i) { + argN[i] = argFromPtr[i](args + offset); + offset += GenericWireTypeSize; + } + var rv; + switch (kind) { + case 0: + rv = Emval.toValue(handle).apply(null, argN); + break; + + case 2: + rv = Reflect.construct(Emval.toValue(handle), argN); + break; + + case 3: + // no-op, just return the argument + rv = argN[0]; + break; + + case 1: + rv = Emval.toValue(handle)[getStringOrSymbol(methodName)](...argN); + break; + } + return emval_returnValue(toReturnWire, destructorsRef, rv); + }; + var functionName = `methodCaller<(${argTypes.map(t => t.name)}) => ${retType.name}>`; + return emval_addMethodCaller(createNamedFunction(functionName, invokerFunction)); +}; + +function __emval_incref(handle) { + handle >>>= 0; + if (handle > 9) { + emval_handles[handle + 1] += 1; + } +} + +function __emval_invoke(caller, handle, methodName, destructorsRef, args) { + caller >>>= 0; + handle >>>= 0; + methodName >>>= 0; + destructorsRef >>>= 0; + args >>>= 0; + return emval_methodCallers[caller](handle, methodName, destructorsRef, args); +} + +function __emval_run_destructors(handle) { + handle >>>= 0; + var destructors = Emval.toValue(handle); + runDestructors(destructors); + __emval_decref(handle); +} + +function __gmtime_js(time_low, time_high, tmPtr) { + var time = convertI32PairToI53Checked(time_low, time_high); + tmPtr >>>= 0; + var date = new Date(time * 1e3); + HEAP32[((tmPtr) >>> 2) >>> 0] = date.getUTCSeconds(); + HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0] = date.getUTCMinutes(); + HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0] = date.getUTCHours(); + HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0] = date.getUTCDate(); + HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0] = date.getUTCMonth(); + HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] = date.getUTCFullYear() - 1900; + HEAP32[(((tmPtr) + (24)) >>> 2) >>> 0] = date.getUTCDay(); + var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); + var yday = ((date.getTime() - start) / (1e3 * 60 * 60 * 24)) | 0; + HEAP32[(((tmPtr) + (28)) >>> 2) >>> 0] = yday; +} + +var isLeapYear = year => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + +var MONTH_DAYS_LEAP_CUMULATIVE = [ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 ]; + +var MONTH_DAYS_REGULAR_CUMULATIVE = [ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ]; + +var ydayFromDate = date => { + var leap = isLeapYear(date.getFullYear()); + var monthDaysCumulative = (leap ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE); + var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; + // -1 since it's days since Jan 1 + return yday; +}; + +function __localtime_js(time_low, time_high, tmPtr) { + var time = convertI32PairToI53Checked(time_low, time_high); + tmPtr >>>= 0; + var date = new Date(time * 1e3); + HEAP32[((tmPtr) >>> 2) >>> 0] = date.getSeconds(); + HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0] = date.getMinutes(); + HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0] = date.getHours(); + HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0] = date.getDate(); + HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0] = date.getMonth(); + HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] = date.getFullYear() - 1900; + HEAP32[(((tmPtr) + (24)) >>> 2) >>> 0] = date.getDay(); + var yday = ydayFromDate(date) | 0; + HEAP32[(((tmPtr) + (28)) >>> 2) >>> 0] = yday; + HEAP32[(((tmPtr) + (36)) >>> 2) >>> 0] = -(date.getTimezoneOffset() * 60); + // Attention: DST is in December in South, and some regions don't have DST at all. + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset)) | 0; + HEAP32[(((tmPtr) + (32)) >>> 2) >>> 0] = dst; +} + +var setTempRet0 = val => __emscripten_tempret_set(val); + +var __mktime_js = function(tmPtr) { + tmPtr >>>= 0; + var ret = (() => { + var date = new Date(HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] + 1900, HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0], HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0], HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0], HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0], HEAP32[((tmPtr) >>> 2) >>> 0], 0); + // There's an ambiguous hour when the time goes back; the tm_isdst field is + // used to disambiguate it. Date() basically guesses, so we fix it up if it + // guessed wrong, or fill in tm_isdst with the guess if it's -1. + var dst = HEAP32[(((tmPtr) + (32)) >>> 2) >>> 0]; + var guessedOffset = date.getTimezoneOffset(); + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dstOffset = Math.min(winterOffset, summerOffset); + // DST is in December in South + if (dst < 0) { + // Attention: some regions don't have DST at all. + HEAP32[(((tmPtr) + (32)) >>> 2) >>> 0] = Number(summerOffset != winterOffset && dstOffset == guessedOffset); + } else if ((dst > 0) != (dstOffset == guessedOffset)) { + var nonDstOffset = Math.max(winterOffset, summerOffset); + var trueOffset = dst > 0 ? dstOffset : nonDstOffset; + // Don't try setMinutes(date.getMinutes() + ...) -- it's messed up. + date.setTime(date.getTime() + (trueOffset - guessedOffset) * 6e4); + } + HEAP32[(((tmPtr) + (24)) >>> 2) >>> 0] = date.getDay(); + var yday = ydayFromDate(date) | 0; + HEAP32[(((tmPtr) + (28)) >>> 2) >>> 0] = yday; + // To match expected behavior, update fields from date + HEAP32[((tmPtr) >>> 2) >>> 0] = date.getSeconds(); + HEAP32[(((tmPtr) + (4)) >>> 2) >>> 0] = date.getMinutes(); + HEAP32[(((tmPtr) + (8)) >>> 2) >>> 0] = date.getHours(); + HEAP32[(((tmPtr) + (12)) >>> 2) >>> 0] = date.getDate(); + HEAP32[(((tmPtr) + (16)) >>> 2) >>> 0] = date.getMonth(); + HEAP32[(((tmPtr) + (20)) >>> 2) >>> 0] = date.getYear(); + var timeMs = date.getTime(); + if (isNaN(timeMs)) { + return -1; + } + // Return time in microseconds + return timeMs / 1e3; + })(); + return (setTempRet0((tempDouble = ret, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0)), + ret >>> 0); +}; + +function __mmap_js(len, prot, flags, fd, offset_low, offset_high, allocated, addr) { + len >>>= 0; + var offset = convertI32PairToI53Checked(offset_low, offset_high); + allocated >>>= 0; + addr >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var res = FS.mmap(stream, len, offset, prot, flags); + var ptr = res.ptr; + HEAP32[((allocated) >>> 2) >>> 0] = res.allocated; + HEAPU32[((addr) >>> 2) >>> 0] = ptr; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +function __munmap_js(addr, len, prot, flags, fd, offset_low, offset_high) { + addr >>>= 0; + len >>>= 0; + var offset = convertI32PairToI53Checked(offset_low, offset_high); + try { + var stream = SYSCALLS.getStreamFromFD(fd); + if (prot & 2) { + SYSCALLS.doMsync(addr, stream, len, flags, offset); + } + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return -e.errno; + } +} + +var __tzset_js = function(timezone, daylight, std_name, dst_name) { + timezone >>>= 0; + daylight >>>= 0; + std_name >>>= 0; + dst_name >>>= 0; + // TODO: Use (malleable) environment variables instead of system settings. + var currentYear = (new Date).getFullYear(); + var winter = new Date(currentYear, 0, 1); + var summer = new Date(currentYear, 6, 1); + var winterOffset = winter.getTimezoneOffset(); + var summerOffset = summer.getTimezoneOffset(); + // Local standard timezone offset. Local standard time is not adjusted for + // daylight savings. This code uses the fact that getTimezoneOffset returns + // a greater value during Standard Time versus Daylight Saving Time (DST). + // Thus it determines the expected output during Standard Time, and it + // compares whether the output of the given date the same (Standard) or less + // (DST). + var stdTimezoneOffset = Math.max(winterOffset, summerOffset); + // timezone is specified as seconds west of UTC ("The external variable + // `timezone` shall be set to the difference, in seconds, between + // Coordinated Universal Time (UTC) and local standard time."), the same + // as returned by stdTimezoneOffset. + // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html + HEAPU32[((timezone) >>> 2) >>> 0] = stdTimezoneOffset * 60; + HEAP32[((daylight) >>> 2) >>> 0] = Number(winterOffset != summerOffset); + var extractZone = timezoneOffset => { + // Why inverse sign? + // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset + var sign = timezoneOffset >= 0 ? "-" : "+"; + var absOffset = Math.abs(timezoneOffset); + var hours = String(Math.floor(absOffset / 60)).padStart(2, "0"); + var minutes = String(absOffset % 60).padStart(2, "0"); + return `UTC${sign}${hours}${minutes}`; + }; + var winterName = extractZone(winterOffset); + var summerName = extractZone(summerOffset); + if (summerOffset < winterOffset) { + // Northern hemisphere + stringToUTF8(winterName, std_name, 17); + stringToUTF8(summerName, dst_name, 17); + } else { + stringToUTF8(winterName, dst_name, 17); + stringToUTF8(summerName, std_name, 17); + } +}; + +var _emscripten_get_now = () => performance.now(); + +var _emscripten_date_now = () => Date.now(); + +var nowIsMonotonic = 1; + +var checkWasiClock = clock_id => clock_id >= 0 && clock_id <= 3; + +function _clock_time_get(clk_id, ignored_precision_low, ignored_precision_high, ptime) { + var ignored_precision = convertI32PairToI53Checked(ignored_precision_low, ignored_precision_high); + ptime >>>= 0; + if (!checkWasiClock(clk_id)) { + return 28; + } + var now; + // all wasi clocks but realtime are monotonic + if (clk_id === 0) { + now = _emscripten_date_now(); + } else if (nowIsMonotonic) { + now = _emscripten_get_now(); + } else { + return 52; + } + // "now" is in ms, and wasi times are in ns. + var nsec = Math.round(now * 1e3 * 1e3); + (tempI64 = [ nsec >>> 0, (tempDouble = nsec, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[((ptime) >>> 2) >>> 0] = tempI64[0], HEAP32[(((ptime) + (4)) >>> 2) >>> 0] = tempI64[1]); + return 0; +} + +var readEmAsmArgsArray = []; + +var readEmAsmArgs = (sigPtr, buf) => { + readEmAsmArgsArray.length = 0; + var ch; + // Most arguments are i32s, so shift the buffer pointer so it is a plain + // index into HEAP32. + while (ch = HEAPU8[sigPtr++ >>> 0]) { + // Floats are always passed as doubles, so all types except for 'i' + // are 8 bytes and require alignment. + var wide = (ch != 105); + wide &= (ch != 112); + buf += wide && (buf % 8) ? 4 : 0; + readEmAsmArgsArray.push(// Special case for pointers under wasm64 or CAN_ADDRESS_2GB mode. + ch == 112 ? HEAPU32[((buf) >>> 2) >>> 0] : ch == 105 ? HEAP32[((buf) >>> 2) >>> 0] : HEAPF64[((buf) >>> 3) >>> 0]); + buf += wide ? 8 : 4; + } + return readEmAsmArgsArray; +}; + +var runEmAsmFunction = (code, sigPtr, argbuf) => { + var args = readEmAsmArgs(sigPtr, argbuf); + return ASM_CONSTS[code](...args); +}; + +function _emscripten_asm_const_int(code, sigPtr, argbuf) { + code >>>= 0; + sigPtr >>>= 0; + argbuf >>>= 0; + return runEmAsmFunction(code, sigPtr, argbuf); +} + +function _emscripten_errn(str, len) { + str >>>= 0; + len >>>= 0; + return err(UTF8ToString(str, len)); +} + +var getHeapMax = () => // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate +// full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side +// for any code that deals with heap sizes, which would require special +// casing all heap size related code to treat 0 specially. +4294901760; + +function _emscripten_get_heap_max() { + return getHeapMax(); +} + +var _emscripten_has_asyncify = () => 1; + +function _emscripten_outn(str, len) { + str >>>= 0; + len >>>= 0; + return out(UTF8ToString(str, len)); +} + +var UNWIND_CACHE = {}; + +var stringToNewUTF8 = str => { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8(str, ret, size); + return ret; +}; + +/** @returns {number} */ var convertFrameToPC = frame => { + var match; + if (match = /\bwasm-function\[\d+\]:(0x[0-9a-f]+)/.exec(frame)) { + // Wasm engines give the binary offset directly, so we use that as return address + return +match[1]; + } else if (match = /:(\d+):\d+(?:\)|$)/.exec(frame)) { + // If we are in js, we can use the js line number as the "return address". + // This should work for wasm2js. We tag the high bit to distinguish this + // from wasm addresses. + return 2147483648 | +match[1]; + } + // return 0 if we can't find any + return 0; +}; + +var saveInUnwindCache = callstack => { + for (var line of callstack) { + var pc = convertFrameToPC(line); + if (pc) { + UNWIND_CACHE[pc] = line; + } + } +}; + +var jsStackTrace = () => (new Error).stack.toString(); + +function _emscripten_stack_snapshot() { + var callstack = jsStackTrace().split("\n"); + if (callstack[0] == "Error") { + callstack.shift(); + } + saveInUnwindCache(callstack); + // Caches the stack snapshot so that emscripten_stack_unwind_buffer() can + // unwind from this spot. + UNWIND_CACHE.last_addr = convertFrameToPC(callstack[3]); + UNWIND_CACHE.last_stack = callstack; + return UNWIND_CACHE.last_addr; +} + +function _emscripten_pc_get_function(pc) { + pc >>>= 0; + var frame = UNWIND_CACHE[pc]; + if (!frame) return 0; + var name; + var match; + // First try to match foo.wasm.sym files explcitly. e.g. + // at test_return_address.wasm.main (wasm://wasm/test_return_address.wasm-0012cc2a:wasm-function[26]:0x9f3 + // Then match JS symbols which don't include that module name: + // at invokeEntryPoint (.../test_return_address.js:1500:42) + // Finally match firefox format: + // Object._main@http://server.com:4324:12' + if (match = /^\s+at .*\.wasm\.(.*) \(.*\)$/.exec(frame)) { + name = match[1]; + } else if (match = /^\s+at (.*) \(.*\)$/.exec(frame)) { + name = match[1]; + } else if (match = /^(.+?)@/.exec(frame)) { + name = match[1]; + } else { + return 0; + } + _free(_emscripten_pc_get_function.ret ?? 0); + _emscripten_pc_get_function.ret = stringToNewUTF8(name); + return _emscripten_pc_get_function.ret; +} + +var growMemory = size => { + var oldHeapSize = wasmMemory.buffer.byteLength; + var pages = ((size - oldHeapSize + 65535) / 65536) | 0; + try { + // round size grow request up to wasm page size (fixed 64KB per spec) + wasmMemory.grow(pages); + // .grow() takes a delta compared to the previous size + updateMemoryViews(); + return 1; + } catch (e) {} +}; + +function _emscripten_resize_heap(requestedSize) { + requestedSize >>>= 0; + var oldSize = HEAPU8.length; + // With multithreaded builds, races can happen (another thread might increase the size + // in between), so return a failure, and let the caller retry. + // Memory resize rules: + // 1. Always increase heap size to at least the requested size, rounded up + // to next page multiple. + // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap + // geometrically: increase the heap size according to + // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most + // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB). + // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap + // linearly: increase the heap size by at least + // MEMORY_GROWTH_LINEAR_STEP bytes. + // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by + // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest + // 4. If we were unable to allocate as much memory, it may be due to + // over-eager decision to excessively reserve due to (3) above. + // Hence if an allocation fails, cut down on the amount of excess + // growth, in an attempt to succeed to perform a smaller allocation. + // A limit is set for how much we can grow. We should not exceed that + // (the wasm binary specifies it, so if we tried, we'd fail anyhow). + var maxHeapSize = getHeapMax(); + if (requestedSize > maxHeapSize) { + return false; + } + // Loop through potential heap size increases. If we attempt a too eager + // reservation that fails, cut down on the attempted size and reserve a + // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + .2 / cutDown); + // ensure geometric growth + // but limit overreserving (default to capping at +96MB overgrowth at most) + overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296); + var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)); + var replacement = growMemory(newSize); + if (replacement) { + return true; + } + } + return false; +} + +function _emscripten_stack_unwind_buffer(addr, buffer, count) { + addr >>>= 0; + buffer >>>= 0; + var stack; + if (UNWIND_CACHE.last_addr == addr) { + stack = UNWIND_CACHE.last_stack; + } else { + stack = jsStackTrace().split("\n"); + if (stack[0] == "Error") { + stack.shift(); + } + saveInUnwindCache(stack); + } + var offset = 3; + while (stack[offset] && convertFrameToPC(stack[offset]) != addr) { + ++offset; + } + for (var i = 0; i < count && stack[i + offset]; ++i) { + HEAP32[(((buffer) + (i * 4)) >>> 2) >>> 0] = convertFrameToPC(stack[i + offset]); + } + return i; +} + +var GLctx; + +var webgl_enable_ANGLE_instanced_arrays = ctx => { + // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension("ANGLE_instanced_arrays"); + // Because this extension is a core function in WebGL 2, assign the extension entry points in place of + // where the core functions will reside in WebGL 2. This way the calling code can call these without + // having to dynamically branch depending if running against WebGL 1 or WebGL 2. + if (ext) { + ctx["vertexAttribDivisor"] = (index, divisor) => ext["vertexAttribDivisorANGLE"](index, divisor); + ctx["drawArraysInstanced"] = (mode, first, count, primcount) => ext["drawArraysInstancedANGLE"](mode, first, count, primcount); + ctx["drawElementsInstanced"] = (mode, count, type, indices, primcount) => ext["drawElementsInstancedANGLE"](mode, count, type, indices, primcount); + return 1; + } +}; + +var webgl_enable_OES_vertex_array_object = ctx => { + // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension("OES_vertex_array_object"); + if (ext) { + ctx["createVertexArray"] = () => ext["createVertexArrayOES"](); + ctx["deleteVertexArray"] = vao => ext["deleteVertexArrayOES"](vao); + ctx["bindVertexArray"] = vao => ext["bindVertexArrayOES"](vao); + ctx["isVertexArray"] = vao => ext["isVertexArrayOES"](vao); + return 1; + } +}; + +var webgl_enable_WEBGL_draw_buffers = ctx => { + // Extension available in WebGL 1 from Firefox 28 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension("WEBGL_draw_buffers"); + if (ext) { + ctx["drawBuffers"] = (n, bufs) => ext["drawBuffersWEBGL"](n, bufs); + return 1; + } +}; + +var webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance = ctx => // Closure is expected to be allowed to minify the '.dibvbi' property, so not accessing it quoted. +!!(ctx.dibvbi = ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance")); + +var webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance = ctx => !!(ctx.mdibvbi = ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance")); + +var webgl_enable_EXT_polygon_offset_clamp = ctx => !!(ctx.extPolygonOffsetClamp = ctx.getExtension("EXT_polygon_offset_clamp")); + +var webgl_enable_EXT_clip_control = ctx => !!(ctx.extClipControl = ctx.getExtension("EXT_clip_control")); + +var webgl_enable_WEBGL_polygon_mode = ctx => !!(ctx.webglPolygonMode = ctx.getExtension("WEBGL_polygon_mode")); + +var webgl_enable_WEBGL_multi_draw = ctx => // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted. +!!(ctx.multiDrawWebgl = ctx.getExtension("WEBGL_multi_draw")); + +var getEmscriptenSupportedExtensions = ctx => { + // Restrict the list of advertised extensions to those that we actually + // support. + var supportedExtensions = [ // WebGL 1 extensions + "ANGLE_instanced_arrays", "EXT_blend_minmax", "EXT_disjoint_timer_query", "EXT_frag_depth", "EXT_shader_texture_lod", "EXT_sRGB", "OES_element_index_uint", "OES_fbo_render_mipmap", "OES_standard_derivatives", "OES_texture_float", "OES_texture_half_float", "OES_texture_half_float_linear", "OES_vertex_array_object", "WEBGL_color_buffer_float", "WEBGL_depth_texture", "WEBGL_draw_buffers", // WebGL 2 extensions + "EXT_color_buffer_float", "EXT_conservative_depth", "EXT_disjoint_timer_query_webgl2", "EXT_texture_norm16", "NV_shader_noperspective_interpolation", "WEBGL_clip_cull_distance", // WebGL 1 and WebGL 2 extensions + "EXT_clip_control", "EXT_color_buffer_half_float", "EXT_depth_clamp", "EXT_float_blend", "EXT_polygon_offset_clamp", "EXT_texture_compression_bptc", "EXT_texture_compression_rgtc", "EXT_texture_filter_anisotropic", "KHR_parallel_shader_compile", "OES_texture_float_linear", "WEBGL_blend_func_extended", "WEBGL_compressed_texture_astc", "WEBGL_compressed_texture_etc", "WEBGL_compressed_texture_etc1", "WEBGL_compressed_texture_s3tc", "WEBGL_compressed_texture_s3tc_srgb", "WEBGL_debug_renderer_info", "WEBGL_debug_shaders", "WEBGL_lose_context", "WEBGL_multi_draw", "WEBGL_polygon_mode" ]; + // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. + return (ctx.getSupportedExtensions() || []).filter(ext => supportedExtensions.includes(ext)); +}; + +var registerPreMainLoop = f => { + // Does nothing unless $MainLoop is included/used. + typeof MainLoop != "undefined" && MainLoop.preMainLoop.push(f); +}; + +var GL = { + counter: 1, + buffers: [], + mappedBuffers: {}, + programs: [], + framebuffers: [], + renderbuffers: [], + textures: [], + shaders: [], + vaos: [], + contexts: [], + offscreenCanvases: {}, + queries: [], + samplers: [], + transformFeedbacks: [], + syncs: [], + byteSizeByTypeRoot: 5120, + byteSizeByType: [ 1, 1, 2, 2, 4, 4, 4, 2, 3, 4, 8 ], + stringCache: {}, + stringiCache: {}, + unpackAlignment: 4, + unpackRowLength: 0, + recordError: errorCode => { + if (!GL.lastError) { + GL.lastError = errorCode; + } + }, + getNewId: table => { + var ret = GL.counter++; + for (var i = table.length; i < ret; i++) { + table[i] = null; + } + // Skip over any non-null elements that might have been created by + // glBindBuffer. + while (table[ret]) { + ret = GL.counter++; + } + return ret; + }, + genObject: (n, buffers, createFunction, objectTable) => { + for (var i = 0; i < n; i++) { + var buffer = GLctx[createFunction](); + var id = buffer && GL.getNewId(objectTable); + if (buffer) { + buffer.name = id; + objectTable[id] = buffer; + } else { + GL.recordError(1282); + } + HEAP32[(((buffers) + (i * 4)) >>> 2) >>> 0] = id; + } + }, + MAX_TEMP_BUFFER_SIZE: 2097152, + numTempVertexBuffersPerSize: 64, + log2ceilLookup: i => 32 - Math.clz32(i === 0 ? 0 : i - 1), + generateTempBuffers: (quads, context) => { + var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE); + context.tempVertexBufferCounters1 = []; + context.tempVertexBufferCounters2 = []; + context.tempVertexBufferCounters1.length = context.tempVertexBufferCounters2.length = largestIndex + 1; + context.tempVertexBuffers1 = []; + context.tempVertexBuffers2 = []; + context.tempVertexBuffers1.length = context.tempVertexBuffers2.length = largestIndex + 1; + context.tempIndexBuffers = []; + context.tempIndexBuffers.length = largestIndex + 1; + for (var i = 0; i <= largestIndex; ++i) { + context.tempIndexBuffers[i] = null; + // Created on-demand + context.tempVertexBufferCounters1[i] = context.tempVertexBufferCounters2[i] = 0; + var ringbufferLength = GL.numTempVertexBuffersPerSize; + context.tempVertexBuffers1[i] = []; + context.tempVertexBuffers2[i] = []; + var ringbuffer1 = context.tempVertexBuffers1[i]; + var ringbuffer2 = context.tempVertexBuffers2[i]; + ringbuffer1.length = ringbuffer2.length = ringbufferLength; + for (var j = 0; j < ringbufferLength; ++j) { + ringbuffer1[j] = ringbuffer2[j] = null; + } + } + if (quads) { + // GL_QUAD indexes can be precalculated + context.tempQuadIndexBuffer = GLctx.createBuffer(); + context.GLctx.bindBuffer(34963, context.tempQuadIndexBuffer); + var numIndexes = GL.MAX_TEMP_BUFFER_SIZE >> 1; + var quadIndexes = new Uint16Array(numIndexes); + var i = 0, v = 0; + while (1) { + quadIndexes[i++] = v; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 1; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 2; + if (i >= numIndexes) break; + quadIndexes[i++] = v; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 2; + if (i >= numIndexes) break; + quadIndexes[i++] = v + 3; + if (i >= numIndexes) break; + v += 4; + } + context.GLctx.bufferData(34963, quadIndexes, 35044); + context.GLctx.bindBuffer(34963, null); + } + }, + getTempVertexBuffer: sizeBytes => { + var idx = GL.log2ceilLookup(sizeBytes); + var ringbuffer = GL.currentContext.tempVertexBuffers1[idx]; + var nextFreeBufferIndex = GL.currentContext.tempVertexBufferCounters1[idx]; + GL.currentContext.tempVertexBufferCounters1[idx] = (GL.currentContext.tempVertexBufferCounters1[idx] + 1) & (GL.numTempVertexBuffersPerSize - 1); + var vbo = ringbuffer[nextFreeBufferIndex]; + if (vbo) { + return vbo; + } + var prevVBO = GLctx.getParameter(34964); + ringbuffer[nextFreeBufferIndex] = GLctx.createBuffer(); + GLctx.bindBuffer(34962, ringbuffer[nextFreeBufferIndex]); + GLctx.bufferData(34962, 1 << idx, 35048); + GLctx.bindBuffer(34962, prevVBO); + return ringbuffer[nextFreeBufferIndex]; + }, + getTempIndexBuffer: sizeBytes => { + var idx = GL.log2ceilLookup(sizeBytes); + var ibo = GL.currentContext.tempIndexBuffers[idx]; + if (ibo) { + return ibo; + } + var prevIBO = GLctx.getParameter(34965); + GL.currentContext.tempIndexBuffers[idx] = GLctx.createBuffer(); + GLctx.bindBuffer(34963, GL.currentContext.tempIndexBuffers[idx]); + GLctx.bufferData(34963, 1 << idx, 35048); + GLctx.bindBuffer(34963, prevIBO); + return GL.currentContext.tempIndexBuffers[idx]; + }, + newRenderingFrameStarted: () => { + if (!GL.currentContext) { + return; + } + var vb = GL.currentContext.tempVertexBuffers1; + GL.currentContext.tempVertexBuffers1 = GL.currentContext.tempVertexBuffers2; + GL.currentContext.tempVertexBuffers2 = vb; + vb = GL.currentContext.tempVertexBufferCounters1; + GL.currentContext.tempVertexBufferCounters1 = GL.currentContext.tempVertexBufferCounters2; + GL.currentContext.tempVertexBufferCounters2 = vb; + var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE); + for (var i = 0; i <= largestIndex; ++i) { + GL.currentContext.tempVertexBufferCounters1[i] = 0; + } + }, + getSource: (shader, count, string, length) => { + var source = ""; + for (var i = 0; i < count; ++i) { + var len = length ? HEAPU32[(((length) + (i * 4)) >>> 2) >>> 0] : undefined; + source += UTF8ToString(HEAPU32[(((string) + (i * 4)) >>> 2) >>> 0], len); + } + return source; + }, + calcBufLength: (size, type, stride, count) => { + if (stride > 0) { + return count * stride; + } + var typeSize = GL.byteSizeByType[type - GL.byteSizeByTypeRoot]; + return size * typeSize * count; + }, + usedTempBuffers: [], + preDrawHandleClientVertexAttribBindings: count => { + GL.resetBufferBinding = false; + // TODO: initial pass to detect ranges we need to upload, might not need + // an upload per attrib + for (var i = 0; i < GL.currentContext.maxVertexAttribs; ++i) { + var cb = GL.currentContext.clientBuffers[i]; + if (!cb.clientside || !cb.enabled) continue; + GL.resetBufferBinding = true; + var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count); + var buf = GL.getTempVertexBuffer(size); + GLctx.bindBuffer(34962, buf); + GLctx.bufferSubData(34962, 0, HEAPU8.subarray(cb.ptr >>> 0, cb.ptr + size >>> 0)); + cb.vertexAttribPointerAdaptor.call(GLctx, i, cb.size, cb.type, cb.normalized, cb.stride, 0); + } + }, + postDrawHandleClientVertexAttribBindings: () => { + if (GL.resetBufferBinding) { + GLctx.bindBuffer(34962, GL.buffers[GLctx.currentArrayBufferBinding]); + } + }, + createContext: (/** @type {HTMLCanvasElement} */ canvas, webGLContextAttributes) => { + // BUG: Workaround Safari WebGL issue: After successfully acquiring WebGL + // context on a canvas, calling .getContext() will always return that + // context independent of which 'webgl' or 'webgl2' + // context version was passed. See: + // https://webkit.org/b/222758 + // and: + // https://github.com/emscripten-core/emscripten/issues/13295. + // TODO: Once the bug is fixed and shipped in Safari, adjust the Safari + // version field in above check. + if (!canvas.getContextSafariWebGL2Fixed) { + canvas.getContextSafariWebGL2Fixed = canvas.getContext; + /** @type {function(this:HTMLCanvasElement, string, (Object|null)=): (Object|null)} */ function fixedGetContext(ver, attrs) { + var gl = canvas.getContextSafariWebGL2Fixed(ver, attrs); + return ((ver == "webgl") == (gl instanceof WebGLRenderingContext)) ? gl : null; + } + canvas.getContext = fixedGetContext; + } + var ctx = (webGLContextAttributes.majorVersion > 1) ? canvas.getContext("webgl2", webGLContextAttributes) : canvas.getContext("webgl", webGLContextAttributes); + if (!ctx) return 0; + var handle = GL.registerContext(ctx, webGLContextAttributes); + return handle; + }, + registerContext: (ctx, webGLContextAttributes) => { + // without pthreads a context is just an integer ID + var handle = GL.getNewId(GL.contexts); + var context = { + handle, + attributes: webGLContextAttributes, + version: webGLContextAttributes.majorVersion, + GLctx: ctx + }; + // Store the created context object so that we can access the context + // given a canvas without having to pass the parameters again. + if (ctx.canvas) ctx.canvas.GLctxObject = context; + GL.contexts[handle] = context; + if (typeof webGLContextAttributes.enableExtensionsByDefault == "undefined" || webGLContextAttributes.enableExtensionsByDefault) { + GL.initExtensions(context); + } + context.maxVertexAttribs = context.GLctx.getParameter(34921); + context.clientBuffers = []; + for (var i = 0; i < context.maxVertexAttribs; i++) { + context.clientBuffers[i] = { + enabled: false, + clientside: false, + size: 0, + type: 0, + normalized: 0, + stride: 0, + ptr: 0, + vertexAttribPointerAdaptor: null + }; + } + GL.generateTempBuffers(false, context); + return handle; + }, + makeContextCurrent: contextHandle => { + // Active Emscripten GL layer context object. + GL.currentContext = GL.contexts[contextHandle]; + // Active WebGL context object. + Module["ctx"] = GLctx = GL.currentContext?.GLctx; + return !(contextHandle && !GLctx); + }, + getContext: contextHandle => GL.contexts[contextHandle], + deleteContext: contextHandle => { + if (GL.currentContext === GL.contexts[contextHandle]) { + GL.currentContext = null; + } + if (typeof JSEvents == "object") { + // Release all JS event handlers on the DOM element that the GL context is + // associated with since the context is now deleted. + JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); + } + // Make sure the canvas object no longer refers to the context object so + // there are no GC surprises. + if (GL.contexts[contextHandle]?.GLctx.canvas) { + GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; + } + GL.contexts[contextHandle] = null; + }, + initExtensions: context => { + // If this function is called without a specific context object, init the + // extensions of the currently active context. + context ||= GL.currentContext; + if (context.initExtensionsDone) return; + context.initExtensionsDone = true; + var GLctx = context.GLctx; + // Detect the presence of a few extensions manually, since the GL interop + // layer itself will need to know if they exist. + // Extensions that are available in both WebGL 1 and WebGL 2 + webgl_enable_WEBGL_multi_draw(GLctx); + webgl_enable_EXT_polygon_offset_clamp(GLctx); + webgl_enable_EXT_clip_control(GLctx); + webgl_enable_WEBGL_polygon_mode(GLctx); + // Extensions that are only available in WebGL 1 (the calls will be no-ops + // if called on a WebGL 2 context active) + webgl_enable_ANGLE_instanced_arrays(GLctx); + webgl_enable_OES_vertex_array_object(GLctx); + webgl_enable_WEBGL_draw_buffers(GLctx); + // Extensions that are available from WebGL >= 2 (no-op if called on a WebGL 1 context active) + webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx); + webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx); + // On WebGL 2, EXT_disjoint_timer_query is replaced with an alternative + // that's based on core APIs, and exposes only the queryCounterEXT() + // entrypoint. + if (context.version >= 2) { + GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query_webgl2"); + } + // However, Firefox exposes the WebGL 1 version on WebGL 2 as well and + // thus we look for the WebGL 1 version again if the WebGL 2 version + // isn't present. https://bugzil.la/1328882 + if (context.version < 2 || !GLctx.disjointTimerQueryExt) { + GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query"); + } + for (var ext of getEmscriptenSupportedExtensions(GLctx)) { + // WEBGL_lose_context, WEBGL_debug_renderer_info and WEBGL_debug_shaders + // are not enabled by default. + if (!ext.includes("lose_context") && !ext.includes("debug")) { + // Call .getExtension() to enable that extension permanently. + GLctx.getExtension(ext); + } + } + } +}; + +var webglPowerPreferences = [ "default", "low-power", "high-performance" ]; + +/** @type {Object} */ var specialHTMLTargets = [ 0, globalThis.document ?? 0, globalThis.window ?? 0 ]; + +var findEventTarget = target => { + // The sensible "default" target varies between events, but use window as the default + // since DOM events mostly can default to that. Specific callback registrations + // override their own defaults. + if (!target) return window; + if (typeof target == "number") target = specialHTMLTargets[target] || UTF8ToString(target); + if (target === "#window") return window; else if (target === "#document") return document; else if (target === "#screen") return screen; else if (target === "#canvas") return Module["canvas"]; else if (typeof target == "string") return globalThis.document?.getElementById(target); + return target; +}; + +var findCanvasEventTarget = target => { + if (typeof target == "number") target = UTF8ToString(target); + if (!target || target === "#canvas") { + if (typeof GL != "undefined" && GL.offscreenCanvases["canvas"]) return GL.offscreenCanvases["canvas"]; + // TODO: Remove this line, target '#canvas' should refer only to Module['canvas'], not to GL.offscreenCanvases['canvas'] - but need stricter tests to be able to remove this line. + return Module["canvas"]; + } + if (typeof GL != "undefined" && GL.offscreenCanvases[target]) return GL.offscreenCanvases[target]; + return findEventTarget(target); +}; + +function _emscripten_webgl_do_create_context(target, attributes) { + target >>>= 0; + attributes >>>= 0; + var attr32 = ((attributes) >>> 2); + var powerPreference = HEAP32[attr32 + (8 >> 2) >>> 0]; + var contextAttributes = { + "alpha": !!HEAP8[attributes + 0 >>> 0], + "depth": !!HEAP8[attributes + 1 >>> 0], + "stencil": !!HEAP8[attributes + 2 >>> 0], + "antialias": !!HEAP8[attributes + 3 >>> 0], + "premultipliedAlpha": !!HEAP8[attributes + 4 >>> 0], + "preserveDrawingBuffer": !!HEAP8[attributes + 5 >>> 0], + "powerPreference": webglPowerPreferences[powerPreference], + "failIfMajorPerformanceCaveat": !!HEAP8[attributes + 12 >>> 0], + // The following are not predefined WebGL context attributes in the WebGL specification, so the property names can be minified by Closure. + majorVersion: HEAP32[attr32 + (16 >> 2) >>> 0], + minorVersion: HEAP32[attr32 + (20 >> 2) >>> 0], + enableExtensionsByDefault: HEAP8[attributes + 24 >>> 0], + explicitSwapControl: HEAP8[attributes + 25 >>> 0], + proxyContextToMainThread: HEAP32[attr32 + (28 >> 2) >>> 0], + renderViaOffscreenBackBuffer: HEAP8[attributes + 32 >>> 0] + }; + var canvas = findCanvasEventTarget(target); + if (!canvas) { + return 0; + } + if (contextAttributes.explicitSwapControl) { + return 0; + } + var contextHandle = GL.createContext(canvas, contextAttributes); + return contextHandle; +} + +var _emscripten_webgl_create_context = _emscripten_webgl_do_create_context; + +function _emscripten_webgl_destroy_context(contextHandle) { + contextHandle >>>= 0; + if (GL.currentContext == contextHandle) GL.currentContext = 0; + GL.deleteContext(contextHandle); +} + +function _emscripten_webgl_get_context_attributes(c, a) { + c >>>= 0; + a >>>= 0; + if (!a) return -5; + c = GL.contexts[c]; + if (!c) return -3; + var t = c.GLctx?.getContextAttributes(); + if (!t) return -3; + HEAP8[a >>> 0] = t.alpha; + HEAP8[(a) + (1) >>> 0] = t.depth; + HEAP8[(a) + (2) >>> 0] = t.stencil; + HEAP8[(a) + (3) >>> 0] = t.antialias; + HEAP8[(a) + (4) >>> 0] = t.premultipliedAlpha; + HEAP8[(a) + (5) >>> 0] = t.preserveDrawingBuffer; + var power = t["powerPreference"] && webglPowerPreferences.indexOf(t["powerPreference"]); + HEAP32[(((a) + (8)) >>> 2) >>> 0] = power; + HEAP8[(a) + (12) >>> 0] = t.failIfMajorPerformanceCaveat; + HEAP32[(((a) + (16)) >>> 2) >>> 0] = c.version; + HEAP32[(((a) + (20)) >>> 2) >>> 0] = 0; + HEAP8[(a) + (24) >>> 0] = c.attributes.enableExtensionsByDefault; + return 0; +} + +function _emscripten_webgl_do_get_current_context() { + return GL.currentContext ? GL.currentContext.handle : 0; +} + +var _emscripten_webgl_get_current_context = _emscripten_webgl_do_get_current_context; + +function _emscripten_webgl_make_context_current(contextHandle) { + contextHandle >>>= 0; + var success = GL.makeContextCurrent(contextHandle); + return success ? 0 : -5; +} + +var stackAlloc = sz => __emscripten_stack_alloc(sz); + +var stringToUTF8OnStack = str => { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8(str, ret, size); + return ret; +}; + +var writeI53ToI64 = (ptr, num) => { + HEAPU32[((ptr) >>> 2) >>> 0] = num; + var lower = HEAPU32[((ptr) >>> 2) >>> 0]; + HEAPU32[(((ptr) + (4)) >>> 2) >>> 0] = (num - lower) / 4294967296; +}; + +var readI53FromI64 = ptr => HEAPU32[((ptr) >>> 2) >>> 0] + HEAP32[(((ptr) + (4)) >>> 2) >>> 0] * 4294967296; + +var WebGPU = { + Internals: { + jsObjects: [], + jsObjectInsert: (ptr, jsObject) => { + ptr >>>= 0; + WebGPU.Internals.jsObjects[ptr] = jsObject; + }, + bufferOnUnmaps: [], + futures: [], + futureInsert: (futureId, promise) => { + WebGPU.Internals.futures[futureId] = new Promise(resolve => promise.finally(() => resolve(futureId))); + } + }, + getJsObject: ptr => { + if (!ptr) return undefined; + ptr >>>= 0; + return WebGPU.Internals.jsObjects[ptr]; + }, + importJsAdapter: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateAdapter(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsBindGroup: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateBindGroup(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsBindGroupLayout: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateBindGroupLayout(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsBuffer: (buffer, parentPtr = 0) => { + // At the moment, we do not allow importing pending buffers. + assert(buffer.mapState === "unmapped"); + var bufferPtr = _emwgpuImportBuffer(parentPtr); + WebGPU.Internals.jsObjectInsert(bufferPtr, buffer); + return bufferPtr; + }, + importJsCommandBuffer: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateCommandBuffer(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsCommandEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateCommandEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsComputePassEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateComputePassEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsComputePipeline: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateComputePipeline(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsDevice: (device, parentPtr = 0) => { + var queuePtr = _emwgpuCreateQueue(parentPtr); + var devicePtr = _emwgpuCreateDevice(parentPtr, queuePtr); + WebGPU.Internals.jsObjectInsert(queuePtr, device.queue); + WebGPU.Internals.jsObjectInsert(devicePtr, device); + return devicePtr; + }, + importJsExternalTexture: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateExternalTexture(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsPipelineLayout: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreatePipelineLayout(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsQuerySet: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateQuerySet(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsQueue: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateQueue(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderBundle: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderBundle(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderBundleEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderBundleEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderPassEncoder: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderPassEncoder(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsRenderPipeline: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateRenderPipeline(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsSampler: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateSampler(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsShaderModule: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateShaderModule(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsSurface: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateSurface(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsTexture: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateTexture(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + importJsTextureView: (obj, parentPtr = 0) => { + var ptr = _emwgpuCreateTextureView(parentPtr); + WebGPU.Internals.jsObjects[ptr] = obj; + return ptr; + }, + errorCallback: (callback, type, message, userdata) => { + var sp = stackSave(); + var messagePtr = stringToUTF8OnStack(message); + ((a1, a2, a3) => dynCall_viii(callback, a1, a2, a3))(type, messagePtr, userdata); + stackRestore(sp); + }, + iterateExtensions: (root, handlers) => { + for (var ptr = HEAPU32[((root) >>> 2) >>> 0]; ptr; ptr = HEAPU32[((ptr) >>> 2) >>> 0]) { + var sType = HEAP32[(((ptr) + (4)) >>> 2) >>> 0]; + // This will crash if there's no handler indicating either a bogus + // sType, or one we haven't implemented yet. + var handler = handlers[sType](ptr); + } + }, + setStringView: (ptr, data, length) => { + HEAPU32[((ptr) >>> 2) >>> 0] = data; + HEAPU32[(((ptr) + (4)) >>> 2) >>> 0] = length; + }, + makeStringFromStringView: stringViewPtr => { + var ptr = HEAPU32[((stringViewPtr) >>> 2) >>> 0]; + var length = HEAPU32[(((stringViewPtr) + (4)) >>> 2) >>> 0]; + // UTF8ToString stops at the first null terminator character in the + // string regardless of the length. + return UTF8ToString(ptr, length); + }, + makeStringFromOptionalStringView: stringViewPtr => { + var ptr = HEAPU32[((stringViewPtr) >>> 2) >>> 0]; + var length = HEAPU32[(((stringViewPtr) + (4)) >>> 2) >>> 0]; + // If we don't have a valid string pointer, just return undefined when + // optional. + if (!ptr) { + if (length === 0) { + return ""; + } + return undefined; + } + // UTF8ToString stops at the first null terminator character in the + // string regardless of the length. + return UTF8ToString(ptr, length); + }, + makeColor: ptr => ({ + "r": HEAPF64[((ptr) >>> 3) >>> 0], + "g": HEAPF64[(((ptr) + (8)) >>> 3) >>> 0], + "b": HEAPF64[(((ptr) + (16)) >>> 3) >>> 0], + "a": HEAPF64[(((ptr) + (24)) >>> 3) >>> 0] + }), + makeExtent3D: ptr => ({ + "width": HEAPU32[((ptr) >>> 2) >>> 0], + "height": HEAPU32[(((ptr) + (4)) >>> 2) >>> 0], + "depthOrArrayLayers": HEAPU32[(((ptr) + (8)) >>> 2) >>> 0] + }), + makeOrigin3D: ptr => ({ + "x": HEAPU32[((ptr) >>> 2) >>> 0], + "y": HEAPU32[(((ptr) + (4)) >>> 2) >>> 0], + "z": HEAPU32[(((ptr) + (8)) >>> 2) >>> 0] + }), + makeTexelCopyTextureInfo: ptr => ({ + "texture": WebGPU.getJsObject(HEAPU32[((ptr) >>> 2) >>> 0]), + "mipLevel": HEAPU32[(((ptr) + (4)) >>> 2) >>> 0], + "origin": WebGPU.makeOrigin3D(ptr + 8), + "aspect": WebGPU.TextureAspect[HEAP32[(((ptr) + (20)) >>> 2) >>> 0]] + }), + makeTexelCopyBufferLayout: ptr => { + var bytesPerRow = HEAPU32[(((ptr) + (8)) >>> 2) >>> 0]; + var rowsPerImage = HEAPU32[(((ptr) + (12)) >>> 2) >>> 0]; + return { + "offset": readI53FromI64(ptr), + "bytesPerRow": bytesPerRow === 4294967295 ? undefined : bytesPerRow, + "rowsPerImage": rowsPerImage === 4294967295 ? undefined : rowsPerImage + }; + }, + makeTexelCopyBufferInfo: ptr => { + var layoutPtr = ptr + 0; + var bufferCopyView = WebGPU.makeTexelCopyBufferLayout(layoutPtr); + bufferCopyView["buffer"] = WebGPU.getJsObject(HEAPU32[(((ptr) + (16)) >>> 2) >>> 0]); + return bufferCopyView; + }, + makePassTimestampWrites: ptr => { + if (ptr === 0) return undefined; + return { + "querySet": WebGPU.getJsObject(HEAPU32[(((ptr) + (4)) >>> 2) >>> 0]), + "beginningOfPassWriteIndex": HEAPU32[(((ptr) + (8)) >>> 2) >>> 0], + "endOfPassWriteIndex": HEAPU32[(((ptr) + (12)) >>> 2) >>> 0] + }; + }, + makePipelineConstants: (constantCount, constantsPtr) => { + if (!constantCount) return; + var constants = {}; + for (var i = 0; i < constantCount; ++i) { + var entryPtr = constantsPtr + 24 * i; + var key = WebGPU.makeStringFromStringView(entryPtr + 4); + constants[key] = HEAPF64[(((entryPtr) + (16)) >>> 3) >>> 0]; + } + return constants; + }, + makePipelineLayout: layoutPtr => { + if (!layoutPtr) return "auto"; + return WebGPU.getJsObject(layoutPtr); + }, + makeComputeState: ptr => { + if (!ptr) return undefined; + var desc = { + "module": WebGPU.getJsObject(HEAPU32[(((ptr) + (4)) >>> 2) >>> 0]), + "constants": WebGPU.makePipelineConstants(HEAPU32[(((ptr) + (16)) >>> 2) >>> 0], HEAPU32[(((ptr) + (20)) >>> 2) >>> 0]), + "entryPoint": WebGPU.makeStringFromOptionalStringView(ptr + 8) + }; + return desc; + }, + makeComputePipelineDesc: descriptor => { + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "layout": WebGPU.makePipelineLayout(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]), + "compute": WebGPU.makeComputeState(descriptor + 16) + }; + return desc; + }, + makeRenderPipelineDesc: descriptor => { + function makePrimitiveState(psPtr) { + if (!psPtr) return undefined; + return { + "topology": WebGPU.PrimitiveTopology[HEAP32[(((psPtr) + (4)) >>> 2) >>> 0]], + "stripIndexFormat": WebGPU.IndexFormat[HEAP32[(((psPtr) + (8)) >>> 2) >>> 0]], + "frontFace": WebGPU.FrontFace[HEAP32[(((psPtr) + (12)) >>> 2) >>> 0]], + "cullMode": WebGPU.CullMode[HEAP32[(((psPtr) + (16)) >>> 2) >>> 0]], + "unclippedDepth": !!(HEAPU32[(((psPtr) + (20)) >>> 2) >>> 0]) + }; + } + function makeBlendComponent(bdPtr) { + if (!bdPtr) return undefined; + return { + "operation": WebGPU.BlendOperation[HEAP32[((bdPtr) >>> 2) >>> 0]], + "srcFactor": WebGPU.BlendFactor[HEAP32[(((bdPtr) + (4)) >>> 2) >>> 0]], + "dstFactor": WebGPU.BlendFactor[HEAP32[(((bdPtr) + (8)) >>> 2) >>> 0]] + }; + } + function makeBlendState(bsPtr) { + if (!bsPtr) return undefined; + return { + "alpha": makeBlendComponent(bsPtr + 12), + "color": makeBlendComponent(bsPtr + 0) + }; + } + function makeColorState(csPtr) { + var format = WebGPU.TextureFormat[HEAP32[(((csPtr) + (4)) >>> 2) >>> 0]]; + return format ? { + "format": format, + "blend": makeBlendState(HEAPU32[(((csPtr) + (8)) >>> 2) >>> 0]), + "writeMask": HEAPU32[(((csPtr) + (16)) >>> 2) >>> 0] + } : undefined; + } + function makeColorStates(count, csArrayPtr) { + var states = []; + for (var i = 0; i < count; ++i) { + states.push(makeColorState(csArrayPtr + 24 * i)); + } + return states; + } + function makeStencilStateFace(ssfPtr) { + return { + "compare": WebGPU.CompareFunction[HEAP32[((ssfPtr) >>> 2) >>> 0]], + "failOp": WebGPU.StencilOperation[HEAP32[(((ssfPtr) + (4)) >>> 2) >>> 0]], + "depthFailOp": WebGPU.StencilOperation[HEAP32[(((ssfPtr) + (8)) >>> 2) >>> 0]], + "passOp": WebGPU.StencilOperation[HEAP32[(((ssfPtr) + (12)) >>> 2) >>> 0]] + }; + } + function makeDepthStencilState(dssPtr) { + if (!dssPtr) return undefined; + return { + "format": WebGPU.TextureFormat[HEAP32[(((dssPtr) + (4)) >>> 2) >>> 0]], + "depthWriteEnabled": !!(HEAPU32[(((dssPtr) + (8)) >>> 2) >>> 0]), + "depthCompare": WebGPU.CompareFunction[HEAP32[(((dssPtr) + (12)) >>> 2) >>> 0]], + "stencilFront": makeStencilStateFace(dssPtr + 16), + "stencilBack": makeStencilStateFace(dssPtr + 32), + "stencilReadMask": HEAPU32[(((dssPtr) + (48)) >>> 2) >>> 0], + "stencilWriteMask": HEAPU32[(((dssPtr) + (52)) >>> 2) >>> 0], + "depthBias": HEAP32[(((dssPtr) + (56)) >>> 2) >>> 0], + "depthBiasSlopeScale": HEAPF32[(((dssPtr) + (60)) >>> 2) >>> 0], + "depthBiasClamp": HEAPF32[(((dssPtr) + (64)) >>> 2) >>> 0] + }; + } + function makeVertexAttribute(vaPtr) { + return { + "format": WebGPU.VertexFormat[HEAP32[(((vaPtr) + (4)) >>> 2) >>> 0]], + "offset": readI53FromI64((vaPtr) + (8)), + "shaderLocation": HEAPU32[(((vaPtr) + (16)) >>> 2) >>> 0] + }; + } + function makeVertexAttributes(count, vaArrayPtr) { + var vas = []; + for (var i = 0; i < count; ++i) { + vas.push(makeVertexAttribute(vaArrayPtr + i * 24)); + } + return vas; + } + function makeVertexBuffer(vbPtr) { + if (!vbPtr) return undefined; + var stepMode = WebGPU.VertexStepMode[HEAP32[(((vbPtr) + (4)) >>> 2) >>> 0]]; + var attributeCount = HEAPU32[(((vbPtr) + (16)) >>> 2) >>> 0]; + if (!stepMode && !attributeCount) { + return null; + } + return { + "arrayStride": readI53FromI64((vbPtr) + (8)), + "stepMode": stepMode, + "attributes": makeVertexAttributes(attributeCount, HEAPU32[(((vbPtr) + (20)) >>> 2) >>> 0]) + }; + } + function makeVertexBuffers(count, vbArrayPtr) { + if (!count) return undefined; + var vbs = []; + for (var i = 0; i < count; ++i) { + vbs.push(makeVertexBuffer(vbArrayPtr + i * 24)); + } + return vbs; + } + function makeVertexState(viPtr) { + if (!viPtr) return undefined; + var desc = { + "module": WebGPU.getJsObject(HEAPU32[(((viPtr) + (4)) >>> 2) >>> 0]), + "constants": WebGPU.makePipelineConstants(HEAPU32[(((viPtr) + (16)) >>> 2) >>> 0], HEAPU32[(((viPtr) + (20)) >>> 2) >>> 0]), + "buffers": makeVertexBuffers(HEAPU32[(((viPtr) + (24)) >>> 2) >>> 0], HEAPU32[(((viPtr) + (28)) >>> 2) >>> 0]), + "entryPoint": WebGPU.makeStringFromOptionalStringView(viPtr + 8) + }; + return desc; + } + function makeMultisampleState(msPtr) { + if (!msPtr) return undefined; + return { + "count": HEAPU32[(((msPtr) + (4)) >>> 2) >>> 0], + "mask": HEAPU32[(((msPtr) + (8)) >>> 2) >>> 0], + "alphaToCoverageEnabled": !!(HEAPU32[(((msPtr) + (12)) >>> 2) >>> 0]) + }; + } + function makeFragmentState(fsPtr) { + if (!fsPtr) return undefined; + var desc = { + "module": WebGPU.getJsObject(HEAPU32[(((fsPtr) + (4)) >>> 2) >>> 0]), + "constants": WebGPU.makePipelineConstants(HEAPU32[(((fsPtr) + (16)) >>> 2) >>> 0], HEAPU32[(((fsPtr) + (20)) >>> 2) >>> 0]), + "targets": makeColorStates(HEAPU32[(((fsPtr) + (24)) >>> 2) >>> 0], HEAPU32[(((fsPtr) + (28)) >>> 2) >>> 0]), + "entryPoint": WebGPU.makeStringFromOptionalStringView(fsPtr + 8) + }; + return desc; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "layout": WebGPU.makePipelineLayout(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]), + "vertex": makeVertexState(descriptor + 16), + "primitive": makePrimitiveState(descriptor + 48), + "depthStencil": makeDepthStencilState(HEAPU32[(((descriptor) + (72)) >>> 2) >>> 0]), + "multisample": makeMultisampleState(descriptor + 76), + "fragment": makeFragmentState(HEAPU32[(((descriptor) + (92)) >>> 2) >>> 0]) + }; + return desc; + }, + fillLimitStruct: (limits, limitsOutPtr) => { + var nextInChainPtr = HEAPU32[((limitsOutPtr) >>> 2) >>> 0]; + function setLimitValueU32(name, basePtr, limitOffset, fallbackValue = 0) { + var limitValue = limits[name] ?? fallbackValue; + HEAPU32[(((basePtr) + (limitOffset)) >>> 2) >>> 0] = limitValue; + } + function setLimitValueU64(name, basePtr, limitOffset, fallbackValue = 0) { + var limitValue = limits[name] ?? fallbackValue; + // Limits are integer-valued JS `Number`s, so they fit in 'i53'. + writeI53ToI64((basePtr) + (limitOffset), limitValue); + } + setLimitValueU32("maxTextureDimension1D", limitsOutPtr, 4); + setLimitValueU32("maxTextureDimension2D", limitsOutPtr, 8); + setLimitValueU32("maxTextureDimension3D", limitsOutPtr, 12); + setLimitValueU32("maxTextureArrayLayers", limitsOutPtr, 16); + setLimitValueU32("maxBindGroups", limitsOutPtr, 20); + setLimitValueU32("maxBindGroupsPlusVertexBuffers", limitsOutPtr, 24); + setLimitValueU32("maxBindingsPerBindGroup", limitsOutPtr, 28); + setLimitValueU32("maxDynamicUniformBuffersPerPipelineLayout", limitsOutPtr, 32); + setLimitValueU32("maxDynamicStorageBuffersPerPipelineLayout", limitsOutPtr, 36); + setLimitValueU32("maxSampledTexturesPerShaderStage", limitsOutPtr, 40); + setLimitValueU32("maxSamplersPerShaderStage", limitsOutPtr, 44); + setLimitValueU32("maxStorageBuffersPerShaderStage", limitsOutPtr, 48); + setLimitValueU32("maxStorageTexturesPerShaderStage", limitsOutPtr, 52); + setLimitValueU32("maxUniformBuffersPerShaderStage", limitsOutPtr, 56); + setLimitValueU32("minUniformBufferOffsetAlignment", limitsOutPtr, 80); + setLimitValueU32("minStorageBufferOffsetAlignment", limitsOutPtr, 84); + setLimitValueU64("maxUniformBufferBindingSize", limitsOutPtr, 64); + setLimitValueU64("maxStorageBufferBindingSize", limitsOutPtr, 72); + setLimitValueU32("maxVertexBuffers", limitsOutPtr, 88); + setLimitValueU64("maxBufferSize", limitsOutPtr, 96); + setLimitValueU32("maxVertexAttributes", limitsOutPtr, 104); + setLimitValueU32("maxVertexBufferArrayStride", limitsOutPtr, 108); + setLimitValueU32("maxInterStageShaderVariables", limitsOutPtr, 112); + setLimitValueU32("maxColorAttachments", limitsOutPtr, 116); + setLimitValueU32("maxColorAttachmentBytesPerSample", limitsOutPtr, 120); + setLimitValueU32("maxComputeWorkgroupStorageSize", limitsOutPtr, 124); + setLimitValueU32("maxComputeInvocationsPerWorkgroup", limitsOutPtr, 128); + setLimitValueU32("maxComputeWorkgroupSizeX", limitsOutPtr, 132); + setLimitValueU32("maxComputeWorkgroupSizeY", limitsOutPtr, 136); + setLimitValueU32("maxComputeWorkgroupSizeZ", limitsOutPtr, 140); + setLimitValueU32("maxComputeWorkgroupsPerDimension", limitsOutPtr, 144); + // Note this limit is new and won't be present in all browsers for a while. Fall back to 0. + setLimitValueU32("maxImmediateSize", limitsOutPtr, 148); + if (nextInChainPtr !== 0) { + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var compatibilityModeLimitsPtr = nextInChainPtr; + // Note these limits are new and won't be present in all browsers for a while. Fall back to exposing the PerShaderStage limit. + setLimitValueU32("maxStorageBuffersInVertexStage", compatibilityModeLimitsPtr, 8, limits.maxStorageBuffersPerShaderStage); + setLimitValueU32("maxStorageBuffersInFragmentStage", compatibilityModeLimitsPtr, 16, limits.maxStorageBuffersPerShaderStage); + setLimitValueU32("maxStorageTexturesInVertexStage", compatibilityModeLimitsPtr, 12, limits.maxStorageTexturesPerShaderStage); + setLimitValueU32("maxStorageTexturesInFragmentStage", compatibilityModeLimitsPtr, 20, limits.maxStorageTexturesPerShaderStage); + } + }, + fillAdapterInfoStruct: (info, infoStruct) => { + // Populate subgroup limits. + HEAPU32[(((infoStruct) + (52)) >>> 2) >>> 0] = info.subgroupMinSize; + HEAPU32[(((infoStruct) + (56)) >>> 2) >>> 0] = info.subgroupMaxSize; + // Append all the strings together to condense into a single malloc. + var strs = info.vendor + info.architecture + info.device + info.description; + var strPtr = stringToNewUTF8(strs); + var vendorLen = lengthBytesUTF8(info.vendor); + WebGPU.setStringView(infoStruct + 4, strPtr, vendorLen); + strPtr += vendorLen; + var architectureLen = lengthBytesUTF8(info.architecture); + WebGPU.setStringView(infoStruct + 12, strPtr, architectureLen); + strPtr += architectureLen; + var deviceLen = lengthBytesUTF8(info.device); + WebGPU.setStringView(infoStruct + 20, strPtr, deviceLen); + strPtr += deviceLen; + var descriptionLen = lengthBytesUTF8(info.description); + WebGPU.setStringView(infoStruct + 28, strPtr, descriptionLen); + strPtr += descriptionLen; + HEAP32[(((infoStruct) + (36)) >>> 2) >>> 0] = 2; + var adapterType = info.isFallbackAdapter ? 3 : 4; + HEAP32[(((infoStruct) + (40)) >>> 2) >>> 0] = adapterType; + HEAPU32[(((infoStruct) + (44)) >>> 2) >>> 0] = 0; + HEAPU32[(((infoStruct) + (48)) >>> 2) >>> 0] = 0; + }, + AddressMode: [ , "clamp-to-edge", "repeat", "mirror-repeat" ], + BlendFactor: [ , "zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", "src1", "one-minus-src1", "src1-alpha", "one-minus-src1-alpha" ], + BlendOperation: [ , "add", "subtract", "reverse-subtract", "min", "max" ], + BufferBindingType: [ , , "uniform", "storage", "read-only-storage" ], + BufferMapState: [ , "unmapped", "pending", "mapped" ], + CompareFunction: [ , "never", "less", "equal", "less-equal", "greater", "not-equal", "greater-equal", "always" ], + CompilationInfoRequestStatus: [ , "success", "callback-cancelled" ], + ComponentSwizzle: [ , "0", "1", "r", "g", "b", "a" ], + CompositeAlphaMode: [ , "opaque", "premultiplied", "unpremultiplied", "inherit" ], + CullMode: [ , "none", "front", "back" ], + ErrorFilter: [ , "validation", "out-of-memory", "internal" ], + FeatureLevel: [ , "compatibility", "core" ], + FeatureName: { + 1: "core-features-and-limits", + 2: "depth-clip-control", + 3: "depth32float-stencil8", + 4: "texture-compression-bc", + 5: "texture-compression-bc-sliced-3d", + 6: "texture-compression-etc2", + 7: "texture-compression-astc", + 8: "texture-compression-astc-sliced-3d", + 9: "timestamp-query", + 10: "indirect-first-instance", + 11: "shader-f16", + 12: "rg11b10ufloat-renderable", + 13: "bgra8unorm-storage", + 14: "float32-filterable", + 15: "float32-blendable", + 16: "clip-distances", + 17: "dual-source-blending", + 18: "subgroups", + 19: "texture-formats-tier1", + 20: "texture-formats-tier2", + 21: "primitive-index", + 22: "texture-component-swizzle", + 327692: "chromium-experimental-unorm16-texture-formats", + 327729: "chromium-experimental-multi-draw-indirect" + }, + FilterMode: [ , "nearest", "linear" ], + FrontFace: [ , "ccw", "cw" ], + IndexFormat: [ , "uint16", "uint32" ], + InstanceFeatureName: [ , "timed-wait-any", "shader-source-spirv", "multiple-devices-per-adapter" ], + LoadOp: [ , "load", "clear" ], + MipmapFilterMode: [ , "nearest", "linear" ], + OptionalBool: [ "false", "true" ], + PowerPreference: [ , "low-power", "high-performance" ], + PredefinedColorSpace: [ , "srgb", "display-p3" ], + PrimitiveTopology: [ , "point-list", "line-list", "line-strip", "triangle-list", "triangle-strip" ], + QueryType: [ , "occlusion", "timestamp" ], + SamplerBindingType: [ , , "filtering", "non-filtering", "comparison" ], + Status: [ , "success", "error" ], + StencilOperation: [ , "keep", "zero", "replace", "invert", "increment-clamp", "decrement-clamp", "increment-wrap", "decrement-wrap" ], + StorageTextureAccess: [ , , "write-only", "read-only", "read-write" ], + StoreOp: [ , "store", "discard" ], + SurfaceGetCurrentTextureStatus: [ , "success-optimal", "success-suboptimal", "timeout", "outdated", "lost", "error" ], + TextureAspect: [ , "all", "stencil-only", "depth-only" ], + TextureDimension: [ , "1d", "2d", "3d" ], + TextureFormat: [ , "r8unorm", "r8snorm", "r8uint", "r8sint", "r16unorm", "r16snorm", "r16uint", "r16sint", "r16float", "rg8unorm", "rg8snorm", "rg8uint", "rg8sint", "r32float", "r32uint", "r32sint", "rg16unorm", "rg16snorm", "rg16uint", "rg16sint", "rg16float", "rgba8unorm", "rgba8unorm-srgb", "rgba8snorm", "rgba8uint", "rgba8sint", "bgra8unorm", "bgra8unorm-srgb", "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", "rgb9e5ufloat", "rg32float", "rg32uint", "rg32sint", "rgba16unorm", "rgba16snorm", "rgba16uint", "rgba16sint", "rgba16float", "rgba32float", "rgba32uint", "rgba32sint", "stencil8", "depth16unorm", "depth24plus", "depth24plus-stencil8", "depth32float", "depth32float-stencil8", "bc1-rgba-unorm", "bc1-rgba-unorm-srgb", "bc2-rgba-unorm", "bc2-rgba-unorm-srgb", "bc3-rgba-unorm", "bc3-rgba-unorm-srgb", "bc4-r-unorm", "bc4-r-snorm", "bc5-rg-unorm", "bc5-rg-snorm", "bc6h-rgb-ufloat", "bc6h-rgb-float", "bc7-rgba-unorm", "bc7-rgba-unorm-srgb", "etc2-rgb8unorm", "etc2-rgb8unorm-srgb", "etc2-rgb8a1unorm", "etc2-rgb8a1unorm-srgb", "etc2-rgba8unorm", "etc2-rgba8unorm-srgb", "eac-r11unorm", "eac-r11snorm", "eac-rg11unorm", "eac-rg11snorm", "astc-4x4-unorm", "astc-4x4-unorm-srgb", "astc-5x4-unorm", "astc-5x4-unorm-srgb", "astc-5x5-unorm", "astc-5x5-unorm-srgb", "astc-6x5-unorm", "astc-6x5-unorm-srgb", "astc-6x6-unorm", "astc-6x6-unorm-srgb", "astc-8x5-unorm", "astc-8x5-unorm-srgb", "astc-8x6-unorm", "astc-8x6-unorm-srgb", "astc-8x8-unorm", "astc-8x8-unorm-srgb", "astc-10x5-unorm", "astc-10x5-unorm-srgb", "astc-10x6-unorm", "astc-10x6-unorm-srgb", "astc-10x8-unorm", "astc-10x8-unorm-srgb", "astc-10x10-unorm", "astc-10x10-unorm-srgb", "astc-12x10-unorm", "astc-12x10-unorm-srgb", "astc-12x12-unorm", "astc-12x12-unorm-srgb" ], + TextureSampleType: [ , , "float", "unfilterable-float", "depth", "sint", "uint" ], + TextureViewDimension: [ , "1d", "2d", "2d-array", "cube", "cube-array", "3d" ], + ToneMappingMode: [ , "standard", "extended" ], + VertexFormat: [ , "uint8", "uint8x2", "uint8x4", "sint8", "sint8x2", "sint8x4", "unorm8", "unorm8x2", "unorm8x4", "snorm8", "snorm8x2", "snorm8x4", "uint16", "uint16x2", "uint16x4", "sint16", "sint16x2", "sint16x4", "unorm16", "unorm16x2", "unorm16x4", "snorm16", "snorm16x2", "snorm16x4", "float16", "float16x2", "float16x4", "float32", "float32x2", "float32x3", "float32x4", "uint32", "uint32x2", "uint32x3", "uint32x4", "sint32", "sint32x2", "sint32x3", "sint32x4", "unorm10-10-10-2", "unorm8x4-bgra" ], + VertexStepMode: [ , "vertex", "instance" ], + WGSLLanguageFeatureName: [ , "readonly_and_readwrite_storage_textures", "packed_4x8_integer_dot_product", "unrestricted_pointer_parameters", "pointer_composite_access", "uniform_buffer_standard_layout", "subgroup_id", "texture_and_sampler_let", "subgroup_uniformity", "texture_formats_tier1" ] +}; + +function _emscripten_webgpu_get_device() { + if (WebGPU.preinitializedDeviceId === undefined) { + WebGPU.preinitializedDeviceId = WebGPU.importJsDevice(Module["preinitializedWebGPUDevice"]); + // Some users depend on this keeping the device alive, so we add an + // additional reference when we first initialize it. + _wgpuDeviceAddRef(WebGPU.preinitializedDeviceId); + } + _wgpuDeviceAddRef(WebGPU.preinitializedDeviceId); + return WebGPU.preinitializedDeviceId; +} + +function _emwgpuBufferDestroy(bufferPtr) { + bufferPtr >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + var onUnmap = WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + if (onUnmap) { + for (var i = 0; i < onUnmap.length; ++i) { + onUnmap[i](); + } + delete WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + } + buffer.destroy(); +} + +function _emwgpuBufferGetMappedRange(bufferPtr, offset, size) { + bufferPtr >>>= 0; + offset >>>= 0; + size >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + if (size == 4294967295) size = undefined; + var mapped; + try { + mapped = buffer.getMappedRange(offset, size); + } catch (ex) { + return 0; + } + var data = _memalign(16, mapped.byteLength); + HEAPU8.fill(0, data, mapped.byteLength); + WebGPU.Internals.bufferOnUnmaps[bufferPtr].push(() => { + new Uint8Array(mapped).set(HEAPU8.subarray(data >>> 0, data + mapped.byteLength >>> 0)); + _free(data); + }); + return data; +} + +function _emwgpuBufferUnmap(bufferPtr) { + bufferPtr >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + var onUnmap = WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + if (!onUnmap) { + // Already unmapped + return; + } + for (var i = 0; i < onUnmap.length; ++i) { + onUnmap[i](); + } + delete WebGPU.Internals.bufferOnUnmaps[bufferPtr]; + buffer.unmap(); +} + +function _emwgpuBufferWriteMappedRange(bufferPtr, offset, data, size) { + bufferPtr >>>= 0; + offset >>>= 0; + data >>>= 0; + size >>>= 0; + var buffer = WebGPU.getJsObject(bufferPtr); + var mapped; + try { + mapped = buffer.getMappedRange(offset, size); + } catch (ex) { + return 2; + } + new Uint8Array(mapped).set(HEAPU8.subarray(data >>> 0, data + size >>> 0)); + return 1; +} + +function _emwgpuDelete(ptr) { + ptr >>>= 0; + delete WebGPU.Internals.jsObjects[ptr]; +} + +function _emwgpuDeviceCreateBuffer(devicePtr, descriptor, bufferPtr) { + devicePtr >>>= 0; + descriptor >>>= 0; + bufferPtr >>>= 0; + var mappedAtCreation = !!(HEAPU32[(((descriptor) + (32)) >>> 2) >>> 0]); + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "usage": HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0], + "size": readI53FromI64((descriptor) + (24)), + "mappedAtCreation": mappedAtCreation + }; + var device = WebGPU.getJsObject(devicePtr); + var buffer; + try { + buffer = device.createBuffer(desc); + } catch (ex) { + // The only exception should be RangeError if mapping at creation ran out of memory. + return false; + } + WebGPU.Internals.jsObjectInsert(bufferPtr, buffer); + if (mappedAtCreation) { + WebGPU.Internals.bufferOnUnmaps[bufferPtr] = []; + } + return true; +} + +var _emwgpuDeviceCreateComputePipelineAsync = function(devicePtr, futureId_low, futureId_high, descriptor, pipelinePtr) { + devicePtr >>>= 0; + var futureId = convertI32PairToI53Checked(futureId_low, futureId_high); + descriptor >>>= 0; + pipelinePtr >>>= 0; + var desc = WebGPU.makeComputePipelineDesc(descriptor); + var device = WebGPU.getJsObject(devicePtr); + // createComputePipelineAsync + WebGPU.Internals.futureInsert(futureId, device.createComputePipelineAsync(desc).then(pipeline => { + // createComputePipelineAsync fulfilled + callUserCallback(() => { + WebGPU.Internals.jsObjectInsert(pipelinePtr, pipeline); + _emwgpuOnCreateComputePipelineCompleted(futureId, 1, pipelinePtr, 0); + }); + }, pipelineError => { + // createComputePipelineAsync rejected + callUserCallback(() => { + var sp = stackSave(); + var messagePtr = stringToUTF8OnStack(pipelineError.message); + var status = pipelineError.reason === "validation" ? 3 : pipelineError.reason === "internal" ? 4 : 0; + _emwgpuOnCreateComputePipelineCompleted(futureId, status, pipelinePtr, messagePtr); + stackRestore(sp); + }); + })); +}; + +function _emwgpuDeviceCreateShaderModule(devicePtr, descriptor, shaderModulePtr) { + devicePtr >>>= 0; + descriptor >>>= 0; + shaderModulePtr >>>= 0; + var nextInChainPtr = HEAPU32[((descriptor) >>> 2) >>> 0]; + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "code": "" + }; + switch (sType) { + case 2: + { + desc["code"] = WebGPU.makeStringFromStringView(nextInChainPtr + 8); + break; + } + } + var device = WebGPU.getJsObject(devicePtr); + WebGPU.Internals.jsObjectInsert(shaderModulePtr, device.createShaderModule(desc)); +} + +var _emwgpuDeviceDestroy = devicePtr => { + const device = WebGPU.getJsObject(devicePtr); + // Remove the onuncapturederror handler which holds a pointer to the WGPUDevice. + device.onuncapturederror = null; + device.destroy(); +}; + +var _emwgpuQueueOnSubmittedWorkDone = function(queuePtr, futureId_low, futureId_high) { + queuePtr >>>= 0; + var futureId = convertI32PairToI53Checked(futureId_low, futureId_high); + var queue = WebGPU.getJsObject(queuePtr); + // onSubmittedWorkDone + WebGPU.Internals.futureInsert(futureId, queue.onSubmittedWorkDone().then(() => { + // onSubmittedWorkDone fulfilled (assumed not to reject) + callUserCallback(() => { + _emwgpuOnWorkDoneCompleted(futureId, 1); + }); + })); +}; + +var _emwgpuWaitAny = function(futurePtr, futureCount, timeoutMSPtr) { + futurePtr >>>= 0; + futureCount >>>= 0; + timeoutMSPtr >>>= 0; + return Asyncify.handleAsync(async () => { + var promises = []; + if (timeoutMSPtr) { + var timeoutMS = HEAP32[((timeoutMSPtr) >>> 2) >>> 0]; + promises.length = futureCount + 1; + promises[futureCount] = new Promise(resolve => setTimeout(resolve, timeoutMS, 0)); + } else { + promises.length = futureCount; + } + for (var i = 0; i < futureCount; ++i) { + // If any FutureID is not tracked, it means it must be done. + var futureId = readI53FromI64((futurePtr + i * 8)); + if (!(futureId in WebGPU.Internals.futures)) { + return futureId; + } + promises[i] = WebGPU.Internals.futures[futureId]; + } + const firstResolvedFuture = await Promise.race(promises); + delete WebGPU.Internals.futures[firstResolvedFuture]; + return firstResolvedFuture; + }); +}; + +_emwgpuWaitAny.isAsync = true; + +var ENV = {}; + +var getExecutableName = () => thisProgram || "./this.program"; + +var getEnvStrings = () => { + if (!getEnvStrings.strings) { + // Default values. + // Browser language detection #8751 + var lang = (globalThis.navigator?.language ?? "C").replace("-", "_") + ".UTF-8"; + var env = { + "USER": "web_user", + "LOGNAME": "web_user", + "PATH": "/", + "PWD": "/", + "HOME": "/home/web_user", + "LANG": lang, + "_": getExecutableName() + }; + // Apply the user-provided values, if any. + for (var x in ENV) { + // x is a key in ENV; if ENV[x] is undefined, that means it was + // explicitly set to be so. We allow user code to do that to + // force variables with default values to remain unset. + if (ENV[x] === undefined) delete env[x]; else env[x] = ENV[x]; + } + var strings = []; + for (var x in env) { + strings.push(`${x}=${env[x]}`); + } + getEnvStrings.strings = strings; + } + return getEnvStrings.strings; +}; + +function _environ_get(__environ, environ_buf) { + __environ >>>= 0; + environ_buf >>>= 0; + var bufSize = 0; + var envp = 0; + for (var string of getEnvStrings()) { + var ptr = environ_buf + bufSize; + HEAPU32[(((__environ) + (envp)) >>> 2) >>> 0] = ptr; + bufSize += stringToUTF8(string, ptr, Infinity) + 1; + envp += 4; + } + return 0; +} + +function _environ_sizes_get(penviron_count, penviron_buf_size) { + penviron_count >>>= 0; + penviron_buf_size >>>= 0; + var strings = getEnvStrings(); + HEAPU32[((penviron_count) >>> 2) >>> 0] = strings.length; + var bufSize = 0; + for (var string of strings) { + bufSize += lengthBytesUTF8(string) + 1; + } + HEAPU32[((penviron_buf_size) >>> 2) >>> 0] = bufSize; + return 0; +} + +function _fd_close(fd) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + FS.close(stream); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +/** @param {number=} offset */ var doReadv = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov) >>> 2) >>> 0]; + var len = HEAPU32[(((iov) + (4)) >>> 2) >>> 0]; + iov += 8; + var curr = FS.read(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) break; + // nothing more to read + if (typeof offset != "undefined") { + offset += curr; + } + } + return ret; +}; + +function _fd_pread(fd, iov, iovcnt, offset_low, offset_high, pnum) { + iov >>>= 0; + iovcnt >>>= 0; + var offset = convertI32PairToI53Checked(offset_low, offset_high); + pnum >>>= 0; + try { + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt, offset); + HEAPU32[((pnum) >>> 2) >>> 0] = num; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +function _fd_read(fd, iov, iovcnt, pnum) { + iov >>>= 0; + iovcnt >>>= 0; + pnum >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt); + HEAPU32[((pnum) >>> 2) >>> 0] = num; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { + var offset = convertI32PairToI53Checked(offset_low, offset_high); + newOffset >>>= 0; + try { + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + FS.llseek(stream, offset, whence); + (tempI64 = [ stream.position >>> 0, (tempDouble = stream.position, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0) ], + HEAP32[((newOffset) >>> 2) >>> 0] = tempI64[0], HEAP32[(((newOffset) + (4)) >>> 2) >>> 0] = tempI64[1]); + if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; + // reset readdir state + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +/** @param {number=} offset */ var doWritev = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov) >>> 2) >>> 0]; + var len = HEAPU32[(((iov) + (4)) >>> 2) >>> 0]; + iov += 8; + var curr = FS.write(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) { + // No more space to write. + break; + } + if (typeof offset != "undefined") { + offset += curr; + } + } + return ret; +}; + +function _fd_write(fd, iov, iovcnt, pnum) { + iov >>>= 0; + iovcnt >>>= 0; + pnum >>>= 0; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doWritev(stream, iov, iovcnt); + HEAPU32[((pnum) >>> 2) >>> 0] = num; + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +var _emscripten_glActiveTexture = x0 => GLctx.activeTexture(x0); + +var _glActiveTexture = _emscripten_glActiveTexture; + +var _emscripten_glAttachShader = (program, shader) => { + GLctx.attachShader(GL.programs[program], GL.shaders[shader]); +}; + +var _glAttachShader = _emscripten_glAttachShader; + +function _emscripten_glBindAttribLocation(program, index, name) { + name >>>= 0; + GLctx.bindAttribLocation(GL.programs[program], index, UTF8ToString(name)); +} + +var _glBindAttribLocation = _emscripten_glBindAttribLocation; + +var _emscripten_glBindBuffer = (target, buffer) => { + // Calling glBindBuffer with an unknown buffer will implicitly create a + // new one. Here we bypass `GL.counter` and directly using the ID passed + // in. + if (buffer && !GL.buffers[buffer]) { + var b = GLctx.createBuffer(); + b.name = buffer; + GL.buffers[buffer] = b; + } + if (target == 34962) { + GLctx.currentArrayBufferBinding = buffer; + } else if (target == 34963) { + GLctx.currentElementArrayBufferBinding = buffer; + } + if (target == 35051) { + // In WebGL 2 glReadPixels entry point, we need to use a different WebGL 2 + // API function call when a buffer is bound to + // GL_PIXEL_PACK_BUFFER_BINDING point, so must keep track whether that + // binding point is non-null to know what is the proper API function to + // call. + GLctx.currentPixelPackBufferBinding = buffer; + } else if (target == 35052) { + // In WebGL 2 gl(Compressed)Tex(Sub)Image[23]D entry points, we need to + // use a different WebGL 2 API function call when a buffer is bound to + // GL_PIXEL_UNPACK_BUFFER_BINDING point, so must keep track whether that + // binding point is non-null to know what is the proper API function to + // call. + GLctx.currentPixelUnpackBufferBinding = buffer; + } + GLctx.bindBuffer(target, GL.buffers[buffer]); +}; + +var _glBindBuffer = _emscripten_glBindBuffer; + +var _emscripten_glBindFramebuffer = (target, framebuffer) => { + GLctx.bindFramebuffer(target, GL.framebuffers[framebuffer]); +}; + +var _glBindFramebuffer = _emscripten_glBindFramebuffer; + +var _emscripten_glBindTexture = (target, texture) => { + GLctx.bindTexture(target, GL.textures[texture]); +}; + +var _glBindTexture = _emscripten_glBindTexture; + +function _emscripten_glBufferData(target, size, data, usage) { + size >>>= 0; + data >>>= 0; + // N.b. here first form specifies a heap subarray, second form an integer + // size, so the ?: code here is polymorphic. It is advised to avoid + // randomly mixing both uses in calling code, to avoid any potential JS + // engine JIT issues. + GLctx.bufferData(target, data ? HEAPU8.subarray(data >>> 0, data + size >>> 0) : size, usage); +} + +var _glBufferData = _emscripten_glBufferData; + +var convertI32PairToI53 = (lo, hi) => (lo >>> 0) + hi * 4294967296; + +function _emscripten_glClientWaitSync(sync, flags, timeout_low, timeout_high) { + sync >>>= 0; + // WebGL2 vs GLES3 differences: in GLES3, the timeout parameter is a uint64, where 0xFFFFFFFFFFFFFFFFULL means GL_TIMEOUT_IGNORED. + // In JS, there's no 64-bit value types, so instead timeout is taken to be signed, and GL_TIMEOUT_IGNORED is given value -1. + // Inherently the value accepted in the timeout is lossy, and can't take in arbitrary u64 bit pattern (but most likely doesn't matter) + // See https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.15 + var timeout = convertI32PairToI53(timeout_low, timeout_high); + return GLctx.clientWaitSync(GL.syncs[sync], flags, timeout); +} + +var _glClientWaitSync = _emscripten_glClientWaitSync; + +var _emscripten_glCompileShader = shader => { + GLctx.compileShader(GL.shaders[shader]); +}; + +var _glCompileShader = _emscripten_glCompileShader; + +var _emscripten_glCreateProgram = () => { + var id = GL.getNewId(GL.programs); + var program = GLctx.createProgram(); + // Store additional information needed for each shader program: + program.name = id; + // Lazy cache results of + // glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) + program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0; + program.uniformIdCounter = 1; + GL.programs[id] = program; + return id; +}; + +var _glCreateProgram = _emscripten_glCreateProgram; + +var _emscripten_glCreateShader = shaderType => { + var id = GL.getNewId(GL.shaders); + GL.shaders[id] = GLctx.createShader(shaderType); + return id; +}; + +var _glCreateShader = _emscripten_glCreateShader; + +function _emscripten_glDeleteFramebuffers(n, framebuffers) { + framebuffers >>>= 0; + for (var i = 0; i < n; ++i) { + var id = HEAP32[(((framebuffers) + (i * 4)) >>> 2) >>> 0]; + var framebuffer = GL.framebuffers[id]; + if (!framebuffer) continue; + // GL spec: "glDeleteFramebuffers silently ignores 0s and names that do not correspond to existing framebuffer objects". + GLctx.deleteFramebuffer(framebuffer); + framebuffer.name = 0; + GL.framebuffers[id] = null; + } +} + +var _glDeleteFramebuffers = _emscripten_glDeleteFramebuffers; + +var _emscripten_glDeleteProgram = id => { + if (!id) return; + var program = GL.programs[id]; + if (!program) { + // glDeleteProgram actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(1281); + return; + } + GLctx.deleteProgram(program); + program.name = 0; + GL.programs[id] = null; +}; + +var _glDeleteProgram = _emscripten_glDeleteProgram; + +var _emscripten_glDeleteShader = id => { + if (!id) return; + var shader = GL.shaders[id]; + if (!shader) { + // glDeleteShader actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(1281); + return; + } + GLctx.deleteShader(shader); + GL.shaders[id] = null; +}; + +var _glDeleteShader = _emscripten_glDeleteShader; + +function _emscripten_glDeleteSync(id) { + id >>>= 0; + if (!id) return; + var sync = GL.syncs[id]; + if (!sync) { + // glDeleteSync signals an error when deleting a nonexisting object, unlike some other GL delete functions. + GL.recordError(1281); + return; + } + GLctx.deleteSync(sync); + sync.name = 0; + GL.syncs[id] = null; +} + +var _glDeleteSync = _emscripten_glDeleteSync; + +function _emscripten_glDeleteTextures(n, textures) { + textures >>>= 0; + for (var i = 0; i < n; i++) { + var id = HEAP32[(((textures) + (i * 4)) >>> 2) >>> 0]; + var texture = GL.textures[id]; + // GL spec: "glDeleteTextures silently ignores 0s and names that do not + // correspond to existing textures". + if (!texture) continue; + GLctx.deleteTexture(texture); + texture.name = 0; + GL.textures[id] = null; + } +} + +var _glDeleteTextures = _emscripten_glDeleteTextures; + +var _emscripten_glDetachShader = (program, shader) => { + GLctx.detachShader(GL.programs[program], GL.shaders[shader]); +}; + +var _glDetachShader = _emscripten_glDetachShader; + +var _emscripten_glDisableVertexAttribArray = index => { + var cb = GL.currentContext.clientBuffers[index]; + cb.enabled = false; + GLctx.disableVertexAttribArray(index); +}; + +var _glDisableVertexAttribArray = _emscripten_glDisableVertexAttribArray; + +var _emscripten_glDrawArrays = (mode, first, count) => { + // bind any client-side buffers + GL.preDrawHandleClientVertexAttribBindings(first + count); + GLctx.drawArrays(mode, first, count); + GL.postDrawHandleClientVertexAttribBindings(); +}; + +var _glDrawArrays = _emscripten_glDrawArrays; + +var _emscripten_glEnableVertexAttribArray = index => { + var cb = GL.currentContext.clientBuffers[index]; + cb.enabled = true; + GLctx.enableVertexAttribArray(index); +}; + +var _glEnableVertexAttribArray = _emscripten_glEnableVertexAttribArray; + +function _emscripten_glFenceSync(condition, flags) { + var sync = GLctx.fenceSync(condition, flags); + if (sync) { + var id = GL.getNewId(GL.syncs); + sync.name = id; + GL.syncs[id] = sync; + return id; + } + return 0; +} + +var _glFenceSync = _emscripten_glFenceSync; + +var _emscripten_glFinish = () => GLctx.finish(); + +var _glFinish = _emscripten_glFinish; + +var _emscripten_glFramebufferTexture2D = (target, attachment, textarget, texture, level) => { + GLctx.framebufferTexture2D(target, attachment, textarget, GL.textures[texture], level); +}; + +var _glFramebufferTexture2D = _emscripten_glFramebufferTexture2D; + +function _emscripten_glGenBuffers(n, buffers) { + buffers >>>= 0; + GL.genObject(n, buffers, "createBuffer", GL.buffers); +} + +var _glGenBuffers = _emscripten_glGenBuffers; + +function _emscripten_glGenFramebuffers(n, ids) { + ids >>>= 0; + GL.genObject(n, ids, "createFramebuffer", GL.framebuffers); +} + +var _glGenFramebuffers = _emscripten_glGenFramebuffers; + +function _emscripten_glGenTextures(n, textures) { + textures >>>= 0; + GL.genObject(n, textures, "createTexture", GL.textures); +} + +var _glGenTextures = _emscripten_glGenTextures; + +var _emscripten_glGetError = () => { + var error = GLctx.getError() || GL.lastError; + GL.lastError = 0; + return error; +}; + +var _glGetError = _emscripten_glGetError; + +var webglGetExtensions = () => { + var exts = getEmscriptenSupportedExtensions(GLctx); + exts = exts.concat(exts.map(e => "GL_" + e)); + return exts; +}; + +var emscriptenWebGLGet = (name_, p, type) => { + // Guard against user passing a null pointer. + // Note that GLES2 spec does not say anything about how passing a null + // pointer should be treated. Testing on desktop core GL 3, the application + // crashes on glGetIntegerv to a null pointer, but better to report an error + // instead of doing anything random. + if (!p) { + GL.recordError(1281); + return; + } + var ret = undefined; + switch (name_) { + // Handle a few trivial GLES values + case 36346: + // GL_SHADER_COMPILER + ret = 1; + break; + + case 36344: + // GL_SHADER_BINARY_FORMATS + if (type != 0 && type != 1) { + GL.recordError(1280); + } + // Do not write anything to the out pointer, since no binary formats are + // supported. + return; + + case 34814: + // GL_NUM_PROGRAM_BINARY_FORMATS + case 36345: + // GL_NUM_SHADER_BINARY_FORMATS + ret = 0; + break; + + case 34466: + // GL_NUM_COMPRESSED_TEXTURE_FORMATS + // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete + // since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be + // queried for length), so implement it ourselves to allow C++ GLES2 + // code to get the length. + var formats = GLctx.getParameter(34467); + ret = formats ? formats.length : 0; + break; + + case 33309: + // GL_NUM_EXTENSIONS + if (GL.currentContext.version < 2) { + // Calling GLES3/WebGL2 function with a GLES2/WebGL1 context + GL.recordError(1282); + return; + } + ret = webglGetExtensions().length; + break; + + case 33307: + // GL_MAJOR_VERSION + case 33308: + // GL_MINOR_VERSION + if (GL.currentContext.version < 2) { + GL.recordError(1280); + // GL_INVALID_ENUM + return; + } + ret = name_ == 33307 ? 3 : 0; + // return version 3.0 + break; + } + if (ret === undefined) { + var result = GLctx.getParameter(name_); + switch (typeof result) { + case "number": + ret = result; + break; + + case "boolean": + ret = result ? 1 : 0; + break; + + case "string": + GL.recordError(1280); + // GL_INVALID_ENUM + return; + + case "object": + if (result === null) { + // null is a valid result for some (e.g., which buffer is bound - + // perhaps nothing is bound), but otherwise can mean an invalid + // name_, which we need to report as an error + switch (name_) { + case 34964: + // ARRAY_BUFFER_BINDING + case 35725: + // CURRENT_PROGRAM + case 34965: + // ELEMENT_ARRAY_BUFFER_BINDING + case 36006: + // FRAMEBUFFER_BINDING or DRAW_FRAMEBUFFER_BINDING + case 36007: + // RENDERBUFFER_BINDING + case 32873: + // TEXTURE_BINDING_2D + case 34229: + // WebGL 2 GL_VERTEX_ARRAY_BINDING, or WebGL 1 extension OES_vertex_array_object GL_VERTEX_ARRAY_BINDING_OES + case 36662: + // COPY_READ_BUFFER_BINDING or COPY_READ_BUFFER + case 36663: + // COPY_WRITE_BUFFER_BINDING or COPY_WRITE_BUFFER + case 35053: + // PIXEL_PACK_BUFFER_BINDING + case 35055: + // PIXEL_UNPACK_BUFFER_BINDING + case 36010: + // READ_FRAMEBUFFER_BINDING + case 35097: + // SAMPLER_BINDING + case 35869: + // TEXTURE_BINDING_2D_ARRAY + case 32874: + // TEXTURE_BINDING_3D + case 36389: + // TRANSFORM_FEEDBACK_BINDING + case 35983: + // TRANSFORM_FEEDBACK_BUFFER_BINDING + case 35368: + // UNIFORM_BUFFER_BINDING + case 34068: + { + // TEXTURE_BINDING_CUBE_MAP + ret = 0; + break; + } + + default: + { + GL.recordError(1280); + // GL_INVALID_ENUM + return; + } + } + } else if (result instanceof Float32Array || result instanceof Uint32Array || result instanceof Int32Array || result instanceof Array) { + for (var i = 0; i < result.length; ++i) { + switch (type) { + case 0: + HEAP32[(((p) + (i * 4)) >>> 2) >>> 0] = result[i]; + break; + + case 2: + HEAPF32[(((p) + (i * 4)) >>> 2) >>> 0] = result[i]; + break; + + case 4: + HEAP8[(p) + (i) >>> 0] = result[i] ? 1 : 0; + break; + } + } + return; + } else { + try { + ret = result.name | 0; + } catch (e) { + GL.recordError(1280); + // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`); + return; + } + } + break; + + default: + GL.recordError(1280); + // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof (result)}!`); + return; + } + } + switch (type) { + case 1: + writeI53ToI64(p, ret); + break; + + case 0: + HEAP32[((p) >>> 2) >>> 0] = ret; + break; + + case 2: + HEAPF32[((p) >>> 2) >>> 0] = ret; + break; + + case 4: + HEAP8[p >>> 0] = ret ? 1 : 0; + break; + } +}; + +function _emscripten_glGetIntegerv(name_, p) { + p >>>= 0; + return emscriptenWebGLGet(name_, p, 0); +} + +var _glGetIntegerv = _emscripten_glGetIntegerv; + +function _emscripten_glGetString(name_) { + var ret = GL.stringCache[name_]; + if (!ret) { + switch (name_) { + case 7939: + ret = stringToNewUTF8(webglGetExtensions().join(" ")); + break; + + case 7936: + case 7937: + case 37445: + case 37446: + var s = GLctx.getParameter(name_); + if (!s) { + GL.recordError(1280); + } + ret = s ? stringToNewUTF8(s) : 0; + break; + + case 7938: + var webGLVersion = GLctx.getParameter(7938); + // return GLES version string corresponding to the version of the WebGL context + var glVersion = `OpenGL ES 2.0 (${webGLVersion})`; + if (GL.currentContext.version >= 2) glVersion = `OpenGL ES 3.0 (${webGLVersion})`; + ret = stringToNewUTF8(glVersion); + break; + + case 35724: + var glslVersion = GLctx.getParameter(35724); + // extract the version number 'N.M' from the string 'WebGL GLSL ES N.M ...' + var ver_re = /^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/; + var ver_num = glslVersion.match(ver_re); + if (ver_num !== null) { + if (ver_num[1].length == 3) ver_num[1] = ver_num[1] + "0"; + // ensure minor version has 2 digits + glslVersion = `OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`; + } + ret = stringToNewUTF8(glslVersion); + break; + + default: + GL.recordError(1280); + } + GL.stringCache[name_] = ret; + } + return ret; +} + +var _glGetString = _emscripten_glGetString; + +/** @suppress {checkTypes} */ var jstoi_q = str => parseInt(str); + +/** @noinline */ var webglGetLeftBracePos = name => name.slice(-1) == "]" && name.lastIndexOf("["); + +var webglPrepareUniformLocationsBeforeFirstUse = program => { + var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation + uniformSizeAndIdsByName = program.uniformSizeAndIdsByName, // Maps name -> [uniform array length, GLuint] + i, j; + // On the first time invocation of glGetUniformLocation on this shader program: + // initialize cache data structures and discover which uniforms are arrays. + if (!uniformLocsById) { + // maps GLint integer locations to WebGLUniformLocations + program.uniformLocsById = uniformLocsById = {}; + // maps integer locations back to uniform name strings, so that we can lazily fetch uniform array locations + program.uniformArrayNamesById = {}; + var numActiveUniforms = GLctx.getProgramParameter(program, 35718); + for (i = 0; i < numActiveUniforms; ++i) { + var u = GLctx.getActiveUniform(program, i); + var nm = u.name; + var sz = u.size; + var lb = webglGetLeftBracePos(nm); + var arrayName = lb > 0 ? nm.slice(0, lb) : nm; + // Assign a new location. + var id = program.uniformIdCounter; + program.uniformIdCounter += sz; + // Eagerly get the location of the uniformArray[0] base element. + // The remaining indices >0 will be left for lazy evaluation to + // improve performance. Those may never be needed to fetch, if the + // application fills arrays always in full starting from the first + // element of the array. + uniformSizeAndIdsByName[arrayName] = [ sz, id ]; + // Store placeholder integers in place that highlight that these + // >0 index locations are array indices pending population. + for (j = 0; j < sz; ++j) { + uniformLocsById[id] = j; + program.uniformArrayNamesById[id++] = arrayName; + } + } + } +}; + +function _emscripten_glGetUniformLocation(program, name) { + name >>>= 0; + name = UTF8ToString(name); + if (program = GL.programs[program]) { + webglPrepareUniformLocationsBeforeFirstUse(program); + var uniformLocsById = program.uniformLocsById; + // Maps GLuint -> WebGLUniformLocation + var arrayIndex = 0; + var uniformBaseName = name; + // Invariant: when populating integer IDs for uniform locations, we must + // maintain the precondition that arrays reside in contiguous addresses, + // i.e. for a 'vec4 colors[10];', colors[4] must be at location + // colors[0]+4. However, user might call glGetUniformLocation(program, + // "colors") for an array, so we cannot discover based on the user input + // arguments whether the uniform we are dealing with is an array. The only + // way to discover which uniforms are arrays is to enumerate over all the + // active uniforms in the program. + var leftBrace = webglGetLeftBracePos(name); + // If user passed an array accessor "[index]", parse the array index off the accessor. + if (leftBrace > 0) { + arrayIndex = jstoi_q(name.slice(leftBrace + 1)) >>> 0; + // "index]", coerce parseInt(']') with >>>0 to treat "foo[]" as "foo[0]" and foo[-1] as unsigned out-of-bounds. + uniformBaseName = name.slice(0, leftBrace); + } + // Have we cached the location of this uniform before? + // A pair [array length, GLint of the uniform location] + var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; + // If a uniform with this name exists, and if its index is within the + // array limits (if it's even an array), query the WebGLlocation, or + // return an existing cached location. + if (sizeAndId && arrayIndex < sizeAndId[0]) { + arrayIndex += sizeAndId[1]; + // Add the base location of the uniform to the array index offset. + if ((uniformLocsById[arrayIndex] = uniformLocsById[arrayIndex] || GLctx.getUniformLocation(program, name))) { + return arrayIndex; + } + } + } else { + // N.b. we are currently unable to distinguish between GL program IDs that + // never existed vs GL program IDs that have been deleted, so report + // GL_INVALID_VALUE in both cases. + GL.recordError(1281); + } + return -1; +} + +var _glGetUniformLocation = _emscripten_glGetUniformLocation; + +var _emscripten_glLinkProgram = program => { + program = GL.programs[program]; + GLctx.linkProgram(program); + // Invalidate earlier computed uniform->ID mappings, those have now become stale + program.uniformLocsById = 0; + // Mark as null-like so that glGetUniformLocation() knows to populate this again. + program.uniformSizeAndIdsByName = {}; +}; + +var _glLinkProgram = _emscripten_glLinkProgram; + +var _emscripten_glPixelStorei = (pname, param) => { + if (pname == 3317) { + GL.unpackAlignment = param; + } else if (pname == 3314) { + GL.unpackRowLength = param; + } + GLctx.pixelStorei(pname, param); +}; + +var _glPixelStorei = _emscripten_glPixelStorei; + +var computeUnpackAlignedImageSize = (width, height, sizePerPixel) => { + function roundedToNextMultipleOf(x, y) { + return (x + y - 1) & -y; + } + var plainRowSize = (GL.unpackRowLength || width) * sizePerPixel; + var alignedRowSize = roundedToNextMultipleOf(plainRowSize, GL.unpackAlignment); + return height * alignedRowSize; +}; + +var colorChannelsInGlTextureFormat = format => { + // Micro-optimizations for size: map format to size by subtracting smallest + // enum value (0x1902) from all values first. Also omit the most common + // size value (1) from the list, which is assumed by formats not on the + // list. + var colorChannels = { + // 0x1902 /* GL_DEPTH_COMPONENT */ - 0x1902: 1, + // 0x1906 /* GL_ALPHA */ - 0x1902: 1, + 5: 3, + 6: 4, + // 0x1909 /* GL_LUMINANCE */ - 0x1902: 1, + 8: 2, + 29502: 3, + 29504: 4, + // 0x1903 /* GL_RED */ - 0x1902: 1, + 26917: 2, + 26918: 2, + // 0x8D94 /* GL_RED_INTEGER */ - 0x1902: 1, + 29846: 3, + 29847: 4 + }; + return colorChannels[format - 6402] || 1; +}; + +var heapObjectForWebGLType = type => { + // Micro-optimization for size: Subtract lowest GL enum number (0x1400/* GL_BYTE */) from type to compare + // smaller values for the heap, for shorter generated code size. + // Also the type HEAPU16 is not tested for explicitly, but any unrecognized type will return out HEAPU16. + // (since most types are HEAPU16) + type -= 5120; + if (type == 0) return HEAP8; + if (type == 1) return HEAPU8; + if (type == 2) return HEAP16; + if (type == 4) return HEAP32; + if (type == 6) return HEAPF32; + if (type == 5 || type == 28922 || type == 28520 || type == 30779 || type == 30782) return HEAPU32; + return HEAPU16; +}; + +var toTypedArrayIndex = (pointer, heap) => pointer >>> (31 - Math.clz32(heap.BYTES_PER_ELEMENT)); + +var emscriptenWebGLGetTexPixelData = (type, format, width, height, pixels, internalFormat) => { + var heap = heapObjectForWebGLType(type); + var sizePerPixel = colorChannelsInGlTextureFormat(format) * heap.BYTES_PER_ELEMENT; + var bytes = computeUnpackAlignedImageSize(width, height, sizePerPixel); + return heap.subarray(toTypedArrayIndex(pixels, heap) >>> 0, toTypedArrayIndex(pixels + bytes, heap) >>> 0); +}; + +function _emscripten_glReadPixels(x, y, width, height, format, type, pixels) { + pixels >>>= 0; + if (GL.currentContext.version >= 2) { + if (GLctx.currentPixelPackBufferBinding) { + GLctx.readPixels(x, y, width, height, format, type, pixels); + return; + } + } + var pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, format); + if (!pixelData) { + GL.recordError(1280); + return; + } + GLctx.readPixels(x, y, width, height, format, type, pixelData); +} + +var _glReadPixels = _emscripten_glReadPixels; + +function _emscripten_glShaderSource(shader, count, string, length) { + string >>>= 0; + length >>>= 0; + var source = GL.getSource(shader, count, string, length); + GLctx.shaderSource(GL.shaders[shader], source); +} + +var _glShaderSource = _emscripten_glShaderSource; + +function _emscripten_glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels) { + pixels >>>= 0; + if (GL.currentContext.version >= 2) { + if (GLctx.currentPixelUnpackBufferBinding) { + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels); + return; + } + } + var pixelData = pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null; + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixelData); +} + +var _glTexImage2D = _emscripten_glTexImage2D; + +var _emscripten_glTexParameteri = (x0, x1, x2) => GLctx.texParameteri(x0, x1, x2); + +var _glTexParameteri = _emscripten_glTexParameteri; + +var _emscripten_glTexStorage2D = (x0, x1, x2, x3, x4) => GLctx.texStorage2D(x0, x1, x2, x3, x4); + +var _glTexStorage2D = _emscripten_glTexStorage2D; + +var webglGetUniformLocation = location => { + var p = GLctx.currentProgram; + if (p) { + var webglLoc = p.uniformLocsById[location]; + // p.uniformLocsById[location] stores either an integer, or a + // WebGLUniformLocation. + // If an integer, we have not yet bound the location, so do it now. The + // integer value specifies the array index we should bind to. + if (typeof webglLoc == "number") { + p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? `[${webglLoc}]` : "")); + } + // Else an already cached WebGLUniformLocation, return it. + return webglLoc; + } else { + GL.recordError(1282); + } +}; + +var _emscripten_glUniform1i = (location, v0) => { + GLctx.uniform1i(webglGetUniformLocation(location), v0); +}; + +var _glUniform1i = _emscripten_glUniform1i; + +var _emscripten_glUseProgram = program => { + program = GL.programs[program]; + GLctx.useProgram(program); + // Record the currently active program so that we can access the uniform + // mapping table of that program. + GLctx.currentProgram = program; +}; + +var _glUseProgram = _emscripten_glUseProgram; + +function _emscripten_glVertexAttribPointer(index, size, type, normalized, stride, ptr) { + ptr >>>= 0; + var cb = GL.currentContext.clientBuffers[index]; + if (!GLctx.currentArrayBufferBinding) { + cb.size = size; + cb.type = type; + cb.normalized = normalized; + cb.stride = stride; + cb.ptr = ptr; + cb.clientside = true; + cb.vertexAttribPointerAdaptor = function(index, size, type, normalized, stride, ptr) { + this.vertexAttribPointer(index, size, type, normalized, stride, ptr); + }; + return; + } + cb.clientside = false; + GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr); +} + +var _glVertexAttribPointer = _emscripten_glVertexAttribPointer; + +var _emscripten_glViewport = (x0, x1, x2, x3) => GLctx.viewport(x0, x1, x2, x3); + +var _glViewport = _emscripten_glViewport; + +function _random_get(buffer, size) { + buffer >>>= 0; + size >>>= 0; + try { + randomFill(HEAPU8.subarray(buffer >>> 0, buffer + size >>> 0)); + return 0; + } catch (e) { + if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e; + return e.errno; + } +} + +var _wgpuBufferGetSize = function(bufferPtr) { + bufferPtr >>>= 0; + var ret = (() => { + var buffer = WebGPU.getJsObject(bufferPtr); + // 64-bit + return buffer.size; + })(); + return (setTempRet0((tempDouble = ret, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0)), + ret >>> 0); +}; + +var _wgpuBufferGetUsage = function(bufferPtr) { + bufferPtr >>>= 0; + var ret = (() => { + var buffer = WebGPU.getJsObject(bufferPtr); + return buffer.usage; + })(); + return (setTempRet0((tempDouble = ret, (+(Math.abs(tempDouble))) >= 1 ? (tempDouble > 0 ? (+(Math.floor((tempDouble) / 4294967296))) >>> 0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble))) >>> 0)) / 4294967296))))) >>> 0) : 0)), + ret >>> 0); +}; + +function _wgpuCommandEncoderBeginComputePass(encoderPtr, descriptor) { + encoderPtr >>>= 0; + descriptor >>>= 0; + var desc; + if (descriptor) { + desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "timestampWrites": WebGPU.makePassTimestampWrites(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]) + }; + } + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var ptr = _emwgpuCreateComputePassEncoder(0); + WebGPU.Internals.jsObjectInsert(ptr, commandEncoder.beginComputePass(desc)); + return ptr; +} + +function _wgpuCommandEncoderCopyBufferToBuffer(encoderPtr, srcPtr, srcOffset_low, srcOffset_high, dstPtr, dstOffset_low, dstOffset_high, size_low, size_high) { + encoderPtr >>>= 0; + srcPtr >>>= 0; + var srcOffset = convertI32PairToI53Checked(srcOffset_low, srcOffset_high); + dstPtr >>>= 0; + var dstOffset = convertI32PairToI53Checked(dstOffset_low, dstOffset_high); + var size = convertI32PairToI53Checked(size_low, size_high); + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var src = WebGPU.getJsObject(srcPtr); + var dst = WebGPU.getJsObject(dstPtr); + commandEncoder.copyBufferToBuffer(src, srcOffset, dst, dstOffset, size); +} + +function _wgpuCommandEncoderCopyTextureToBuffer(encoderPtr, srcPtr, dstPtr, copySizePtr) { + encoderPtr >>>= 0; + srcPtr >>>= 0; + dstPtr >>>= 0; + copySizePtr >>>= 0; + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var copySize = WebGPU.makeExtent3D(copySizePtr); + commandEncoder.copyTextureToBuffer(WebGPU.makeTexelCopyTextureInfo(srcPtr), WebGPU.makeTexelCopyBufferInfo(dstPtr), copySize); +} + +function _wgpuCommandEncoderCopyTextureToTexture(encoderPtr, srcPtr, dstPtr, copySizePtr) { + encoderPtr >>>= 0; + srcPtr >>>= 0; + dstPtr >>>= 0; + copySizePtr >>>= 0; + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var copySize = WebGPU.makeExtent3D(copySizePtr); + commandEncoder.copyTextureToTexture(WebGPU.makeTexelCopyTextureInfo(srcPtr), WebGPU.makeTexelCopyTextureInfo(dstPtr), copySize); +} + +function _wgpuCommandEncoderFinish(encoderPtr, descriptor) { + encoderPtr >>>= 0; + descriptor >>>= 0; + // TODO: Use the descriptor. + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var ptr = _emwgpuCreateCommandBuffer(0); + WebGPU.Internals.jsObjectInsert(ptr, commandEncoder.finish()); + return ptr; +} + +function _wgpuCommandEncoderResolveQuerySet(encoderPtr, querySetPtr, firstQuery, queryCount, destinationPtr, destinationOffset_low, destinationOffset_high) { + encoderPtr >>>= 0; + querySetPtr >>>= 0; + destinationPtr >>>= 0; + var destinationOffset = convertI32PairToI53Checked(destinationOffset_low, destinationOffset_high); + var commandEncoder = WebGPU.getJsObject(encoderPtr); + var querySet = WebGPU.getJsObject(querySetPtr); + var destination = WebGPU.getJsObject(destinationPtr); + commandEncoder.resolveQuerySet(querySet, firstQuery, queryCount, destination, destinationOffset); +} + +function _wgpuComputePassEncoderDispatchWorkgroups(passPtr, x, y, z) { + passPtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + pass.dispatchWorkgroups(x, y, z); +} + +function _wgpuComputePassEncoderEnd(passPtr) { + passPtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + pass.end(); +} + +function _wgpuComputePassEncoderSetBindGroup(passPtr, groupIndex, groupPtr, dynamicOffsetCount, dynamicOffsetsPtr) { + passPtr >>>= 0; + groupPtr >>>= 0; + dynamicOffsetCount >>>= 0; + dynamicOffsetsPtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + var group = WebGPU.getJsObject(groupPtr); + if (dynamicOffsetCount == 0) { + pass.setBindGroup(groupIndex, group); + } else { + pass.setBindGroup(groupIndex, group, HEAPU32, ((dynamicOffsetsPtr) >>> 2), dynamicOffsetCount); + } +} + +function _wgpuComputePassEncoderSetPipeline(passPtr, pipelinePtr) { + passPtr >>>= 0; + pipelinePtr >>>= 0; + var pass = WebGPU.getJsObject(passPtr); + var pipeline = WebGPU.getJsObject(pipelinePtr); + pass.setPipeline(pipeline); +} + +var _wgpuDeviceCreateBindGroup = function(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + function makeEntry(entryPtr) { + var bufferPtr = HEAPU32[(((entryPtr) + (8)) >>> 2) >>> 0]; + var samplerPtr = HEAPU32[(((entryPtr) + (32)) >>> 2) >>> 0]; + var textureViewPtr = HEAPU32[(((entryPtr) + (36)) >>> 2) >>> 0]; + var externalTexturePtr = 0; + WebGPU.iterateExtensions(entryPtr, { + 14: ptr => { + externalTexturePtr = HEAPU32[(((ptr) + (8)) >>> 2) >>> 0]; + } + }); + var resource; + if (bufferPtr) { + // Note the sentinel UINT64_MAX will be read as -1. + var size = readI53FromI64((entryPtr) + (24)); + if (size == -1) size = undefined; + resource = { + "buffer": WebGPU.getJsObject(bufferPtr), + "offset": readI53FromI64((entryPtr) + (16)), + "size": size + }; + } else { + resource = WebGPU.getJsObject(samplerPtr || textureViewPtr || externalTexturePtr); + } + return { + "binding": HEAPU32[(((entryPtr) + (4)) >>> 2) >>> 0], + "resource": resource + }; + } + function makeEntries(count, entriesPtrs) { + var entries = []; + for (var i = 0; i < count; ++i) { + entries.push(makeEntry(entriesPtrs + 40 * i)); + } + return entries; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "layout": WebGPU.getJsObject(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]), + "entries": makeEntries(HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0], HEAPU32[(((descriptor) + (20)) >>> 2) >>> 0]) + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateBindGroup(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createBindGroup(desc)); + return ptr; +}; + +function _wgpuDeviceCreateBindGroupLayout(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + function makeBufferEntry(substructPtr) { + var typeInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!typeInt) return undefined; + return { + "type": WebGPU.BufferBindingType[typeInt], + "hasDynamicOffset": !!(HEAPU32[(((substructPtr) + (8)) >>> 2) >>> 0]), + "minBindingSize": readI53FromI64((substructPtr) + (16)) + }; + } + function makeSamplerEntry(substructPtr) { + var typeInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!typeInt) return undefined; + return { + "type": WebGPU.SamplerBindingType[typeInt] + }; + } + function makeTextureEntry(substructPtr) { + var sampleTypeInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!sampleTypeInt) return undefined; + return { + "sampleType": WebGPU.TextureSampleType[sampleTypeInt], + "viewDimension": WebGPU.TextureViewDimension[HEAP32[(((substructPtr) + (8)) >>> 2) >>> 0]], + "multisampled": !!(HEAPU32[(((substructPtr) + (12)) >>> 2) >>> 0]) + }; + } + function makeStorageTextureEntry(substructPtr) { + var accessInt = HEAPU32[(((substructPtr) + (4)) >>> 2) >>> 0]; + if (!accessInt) return undefined; + return { + "access": WebGPU.StorageTextureAccess[accessInt], + "format": WebGPU.TextureFormat[HEAP32[(((substructPtr) + (8)) >>> 2) >>> 0]], + "viewDimension": WebGPU.TextureViewDimension[HEAP32[(((substructPtr) + (12)) >>> 2) >>> 0]] + }; + } + function makeEntry(entryPtr) { + var entry = { + "binding": HEAPU32[(((entryPtr) + (4)) >>> 2) >>> 0], + "visibility": HEAPU32[(((entryPtr) + (8)) >>> 2) >>> 0], + "buffer": makeBufferEntry(entryPtr + 24), + "sampler": makeSamplerEntry(entryPtr + 48), + "texture": makeTextureEntry(entryPtr + 56), + "storageTexture": makeStorageTextureEntry(entryPtr + 72) + }; + WebGPU.iterateExtensions(entryPtr, { + 13: ptr => { + entry["externalTexture"] = {}; + } + }); + return entry; + } + function makeEntries(count, entriesPtrs) { + var entries = []; + for (var i = 0; i < count; ++i) { + entries.push(makeEntry(entriesPtrs + 88 * i)); + } + return entries; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "entries": makeEntries(HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0], HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0]) + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateBindGroupLayout(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createBindGroupLayout(desc)); + return ptr; +} + +function _wgpuDeviceCreateCommandEncoder(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var desc; + if (descriptor) { + desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4) + }; + } + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateCommandEncoder(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createCommandEncoder(desc)); + return ptr; +} + +function _wgpuDeviceCreateComputePipeline(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var desc = WebGPU.makeComputePipelineDesc(descriptor); + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateComputePipeline(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createComputePipeline(desc)); + return ptr; +} + +function _wgpuDeviceCreatePipelineLayout(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var bglCount = HEAPU32[(((descriptor) + (12)) >>> 2) >>> 0]; + var bglPtr = HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0]; + var bgls = []; + for (var i = 0; i < bglCount; ++i) { + bgls.push(WebGPU.getJsObject(HEAPU32[(((bglPtr) + (4 * i)) >>> 2) >>> 0])); + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "bindGroupLayouts": bgls + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreatePipelineLayout(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createPipelineLayout(desc)); + return ptr; +} + +function _wgpuDeviceCreateQuerySet(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var desc = { + "type": WebGPU.QueryType[HEAP32[(((descriptor) + (12)) >>> 2) >>> 0]], + "count": HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0] + }; + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateQuerySet(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createQuerySet(desc)); + return ptr; +} + +function _wgpuDeviceCreateTexture(devicePtr, descriptor) { + devicePtr >>>= 0; + descriptor >>>= 0; + var nextInChainPtr = HEAPU32[((descriptor) >>> 2) >>> 0]; + var textureBindingViewDimension; + if (nextInChainPtr !== 0) { + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var textureBindingViewDimensionDescriptor = nextInChainPtr; + textureBindingViewDimension = WebGPU.TextureViewDimension[HEAP32[(((textureBindingViewDimensionDescriptor) + (8)) >>> 2) >>> 0]]; + } + var desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "size": WebGPU.makeExtent3D(descriptor + 28), + "mipLevelCount": HEAPU32[(((descriptor) + (44)) >>> 2) >>> 0], + "sampleCount": HEAPU32[(((descriptor) + (48)) >>> 2) >>> 0], + "dimension": WebGPU.TextureDimension[HEAP32[(((descriptor) + (24)) >>> 2) >>> 0]], + "format": WebGPU.TextureFormat[HEAP32[(((descriptor) + (40)) >>> 2) >>> 0]], + "usage": HEAPU32[(((descriptor) + (16)) >>> 2) >>> 0], + "textureBindingViewDimension": textureBindingViewDimension + }; + var viewFormatCount = HEAPU32[(((descriptor) + (52)) >>> 2) >>> 0]; + if (viewFormatCount) { + var viewFormatsPtr = HEAPU32[(((descriptor) + (56)) >>> 2) >>> 0]; + // viewFormatsPtr pointer to an array of TextureFormat which is an enum of size uint32_t + desc["viewFormats"] = Array.from(HEAP32.subarray((((viewFormatsPtr) >>> 2)) >>> 0, ((viewFormatsPtr + viewFormatCount * 4) >>> 2) >>> 0), format => WebGPU.TextureFormat[format]); + } + var device = WebGPU.getJsObject(devicePtr); + var ptr = _emwgpuCreateTexture(0); + WebGPU.Internals.jsObjectInsert(ptr, device.createTexture(desc)); + return ptr; +} + +function _wgpuDeviceGetAdapterInfo(devicePtr, adapterInfo) { + devicePtr >>>= 0; + adapterInfo >>>= 0; + var device = WebGPU.getJsObject(devicePtr); + WebGPU.fillAdapterInfoStruct(device.adapterInfo, adapterInfo); + return 1; +} + +function _wgpuDeviceGetLimits(devicePtr, limitsOutPtr) { + devicePtr >>>= 0; + limitsOutPtr >>>= 0; + var device = WebGPU.getJsObject(devicePtr); + WebGPU.fillLimitStruct(device.limits, limitsOutPtr); + return 1; +} + +function _wgpuDeviceHasFeature(devicePtr, featureEnumValue) { + devicePtr >>>= 0; + var device = WebGPU.getJsObject(devicePtr); + return device.features.has(WebGPU.FeatureName[featureEnumValue]); +} + +var _wgpuQueueSubmit = function(queuePtr, commandCount, commands) { + queuePtr >>>= 0; + commandCount >>>= 0; + commands >>>= 0; + var queue = WebGPU.getJsObject(queuePtr); + var cmds = Array.from(HEAP32.subarray((((commands) >>> 2)) >>> 0, ((commands + commandCount * 4) >>> 2) >>> 0), id => WebGPU.getJsObject(id)); + queue.submit(cmds); +}; + +function _wgpuQueueWriteBuffer(queuePtr, bufferPtr, bufferOffset_low, bufferOffset_high, data, size) { + queuePtr >>>= 0; + bufferPtr >>>= 0; + var bufferOffset = convertI32PairToI53Checked(bufferOffset_low, bufferOffset_high); + data >>>= 0; + size >>>= 0; + var queue = WebGPU.getJsObject(queuePtr); + var buffer = WebGPU.getJsObject(bufferPtr); + // There is a size limitation for ArrayBufferView. Work around by passing in a subarray + // instead of the whole heap. crbug.com/1201109 + var subarray = HEAPU8.subarray(data >>> 0, data + size >>> 0); + queue.writeBuffer(buffer, bufferOffset, subarray, 0, size); +} + +function _wgpuQueueWriteTexture(queuePtr, destinationPtr, data, dataSize, dataLayoutPtr, writeSizePtr) { + queuePtr >>>= 0; + destinationPtr >>>= 0; + data >>>= 0; + dataSize >>>= 0; + dataLayoutPtr >>>= 0; + writeSizePtr >>>= 0; + var queue = WebGPU.getJsObject(queuePtr); + var destination = WebGPU.makeTexelCopyTextureInfo(destinationPtr); + var dataLayout = WebGPU.makeTexelCopyBufferLayout(dataLayoutPtr); + var writeSize = WebGPU.makeExtent3D(writeSizePtr); + // This subarray isn't strictly necessary, but helps work around an issue + // where Chromium makes a copy of the entire heap. crbug.com/1134457 + var subarray = HEAPU8.subarray(data >>> 0, data + dataSize >>> 0); + queue.writeTexture(destination, subarray, dataLayout, writeSize); +} + +function _wgpuTextureCreateView(texturePtr, descriptor) { + texturePtr >>>= 0; + descriptor >>>= 0; + var desc; + if (descriptor) { + var swizzle; + var nextInChainPtr = HEAPU32[((descriptor) >>> 2) >>> 0]; + if (nextInChainPtr !== 0) { + var sType = HEAP32[(((nextInChainPtr) + (4)) >>> 2) >>> 0]; + var swizzleDescriptor = nextInChainPtr; + var swizzlePtr = swizzleDescriptor + 8; + var r = WebGPU.ComponentSwizzle[HEAP32[((swizzlePtr) >>> 2) >>> 0]] || "r"; + var g = WebGPU.ComponentSwizzle[HEAP32[(((swizzlePtr) + (4)) >>> 2) >>> 0]] || "g"; + var b = WebGPU.ComponentSwizzle[HEAP32[(((swizzlePtr) + (8)) >>> 2) >>> 0]] || "b"; + var a = WebGPU.ComponentSwizzle[HEAP32[(((swizzlePtr) + (12)) >>> 2) >>> 0]] || "a"; + swizzle = `${r}${g}${b}${a}`; + } + var mipLevelCount = HEAPU32[(((descriptor) + (24)) >>> 2) >>> 0]; + var arrayLayerCount = HEAPU32[(((descriptor) + (32)) >>> 2) >>> 0]; + desc = { + "label": WebGPU.makeStringFromOptionalStringView(descriptor + 4), + "format": WebGPU.TextureFormat[HEAP32[(((descriptor) + (12)) >>> 2) >>> 0]], + "dimension": WebGPU.TextureViewDimension[HEAP32[(((descriptor) + (16)) >>> 2) >>> 0]], + "baseMipLevel": HEAPU32[(((descriptor) + (20)) >>> 2) >>> 0], + "mipLevelCount": mipLevelCount === 4294967295 ? undefined : mipLevelCount, + "baseArrayLayer": HEAPU32[(((descriptor) + (28)) >>> 2) >>> 0], + "arrayLayerCount": arrayLayerCount === 4294967295 ? undefined : arrayLayerCount, + "aspect": WebGPU.TextureAspect[HEAP32[(((descriptor) + (36)) >>> 2) >>> 0]], + "usage": HEAPU32[(((descriptor) + (40)) >>> 2) >>> 0], + "swizzle": swizzle + }; + } + var texture = WebGPU.getJsObject(texturePtr); + var ptr = _emwgpuCreateTextureView(0); + WebGPU.Internals.jsObjectInsert(ptr, texture.createView(desc)); + return ptr; +} + +function _wgpuTextureDestroy(texturePtr) { + texturePtr >>>= 0; + WebGPU.getJsObject(texturePtr).destroy(); +} + +function _wgpuTextureGetDepthOrArrayLayers(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + return texture.depthOrArrayLayers; +} + +function _wgpuTextureGetFormat(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + // Should return the enum integer instead of string. + return WebGPU.TextureFormat.indexOf(texture.format); +} + +function _wgpuTextureGetHeight(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + return texture.height; +} + +function _wgpuTextureGetWidth(texturePtr) { + texturePtr >>>= 0; + var texture = WebGPU.getJsObject(texturePtr); + return texture.width; +} + +var getCFunc = ident => { + var func = Module["_" + ident]; + // closure exported function + return func; +}; + +var writeArrayToMemory = (array, buffer) => { + HEAP8.set(array, buffer >>> 0); +}; + +/** + * @param {string|null=} returnType + * @param {Array=} argTypes + * @param {Array=} args + * @param {Object=} opts + */ var ccall = (ident, returnType, argTypes, args, opts) => { + // For fast lookup of conversion functions + var toC = { + "string": str => { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { + // null string + ret = stringToUTF8OnStack(str); + } + return ret; + }, + "array": arr => { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + } + }; + function convertReturnValue(ret) { + if (returnType === "string") { + return UTF8ToString(ret); + } + if (returnType === "pointer") return ret >>> 0; + if (returnType === "boolean") return Boolean(ret); + return ret; + } + var func = getCFunc(ident); + var cArgs = []; + var stack = 0; + if (args) { + for (var i = 0; i < args.length; i++) { + var converter = toC[argTypes[i]]; + if (converter) { + if (stack === 0) stack = stackSave(); + cArgs[i] = converter(args[i]); + } else { + cArgs[i] = args[i]; + } + } + } + // Data for a previous async operation that was in flight before us. + var previousAsync = Asyncify.currData; + var ret = func(...cArgs); + function onDone(ret) { + runtimeKeepalivePop(); + if (stack !== 0) stackRestore(stack); + return convertReturnValue(ret); + } + var asyncMode = opts?.async; + // Keep the runtime alive through all calls. Note that this call might not be + // async, but for simplicity we push and pop in all calls. + runtimeKeepalivePush(); + if (Asyncify.currData != previousAsync) { + // This is a new async operation. The wasm is paused and has unwound its stack. + // We need to return a Promise that resolves the return value + // once the stack is rewound and execution finishes. + return Asyncify.whenDone().then(onDone); + } + ret = onDone(ret); + // If this is an async ccall, ensure we return a promise + if (asyncMode) return Promise.resolve(ret); + return ret; +}; + +var FS_createPath = (...args) => FS.createPath(...args); + +var FS_unlink = (...args) => FS.unlink(...args); + +var FS_createLazyFile = (...args) => FS.createLazyFile(...args); + +var FS_createDevice = (...args) => FS.createDevice(...args); + +FS.createPreloadedFile = FS_createPreloadedFile; + +FS.preloadFile = FS_preloadFile; + +FS.staticInit(); + +// Signal GL rendering layer that processing of a new frame is about to +// start. This helps it optimize VBO double-buffering and reduce GPU stalls. +registerPreMainLoop(() => GL.newRenderingFrameStarted()); + +// End JS library code +// include: postlibrary.js +// This file is included after the automatically-generated JS library code +// but before the wasm module is created. +{ + // Begin ATMODULES hooks + if (Module["preloadPlugins"]) preloadPlugins = Module["preloadPlugins"]; + if (Module["noExitRuntime"]) noExitRuntime = Module["noExitRuntime"]; + if (Module["print"]) out = Module["print"]; + if (Module["printErr"]) err = Module["printErr"]; + if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; + // End ATMODULES hooks + if (Module["arguments"]) arguments_ = Module["arguments"]; + if (Module["thisProgram"]) thisProgram = Module["thisProgram"]; + if (Module["preInit"]) { + if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ]; + while (Module["preInit"].length > 0) { + Module["preInit"].shift()(); + } + } +} + +// Begin runtime exports +Module["addRunDependency"] = addRunDependency; + +Module["removeRunDependency"] = removeRunDependency; + +Module["ccall"] = ccall; + +Module["stringToNewUTF8"] = stringToNewUTF8; + +Module["FS_preloadFile"] = FS_preloadFile; + +Module["FS_unlink"] = FS_unlink; + +Module["FS_createPath"] = FS_createPath; + +Module["FS_createDevice"] = FS_createDevice; + +Module["FS_createDataFile"] = FS_createDataFile; + +Module["FS_createLazyFile"] = FS_createLazyFile; + +// End runtime exports +// Begin JS library exports +// End JS library exports +// end include: postlibrary.js +var ASM_CONSTS = { + 2019768: () => !!Module["preinitializedWebGPUDevice"], + 2019819: () => { + const retVal = Module.LLM_CANCEL_FLAG; + Module.LLM_CANCEL_FLAG = undefined; + return retVal || 0; + }, + 2019918: $0 => { + const device = WebGPU.getJsObject($0); + return device.features.has("subgroups"); + }, + 2020002: () => !!Module["preinitializedWebGPUDevice"], + 2020053: () => { + specialHTMLTargets["#canvas"] = Module.canvas; + } +}; + +function __asyncjs__InvokeReadDataFn(fn, offset, size, mode) { + return Asyncify.handleAsync(async () => await Emval.toValue(fn)(offset, size, mode)); +} + +function JsProgressListener(text, done) { + Module._userProgressListener(UTF8ToString(text), done); +} + +function DefaultErrorReporter(message) { + throw new Error(UTF8ToString(message)); +} + +function ThrowError(val_handle) { + const error = Emval.toValue(val_handle); + throw error; +} + +function JsOnEmptyPacketListener(output_stream_name, timestamp) { + Module._wrapEmptyPacketListenerOutput(output_stream_name, timestamp); +} + +function JsOnVectorFinishedListener(output_stream_name, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, undefined, true, timestamp); +} + +function JsOnSimpleListenerBool(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerBool(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerInt(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerInt(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerUint(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerUint(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerDouble(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerDouble(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerFloat(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, timestamp); +} + +function JsOnVectorListenerFloat(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, out_data, false, timestamp); +} + +function JsOnSimpleListenerString(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, UTF8ToString(out_data), timestamp); +} + +function JsOnVectorListenerString(output_stream_name, out_data, timestamp) { + Module._wrapSimpleListenerOutput(output_stream_name, UTF8ToString(out_data), false, timestamp); +} + +function JsOnVectorListenerProto(output_stream_name, proto_ptr, proto_size, make_deep_copy, timestamp) { + const newProtoArray = make_deep_copy ? Module.HEAPU8.slice(proto_ptr, proto_ptr + proto_size) : new Uint8Array(Module.HEAPU8.buffer, proto_ptr, proto_size); + Module._wrapSimpleListenerOutput(output_stream_name, newProtoArray, false, timestamp); +} + +function JsWrapSimpleListeners() { + if (!Module._wrapSimpleListenerOutput) { + Module._wrapSimpleListenerOutput = (outputStreamName, ...args) => { + if (Module.simpleListeners) { + const streamName = UTF8ToString(outputStreamName); + if (Module.simpleListeners[streamName]) { + Module.simpleListeners[streamName](...args); + } + } + }; + } + if (!Module._wrapEmptyPacketListenerOutput) { + Module._wrapEmptyPacketListenerOutput = (outputStreamName, timestamp) => { + if (Module.emptyPacketListeners) { + const streamName = UTF8ToString(outputStreamName); + if (Module.emptyPacketListeners[streamName]) { + Module.emptyPacketListeners[streamName](timestamp); + } + } + }; + } +} + +function JsOnSimpleListenerBinaryArray(output_stream_name, binary_ptr, binary_size, make_deep_copy, timestamp) { + const newProtoArray = make_deep_copy ? Module.HEAPU8.slice(binary_ptr, binary_ptr + binary_size) : new Uint8Array(Module.HEAPU8.buffer, binary_ptr, binary_size); + Module._wrapSimpleListenerOutput(output_stream_name, newProtoArray, timestamp); +} + +function __asyncjs__CallReadDataFn(fn, offset, size, mode) { + return Asyncify.handleAsync(async () => await Emval.toValue(fn)(offset, size, mode)); +} + +function __asyncjs__mediapipe_map_buffer_jspi(buffer_handle, data) { + return Asyncify.handleAsync(async () => { + const buffer = WebGPU.getJsObject(buffer_handle); + if ("mapSync" in buffer) { + buffer.mapSync(GPUMapMode.READ); + } else { + await buffer.mapAsync(GPUMapMode.READ); + } + const mapped = buffer.getMappedRange(); + HEAPU8.set(new Uint8Array(mapped), data >>> 0); + buffer.unmap(); + }); +} + +function JsGetDeviceMinSubgroupSize(deviceId) { + const device = WebGPU.getJsObject(deviceId); + return device.adapterInfo.subgroupMinSize || device.limits.minSubgroupSize; +} + +function JsGetDeviceMaxSubgroupSize(deviceId) { + const device = WebGPU.getJsObject(deviceId); + return device.adapterInfo.subgroupMaxSize || device.limits.maxSubgroupSize; +} + +function __asyncjs__ReadBufferDataJs(buffer_handle, data_ptr) { + return Asyncify.handleAsync(async () => { + const gpuReadBuffer = WebGPU.getJsObject(buffer_handle); + await gpuReadBuffer.mapAsync(GPUMapMode.READ); + const arrayBuffer = gpuReadBuffer.getMappedRange(); + const u8view = new Uint8Array(arrayBuffer); + HEAPU8.set(u8view, data_ptr >>> 0 >>> 0); + gpuReadBuffer.unmap(); + }); +} + +function GetAdapterArchitecture() { + const device = Module["preinitializedWebGPUDevice"]; + const architecture = device.adapterInfo ? device.adapterInfo.architecture : "Unknown"; + return stringToNewUTF8(architecture); +} + +function GetAdapterDescription() { + const device = Module["preinitializedWebGPUDevice"]; + const description = device.adapterInfo ? device.adapterInfo.description : "Unknown"; + return stringToNewUTF8(description); +} + +function GetAdapterDeviceName() { + const device = Module["preinitializedWebGPUDevice"]; + const deviceName = device.adapterInfo ? device.adapterInfo.device : "Unknown"; + return stringToNewUTF8(deviceName); +} + +function GetAdapterVendor() { + const device = Module["preinitializedWebGPUDevice"]; + const vendor = device.adapterInfo ? device.adapterInfo.vendor : "Unknown"; + return stringToNewUTF8(vendor); +} + +function hardware_concurrency() { + var concurrency = 1; + try { + concurrency = self.navigator.hardwareConcurrency; + } catch (e) {} + return concurrency; +} + +function JsWrapErrorListener(code, message) { + if (Module.errorListener) { + const stringMessage = UTF8ToString(message); + Module.errorListener(code, stringMessage); + } +} + +function UseBottomLeftGpuOrigin() { + return (Module && Module.gpuOriginForWebTexturesIsBottomLeft); +} + +function custom_emscripten_dbgn(str, len) { + if (typeof (dbg) !== "undefined") { + dbg(UTF8ToString(str, len)); + } else { + if (typeof (custom_dbg) === "undefined") { + function custom_dbg(text) { + console.warn.apply(console, arguments); + } + } + custom_dbg(UTF8ToString(str, len)); + } +} + +// Imports from the Wasm binary. +var _free, _CreateLlmInferenceEngineConverted, _DeleteLlmInferenceEngine, _MakeSessionForPredict, _AddTextQueryChunk, _AddImageQueryChunk, _AddAudioQueryChunk, _malloc, _PredictSession, _FreeSession, _GetSizeInTokens, _wgpuDeviceAddRef, _registerModelResourcesGraphService, _bindTextureToStream, _addBoundTextureToStream, _addDoubleToInputStream, _addFloatToInputStream, _addBoolToInputStream, _addIntToInputStream, _addUintToInputStream, _addStringToInputStream, _addRawDataSpanToInputStream, _allocateBoolVector, _allocateFloatVector, _allocateDoubleVector, _allocateIntVector, _allocateUintVector, _allocateStringVector, _addBoolVectorEntry, _addFloatVectorEntry, _addDoubleVectorEntry, _addIntVectorEntry, _addUintVectorEntry, _addStringVectorEntry, _addBoolVectorToInputStream, _addFloatVectorToInputStream, _addDoubleVectorToInputStream, _addIntVectorToInputStream, _addUintVectorToInputStream, _addStringVectorToInputStream, _addFlatHashMapToInputStream, _addProtoToInputStream, _addEmptyPacketToInputStream, _addBoolToInputSidePacket, _addDoubleToInputSidePacket, _addFloatToInputSidePacket, _addIntToInputSidePacket, _addUintToInputSidePacket, _addStringToInputSidePacket, _addRawDataSpanToInputSidePacket, _addProtoToInputSidePacket, _addBoolVectorToInputSidePacket, _addDoubleVectorToInputSidePacket, _addFloatVectorToInputSidePacket, _addIntVectorToInputSidePacket, _addUintVectorToInputSidePacket, _addStringVectorToInputSidePacket, _attachBoolListener, _attachBoolVectorListener, _attachDoubleListener, _attachDoubleVectorListener, _attachFloatListener, _attachFloatVectorListener, _attachIntListener, _attachIntVectorListener, _attachUintListener, _attachUintVectorListener, _attachStringListener, _attachStringVectorListener, _attachProtoListener, _attachProtoVectorListener, _getGraphConfig, ___getTypeName, _emwgpuCreateBindGroup, _emwgpuCreateBindGroupLayout, _emwgpuCreateCommandBuffer, _emwgpuCreateCommandEncoder, _emwgpuCreateComputePassEncoder, _emwgpuCreateComputePipeline, _emwgpuCreateExternalTexture, _emwgpuCreatePipelineLayout, _emwgpuCreateQuerySet, _emwgpuCreateRenderBundle, _emwgpuCreateRenderBundleEncoder, _emwgpuCreateRenderPassEncoder, _emwgpuCreateRenderPipeline, _emwgpuCreateSampler, _emwgpuCreateSurface, _emwgpuCreateTexture, _emwgpuCreateTextureView, _emwgpuCreateAdapter, _emwgpuImportBuffer, _emwgpuCreateDevice, _emwgpuCreateQueue, _emwgpuCreateShaderModule, _emwgpuOnCreateComputePipelineCompleted, _emwgpuOnWorkDoneCompleted, _clearSubgraphs, _pushBinarySubgraph, _pushTextSubgraph, _changeBinaryGraph, _changeTextGraph, _processGl, _process, _bindTextureToCanvas, _requestShaderRefreshOnGraphChange, _waitUntilIdle, _closeGraph, _setAutoRenderToScreen, _emscripten_builtin_memalign, _memalign, __emscripten_tempret_set, __emscripten_stack_restore, __emscripten_stack_alloc, _emscripten_stack_get_current, dynCall_vii, dynCall_viiiiiii, dynCall_viiiiii, dynCall_v, dynCall_ii, dynCall_vi, dynCall_iiiii, dynCall_iii, dynCall_viii, dynCall_i, dynCall_ji, dynCall_iiii, dynCall_viiii, dynCall_viiiii, dynCall_jii, dynCall_iiiijij, dynCall_ff, dynCall_did, dynCall_iiiiiii, dynCall_iiiiii, dynCall_iiiiiiiiiii, dynCall_iiiiiiiiiiii, dynCall_viji, dynCall_vijiii, dynCall_iiiiiiiii, dynCall_viiiiiiii, dynCall_iiiif, dynCall_viiiiiiiiiiiiiii, dynCall_viff, dynCall_viiffii, dynCall_viiffi, dynCall_viiiiiiiiii, dynCall_fi, dynCall_viiffff, dynCall_viiiiij, dynCall_vij, dynCall_viiiiiffii, dynCall_vif, dynCall_ddd, dynCall_dddd, dynCall_idd, dynCall_di, dynCall_jiiiijiiiii, dynCall_viiij, dynCall_viid, dynCall_vidd, dynCall_vifd, dynCall_viiiiiiiiiii, dynCall_iiif, dynCall_jiii, dynCall_viijj, dynCall_iiiiiiii, dynCall_iiiiiiiiii, dynCall_iij, dynCall_iiiijj, dynCall_viiijjj, dynCall_fff, dynCall_viifii, dynCall_fii, dynCall_jjj, dynCall_fiii, dynCall_viiiiiiiii, dynCall_viiiffii, dynCall_iiiiiffi, dynCall_viiiiiff, dynCall_viiiiiiiiiiiii, dynCall_viiiiiiiiiiii, dynCall_viiiiiiiiiiiiiiiii, dynCall_iifff, dynCall_iiff, dynCall_iiifiii, dynCall_iiffi, dynCall_iiffii, dynCall_viiiiiiiiiiiiii, dynCall_iif, dynCall_viijii, dynCall_iiiji, dynCall_viiif, dynCall_viiifiii, dynCall_fiif, dynCall_iiiifi, dynCall_iiiifiii, dynCall_iiifi, dynCall_viiiif, dynCall_viiiifii, dynCall_dii, dynCall_vifi, dynCall_vidi, dynCall_viiiji, dynCall_viiji, dynCall_vijjj, dynCall_vj, dynCall_viij, dynCall_jiji, dynCall_iidiiii, dynCall_iiiiij, dynCall_iiiiid, dynCall_iiiiijj, dynCall_iiiiiijj, _asyncify_start_unwind, _asyncify_stop_unwind, _asyncify_start_rewind, _asyncify_stop_rewind, memory, _kVersionStampBuildChangelistStr, _kVersionStampCitcSnapshotStr, _kVersionStampCitcWorkspaceIdStr, _kVersionStampSourceUriStr, _kVersionStampBuildClientStr, _kVersionStampBuildClientMintStatusStr, _kVersionStampBuildCompilerStr, _kVersionStampBuildDateTimePstStr, _kVersionStampBuildDepotPathStr, _kVersionStampBuildIdStr, _kVersionStampBuildInfoStr, _kVersionStampBuildLabelStr, _kVersionStampBuildTargetStr, _kVersionStampBuildTimestampStr, _kVersionStampBuildToolStr, _kVersionStampG3BuildTargetStr, _kVersionStampVerifiableStr, _kVersionStampBuildFdoTypeStr, _kVersionStampBuildBaselineChangelistStr, _kVersionStampBuildLtoTypeStr, _kVersionStampBuildPropellerTypeStr, _kVersionStampBuildPghoTypeStr, _kVersionStampBuildUsernameStr, _kVersionStampBuildHostnameStr, _kVersionStampBuildDirectoryStr, _kVersionStampBuildChangelistInt, _kVersionStampCitcSnapshotInt, _kVersionStampBuildClientMintStatusInt, _kVersionStampBuildTimestampInt, _kVersionStampVerifiableInt, _kVersionStampBuildCoverageEnabledInt, _kVersionStampBuildBaselineChangelistInt, _kVersionStampPrecookedTimestampStr, _kVersionStampPrecookedClientInfoStr, __indirect_function_table, wasmMemory; + +function assignWasmExports(wasmExports) { + _free = Module["_free"] = wasmExports["ad"]; + _CreateLlmInferenceEngineConverted = Module["_CreateLlmInferenceEngineConverted"] = wasmExports["bd"]; + _DeleteLlmInferenceEngine = Module["_DeleteLlmInferenceEngine"] = wasmExports["cd"]; + _MakeSessionForPredict = Module["_MakeSessionForPredict"] = wasmExports["dd"]; + _AddTextQueryChunk = Module["_AddTextQueryChunk"] = wasmExports["ed"]; + _AddImageQueryChunk = Module["_AddImageQueryChunk"] = wasmExports["fd"]; + _AddAudioQueryChunk = Module["_AddAudioQueryChunk"] = wasmExports["gd"]; + _malloc = Module["_malloc"] = wasmExports["hd"]; + _PredictSession = Module["_PredictSession"] = wasmExports["id"]; + _FreeSession = Module["_FreeSession"] = wasmExports["jd"]; + _GetSizeInTokens = Module["_GetSizeInTokens"] = wasmExports["kd"]; + _wgpuDeviceAddRef = wasmExports["ld"]; + _registerModelResourcesGraphService = Module["_registerModelResourcesGraphService"] = wasmExports["md"]; + _bindTextureToStream = Module["_bindTextureToStream"] = wasmExports["nd"]; + _addBoundTextureToStream = Module["_addBoundTextureToStream"] = wasmExports["od"]; + _addDoubleToInputStream = Module["_addDoubleToInputStream"] = wasmExports["pd"]; + _addFloatToInputStream = Module["_addFloatToInputStream"] = wasmExports["qd"]; + _addBoolToInputStream = Module["_addBoolToInputStream"] = wasmExports["rd"]; + _addIntToInputStream = Module["_addIntToInputStream"] = wasmExports["sd"]; + _addUintToInputStream = Module["_addUintToInputStream"] = wasmExports["td"]; + _addStringToInputStream = Module["_addStringToInputStream"] = wasmExports["ud"]; + _addRawDataSpanToInputStream = Module["_addRawDataSpanToInputStream"] = wasmExports["vd"]; + _allocateBoolVector = Module["_allocateBoolVector"] = wasmExports["wd"]; + _allocateFloatVector = Module["_allocateFloatVector"] = wasmExports["xd"]; + _allocateDoubleVector = Module["_allocateDoubleVector"] = wasmExports["yd"]; + _allocateIntVector = Module["_allocateIntVector"] = wasmExports["zd"]; + _allocateUintVector = Module["_allocateUintVector"] = wasmExports["Ad"]; + _allocateStringVector = Module["_allocateStringVector"] = wasmExports["Bd"]; + _addBoolVectorEntry = Module["_addBoolVectorEntry"] = wasmExports["Cd"]; + _addFloatVectorEntry = Module["_addFloatVectorEntry"] = wasmExports["Dd"]; + _addDoubleVectorEntry = Module["_addDoubleVectorEntry"] = wasmExports["Ed"]; + _addIntVectorEntry = Module["_addIntVectorEntry"] = wasmExports["Fd"]; + _addUintVectorEntry = Module["_addUintVectorEntry"] = wasmExports["Gd"]; + _addStringVectorEntry = Module["_addStringVectorEntry"] = wasmExports["Hd"]; + _addBoolVectorToInputStream = Module["_addBoolVectorToInputStream"] = wasmExports["Id"]; + _addFloatVectorToInputStream = Module["_addFloatVectorToInputStream"] = wasmExports["Jd"]; + _addDoubleVectorToInputStream = Module["_addDoubleVectorToInputStream"] = wasmExports["Kd"]; + _addIntVectorToInputStream = Module["_addIntVectorToInputStream"] = wasmExports["Ld"]; + _addUintVectorToInputStream = Module["_addUintVectorToInputStream"] = wasmExports["Md"]; + _addStringVectorToInputStream = Module["_addStringVectorToInputStream"] = wasmExports["Nd"]; + _addFlatHashMapToInputStream = Module["_addFlatHashMapToInputStream"] = wasmExports["Od"]; + _addProtoToInputStream = Module["_addProtoToInputStream"] = wasmExports["Pd"]; + _addEmptyPacketToInputStream = Module["_addEmptyPacketToInputStream"] = wasmExports["Qd"]; + _addBoolToInputSidePacket = Module["_addBoolToInputSidePacket"] = wasmExports["Rd"]; + _addDoubleToInputSidePacket = Module["_addDoubleToInputSidePacket"] = wasmExports["Sd"]; + _addFloatToInputSidePacket = Module["_addFloatToInputSidePacket"] = wasmExports["Td"]; + _addIntToInputSidePacket = Module["_addIntToInputSidePacket"] = wasmExports["Ud"]; + _addUintToInputSidePacket = Module["_addUintToInputSidePacket"] = wasmExports["Vd"]; + _addStringToInputSidePacket = Module["_addStringToInputSidePacket"] = wasmExports["Wd"]; + _addRawDataSpanToInputSidePacket = Module["_addRawDataSpanToInputSidePacket"] = wasmExports["Xd"]; + _addProtoToInputSidePacket = Module["_addProtoToInputSidePacket"] = wasmExports["Yd"]; + _addBoolVectorToInputSidePacket = Module["_addBoolVectorToInputSidePacket"] = wasmExports["Zd"]; + _addDoubleVectorToInputSidePacket = Module["_addDoubleVectorToInputSidePacket"] = wasmExports["_d"]; + _addFloatVectorToInputSidePacket = Module["_addFloatVectorToInputSidePacket"] = wasmExports["$d"]; + _addIntVectorToInputSidePacket = Module["_addIntVectorToInputSidePacket"] = wasmExports["ae"]; + _addUintVectorToInputSidePacket = Module["_addUintVectorToInputSidePacket"] = wasmExports["be"]; + _addStringVectorToInputSidePacket = Module["_addStringVectorToInputSidePacket"] = wasmExports["ce"]; + _attachBoolListener = Module["_attachBoolListener"] = wasmExports["de"]; + _attachBoolVectorListener = Module["_attachBoolVectorListener"] = wasmExports["ee"]; + _attachDoubleListener = Module["_attachDoubleListener"] = wasmExports["fe"]; + _attachDoubleVectorListener = Module["_attachDoubleVectorListener"] = wasmExports["ge"]; + _attachFloatListener = Module["_attachFloatListener"] = wasmExports["he"]; + _attachFloatVectorListener = Module["_attachFloatVectorListener"] = wasmExports["ie"]; + _attachIntListener = Module["_attachIntListener"] = wasmExports["je"]; + _attachIntVectorListener = Module["_attachIntVectorListener"] = wasmExports["ke"]; + _attachUintListener = Module["_attachUintListener"] = wasmExports["le"]; + _attachUintVectorListener = Module["_attachUintVectorListener"] = wasmExports["me"]; + _attachStringListener = Module["_attachStringListener"] = wasmExports["ne"]; + _attachStringVectorListener = Module["_attachStringVectorListener"] = wasmExports["oe"]; + _attachProtoListener = Module["_attachProtoListener"] = wasmExports["pe"]; + _attachProtoVectorListener = Module["_attachProtoVectorListener"] = wasmExports["qe"]; + _getGraphConfig = Module["_getGraphConfig"] = wasmExports["re"]; + ___getTypeName = wasmExports["se"]; + _emwgpuCreateBindGroup = wasmExports["te"]; + _emwgpuCreateBindGroupLayout = wasmExports["ue"]; + _emwgpuCreateCommandBuffer = wasmExports["ve"]; + _emwgpuCreateCommandEncoder = wasmExports["we"]; + _emwgpuCreateComputePassEncoder = wasmExports["xe"]; + _emwgpuCreateComputePipeline = wasmExports["ye"]; + _emwgpuCreateExternalTexture = wasmExports["ze"]; + _emwgpuCreatePipelineLayout = wasmExports["Ae"]; + _emwgpuCreateQuerySet = wasmExports["Be"]; + _emwgpuCreateRenderBundle = wasmExports["Ce"]; + _emwgpuCreateRenderBundleEncoder = wasmExports["De"]; + _emwgpuCreateRenderPassEncoder = wasmExports["Ee"]; + _emwgpuCreateRenderPipeline = wasmExports["Fe"]; + _emwgpuCreateSampler = wasmExports["Ge"]; + _emwgpuCreateSurface = wasmExports["He"]; + _emwgpuCreateTexture = wasmExports["Ie"]; + _emwgpuCreateTextureView = wasmExports["Je"]; + _emwgpuCreateAdapter = wasmExports["Ke"]; + _emwgpuImportBuffer = wasmExports["Le"]; + _emwgpuCreateDevice = wasmExports["Me"]; + _emwgpuCreateQueue = wasmExports["Ne"]; + _emwgpuCreateShaderModule = wasmExports["Oe"]; + _emwgpuOnCreateComputePipelineCompleted = wasmExports["Pe"]; + _emwgpuOnWorkDoneCompleted = wasmExports["Qe"]; + _clearSubgraphs = Module["_clearSubgraphs"] = wasmExports["Re"]; + _pushBinarySubgraph = Module["_pushBinarySubgraph"] = wasmExports["Se"]; + _pushTextSubgraph = Module["_pushTextSubgraph"] = wasmExports["Te"]; + _changeBinaryGraph = Module["_changeBinaryGraph"] = wasmExports["Ue"]; + _changeTextGraph = Module["_changeTextGraph"] = wasmExports["Ve"]; + _processGl = Module["_processGl"] = wasmExports["We"]; + _process = Module["_process"] = wasmExports["Xe"]; + _bindTextureToCanvas = Module["_bindTextureToCanvas"] = wasmExports["Ye"]; + _requestShaderRefreshOnGraphChange = Module["_requestShaderRefreshOnGraphChange"] = wasmExports["Ze"]; + _waitUntilIdle = Module["_waitUntilIdle"] = wasmExports["_e"]; + _closeGraph = Module["_closeGraph"] = wasmExports["$e"]; + _setAutoRenderToScreen = Module["_setAutoRenderToScreen"] = wasmExports["af"]; + _emscripten_builtin_memalign = wasmExports["bf"]; + _memalign = wasmExports["cf"]; + __emscripten_tempret_set = wasmExports["df"]; + __emscripten_stack_restore = wasmExports["ef"]; + __emscripten_stack_alloc = wasmExports["ff"]; + _emscripten_stack_get_current = wasmExports["gf"]; + dynCall_vii = dynCalls["vii"] = wasmExports["hf"]; + dynCall_viiiiiii = dynCalls["viiiiiii"] = wasmExports["jf"]; + dynCall_viiiiii = dynCalls["viiiiii"] = wasmExports["kf"]; + dynCall_v = dynCalls["v"] = wasmExports["lf"]; + dynCall_ii = dynCalls["ii"] = wasmExports["mf"]; + dynCall_vi = dynCalls["vi"] = wasmExports["nf"]; + dynCall_iiiii = dynCalls["iiiii"] = wasmExports["of"]; + dynCall_iii = dynCalls["iii"] = wasmExports["pf"]; + dynCall_viii = dynCalls["viii"] = wasmExports["qf"]; + dynCall_i = dynCalls["i"] = wasmExports["rf"]; + dynCall_ji = dynCalls["ji"] = wasmExports["sf"]; + dynCall_iiii = dynCalls["iiii"] = wasmExports["tf"]; + dynCall_viiii = dynCalls["viiii"] = wasmExports["uf"]; + dynCall_viiiii = dynCalls["viiiii"] = wasmExports["vf"]; + dynCall_jii = dynCalls["jii"] = wasmExports["wf"]; + dynCall_iiiijij = dynCalls["iiiijij"] = wasmExports["xf"]; + dynCall_ff = dynCalls["ff"] = wasmExports["yf"]; + dynCall_did = dynCalls["did"] = wasmExports["zf"]; + dynCall_iiiiiii = dynCalls["iiiiiii"] = wasmExports["Af"]; + dynCall_iiiiii = dynCalls["iiiiii"] = wasmExports["Bf"]; + dynCall_iiiiiiiiiii = dynCalls["iiiiiiiiiii"] = wasmExports["Cf"]; + dynCall_iiiiiiiiiiii = dynCalls["iiiiiiiiiiii"] = wasmExports["Df"]; + dynCall_viji = dynCalls["viji"] = wasmExports["Ef"]; + dynCall_vijiii = dynCalls["vijiii"] = wasmExports["Ff"]; + dynCall_iiiiiiiii = dynCalls["iiiiiiiii"] = wasmExports["Gf"]; + dynCall_viiiiiiii = dynCalls["viiiiiiii"] = wasmExports["Hf"]; + dynCall_iiiif = dynCalls["iiiif"] = wasmExports["If"]; + dynCall_viiiiiiiiiiiiiii = dynCalls["viiiiiiiiiiiiiii"] = wasmExports["Jf"]; + dynCall_viff = dynCalls["viff"] = wasmExports["Kf"]; + dynCall_viiffii = dynCalls["viiffii"] = wasmExports["Lf"]; + dynCall_viiffi = dynCalls["viiffi"] = wasmExports["Mf"]; + dynCall_viiiiiiiiii = dynCalls["viiiiiiiiii"] = wasmExports["Nf"]; + dynCall_fi = dynCalls["fi"] = wasmExports["Of"]; + dynCall_viiffff = dynCalls["viiffff"] = wasmExports["Pf"]; + dynCall_viiiiij = dynCalls["viiiiij"] = wasmExports["Qf"]; + dynCall_vij = dynCalls["vij"] = wasmExports["Rf"]; + dynCall_viiiiiffii = dynCalls["viiiiiffii"] = wasmExports["Sf"]; + dynCall_vif = dynCalls["vif"] = wasmExports["Tf"]; + dynCall_ddd = dynCalls["ddd"] = wasmExports["Uf"]; + dynCall_dddd = dynCalls["dddd"] = wasmExports["Vf"]; + dynCall_idd = dynCalls["idd"] = wasmExports["Wf"]; + dynCall_di = dynCalls["di"] = wasmExports["Xf"]; + dynCall_jiiiijiiiii = dynCalls["jiiiijiiiii"] = wasmExports["Yf"]; + dynCall_viiij = dynCalls["viiij"] = wasmExports["Zf"]; + dynCall_viid = dynCalls["viid"] = wasmExports["_f"]; + dynCall_vidd = dynCalls["vidd"] = wasmExports["$f"]; + dynCall_vifd = dynCalls["vifd"] = wasmExports["ag"]; + dynCall_viiiiiiiiiii = dynCalls["viiiiiiiiiii"] = wasmExports["bg"]; + dynCall_iiif = dynCalls["iiif"] = wasmExports["cg"]; + dynCall_jiii = dynCalls["jiii"] = wasmExports["dg"]; + dynCall_viijj = dynCalls["viijj"] = wasmExports["eg"]; + dynCall_iiiiiiii = dynCalls["iiiiiiii"] = wasmExports["fg"]; + dynCall_iiiiiiiiii = dynCalls["iiiiiiiiii"] = wasmExports["gg"]; + dynCall_iij = dynCalls["iij"] = wasmExports["hg"]; + dynCall_iiiijj = dynCalls["iiiijj"] = wasmExports["ig"]; + dynCall_viiijjj = dynCalls["viiijjj"] = wasmExports["jg"]; + dynCall_fff = dynCalls["fff"] = wasmExports["kg"]; + dynCall_viifii = dynCalls["viifii"] = wasmExports["lg"]; + dynCall_fii = dynCalls["fii"] = wasmExports["mg"]; + dynCall_jjj = dynCalls["jjj"] = wasmExports["ng"]; + dynCall_fiii = dynCalls["fiii"] = wasmExports["og"]; + dynCall_viiiiiiiii = dynCalls["viiiiiiiii"] = wasmExports["pg"]; + dynCall_viiiffii = dynCalls["viiiffii"] = wasmExports["qg"]; + dynCall_iiiiiffi = dynCalls["iiiiiffi"] = wasmExports["rg"]; + dynCall_viiiiiff = dynCalls["viiiiiff"] = wasmExports["sg"]; + dynCall_viiiiiiiiiiiii = dynCalls["viiiiiiiiiiiii"] = wasmExports["tg"]; + dynCall_viiiiiiiiiiii = dynCalls["viiiiiiiiiiii"] = wasmExports["ug"]; + dynCall_viiiiiiiiiiiiiiiii = dynCalls["viiiiiiiiiiiiiiiii"] = wasmExports["vg"]; + dynCall_iifff = dynCalls["iifff"] = wasmExports["wg"]; + dynCall_iiff = dynCalls["iiff"] = wasmExports["xg"]; + dynCall_iiifiii = dynCalls["iiifiii"] = wasmExports["yg"]; + dynCall_iiffi = dynCalls["iiffi"] = wasmExports["zg"]; + dynCall_iiffii = dynCalls["iiffii"] = wasmExports["Ag"]; + dynCall_viiiiiiiiiiiiii = dynCalls["viiiiiiiiiiiiii"] = wasmExports["Bg"]; + dynCall_iif = dynCalls["iif"] = wasmExports["Cg"]; + dynCall_viijii = dynCalls["viijii"] = wasmExports["Dg"]; + dynCall_iiiji = dynCalls["iiiji"] = wasmExports["Eg"]; + dynCall_viiif = dynCalls["viiif"] = wasmExports["Fg"]; + dynCall_viiifiii = dynCalls["viiifiii"] = wasmExports["Gg"]; + dynCall_fiif = dynCalls["fiif"] = wasmExports["Hg"]; + dynCall_iiiifi = dynCalls["iiiifi"] = wasmExports["Ig"]; + dynCall_iiiifiii = dynCalls["iiiifiii"] = wasmExports["Jg"]; + dynCall_iiifi = dynCalls["iiifi"] = wasmExports["Kg"]; + dynCall_viiiif = dynCalls["viiiif"] = wasmExports["Lg"]; + dynCall_viiiifii = dynCalls["viiiifii"] = wasmExports["Mg"]; + dynCall_dii = dynCalls["dii"] = wasmExports["Ng"]; + dynCall_vifi = dynCalls["vifi"] = wasmExports["Og"]; + dynCall_vidi = dynCalls["vidi"] = wasmExports["Pg"]; + dynCall_viiiji = dynCalls["viiiji"] = wasmExports["Qg"]; + dynCall_viiji = dynCalls["viiji"] = wasmExports["Rg"]; + dynCall_vijjj = dynCalls["vijjj"] = wasmExports["Sg"]; + dynCall_vj = dynCalls["vj"] = wasmExports["Tg"]; + dynCall_viij = dynCalls["viij"] = wasmExports["Ug"]; + dynCall_jiji = dynCalls["jiji"] = wasmExports["Vg"]; + dynCall_iidiiii = dynCalls["iidiiii"] = wasmExports["Wg"]; + dynCall_iiiiij = dynCalls["iiiiij"] = wasmExports["Xg"]; + dynCall_iiiiid = dynCalls["iiiiid"] = wasmExports["Yg"]; + dynCall_iiiiijj = dynCalls["iiiiijj"] = wasmExports["Zg"]; + dynCall_iiiiiijj = dynCalls["iiiiiijj"] = wasmExports["_g"]; + _asyncify_start_unwind = wasmExports["$g"]; + _asyncify_stop_unwind = wasmExports["ah"]; + _asyncify_start_rewind = wasmExports["bh"]; + _asyncify_stop_rewind = wasmExports["ch"]; + memory = wasmMemory = wasmExports["sc"]; + _kVersionStampBuildChangelistStr = Module["_kVersionStampBuildChangelistStr"] = (wasmExports["uc"].value) >>> 0; + _kVersionStampCitcSnapshotStr = Module["_kVersionStampCitcSnapshotStr"] = (wasmExports["vc"].value) >>> 0; + _kVersionStampCitcWorkspaceIdStr = Module["_kVersionStampCitcWorkspaceIdStr"] = (wasmExports["wc"].value) >>> 0; + _kVersionStampSourceUriStr = Module["_kVersionStampSourceUriStr"] = (wasmExports["xc"].value) >>> 0; + _kVersionStampBuildClientStr = Module["_kVersionStampBuildClientStr"] = (wasmExports["yc"].value) >>> 0; + _kVersionStampBuildClientMintStatusStr = Module["_kVersionStampBuildClientMintStatusStr"] = (wasmExports["zc"].value) >>> 0; + _kVersionStampBuildCompilerStr = Module["_kVersionStampBuildCompilerStr"] = (wasmExports["Ac"].value) >>> 0; + _kVersionStampBuildDateTimePstStr = Module["_kVersionStampBuildDateTimePstStr"] = (wasmExports["Bc"].value) >>> 0; + _kVersionStampBuildDepotPathStr = Module["_kVersionStampBuildDepotPathStr"] = (wasmExports["Cc"].value) >>> 0; + _kVersionStampBuildIdStr = Module["_kVersionStampBuildIdStr"] = (wasmExports["Dc"].value) >>> 0; + _kVersionStampBuildInfoStr = Module["_kVersionStampBuildInfoStr"] = (wasmExports["Ec"].value) >>> 0; + _kVersionStampBuildLabelStr = Module["_kVersionStampBuildLabelStr"] = (wasmExports["Fc"].value) >>> 0; + _kVersionStampBuildTargetStr = Module["_kVersionStampBuildTargetStr"] = (wasmExports["Gc"].value) >>> 0; + _kVersionStampBuildTimestampStr = Module["_kVersionStampBuildTimestampStr"] = (wasmExports["Hc"].value) >>> 0; + _kVersionStampBuildToolStr = Module["_kVersionStampBuildToolStr"] = (wasmExports["Ic"].value) >>> 0; + _kVersionStampG3BuildTargetStr = Module["_kVersionStampG3BuildTargetStr"] = (wasmExports["Jc"].value) >>> 0; + _kVersionStampVerifiableStr = Module["_kVersionStampVerifiableStr"] = (wasmExports["Kc"].value) >>> 0; + _kVersionStampBuildFdoTypeStr = Module["_kVersionStampBuildFdoTypeStr"] = (wasmExports["Lc"].value) >>> 0; + _kVersionStampBuildBaselineChangelistStr = Module["_kVersionStampBuildBaselineChangelistStr"] = (wasmExports["Mc"].value) >>> 0; + _kVersionStampBuildLtoTypeStr = Module["_kVersionStampBuildLtoTypeStr"] = (wasmExports["Nc"].value) >>> 0; + _kVersionStampBuildPropellerTypeStr = Module["_kVersionStampBuildPropellerTypeStr"] = (wasmExports["Oc"].value) >>> 0; + _kVersionStampBuildPghoTypeStr = Module["_kVersionStampBuildPghoTypeStr"] = (wasmExports["Pc"].value) >>> 0; + _kVersionStampBuildUsernameStr = Module["_kVersionStampBuildUsernameStr"] = (wasmExports["Qc"].value) >>> 0; + _kVersionStampBuildHostnameStr = Module["_kVersionStampBuildHostnameStr"] = (wasmExports["Rc"].value) >>> 0; + _kVersionStampBuildDirectoryStr = Module["_kVersionStampBuildDirectoryStr"] = (wasmExports["Sc"].value) >>> 0; + _kVersionStampBuildChangelistInt = Module["_kVersionStampBuildChangelistInt"] = (wasmExports["Tc"].value) >>> 0; + _kVersionStampCitcSnapshotInt = Module["_kVersionStampCitcSnapshotInt"] = (wasmExports["Uc"].value) >>> 0; + _kVersionStampBuildClientMintStatusInt = Module["_kVersionStampBuildClientMintStatusInt"] = (wasmExports["Vc"].value) >>> 0; + _kVersionStampBuildTimestampInt = Module["_kVersionStampBuildTimestampInt"] = (wasmExports["Wc"].value) >>> 0; + _kVersionStampVerifiableInt = Module["_kVersionStampVerifiableInt"] = (wasmExports["Xc"].value) >>> 0; + _kVersionStampBuildCoverageEnabledInt = Module["_kVersionStampBuildCoverageEnabledInt"] = (wasmExports["Yc"].value) >>> 0; + _kVersionStampBuildBaselineChangelistInt = Module["_kVersionStampBuildBaselineChangelistInt"] = (wasmExports["Zc"].value) >>> 0; + _kVersionStampPrecookedTimestampStr = Module["_kVersionStampPrecookedTimestampStr"] = (wasmExports["_c"].value) >>> 0; + _kVersionStampPrecookedClientInfoStr = Module["_kVersionStampPrecookedClientInfoStr"] = (wasmExports["$c"].value) >>> 0; + __indirect_function_table = wasmExports["__indirect_function_table"]; +} + +var wasmImports = { + /** @export */ qc: DefaultErrorReporter, + /** @export */ pc: GetAdapterArchitecture, + /** @export */ oc: GetAdapterDescription, + /** @export */ nc: GetAdapterDeviceName, + /** @export */ mc: GetAdapterVendor, + /** @export */ kc: JsGetDeviceMaxSubgroupSize, + /** @export */ jc: JsGetDeviceMinSubgroupSize, + /** @export */ ic: JsOnEmptyPacketListener, + /** @export */ ma: JsOnSimpleListenerBinaryArray, + /** @export */ hc: JsOnSimpleListenerBool, + /** @export */ gc: JsOnSimpleListenerDouble, + /** @export */ fc: JsOnSimpleListenerFloat, + /** @export */ ec: JsOnSimpleListenerInt, + /** @export */ dc: JsOnSimpleListenerString, + /** @export */ cc: JsOnSimpleListenerUint, + /** @export */ p: JsOnVectorFinishedListener, + /** @export */ bc: JsOnVectorListenerBool, + /** @export */ ac: JsOnVectorListenerDouble, + /** @export */ $b: JsOnVectorListenerFloat, + /** @export */ _b: JsOnVectorListenerInt, + /** @export */ Zb: JsOnVectorListenerProto, + /** @export */ Yb: JsOnVectorListenerString, + /** @export */ Xb: JsOnVectorListenerUint, + /** @export */ la: JsProgressListener, + /** @export */ K: JsWrapErrorListener, + /** @export */ g: JsWrapSimpleListeners, + /** @export */ Wb: ThrowError, + /** @export */ ka: UseBottomLeftGpuOrigin, + /** @export */ Vb: __Unwind_RaiseException, + /** @export */ rc: __asyncjs__CallReadDataFn, + /** @export */ lc: __asyncjs__InvokeReadDataFn, + /** @export */ J: __asyncjs__ReadBufferDataJs, + /** @export */ Ea: __asyncjs__mediapipe_map_buffer_jspi, + /** @export */ Ub: ___syscall_dup, + /** @export */ Tb: ___syscall_faccessat, + /** @export */ ja: ___syscall_fcntl64, + /** @export */ Sb: ___syscall_fstat64, + /** @export */ Va: ___syscall_ftruncate64, + /** @export */ Rb: ___syscall_getcwd, + /** @export */ Qb: ___syscall_getdents64, + /** @export */ Pb: ___syscall_ioctl, + /** @export */ Ob: ___syscall_lstat64, + /** @export */ Nb: ___syscall_mkdirat, + /** @export */ Mb: ___syscall_newfstatat, + /** @export */ ia: ___syscall_openat, + /** @export */ Lb: ___syscall_stat64, + /** @export */ Gb: __abort_js, + /** @export */ Ra: __embind_register_bigint, + /** @export */ Fb: __embind_register_bool, + /** @export */ Eb: __embind_register_emval, + /** @export */ ga: __embind_register_float, + /** @export */ x: __embind_register_function, + /** @export */ n: __embind_register_integer, + /** @export */ e: __embind_register_memory_view, + /** @export */ Db: __embind_register_std_string, + /** @export */ I: __embind_register_std_wstring, + /** @export */ Cb: __embind_register_void, + /** @export */ fa: __emval_create_invoker, + /** @export */ l: __emval_decref, + /** @export */ o: __emval_incref, + /** @export */ ea: __emval_invoke, + /** @export */ da: __emval_run_destructors, + /** @export */ Qa: __gmtime_js, + /** @export */ Pa: __localtime_js, + /** @export */ Oa: __mktime_js, + /** @export */ Na: __mmap_js, + /** @export */ Ma: __munmap_js, + /** @export */ Bb: __tzset_js, + /** @export */ Ua: _clock_time_get, + /** @export */ Ab: custom_emscripten_dbgn, + /** @export */ s: _emscripten_asm_const_int, + /** @export */ H: _emscripten_errn, + /** @export */ zb: _emscripten_get_heap_max, + /** @export */ d: _emscripten_get_now, + /** @export */ ca: _emscripten_has_asyncify, + /** @export */ yb: _emscripten_outn, + /** @export */ xb: _emscripten_pc_get_function, + /** @export */ wb: _emscripten_resize_heap, + /** @export */ ba: _emscripten_stack_snapshot, + /** @export */ vb: _emscripten_stack_unwind_buffer, + /** @export */ ub: _emscripten_webgl_create_context, + /** @export */ tb: _emscripten_webgl_destroy_context, + /** @export */ sb: _emscripten_webgl_get_context_attributes, + /** @export */ r: _emscripten_webgl_get_current_context, + /** @export */ rb: _emscripten_webgl_make_context_current, + /** @export */ aa: _emscripten_webgpu_get_device, + /** @export */ qb: _emwgpuBufferDestroy, + /** @export */ pb: _emwgpuBufferGetMappedRange, + /** @export */ ob: _emwgpuBufferUnmap, + /** @export */ nb: _emwgpuBufferWriteMappedRange, + /** @export */ f: _emwgpuDelete, + /** @export */ mb: _emwgpuDeviceCreateBuffer, + /** @export */ La: _emwgpuDeviceCreateComputePipelineAsync, + /** @export */ lb: _emwgpuDeviceCreateShaderModule, + /** @export */ kb: _emwgpuDeviceDestroy, + /** @export */ Ka: _emwgpuQueueOnSubmittedWorkDone, + /** @export */ jb: _emwgpuWaitAny, + /** @export */ Kb: _environ_get, + /** @export */ Jb: _environ_sizes_get, + /** @export */ ib: _exit, + /** @export */ z: _fd_close, + /** @export */ Ta: _fd_pread, + /** @export */ ha: _fd_read, + /** @export */ Sa: _fd_seek, + /** @export */ y: _fd_write, + /** @export */ G: _glActiveTexture, + /** @export */ $: _glAttachShader, + /** @export */ hb: _glBindAttribLocation, + /** @export */ m: _glBindBuffer, + /** @export */ w: _glBindFramebuffer, + /** @export */ k: _glBindTexture, + /** @export */ F: _glBufferData, + /** @export */ q: _glClientWaitSync, + /** @export */ gb: _glCompileShader, + /** @export */ fb: _glCreateProgram, + /** @export */ eb: _glCreateShader, + /** @export */ _: _glDeleteFramebuffers, + /** @export */ db: _glDeleteProgram, + /** @export */ Z: _glDeleteShader, + /** @export */ v: _glDeleteSync, + /** @export */ Y: _glDeleteTextures, + /** @export */ X: _glDetachShader, + /** @export */ W: _glDisableVertexAttribArray, + /** @export */ cb: _glDrawArrays, + /** @export */ V: _glEnableVertexAttribArray, + /** @export */ U: _glFenceSync, + /** @export */ u: _glFinish, + /** @export */ E: _glFramebufferTexture2D, + /** @export */ T: _glGenBuffers, + /** @export */ bb: _glGenFramebuffers, + /** @export */ D: _glGenTextures, + /** @export */ t: _glGetError, + /** @export */ S: _glGetIntegerv, + /** @export */ C: _glGetString, + /** @export */ ab: _glGetUniformLocation, + /** @export */ $a: _glLinkProgram, + /** @export */ B: _glPixelStorei, + /** @export */ R: _glReadPixels, + /** @export */ _a: _glShaderSource, + /** @export */ Za: _glTexImage2D, + /** @export */ j: _glTexParameteri, + /** @export */ Q: _glTexStorage2D, + /** @export */ Ya: _glUniform1i, + /** @export */ Xa: _glUseProgram, + /** @export */ P: _glVertexAttribPointer, + /** @export */ Wa: _glViewport, + /** @export */ A: hardware_concurrency, + /** @export */ Ib: _proc_exit, + /** @export */ Hb: _random_get, + /** @export */ Ja: _wgpuBufferGetSize, + /** @export */ Ia: _wgpuBufferGetUsage, + /** @export */ i: _wgpuCommandEncoderBeginComputePass, + /** @export */ Ha: _wgpuCommandEncoderCopyBufferToBuffer, + /** @export */ O: _wgpuCommandEncoderCopyTextureToBuffer, + /** @export */ Da: _wgpuCommandEncoderCopyTextureToTexture, + /** @export */ c: _wgpuCommandEncoderFinish, + /** @export */ Ga: _wgpuCommandEncoderResolveQuerySet, + /** @export */ N: _wgpuComputePassEncoderDispatchWorkgroups, + /** @export */ h: _wgpuComputePassEncoderEnd, + /** @export */ Ca: _wgpuComputePassEncoderSetBindGroup, + /** @export */ M: _wgpuComputePassEncoderSetPipeline, + /** @export */ Ba: _wgpuDeviceCreateBindGroup, + /** @export */ Aa: _wgpuDeviceCreateBindGroupLayout, + /** @export */ b: _wgpuDeviceCreateCommandEncoder, + /** @export */ za: _wgpuDeviceCreateComputePipeline, + /** @export */ ya: _wgpuDeviceCreatePipelineLayout, + /** @export */ xa: _wgpuDeviceCreateQuerySet, + /** @export */ wa: _wgpuDeviceCreateTexture, + /** @export */ L: _wgpuDeviceGetAdapterInfo, + /** @export */ va: _wgpuDeviceGetLimits, + /** @export */ ua: _wgpuDeviceHasFeature, + /** @export */ a: _wgpuQueueSubmit, + /** @export */ Fa: _wgpuQueueWriteBuffer, + /** @export */ ta: _wgpuQueueWriteTexture, + /** @export */ sa: _wgpuTextureCreateView, + /** @export */ ra: _wgpuTextureDestroy, + /** @export */ qa: _wgpuTextureGetDepthOrArrayLayers, + /** @export */ pa: _wgpuTextureGetFormat, + /** @export */ oa: _wgpuTextureGetHeight, + /** @export */ na: _wgpuTextureGetWidth +}; + +// Argument name here must shadow the `wasmExports` global so +// that it is recognised by metadce and minify-import-export-names +// passes. +function applySignatureConversions(wasmExports) { + // First, make a copy of the incoming exports object + wasmExports = Object.assign({}, wasmExports); + var makeWrapper_pp = f => a0 => f(a0) >>> 0; + var makeWrapper_ppp = f => (a0, a1) => f(a0, a1) >>> 0; + var makeWrapper_p = f => () => f() >>> 0; + wasmExports["hd"] = makeWrapper_pp(wasmExports["hd"]); + wasmExports["se"] = makeWrapper_pp(wasmExports["se"]); + wasmExports["bf"] = makeWrapper_ppp(wasmExports["bf"]); + wasmExports["cf"] = makeWrapper_ppp(wasmExports["cf"]); + wasmExports["ff"] = makeWrapper_pp(wasmExports["ff"]); + wasmExports["gf"] = makeWrapper_p(wasmExports["gf"]); + return wasmExports; +} + +// include: postamble.js +// === Auto-generated postamble setup entry stuff === +function run() { + if (runDependencies > 0) { + dependenciesFulfilled = run; + return; + } + preRun(); + // a preRun added a dependency, run will be called later + if (runDependencies > 0) { + dependenciesFulfilled = run; + return; + } + function doRun() { + // run may have just been called through dependencies being fulfilled just in this very frame, + // or while the async setStatus time below was happening + Module["calledRun"] = true; + if (ABORT) return; + initRuntime(); + readyPromiseResolve?.(Module); + Module["onRuntimeInitialized"]?.(); + postRun(); + } + if (Module["setStatus"]) { + Module["setStatus"]("Running..."); + setTimeout(() => { + setTimeout(() => Module["setStatus"](""), 1); + doRun(); + }, 1); + } else { + doRun(); + } +} + +var wasmExports; + +// In modularize mode the generated code is within a factory function so we +// can use await here (since it's not top-level-await). +wasmExports = await (createWasm()); + +run(); + +// end include: postamble.js +// include: postamble_modularize.js +// In MODULARIZE mode we wrap the generated code in a factory function +// and return either the Module itself, or a promise of the module. +// We assign to the `moduleRtn` global here and configure closure to see +// this as an extern so it won't get minified. +if (runtimeInitialized) { + moduleRtn = Module; +} else { + // Set up the promise that indicates the Module is initialized + moduleRtn = new Promise((resolve, reject) => { + readyPromiseResolve = resolve; + readyPromiseReject = reject; + }); +} + + + return moduleRtn; +} + +// Export using a UMD style export, or ES6 exports if selected +export default ModuleFactory; + diff --git a/public/mediapipe/wasm/genai_wasm_module_internal.wasm b/public/mediapipe/wasm/genai_wasm_module_internal.wasm new file mode 100644 index 0000000..a16e3a7 Binary files /dev/null and b/public/mediapipe/wasm/genai_wasm_module_internal.wasm differ diff --git a/public/prompts/system_compact.md b/public/prompts/system_compact.md new file mode 100644 index 0000000..8c6a5da --- /dev/null +++ b/public/prompts/system_compact.md @@ -0,0 +1,102 @@ +You are K.G.Studio Music Assistant Agent. + +You are a skilled AI music assistant focused on composition, harmony, arrangement, MIDI editing, and music production. + +Your job: +- Understand the user request +- Read existing music if needed +- Edit music step-by-step using tools +- Make musically coherent decisions +- Return a short summary after finishing + +==== + +TOOLS + +## read_music +Reads existing music in ABC notation. + +## remove_notes +Removes notes from a beat range. + +## add_notes +Adds notes to the current region. + +Pitch format: +- Scientific notation +- Examples: C4, F#3, Bb2 + +Important: +- `start` is ALWAYS the absolute beat position in the project timeline. + +==== + +TOOL RULES + +- Use tools step-by-step. +- Check tool results before continuing. +- Do not assume success. +- If information is missing, ask the user. +- Use `read_music` before editing when musical context is needed. +- Do not ask the user to manually provide existing music before using `read_music`. + +==== + +EDITING RULES + +When adding notes: +- Explicitly include ALL notes. +- Never omit repeated notes with "..." or summaries. +- Chords = multiple notes sharing the same `start`. +- Melodies = sequential `start` values. + +Before adding notes: +- Remove conflicting notes if necessary. +- Avoid stacking unintended duplicate notes. + +Music quality guidelines: +- Stay in key unless stylistically appropriate. +- Use reasonable instrument ranges. +- Respect the time signature grid. +- Keep harmony and rhythm musically coherent. +- Prefer smooth melodic and harmonic movement. + +==== + +DRUM NOTE MAP + +Common drum pitches: +- C2 = Kick +- D2 = Snare +- F#2 = Closed Hi-Hat +- Bb2 = Open Hi-Hat +- Db3 = Crash +- Eb3 = Ride + +==== + +CAPABILITIES + +You can: +- Analyze existing music +- Continue musical ideas +- Create melodies, chords, basslines, and drums +- Adapt to musical style and genre +- Make arrangement decisions using music theory knowledge + +Project information such as BPM, key, time signature, track instrument, and region boundaries will be provided dynamically. + +Focus mainly on the current region. + +==== + +WORKFLOW + +1. Understand the task +2. Read music if needed +3. Plan musical changes +4. Edit step-by-step with tools +5. Verify results +6. Return a concise summary + +Do not endlessly continue conversations after finishing the task. \ No newline at end of file diff --git a/src/agent/core/AgentCore.ts b/src/agent/core/AgentCore.ts index c943c3d..d404c2f 100644 --- a/src/agent/core/AgentCore.ts +++ b/src/agent/core/AgentCore.ts @@ -1,4 +1,4 @@ -import { LLMProvider } from '../llm/LLMProvider'; +import type { LLMProvider } from '../llm/LLMProvider'; import { AgentState } from './AgentState'; import { SystemPrompts } from './SystemPrompts'; import { AVAILABLE_TOOLS } from '../tools'; @@ -92,7 +92,9 @@ export class AgentCore { // Add user message to state this.currentUserMessageId = this.agentState.addMessage('user', userInput); - const systemPrompt = await SystemPrompts.getSystemPromptWithContext(); + const systemPrompt = await SystemPrompts.getSystemPromptWithContext( + this.llmProvider.getPreferredSystemPromptPath?.(), + ); const tools = this.getToolDefinitions(); try { diff --git a/src/agent/core/SystemPrompts.ts b/src/agent/core/SystemPrompts.ts index 1f20d2d..9f4e80d 100644 --- a/src/agent/core/SystemPrompts.ts +++ b/src/agent/core/SystemPrompts.ts @@ -22,25 +22,26 @@ interface SystemPromptContext { * System prompts for the AI agent with dynamic context loading */ export class SystemPrompts { - private static cachedTemplate: string | null = null; + private static cachedTemplates: Map = new Map(); private static readonly FALLBACK_PROMPT = `You are K.G.Studio Musician Assistant Agent, a highly skilled music musician with extensive knowledge in music theory, composition, and production.`; /** * Load the system prompt template from the public folder */ - private static async loadTemplate(): Promise { - if (this.cachedTemplate) { - return this.cachedTemplate; + private static async loadTemplate(templatePath: string = 'prompts/system.md'): Promise { + if (this.cachedTemplates.has(templatePath)) { + return this.cachedTemplates.get(templatePath)!; } try { - const response = await fetch(`${import.meta.env.BASE_URL}prompts/system.md`); + const response = await fetch(`${import.meta.env.BASE_URL}${templatePath}`); if (!response.ok) { throw new Error(`Failed to load system prompt: ${response.status}`); } - this.cachedTemplate = await response.text(); - return this.cachedTemplate; + const template = await response.text(); + this.cachedTemplates.set(templatePath, template); + return template; } catch (error) { console.error('Failed to load system prompt template:', error); return this.FALLBACK_PROMPT; @@ -231,9 +232,9 @@ export class SystemPrompts { /** * Get the system prompt with current context applied (backward compatible) */ - static async getSystemPromptWithContext(): Promise { + static async getSystemPromptWithContext(templatePath?: string): Promise { try { - const template = await this.loadTemplate(); + const template = await this.loadTemplate(templatePath); let promptWithContext = await this.getPromptWithContext(template); // Append custom instructions from config if provided @@ -263,4 +264,4 @@ export class SystemPrompts { static clearCache(): void { this.cachedTemplate = null; } -} \ No newline at end of file +} diff --git a/src/agent/llm/LLMProvider.ts b/src/agent/llm/LLMProvider.ts index ad896e8..7a8db11 100644 --- a/src/agent/llm/LLMProvider.ts +++ b/src/agent/llm/LLMProvider.ts @@ -3,16 +3,24 @@ import type { StreamChunk } from './StreamingTypes'; import type { Message, ToolCall } from '../core/AgentState'; import type { OpenAIToolDefinition } from '../tools/BaseTool'; +export interface LLMProvider { + getPreferredSystemPromptPath?(): string | undefined; + generateStream( + messages: Message[], + systemPrompt?: string, + tools?: OpenAIToolDefinition[], + ): AsyncIterableIterator; +} + /** - * LLM provider using the OpenAI SDK. - * Works with any OpenAI-compatible API (OpenAI, OpenRouter, Ollama, vLLM, etc.) + * OpenAI-compatible provider implementation. + * Works with OpenAI and OpenAI-compatible APIs (OpenRouter, Ollama, vLLM, etc.) */ -export class LLMProvider { +export class OpenAICompatibleLLMProvider implements LLMProvider { private client: OpenAI; private model: string; constructor(apiKey: string, model: string, baseURL?: string) { - // The OpenAI SDK appends /chat/completions itself, so strip it if the user included it const normalizedBaseURL = baseURL?.replace(/\/chat\/completions\/?$/, '') || undefined; this.client = new OpenAI({ @@ -23,12 +31,9 @@ export class LLMProvider { this.model = model; } - /** - * Convert internal Message[] to OpenAI ChatCompletionMessageParam[] - */ private convertMessages( messages: Message[], - systemPrompt?: string + systemPrompt?: string, ): OpenAI.ChatCompletionMessageParam[] { const result: OpenAI.ChatCompletionMessageParam[] = []; @@ -64,10 +69,6 @@ export class LLMProvider { return result; } - /** - * Generate a streaming response from the LLM. - * Yields StreamChunks for text content and tool calls. - */ async *generateStream( messages: Message[], systemPrompt?: string, @@ -87,8 +88,6 @@ export class LLMProvider { } const stream = this.client.chat.completions.stream(requestParams); - - // Accumulate tool calls across chunks (they arrive incrementally) const toolCallAccumulator = new Map(); for await (const chunk of stream) { @@ -97,23 +96,18 @@ export class LLMProvider { if (!choice) continue; const delta = choice.delta; - - // Yield text content if (delta.content) { yield { type: 'text', content: delta.content }; } - // Accumulate tool calls from deltas if (delta.tool_calls) { for (const tc of delta.tool_calls) { const existing = toolCallAccumulator.get(tc.index); if (existing) { - // Append to existing tool call if (tc.function?.arguments) { existing.arguments += tc.function.arguments; } } else { - // New tool call toolCallAccumulator.set(tc.index, { id: tc.id ?? '', name: tc.function?.name ?? '', @@ -124,11 +118,9 @@ export class LLMProvider { } } - // After stream ends, get the final completion for finish_reason const finalCompletion = await stream.finalChatCompletion(); const finishReason = finalCompletion.choices[0]?.finish_reason ?? 'stop'; - // Emit accumulated tool calls if (toolCallAccumulator.size > 0) { for (const [, tc] of toolCallAccumulator) { const toolCall: ToolCall = { @@ -140,7 +132,6 @@ export class LLMProvider { } } - // Signal completion yield { type: 'done', content: '', finishReason }; } } diff --git a/src/agent/llm/LocalBrowserLLMProvider.ts b/src/agent/llm/LocalBrowserLLMProvider.ts new file mode 100644 index 0000000..9b8b9cb --- /dev/null +++ b/src/agent/llm/LocalBrowserLLMProvider.ts @@ -0,0 +1,301 @@ +import type { StreamChunk } from './StreamingTypes'; +import type { Message, ToolCall } from '../core/AgentState'; +import type { OpenAIToolDefinition } from '../tools/BaseTool'; +import { LocalLLMModelManager } from '../../util/localLLMModelManager'; +import { + formatToolCall, + formatToolDeclaration, + formatToolResponse, + parseToolCalls, + stripToolProtocol, +} from './gemmaToolProtocol'; +import { LOCAL_LLM_MODEL_FILENAME, LOCAL_LLM_MODEL_URL } from '../../util/localLLMConfig'; +import { LocalLLMModelCache } from '../../util/localLLMModelCache'; +import type { LLMProvider } from './LLMProvider'; + +type MediaPipeGenAI = { + FilesetResolver: { + forGenAiTasks(basePath: string): Promise; + }; + LlmInference: { + createFromOptions(fileset: unknown, options: Record): Promise; + }; +}; + +type GemmaInference = { + generateResponse( + prompt: string, + callback: (partial: string, done: boolean) => void, + ): Promise | void; + sizeInTokens(text: string): number; + close?: () => void; +}; + +interface PromptTemplatePart { + pre: string; + post: string; +} + +const PROMPT_TEMPLATE: Record<'user' | 'model' | 'system', PromptTemplatePart> = { + user: { pre: '<|turn>user\n', post: '\n' }, + model: { pre: '<|turn>model\n', post: '\n' }, + system: { pre: '<|turn>system\n', post: '\n' }, +}; + +async function importMediaPipe(): Promise { + const bundleUrl = new URL(`${import.meta.env.BASE_URL}mediapipe/genai_bundle.mjs`, window.location.origin).href; + return import(/* @vite-ignore */ bundleUrl) as Promise; +} + +export class LocalBrowserLLMProvider implements LLMProvider { + private inference: GemmaInference | null = null; + + getPreferredSystemPromptPath(): string | undefined { + return 'prompts/system_compact.md'; + } + + private async ensureInference(): Promise { + await LocalLLMModelManager.ensureRuntimeSupported(); + if (this.inference) { + return this.inference; + } + + const [{ FilesetResolver, LlmInference }, modelLoad] = await Promise.all([ + this.getMediaPipeModule(), + LocalLLMModelCache.loadModelReaderWithCache( + LOCAL_LLM_MODEL_URL, + LOCAL_LLM_MODEL_FILENAME, + progress => { + if (progress.fromCache) { + LocalLLMModelManager.notifyLoadStart(true); + } else { + LocalLLMModelManager.notifyLoadProgress(progress.receivedBytes, progress.totalBytes, false); + } + }, + ), + ]); + + LocalLLMModelManager.notifyLoadStart(modelLoad.fromCache); + console.log('[localLLM] Model stream prepared for MediaPipe.', { + filename: LOCAL_LLM_MODEL_FILENAME, + totalBytes: modelLoad.totalBytes, + fromCache: modelLoad.fromCache, + }); + + const fileset = await FilesetResolver.forGenAiTasks(`${import.meta.env.BASE_URL}mediapipe/wasm`); + console.log('[localLLM] MediaPipe fileset resolved. Creating inference engine...'); + try { + this.inference = await LlmInference.createFromOptions(fileset, { + baseOptions: { + modelAssetBuffer: modelLoad.reader, + }, + numResponses: 1, + maxTokens: 32768, + topK: 64, + temperature: 1.0, + }); + console.log('[localLLM] MediaPipe inference engine created successfully.'); + if (modelLoad.cacheWritePromise) { + void modelLoad.cacheWritePromise.then(() => { + LocalLLMModelManager.notifyCacheReady(); + }).catch(error => { + console.error('[localLLM] Background cache write failed after inference creation.', error); + LocalLLMModelManager.notifyLoadError(error); + }); + } else { + LocalLLMModelManager.notifyCacheReady(); + } + return this.inference; + } catch (error) { + LocalLLMModelManager.notifyLoadError(error); + throw error; + } + } + + private async getMediaPipeModule(): Promise { + return importMediaPipe(); + } + + private applyTemplate(message: { role: 'user' | 'model'; text: string }): string { + const template = PROMPT_TEMPLATE[message.role]; + return `${template.pre}${message.text}${template.post}`; + } + + private renderPrompt( + messages: Message[], + systemPrompt: string | undefined, + tools: OpenAIToolDefinition[] | undefined, + ): string { + const thinkPrefix = '<|think|>'; + const toolDeclarations = (tools ?? []).map(formatToolDeclaration).join(''); + const systemContent = `${thinkPrefix}${systemPrompt ?? ''}${toolDeclarations}`; + const systemSection = systemContent + ? `${PROMPT_TEMPLATE.system.pre}${systemContent}${PROMPT_TEMPLATE.system.post}` + : ''; + + const conversationParts: string[] = []; + + for (let i = 0; i < messages.length; i += 1) { + const message = messages[i]; + if (message.role === 'user') { + conversationParts.push(this.applyTemplate({ role: 'user', text: message.content ?? '' })); + continue; + } + + if (message.role === 'assistant') { + let modelText = message.content ?? ''; + if (message.tool_calls?.length) { + for (const toolCall of message.tool_calls) { + modelText += formatToolCall(toolCall.function.name, toolCall.function.arguments); + } + + let scanIndex = i + 1; + while (scanIndex < messages.length && messages[scanIndex].role === 'tool') { + const toolMessage = messages[scanIndex]; + const matchedCall = message.tool_calls.find(call => call.id === toolMessage.tool_call_id); + if (matchedCall) { + let parsedResult: unknown = toolMessage.content ?? ''; + try { + parsedResult = JSON.parse(toolMessage.content ?? '{}'); + } catch { + parsedResult = toolMessage.content ?? ''; + } + modelText += formatToolResponse(matchedCall.function.name, parsedResult); + } + scanIndex += 1; + } + } + + conversationParts.push(this.applyTemplate({ role: 'model', text: modelText })); + } + } + + return `${systemSection}${conversationParts.join('')}${PROMPT_TEMPLATE.model.pre}`; + } + + async *generateStream( + messages: Message[], + systemPrompt?: string, + tools?: OpenAIToolDefinition[], + ): AsyncIterableIterator { + const inference = await this.ensureInference(); + const prompt = this.renderPrompt(messages, systemPrompt, tools); + console.log('------------ LOCAL RAW PROMPT ------------'); + console.log(prompt); + console.log('------------------------------------------'); + + const start = performance.now(); + let firstTokenTime: number | null = null; + let rawResponse = ''; + let streamedVisibleText = ''; + const pendingTextDeltas: string[] = []; + let generationError: unknown = null; + let generationDone = false; + let notifyWaiting: (() => void) | null = null; + + const wake = () => { + if (notifyWaiting) { + const resolve = notifyWaiting; + notifyWaiting = null; + resolve(); + } + }; + + const generationPromise = new Promise((resolve, reject) => { + try { + const result = inference.generateResponse(prompt, (partial, done) => { + if (firstTokenTime === null) { + firstTokenTime = performance.now(); + } + rawResponse += partial; + + const visibleText = stripToolProtocol(rawResponse); + if (visibleText.startsWith(streamedVisibleText)) { + const delta = visibleText.slice(streamedVisibleText.length); + if (delta) { + streamedVisibleText = visibleText; + pendingTextDeltas.push(delta); + wake(); + } + } else if (visibleText && visibleText !== streamedVisibleText) { + const delta = visibleText.slice(streamedVisibleText.length) || visibleText; + streamedVisibleText = visibleText; + pendingTextDeltas.push(delta); + wake(); + } + + if (done) { + generationDone = true; + wake(); + setTimeout(resolve, 0); + } + }); + + Promise.resolve(result).catch(error => { + generationError = error; + generationDone = true; + wake(); + reject(error); + }); + } catch (error) { + generationError = error; + generationDone = true; + wake(); + reject(error); + } + }); + + while (!generationDone || pendingTextDeltas.length > 0) { + while (pendingTextDeltas.length > 0) { + const delta = pendingTextDeltas.shift(); + if (delta) { + yield { type: 'text', content: delta }; + } + } + + if (generationDone) { + break; + } + + await new Promise(resolve => { + notifyWaiting = resolve; + }); + } + + await generationPromise; + if (generationError) { + throw generationError; + } + + console.log('------------ LOCAL RAW RESPONSE ------------'); + console.log(rawResponse); + console.log('--------------------------------------------'); + + const toolCalls = parseToolCalls(rawResponse); + const finishReason = toolCalls.length > 0 ? 'tool_calls' : 'stop'; + + const promptTokenCount = inference.sizeInTokens(prompt); + const generatedTokenCount = inference.sizeInTokens(rawResponse); + const totalEnd = performance.now(); + const prefillMs = firstTokenTime !== null ? firstTokenTime - start : 0; + const decodeMs = Math.max(0, totalEnd - start - prefillMs); + const prefillTps = prefillMs > 0 ? promptTokenCount / (prefillMs / 1000) : 0; + const generationTps = decodeMs > 0 ? generatedTokenCount / (decodeMs / 1000) : 0; + console.log(`[localLLM] prefill t/s: ${prefillTps.toFixed(1)}`); + console.log(`[localLLM] generation t/s: ${generationTps.toFixed(1)}`); + + for (const parsed of toolCalls) { + const toolCall: ToolCall = { + id: `gemma_tool_${Date.now()}_${Math.random().toString(36).slice(2)}`, + type: 'function', + function: { + name: parsed.name, + arguments: JSON.stringify(parsed.args), + }, + }; + yield { type: 'tool_call', content: '', toolCall }; + } + + yield { type: 'done', content: '', finishReason }; + } +} diff --git a/src/agent/llm/gemmaToolProtocol.streaming.test.ts b/src/agent/llm/gemmaToolProtocol.streaming.test.ts new file mode 100644 index 0000000..04a388e --- /dev/null +++ b/src/agent/llm/gemmaToolProtocol.streaming.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; +import { stripToolProtocol } from './gemmaToolProtocol'; + +describe('stripToolProtocol streaming safety', () => { + it('hides incomplete thought blocks entirely until they are closed', () => { + const partial = `<|channel>thought +I have successfully read the music. +I will summarize this for the user.`; + + expect(stripToolProtocol(partial)).toBe(''); + }); + + it('reveals visible answer cleanly after a thought block closes', () => { + const completed = `<|channel>thought +Internal reasoning here. +Here is the sheet music I read.`; + + expect(stripToolProtocol(completed)).toBe('Here is the sheet music I read.'); + }); +}); diff --git a/src/agent/llm/gemmaToolProtocol.test.ts b/src/agent/llm/gemmaToolProtocol.test.ts new file mode 100644 index 0000000..1e64207 --- /dev/null +++ b/src/agent/llm/gemmaToolProtocol.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from 'vitest'; +import { parseToolCalls } from './gemmaToolProtocol'; + +describe('parseToolCalls', () => { + it('parses nested object arguments emitted by Gemma tool calling', () => { + const text = '<|tool_call>call:add_notes{notes:[{pitch:<|"|>C4<|"|>,meta:{velocity:90,length:1.5}}],replaceExisting:false}'; + + const parsed = parseToolCalls(text); + + expect(parsed).toHaveLength(1); + expect(parsed[0].name).toBe('add_notes'); + expect(parsed[0].args).toEqual({ + notes: [ + { + pitch: 'C4', + meta: { + velocity: 90, + length: 1.5, + }, + }, + ], + replaceExisting: false, + }); + }); +}); diff --git a/src/agent/llm/gemmaToolProtocol.ts b/src/agent/llm/gemmaToolProtocol.ts new file mode 100644 index 0000000..2079755 --- /dev/null +++ b/src/agent/llm/gemmaToolProtocol.ts @@ -0,0 +1,154 @@ +import type { OpenAIToolDefinition } from '../tools/BaseTool'; + +function gemmaValue(value: unknown): string { + if (typeof value === 'string') return `<|"|>${value}<|"|>`; + if (Array.isArray(value)) return `[${value.map(gemmaValue).join(',')}]`; + if (typeof value === 'object' && value !== null) { + return `{${Object.entries(value as Record).map(([key, nested]) => `${key}:${gemmaValue(nested)}`).join(',')}}`; + } + return String(value); +} + +export function formatToolDeclaration(tool: OpenAIToolDefinition): string { + const body = { + description: tool.function.description, + parameters: tool.function.parameters, + }; + return `<|tool>declaration:${tool.function.name}${gemmaValue(body)}`; +} + +export function formatToolCall(name: string, args: string): string { + const parsed = JSON.parse(args) as Record; + return `<|tool_call>call:${name}${gemmaValue(parsed)}`; +} + +export function formatToolResponse(name: string, result: unknown): string { + return `<|tool_response>response:${name}${gemmaValue(result)}`; +} + +function parseGemmaValue(str: string, pos: number): { value: unknown; next: number } { + while (pos < str.length && str[pos] === ' ') pos += 1; + + const stringDelimiter = '<|"|>'; + if (str.startsWith(stringDelimiter, pos)) { + const start = pos + stringDelimiter.length; + const end = str.indexOf(stringDelimiter, start); + if (end === -1) { + return { value: '', next: str.length }; + } + return { value: str.slice(start, end), next: end + stringDelimiter.length }; + } + + if (str[pos] === '{') { + const result: Record = {}; + pos += 1; + while (pos < str.length && str[pos] !== '}') { + while (pos < str.length && (str[pos] === ',' || str[pos] === ' ')) pos += 1; + if (str[pos] === '}') break; + const colonIndex = str.indexOf(':', pos); + if (colonIndex === -1) break; + const key = str.slice(pos, colonIndex).trim(); + pos = colonIndex + 1; + const nested = parseGemmaValue(str, pos); + result[key] = nested.value; + pos = nested.next; + } + return { value: result, next: pos + 1 }; + } + + if (str[pos] === '[') { + const result: unknown[] = []; + pos += 1; + while (pos < str.length && str[pos] !== ']') { + while (pos < str.length && (str[pos] === ',' || str[pos] === ' ')) pos += 1; + if (str[pos] === ']') break; + const nested = parseGemmaValue(str, pos); + result.push(nested.value); + pos = nested.next; + } + return { value: result, next: pos + 1 }; + } + + let end = pos; + while (end < str.length && str[end] !== ',' && str[end] !== '}' && str[end] !== ']') end += 1; + const raw = str.slice(pos, end).trim(); + if (raw === 'true') return { value: true, next: end }; + if (raw === 'false') return { value: false, next: end }; + if (raw !== '' && !Number.isNaN(Number(raw))) return { value: Number(raw), next: end }; + return { value: raw, next: end }; +} + +function parseArgs(argsStr: string): Record { + const parsed = parseGemmaValue(`{${argsStr}}`, 0).value; + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { + return {}; + } + return parsed as Record; +} + +export interface ParsedGemmaToolCall { + name: string; + args: Record; + fullMatch: string; + index: number; + endIndex: number; +} + +export function parseToolCalls(text: string): ParsedGemmaToolCall[] { + const prefix = '<|tool_call>call:'; + const suffix = ''; + const stringDelimiter = '<|"|>'; + const calls: ParsedGemmaToolCall[] = []; + let searchFrom = 0; + + while (true) { + const prefixIndex = text.indexOf(prefix, searchFrom); + if (prefixIndex === -1) break; + + const braceStart = text.indexOf('{', prefixIndex + prefix.length); + if (braceStart === -1) break; + const name = text.slice(prefixIndex + prefix.length, braceStart).trim(); + + let depth = 1; + let index = braceStart + 1; + while (index < text.length && depth > 0) { + if (text.startsWith(stringDelimiter, index)) { + const stringEnd = text.indexOf(stringDelimiter, index + stringDelimiter.length); + index = stringEnd === -1 ? text.length : stringEnd + stringDelimiter.length; + continue; + } + if (text[index] === '{') depth += 1; + else if (text[index] === '}') depth -= 1; + index += 1; + } + const braceEnd = index; + const suffixIndex = text.indexOf(suffix, braceEnd); + if (suffixIndex === -1) break; + + const argsStr = text.slice(braceStart + 1, braceEnd - 1); + const endIndex = suffixIndex + suffix.length; + calls.push({ + name, + args: parseArgs(argsStr), + fullMatch: text.slice(prefixIndex, endIndex), + index: prefixIndex, + endIndex, + }); + searchFrom = endIndex; + } + + return calls; +} + +export function stripToolProtocol(text: string): string { + let result = text.replace( + /<\|tool_call>call:(\w+)\{[\s\S]*?\}<\|tool_response>[\s\S]*?/g, + '[Tool call completed]', + ); + result = result.replace(/<\|channel>thought[\s\S]*?/g, ''); + result = result.replace(/<\|channel>thought[\s\S]*/g, ''); + result = result.replace(/<\|tool_call>[\s\S]*/g, ''); + result = result.replace(/<\|tool_response>[\s\S]*/g, ''); + result = result.replace(/<\|"\|>/g, ''); + return result.trimStart(); +} diff --git a/src/components/ChatBox.tsx b/src/components/ChatBox.tsx index c2736b4..2b9940a 100644 --- a/src/components/ChatBox.tsx +++ b/src/components/ChatBox.tsx @@ -3,7 +3,8 @@ import './ChatBox.css'; import { FaPlus, FaBan, FaDownload } from 'react-icons/fa'; import { UserMessage, AssistantMessage } from './chat'; import { AgentCore } from '../agent/core/AgentCore'; -import { LLMProvider } from '../agent/llm/LLMProvider'; +import { OpenAICompatibleLLMProvider, type LLMProvider } from '../agent/llm/LLMProvider'; +import { LocalBrowserLLMProvider } from '../agent/llm/LocalBrowserLLMProvider'; import { ConfigManager } from '../core/config/ConfigManager'; import { useProjectStore } from '../stores/projectStore'; import { SystemPrompts } from '../agent/core/SystemPrompts'; @@ -13,6 +14,8 @@ import { useStreamProcessor } from '../hooks/useStreamProcessor'; import { createMessage, addWelcomeMessage } from '../utils/chatMessageUtils'; import { formatLocalDateTime } from '../util/timeUtil'; import { downloadBlob, buildTimestampSuffix } from '../util/miscUtil'; +import { LocalLLMModelManager, type LocalLLMModelState } from '../util/localLLMModelManager'; +import { LOCAL_LLM_DISPLAY_NAME, LOCAL_LLM_PROVIDER_KEY } from '../util/localLLMConfig'; import KGDropdown from './common/KGDropdown'; import type { ChatMessage } from '../types/projectTypes'; @@ -32,6 +35,8 @@ const createLLMProviderFromConfig = (): LLMProvider => { let baseURL: string | undefined; switch (providerType) { + case LOCAL_LLM_PROVIDER_KEY: + return new LocalBrowserLLMProvider(); case 'openai': apiKey = configManager.get('general.openai.api_key') as string; model = configManager.get('general.openai.model') as string; @@ -50,7 +55,7 @@ const createLLMProviderFromConfig = (): LLMProvider => { break; } - return new LLMProvider(apiKey, model, baseURL); + return new OpenAICompatibleLLMProvider(apiKey, model, baseURL); }; interface ChatBoxProps { @@ -64,6 +69,8 @@ const ChatBox: React.FC = ({ isVisible }) => { const [messages, setMessages] = useState([]); const [isProcessing, setIsProcessing] = useState(false); const [lastUserMessage, setLastUserMessage] = useState(''); + const [localModelState, setLocalModelState] = useState(LocalLLMModelManager.getState()); + const [activeProvider, setActiveProvider] = useState('openai'); // Track if this is the first message (for system prompt logging) const [isFirstMessage, setIsFirstMessage] = useState(true); @@ -180,9 +187,11 @@ const ChatBox: React.FC = ({ isVisible }) => { } const applyProviderFromConfig = () => { + const providerType = (configManager.get('general.llm_provider') as string) || 'openai'; const provider = createLLMProviderFromConfig(); const agentCore = AgentCore.instance(); agentCore.setLLMProvider(provider); + setActiveProvider(providerType); console.log('LLM provider configured'); }; @@ -204,6 +213,7 @@ const ChatBox: React.FC = ({ isVisible }) => { registerClearChatUICallback(clearChatUI); const maybeUnsubscribePromise = initializeProvider(); + const unsubscribeLocalModel = LocalLLMModelManager.subscribe(setLocalModelState); (async () => { if (hasShownWelcomeOnceInRuntime) return; @@ -216,6 +226,7 @@ const ChatBox: React.FC = ({ isVisible }) => { })(); return () => { + unsubscribeLocalModel(); Promise.resolve(maybeUnsubscribePromise).then((cleanup) => { if (typeof cleanup === 'function') cleanup(); }).catch(() => {}); @@ -266,7 +277,10 @@ const ChatBox: React.FC = ({ isVisible }) => { // Log system prompt only for first message if (isFirstMessage) { try { - const systemPrompt = await SystemPrompts.getSystemPromptWithContext(); + const provider = AgentCore.instance().getLLMProvider(); + const systemPrompt = await SystemPrompts.getSystemPromptWithContext( + provider?.getPreferredSystemPromptPath?.(), + ); console.log('------------ SYSTEM ------------'); console.log(systemPrompt); console.log('--------------------------------'); @@ -372,6 +386,45 @@ const ChatBox: React.FC = ({ isVisible }) => { + {activeProvider === LOCAL_LLM_PROVIDER_KEY && ( +
+
+

{LOCAL_LLM_DISPLAY_NAME} Local Runtime

+ {!localModelState.runtimeSupport.supported && ( +
+ {localModelState.runtimeSupport.reason} +
+ )} + {!localModelState.isCached && !localModelState.isDownloading && localModelState.runtimeSupport.supported && ( +
+ The local language model has not been downloaded yet. It will be downloaded automatically the next time you send a chat request with this provider. +
+ )} + {(localModelState.isChecking || localModelState.isDownloading || localModelState.progressText) && ( +
+
+
+
+
+ {localModelState.isChecking ? 'Checking local model cache...' : localModelState.progressText} +
+
+ )} + {localModelState.error && ( +
+ {localModelState.error} +
+ )} +
+
+ )} +
{messages.map((message) => ( message.role === 'user' ? ( diff --git a/src/components/settings/Settings.css b/src/components/settings/Settings.css index d916da9..bf85606 100644 --- a/src/components/settings/Settings.css +++ b/src/components/settings/Settings.css @@ -293,6 +293,25 @@ font-size: 12px; } +.settings-progress-block { + margin-top: 10px; +} + +.settings-progress-track { + width: 100%; + height: 10px; + border-radius: 999px; + overflow: hidden; + background-color: #3a3a3a; + border: 1px solid #4a4a4a; +} + +.settings-progress-fill { + height: 100%; + background: linear-gradient(90deg, #5a9fd4 0%, #76c28f 100%); + transition: width 0.2s ease; +} + /* Settings Help Links */ .settings-help-links { display: flex; diff --git a/src/components/settings/sections/GeneralSettings.tsx b/src/components/settings/sections/GeneralSettings.tsx index 8baedfd..8814ad7 100644 --- a/src/components/settings/sections/GeneralSettings.tsx +++ b/src/components/settings/sections/GeneralSettings.tsx @@ -1,8 +1,10 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { ConfigManager } from '../../../core/config/ConfigManager'; +import { LocalLLMModelManager, type LocalLLMModelState } from '../../../util/localLLMModelManager'; +import { LOCAL_LLM_DISPLAY_NAME, LOCAL_LLM_PROVIDER_KEY } from '../../../util/localLLMConfig'; const GeneralSettings: React.FC = () => { - const [llmProvider, setLlmProvider] = useState('openai'); + const [llmProvider, setLlmProvider] = useState(LOCAL_LLM_PROVIDER_KEY); const [openaiKey, setOpenaiKey] = useState(''); const [openaiModel, setOpenaiModel] = useState(''); const [geminiKey, setGeminiKey] = useState(''); @@ -22,6 +24,7 @@ const GeneralSettings: React.FC = () => { const [kgoneBaseUrl, setKgoneBaseUrl] = useState(''); const [kgoneServerManaged, setKgoneServerManaged] = useState(false); const [soundfontServerManaged, setSoundfontServerManaged] = useState(false); + const [localModelState, setLocalModelState] = useState(LocalLLMModelManager.getState()); const configManager = ConfigManager.instance(); @@ -46,7 +49,7 @@ const GeneralSettings: React.FC = () => { await configManager.initialize(); } - setLlmProvider((configManager.get('general.llm_provider') as string) || 'openai'); + setLlmProvider((configManager.get('general.llm_provider') as string) || LOCAL_LLM_PROVIDER_KEY); setOpenaiKey((configManager.get('general.openai.api_key') as string) || ''); setOpenaiModel((configManager.get('general.openai.model') as string) || ''); setOpenaiFlex((configManager.get('general.openai.flex') as boolean) ?? false); @@ -69,6 +72,8 @@ const GeneralSettings: React.FC = () => { }; loadConfig(); + const unsubscribe = LocalLLMModelManager.subscribe(setLocalModelState); + return unsubscribe; }, [configManager]); // Debounced save function for text inputs @@ -197,6 +202,14 @@ const GeneralSettings: React.FC = () => { debouncedSave('general.kgone.base_url', value); }; + const handleDeleteLocalModel = async () => { + try { + await LocalLLMModelManager.deleteCachedModel(); + } catch (error) { + console.error('Failed to delete local language model cache:', error); + } + }; + // NOTE: Gemini and Claude are not supported yet due to CORS issues. return (
@@ -217,6 +230,7 @@ const GeneralSettings: React.FC = () => { value={llmProvider} onChange={(e) => handleLlmProviderChange(e.target.value)} > + {/* */} @@ -243,6 +257,69 @@ const GeneralSettings: React.FC = () => {
+
+

{LOCAL_LLM_DISPLAY_NAME} Local Runtime

+ + {!localModelState.runtimeSupport.supported && ( +
+ {localModelState.runtimeSupport.reason} +
+ )} + +
+ +
+ {localModelState.isChecking + ? 'Checking local model cache...' + : localModelState.isCached + ? 'Downloaded in browser cache.' + : 'Not downloaded yet.'} +
+
+ + {!localModelState.isCached && !localModelState.isDownloading && localModelState.runtimeSupport.supported && ( +
+ The local model downloads automatically the next time you chat with `Local LLM (Browser)`. +
+ )} + + {(localModelState.isDownloading || localModelState.progressText) && ( +
+
+
+
+
+ {localModelState.progressText} +
+
+ )} + + {localModelState.error && ( +
+ {localModelState.error} +
+ )} + +
+ +
+
+

OpenAI

@@ -600,4 +677,4 @@ const GeneralSettings: React.FC = () => { ); }; -export default GeneralSettings; \ No newline at end of file +export default GeneralSettings; diff --git a/src/constants/coreConstants.ts b/src/constants/coreConstants.ts index f675279..1e03999 100644 --- a/src/constants/coreConstants.ts +++ b/src/constants/coreConstants.ts @@ -104,7 +104,7 @@ export const OPFS_CONSTANTS = { export const CONFIG_UPGRADER_CONSTANTS = { VERSION_KEY: '__config_version', - CURRENT_VERSION: 1, + CURRENT_VERSION: 2, }; export const URL_CONSTANTS = { diff --git a/src/core/config-upgrader/KGConfigUpgrader.ts b/src/core/config-upgrader/KGConfigUpgrader.ts index 63ee19f..22066fb 100644 --- a/src/core/config-upgrader/KGConfigUpgrader.ts +++ b/src/core/config-upgrader/KGConfigUpgrader.ts @@ -1,6 +1,7 @@ import { KGConfigStorage } from '../io/KGConfigStorage'; import { CONFIG_UPGRADER_CONSTANTS } from '../../constants/coreConstants'; import { upgradeConfigToV1 } from './upgradeConfigToV1'; +import { upgradeConfigToV2 } from './upgradeConfigToV2'; /** * KGConfigUpgrader — Orchestrates app-level migrations (e.g., storage backend changes). @@ -33,6 +34,10 @@ export class KGConfigUpgrader { await upgradeConfigToV1(); break; } + case 2: { + await upgradeConfigToV2(); + break; + } default: { throw new Error(`No config upgrader found for version ${nextVersion}`); } diff --git a/src/core/config-upgrader/upgradeConfigToV2.test.ts b/src/core/config-upgrader/upgradeConfigToV2.test.ts new file mode 100644 index 0000000..6f4c8ce --- /dev/null +++ b/src/core/config-upgrader/upgradeConfigToV2.test.ts @@ -0,0 +1,54 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const configStore = new Map; lastModified: number }>(); + +vi.mock('../io/KGConfigStorage', () => ({ + KGConfigStorage: { + getInstance: () => ({ + getRaw: vi.fn(async (name: string) => configStore.get(name)?.data ?? null), + saveRaw: vi.fn(async (name: string, data: Record) => { + configStore.set(name, { name, data, lastModified: Date.now() }); + }), + }), + }, +})); + +import { upgradeConfigToV2 } from './upgradeConfigToV2'; + +describe('upgradeConfigToV2', () => { + beforeEach(() => { + configStore.clear(); + }); + + it('pins legacy installs without an explicit provider to the old default provider', async () => { + configStore.set('userConfig', { + name: 'userConfig', + data: { + general: { + openai: { api_key: '', model: 'gpt-5.4-mini', flex: false }, + }, + }, + lastModified: Date.now(), + }); + + await upgradeConfigToV2(); + + expect((configStore.get('userConfig')?.data.general as Record).llm_provider).toBe('openai'); + }); + + it('leaves explicit providers unchanged', async () => { + configStore.set('userConfig', { + name: 'userConfig', + data: { + general: { + llm_provider: 'openai_compatible', + }, + }, + lastModified: Date.now(), + }); + + await upgradeConfigToV2(); + + expect((configStore.get('userConfig')?.data.general as Record).llm_provider).toBe('openai_compatible'); + }); +}); diff --git a/src/core/config-upgrader/upgradeConfigToV2.ts b/src/core/config-upgrader/upgradeConfigToV2.ts new file mode 100644 index 0000000..e7a811b --- /dev/null +++ b/src/core/config-upgrader/upgradeConfigToV2.ts @@ -0,0 +1,25 @@ +import { KGConfigStorage } from '../io/KGConfigStorage'; + +const CONFIG_KEY = 'userConfig'; +const LEGACY_DEFAULT_PROVIDER = 'openai'; + +export async function upgradeConfigToV2(): Promise { + const storage = KGConfigStorage.getInstance(); + const rawConfig = await storage.getRaw(CONFIG_KEY); + if (!rawConfig || typeof rawConfig !== 'object') { + return; + } + + const config = rawConfig as Record; + const general = config.general; + if (!general || typeof general !== 'object') { + return; + } + + if ('llm_provider' in (general as Record)) { + return; + } + + (general as Record).llm_provider = LEGACY_DEFAULT_PROVIDER; + await storage.saveRaw(CONFIG_KEY, config); +} diff --git a/src/core/config/ConfigManager.ts b/src/core/config/ConfigManager.ts index b38884f..118e048 100644 --- a/src/core/config/ConfigManager.ts +++ b/src/core/config/ConfigManager.ts @@ -6,7 +6,7 @@ import { KGConfigStorage } from '../io/KGConfigStorage'; interface AppConfig { general: { language: string; - llm_provider: 'openai' | 'gemini' | 'claude' | 'claude_openrouter' | 'openai_compatible'; + llm_provider: 'local_browser' | 'openai' | 'gemini' | 'claude' | 'claude_openrouter' | 'openai_compatible'; persist_api_keys_non_localhost: boolean; openai: { api_key: string; @@ -183,7 +183,7 @@ export class ConfigManager { this.defaultConfig = { general: { language: 'en_us', - llm_provider: 'openai', + llm_provider: 'local_browser', persist_api_keys_non_localhost: false, openai: { api_key: '', diff --git a/src/core/io/LocalSeparatorModelCache.test.ts b/src/core/io/LocalSeparatorModelCache.test.ts index 0642e25..8e96f03 100644 --- a/src/core/io/LocalSeparatorModelCache.test.ts +++ b/src/core/io/LocalSeparatorModelCache.test.ts @@ -9,10 +9,12 @@ class MockWritableFileStream { this.handle = handle; } - async write(content: ArrayBuffer | ArrayBufferView): Promise { - const bytes = content instanceof ArrayBuffer - ? new Uint8Array(content) - : new Uint8Array(content.buffer, content.byteOffset, content.byteLength); + async write(content: ArrayBuffer | ArrayBufferView | string): Promise { + const bytes = typeof content === 'string' + ? new TextEncoder().encode(content) + : content instanceof ArrayBuffer + ? new Uint8Array(content) + : new Uint8Array(content.buffer, content.byteOffset, content.byteLength); this.chunks.push(new Uint8Array(bytes)); } @@ -44,6 +46,8 @@ class MockFileSystemFileHandle { async getFile(): Promise { return { + size: this.content.byteLength, + text: async () => new TextDecoder().decode(this.content), arrayBuffer: async () => this.content.buffer.slice(0), } as unknown as File; } diff --git a/src/util/localLLMConfig.ts b/src/util/localLLMConfig.ts new file mode 100644 index 0000000..577145d --- /dev/null +++ b/src/util/localLLMConfig.ts @@ -0,0 +1,42 @@ +export const LOCAL_LLM_PROVIDER_KEY = 'local_browser'; +export const LOCAL_LLM_MODEL_URL = + 'http://localhost:3000/models/gemma-4-E4B-it-web.task'; +export const LOCAL_LLM_MODEL_FILENAME = 'gemma-4-E4B-it-web.task'; +export const LOCAL_LLM_DISPLAY_NAME = 'Gemma 4 E4B'; +export const LOCAL_LLM_LEGACY_FILENAMES = [ + 'gemma-3n-E4B-it-int4-Web.litertlm', +]; + +export interface LocalLLMRuntimeSupport { + supported: boolean; + webgpuExposed: boolean; + crossOriginIsolated: boolean; + sharedArrayBufferAvailable: boolean; + secureContext: boolean; + reason: string | null; +} + +export function detectLocalLLMRuntimeSupport(): LocalLLMRuntimeSupport { + const secureContext = typeof window !== 'undefined' ? window.isSecureContext : false; + const crossOriginIsolated = typeof window !== 'undefined' ? window.crossOriginIsolated : false; + const sharedArrayBufferAvailable = typeof SharedArrayBuffer !== 'undefined'; + const webgpuExposed = typeof navigator !== 'undefined' && 'gpu' in navigator; + + let reason: string | null = null; + if (!secureContext) { + reason = 'Local browser LLM requires a secure context (HTTPS or localhost).'; + } else if (!crossOriginIsolated || !sharedArrayBufferAvailable) { + reason = 'Local browser LLM requires SharedArrayBuffer support. Ensure COOP/COEP headers are enabled.'; + } else if (!webgpuExposed) { + reason = 'Local browser LLM currently requires a browser with WebGPU support.'; + } + + return { + supported: reason === null, + webgpuExposed, + crossOriginIsolated, + sharedArrayBufferAvailable, + secureContext, + reason, + }; +} diff --git a/src/util/localLLMModelCache.ts b/src/util/localLLMModelCache.ts new file mode 100644 index 0000000..525411d --- /dev/null +++ b/src/util/localLLMModelCache.ts @@ -0,0 +1,92 @@ +import { OpfsModelCache, type ModelDownloadProgress } from './opfsModelCache'; +import { LOCAL_LLM_MODEL_FILENAME } from './localLLMConfig'; + +const cache = new OpfsModelCache({ directoryName: 'models' }); +let writingToCachePromise: Promise | null = null; + +export { type ModelDownloadProgress }; + +export interface CachedModelStreamResult { + reader: ReadableStreamDefaultReader; + totalBytes: number; + fromCache: boolean; + cacheWritePromise: Promise | null; +} + +export class LocalLLMModelCache { + public static async exists(filename: string = LOCAL_LLM_MODEL_FILENAME): Promise { + return cache.exists(filename); + } + + public static async getFile(filename: string = LOCAL_LLM_MODEL_FILENAME): Promise { + return cache.getFile(filename); + } + + public static async getArrayBuffer(filename: string = LOCAL_LLM_MODEL_FILENAME): Promise { + return cache.getArrayBuffer(filename); + } + + public static async delete(filename: string = LOCAL_LLM_MODEL_FILENAME): Promise { + await cache.delete(filename); + } + + public static async loadModelReaderWithCache( + sourceUrl: string, + filename: string = LOCAL_LLM_MODEL_FILENAME, + onProgress?: (progress: ModelDownloadProgress & { fromCache: boolean }) => void, + ): Promise { + if (writingToCachePromise) { + await writingToCachePromise.catch(() => {}); + } + + if (await this.exists(filename)) { + const file = await this.getFile(filename); + onProgress?.({ + receivedBytes: file.size, + totalBytes: file.size, + percent: 100, + fromCache: true, + }); + return { + reader: file.stream().getReader(), + totalBytes: file.size, + fromCache: true, + cacheWritePromise: null, + }; + } + + const response = await fetch(sourceUrl); + if (!response.ok || !response.body) { + throw new Error(`Model download failed (${response.status})`); + } + + const totalBytesHeader = response.headers.get('Content-Length'); + const totalBytes = totalBytesHeader ? Number(totalBytesHeader) : 0; + const [streamForConsumer, streamForCache] = response.body.tee(); + + writingToCachePromise = cache.downloadStream( + streamForCache, + filename, + totalBytes > 0 ? totalBytes : null, + progress => onProgress?.({ ...progress, fromCache: false }), + ); + writingToCachePromise = writingToCachePromise.finally(() => { + writingToCachePromise = null; + }); + + return { + reader: streamForConsumer.getReader(), + totalBytes, + fromCache: false, + cacheWritePromise: writingToCachePromise, + }; + } + + public static async download( + sourceUrl: string, + filename: string = LOCAL_LLM_MODEL_FILENAME, + onProgress?: (progress: ModelDownloadProgress) => void, + ): Promise { + await cache.download(sourceUrl, filename, onProgress); + } +} diff --git a/src/util/localLLMModelManager.ts b/src/util/localLLMModelManager.ts new file mode 100644 index 0000000..9d2405b --- /dev/null +++ b/src/util/localLLMModelManager.ts @@ -0,0 +1,159 @@ +import { + detectLocalLLMRuntimeSupport, + LOCAL_LLM_LEGACY_FILENAMES, + LOCAL_LLM_MODEL_FILENAME, + LOCAL_LLM_MODEL_URL, + type LocalLLMRuntimeSupport, +} from './localLLMConfig'; +import { LocalLLMModelCache } from './localLLMModelCache'; + +export interface LocalLLMModelState { + isCached: boolean; + isChecking: boolean; + isDownloading: boolean; + isDeleting: boolean; + progressPercent: number; + progressText: string; + error: string; + runtimeSupport: LocalLLMRuntimeSupport; +} + +type Listener = (state: LocalLLMModelState) => void; + +export class LocalLLMModelManager { + private static listeners = new Set(); + private static initialized = false; + private static state: LocalLLMModelState = { + isCached: false, + isChecking: false, + isDownloading: false, + isDeleting: false, + progressPercent: 0, + progressText: '', + error: '', + runtimeSupport: detectLocalLLMRuntimeSupport(), + }; + + public static subscribe(listener: Listener): () => void { + this.listeners.add(listener); + listener(this.getState()); + if (!this.initialized) { + this.initialized = true; + void this.refresh(); + } + return () => this.listeners.delete(listener); + } + + public static getState(): LocalLLMModelState { + return { ...this.state, runtimeSupport: { ...this.state.runtimeSupport } }; + } + + public static async refresh(): Promise { + this.setState({ + isChecking: true, + runtimeSupport: detectLocalLLMRuntimeSupport(), + }); + try { + await this.cleanupLegacyEntries(); + const isCached = await LocalLLMModelCache.exists(); + this.setState({ isCached, error: '' }); + } catch (error) { + this.setState({ error: error instanceof Error ? error.message : String(error) }); + } finally { + this.setState({ isChecking: false }); + } + } + + public static async ensureRuntimeSupported(): Promise { + const runtimeSupport = detectLocalLLMRuntimeSupport(); + this.setState({ runtimeSupport }); + if (!runtimeSupport.supported) { + throw new Error(runtimeSupport.reason ?? 'Local browser LLM is not supported in this browser.'); + } + + await this.cleanupLegacyEntries(); + } + + public static async deleteCachedModel(): Promise { + this.setState({ isDeleting: true, error: '' }); + try { + await LocalLLMModelCache.delete(); + await this.cleanupLegacyEntries(); + this.setState({ + isCached: false, + progressPercent: 0, + progressText: '', + }); + } catch (error) { + this.setState({ error: error instanceof Error ? error.message : String(error) }); + throw error; + } finally { + this.setState({ isDeleting: false }); + } + } + + private static setState(partial: Partial): void { + this.state = { + ...this.state, + ...partial, + }; + for (const listener of this.listeners) { + listener(this.getState()); + } + } + + private static async cleanupLegacyEntries(): Promise { + await Promise.all( + LOCAL_LLM_LEGACY_FILENAMES.map(async legacyFilename => { + try { + await LocalLLMModelCache.delete(legacyFilename); + } catch { + // Ignore best-effort legacy cleanup failures. + } + }), + ); + } + + public static notifyLoadStart(fromCache: boolean): void { + this.setState({ + isDownloading: !fromCache, + progressPercent: fromCache ? 100 : 0, + progressText: fromCache ? 'Loading local language model from browser cache...' : 'Downloading local language model...', + error: '', + }); + } + + public static notifyLoadProgress(receivedBytes: number, totalBytes: number | null, fromCache: boolean): void { + const receivedMb = (receivedBytes / (1024 * 1024)).toFixed(1); + const totalMb = totalBytes ? (totalBytes / (1024 * 1024)).toFixed(1) : null; + this.setState({ + isDownloading: !fromCache, + progressPercent: totalBytes ? (receivedBytes / totalBytes) * 100 : 0, + progressText: fromCache + ? 'Loading local language model from browser cache...' + : totalMb + ? `Downloading local language model... ${receivedMb} / ${totalMb} MB` + : `Downloading local language model... ${receivedMb} MB`, + error: '', + }); + } + + public static notifyCacheReady(): void { + this.setState({ + isCached: true, + isDownloading: false, + progressPercent: 100, + progressText: 'Local language model is ready.', + error: '', + }); + } + + public static notifyLoadError(error: unknown): void { + this.setState({ + isDownloading: false, + progressPercent: 0, + progressText: '', + error: error instanceof Error ? error.message : String(error), + }); + } +} diff --git a/src/util/localSeparatorModelCache.ts b/src/util/localSeparatorModelCache.ts index a4990ac..b941cd1 100644 --- a/src/util/localSeparatorModelCache.ts +++ b/src/util/localSeparatorModelCache.ts @@ -1,50 +1,25 @@ import { LOCAL_SEPARATOR_MODEL_FILENAME } from './localSeparatorConfig'; +import { OpfsModelCache, type ModelDownloadProgress } from './opfsModelCache'; -export interface ModelDownloadProgress { - receivedBytes: number; - totalBytes: number | null; - percent: number; -} +const cache = new OpfsModelCache({ directoryName: 'models' }); + +export { type ModelDownloadProgress }; export class LocalSeparatorModelCache { - private static readonly MODELS_DIR = 'models'; - private static readonly TEMP_SUFFIX = '.download'; - public static async exists(filename: string = LOCAL_SEPARATOR_MODEL_FILENAME): Promise { - try { - const modelsDir = await this.getModelsDir(); - await modelsDir.getFileHandle(filename); - return true; - } catch { - return false; - } + return cache.exists(filename); } public static async getFile(filename: string = LOCAL_SEPARATOR_MODEL_FILENAME): Promise { - const modelsDir = await this.getModelsDir(); - const fileHandle = await modelsDir.getFileHandle(filename); - return fileHandle.getFile(); + return cache.getFile(filename); } public static async getArrayBuffer(filename: string = LOCAL_SEPARATOR_MODEL_FILENAME): Promise { - const file = await this.getFile(filename); - return file.arrayBuffer(); + return cache.getArrayBuffer(filename); } public static async delete(filename: string = LOCAL_SEPARATOR_MODEL_FILENAME): Promise { - try { - const modelsDir = await this.getModelsDir(); - await modelsDir.removeEntry(filename); - } catch { - // Ignore missing file cleanup. - } - - try { - const modelsDir = await this.getModelsDir(); - await modelsDir.removeEntry(`${filename}${this.TEMP_SUFFIX}`); - } catch { - // Ignore missing temp file cleanup. - } + await cache.delete(filename); } public static async download( @@ -52,75 +27,6 @@ export class LocalSeparatorModelCache { filename: string = LOCAL_SEPARATOR_MODEL_FILENAME, onProgress?: (progress: ModelDownloadProgress) => void, ): Promise { - const response = await fetch(sourceUrl); - if (!response.ok) { - throw new Error(`Model download failed (${response.status})`); - } - - const modelsDir = await this.getModelsDir(); - const tempName = `${filename}${this.TEMP_SUFFIX}`; - await this.delete(filename); - - const tempHandle = await modelsDir.getFileHandle(tempName, { create: true }); - const writable = await tempHandle.createWritable(); - - try { - const totalBytesHeader = response.headers.get('Content-Length'); - const totalBytes = totalBytesHeader ? Number(totalBytesHeader) : null; - - if (!response.body) { - const buffer = await response.arrayBuffer(); - await writable.write(buffer); - onProgress?.({ - receivedBytes: buffer.byteLength, - totalBytes, - percent: 100, - }); - } else { - const reader = response.body.getReader(); - let receivedBytes = 0; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - if (!value) continue; - await writable.write(value); - receivedBytes += value.byteLength; - onProgress?.({ - receivedBytes, - totalBytes, - percent: totalBytes ? (receivedBytes / totalBytes) * 100 : 0, - }); - } - } - } catch (error) { - await writable.abort(); - await this.delete(filename); - throw error; - } - - await writable.close(); - - const finalHandle = await modelsDir.getFileHandle(filename, { create: true }); - const finalWritable = await finalHandle.createWritable(); - try { - const tempFile = await tempHandle.getFile(); - await finalWritable.write(await tempFile.arrayBuffer()); - await finalWritable.close(); - } catch (error) { - await finalWritable.abort(); - throw error; - } finally { - try { - await modelsDir.removeEntry(tempName); - } catch { - // Ignore temp cleanup errors. - } - } - } - - private static async getModelsDir(): Promise { - const root = await navigator.storage.getDirectory(); - return root.getDirectoryHandle(this.MODELS_DIR, { create: true }); + await cache.download(sourceUrl, filename, onProgress); } } diff --git a/src/util/messageFilter/UserMessageFilter.ts b/src/util/messageFilter/UserMessageFilter.ts index 789a378..b314b18 100644 --- a/src/util/messageFilter/UserMessageFilter.ts +++ b/src/util/messageFilter/UserMessageFilter.ts @@ -2,6 +2,7 @@ import { clearChatHistoryAndUI } from '../chatUtil'; import { useProjectStore } from '../../stores/projectStore'; import { ConfigManager } from '../../core/config/ConfigManager'; import { SystemPrompts } from '../../agent/core/SystemPrompts'; +import { detectLocalLLMRuntimeSupport, LOCAL_LLM_PROVIDER_KEY } from '../localLLMConfig'; export interface UserMessageFilterResult { // Whether to render the user message bubble (div.message-user) @@ -134,7 +135,18 @@ export async function processUserMessage(originalMessage: string): Promise { + try { + const dir = await this.getDir(); + const fileHandle = await dir.getFileHandle(filename); + const sizeHandle = await dir.getFileHandle(this.getSizeFilename(filename)); + const [file, sizeFile] = await Promise.all([fileHandle.getFile(), sizeHandle.getFile()]); + const expectedSize = Number(await sizeFile.text()); + if (!Number.isFinite(expectedSize) || expectedSize <= 0) { + await this.delete(filename); + return false; + } + if (file.size !== expectedSize) { + await this.delete(filename); + return false; + } + return true; + } catch { + return false; + } + } + + public async getFile(filename: string): Promise { + const dir = await this.getDir(); + const handle = await dir.getFileHandle(filename); + const file = await handle.getFile(); + console.log('[opfsModelCache] Opened cached file.', { + filename, + size: file.size, + }); + return file; + } + + public async getArrayBuffer(filename: string): Promise { + const file = await this.getFile(filename); + return file.arrayBuffer(); + } + + public async delete(filename: string): Promise { + const dir = await this.getDir(); + await this.removeIfExists(dir, filename); + await this.removeIfExists(dir, this.getSizeFilename(filename)); + await this.removeIfExists(dir, `${filename}${this.tempSuffix}`); + await this.removeIfExists(dir, `${this.getSizeFilename(filename)}${this.tempSuffix}`); + } + + public async download( + sourceUrl: string, + filename: string, + onProgress?: (progress: ModelDownloadProgress) => void, + ): Promise { + const response = await fetch(sourceUrl); + if (!response.ok) { + throw new Error(`Model download failed (${response.status})`); + } + const totalBytesHeader = response.headers.get('Content-Length'); + const totalBytes = totalBytesHeader ? Number(totalBytesHeader) : null; + if (!response.body) { + throw new Error('Model download response did not include a readable body.'); + } + await this.downloadStream(response.body, filename, totalBytes, onProgress); + } + + public async downloadStream( + stream: ReadableStream, + filename: string, + totalBytes: number | null, + onProgress?: (progress: ModelDownloadProgress) => void, + ): Promise { + const dir = await this.getDir(); + await this.delete(filename); + + const tempFilename = `${filename}${this.tempSuffix}`; + const tempHandle = await dir.getFileHandle(tempFilename, { create: true }); + const tempWritable = await tempHandle.createWritable(); + const reader = stream.getReader(); + let receivedBytes = 0; + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + if (!value) continue; + await tempWritable.write(value); + receivedBytes += value.byteLength; + onProgress?.({ + receivedBytes, + totalBytes, + percent: totalBytes ? (receivedBytes / totalBytes) * 100 : 0, + }); + } + await tempWritable.close(); + + const sizeValue = totalBytes ?? receivedBytes; + if (!Number.isFinite(sizeValue) || sizeValue <= 0) { + throw new Error('Model download did not provide a valid size.'); + } + + console.log(`[opfsModelCache] Finalizing cached model ${filename} from temp file ${tempFilename}.`); + const finalHandle = await dir.getFileHandle(filename, { create: true }); + const finalWritable = await finalHandle.createWritable(); + try { + const tempFile = await tempHandle.getFile(); + console.log('[opfsModelCache] Temp file ready for finalize copy.', { + filename, + tempFilename, + tempSize: tempFile.size, + expectedSize: sizeValue, + }); + await finalWritable.write(tempFile); + await finalWritable.close(); + } catch (error) { + await finalWritable.abort(); + throw error; + } + + const sizeHandle = await dir.getFileHandle(this.getSizeFilename(filename), { create: true }); + const sizeWritable = await sizeHandle.createWritable(); + try { + await sizeWritable.write(String(sizeValue)); + await sizeWritable.close(); + } catch (error) { + await sizeWritable.abort(); + throw error; + } + + onProgress?.({ + receivedBytes: sizeValue, + totalBytes: sizeValue, + percent: 100, + }); + console.log('[opfsModelCache] Cached model finalize completed.', { + filename, + size: sizeValue, + }); + } catch (error) { + try { + await tempWritable.abort(); + } catch { + // Ignore abort cleanup errors. + } + await this.delete(filename); + throw error; + } finally { + await this.removeIfExists(dir, tempFilename); + reader.releaseLock(); + } + } + + private getSizeFilename(filename: string): string { + return `${filename}${this.sizeSuffix}`; + } + + private async getDir(): Promise { + const root = await navigator.storage.getDirectory(); + return root.getDirectoryHandle(this.directoryName, { create: true }); + } + + private async removeIfExists(dir: FileSystemDirectoryHandle, name: string): Promise { + try { + await dir.removeEntry(name); + } catch { + // Ignore missing entry cleanup. + } + } +} diff --git a/vite.config.ts b/vite.config.ts index 2e3d8de..492a9cd 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -18,7 +18,17 @@ export default defineConfig({ }, server: { host: true, + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, // IMPORTANT: MAKE SURE TO UPDATE YOUR OS HOSTS FILE TO POINT `testlocal.com` TO YOUR LOCAL IP (e.g. 127.0.0.1). allowedHosts: ['testlocal.com', '.testlocal.com', 'localhost', '127.0.0.1'], }, + preview: { + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, + }, });