// Y2JB Updater by PLK
// Source: https://github.com/itsPLK/y2jb_updater

async function start_update() {

  if (!is_jailbroken()) {
      log("[-] Device is not jailbroken, cannot proceed with Y2JB update");
      send_notification("[-] Device is not jailbroken, cannot proceed with Y2JB update");
      return;
  }

  // fflate 0.8.2 - for zip extraction
  !function(f){typeof module!='undefined'&&typeof exports=='object'?module.exports=f():typeof define!='undefined'&&define.amd?define(f):(typeof self!='undefined'?self:this).fflate=f()}(function(){var _e={};"use strict";var t=(typeof module!='undefined'&&typeof exports=='object'?function(_f){"use strict";var e,t=";var __w=require('worker_threads');__w.parentPort.on('message',function(m){onmessage({data:m})}),postMessage=function(m,t){__w.parentPort.postMessage(m,t)},close=process.exit;self=global";try{e=require("worker_threads").Worker}catch(e){}exports.default=e?function(r,n,o,a,s){var u=!1,i=new e(r+t,{eval:!0}).on("error",(function(e){return s(e,null)})).on("message",(function(e){return s(null,e)})).on("exit",(function(e){e&&!u&&s(Error("exited with code "+e),null)}));return i.postMessage(o,a),i.terminate=function(){return u=!0,e.prototype.terminate.call(i)},i}:function(e,t,r,n,o){setImmediate((function(){return o(Error("async operations unsupported - update to Node 12+ (or Node 10-11 with the --experimental-worker CLI flag)"),null)}));var a=function(){};return{terminate:a,postMessage:a}};return _f}:function(_f){"use strict";var e={};_f.default=function(r,t,s,a,n){var o=new Worker(e[t]||(e[t]=URL.createObjectURL(new Blob([r+';addEventListener("error",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})'],{type:"text/javascript"}))));return o.onmessage=function(e){var r=e.data,t=r.$e$;if(t){var s=Error(t[0]);s.code=t[1],s.stack=t[2],n(s,null)}else n(null,r)},o.postMessage(s,a),o};return _f})({}),n=Uint8Array,r=Uint16Array,e=Int32Array,i=new n([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),o=new n([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),s=new n([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),a=function(t,n){for(var i=new r(31),o=0;o<31;++o)i[o]=n+=1<<t[o-1];var s=new e(i[30]);for(o=1;o<30;++o)for(var a=i[o];a<i[o+1];++a)s[a]=a-i[o]<<5|o;return{b:i,r:s}},u=a(i,2),h=u.b,f=u.r;h[28]=258,f[258]=28;for(var l=a(o,0),c=l.b,p=l.r,v=new r(32768),d=0;d<32768;++d){var g=(43690&d)>>1|(21845&d)<<1;v[d]=((65280&(g=(61680&(g=(52428&g)>>2|(13107&g)<<2))>>4|(3855&g)<<4))>>8|(255&g)<<8)>>1}var y=function(t,n,e){for(var i=t.length,o=0,s=new r(n);o<i;++o)t[o]&&++s[t[o]-1];var a,u=new r(n);for(o=1;o<n;++o)u[o]=u[o-1]+s[o-1]<<1;if(e){a=new r(1<<n);var h=15-n;for(o=0;o<i;++o)if(t[o])for(var f=o<<4|t[o],l=n-t[o],c=u[t[o]-1]++<<l,p=c|(1<<l)-1;c<=p;++c)a[v[c]>>h]=f}else for(a=new r(i),o=0;o<i;++o)t[o]&&(a[o]=v[u[t[o]-1]++]>>15-t[o]);return a},m=new n(288);for(d=0;d<144;++d)m[d]=8;for(d=144;d<256;++d)m[d]=9;for(d=256;d<280;++d)m[d]=7;for(d=280;d<288;++d)m[d]=8;var b=new n(32);for(d=0;d<32;++d)b[d]=5;var w=y(m,9,0),x=y(m,9,1),z=y(b,5,0),k=y(b,5,1),M=function(t){for(var n=t[0],r=1;r<t.length;++r)t[r]>n&&(n=t[r]);return n},S=function(t,n,r){var e=n/8|0;return(t[e]|t[e+1]<<8)>>(7&n)&r},A=function(t,n){var r=n/8|0;return(t[r]|t[r+1]<<8|t[r+2]<<16)>>(7&n)},T=function(t){return(t+7)/8|0},D=function(t,r,e){return(null==r||r<0)&&(r=0),(null==e||e>t.length)&&(e=t.length),new n(t.subarray(r,e))};_e.FlateErrorCode={UnexpectedEOF:0,InvalidBlockType:1,InvalidLengthLiteral:2,InvalidDistance:3,StreamFinished:4,NoStreamHandler:5,InvalidHeader:6,NoCallback:7,InvalidUTF8:8,ExtraFieldTooLong:9,InvalidDate:10,FilenameTooLong:11,StreamFinishing:12,InvalidZipData:13,UnknownCompressionMethod:14};var C=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],I=function(t,n,r){var e=Error(n||C[t]);if(e.code=t,Error.captureStackTrace&&Error.captureStackTrace(e,I),!r)throw e;return e},U=function(t,r,e,a){var u=t.length,f=a?a.length:0;if(!u||r.f&&!r.l)return e||new n(0);var l=!e,p=l||2!=r.i,v=r.i;l&&(e=new n(3*u));var d=function(t){var r=e.length;if(t>r){var i=new n(Math.max(2*r,t));i.set(e),e=i}},g=r.f||0,m=r.p||0,b=r.b||0,w=r.l,z=r.d,C=r.m,U=r.n,F=8*u;do{if(!w){g=S(t,m,1);var E=S(t,m+1,3);if(m+=3,!E){var Z=t[(J=T(m)+4)-4]|t[J-3]<<8,q=J+Z;if(q>u){v&&I(0);break}p&&d(b+Z),e.set(t.subarray(J,q),b),r.b=b+=Z,r.p=m=8*q,r.f=g;continue}if(1==E)w=x,z=k,C=9,U=5;else if(2==E){var O=S(t,m,31)+257,G=S(t,m+10,15)+4,L=O+S(t,m+5,31)+1;m+=14;for(var H=new n(L),j=new n(19),N=0;N<G;++N)j[s[N]]=S(t,m+3*N,7);m+=3*G;var P=M(j),B=(1<<P)-1,Y=y(j,P,1);for(N=0;N<L;){var J,K=Y[S(t,m,B)];if(m+=15&K,(J=K>>4)<16)H[N++]=J;else{var Q=0,R=0;for(16==J?(R=3+S(t,m,3),m+=2,Q=H[N-1]):17==J?(R=3+S(t,m,7),m+=3):18==J&&(R=11+S(t,m,127),m+=7);R--;)H[N++]=Q}}var V=H.subarray(0,O),W=H.subarray(O);C=M(V),U=M(W),w=y(V,C,1),z=y(W,U,1)}else I(1);if(m>F){v&&I(0);break}}p&&d(b+131072);for(var X=(1<<C)-1,$=(1<<U)-1,_=m;;_=m){var tt=(Q=w[A(t,m)&X])>>4;if((m+=15&Q)>F){v&&I(0);break}if(Q||I(2),tt<256)e[b++]=tt;else{if(256==tt){_=m,w=null;break}var nt=tt-254;tt>264&&(nt=S(t,m,(1<<(it=i[N=tt-257]))-1)+h[N],m+=it);var rt=z[A(t,m)&$],et=rt>>4;if(rt||I(3),m+=15&rt,W=c[et],et>3){var it=o[et];W+=A(t,m)&(1<<it)-1,m+=it}if(m>F){v&&I(0);break}p&&d(b+131072);var ot=b+nt;if(b<W){var st=f-W,at=Math.min(W,ot);for(st+b<0&&I(3);b<at;++b)e[b]=a[st+b]}for(;b<ot;++b)e[b]=e[b-W]}}r.l=w,r.p=_,r.b=b,r.f=g,w&&(g=1,r.m=C,r.d=z,r.n=U)}while(!g);return b!=e.length&&l?D(e,0,b):e.subarray(0,b)},F=function(t,n,r){var e=n/8|0;t[e]|=r<<=7&n,t[e+1]|=r>>8},E=function(t,n,r){var e=n/8|0;t[e]|=r<<=7&n,t[e+1]|=r>>8,t[e+2]|=r>>16},Z=function(t,e){for(var i=[],o=0;o<t.length;++o)t[o]&&i.push({s:o,f:t[o]});var s=i.length,a=i.slice();if(!s)return{t:N,l:0};if(1==s){var u=new n(i[0].s+1);return u[i[0].s]=1,{t:u,l:1}}i.sort((function(t,n){return t.f-n.f})),i.push({s:-1,f:25001});var h=i[0],f=i[1],l=0,c=1,p=2;for(i[0]={s:-1,f:h.f+f.f,l:h,r:f};c!=s-1;)h=i[i[l].f<i[p].f?l++:p++],f=i[l!=c&&i[l].f<i[p].f?l++:p++],i[c++]={s:-1,f:h.f+f.f,l:h,r:f};var v=a[0].s;for(o=1;o<s;++o)a[o].s>v&&(v=a[o].s);var d=new r(v+1),g=q(i[c-1],d,0);if(g>e){o=0;var y=0,m=g-e,b=1<<m;for(a.sort((function(t,n){return d[n.s]-d[t.s]||t.f-n.f}));o<s;++o){var w=a[o].s;if(!(d[w]>e))break;y+=b-(1<<g-d[w]),d[w]=e}for(y>>=m;y>0;){var x=a[o].s;d[x]<e?y-=1<<e-d[x]++-1:++o}for(;o>=0&&y;--o){var z=a[o].s;d[z]==e&&(--d[z],++y)}g=e}return{t:new n(d),l:g}},q=function(t,n,r){return-1==t.s?Math.max(q(t.l,n,r+1),q(t.r,n,r+1)):n[t.s]=r},O=function(t){for(var n=t.length;n&&!t[--n];);for(var e=new r(++n),i=0,o=t[0],s=1,a=function(t){e[i++]=t},u=1;u<=n;++u)if(t[u]==o&&u!=n)++s;else{if(!o&&s>2){for(;s>138;s-=138)a(32754);s>2&&(a(s>10?s-11<<5|28690:s-3<<5|12305),s=0)}else if(s>3){for(a(o),--s;s>6;s-=6)a(8304);s>2&&(a(s-3<<5|8208),s=0)}for(;s--;)a(o);s=1,o=t[u]}return{c:e.subarray(0,i),n:n}},G=function(t,n){for(var r=0,e=0;e<n.length;++e)r+=t[e]*n[e];return r},L=function(t,n,r){var e=r.length,i=T(n+2);t[i]=255&e,t[i+1]=e>>8,t[i+2]=255^t[i],t[i+3]=255^t[i+1];for(var o=0;o<e;++o)t[i+o+4]=r[o];return 8*(i+4+e)},H=function(t,n,e,a,u,h,f,l,c,p,v){F(n,v++,e),++u[256];for(var d=Z(u,15),g=d.t,x=d.l,k=Z(h,15),M=k.t,S=k.l,A=O(g),T=A.c,D=A.n,C=O(M),I=C.c,U=C.n,q=new r(19),H=0;H<T.length;++H)++q[31&T[H]];for(H=0;H<I.length;++H)++q[31&I[H]];for(var j=Z(q,7),N=j.t,P=j.l,B=19;B>4&&!N[s[B-1]];--B);var Y,J,K,Q,R=p+5<<3,V=G(u,m)+G(h,b)+f,W=G(u,g)+G(h,M)+f+14+3*B+G(q,N)+2*q[16]+3*q[17]+7*q[18];if(c>=0&&R<=V&&R<=W)return L(n,v,t.subarray(c,c+p));if(F(n,v,1+(W<V)),v+=2,W<V){Y=y(g,x,0),J=g,K=y(M,S,0),Q=M;var X=y(N,P,0);for(F(n,v,D-257),F(n,v+5,U-1),F(n,v+10,B-4),v+=14,H=0;H<B;++H)F(n,v+3*H,N[s[H]]);v+=3*B;for(var $=[T,I],_=0;_<2;++_){var tt=$[_];for(H=0;H<tt.length;++H)F(n,v,X[rt=31&tt[H]]),v+=N[rt],rt>15&&(F(n,v,tt[H]>>5&127),v+=tt[H]>>12)}}else Y=w,J=m,K=z,Q=b;for(H=0;H<l;++H){var nt=a[H];if(nt>255){var rt;E(n,v,Y[257+(rt=nt>>18&31)]),v+=J[rt+257],rt>7&&(F(n,v,nt>>23&31),v+=i[rt]);var et=31&nt;E(n,v,K[et]),v+=Q[et],et>3&&(E(n,v,nt>>5&8191),v+=o[et])}else E(n,v,Y[nt]),v+=J[nt]}return E(n,v,Y[256]),v+J[256]},j=new e([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),N=new n(0),P=function(t,s,a,u,h,l){var c=l.z||t.length,v=new n(u+c+5*(1+Math.ceil(c/7e3))+h),d=v.subarray(u,v.length-h),g=l.l,y=7&(l.r||0);if(s){y&&(d[0]=l.r>>3);for(var m=j[s-1],b=m>>13,w=8191&m,x=(1<<a)-1,z=l.p||new r(32768),k=l.h||new r(x+1),M=Math.ceil(a/3),S=2*M,A=function(n){return(t[n]^t[n+1]<<M^t[n+2]<<S)&x},C=new e(25e3),I=new r(288),U=new r(32),F=0,E=0,Z=l.i||0,q=0,O=l.w||0,G=0;Z+2<c;++Z){var N=A(Z),P=32767&Z,B=k[N];if(z[P]=B,k[N]=P,O<=Z){var Y=c-Z;if((F>7e3||q>24576)&&(Y>423||!g)){y=H(t,d,0,C,I,U,E,q,G,Z-G,y),q=F=E=0,G=Z;for(var J=0;J<286;++J)I[J]=0;for(J=0;J<30;++J)U[J]=0}var K=2,Q=0,R=w,V=P-B&32767;if(Y>2&&N==A(Z-V))for(var W=Math.min(b,Y)-1,X=Math.min(32767,Z),$=Math.min(258,Y);V<=X&&--R&&P!=B;){if(t[Z+K]==t[Z+K-V]){for(var _=0;_<$&&t[Z+_]==t[Z+_-V];++_);if(_>K){if(K=_,Q=V,_>W)break;var tt=Math.min(V,_-2),nt=0;for(J=0;J<tt;++J){var rt=Z-V+J&32767,et=rt-z[rt]&32767;et>nt&&(nt=et,B=rt)}}}V+=(P=B)-(B=z[P])&32767}if(Q){C[q++]=268435456|f[K]<<18|p[Q];var it=31&f[K],ot=31&p[Q];E+=i[it]+o[ot],++I[257+it],++U[ot],O=Z+K,++F}else C[q++]=t[Z],++I[t[Z]]}}for(Z=Math.max(Z,O);Z<c;++Z)C[q++]=t[Z],++I[t[Z]];y=H(t,d,g,C,I,U,E,q,G,Z-G,y),g||(l.r=7&y|d[y/8|0]<<3,y-=7,l.h=k,l.p=z,l.i=Z,l.w=O)}else{for(Z=l.w||0;Z<c+g;Z+=65535){var st=Z+65535;st>=c&&(d[y/8|0]=g,st=c),y=L(d,y+1,t.subarray(Z,st))}l.i=c}return D(v,0,u+T(y)+h)},B=function(){for(var t=new Int32Array(256),n=0;n<256;++n){for(var r=n,e=9;--e;)r=(1&r&&-306674912)^r>>>1;t[n]=r}return t}(),Y=function(){var t=-1;return{p:function(n){for(var r=t,e=0;e<n.length;++e)r=B[255&r^n[e]]^r>>>8;t=r},d:function(){return~t}}},J=function(){var t=1,n=0;return{p:function(r){for(var e=t,i=n,o=0|r.length,s=0;s!=o;){for(var a=Math.min(s+2655,o);s<a;++s)i+=e+=r[s];e=(65535&e)+15*(e>>16),i=(65535&i)+15*(i>>16)}t=e,n=i},d:function(){return(255&(t%=65521))<<24|(65280&t)<<8|(255&(n%=65521))<<8|n>>8}}},K=function(t,r,e,i,o){if(!o&&(o={l:1},r.dictionary)){var s=r.dictionary.subarray(-32768),a=new n(s.length+t.length);a.set(s),a.set(t,s.length),t=a,o.w=s.length}return P(t,null==r.level?6:r.level,null==r.mem?o.l?Math.ceil(1.5*Math.max(8,Math.min(13,Math.log(t.length)))):20:12+r.mem,e,i,o)},Q=function(t,n){var r={};for(var e in t)r[e]=t[e];for(var e in n)r[e]=n[e];return r},R=function(t,n,r){for(var e=t(),i=""+t,o=i.slice(i.indexOf("[")+1,i.lastIndexOf("]")).replace(/\s+/g,"").split(","),s=0;s<e.length;++s){var a=e[s],u=o[s];if("function"==typeof a){n+=";"+u+"=";var h=""+a;if(a.prototype)if(-1!=h.indexOf("[native code]")){var f=h.indexOf(" ",8)+1;n+=h.slice(f,h.indexOf("(",f))}else for(var l in n+=h,a.prototype)n+=";"+u+".prototype."+l+"="+a.prototype[l];else n+=h}else r[u]=a}return n},V=[],W=function(t){var n=[];for(var r in t)t[r].buffer&&n.push((t[r]=new t[r].constructor(t[r])).buffer);return n},X=function(n,r,e,i){if(!V[e]){for(var o="",s={},a=n.length-1,u=0;u<a;++u)o=R(n[u],o,s);V[e]={c:R(n[a],o,s),e:s}}var h=Q({},V[e].e);return(0,t.default)(V[e].c+";onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage="+r+"}",e,h,W(h),i)},$=function(){return[n,r,e,i,o,s,h,c,x,k,v,C,y,M,S,A,T,D,I,U,Tt,it,ot]},_=function(){return[n,r,e,i,o,s,f,p,w,m,z,b,v,j,N,y,F,E,Z,q,O,G,L,H,T,D,P,K,kt,it]},tt=function(){return[pt,gt,ct,Y,B]},nt=function(){return[vt,dt]},rt=function(){return[yt,ct,J]},et=function(){return[mt]},it=function(t){return postMessage(t,[t.buffer])},ot=function(t){return t&&{out:t.size&&new n(t.size),dictionary:t.dictionary}},st=function(t,n,r,e,i,o){var s=X(r,e,i,(function(t,n){s.terminate(),o(t,n)}));return s.postMessage([t,n],n.consume?[t.buffer]:[]),function(){s.terminate()}},at=function(t){return t.ondata=function(t,n){return postMessage([t,n],[t.buffer])},function(n){n.data.length?(t.push(n.data[0],n.data[1]),postMessage([n.data[0].length])):t.flush()}},ut=function(t,n,r,e,i,o,s){var a,u=X(t,e,i,(function(t,r){t?(u.terminate(),n.ondata.call(n,t)):Array.isArray(r)?1==r.length?(n.queuedSize-=r[0],n.ondrain&&n.ondrain(r[0])):(r[1]&&u.terminate(),n.ondata.call(n,t,r[0],r[1])):s(r)}));u.postMessage(r),n.queuedSize=0,n.push=function(t,r){n.ondata||I(5),a&&n.ondata(I(4,0,1),null,!!r),n.queuedSize+=t.length,u.postMessage([t,a=r],[t.buffer])},n.terminate=function(){u.terminate()},o&&(n.flush=function(){u.postMessage([])})},ht=function(t,n){return t[n]|t[n+1]<<8},ft=function(t,n){return(t[n]|t[n+1]<<8|t[n+2]<<16|t[n+3]<<24)>>>0},lt=function(t,n){return ft(t,n)+4294967296*ft(t,n+4)},ct=function(t,n,r){for(;r;++n)t[n]=r,r>>>=8},pt=function(t,n){var r=n.filename;if(t[0]=31,t[1]=139,t[2]=8,t[8]=n.level<2?4:9==n.level?2:0,t[9]=3,0!=n.mtime&&ct(t,4,Math.floor(new Date(n.mtime||Date.now())/1e3)),r){t[3]=8;for(var e=0;e<=r.length;++e)t[e+10]=r.charCodeAt(e)}},vt=function(t){31==t[0]&&139==t[1]&&8==t[2]||I(6,"invalid gzip data");var n=t[3],r=10;4&n&&(r+=2+(t[10]|t[11]<<8));for(var e=(n>>3&1)+(n>>4&1);e>0;e-=!t[r++]);return r+(2&n)},dt=function(t){var n=t.length;return(t[n-4]|t[n-3]<<8|t[n-2]<<16|t[n-1]<<24)>>>0},gt=function(t){return 10+(t.filename?t.filename.length+1:0)},yt=function(t,n){var r=n.level,e=0==r?0:r<6?1:9==r?3:2;if(t[0]=120,t[1]=e<<6|(n.dictionary&&32),t[1]|=31-(t[0]<<8|t[1])%31,n.dictionary){var i=J();i.p(n.dictionary),ct(t,2,i.d())}},mt=function(t,n){return(8!=(15&t[0])||t[0]>>4>7||(t[0]<<8|t[1])%31)&&I(6,"invalid zlib data"),(t[1]>>5&1)==+!n&&I(6,"invalid zlib data: "+(32&t[1]?"need":"unexpected")+" dictionary"),2+(t[1]>>3&4)};function bt(t,n){return"function"==typeof t&&(n=t,t={}),this.ondata=n,t}var wt=function(){function t(t,r){if("function"==typeof t&&(r=t,t={}),this.ondata=r,this.o=t||{},this.s={l:0,i:32768,w:32768,z:32768},this.b=new n(98304),this.o.dictionary){var e=this.o.dictionary.subarray(-32768);this.b.set(e,32768-e.length),this.s.i=32768-e.length}}return t.prototype.p=function(t,n){this.ondata(K(t,this.o,0,0,this.s),n)},t.prototype.push=function(t,r){this.ondata||I(5),this.s.l&&I(4);var e=t.length+this.s.z;if(e>this.b.length){if(e>2*this.b.length-32768){var i=new n(-32768&e);i.set(this.b.subarray(0,this.s.z)),this.b=i}var o=this.b.length-this.s.z;this.b.set(t.subarray(0,o),this.s.z),this.s.z=this.b.length,this.p(this.b,!1),this.b.set(this.b.subarray(-32768)),this.b.set(t.subarray(o),32768),this.s.z=t.length-o+32768,this.s.i=32766,this.s.w=32768}else this.b.set(t,this.s.z),this.s.z+=t.length;this.s.l=1&r,(this.s.z>this.s.w+8191||r)&&(this.p(this.b,r||!1),this.s.w=this.s.i,this.s.i-=2)},t.prototype.flush=function(){this.ondata||I(5),this.s.l&&I(4),this.p(this.b,!1),this.s.w=this.s.i,this.s.i-=2},t}();_e.Deflate=wt;var xt=function(){return function(t,n){ut([_,function(){return[at,wt]}],this,bt.call(this,t,n),(function(t){var n=new wt(t.data);onmessage=at(n)}),6,1)}}();function zt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[_],(function(t){return it(kt(t.data[0],t.data[1]))}),0,r)}function kt(t,n){return K(t,n||{},0,0)}_e.AsyncDeflate=xt,_e.deflate=zt,_e.deflateSync=kt;var Mt=function(){function t(t,r){"function"==typeof t&&(r=t,t={}),this.ondata=r;var e=t&&t.dictionary&&t.dictionary.subarray(-32768);this.s={i:0,b:e?e.length:0},this.o=new n(32768),this.p=new n(0),e&&this.o.set(e)}return t.prototype.e=function(t){if(this.ondata||I(5),this.d&&I(4),this.p.length){if(t.length){var r=new n(this.p.length+t.length);r.set(this.p),r.set(t,this.p.length),this.p=r}}else this.p=t},t.prototype.c=function(t){this.s.i=+(this.d=t||!1);var n=this.s.b,r=U(this.p,this.s,this.o);this.ondata(D(r,n,this.s.b),this.d),this.o=D(r,this.s.b-32768),this.s.b=this.o.length,this.p=D(this.p,this.s.p/8|0),this.s.p&=7},t.prototype.push=function(t,n){this.e(t),this.c(n)},t}();_e.Inflate=Mt;var St=function(){return function(t,n){ut([$,function(){return[at,Mt]}],this,bt.call(this,t,n),(function(t){var n=new Mt(t.data);onmessage=at(n)}),7,0)}}();function At(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[$],(function(t){return it(Tt(t.data[0],ot(t.data[1])))}),1,r)}function Tt(t,n){return U(t,{i:2},n&&n.out,n&&n.dictionary)}_e.AsyncInflate=St,_e.inflate=At,_e.inflateSync=Tt;var Dt=function(){function t(t,n){this.c=Y(),this.l=0,this.v=1,wt.call(this,t,n)}return t.prototype.push=function(t,n){this.c.p(t),this.l+=t.length,wt.prototype.push.call(this,t,n)},t.prototype.p=function(t,n){var r=K(t,this.o,this.v&&gt(this.o),n&&8,this.s);this.v&&(pt(r,this.o),this.v=0),n&&(ct(r,r.length-8,this.c.d()),ct(r,r.length-4,this.l)),this.ondata(r,n)},t.prototype.flush=function(){wt.prototype.flush.call(this)},t}();_e.Gzip=Dt,_e.Compress=Dt;var Ct=function(){return function(t,n){ut([_,tt,function(){return[at,wt,Dt]}],this,bt.call(this,t,n),(function(t){var n=new Dt(t.data);onmessage=at(n)}),8,1)}}();function It(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[_,tt,function(){return[Ut]}],(function(t){return it(Ut(t.data[0],t.data[1]))}),2,r)}function Ut(t,n){n||(n={});var r=Y(),e=t.length;r.p(t);var i=K(t,n,gt(n),8),o=i.length;return pt(i,n),ct(i,o-8,r.d()),ct(i,o-4,e),i}_e.AsyncGzip=Ct,_e.AsyncCompress=Ct,_e.gzip=It,_e.compress=It,_e.gzipSync=Ut,_e.compressSync=Ut;var Ft=function(){function t(t,n){this.v=1,this.r=0,Mt.call(this,t,n)}return t.prototype.push=function(t,r){if(Mt.prototype.e.call(this,t),this.r+=t.length,this.v){var e=this.p.subarray(this.v-1),i=e.length>3?vt(e):4;if(i>e.length){if(!r)return}else this.v>1&&this.onmember&&this.onmember(this.r-e.length);this.p=e.subarray(i),this.v=0}Mt.prototype.c.call(this,r),!this.s.f||this.s.l||r||(this.v=T(this.s.p)+9,this.s={i:0},this.o=new n(0),this.push(new n(0),r))},t}();_e.Gunzip=Ft;var Et=function(){return function(t,n){var r=this;ut([$,nt,function(){return[at,Mt,Ft]}],this,bt.call(this,t,n),(function(t){var n=new Ft(t.data);n.onmember=function(t){return postMessage(t)},onmessage=at(n)}),9,0,(function(t){return r.onmember&&r.onmember(t)}))}}();function Zt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[$,nt,function(){return[qt]}],(function(t){return it(qt(t.data[0],t.data[1]))}),3,r)}function qt(t,r){var e=vt(t);return e+8>t.length&&I(6,"invalid gzip data"),U(t.subarray(e,-8),{i:2},r&&r.out||new n(dt(t)),r&&r.dictionary)}_e.AsyncGunzip=Et,_e.gunzip=Zt,_e.gunzipSync=qt;var Ot=function(){function t(t,n){this.c=J(),this.v=1,wt.call(this,t,n)}return t.prototype.push=function(t,n){this.c.p(t),wt.prototype.push.call(this,t,n)},t.prototype.p=function(t,n){var r=K(t,this.o,this.v&&(this.o.dictionary?6:2),n&&4,this.s);this.v&&(yt(r,this.o),this.v=0),n&&ct(r,r.length-4,this.c.d()),this.ondata(r,n)},t.prototype.flush=function(){wt.prototype.flush.call(this)},t}();_e.Zlib=Ot;var Gt=function(){return function(t,n){ut([_,rt,function(){return[at,wt,Ot]}],this,bt.call(this,t,n),(function(t){var n=new Ot(t.data);onmessage=at(n)}),10,1)}}();function Lt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[_,rt,function(){return[Ht]}],(function(t){return it(Ht(t.data[0],t.data[1]))}),4,r)}function Ht(t,n){n||(n={});var r=J();r.p(t);var e=K(t,n,n.dictionary?6:2,4);return yt(e,n),ct(e,e.length-4,r.d()),e}_e.AsyncZlib=Gt,_e.zlib=Lt,_e.zlibSync=Ht;var jt=function(){function t(t,n){Mt.call(this,t,n),this.v=t&&t.dictionary?2:1}return t.prototype.push=function(t,n){if(Mt.prototype.e.call(this,t),this.v){if(this.p.length<6&&!n)return;this.p=this.p.subarray(mt(this.p,this.v-1)),this.v=0}n&&(this.p.length<4&&I(6,"invalid zlib data"),this.p=this.p.subarray(0,-4)),Mt.prototype.c.call(this,n)},t}();_e.Unzlib=jt;var Nt=function(){return function(t,n){ut([$,et,function(){return[at,Mt,jt]}],this,bt.call(this,t,n),(function(t){var n=new jt(t.data);onmessage=at(n)}),11,0)}}();function Pt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),st(t,n,[$,et,function(){return[Bt]}],(function(t){return it(Bt(t.data[0],ot(t.data[1])))}),5,r)}function Bt(t,n){return U(t.subarray(mt(t,n&&n.dictionary),-4),{i:2},n&&n.out,n&&n.dictionary)}_e.AsyncUnzlib=Nt,_e.unzlib=Pt,_e.unzlibSync=Bt;var Yt=function(){function t(t,n){this.o=bt.call(this,t,n)||{},this.G=Ft,this.I=Mt,this.Z=jt}return t.prototype.i=function(){var t=this;this.s.ondata=function(n,r){t.ondata(n,r)}},t.prototype.push=function(t,r){if(this.ondata||I(5),this.s)this.s.push(t,r);else{if(this.p&&this.p.length){var e=new n(this.p.length+t.length);e.set(this.p),e.set(t,this.p.length)}else this.p=t;this.p.length>2&&(this.s=31==this.p[0]&&139==this.p[1]&&8==this.p[2]?new this.G(this.o):8!=(15&this.p[0])||this.p[0]>>4>7||(this.p[0]<<8|this.p[1])%31?new this.I(this.o):new this.Z(this.o),this.i(),this.s.push(this.p,r),this.p=null)}},t}();_e.Decompress=Yt;var Jt=function(){function t(t,n){Yt.call(this,t,n),this.queuedSize=0,this.G=Et,this.I=St,this.Z=Nt}return t.prototype.i=function(){var t=this;this.s.ondata=function(n,r,e){t.ondata(n,r,e)},this.s.ondrain=function(n){t.queuedSize-=n,t.ondrain&&t.ondrain(n)}},t.prototype.push=function(t,n){this.queuedSize+=t.length,Yt.prototype.push.call(this,t,n)},t}();function Kt(t,n,r){return r||(r=n,n={}),"function"!=typeof r&&I(7),31==t[0]&&139==t[1]&&8==t[2]?Zt(t,n,r):8!=(15&t[0])||t[0]>>4>7||(t[0]<<8|t[1])%31?At(t,n,r):Pt(t,n,r)}function Qt(t,n){return 31==t[0]&&139==t[1]&&8==t[2]?qt(t,n):8!=(15&t[0])||t[0]>>4>7||(t[0]<<8|t[1])%31?Tt(t,n):Bt(t,n)}_e.AsyncDecompress=Jt,_e.decompress=Kt,_e.decompressSync=Qt;var Rt=function(t,r,e,i){for(var o in t){var s=t[o],a=r+o,u=i;Array.isArray(s)&&(u=Q(i,s[1]),s=s[0]),s instanceof n?e[a]=[s,u]:(e[a+="/"]=[new n(0),u],Rt(s,a,e,i))}},Vt="undefined"!=typeof TextEncoder&&new TextEncoder,Wt="undefined"!=typeof TextDecoder&&new TextDecoder,Xt=0;try{Wt.decode(N,{stream:!0}),Xt=1}catch(t){}var $t=function(t){for(var n="",r=0;;){var e=t[r++],i=(e>127)+(e>223)+(e>239);if(r+i>t.length)return{s:n,r:D(t,r-1)};i?3==i?(e=((15&e)<<18|(63&t[r++])<<12|(63&t[r++])<<6|63&t[r++])-65536,n+=String.fromCharCode(55296|e>>10,56320|1023&e)):n+=String.fromCharCode(1&i?(31&e)<<6|63&t[r++]:(15&e)<<12|(63&t[r++])<<6|63&t[r++]):n+=String.fromCharCode(e)}},_t=function(){function t(t){this.ondata=t,Xt?this.t=new TextDecoder:this.p=N}return t.prototype.push=function(t,r){if(this.ondata||I(5),r=!!r,this.t)return this.ondata(this.t.decode(t,{stream:!0}),r),void(r&&(this.t.decode().length&&I(8),this.t=null));this.p||I(4);var e=new n(this.p.length+t.length);e.set(this.p),e.set(t,this.p.length);var i=$t(e),o=i.s,s=i.r;r?(s.length&&I(8),this.p=null):this.p=s,this.ondata(o,r)},t}();_e.DecodeUTF8=_t;var tn=function(){function t(t){this.ondata=t}return t.prototype.push=function(t,n){this.ondata||I(5),this.d&&I(4),this.ondata(nn(t),this.d=n||!1)},t}();function nn(t,r){if(r){for(var e=new n(t.length),i=0;i<t.length;++i)e[i]=t.charCodeAt(i);return e}if(Vt)return Vt.encode(t);var o=t.length,s=new n(t.length+(t.length>>1)),a=0,u=function(t){s[a++]=t};for(i=0;i<o;++i){if(a+5>s.length){var h=new n(a+8+(o-i<<1));h.set(s),s=h}var f=t.charCodeAt(i);f<128||r?u(f):f<2048?(u(192|f>>6),u(128|63&f)):f>55295&&f<57344?(u(240|(f=65536+(1047552&f)|1023&t.charCodeAt(++i))>>18),u(128|f>>12&63),u(128|f>>6&63),u(128|63&f)):(u(224|f>>12),u(128|f>>6&63),u(128|63&f))}return D(s,0,a)}function rn(t,n){if(n){for(var r="",e=0;e<t.length;e+=16384)r+=String.fromCharCode.apply(null,t.subarray(e,e+16384));return r}if(Wt)return Wt.decode(t);var i=$t(t),o=i.s;return(r=i.r).length&&I(8),o}_e.EncodeUTF8=tn,_e.strToU8=nn,_e.strFromU8=rn;var en=function(t){return 1==t?3:t<6?2:9==t?1:0},on=function(t,n){return n+30+ht(t,n+26)+ht(t,n+28)},sn=function(t,n,r){var e=ht(t,n+28),i=rn(t.subarray(n+46,n+46+e),!(2048&ht(t,n+8))),o=n+46+e,s=ft(t,n+20),a=r&&4294967295==s?an(t,o):[s,ft(t,n+24),ft(t,n+42)],u=a[0],h=a[1],f=a[2];return[ht(t,n+10),u,h,i,o+ht(t,n+30)+ht(t,n+32),f]},an=function(t,n){for(;1!=ht(t,n);n+=4+ht(t,n+2));return[lt(t,n+12),lt(t,n+4),lt(t,n+20)]},un=function(t){var n=0;if(t)for(var r in t){var e=t[r].length;e>65535&&I(9),n+=e+4}return n},hn=function(t,n,r,e,i,o,s,a){var u=e.length,h=r.extra,f=a&&a.length,l=un(h);ct(t,n,null!=s?33639248:67324752),n+=4,null!=s&&(t[n++]=20,t[n++]=r.os),t[n]=20,n+=2,t[n++]=r.flag<<1|(o<0&&8),t[n++]=i&&8,t[n++]=255&r.compression,t[n++]=r.compression>>8;var c=new Date(null==r.mtime?Date.now():r.mtime),p=c.getFullYear()-1980;if((p<0||p>119)&&I(10),ct(t,n,p<<25|c.getMonth()+1<<21|c.getDate()<<16|c.getHours()<<11|c.getMinutes()<<5|c.getSeconds()>>1),n+=4,-1!=o&&(ct(t,n,r.crc),ct(t,n+4,o<0?-o-2:o),ct(t,n+8,r.size)),ct(t,n+12,u),ct(t,n+14,l),n+=16,null!=s&&(ct(t,n,f),ct(t,n+6,r.attrs),ct(t,n+10,s),n+=14),t.set(e,n),n+=u,l)for(var v in h){var d=h[v],g=d.length;ct(t,n,+v),ct(t,n+2,g),t.set(d,n+4),n+=4+g}return f&&(t.set(a,n),n+=f),n},fn=function(t,n,r,e,i){ct(t,n,101010256),ct(t,n+8,r),ct(t,n+10,r),ct(t,n+12,e),ct(t,n+16,i)},ln=function(){function t(t){this.filename=t,this.c=Y(),this.size=0,this.compression=0}return t.prototype.process=function(t,n){this.ondata(null,t,n)},t.prototype.push=function(t,n){this.ondata||I(5),this.c.p(t),this.size+=t.length,n&&(this.crc=this.c.d()),this.process(t,n||!1)},t}();_e.ZipPassThrough=ln;var cn=function(){function t(t,n){var r=this;n||(n={}),ln.call(this,t),this.d=new wt(n,(function(t,n){r.ondata(null,t,n)})),this.compression=8,this.flag=en(n.level)}return t.prototype.process=function(t,n){try{this.d.push(t,n)}catch(t){this.ondata(t,null,n)}},t.prototype.push=function(t,n){ln.prototype.push.call(this,t,n)},t}();_e.ZipDeflate=cn;var pn=function(){function t(t,n){var r=this;n||(n={}),ln.call(this,t),this.d=new xt(n,(function(t,n,e){r.ondata(t,n,e)})),this.compression=8,this.flag=en(n.level),this.terminate=this.d.terminate}return t.prototype.process=function(t,n){this.d.push(t,n)},t.prototype.push=function(t,n){ln.prototype.push.call(this,t,n)},t}();_e.AsyncZipDeflate=pn;var vn=function(){function t(t){this.ondata=t,this.u=[],this.d=1}return t.prototype.add=function(t){var r=this;if(this.ondata||I(5),2&this.d)this.ondata(I(4+8*(1&this.d),0,1),null,!1);else{var e=nn(t.filename),i=e.length,o=t.comment,s=o&&nn(o),a=i!=t.filename.length||s&&o.length!=s.length,u=i+un(t.extra)+30;i>65535&&this.ondata(I(11,0,1),null,!1);var h=new n(u);hn(h,0,t,e,a,-1);var f=[h],l=function(){for(var t=0,n=f;t<n.length;t++)r.ondata(null,n[t],!1);f=[]},c=this.d;this.d=0;var p=this.u.length,v=Q(t,{f:e,u:a,o:s,t:function(){t.terminate&&t.terminate()},r:function(){if(l(),c){var t=r.u[p+1];t?t.r():r.d=1}c=1}}),d=0;t.ondata=function(e,i,o){if(e)r.ondata(e,i,o),r.terminate();else if(d+=i.length,f.push(i),o){var s=new n(16);ct(s,0,134695760),ct(s,4,t.crc),ct(s,8,d),ct(s,12,t.size),f.push(s),v.c=d,v.b=u+d+16,v.crc=t.crc,v.size=t.size,c&&v.r(),c=1}else c&&l()},this.u.push(v)}},t.prototype.end=function(){var t=this;2&this.d?this.ondata(I(4+8*(1&this.d),0,1),null,!0):(this.d?this.e():this.u.push({r:function(){1&t.d&&(t.u.splice(-1,1),t.e())},t:function(){}}),this.d=3)},t.prototype.e=function(){for(var t=0,r=0,e=0,i=0,o=this.u;i<o.length;i++)e+=46+(h=o[i]).f.length+un(h.extra)+(h.o?h.o.length:0);for(var s=new n(e+22),a=0,u=this.u;a<u.length;a++){var h;hn(s,t,h=u[a],h.f,h.u,-h.c-2,r,h.o),t+=46+h.f.length+un(h.extra)+(h.o?h.o.length:0),r+=h.b}fn(s,t,this.u.length,e,r),this.ondata(null,s,!0),this.d=2},t.prototype.terminate=function(){for(var t=0,n=this.u;t<n.length;t++)n[t].t();this.d=2},t}();function dn(t,r,e){e||(e=r,r={}),"function"!=typeof e&&I(7);var i={};Rt(t,"",i,r);var o=Object.keys(i),s=o.length,a=0,u=0,h=s,f=Array(s),l=[],c=function(){for(var t=0;t<l.length;++t)l[t]()},p=function(t,n){xn((function(){e(t,n)}))};xn((function(){p=e}));var v=function(){var t=new n(u+22),r=a,e=u-a;u=0;for(var i=0;i<h;++i){var o=f[i];try{var s=o.c.length;hn(t,u,o,o.f,o.u,s);var l=30+o.f.length+un(o.extra),c=u+l;t.set(o.c,c),hn(t,a,o,o.f,o.u,s,u,o.m),a+=16+l+(o.m?o.m.length:0),u=c+s}catch(t){return p(t,null)}}fn(t,a,f.length,e,r),p(null,t)};s||v();for(var d=function(t){var n=o[t],r=i[n],e=r[0],h=r[1],d=Y(),g=e.length;d.p(e);var y=nn(n),m=y.length,b=h.comment,w=b&&nn(b),x=w&&w.length,z=un(h.extra),k=0==h.level?0:8,M=function(r,e){if(r)c(),p(r,null);else{var i=e.length;f[t]=Q(h,{size:g,crc:d.d(),c:e,f:y,m:w,u:m!=n.length||w&&b.length!=x,compression:k}),a+=30+m+z+i,u+=76+2*(m+z)+(x||0)+i,--s||v()}};if(m>65535&&M(I(11,0,1),null),k)if(g<16e4)try{M(null,kt(e,h))}catch(t){M(t,null)}else l.push(zt(e,h,M));else M(null,e)},g=0;g<h;++g)d(g);return c}function gn(t,r){r||(r={});var e={},i=[];Rt(t,"",e,r);var o=0,s=0;for(var a in e){var u=e[a],h=u[0],f=u[1],l=0==f.level?0:8,c=(M=nn(a)).length,p=f.comment,v=p&&nn(p),d=v&&v.length,g=un(f.extra);c>65535&&I(11);var y=l?kt(h,f):h,m=y.length,b=Y();b.p(h),i.push(Q(f,{size:h.length,crc:b.d(),c:y,f:M,m:v,u:c!=a.length||v&&p.length!=d,o:o,compression:l})),o+=30+c+g+m,s+=76+2*(c+g)+(d||0)+m}for(var w=new n(s+22),x=o,z=s-o,k=0;k<i.length;++k){var M;hn(w,(M=i[k]).o,M,M.f,M.u,M.c.length);var S=30+M.f.length+un(M.extra);w.set(M.c,M.o+S),hn(w,o,M,M.f,M.u,M.c.length,M.o,M.m),o+=16+S+(M.m?M.m.length:0)}return fn(w,o,i.length,z,x),w}_e.Zip=vn,_e.zip=dn,_e.zipSync=gn;var yn=function(){function t(){}return t.prototype.push=function(t,n){this.ondata(null,t,n)},t.compression=0,t}();_e.UnzipPassThrough=yn;var mn=function(){function t(){var t=this;this.i=new Mt((function(n,r){t.ondata(null,n,r)}))}return t.prototype.push=function(t,n){try{this.i.push(t,n)}catch(t){this.ondata(t,null,n)}},t.compression=8,t}();_e.UnzipInflate=mn;var bn=function(){function t(t,n){var r=this;n<32e4?this.i=new Mt((function(t,n){r.ondata(null,t,n)})):(this.i=new St((function(t,n,e){r.ondata(t,n,e)})),this.terminate=this.i.terminate)}return t.prototype.push=function(t,n){this.i.terminate&&(t=D(t,0)),this.i.push(t,n)},t.compression=8,t}();_e.AsyncUnzipInflate=bn;var wn=function(){function t(t){this.onfile=t,this.k=[],this.o={0:yn},this.p=N}return t.prototype.push=function(t,r){var e=this;if(this.onfile||I(5),this.p||I(4),this.c>0){var i=Math.min(this.c,t.length),o=t.subarray(0,i);if(this.c-=i,this.d?this.d.push(o,!this.c):this.k[0].push(o),(t=t.subarray(i)).length)return this.push(t,r)}else{var s=0,a=0,u=void 0,h=void 0;this.p.length?t.length?((h=new n(this.p.length+t.length)).set(this.p),h.set(t,this.p.length)):h=this.p:h=t;for(var f=h.length,l=this.c,c=l&&this.d,p=function(){var t,n=ft(h,a);if(67324752==n){s=1,u=a,v.d=null,v.c=0;var r=ht(h,a+6),i=ht(h,a+8),o=2048&r,c=8&r,p=ht(h,a+26),d=ht(h,a+28);if(f>a+30+p+d){var g=[];v.k.unshift(g),s=2;var y,m=ft(h,a+18),b=ft(h,a+22),w=rn(h.subarray(a+30,a+=30+p),!o);4294967295==m?(t=c?[-2]:an(h,a),m=t[0],b=t[1]):c&&(m=-1),a+=d,v.c=m;var x={name:w,compression:i,start:function(){if(x.ondata||I(5),m){var t=e.o[i];t||x.ondata(I(14,"unknown compression type "+i,1),null,!1),(y=m<0?new t(w):new t(w,m,b)).ondata=function(t,n,r){x.ondata(t,n,r)};for(var n=0,r=g;n<r.length;n++)y.push(r[n],!1);e.k[0]==g&&e.c?e.d=y:y.push(N,!0)}else x.ondata(null,N,!0)},terminate:function(){y&&y.terminate&&y.terminate()}};m>=0&&(x.size=m,x.originalSize=b),v.onfile(x)}return"break"}if(l){if(134695760==n)return u=a+=12+(-2==l&&8),s=3,v.c=0,"break";if(33639248==n)return u=a-=4,s=3,v.c=0,"break"}},v=this;a<f-4&&"break"!==p();++a);if(this.p=N,l<0){var d=h.subarray(0,s?u-12-(-2==l&&8)-(134695760==ft(h,u-16)&&4):a);c?c.push(d,!!s):this.k[+(2==s)].push(d)}if(2&s)return this.push(h.subarray(a),r);this.p=h.subarray(a)}r&&(this.c&&I(13),this.p=null)},t.prototype.register=function(t){this.o[t.compression]=t},t}();_e.Unzip=wn;var xn="function"==typeof queueMicrotask?queueMicrotask:"function"==typeof setTimeout?setTimeout:function(t){t()};function zn(t,r,e){e||(e=r,r={}),"function"!=typeof e&&I(7);var i=[],o=function(){for(var t=0;t<i.length;++t)i[t]()},s={},a=function(t,n){xn((function(){e(t,n)}))};xn((function(){a=e}));for(var u=t.length-22;101010256!=ft(t,u);--u)if(!u||t.length-u>65558)return a(I(13,0,1),null),o;var h=ht(t,u+8);if(h){var f=h,l=ft(t,u+16),c=4294967295==l||65535==f;if(c){var p=ft(t,u-12);(c=101075792==ft(t,p))&&(f=h=ft(t,p+32),l=ft(t,p+48))}for(var v=r&&r.filter,d=function(r){var e=sn(t,l,c),u=e[0],f=e[1],p=e[2],d=e[3],g=e[4],y=on(t,e[5]);l=g;var m=function(t,n){t?(o(),a(t,null)):(n&&(s[d]=n),--h||a(null,s))};if(!v||v({name:d,size:f,originalSize:p,compression:u}))if(u)if(8==u){var b=t.subarray(y,y+f);if(p<524288||f>.8*p)try{m(null,Tt(b,{out:new n(p)}))}catch(t){m(t,null)}else i.push(At(b,{size:p},m))}else m(I(14,"unknown compression type "+u,1),null);else m(null,D(t,y,y+f));else m(null,null)},g=0;g<f;++g)d()}else a(null,{});return o}function kn(t,r){for(var e={},i=t.length-22;101010256!=ft(t,i);--i)(!i||t.length-i>65558)&&I(13);var o=ht(t,i+8);if(!o)return{};var s=ft(t,i+16),a=4294967295==s||65535==o;if(a){var u=ft(t,i-12);(a=101075792==ft(t,u))&&(o=ft(t,u+32),s=ft(t,u+48))}for(var h=r&&r.filter,f=0;f<o;++f){var l=sn(t,s,a),c=l[0],p=l[1],v=l[2],d=l[3],g=l[4],y=on(t,l[5]);s=g,h&&!h({name:d,size:p,originalSize:v,compression:c})||(c?8==c?e[d]=Tt(t.subarray(y,y+p),{out:new n(v)}):I(14,"unknown compression type "+c):e[d]=D(t,y,y+p))}return e}_e.unzip=zn,_e.unzipSync=kn;return _e});

  const UPDATE_DEBUG = false;

  const Y2JB_UPDATER_VERSION = "1.2";

  const WORKDIR = "/mnt/sandbox/" + get_title_id() + "_000/download0/cache/splash_screen/";
  const WORKDIR_DEBUG = "/mnt/usb0/";

  let FINAL_PATH =  WORKDIR + "aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=";
  let EXTRACT_PATH = WORKDIR + "UPDATER_EXTRACT";
  let TEMP_BACKUP = WORKDIR + "UPDATER_BACKUP";

  if (UPDATE_DEBUG == true) {
      FINAL_PATH = WORKDIR_DEBUG + "UPDATER_DEBUG_FINAL";
      EXTRACT_PATH = WORKDIR_DEBUG + "UPDATER_DEBUG_EXTRACT";
      TEMP_BACKUP = WORKDIR_DEBUG + "UPDATER_DEBUG_BACKUP";
  }

  const createdDirs = new Set(['/']);

  function ensureDirectoryExists(dirPath) {
      if (!dirPath || dirPath.length === 0) return false;
      // remove trailing slash
      if (dirPath.endsWith('/')) dirPath = dirPath.slice(0, -1);
      // If it's just root or empty, nothing to do
      if (dirPath === '' || dirPath === '/') return true;

      const parts = dirPath.split('/');
      // handle absolute paths: first element will be empty string
      let cur = parts[0] === "" ? "" : parts[0];

      for (let i = (parts[0] === "" ? 1 : 0); i < parts.length; i++) {
          if (!parts[i]) continue;
          cur = (cur === "") ? ("/" + parts[i]) : (cur + "/" + parts[i]);

          // skip if already created/checked
          if (createdDirs.has(cur)) continue;

          try {
              // check if exists (stat)
              const addr = alloc_string(cur);
              const stat_buf = malloc(0x200n);
              const st = syscall(SYSCALL.stat, addr, stat_buf);
              if (st === 0n) {
                  createdDirs.add(cur);
                  continue;
              }

              // try to create
              const ret = syscall(SYSCALL.mkdir, addr, 0o755n);
              if (ret === 0n) {
                  createdDirs.add(cur);
                  log("mkdir created: " + cur);
              } else {
                  // if ret < 0, possible errno (e.g. EEXIST) — check stat again
                  const stat_buf2 = malloc(0x200n);
                  const st2 = syscall(SYSCALL.stat, addr, stat_buf2);
                  if (st2 === 0n) {
                      createdDirs.add(cur);
                  } else {
                      // report error to log
                      log("mkdir returned: " + toHex(ret) + " for " + cur);
                  }
              }
          } catch (e) {
              log("mkdir threw: " + (e && e.message ? e.message : String(e)));
          }
      }
      return true;
  }

  async function rmdir(dirPath) {
    try {
      if (typeof dirPath !== "string" || !dirPath.startsWith("/")) {
        send_notification("rmdir: invalid path (must be absolute)");
        return { ok: false, code: -1n, msg: "path must be absolute" };
      }

      if (!dirPath.startsWith(WORKDIR) && !dirPath.startsWith(WORKDIR_DEBUG)) {
        send_notification("rmdir: refusing to remove outside safe area -> " + dirPath);
        return { ok: false, code: -3n, msg: "refuse to remove outside safe area" };
      }

      const parts = dirPath.split("/");
      if (dirPath.startsWith(WORKDIR_DEBUG) && parts.length <= 3) { // e.g., blocks /mnt/usb0 itself
          send_notification("rmdir: refusing to remove debug root -> " + dirPath);
          return { ok: false, code: -2n, msg: "refuse to remove top-level" };
      }
      if (dirPath.startsWith(WORKDIR) && parts.length <= 7) { // blocks base path
          send_notification("rmdir: refusing to remove sandbox root -> " + dirPath);
          return { ok: false, code: -2n, msg: "refuse to remove top-level" };
      }

      const O_RDONLY = 0n;
      const buf_size = 4096n;
      const buf = malloc(buf_size);
      const path_ptr = alloc_string(dirPath);
      const dirfd = syscall(SYSCALL.open, path_ptr, O_RDONLY, 0n);
      if (dirfd < 0n) {
        send_notification("rmdir: open failed -> " + toHex(dirfd));
        return { ok: false, code: dirfd, msg: "open failed" };
      }

      // pre-check: does directory exist?
      const stat_chk_buf = malloc(0x200n);
      const stat_ret = syscall(SYSCALL.stat, path_ptr, stat_chk_buf);
      if (stat_ret !== 0n) {
        syscall(SYSCALL.close, dirfd);
        send_notification("rmdir: path does not exist or inaccessible -> " + String(dirPath));
        return { ok: false, code: stat_ret, msg: "not exists or inaccessible" };
      }

      // 1) Read all entries into an array first (avoid modifying dir while iterating)
      const entries = [];
      let seenGetdentsError = false;
      while (true) {
        const nread = syscall(SYSCALL.getdents, dirfd, buf, buf_size);
        // only notify once on persistent getdents error to avoid spam
        if (nread < 0n) {
          if (!seenGetdentsError) {
            const errno = Number(-nread);
            send_notification("rmdir: getdents error -> " + toHex(nread) + " errno=" + String(errno));
            seenGetdentsError = true;
          }
          syscall(SYSCALL.close, dirfd);
          return { ok: false, code: nread, msg: "getdents failed" };
        }
        if (nread === 0n) break;

        let offset = 0n;
        while (offset < nread) {
          const d_reclen = Number(read16(buf + offset + 4n));
          if (d_reclen === 0) break;
          const d_type = Number(read8(buf + offset + 6n));
          const d_namlen = Number(read8(buf + offset + 7n));
          let name = "";
          for (let i = 0; i < d_namlen; i++) {
            const ch = Number(read8(buf + offset + 8n + BigInt(i)));
            if (ch === 0) break;
            name += String.fromCharCode(ch);
          }
          offset += BigInt(d_reclen);
          if (!name || name === "." || name === "..") continue;
          entries.push({ name, d_type });
        }
      }
      syscall(SYSCALL.close, dirfd);

      // 2) Process collected entries sequentially
      for (const ent of entries) {
        const name = ent.name;
        const child = dirPath === "/" ? ("/" + name) : (dirPath + "/" + name);
        const cptr = alloc_string(child);

        if (ent.d_type === 0x4) { // It's a directory
          // directory -> recurse
          const rec = await rmdir(child);
          if (!rec.ok) return rec;
          await sleep(20);

        } else if (ent.d_type === 0x8) { // It's a file
          const unlinkRet = syscall(SYSCALL.unlink, cptr);
          if (unlinkRet !== 0n) {
            send_notification("rmdir: unlink failed for file " + child + " -> " + toHex(unlinkRet));
            return { ok: false, code: unlinkRet, msg: "unlink failed for file" };
          }
          await sleep(10);

        } else {
          // It's a symlink, socket, etc. Try to unlink it.
          const unlinkRet = syscall(SYSCALL.unlink, cptr);
          if (unlinkRet === 0n) {
            await sleep(10);
            continue;
          }
          
          // If unlink failed, it might be a directory we couldn't stat (e.g. symlink to dir)
          // Fallback to the stat logic just in case
          const stat_buf = malloc(0x200n);
          const sret = syscall(SYSCALL.stat, cptr, stat_buf);
          if (sret === 0n && (read16(stat_buf + 8n) & 0x4000n) !== 0n) {
            const rec = await rmdir(child);
            if (!rec.ok) return rec;
            await sleep(20);
          } else {
            send_notification("rmdir: unlink failed for " + child + " -> " + toHex(unlinkRet));
            return { ok: false, code: unlinkRet, msg: "unlink failed for unknown type" };
          }
        }
      }

      // finally remove the directory itself
      const final = syscall(SYSCALL.rmdir, alloc_string(dirPath));
      if (final !== 0n) {
        send_notification("rmdir: final rmdir failed for " + dirPath + " -> " + toHex(final));
        return { ok: false, code: final, msg: "final rmdir failed" };
      }

      return { ok: true, code: 0n };
    } catch (e) {
      const msg = e && e.message ? e.message : String(e);
      send_notification("rmdir: exception -> " + msg);
      return { ok: false, code: -99n, msg };
    }
  }



  function bufferPtrToUint8Array(bufPtr, size) {
      const n = Number(size);
      const arr = new Uint8Array(n);
      for (let i = 0; i < n; i++) {
          arr[i] = Number(read8(bufPtr + BigInt(i)));
      }
      return arr;
  }

  function writeUint8ArrayToFile(path, uint8arr) {
      const path_addr = alloc_string(path);
      // flags: O_WRONLY|O_CREAT|O_TRUNC, mode 0755
      const flags = O_WRONLY | O_CREAT | O_TRUNC;
      const mode = 0o755n;
      const fd = syscall(SYSCALL.open, path_addr, BigInt(flags), mode);
      if (fd < 0n) {
          const err = toHex(fd);
          log("[ERROR] open for write failed: " + path + " fd=" + err);
          send_notification("[ERROR] open for write failed: " + path + " fd=" + err);
          return false;
      }
      // allocate buffer in memory and copy bytes
      const buf = malloc(BigInt(uint8arr.length));
      for (let i = 0; i < uint8arr.length; i++) {
          write8(buf + BigInt(i), BigInt(uint8arr[i]));
      }
      const wrote = syscall(SYSCALL.write, fd, buf, BigInt(uint8arr.length));
      const closeRet = syscall(SYSCALL.close, fd);
      if (wrote < 0n) {
          const err = toHex(wrote);
          log("[ERROR] write failed for " + path + " -> " + err);
          send_notification("[ERROR] write failed for " + path + " -> " + err);
          return false;
      }
      if (wrote !== BigInt(uint8arr.length)) {
          log("[WARN] partial write for " + path + " wrote=" + wrote + " expected=" + uint8arr.length);
          send_notification("[WARN] partial write for " + path + " wrote=" + wrote + " expected=" + uint8arr.length);
          return false;
      }
      if (closeRet < 0n) {
          log("[WARN] close returned " + toHex(closeRet) + " for " + path);
          send_notification("[WARN] close returned " + toHex(closeRet) + " for " + path);
      }
      return true;
  }

  function write_buffer_to_file(path, buffer_ptr, size) {
      const path_addr = alloc_string(path);
      // flags: O_WRONLY|O_CREAT|O_TRUNC, mode 0755
      const flags = O_WRONLY | O_CREAT | O_TRUNC;
      const mode = 0o755n;
      const fd = syscall(SYSCALL.open, path_addr, BigInt(flags), mode);
      if (fd < 0n) {
          const err = toHex(fd);
          log("[ERROR] open for write failed: " + path + " fd=" + err);
          send_notification("[ERROR] open for write failed: " + path + " fd=" + err);
          return false;
      }

      // Write directly from the provided buffer pointer
      const wrote = syscall(SYSCALL.write, fd, buffer_ptr, BigInt(size));
      const closeRet = syscall(SYSCALL.close, fd);

      if (wrote < 0n) {
          const err = toHex(wrote);
          log("[ERROR] write failed for " + path + " -> " + err);
          send_notification("[ERROR] write failed for " + path + " -> " + err);
          return false;
      }
      if (wrote !== BigInt(size)) {
          log("[WARN] partial write for " + path + " wrote=" + wrote + " expected=" + size);
          send_notification("[WARN] partial write for " + path + " wrote=" + wrote + " expected=" + size);
          return false;
      }
      if (closeRet < 0n) {
          log("[WARN] close returned " + toHex(closeRet) + " for " + path);
          send_notification("[WARN] close returned " + toHex(closeRet) + " for " + path);
      }
      return true;
  }


  function read_file_to_buffer(path) {
    const path_addr = alloc_string(path);
    const stat_buf = malloc(0x200n);
    if (syscall(SYSCALL.stat, path_addr, stat_buf) !== 0n) {
      throw new Error("read_file_to_buffer: stat failed for " + path);
    }
    const file_size = Number(read64(stat_buf + 72n));

    if (file_size < 0n) {
      throw new Error("read_file_to_buffer: invalid file size " + file_size);
    }
    if (file_size === 0n) { // empty file
        return { buffer: malloc(0n), size: 0 };
    }

    const fd = syscall(SYSCALL.open, path_addr, O_RDONLY, 0n);
    if (fd < 0n) {
      throw new Error("read_file_to_buffer: open failed for " + path + " fd: " + toHex(fd));
    }

    const file_buffer = malloc(BigInt(file_size));
    let total_bytes_read = 0n;

    try {
      const bytes_read = syscall(SYSCALL.read, fd, file_buffer, BigInt(file_size));
      total_bytes_read = bytes_read;

      if (bytes_read < 0n) {
        throw new Error("read_file_to_buffer: read failed: " + toHex(bytes_read));
      }
      if (Number(bytes_read) !== file_size) {
        throw new Error(`read_file_to_buffer: incomplete read. Expected ${file_size}, got ${bytes_read}`);
      }
    } finally {
      syscall(SYSCALL.close, fd);
    }

    return { buffer: file_buffer, size: file_size };
  }

