diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h @@ -80,6 +80,9 @@ virtual void setMetadata(std::string entry_name, std::string data) const = 0; virtual void clearMetadata(std::string entry_name) const = 0; virtual std::string getMetadata(std::string entry_name) const = 0; + virtual void restoreFromMainCompaction( + std::string mainCompactionPath, + std::string mainCompactionEncryptionKey) const = 0; #ifdef EMSCRIPTEN virtual std::vector getAllThreadsWeb() const = 0; diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h @@ -84,6 +84,9 @@ void setMetadata(std::string entry_name, std::string data) const override; void clearMetadata(std::string entry_name) const override; std::string getMetadata(std::string entry_name) const override; + void restoreFromMainCompaction( + std::string mainCompactionPath, + std::string mainCompactionEncryptionKey) const override; #ifdef EMSCRIPTEN std::vector getAllThreadsWeb() const override; diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp @@ -646,7 +646,7 @@ // We don't want to run `PRAGMA key = ...;` // on main web database. The context is here: // https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web -void on_database_open(sqlite3 *db) { +void default_on_db_open_callback(sqlite3 *db) { #ifndef EMSCRIPTEN set_encryption_key(db); #endif @@ -683,13 +683,17 @@ } } -bool is_database_queryable(sqlite3 *db, bool use_encryption_key) { +bool is_database_queryable( + sqlite3 *db, + bool use_encryption_key, + const std::string &path = SQLiteQueryExecutor::sqliteFilePath, + const std::string &encryptionKey = SQLiteQueryExecutor::encryptionKey) { char *err_msg; - sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db); + sqlite3_open(path.c_str(), &db); // According to SQLCipher documentation running some SELECT is the only way to // check for key validity if (use_encryption_key) { - set_encryption_key(db); + set_encryption_key(db, encryptionKey); } sqlite3_exec( db, "SELECT COUNT(*) FROM sqlite_master;", nullptr, nullptr, &err_msg); @@ -883,7 +887,10 @@ return true; } -auto getEncryptedStorageAtPath(const std::string &databasePath) { +auto getEncryptedStorageAtPath( + const std::string &databasePath, + std::function on_open_callback = + default_on_db_open_callback) { auto storage = make_storage( databasePath, make_index("messages_idx_thread_time", &Message::thread, &Message::time), @@ -962,7 +969,7 @@ make_column("user_info", &UserInfo::user_info)) ); - storage.on_open = on_database_open; + storage.on_open = on_open_callback; return storage; } @@ -976,7 +983,7 @@ sqlite3 *db; sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db); - on_database_open(db); + default_on_db_open_callback(db); std::stringstream db_path; db_path << "db path: " << SQLiteQueryExecutor::sqliteFilePath.c_str() @@ -1452,7 +1459,8 @@ "attempt."); } - auto backupStorage = getEncryptedStorageAtPath(tempBackupPath); + auto backupStorage = getEncryptedStorageAtPath( + tempBackupPath, [](sqlite3 *db) { set_encryption_key(db); }); auto backupObj = SQLiteQueryExecutor::getStorage().make_backup_to(backupStorage); int backupResult = backupObj.step(-1); @@ -1505,4 +1513,92 @@ } #endif +void SQLiteQueryExecutor::restoreFromMainCompaction( + std::string mainCompactionPath, + std::string mainCompactionEncryptionKey) const { + + if (!file_exists(mainCompactionPath)) { + throw std::runtime_error("Restore attempt but backup file does not exist."); + } + + sqlite3 *backup_db; + if (!is_database_queryable( + backup_db, true, mainCompactionPath, mainCompactionEncryptionKey)) { + throw std::runtime_error("Backup file or encryption key corrupted."); + } + +// We don't want to run `PRAGMA key = ...;` +// on main web database. The context is here: +// https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web +#ifdef EMSCRIPTEN + std::string plaintextBackupPath = mainCompactionPath + "_plaintext"; + if (file_exists(plaintextBackupPath)) { + attempt_delete_file( + plaintextBackupPath, + "Failed to delete plaintext backup file from previous backup attempt."); + } + + std::string plaintextMigrationDBQuery = "PRAGMA key = \"x'" + + mainCompactionEncryptionKey + + "'\";" + "ATTACH DATABASE '" + + plaintextBackupPath + + "' AS plaintext KEY '';" + "SELECT sqlcipher_export('plaintext');" + "DETACH DATABASE plaintext;"; + + sqlite3_open(mainCompactionPath.c_str(), &backup_db); + + char *plaintextMigrationErr; + sqlite3_exec( + backup_db, + plaintextMigrationDBQuery.c_str(), + nullptr, + nullptr, + &plaintextMigrationErr); + sqlite3_close(backup_db); + + if (plaintextMigrationErr) { + std::stringstream error_message; + error_message << "Failed to migrate backup SQLCipher file to plaintext " + "SQLite file. Details" + << plaintextMigrationErr << std::endl; + std::string error_message_str = error_message.str(); + sqlite3_free(plaintextMigrationErr); + + throw std::runtime_error(error_message_str); + } + auto backupStorage = getEncryptedStorageAtPath(plaintextBackupPath); +#else + auto backupStorage = getEncryptedStorageAtPath( + mainCompactionPath, [mainCompactionEncryptionKey](sqlite3 *db) { + set_encryption_key(db, mainCompactionEncryptionKey); + }); +#endif + + auto backupObject = + SQLiteQueryExecutor::getStorage().make_backup_from(backupStorage); + int backupResult = backupObject.step(-1); + + if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) { + throw std::runtime_error( + "Programmer error. Database in transaction during restore attempt."); + } else if (backupResult != SQLITE_DONE) { + std::stringstream error_message; + error_message << "Failed to restore database from backup. Details: " + << sqlite3_errstr(backupResult); + throw std::runtime_error(error_message.str()); + } + +#ifdef EMSCRIPTEN + attempt_delete_file( + plaintextBackupPath, + "Failed to delete plaintext compaction file after successful restore."); +#endif + + attempt_delete_file( + mainCompactionPath, + "Failed to delete main compaction file after successful restore."); +} + } // namespace comm diff --git a/web/cpp/SQLiteQueryExecutorBindings.cpp b/web/cpp/SQLiteQueryExecutorBindings.cpp --- a/web/cpp/SQLiteQueryExecutorBindings.cpp +++ b/web/cpp/SQLiteQueryExecutorBindings.cpp @@ -89,7 +89,10 @@ .function("beginTransaction", &SQLiteQueryExecutor::beginTransaction) .function("commitTransaction", &SQLiteQueryExecutor::commitTransaction) .function( - "rollbackTransaction", &SQLiteQueryExecutor::rollbackTransaction); + "rollbackTransaction", &SQLiteQueryExecutor::rollbackTransaction) + .function( + "restoreFromMainCompaction", + &SQLiteQueryExecutor::restoreFromMainCompaction); } } // namespace comm diff --git a/web/database/_generated/comm-query-executor.js b/web/database/_generated/comm-query-executor.js --- a/web/database/_generated/comm-query-executor.js +++ b/web/database/_generated/comm-query-executor.js @@ -118,33 +118,33 @@ {Wa:d,Ra:f})};Wb=e.UnboundTypeError=rb("UnboundTypeError");e.count_emval_handles=function(){for(var a=0,b=5;bf?-28:N.Ec(d,f).fd;case 1:case 2:return 0;case 3:return d.flags;case 4:return f=hb(),d.flags|=f,0;case 5:return f=hb(),D[f+0>>1]=2,0;case 6:case 7:return 0;case 16:case 8:return-28;case 9:return E[Kc()>>2]=28,-1;default:return-28}}catch(g){if("undefined"== -typeof N||!(g instanceof N.La))throw g;return-g.Qa}},W:function(a,b){try{var c=Q(a);return fb(N.stat,c.path,b)}catch(d){if("undefined"==typeof N||!(d instanceof N.La))throw d;return-d.Qa}},z:function(a,b,c){try{b=c+2097152>>>0<4194305-!!b?(b>>>0)+4294967296*c:NaN;if(isNaN(b))return-61;N.td(a,b);return 0}catch(d){if("undefined"==typeof N||!(d instanceof N.La))throw d;return-d.Qa}},R:function(a,b){try{if(0===b)return-28;var c=N.cwd(),d=ta(c)+1;if(b>>0<4194305-!!b?(b>>>0)+4294967296*c:NaN;if(isNaN(b))return-61;N.td(a,b);return 0}catch(d){if("undefined"==typeof N||!(d instanceof N.La))throw d;return-d.Qa}},R:function(a,b){try{if(0===b)return-28;var c=N.cwd(),d=ta(c)+1;if(b>>0,(G=h,1<=+Math.abs(G)?0>>0:~~+Math.ceil((G-+(~~G>>>0))/4294967296)>>> 0:0)];E[b+a>>2]=J[0];E[b+a+4>>2]=J[1];J=[280*(g+1)>>>0,(G=280*(g+1),1<=+Math.abs(G)?0>>0:~~+Math.ceil((G-+(~~G>>>0))/4294967296)>>>0:0)];E[b+a+8>>2]=J[0];E[b+a+12>>2]=J[1];D[b+a+16>>1]=280;B[b+a+18>>0]=n;A(k,z,b+a+19,256);a+=280;g+=1}N.ab(d,280*g,0);return a}catch(p){if("undefined"==typeof N||!(p instanceof N.La))throw p;return-p.Qa}},X:function(a,b,c){gb=c;try{var d=Q(a);switch(b){case 21509:case 21505:return d.tty?0:-59;case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:return d.tty? 0:-59;case 21519:if(!d.tty)return-59;var f=hb();return E[f>>2]=0;case 21520:return d.tty?-28:-59;case 21531:return f=hb(),N.jc(d,b,f);case 21523:return d.tty?0:-59;case 21524:return d.tty?0:-59;default:v("bad ioctl syscall "+b)}}catch(g){if("undefined"==typeof N||!(g instanceof N.La))throw g;return-g.Qa}},U:function(a,b){try{return a=y(a),fb(N.lstat,a,b)}catch(c){if("undefined"==typeof N||!(c instanceof N.La))throw c;return-c.Qa}},O:function(a,b,c){try{return b=y(b),b=P(a,b),b=L(b),"/"===b[b.length- -1]&&(b=b.substr(0,b.length-1)),N.mkdir(b,c,0),0}catch(d){if("undefined"==typeof N||!(d instanceof N.La))throw d;return-d.Qa}},T:function(a,b,c,d){try{b=y(b);var f=d&256;b=P(a,b,d&4096);return fb(f?N.lstat:N.stat,b,c)}catch(g){if("undefined"==typeof N||!(g instanceof N.La))throw g;return-g.Qa}},r:function(a,b,c,d){gb=d;try{b=y(b);b=P(a,b);var f=d?hb():0;return N.open(b,c,f).fd}catch(g){if("undefined"==typeof N||!(g instanceof N.La))throw g;return-g.Qa}},K:function(a,b,c,d){try{b=y(b);b=P(a,b);if(0>= -d)return-28;var f=N.readlink(b),g=Math.min(d,ta(f)),k=B[c+g];A(f,z,c,d+1);B[c+g]=k;return g}catch(h){if("undefined"==typeof N||!(h instanceof N.La))throw h;return-h.Qa}},H:function(a,b,c,d){try{return b=y(b),d=y(d),b=P(a,b),d=P(c,d),N.rename(b,d),0}catch(f){if("undefined"==typeof N||!(f instanceof N.La))throw f;return-f.Qa}},I:function(a){try{return a=y(a),N.rmdir(a),0}catch(b){if("undefined"==typeof N||!(b instanceof N.La))throw b;return-b.Qa}},V:function(a,b){try{return a=y(a),fb(N.stat,a,b)}catch(c){if("undefined"== -typeof N||!(c instanceof N.La))throw c;return-c.Qa}},J:function(a,b,c){try{return b=y(b),b=P(a,b),0===c?N.unlink(b):512===c?N.rmdir(b):v("Invalid flags passed to unlinkat"),0}catch(d){if("undefined"==typeof N||!(d instanceof N.La))throw d;return-d.Qa}},E:function(a,b,c){try{b=y(b);b=P(a,b,!0);if(c){var d=ib(c),f=E[c+8>>2];g=1E3*d+f/1E6;c+=16;d=ib(c);f=E[c+8>>2];k=1E3*d+f/1E6}else var g=Date.now(),k=g;N.$d(b,g,k);return 0}catch(h){if("undefined"==typeof N||!(h instanceof N.La))throw h;return-h.Qa}}, +1]&&(b=b.substr(0,b.length-1)),N.mkdir(b,c,0),0}catch(d){if("undefined"==typeof N||!(d instanceof N.La))throw d;return-d.Qa}},T:function(a,b,c,d){try{b=y(b);var f=d&256;b=P(a,b,d&4096);return fb(f?N.lstat:N.stat,b,c)}catch(g){if("undefined"==typeof N||!(g instanceof N.La))throw g;return-g.Qa}},t:function(a,b,c,d){gb=d;try{b=y(b);b=P(a,b);var f=d?hb():0;return N.open(b,c,f).fd}catch(g){if("undefined"==typeof N||!(g instanceof N.La))throw g;return-g.Qa}},K:function(a,b,c,d){try{b=y(b);b=P(a,b);if(0>= +d)return-28;var f=N.readlink(b),g=Math.min(d,ta(f)),k=B[c+g];A(f,z,c,d+1);B[c+g]=k;return g}catch(h){if("undefined"==typeof N||!(h instanceof N.La))throw h;return-h.Qa}},J:function(a,b,c,d){try{return b=y(b),d=y(d),b=P(a,b),d=P(c,d),N.rename(b,d),0}catch(f){if("undefined"==typeof N||!(f instanceof N.La))throw f;return-f.Qa}},p:function(a){try{return a=y(a),N.rmdir(a),0}catch(b){if("undefined"==typeof N||!(b instanceof N.La))throw b;return-b.Qa}},V:function(a,b){try{return a=y(a),fb(N.stat,a,b)}catch(c){if("undefined"== +typeof N||!(c instanceof N.La))throw c;return-c.Qa}},q:function(a,b,c){try{return b=y(b),b=P(a,b),0===c?N.unlink(b):512===c?N.rmdir(b):v("Invalid flags passed to unlinkat"),0}catch(d){if("undefined"==typeof N||!(d instanceof N.La))throw d;return-d.Qa}},G:function(a,b,c){try{b=y(b);b=P(a,b,!0);if(c){var d=ib(c),f=E[c+8>>2];g=1E3*d+f/1E6;c+=16;d=ib(c);f=E[c+8>>2];k=1E3*d+f/1E6}else var g=Date.now(),k=g;N.$d(b,g,k);return 0}catch(h){if("undefined"==typeof N||!(h instanceof N.La))throw h;return-h.Qa}}, h:function(a){var b=jb[a];delete jb[a];var c=b.qc,d=b.ob,f=b.Kc,g=f.map(k=>k.yd).concat(f.map(k=>k.Rd));ub([a],g,k=>{var h={};f.forEach((n,q)=>{var p=k[q],t=n.Rb,x=n.xd,l=k[q+f.length],u=n.Qd,w=n.Sd;h[n.qd]={read:C=>p.fromWireType(t(x,C)),write:(C,K)=>{var H=[];u(w,C,l.toWireType(H,K));kb(H)}}});return[{name:b.name,fromWireType:function(n){var q={},p;for(p in h)q[p]=h[p].read(n);d(n);return q},toWireType:function(n,q){for(var p in h)if(!(p in q))throw new TypeError('Missing field: "'+p+'"');var t= -c();for(p in h)h[p].write(t,q[p]);null!==n&&n.push(d,t);return t},argPackAdvance:8,readValueFromPointer:lb,hb:d}]})},A:function(){},ea:function(a,b,c,d,f){var g=vb(c);b=S(b);R(a,{name:b,fromWireType:function(k){return!!k},toWireType:function(k,h){return h?d:f},argPackAdvance:8,readValueFromPointer:function(k){if(1===c)var h=B;else if(2===c)h=D;else if(4===c)h=E;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(h[k>>g])},hb:null})},G:function(a,b,c,d,f,g,k,h,n,q,p, +c();for(p in h)h[p].write(t,q[p]);null!==n&&n.push(d,t);return t},argPackAdvance:8,readValueFromPointer:lb,hb:d}]})},C:function(){},ea:function(a,b,c,d,f){var g=vb(c);b=S(b);R(a,{name:b,fromWireType:function(k){return!!k},toWireType:function(k,h){return h?d:f},argPackAdvance:8,readValueFromPointer:function(k){if(1===c)var h=B;else if(2===c)h=D;else if(4===c)h=E;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(h[k>>g])},hb:null})},I:function(a,b,c,d,f,g,k,h,n,q,p, t,x){p=S(p);g=W(f,g);h&&(h=W(k,h));q&&(q=W(n,q));x=W(t,x);var l=pb(p);Mb(l,function(){Zb("Cannot construct "+p+" due to unbound types",[d])});ub([a,b,c],d?[d]:[],function(u){u=u[0];if(d){var w=u.Sa;var C=w.Db}else C=U.prototype;u=qb(l,function(){if(Object.getPrototypeOf(this)!==K)throw new xb("Use 'new' to construct "+p);if(void 0===H.sb)throw new xb(p+" has no accessible constructor");var I=H.sb[arguments.length];if(void 0===I)throw new xb("Tried to invoke ctor of "+p+" with invalid number of parameters ("+ -arguments.length+") - expected ("+Object.keys(H.sb).toString()+") parameters instead!");return I.apply(this,arguments)});var K=Object.create(C,{constructor:{value:u}});u.prototype=K;var H=new Nb(p,u,K,x,w,g,h,q);w=new V(p,H,!0,!1);C=new V(p+"*",H,!1,!1);var Ga=new V(p+" const*",H,!1,!0);Db[a]={pointerType:C,hd:Ga};Ub(l,u);return[w,C,Ga]})},x:function(a,b,c,d,f,g){0{Zb("Cannot construct "+h.name+" due to unbound types",k)};ub([],k,function(q){q.splice(1,0,null);h.Sa.sb[b-1]=bc(n,q,null,f,g);return[]});return[]})},d:function(a,b,c,d,f,g,k,h){var n=$b(c,d);b=S(b);g=W(f,g);ub([],[a],function(q){function p(){Zb("Cannot call "+ t+" due to unbound types",n)}q=q[0];var t=q.name+"."+b;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);h&&q.Sa.Md.push(b);var x=q.Sa.Db,l=x[b];void 0===l||void 0===l.Za&&l.className!==q.name&&l.Pb===c-2?(p.Pb=c-2,p.className=q.name,x[b]=p):(Lb(x,b,t),x[b].Za[c-2]=p);ub([],n,function(u){u=bc(t,u,q,g,k);void 0===x[b].Za?(u.Pb=c-2,x[b]=u):x[b].Za[c-2]=u;return[]});return[]})},da:function(a,b){b=S(b);R(a,{name:b,fromWireType:function(c){var d=ec(c);dc(c);return d},toWireType:function(c,d){return Sb(d)}, -argPackAdvance:8,readValueFromPointer:lb,hb:null})},t:function(a,b,c){c=vb(c);b=S(b);R(a,{name:b,fromWireType:function(d){return d},toWireType:function(d,f){return f},argPackAdvance:8,readValueFromPointer:fc(b,c),hb:null})},ga:function(a,b,c,d,f,g){var k=$b(b,c);a=S(a);f=W(d,f);Mb(a,function(){Zb("Cannot call "+a+" due to unbound types",k)},b-1);ub([],k,function(h){h=[h[0],null].concat(h.slice(1));Ub(a,bc(a,h,null,f,g),b-1);return[]})},g:function(a,b,c,d,f){b=S(b);-1===f&&(f=4294967295);f=vb(c);var g= -h=>h;if(0===d){var k=32-8*c;g=h=>h<>>k}c=b.includes("unsigned")?function(h,n){return n>>>0}:function(h,n){return n};R(a,{name:b,fromWireType:g,toWireType:c,argPackAdvance:8,readValueFromPointer:gc(b,f,0!==d),hb:null})},c:function(a,b,c){function d(g){g>>=2;var k=F;return new f(ua,k[g+1],k[g])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=S(c);R(a,{name:c,fromWireType:d,argPackAdvance:8,readValueFromPointer:d},{zd:!0})},u:function(a,b){b= +argPackAdvance:8,readValueFromPointer:lb,hb:null})},v:function(a,b,c){c=vb(c);b=S(b);R(a,{name:b,fromWireType:function(d){return d},toWireType:function(d,f){return f},argPackAdvance:8,readValueFromPointer:fc(b,c),hb:null})},ga:function(a,b,c,d,f,g){var k=$b(b,c);a=S(a);f=W(d,f);Mb(a,function(){Zb("Cannot call "+a+" due to unbound types",k)},b-1);ub([],k,function(h){h=[h[0],null].concat(h.slice(1));Ub(a,bc(a,h,null,f,g),b-1);return[]})},g:function(a,b,c,d,f){b=S(b);-1===f&&(f=4294967295);f=vb(c);var g= +h=>h;if(0===d){var k=32-8*c;g=h=>h<>>k}c=b.includes("unsigned")?function(h,n){return n>>>0}:function(h,n){return n};R(a,{name:b,fromWireType:g,toWireType:c,argPackAdvance:8,readValueFromPointer:gc(b,f,0!==d),hb:null})},c:function(a,b,c){function d(g){g>>=2;var k=F;return new f(ua,k[g+1],k[g])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=S(c);R(a,{name:c,fromWireType:d,argPackAdvance:8,readValueFromPointer:d},{zd:!0})},w:function(a,b){b= S(b);var c="std::string"===b;R(a,{name:b,fromWireType:function(d){var f=F[d>>2],g=d+4;if(c)for(var k=g,h=0;h<=f;++h){var n=g+h;if(h==f||0==z[n]){k=y(k,n-k);if(void 0===q)var q=k;else q+=String.fromCharCode(0),q+=k;k=n+1}}else{q=Array(f);for(h=0;h>2]=k;if(c&&g)A(f,z,n,k+1);else if(g)for(g=0;gva;var h=1}else 4===b&&(d=lc,f=mc,g=nc,k=()=>F,h=2);R(a,{name:c,fromWireType:function(n){for(var q= F[n>>2],p=k(),t,x=n+4,l=0;l<=q;++l){var u=n+4+l*b;if(l==q||0==p[u>>h])x=d(x,u-x),void 0===t?t=x:(t+=String.fromCharCode(0),t+=x),x=u+b}X(n);return t},toWireType:function(n,q){"string"!=typeof q&&T("Cannot pass non-string to C++ string type "+c);var p=g(q),t=wc(4+p+b);F[t>>2]=p>>h;f(q,t+4,p+b);null!==n&&n.push(X,t);return t},argPackAdvance:8,readValueFromPointer:lb,hb:function(n){X(n)}})},i:function(a,b,c,d,f,g){jb[a]={name:S(b),qc:W(c,d),ob:W(f,g),Kc:[]}},f:function(a,b,c,d,f,g,k,h,n,q){jb[a].Kc.push({qd:S(b), -yd:c,Rb:W(d,f),xd:g,Rd:k,Qd:W(h,n),Sd:q})},fa:function(a,b){b=S(b);R(a,{Cd:!0,name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},n:function(){return Date.now()},$:function(){return!0},v:function(a,b,c){a=ec(a);b=oc(b,"emval::as");var d=[],f=Sb(d);F[c>>2]=f;return b.toWireType(d,a)},ma:function(a,b,c,d){a=rc[a];b=ec(b);c=qc(c);a(b,c,null,d)},ka:dc,la:function(a,b){var c=tc(a,b),d=c[0];b=d.name+"_$"+c.slice(1).map(function(p){return p.name}).join("_")+"$";var f=uc[b];if(void 0!== +yd:c,Rb:W(d,f),xd:g,Rd:k,Qd:W(h,n),Sd:q})},fa:function(a,b){b=S(b);R(a,{Cd:!0,name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},n:function(){return Date.now()},$:function(){return!0},x:function(a,b,c){a=ec(a);b=oc(b,"emval::as");var d=[],f=Sb(d);F[c>>2]=f;return b.toWireType(d,a)},ma:function(a,b,c,d){a=rc[a];b=ec(b);c=qc(c);a(b,c,null,d)},ka:dc,la:function(a,b){var c=tc(a,b),d=c[0];b=d.name+"_$"+c.slice(1).map(function(p){return p.name}).join("_")+"$";var f=uc[b];if(void 0!== f)return f;f=["retType"];for(var g=[d],k="",h=0;h>2]=a.getSeconds();E[b+4>>2]=a.getMinutes();E[b+8>>2]=a.getHours();E[b+12>>2]=a.getDate();E[b+16>>2]=a.getMonth();E[b+20>>2]= +f.push(n+"};\n");a=ac(f).apply(null,g);f=sc(a);return uc[b]=f},y:function(a,b){a=ec(a);b=ec(b);return Sb(a[b])},oa:function(a){4>2]=a.getSeconds();E[b+4>>2]=a.getMinutes();E[b+8>>2]=a.getHours();E[b+12>>2]=a.getDate();E[b+16>>2]=a.getMonth();E[b+20>>2]= a.getFullYear()-1900;E[b+24>>2]=a.getDay();var c=new Date(a.getFullYear(),0,1);E[b+28>>2]=(a.getTime()-c.getTime())/864E5|0;E[b+36>>2]=-(60*a.getTimezoneOffset());var d=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();c=c.getTimezoneOffset();E[b+32>>2]=(d!=c&&a.getTimezoneOffset()==Math.min(c,d))|0},M:function(a,b,c,d,f,g){try{var k=N.qb(d);if(!k)return-8;var h=N.xb(k,a,f,b,c),n=h.Ra;E[g>>2]=h.yc;return n}catch(q){if("undefined"==typeof N||!(q instanceof N.La))throw q;return-q.Qa}},N:function(a, -b,c,d,f,g){try{var k=N.qb(f);if(k&&c&2){var h=z.slice(a,a+b);N.Eb(k,h,g,b,d)}}catch(n){if("undefined"==typeof N||!(n instanceof N.La))throw n;return-n.Qa}},ba:yc,k:function(){v("")},F:function(){return 2147483648},s:zc,m:function(a){var b=z.length;a>>>=0;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);var f=Math;d=Math.max(a,d);f=f.min.call(f,2147483648,d+(65536-d%65536)%65536);a:{try{pa.grow(f-ua.byteLength+65535>>>16);ya();var g=1;break a}catch(k){}g=void 0}if(g)return!0}return!1}, -P:function(a,b){var c=0;Bc().forEach(function(d,f){var g=b+c;f=F[a+4*f>>2]=g;for(g=0;g>0]=d.charCodeAt(g);B[f>>0]=0;c+=d.length+1});return 0},Q:function(a,b){var c=Bc();F[a>>2]=c.length;var d=0;c.forEach(function(f){d+=f.length+1});F[b>>2]=d;return 0},j:function(a){try{var b=Q(a);N.close(b);return 0}catch(c){if("undefined"==typeof N||!(c instanceof N.La))throw c;return c.Qa}},D:function(a,b){try{var c=Q(a);B[b>>0]=c.tty?2:N.Xa(c.mode)?3:N.ub(c.mode)?7:4;return 0}catch(d){if("undefined"== -typeof N||!(d instanceof N.La))throw d;return d.Qa}},q:function(a,b,c,d){try{a:{var f=Q(a);a=b;for(var g=b=0;g>2],h=F[a+4>>2];a+=8;var n=N.read(f,B,k,h,void 0);if(0>n){var q=-1;break a}b+=n;if(n>2]=q;return 0}catch(p){if("undefined"==typeof N||!(p instanceof N.La))throw p;return p.Qa}},y:function(a,b,c,d,f){try{b=c+2097152>>>0<4194305-!!b?(b>>>0)+4294967296*c:NaN;if(isNaN(b))return 61;var g=Q(a);N.ab(g,b,d);J=[g.position>>>0,(G=g.position,1<=+Math.abs(G)?0>>0:~~+Math.ceil((G-+(~~G>>>0))/4294967296)>>>0:0)];E[f>>2]=J[0];E[f+4>>2]=J[1];g.tb&&0===b&&0===d&&(g.tb=null);return 0}catch(k){if("undefined"==typeof N||!(k instanceof N.La))throw k;return k.Qa}},S:function(a){try{var b=Q(a);return b.Pa&&b.Pa.fsync?-b.Pa.fsync(b):0}catch(c){if("undefined"==typeof N||!(c instanceof N.La))throw c;return c.Qa}},p:function(a,b,c,d){try{a:{var f=Q(a);a=b;for(var g=b=0;g>2],h=F[a+4>>2];a+=8;var n=N.write(f,B,k,h,void 0);if(0> -n){var q=-1;break a}b+=n}q=b}F[d>>2]=q;return 0}catch(p){if("undefined"==typeof N||!(p instanceof N.La))throw p;return p.Qa}},B:function(){},ha:Gc,C:function(a,b,c,d){return Gc(a,b,c,d)}},Z=function(){function a(c){e.asm=c.exports;pa=e.asm.pa;ya();za=e.asm.ua;Ba.unshift(e.asm.qa);Ja("wasm-instantiate")}var b={a:Lc};Ia("wasm-instantiate");if(e.instantiateWasm)try{return e.instantiateWasm(b,a)}catch(c){return r("Module.instantiateWasm callback failed with error: "+c),!1}b=Ma(b);a(b[0]);return e.asm}(); +b,c,d,f,g){try{var k=N.qb(f);if(k&&c&2){var h=z.slice(a,a+b);N.Eb(k,h,g,b,d)}}catch(n){if("undefined"==typeof N||!(n instanceof N.La))throw n;return-n.Qa}},ba:yc,k:function(){v("")},H:function(){return 2147483648},u:zc,m:function(a){var b=z.length;a>>>=0;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);var f=Math;d=Math.max(a,d);f=f.min.call(f,2147483648,d+(65536-d%65536)%65536);a:{try{pa.grow(f-ua.byteLength+65535>>>16);ya();var g=1;break a}catch(k){}g=void 0}if(g)return!0}return!1}, +P:function(a,b){var c=0;Bc().forEach(function(d,f){var g=b+c;f=F[a+4*f>>2]=g;for(g=0;g>0]=d.charCodeAt(g);B[f>>0]=0;c+=d.length+1});return 0},Q:function(a,b){var c=Bc();F[a>>2]=c.length;var d=0;c.forEach(function(f){d+=f.length+1});F[b>>2]=d;return 0},j:function(a){try{var b=Q(a);N.close(b);return 0}catch(c){if("undefined"==typeof N||!(c instanceof N.La))throw c;return c.Qa}},F:function(a,b){try{var c=Q(a);B[b>>0]=c.tty?2:N.Xa(c.mode)?3:N.ub(c.mode)?7:4;return 0}catch(d){if("undefined"== +typeof N||!(d instanceof N.La))throw d;return d.Qa}},s:function(a,b,c,d){try{a:{var f=Q(a);a=b;for(var g=b=0;g>2],h=F[a+4>>2];a+=8;var n=N.read(f,B,k,h,void 0);if(0>n){var q=-1;break a}b+=n;if(n>2]=q;return 0}catch(p){if("undefined"==typeof N||!(p instanceof N.La))throw p;return p.Qa}},A:function(a,b,c,d,f){try{b=c+2097152>>>0<4194305-!!b?(b>>>0)+4294967296*c:NaN;if(isNaN(b))return 61;var g=Q(a);N.ab(g,b,d);J=[g.position>>>0,(G=g.position,1<=+Math.abs(G)?0>>0:~~+Math.ceil((G-+(~~G>>>0))/4294967296)>>>0:0)];E[f>>2]=J[0];E[f+4>>2]=J[1];g.tb&&0===b&&0===d&&(g.tb=null);return 0}catch(k){if("undefined"==typeof N||!(k instanceof N.La))throw k;return k.Qa}},S:function(a){try{var b=Q(a);return b.Pa&&b.Pa.fsync?-b.Pa.fsync(b):0}catch(c){if("undefined"==typeof N||!(c instanceof N.La))throw c;return c.Qa}},r:function(a,b,c,d){try{a:{var f=Q(a);a=b;for(var g=b=0;g>2],h=F[a+4>>2];a+=8;var n=N.write(f,B,k,h,void 0);if(0> +n){var q=-1;break a}b+=n}q=b}F[d>>2]=q;return 0}catch(p){if("undefined"==typeof N||!(p instanceof N.La))throw p;return p.Qa}},D:function(){},ha:Gc,E:function(a,b,c,d){return Gc(a,b,c,d)}},Z=function(){function a(c){e.asm=c.exports;pa=e.asm.pa;ya();za=e.asm.ua;Ba.unshift(e.asm.qa);Ja("wasm-instantiate")}var b={a:Lc};Ia("wasm-instantiate");if(e.instantiateWasm)try{return e.instantiateWasm(b,a)}catch(c){return r("Module.instantiateWasm callback failed with error: "+c),!1}b=Ma(b);a(b[0]);return e.asm}(); e.___wasm_call_ctors=Z.qa;var Kc=e.___errno_location=Z.ra,wc=e._malloc=Z.sa,X=e._free=Z.ta,Yb=e.___getTypeName=Z.va;e.___embind_register_native_and_builtin_types=Z.wa;var cb=e._emscripten_builtin_memalign=Z.xa;e.___cxa_is_pointer_type=Z.ya;e.dynCall_iiiij=Z.za;e.dynCall_iij=Z.Aa;e.dynCall_iijii=Z.Ba;e.dynCall_iiji=Z.Ca;e.dynCall_iiiiiij=Z.Da;e.dynCall_vjii=Z.Ea;e.dynCall_vji=Z.Fa;e.dynCall_jiji=Z.Ga;e.dynCall_viijii=Z.Ha;e.dynCall_iiiiij=Z.Ia;e.dynCall_iiiiijj=Z.Ja;e.dynCall_iiiiiijj=Z.Ka; e.addRunDependency=Ia;e.removeRunDependency=Ja;e.FS_createPath=N.Cc;e.FS_createDataFile=N.Qb;e.FS_createPreloadedFile=N.Dc;e.FS_createLazyFile=N.Bc;e.FS_createDevice=N.gb;e.FS_unlink=N.unlink;e.FS=N;var Mc;Ha=function Nc(){Mc||Oc();Mc||(Ha=Nc)}; function Oc(){function a(){if(!Mc&&(Mc=!0,e.calledRun=!0,!qa)){e.noFSInit||N.Cb.ic||N.Cb();N.Qc=!1;Na(Ba);aa(e);if(e.onRuntimeInitialized)e.onRuntimeInitialized();if(e.postRun)for("function"==typeof e.postRun&&(e.postRun=[e.postRun]);e.postRun.length;){var b=e.postRun.shift();Ca.unshift(b)}Na(Ca)}}if(!(0