function compare_buffers(buf1_ptr, buf2_ptr, size) {
      const n = BigInt(size);
      for (let i = 0n; i < n; i++) {
          if (read8(buf1_ptr + i) !== read8(buf2_ptr + i)) {
              return false; // Buffers are different
          }
      }
      return true; // Buffers are identical
  }
  

async function updateIcon() {
    const iconPath = "/user/appmeta/" + get_title_id() + "/icon0.png";
    const newIconPath = FINAL_PATH + "/icon0.png";

    if (!file_exists(iconPath)) {
        log("Icon file does not exist: " + iconPath);
        return null;
    }
    
    if (!file_exists(newIconPath)) {
        log("New icon file not found in update package: " + newIconPath);
        return null;
    }

    let currentIcon = null;
    let newIcon = null;
    let areIdentical = false;

    try {
        log("Reading current icon from: " + iconPath);
        currentIcon = read_file_to_buffer(iconPath);
        log("Current icon size: " + currentIcon.size + " bytes");

        log("Reading new icon from: " + newIconPath);
        newIcon = read_file_to_buffer(newIconPath);
        log("New icon size: " + newIcon.size + " bytes");

        if (currentIcon.size !== newIcon.size) {
            log("Icons are different (size mismatch).");
            areIdentical = false;
        } else {
            log("Icons are the same size. Comparing contents...");
            areIdentical = compare_buffers(currentIcon.buffer, newIcon.buffer, currentIcon.size);
        }

        if (!areIdentical) {
            log("Icons are different. Updating icon...");
            const writeSuccess = write_buffer_to_file(iconPath, newIcon.buffer, newIcon.size);
            if (writeSuccess) {
                log("Icon updated successfully at: " + iconPath);
                send_notification("Icon updated successfully.");
            } else {
                log("Failed to update icon at: " + iconPath);
            }
        } else {
            log("Icons are identical. No update needed.");
        }

    } catch (e) {
        const msg = (e && e.message) ? e.message : String(e);
        log("[ERROR] updateIcon failed: " + msg);
        send_notification("[ERROR] updateIcon: " + msg);
    }
  }


  function file_exists(path) {
    const path_addr = alloc_string(path);
    const stat_buf = malloc(0x200n);
    const ret = syscall(SYSCALL.stat, path_addr, stat_buf);
    return ret === 0n;
  }


  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }


  async function renamePath(oldPath, newPath) {
    try {
      // optionally ensure destination parent exists if helper is available
      if (typeof parentDir === "function" && typeof ensureDirectoryExists === "function") {
        const pd = parentDir(newPath);
        if (pd) ensureDirectoryExists(pd);
      }

      const old_addr = alloc_string(oldPath);
      const new_addr = alloc_string(newPath);
      const ret = syscall(SYSCALL.rename, old_addr, new_addr);
      log("renamed: " + oldPath + " -> " + newPath);
      return { ok: ret === 0n, code: ret };
    } catch (e) {
      log("renamePath exception: " + (e && e.message ? e.message : String(e)));
      return { ok: false, code: -1n };
    }
  }


  // Helper: get parent dir path (no trailing slash)
  function parentDir(path) {
      if (!path) return "";
      const idx = path.lastIndexOf('/');
      if (idx <= 0) return "";
      return path.substring(0, idx);
  }


  async function verify_update(extractDir = EXTRACT_PATH) {
      try {
          const dirNoSlash = extractDir.endsWith('/') ? extractDir.slice(0, -1) : extractDir;
          const infoPath = dirNoSlash + "/update-info.txt";

          if (!file_exists(infoPath)) {
              send_notification("verify_update: missing update-info.txt in " + dirNoSlash);
              log("verify_update: missing update-info.txt -> " + infoPath);
              return { ok: false, msg: "missing update-info.txt" };
          }

          let infoBuf;
          try {
              infoBuf = read_file_to_buffer(infoPath);
          } catch (e) {
              const msg = "verify_update: failed to read update-info.txt -> " + (e && e.message ? e.message : String(e));
              send_notification(msg);
              log(msg);
              return { ok: false, msg };
          }

          const infoArr = bufferPtrToUint8Array(infoBuf.buffer, infoBuf.size);
          const infoText = (typeof TextDecoder !== "undefined") ? new TextDecoder().decode(infoArr) : String.fromCharCode.apply(null, infoArr);
          const lines = infoText.split(/\r?\n/).map(l => l.trim()).filter(l => l.length > 0);

          if (lines.length === 0) {
              send_notification("verify_update: update-info.txt is empty");
              log("verify_update: update-info.txt is empty");
              return { ok: false, msg: "empty update-info.txt" };
          }

          for (const line of lines) {
              const parts = line.split("|");
              if (parts.length !== 2) {
                  send_notification("verify_update: malformed line in update-info.txt: " + line);
                  log("verify_update: malformed line: " + line);
                  return { ok: false, msg: "malformed line: " + line };
              }
              const relPath = parts[0].replace(/^\/*/, "");
              const expectedStr = parts[1].trim();
              const expectedSize = Number.parseInt(expectedStr, 10);
              if (!Number.isFinite(expectedSize) || expectedSize < 0) {
                  send_notification("verify_update: invalid size in update-info.txt: " + expectedStr);
                  log("verify_update: invalid size for " + relPath + " -> " + expectedStr);
                  return { ok: false, msg: "invalid size: " + expectedStr };
              }

              const fullPath = dirNoSlash + "/" + relPath;
              if (!file_exists(fullPath)) {
                  send_notification("verify_update: missing file -> " + relPath);
                  log("verify_update: missing file -> " + fullPath);
                  return { ok: false, msg: "missing file: " + relPath };
              }

              // use stat to get file size (avoid reading full file)
              const path_addr = alloc_string(fullPath);
              const stat_buf = malloc(0x200n);
              const st = syscall(SYSCALL.stat, path_addr, stat_buf);
              if (st !== 0n) {
                  const msg = "verify_update: stat failed for " + fullPath + " -> " + toHex(st);
                  send_notification(msg);
                  log(msg);
                  return { ok: false, msg: "stat failed: " + String(st) };
              }
              const actualSize = Number(read64(stat_buf + 72n));

              if (actualSize !== expectedSize) {
                  send_notification("verify_update: size mismatch for " + relPath + " expected=" + expectedSize + " actual=" + actualSize);
                  log("verify_update: size mismatch for " + fullPath + " expected=" + expectedSize + " actual=" + actualSize);
                  return { ok: false, msg: "size mismatch for " + relPath };
              }

              log("verify_update: OK -> " + relPath + " size=" + actualSize);
              await sleep(2);
          }

          send_notification("verify_update: all files OK");
          log("verify_update: verification passed for " + dirNoSlash);
          return { ok: true };
      } catch (e) {
          const msg = "verify_update: exception -> " + (e && e.message ? e.message : String(e));
          send_notification(msg);
          log(msg);
          return { ok: false, msg };
      }
  }

  const updatePaths = [];
  for (let i = 0; i <= 7; i++) {
      updatePaths.push(`/mnt/usb${i}/y2jb_update.zip`);
      updatePaths.push(`/mnt/usb${i}/ps5_autoloader/y2jb_update.zip`);
  }
  updatePaths.push("/data/y2jb_update.zip");
  updatePaths.push("/data/ps5_autoloader/y2jb_update.zip");

  async function update() {
    let updateFound = false;
    let updatePath = null;
    for (const path of updatePaths) {
      if (file_exists(path)) {
        log("Found Y2JB update file at: " + path);
        send_notification("Found Y2JB update file at: " + path);
        updateFound = true;
        updatePath = path;
          break;
      }
    }

      if (!updateFound) {
        log("No Y2JB update file found");
      } else {
        log("Starting Y2JB update from: " + updatePath);
        send_notification("Starting Y2JB update...");
        await process_update(updatePath);

          // Verify extracted update before renaming
          const verifyRes = await verify_update(EXTRACT_PATH);
          if (!verifyRes.ok) {
              send_notification("Update verification failed: " + (verifyRes.msg || "unknown"));
              log("Verification failed - aborting renames: " + JSON.stringify(verifyRes));
              send_notification("Updater aborted due to failed verification.");
              // cleanup extracted files, don't remove update packages

              await sleep(100);
              await cleanUp(false);
          } else {
              // proceed with renaming only if verification passed
              await renamePath(FINAL_PATH, TEMP_BACKUP);
              // check if rename succeeded
              if (!file_exists(TEMP_BACKUP)) {
                  send_notification("Failed to rename:\n" + FINAL_PATH + " ->\n" + TEMP_BACKUP + "\nAborting update.");
                  log("Failed to rename "+ FINAL_PATH + " -> " + TEMP_BACKUP + " Aborting update.");
                  // cleanup extracted files, don't remove update packages
                  await sleep(100);
                  await cleanUp(false);
                  return;
              }
              await renamePath(EXTRACT_PATH, FINAL_PATH);
              if (!file_exists(FINAL_PATH)) {
                  send_notification("Failed to rename:\n" + EXTRACT_PATH + " ->\n" + FINAL_PATH + "\nAborting update.");
                  log("Failed to rename "+ EXTRACT_PATH + " -> " + FINAL_PATH + ". Aborting update.");
                  // try to restore backup
                  await renamePath(TEMP_BACKUP, FINAL_PATH);
                  if (file_exists(FINAL_PATH)) {
                      send_notification("Restored original files from backup.");
                      log("Restored original files from backup.");
                  } else {
                      send_notification("Failed to restore original files from backup!\nUse ftp to fix your Y2JB files.");
                      log("Failed to restore original files from backup! Use ftp to fix your Y2JB files.");
                  }
                  return;
              }
              await sleep(100);
              if (UPDATE_DEBUG) {
                  await cleanUp(false);
              } else {
                  // cleanup extracted files and old backup
                  await cleanUp(true);
              }

              // attempt to update the icon
              try {
                  await updateIcon();
              } catch (e) {
                  const msg = (e && e.message) ? e.message : String(e);
                  log("[WARN] Icon update failed: " + msg);
                  send_notification("[WARN] Icon update failed: " + msg);
              }
          }
      }
  }


  async function process_update(updatePath) {
    try {
      // clean up previous extraction if exists
      await cleanUp(false);

      const { buffer, size } = read_file_to_buffer(updatePath);
      log("Update file size: " + size);
      send_notification("Update size: " + size + " bytes");

      // Convert to Uint8Array
      const zipUint8 = bufferPtrToUint8Array(buffer, size);
      log("Unzipping in-memory...");
      send_notification("Starting extraction...");

      let entries;
      try {
        entries = fflate.unzipSync(zipUint8); // requires fflate included in this script
      } catch (e) {
        const msg = "[-] unzip failed: " + (e && e.message ? e.message : String(e));
        log(msg);
        send_notification(msg);
        return;
      }

      if (!entries) {
        log("[ERROR] unzipSync returned falsy value");
        send_notification("[ERROR] unzipSync returned falsy value");
        return;
      }

      const keys = Object.keys(entries || {});
      log("Unzip entries: " + JSON.stringify(keys));

      // Ensure base output dir exists (create recursively)
      const outDir = EXTRACT_PATH + "/";
      ensureDirectoryExists(outDir);

      let count = 0;
      for (const name of keys) {

        const data = entries[name];
        if (!(data instanceof Uint8Array)) {
          log("Skipping entry (not Uint8Array): " + name);
          continue;
        }

        if (name.startsWith('/') || name.includes('../')) {
          log("Skipping unsafe entry: " + name);
          continue;
        }

        const outPath = outDir + name;

        const pdir = parentDir(outPath);
        if (pdir && pdir.length > 0) {
          // Ensure parent dir doesn't escape the extract path
          if (!pdir.startsWith(outDir.slice(0, -1))) { // slice(0, -1) removes trailing '/' from outDir
              log("Skipping malicious parent path: " + name);
              continue;
          }
          ensureDirectoryExists(pdir);
        }

        // if entry is a directory (name ends with '/'), create it and skip write
        if (name.endsWith('/')) {
            const dirPath = outDir + name.replace(/\/+$/,'');
            ensureDirectoryExists(dirPath);
            log("Created dir: " + dirPath);
            continue;
        }

        const ok = writeUint8ArrayToFile(outPath, data);
        if (ok) {
          count++;
          log("Wrote: " + outPath);
        } else {
          log("[ERROR] failed to write " + outPath);
        }
        // brief pause for FS stability
        await sleep(5);
      }

      log("Extracted " + count + " files to " + outDir);
      send_notification("Extracted " + count + " files");

      // set splash.html permission to 444 (read-only)
      try {
          const splashPath = EXTRACT_PATH + "/splash.html";
          if (file_exists(splashPath)) {
              const splash_addr = alloc_string(splashPath);
              const mode = 0o444n; // Read-only (r--r--r--)
              const ret = syscall(SYSCALL.chmod, splash_addr, mode);
              if (ret === 0n) {
                  log("Set permissions for splash.html to 444");
              } else {
                  log("[WARN] Failed to set permissions for splash.html. Code: " + toHex(ret));
                  send_notification("[WARN] Failed to set permissions for splash.html");
              }
          } else {
              log("[WARN] splash.html not found, skipping chmod.");
          }
      } catch (e) {
          const msg = "[ERROR] chmod splash.html: " + (e && e.message ? e.message : String(e));
          log(msg);
          send_notification(msg);
      }


      await sleep(200);
      log("Update processing complete");

    } catch (e) {
      const msg = "[-] Update error: " + (e && e.message ? e.message : String(e));
      log(msg);
      send_notification(msg);
    }
  }


  async function cleanUp(remove_update_packages) {
      if (remove_update_packages) {
          for (const path of updatePaths) {
              if (file_exists(path)) {
                  const path_addr = alloc_string(path);
                  const ret = syscall(SYSCALL.unlink, path_addr);
                  if (ret === 0n) {
                      log("Removed update package: " + path);
                      send_notification("Removed update package: " + path);
                  } else {
                      log("Failed to remove update package: " + path + " code: " + toHex(ret));
                      send_notification("Failed to remove update package: " + path + " code: " + toHex(ret));
                  }
              }
          }
      }
      // remove extracted update directory if exists
      if (file_exists(EXTRACT_PATH)) {

        const res = await rmdir(EXTRACT_PATH);
        if (res.ok) {
            log("Cleaned up extracted update directory: " + EXTRACT_PATH);
        } else {
            log("Failed to clean up extracted update directory: " + EXTRACT_PATH + " code: " + String(res.code));
            send_notification("Failed to clean up extracted update directory: " + EXTRACT_PATH + " code: " + String(res.code));
        }
      }

      // remove OLD directory if exists
      if (file_exists(TEMP_BACKUP)) {
          const res = await rmdir(TEMP_BACKUP);
          if (res.ok) {
              log("Cleaned up OLD directory: " + TEMP_BACKUP);
          } else {
              log("Failed to clean up OLD directory: " + TEMP_BACKUP + " code: " + String(res.code));
              send_notification("Failed to clean up OLD directory: " + TEMP_BACKUP + " code: " + String(res.code));
          }
      }
  }

  log("Y2JB Updater v" + Y2JB_UPDATER_VERSION + " by PLK");
  await update();

}