diff --git a/package.json b/package.json index 1bd9395a..67709728 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@adobe/css-tools": "4.3.2", "@aws-crypto/sha256-js": "^5.2.0", "@breezystack/lamejs": "^1.2.7", + "@browsermt/bergamot-translator": "^0.4.9", "@capacitor/android": "^5.6.0", "@capacitor/core": "^5.6.0", "@capacitor/filesystem": "^5.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 726b3c9e..25f73461 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@breezystack/lamejs': specifier: ^1.2.7 version: 1.2.7 + '@browsermt/bergamot-translator': + specifier: ^0.4.9 + version: 0.4.9 '@capacitor/android': specifier: ^5.6.0 version: 5.6.0(@capacitor/core@5.6.0) @@ -376,6 +379,9 @@ packages: '@breezystack/lamejs@1.2.7': resolution: {integrity: sha512-6wc7ck65ctA75Hq7FYHTtTvGnYs6msgdxiSUICQ+A01nVOWg6rqouZB8IdyteRlfpYYiFovkf67dIeOgWIUzTA==} + '@browsermt/bergamot-translator@0.4.9': + resolution: {integrity: sha512-bNuuCwM/JnsIYQCKXcYKFT4Qc5vLMoB8Nbvz8ReIgs7xzebK8Sa+R8iEK8mLvNBe/WaZ6zrPaUQilLsRT/ea8Q==} + '@capacitor/android@5.6.0': resolution: {integrity: sha512-6O7xV6K6c8WvQzKxOe7fnhRyoVpS3TNDXy1FyfhvOvclBvu+1JddSdFvW4e4dSL60s2c00sCzNRgYhm+cn0/dQ==} peerDependencies: @@ -4110,6 +4116,8 @@ snapshots: '@breezystack/lamejs@1.2.7': {} + '@browsermt/bergamot-translator@0.4.9': {} + '@capacitor/android@5.6.0(@capacitor/core@5.6.0)': dependencies: '@capacitor/core': 5.6.0 diff --git a/public/assets/bergamot-translator-worker.js b/public/assets/bergamot-translator-worker.js new file mode 100644 index 00000000..14254229 --- /dev/null +++ b/public/assets/bergamot-translator-worker.js @@ -0,0 +1,2919 @@ +var BERGAMOT_VERSION_FULL = "v0.4.5+4917c11"; +null; + +var Module = typeof Module != "undefined" ? Module : {}; + +var moduleOverrides = Object.assign({}, Module); + +var arguments_ = []; + +var thisProgram = "./this.program"; + +var quit_ = (status, toThrow) => { + throw toThrow; +}; + +var ENVIRONMENT_IS_WEB = typeof window == "object"; + +var ENVIRONMENT_IS_WORKER = typeof importScripts == "function"; + +var ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string"; + +var scriptDirectory = ""; + +function locateFile(path) { + if (Module["locateFile"]) { + return Module["locateFile"](path, scriptDirectory); + } + return scriptDirectory + path; +} + +var read_, readAsync, readBinary, setWindowTitle; + +if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = self.location.href; + } else if (typeof document != "undefined" && document.currentScript) { + scriptDirectory = document.currentScript.src; + } + if (scriptDirectory.indexOf("blob:") !== 0) { + scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1); + } else { + scriptDirectory = ""; + } + { + read_ = (url => { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, false); + xhr.send(null); + return xhr.responseText; + }); + if (ENVIRONMENT_IS_WORKER) { + readBinary = (url => { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, false); + xhr.responseType = "arraybuffer"; + xhr.send(null); + return new Uint8Array(xhr.response); + }); + } + readAsync = ((url, onload, onerror) => { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + xhr.onload = (() => { + if (xhr.status == 200 || xhr.status == 0 && xhr.response) { + onload(xhr.response); + return; + } + onerror(); + }); + xhr.onerror = onerror; + xhr.send(null); + }); + } + setWindowTitle = (title => document.title = title); +} else {} + +var out = Module["print"] || console.log.bind(console); + +var err = Module["printErr"] || console.warn.bind(console); + +Object.assign(Module, moduleOverrides); + +moduleOverrides = null; + +if (Module["arguments"]) arguments_ = Module["arguments"]; + +if (Module["thisProgram"]) thisProgram = Module["thisProgram"]; + +if (Module["quit"]) quit_ = Module["quit"]; + +var tempRet0 = 0; + +var setTempRet0 = value => { + tempRet0 = value; +}; + +var wasmBinary; + +if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; + +var noExitRuntime = Module["noExitRuntime"] || true; + +if (typeof WebAssembly != "object") { + abort("no native wasm support detected"); +} + +var wasmMemory; + +var ABORT = false; + +var EXITSTATUS; + +function assert(condition, text) { + if (!condition) { + abort(text); + } +} + +var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : undefined; + +function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { + var endIdx = idx + maxBytesToRead; + var endPtr = idx; + while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { + return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); + } else { + var str = ""; + while (idx < endPtr) { + var u0 = heapOrArray[idx++]; + if (!(u0 & 128)) { + str += String.fromCharCode(u0); + continue; + } + var u1 = heapOrArray[idx++] & 63; + if ((u0 & 224) == 192) { + str += String.fromCharCode((u0 & 31) << 6 | u1); + continue; + } + var u2 = heapOrArray[idx++] & 63; + if ((u0 & 240) == 224) { + u0 = (u0 & 15) << 12 | u1 << 6 | u2; + } else { + u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heapOrArray[idx++] & 63; + } + if (u0 < 65536) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 65536; + str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); + } + } + } + return str; +} + +function UTF8ToString(ptr, maxBytesToRead) { + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; +} + +function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { + if (!(maxBytesToWrite > 0)) return 0; + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + for (var i = 0; i < str.length; ++i) { + var u = str.charCodeAt(i); + if (u >= 55296 && u <= 57343) { + var u1 = str.charCodeAt(++i); + u = 65536 + ((u & 1023) << 10) | u1 & 1023; + } + if (u <= 127) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 2047) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 192 | u >> 6; + heap[outIdx++] = 128 | u & 63; + } else if (u <= 65535) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 224 | u >> 12; + heap[outIdx++] = 128 | u >> 6 & 63; + heap[outIdx++] = 128 | u & 63; + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++] = 240 | u >> 18; + heap[outIdx++] = 128 | u >> 12 & 63; + heap[outIdx++] = 128 | u >> 6 & 63; + heap[outIdx++] = 128 | u & 63; + } + } + heap[outIdx] = 0; + return outIdx - startIdx; +} + +function stringToUTF8(str, outPtr, maxBytesToWrite) { + return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); +} + +function lengthBytesUTF8(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var u = str.charCodeAt(i); + if (u >= 55296 && u <= 57343) u = 65536 + ((u & 1023) << 10) | str.charCodeAt(++i) & 1023; + if (u <= 127) ++len; else if (u <= 2047) len += 2; else if (u <= 65535) len += 3; else len += 4; + } + return len; +} + +var UTF16Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf-16le") : undefined; + +function UTF16ToString(ptr, maxBytesToRead) { + var endPtr = ptr; + var idx = endPtr >> 1; + var maxIdx = idx + maxBytesToRead / 2; + while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; + endPtr = idx << 1; + if (endPtr - ptr > 32 && UTF16Decoder) { + return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr)); + } else { + var str = ""; + for (var i = 0; !(i >= maxBytesToRead / 2); ++i) { + var codeUnit = HEAP16[ptr + i * 2 >> 1]; + if (codeUnit == 0) break; + str += String.fromCharCode(codeUnit); + } + return str; + } +} + +function stringToUTF16(str, outPtr, maxBytesToWrite) { + if (maxBytesToWrite === undefined) { + maxBytesToWrite = 2147483647; + } + if (maxBytesToWrite < 2) return 0; + maxBytesToWrite -= 2; + var startPtr = outPtr; + var numCharsToWrite = maxBytesToWrite < str.length * 2 ? maxBytesToWrite / 2 : str.length; + for (var i = 0; i < numCharsToWrite; ++i) { + var codeUnit = str.charCodeAt(i); + HEAP16[outPtr >> 1] = codeUnit; + outPtr += 2; + } + HEAP16[outPtr >> 1] = 0; + return outPtr - startPtr; +} + +function lengthBytesUTF16(str) { + return str.length * 2; +} + +function UTF32ToString(ptr, maxBytesToRead) { + var i = 0; + var str = ""; + while (!(i >= maxBytesToRead / 4)) { + var utf32 = HEAP32[ptr + i * 4 >> 2]; + if (utf32 == 0) break; + ++i; + if (utf32 >= 65536) { + var ch = utf32 - 65536; + str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); + } else { + str += String.fromCharCode(utf32); + } + } + return str; +} + +function stringToUTF32(str, outPtr, maxBytesToWrite) { + if (maxBytesToWrite === undefined) { + maxBytesToWrite = 2147483647; + } + if (maxBytesToWrite < 4) return 0; + var startPtr = outPtr; + var endPtr = startPtr + maxBytesToWrite - 4; + for (var i = 0; i < str.length; ++i) { + var codeUnit = str.charCodeAt(i); + if (codeUnit >= 55296 && codeUnit <= 57343) { + var trailSurrogate = str.charCodeAt(++i); + codeUnit = 65536 + ((codeUnit & 1023) << 10) | trailSurrogate & 1023; + } + HEAP32[outPtr >> 2] = codeUnit; + outPtr += 4; + if (outPtr + 4 > endPtr) break; + } + HEAP32[outPtr >> 2] = 0; + return outPtr - startPtr; +} + +function lengthBytesUTF32(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var codeUnit = str.charCodeAt(i); + if (codeUnit >= 55296 && codeUnit <= 57343) ++i; + len += 4; + } + return len; +} + +function allocateUTF8(str) { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8Array(str, HEAP8, ret, size); + return ret; +} + +function writeArrayToMemory(array, buffer) { + HEAP8.set(array, buffer); +} + +function writeAsciiToMemory(str, buffer, dontAddNull) { + for (var i = 0; i < str.length; ++i) { + HEAP8[buffer++ >> 0] = str.charCodeAt(i); + } + if (!dontAddNull) HEAP8[buffer >> 0] = 0; +} + +var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; + +function updateGlobalBufferAndViews(buf) { + buffer = buf; + Module["HEAP8"] = HEAP8 = new Int8Array(buf); + Module["HEAP16"] = HEAP16 = new Int16Array(buf); + Module["HEAP32"] = HEAP32 = new Int32Array(buf); + Module["HEAPU8"] = HEAPU8 = new Uint8Array(buf); + Module["HEAPU16"] = HEAPU16 = new Uint16Array(buf); + Module["HEAPU32"] = HEAPU32 = new Uint32Array(buf); + Module["HEAPF32"] = HEAPF32 = new Float32Array(buf); + Module["HEAPF64"] = HEAPF64 = new Float64Array(buf); +} + +var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 16777216; + +if (Module["wasmMemory"]) { + wasmMemory = Module["wasmMemory"]; +} else { + wasmMemory = new WebAssembly.Memory({ + "initial": INITIAL_MEMORY / 65536, + "maximum": 2147483648 / 65536 + }); +} + +if (wasmMemory) { + buffer = wasmMemory.buffer; +} + +INITIAL_MEMORY = buffer.byteLength; + +updateGlobalBufferAndViews(buffer); + +var wasmTable; + +var __ATPRERUN__ = []; + +var __ATINIT__ = []; + +var __ATPOSTRUN__ = []; + +var runtimeInitialized = false; + +function keepRuntimeAlive() { + return noExitRuntime; +} + +function preRun() { + if (Module["preRun"]) { + if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ]; + while (Module["preRun"].length) { + addOnPreRun(Module["preRun"].shift()); + } + } + callRuntimeCallbacks(__ATPRERUN__); +} + +function initRuntime() { + runtimeInitialized = true; + callRuntimeCallbacks(__ATINIT__); +} + +function postRun() { + if (Module["postRun"]) { + if (typeof Module["postRun"] == "function") Module["postRun"] = [ Module["postRun"] ]; + while (Module["postRun"].length) { + addOnPostRun(Module["postRun"].shift()); + } + } + callRuntimeCallbacks(__ATPOSTRUN__); +} + +function addOnPreRun(cb) { + __ATPRERUN__.unshift(cb); +} + +function addOnInit(cb) { + __ATINIT__.unshift(cb); +} + +function addOnPostRun(cb) { + __ATPOSTRUN__.unshift(cb); +} + +var runDependencies = 0; + +var runDependencyWatcher = null; + +var dependenciesFulfilled = null; + +function addRunDependency(id) { + runDependencies++; + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); + } +} + +function removeRunDependency(id) { + runDependencies--; + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); + } + if (runDependencies == 0) { + if (runDependencyWatcher !== null) { + clearInterval(runDependencyWatcher); + runDependencyWatcher = null; + } + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); + } + } +} + +Module["preloadedImages"] = {}; + +Module["preloadedAudios"] = {}; + +function abort(what) { + { + if (Module["onAbort"]) { + Module["onAbort"](what); + } + } + what = "Aborted(" + what + ")"; + err(what); + ABORT = true; + EXITSTATUS = 1; + what += ". Build with -s ASSERTIONS=1 for more info."; + var e = new WebAssembly.RuntimeError(what); + throw e; +} + +var dataURIPrefix = "data:application/octet-stream;base64,"; + +function isDataURI(filename) { + return filename.startsWith(dataURIPrefix); +} + +var wasmBinaryFile; + +wasmBinaryFile = "bergamot-translator-worker.wasm"; + +if (!isDataURI(wasmBinaryFile)) { + wasmBinaryFile = locateFile(wasmBinaryFile); +} + +function getBinary(file) { + try { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } else { + throw "both async and sync fetching of the wasm failed"; + } + } catch (err) { + abort(err); + } +} + +function getBinaryPromise() { + if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { + if (typeof fetch == "function") { + return fetch(wasmBinaryFile, { + credentials: "same-origin" + }).then(function(response) { + if (!response["ok"]) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + } + return response["arrayBuffer"](); + }).catch(function() { + return getBinary(wasmBinaryFile); + }); + } + } + return Promise.resolve().then(function() { + return getBinary(wasmBinaryFile); + }); +} + +function createWasm() { + var info = { + "env": asmLibraryArg, + "wasi_snapshot_preview1": asmLibraryArg + }; + function receiveInstance(instance, module) { + var exports = instance.exports; + Module["asm"] = exports; + wasmTable = Module["asm"]["__indirect_function_table"]; + addOnInit(Module["asm"]["__wasm_call_ctors"]); + exportAsmFunctions(exports); + removeRunDependency("wasm-instantiate"); + } + addRunDependency("wasm-instantiate"); + function receiveInstantiationResult(result) { + receiveInstance(result["instance"]); + } + function instantiateArrayBuffer(receiver) { + return getBinaryPromise().then(function(binary) { + return WebAssembly.instantiate(binary, info); + }).then(function(instance) { + return instance; + }).then(receiver, function(reason) { + err("failed to asynchronously prepare wasm: " + reason); + abort(reason); + }); + } + function instantiateAsync() { + if (!wasmBinary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(wasmBinaryFile) && typeof fetch == "function") { + return fetch(wasmBinaryFile, { + credentials: "same-origin" + }).then(function(response) { + var result = WebAssembly.instantiateStreaming(response, info); + return result.then(receiveInstantiationResult, function(reason) { + err("wasm streaming compile failed: " + reason); + err("falling back to ArrayBuffer instantiation"); + return instantiateArrayBuffer(receiveInstantiationResult); + }); + }); + } else { + return instantiateArrayBuffer(receiveInstantiationResult); + } + } + if (Module["instantiateWasm"]) { + try { + var exports = Module["instantiateWasm"](info, receiveInstance); + return exports; + } catch (e) { + err("Module.instantiateWasm callback failed with error: " + e); + return false; + } + } + instantiateAsync(); + return {}; +} + +function callRuntimeCallbacks(callbacks) { + while (callbacks.length > 0) { + var callback = callbacks.shift(); + if (typeof callback == "function") { + callback(Module); + continue; + } + var func = callback.func; + if (typeof func == "number") { + if (callback.arg === undefined) { + getWasmTableEntry(func)(); + } else { + getWasmTableEntry(func)(callback.arg); + } + } else { + func(callback.arg === undefined ? null : callback.arg); + } + } +} + +function asmjsMangle(x) { + var unmangledSymbols = [ "stackAlloc", "stackSave", "stackRestore" ]; + return x.indexOf("dynCall_") == 0 || unmangledSymbols.includes(x) ? x : "_" + x; +} + +function exportAsmFunctions(asm) { + var global_object = this; + for (var __exportedFunc in asm) { + var jsname = asmjsMangle(__exportedFunc); + global_object[jsname] = Module[jsname] = asm[__exportedFunc]; + } +} + +var wasmTableMirror = []; + +function getWasmTableEntry(funcPtr) { + var func = wasmTableMirror[funcPtr]; + if (!func) { + if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1; + wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); + } + return func; +} + +function ___assert_fail(condition, filename, line, func) { + abort("Assertion failed: " + UTF8ToString(condition) + ", at: " + [ filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function" ]); +} + +function ___cxa_allocate_exception(size) { + return _malloc(size + 16) + 16; +} + +var exceptionCaught = []; + +var exceptionLast = 0; + +var uncaughtExceptionCount = 0; + +function ___cxa_rethrow() { + var catchInfo = exceptionCaught.pop(); + if (!catchInfo) { + abort("no exception to throw"); + } + var info = catchInfo.get_exception_info(); + var ptr = catchInfo.get_base_ptr(); + if (!info.get_rethrown()) { + exceptionCaught.push(catchInfo); + info.set_rethrown(true); + info.set_caught(false); + uncaughtExceptionCount++; + } else { + catchInfo.free(); + } + exceptionLast = ptr; + throw ptr; +} + +function ExceptionInfo(excPtr) { + this.excPtr = excPtr; + this.ptr = excPtr - 16; + this.set_type = function(type) { + HEAP32[this.ptr + 4 >> 2] = type; + }; + this.get_type = function() { + return HEAP32[this.ptr + 4 >> 2]; + }; + this.set_destructor = function(destructor) { + HEAP32[this.ptr + 8 >> 2] = destructor; + }; + this.get_destructor = function() { + return HEAP32[this.ptr + 8 >> 2]; + }; + this.set_refcount = function(refcount) { + HEAP32[this.ptr >> 2] = refcount; + }; + this.set_caught = function(caught) { + caught = caught ? 1 : 0; + HEAP8[this.ptr + 12 >> 0] = caught; + }; + this.get_caught = function() { + return HEAP8[this.ptr + 12 >> 0] != 0; + }; + this.set_rethrown = function(rethrown) { + rethrown = rethrown ? 1 : 0; + HEAP8[this.ptr + 13 >> 0] = rethrown; + }; + this.get_rethrown = function() { + return HEAP8[this.ptr + 13 >> 0] != 0; + }; + this.init = function(type, destructor) { + this.set_type(type); + this.set_destructor(destructor); + this.set_refcount(0); + this.set_caught(false); + this.set_rethrown(false); + }; + this.add_ref = function() { + var value = HEAP32[this.ptr >> 2]; + HEAP32[this.ptr >> 2] = value + 1; + }; + this.release_ref = function() { + var prev = HEAP32[this.ptr >> 2]; + HEAP32[this.ptr >> 2] = prev - 1; + return prev === 1; + }; +} + +function ___cxa_throw(ptr, type, destructor) { + var info = new ExceptionInfo(ptr); + info.init(type, destructor); + exceptionLast = ptr; + uncaughtExceptionCount++; + throw ptr; +} + +var SYSCALLS = { + buffers: [ null, [], [] ], + printChar: function(stream, curr) { + var buffer = SYSCALLS.buffers[stream]; + if (curr === 0 || curr === 10) { + (stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0)); + buffer.length = 0; + } else { + buffer.push(curr); + } + }, + varargs: undefined, + get: function() { + SYSCALLS.varargs += 4; + var ret = HEAP32[SYSCALLS.varargs - 4 >> 2]; + return ret; + }, + getStr: function(ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, + get64: function(low, high) { + return low; + } +}; + +function ___syscall_faccessat(dirfd, path, amode, flags) { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + return SYSCALLS.doAccess(path, amode); +} + +function ___syscall_fcntl64(fd, cmd, varargs) { + SYSCALLS.varargs = varargs; + return 0; +} + +function ___syscall_fstat64(fd, buf) {} + +function ___syscall_getcwd(buf, size) {} + +function ___syscall_ioctl(fd, op, varargs) { + SYSCALLS.varargs = varargs; + return 0; +} + +function ___syscall_lstat64(path, buf) {} + +function ___syscall_newfstatat(dirfd, path, buf, flags) {} + +function ___syscall_openat(dirfd, path, flags, varargs) { + SYSCALLS.varargs = varargs; +} + +function ___syscall_renameat(olddirfd, oldpath, newdirfd, newpath) {} + +function ___syscall_rmdir(path) {} + +function ___syscall_stat64(path, buf) {} + +function ___syscall_unlinkat(dirfd, path, flags) {} + +var structRegistrations = {}; + +function runDestructors(destructors) { + while (destructors.length) { + var ptr = destructors.pop(); + var del = destructors.pop(); + del(ptr); + } +} + +function simpleReadValueFromPointer(pointer) { + return this["fromWireType"](HEAPU32[pointer >> 2]); +} + +var awaitingDependencies = {}; + +var registeredTypes = {}; + +var typeDependencies = {}; + +var char_0 = 48; + +var char_9 = 57; + +function makeLegalFunctionName(name) { + if (undefined === name) { + return "_unknown"; + } + name = name.replace(/[^a-zA-Z0-9_]/g, "$"); + var f = name.charCodeAt(0); + if (f >= char_0 && f <= char_9) { + return "_" + name; + } + return name; +} + +function createNamedFunction(name, body) { + name = makeLegalFunctionName(name); + return function() { + null; + return body.apply(this, arguments); + }; +} + +function extendError(baseErrorType, errorName) { + var errorClass = createNamedFunction(errorName, function(message) { + this.name = errorName; + this.message = message; + var stack = new Error(message).stack; + if (stack !== undefined) { + this.stack = this.toString() + "\n" + stack.replace(/^Error(:[^\n]*)?\n/, ""); + } + }); + errorClass.prototype = Object.create(baseErrorType.prototype); + errorClass.prototype.constructor = errorClass; + errorClass.prototype.toString = function() { + if (this.message === undefined) { + return this.name; + } else { + return this.name + ": " + this.message; + } + }; + return errorClass; +} + +var InternalError = undefined; + +function throwInternalError(message) { + throw new InternalError(message); +} + +function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverters) { + myTypes.forEach(function(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; + dependentTypes.forEach((dt, i) => { + 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); + } +} + +function __embind_finalize_value_object(structType) { + var reg = structRegistrations[structType]; + delete structRegistrations[structType]; + var rawConstructor = reg.rawConstructor; + var rawDestructor = reg.rawDestructor; + var fieldRecords = reg.fields; + var fieldTypes = fieldRecords.map(field => field.getterReturnType).concat(fieldRecords.map(field => field.setterArgumentType)); + whenDependentTypesAreResolved([ structType ], fieldTypes, fieldTypes => { + var fields = {}; + fieldRecords.forEach((field, i) => { + var fieldName = field.fieldName; + var getterReturnType = fieldTypes[i]; + var getter = field.getter; + var getterContext = field.getterContext; + var setterArgumentType = fieldTypes[i + fieldRecords.length]; + var setter = field.setter; + var setterContext = field.setterContext; + fields[fieldName] = { + read: ptr => { + return getterReturnType["fromWireType"](getter(getterContext, ptr)); + }, + write: (ptr, o) => { + var destructors = []; + setter(setterContext, ptr, setterArgumentType["toWireType"](destructors, o)); + runDestructors(destructors); + } + }; + }); + return [ { + name: reg.name, + "fromWireType": function(ptr) { + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + rawDestructor(ptr); + return rv; + }, + "toWireType": function(destructors, o) { + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field: "' + fieldName + '"'); + } + } + var ptr = rawConstructor(); + for (fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + if (destructors !== null) { + destructors.push(rawDestructor, ptr); + } + return ptr; + }, + "argPackAdvance": 8, + "readValueFromPointer": simpleReadValueFromPointer, + destructorFunction: rawDestructor + } ]; + }); +} + +function __embind_register_bigint(primitiveType, name, size, minRange, maxRange) {} + +function getShiftFromSize(size) { + switch (size) { + case 1: + return 0; + + case 2: + return 1; + + case 4: + return 2; + + case 8: + return 3; + + default: + throw new TypeError("Unknown type size: " + size); + } +} + +function embind_init_charCodes() { + var codes = new Array(256); + for (var i = 0; i < 256; ++i) { + codes[i] = String.fromCharCode(i); + } + embind_charCodes = codes; +} + +var embind_charCodes = undefined; + +function readLatin1String(ptr) { + var ret = ""; + var c = ptr; + while (HEAPU8[c]) { + ret += embind_charCodes[HEAPU8[c++]]; + } + return ret; +} + +var BindingError = undefined; + +function throwBindingError(message) { + throw new BindingError(message); +} + +function registerType(rawType, registeredInstance, options = {}) { + if (!("argPackAdvance" in registeredInstance)) { + throw new TypeError("registerType registeredInstance requires argPackAdvance"); + } + 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()); + } +} + +function __embind_register_bool(rawType, name, size, trueValue, falseValue) { + var shift = getShiftFromSize(size); + name = readLatin1String(name); + registerType(rawType, { + name: name, + "fromWireType": function(wt) { + return !!wt; + }, + "toWireType": function(destructors, o) { + return o ? trueValue : falseValue; + }, + "argPackAdvance": 8, + "readValueFromPointer": function(pointer) { + var heap; + if (size === 1) { + heap = HEAP8; + } else if (size === 2) { + heap = HEAP16; + } else if (size === 4) { + heap = HEAP32; + } else { + throw new TypeError("Unknown boolean type size: " + name); + } + return this["fromWireType"](heap[pointer >> shift]); + }, + destructorFunction: null + }); +} + +function ClassHandle_isAliasOf(other) { + if (!(this instanceof ClassHandle)) { + return false; + } + if (!(other instanceof ClassHandle)) { + return false; + } + var leftClass = this.$$.ptrType.registeredClass; + var left = this.$$.ptr; + var rightClass = other.$$.ptrType.registeredClass; + var right = other.$$.ptr; + while (leftClass.baseClass) { + left = leftClass.upcast(left); + leftClass = leftClass.baseClass; + } + while (rightClass.baseClass) { + right = rightClass.upcast(right); + rightClass = rightClass.baseClass; + } + return leftClass === rightClass && left === right; +} + +function shallowCopyInternalPointer(o) { + return { + count: o.count, + deleteScheduled: o.deleteScheduled, + preservePointerOnDelete: o.preservePointerOnDelete, + ptr: o.ptr, + ptrType: o.ptrType, + smartPtr: o.smartPtr, + smartPtrType: o.smartPtrType + }; +} + +function throwInstanceAlreadyDeleted(obj) { + function getInstanceTypeName(handle) { + return handle.$$.ptrType.registeredClass.name; + } + throwBindingError(getInstanceTypeName(obj) + " instance already deleted"); +} + +var finalizationRegistry = false; + +function detachFinalizer(handle) {} + +function runDestructor($$) { + if ($$.smartPtr) { + $$.smartPtrType.rawDestructor($$.smartPtr); + } else { + $$.ptrType.registeredClass.rawDestructor($$.ptr); + } +} + +function releaseClassHandle($$) { + $$.count.value -= 1; + var toDelete = 0 === $$.count.value; + if (toDelete) { + runDestructor($$); + } +} + +function downcastPointer(ptr, ptrClass, desiredClass) { + if (ptrClass === desiredClass) { + return ptr; + } + if (undefined === desiredClass.baseClass) { + return null; + } + var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); + if (rv === null) { + return null; + } + return desiredClass.downcast(rv); +} + +var registeredPointers = {}; + +function getInheritedInstanceCount() { + return Object.keys(registeredInstances).length; +} + +function getLiveInheritedInstances() { + var rv = []; + for (var k in registeredInstances) { + if (registeredInstances.hasOwnProperty(k)) { + rv.push(registeredInstances[k]); + } + } + return rv; +} + +var deletionQueue = []; + +function flushPendingDeletes() { + while (deletionQueue.length) { + var obj = deletionQueue.pop(); + obj.$$.deleteScheduled = false; + obj["delete"](); + } +} + +var delayFunction = undefined; + +function setDelayFunction(fn) { + delayFunction = fn; + if (deletionQueue.length && delayFunction) { + delayFunction(flushPendingDeletes); + } +} + +function init_embind() { + Module["getInheritedInstanceCount"] = getInheritedInstanceCount; + Module["getLiveInheritedInstances"] = getLiveInheritedInstances; + Module["flushPendingDeletes"] = flushPendingDeletes; + Module["setDelayFunction"] = setDelayFunction; +} + +var registeredInstances = {}; + +function getBasestPointer(class_, ptr) { + if (ptr === undefined) { + throwBindingError("ptr should not be undefined"); + } + while (class_.baseClass) { + ptr = class_.upcast(ptr); + class_ = class_.baseClass; + } + return ptr; +} + +function getInheritedInstance(class_, ptr) { + ptr = getBasestPointer(class_, ptr); + return registeredInstances[ptr]; +} + +function makeClassHandle(prototype, record) { + if (!record.ptrType || !record.ptr) { + throwInternalError("makeClassHandle requires ptr and ptrType"); + } + var hasSmartPtrType = !!record.smartPtrType; + var hasSmartPtr = !!record.smartPtr; + if (hasSmartPtrType !== hasSmartPtr) { + throwInternalError("Both smartPtrType and smartPtr must be specified"); + } + record.count = { + value: 1 + }; + return attachFinalizer(Object.create(prototype, { + $$: { + value: record + } + })); +} + +function RegisteredPointer_fromWireType(ptr) { + var rawPointer = this.getPointee(ptr); + if (!rawPointer) { + this.destructor(ptr); + return null; + } + var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer); + if (undefined !== registeredInstance) { + if (0 === registeredInstance.$$.count.value) { + registeredInstance.$$.ptr = rawPointer; + registeredInstance.$$.smartPtr = ptr; + return registeredInstance["clone"](); + } else { + var rv = registeredInstance["clone"](); + this.destructor(ptr); + return rv; + } + } + function makeDefaultHandle() { + if (this.isSmartPointer) { + return makeClassHandle(this.registeredClass.instancePrototype, { + ptrType: this.pointeeType, + ptr: rawPointer, + smartPtrType: this, + smartPtr: ptr + }); + } else { + return makeClassHandle(this.registeredClass.instancePrototype, { + ptrType: this, + ptr: ptr + }); + } + } + var actualType = this.registeredClass.getActualType(rawPointer); + var registeredPointerRecord = registeredPointers[actualType]; + if (!registeredPointerRecord) { + return makeDefaultHandle.call(this); + } + var toType; + if (this.isConst) { + toType = registeredPointerRecord.constPointerType; + } else { + toType = registeredPointerRecord.pointerType; + } + var dp = downcastPointer(rawPointer, this.registeredClass, toType.registeredClass); + if (dp === null) { + return makeDefaultHandle.call(this); + } + if (this.isSmartPointer) { + return makeClassHandle(toType.registeredClass.instancePrototype, { + ptrType: toType, + ptr: dp, + smartPtrType: this, + smartPtr: ptr + }); + } else { + return makeClassHandle(toType.registeredClass.instancePrototype, { + ptrType: toType, + ptr: dp + }); + } +} + +function attachFinalizer(handle) { + if ("undefined" === typeof FinalizationRegistry) { + attachFinalizer = (handle => handle); + return handle; + } + finalizationRegistry = new FinalizationRegistry(info => { + releaseClassHandle(info.$$); + }); + attachFinalizer = (handle => { + var $$ = handle.$$; + var hasSmartPtr = !!$$.smartPtr; + if (hasSmartPtr) { + var info = { + $$: $$ + }; + finalizationRegistry.register(handle, info, handle); + } + return handle; + }); + detachFinalizer = (handle => finalizationRegistry.unregister(handle)); + return attachFinalizer(handle); +} + +function ClassHandle_clone() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.preservePointerOnDelete) { + this.$$.count.value += 1; + return this; + } else { + var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), { + $$: { + value: shallowCopyInternalPointer(this.$$) + } + })); + clone.$$.count.value += 1; + clone.$$.deleteScheduled = false; + return clone; + } +} + +function ClassHandle_delete() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { + throwBindingError("Object already scheduled for deletion"); + } + detachFinalizer(this); + releaseClassHandle(this.$$); + if (!this.$$.preservePointerOnDelete) { + this.$$.smartPtr = undefined; + this.$$.ptr = undefined; + } +} + +function ClassHandle_isDeleted() { + return !this.$$.ptr; +} + +function ClassHandle_deleteLater() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { + throwBindingError("Object already scheduled for deletion"); + } + deletionQueue.push(this); + if (deletionQueue.length === 1 && delayFunction) { + delayFunction(flushPendingDeletes); + } + this.$$.deleteScheduled = true; + return this; +} + +function init_ClassHandle() { + ClassHandle.prototype["isAliasOf"] = ClassHandle_isAliasOf; + ClassHandle.prototype["clone"] = ClassHandle_clone; + ClassHandle.prototype["delete"] = ClassHandle_delete; + ClassHandle.prototype["isDeleted"] = ClassHandle_isDeleted; + ClassHandle.prototype["deleteLater"] = ClassHandle_deleteLater; +} + +function ClassHandle() {} + +function ensureOverloadTable(proto, methodName, humanName) { + if (undefined === proto[methodName].overloadTable) { + var prevFunc = proto[methodName]; + proto[methodName] = function() { + if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); + } + return proto[methodName].overloadTable[arguments.length].apply(this, arguments); + }; + proto[methodName].overloadTable = []; + proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } +} + +function 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"); + } + ensureOverloadTable(Module, name, name); + if (Module.hasOwnProperty(numArguments)) { + throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!"); + } + Module[name].overloadTable[numArguments] = value; + } else { + Module[name] = value; + if (undefined !== numArguments) { + Module[name].numArguments = numArguments; + } + } +} + +function RegisteredClass(name, constructor, instancePrototype, rawDestructor, baseClass, getActualType, upcast, downcast) { + this.name = name; + this.constructor = constructor; + this.instancePrototype = instancePrototype; + this.rawDestructor = rawDestructor; + this.baseClass = baseClass; + this.getActualType = getActualType; + this.upcast = upcast; + this.downcast = downcast; + this.pureVirtualFunctions = []; +} + +function upcastPointer(ptr, ptrClass, desiredClass) { + while (ptrClass !== desiredClass) { + if (!ptrClass.upcast) { + throwBindingError("Expected null or instance of " + desiredClass.name + ", got an instance of " + ptrClass.name); + } + ptr = ptrClass.upcast(ptr); + ptrClass = ptrClass.baseClass; + } + return ptr; +} + +function constNoSmartPtrRawPointerToWireType(destructors, handle) { + if (handle === null) { + if (this.isReference) { + throwBindingError("null is not a valid " + this.name); + } + return 0; + } + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); + } + var handleClass = handle.$$.ptrType.registeredClass; + var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + return ptr; +} + +function genericPointerToWireType(destructors, handle) { + var ptr; + if (handle === null) { + if (this.isReference) { + throwBindingError("null is not a valid " + this.name); + } + if (this.isSmartPointer) { + ptr = this.rawConstructor(); + if (destructors !== null) { + destructors.push(this.rawDestructor, ptr); + } + return ptr; + } else { + return 0; + } + } + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); + } + if (!this.isConst && handle.$$.ptrType.isConst) { + throwBindingError("Cannot convert argument of type " + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + " to parameter type " + this.name); + } + var handleClass = handle.$$.ptrType.registeredClass; + ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + if (this.isSmartPointer) { + if (undefined === handle.$$.smartPtr) { + throwBindingError("Passing raw pointer to smart pointer is illegal"); + } + switch (this.sharingPolicy) { + case 0: + if (handle.$$.smartPtrType === this) { + ptr = handle.$$.smartPtr; + } else { + throwBindingError("Cannot convert argument of type " + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + " to parameter type " + this.name); + } + break; + + case 1: + ptr = handle.$$.smartPtr; + break; + + case 2: + if (handle.$$.smartPtrType === this) { + ptr = handle.$$.smartPtr; + } else { + var clonedHandle = handle["clone"](); + ptr = this.rawShare(ptr, Emval.toHandle(function() { + clonedHandle["delete"](); + })); + if (destructors !== null) { + destructors.push(this.rawDestructor, ptr); + } + } + break; + + default: + throwBindingError("Unsupporting sharing policy"); + } + } + return ptr; +} + +function nonConstNoSmartPtrRawPointerToWireType(destructors, handle) { + if (handle === null) { + if (this.isReference) { + throwBindingError("null is not a valid " + this.name); + } + return 0; + } + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); + } + if (handle.$$.ptrType.isConst) { + throwBindingError("Cannot convert argument of type " + handle.$$.ptrType.name + " to parameter type " + this.name); + } + var handleClass = handle.$$.ptrType.registeredClass; + var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + return ptr; +} + +function RegisteredPointer_getPointee(ptr) { + if (this.rawGetPointee) { + ptr = this.rawGetPointee(ptr); + } + return ptr; +} + +function RegisteredPointer_destructor(ptr) { + if (this.rawDestructor) { + this.rawDestructor(ptr); + } +} + +function RegisteredPointer_deleteObject(handle) { + if (handle !== null) { + handle["delete"](); + } +} + +function init_RegisteredPointer() { + RegisteredPointer.prototype.getPointee = RegisteredPointer_getPointee; + RegisteredPointer.prototype.destructor = RegisteredPointer_destructor; + RegisteredPointer.prototype["argPackAdvance"] = 8; + RegisteredPointer.prototype["readValueFromPointer"] = simpleReadValueFromPointer; + RegisteredPointer.prototype["deleteObject"] = RegisteredPointer_deleteObject; + RegisteredPointer.prototype["fromWireType"] = RegisteredPointer_fromWireType; +} + +function RegisteredPointer(name, registeredClass, isReference, isConst, isSmartPointer, pointeeType, sharingPolicy, rawGetPointee, rawConstructor, rawShare, rawDestructor) { + this.name = name; + this.registeredClass = registeredClass; + this.isReference = isReference; + this.isConst = isConst; + this.isSmartPointer = isSmartPointer; + this.pointeeType = pointeeType; + this.sharingPolicy = sharingPolicy; + this.rawGetPointee = rawGetPointee; + this.rawConstructor = rawConstructor; + this.rawShare = rawShare; + this.rawDestructor = rawDestructor; + if (!isSmartPointer && registeredClass.baseClass === undefined) { + if (isConst) { + this["toWireType"] = constNoSmartPtrRawPointerToWireType; + this.destructorFunction = null; + } else { + this["toWireType"] = nonConstNoSmartPtrRawPointerToWireType; + this.destructorFunction = null; + } + } else { + this["toWireType"] = genericPointerToWireType; + } +} + +function replacePublicSymbol(name, value, numArguments) { + if (!Module.hasOwnProperty(name)) { + throwInternalError("Replacing nonexistant public symbol"); + } + if (undefined !== Module[name].overloadTable && undefined !== numArguments) { + Module[name].overloadTable[numArguments] = value; + } else { + Module[name] = value; + Module[name].argCount = numArguments; + } +} + +function dynCallLegacy(sig, ptr, args) { + var f = Module["dynCall_" + sig]; + return args && args.length ? f.apply(null, [ ptr ].concat(args)) : f.call(null, ptr); +} + +function dynCall(sig, ptr, args) { + if (sig.includes("j")) { + return dynCallLegacy(sig, ptr, args); + } + return getWasmTableEntry(ptr).apply(null, args); +} + +function getDynCaller(sig, ptr) { + var argCache = []; + return function() { + argCache.length = 0; + Object.assign(argCache, arguments); + return dynCall(sig, ptr, argCache); + }; +} + +function embind__requireFunction(signature, rawFunction) { + signature = readLatin1String(signature); + function makeDynCaller() { + if (signature.includes("j")) { + return getDynCaller(signature, rawFunction); + } + return getWasmTableEntry(rawFunction); + } + var fp = makeDynCaller(); + if (typeof fp != "function") { + throwBindingError("unknown function pointer with signature " + signature + ": " + rawFunction); + } + return fp; +} + +var UnboundTypeError = undefined; + +function getTypeName(type) { + var ptr = ___getTypeName(type); + var rv = readLatin1String(ptr); + _free(ptr); + return rv; +} + +function 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([ ", " ])); +} + +function __embind_register_class(rawType, rawPointerType, rawConstPointerType, baseClassRawType, getActualTypeSignature, getActualType, upcastSignature, upcast, downcastSignature, downcast, name, destructorSignature, rawDestructor) { + name = readLatin1String(name); + getActualType = embind__requireFunction(getActualTypeSignature, getActualType); + if (upcast) { + upcast = embind__requireFunction(upcastSignature, upcast); + } + if (downcast) { + downcast = embind__requireFunction(downcastSignature, downcast); + } + rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); + var legalFunctionName = makeLegalFunctionName(name); + exposePublicSymbol(legalFunctionName, function() { + throwUnboundTypeError("Cannot construct " + name + " due to unbound types", [ baseClassRawType ]); + }); + whenDependentTypesAreResolved([ rawType, rawPointerType, rawConstPointerType ], baseClassRawType ? [ baseClassRawType ] : [], function(base) { + base = base[0]; + var baseClass; + var basePrototype; + if (baseClassRawType) { + baseClass = base.registeredClass; + basePrototype = baseClass.instancePrototype; + } else { + basePrototype = ClassHandle.prototype; + } + var constructor = createNamedFunction(legalFunctionName, function() { + if (Object.getPrototypeOf(this) !== instancePrototype) { + throw new BindingError("Use 'new' to construct " + name); + } + if (undefined === registeredClass.constructor_body) { + throw new BindingError(name + " has no accessible constructor"); + } + var body = registeredClass.constructor_body[arguments.length]; + if (undefined === body) { + throw new BindingError("Tried to invoke ctor of " + name + " with invalid number of parameters (" + arguments.length + ") - expected (" + Object.keys(registeredClass.constructor_body).toString() + ") parameters instead!"); + } + return body.apply(this, arguments); + }); + var instancePrototype = Object.create(basePrototype, { + constructor: { + value: constructor + } + }); + constructor.prototype = instancePrototype; + var registeredClass = new RegisteredClass(name, constructor, instancePrototype, rawDestructor, baseClass, getActualType, upcast, downcast); + var referenceConverter = new RegisteredPointer(name, registeredClass, true, false, false); + var pointerConverter = new RegisteredPointer(name + "*", registeredClass, false, false, false); + var constPointerConverter = new RegisteredPointer(name + " const*", registeredClass, false, true, false); + registeredPointers[rawType] = { + pointerType: pointerConverter, + constPointerType: constPointerConverter + }; + replacePublicSymbol(legalFunctionName, constructor); + return [ referenceConverter, pointerConverter, constPointerConverter ]; + }); +} + +function heap32VectorToArray(count, firstElement) { + var array = []; + for (var i = 0; i < count; i++) { + array.push(HEAP32[(firstElement >> 2) + i]); + } + return array; +} + +function __embind_register_class_constructor(rawClassType, argCount, rawArgTypesAddr, invokerSignature, invoker, rawConstructor) { + assert(argCount > 0); + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + invoker = embind__requireFunction(invokerSignature, invoker); + whenDependentTypesAreResolved([], [ rawClassType ], function(classType) { + classType = classType[0]; + var humanName = "constructor " + classType.name; + if (undefined === classType.registeredClass.constructor_body) { + classType.registeredClass.constructor_body = []; + } + if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) { + throw new BindingError("Cannot register multiple constructors with identical number of parameters (" + (argCount - 1) + ") for class '" + classType.name + "'! Overload resolution is currently only performed using the parameter count, not actual type info!"); + } + classType.registeredClass.constructor_body[argCount - 1] = (() => { + throwUnboundTypeError("Cannot construct " + classType.name + " due to unbound types", rawArgTypes); + }); + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + argTypes.splice(1, 0, null); + classType.registeredClass.constructor_body[argCount - 1] = craftInvokerFunction(humanName, argTypes, null, invoker, rawConstructor); + return []; + }); + return []; + }); +} + +function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) { + 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; + var needsDestructorStack = false; + for (var i = 1; i < argTypes.length; ++i) { + if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { + needsDestructorStack = true; + break; + } + } + var returns = argTypes[0].name !== "void"; + var expectedArgCount = argCount - 2; + var argsWired = new Array(expectedArgCount); + var invokerFuncArgs = []; + var destructors = []; + return function() { + if (arguments.length !== expectedArgCount) { + throwBindingError("function " + humanName + " called with " + arguments.length + " arguments, expected " + expectedArgCount + " 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, arguments[i]); + invokerFuncArgs.push(argsWired[i]); + } + var rv = cppInvokerFunc.apply(null, 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); + } + } + return onDone(rv); + }; +} + +function __embind_register_class_function(rawClassType, methodName, argCount, rawArgTypesAddr, invokerSignature, rawInvoker, context, isPureVirtual) { + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + methodName = readLatin1String(methodName); + rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); + whenDependentTypesAreResolved([], [ rawClassType ], function(classType) { + classType = classType[0]; + var humanName = classType.name + "." + methodName; + if (methodName.startsWith("@@")) { + methodName = Symbol[methodName.substring(2)]; + } + if (isPureVirtual) { + classType.registeredClass.pureVirtualFunctions.push(methodName); + } + function unboundTypesHandler() { + throwUnboundTypeError("Cannot call " + humanName + " due to unbound types", rawArgTypes); + } + var proto = classType.registeredClass.instancePrototype; + var method = proto[methodName]; + if (undefined === method || undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount - 2) { + unboundTypesHandler.argCount = argCount - 2; + unboundTypesHandler.className = classType.name; + proto[methodName] = unboundTypesHandler; + } else { + ensureOverloadTable(proto, methodName, humanName); + proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler; + } + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context); + if (undefined === proto[methodName].overloadTable) { + memberFunction.argCount = argCount - 2; + proto[methodName] = memberFunction; + } else { + proto[methodName].overloadTable[argCount - 2] = memberFunction; + } + return []; + }); + return []; + }); +} + +var emval_free_list = []; + +var emval_handle_array = [ {}, { + value: undefined +}, { + value: null +}, { + value: true +}, { + value: false +} ]; + +function __emval_decref(handle) { + if (handle > 4 && 0 === --emval_handle_array[handle].refcount) { + emval_handle_array[handle] = undefined; + emval_free_list.push(handle); + } +} + +function count_emval_handles() { + var count = 0; + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== undefined) { + ++count; + } + } + return count; +} + +function get_first_emval() { + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== undefined) { + return emval_handle_array[i]; + } + } + return null; +} + +function init_emval() { + Module["count_emval_handles"] = count_emval_handles; + Module["get_first_emval"] = get_first_emval; +} + +var Emval = { + toValue: handle => { + if (!handle) { + throwBindingError("Cannot use deleted val. handle = " + handle); + } + return emval_handle_array[handle].value; + }, + toHandle: value => { + switch (value) { + case undefined: + return 1; + + case null: + return 2; + + case true: + return 3; + + case false: + return 4; + + default: + { + var handle = emval_free_list.length ? emval_free_list.pop() : emval_handle_array.length; + emval_handle_array[handle] = { + refcount: 1, + value: value + }; + return handle; + } + } + } +}; + +function __embind_register_emval(rawType, name) { + name = readLatin1String(name); + registerType(rawType, { + name: name, + "fromWireType": function(handle) { + var rv = Emval.toValue(handle); + __emval_decref(handle); + return rv; + }, + "toWireType": function(destructors, value) { + return Emval.toHandle(value); + }, + "argPackAdvance": 8, + "readValueFromPointer": simpleReadValueFromPointer, + destructorFunction: null + }); +} + +function _embind_repr(v) { + if (v === null) { + return "null"; + } + var t = typeof v; + if (t === "object" || t === "array" || t === "function") { + return v.toString(); + } else { + return "" + v; + } +} + +function floatReadValueFromPointer(name, shift) { + switch (shift) { + case 2: + return function(pointer) { + return this["fromWireType"](HEAPF32[pointer >> 2]); + }; + + case 3: + return function(pointer) { + return this["fromWireType"](HEAPF64[pointer >> 3]); + }; + + default: + throw new TypeError("Unknown float type: " + name); + } +} + +function __embind_register_float(rawType, name, size) { + var shift = getShiftFromSize(size); + name = readLatin1String(name); + registerType(rawType, { + name: name, + "fromWireType": function(value) { + return value; + }, + "toWireType": function(destructors, value) { + return value; + }, + "argPackAdvance": 8, + "readValueFromPointer": floatReadValueFromPointer(name, shift), + destructorFunction: null + }); +} + +function integerReadValueFromPointer(name, shift, signed) { + switch (shift) { + case 0: + return signed ? function readS8FromPointer(pointer) { + return HEAP8[pointer]; + } : function readU8FromPointer(pointer) { + return HEAPU8[pointer]; + }; + + case 1: + return signed ? function readS16FromPointer(pointer) { + return HEAP16[pointer >> 1]; + } : function readU16FromPointer(pointer) { + return HEAPU16[pointer >> 1]; + }; + + case 2: + return signed ? function readS32FromPointer(pointer) { + return HEAP32[pointer >> 2]; + } : function readU32FromPointer(pointer) { + return HEAPU32[pointer >> 2]; + }; + + default: + throw new TypeError("Unknown integer type: " + name); + } +} + +function __embind_register_integer(primitiveType, name, size, minRange, maxRange) { + name = readLatin1String(name); + if (maxRange === -1) { + maxRange = 4294967295; + } + var shift = getShiftFromSize(size); + var fromWireType = value => value; + if (minRange === 0) { + var bitshift = 32 - 8 * size; + fromWireType = (value => value << bitshift >>> bitshift); + } + var isUnsignedType = name.includes("unsigned"); + var checkAssertions = (value, toTypeName) => {}; + var toWireType; + if (isUnsignedType) { + toWireType = function(destructors, value) { + checkAssertions(value, this.name); + return value >>> 0; + }; + } else { + toWireType = function(destructors, value) { + checkAssertions(value, this.name); + return value; + }; + } + registerType(primitiveType, { + name: name, + "fromWireType": fromWireType, + "toWireType": toWireType, + "argPackAdvance": 8, + "readValueFromPointer": integerReadValueFromPointer(name, shift, minRange !== 0), + destructorFunction: null + }); +} + +function __embind_register_memory_view(rawType, dataTypeIndex, name) { + var typeMapping = [ Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + var TA = typeMapping[dataTypeIndex]; + function decodeMemoryView(handle) { + handle = handle >> 2; + var heap = HEAPU32; + var size = heap[handle]; + var data = heap[handle + 1]; + return new TA(buffer, data, size); + } + name = readLatin1String(name); + registerType(rawType, { + name: name, + "fromWireType": decodeMemoryView, + "argPackAdvance": 8, + "readValueFromPointer": decodeMemoryView + }, { + ignoreDuplicateRegistrations: true + }); +} + +function __embind_register_smart_ptr(rawType, rawPointeeType, name, sharingPolicy, getPointeeSignature, rawGetPointee, constructorSignature, rawConstructor, shareSignature, rawShare, destructorSignature, rawDestructor) { + name = readLatin1String(name); + rawGetPointee = embind__requireFunction(getPointeeSignature, rawGetPointee); + rawConstructor = embind__requireFunction(constructorSignature, rawConstructor); + rawShare = embind__requireFunction(shareSignature, rawShare); + rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); + whenDependentTypesAreResolved([ rawType ], [ rawPointeeType ], function(pointeeType) { + pointeeType = pointeeType[0]; + var registeredPointer = new RegisteredPointer(name, pointeeType.registeredClass, false, false, true, pointeeType, sharingPolicy, rawGetPointee, rawConstructor, rawShare, rawDestructor); + return [ registeredPointer ]; + }); +} + +function __embind_register_std_string(rawType, name) { + name = readLatin1String(name); + var stdStringIsUTF8 = name === "std::string"; + registerType(rawType, { + name: name, + "fromWireType": function(value) { + var length = HEAPU32[value >> 2]; + var str; + if (stdStringIsUTF8) { + var decodeStartPtr = value + 4; + for (var i = 0; i <= length; ++i) { + var currentBytePtr = value + 4 + i; + if (i == length || HEAPU8[currentBytePtr] == 0) { + var maxRead = currentBytePtr - decodeStartPtr; + var stringSegment = UTF8ToString(decodeStartPtr, maxRead); + if (str === undefined) { + str = stringSegment; + } else { + str += String.fromCharCode(0); + str += stringSegment; + } + decodeStartPtr = currentBytePtr + 1; + } + } + } else { + var a = new Array(length); + for (var i = 0; i < length; ++i) { + a[i] = String.fromCharCode(HEAPU8[value + 4 + i]); + } + str = a.join(""); + } + _free(value); + return str; + }, + "toWireType": function(destructors, value) { + if (value instanceof ArrayBuffer) { + value = new Uint8Array(value); + } + var getLength; + var valueIsOfTypeString = typeof value == "string"; + if (!(valueIsOfTypeString || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Int8Array)) { + throwBindingError("Cannot pass non-string to std::string"); + } + if (stdStringIsUTF8 && valueIsOfTypeString) { + getLength = (() => lengthBytesUTF8(value)); + } else { + getLength = (() => value.length); + } + var length = getLength(); + var ptr = _malloc(4 + length + 1); + HEAPU32[ptr >> 2] = length; + if (stdStringIsUTF8 && valueIsOfTypeString) { + stringToUTF8(value, ptr + 4, length + 1); + } else { + if (valueIsOfTypeString) { + for (var i = 0; i < length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode > 255) { + _free(ptr); + throwBindingError("String has UTF-16 code units that do not fit in 8 bits"); + } + HEAPU8[ptr + 4 + i] = charCode; + } + } else { + for (var i = 0; i < length; ++i) { + HEAPU8[ptr + 4 + i] = value[i]; + } + } + } + if (destructors !== null) { + destructors.push(_free, ptr); + } + return ptr; + }, + "argPackAdvance": 8, + "readValueFromPointer": simpleReadValueFromPointer, + destructorFunction: function(ptr) { + _free(ptr); + } + }); +} + +function __embind_register_std_wstring(rawType, charSize, name) { + name = readLatin1String(name); + var decodeString, encodeString, getHeap, lengthBytesUTF, shift; + if (charSize === 2) { + decodeString = UTF16ToString; + encodeString = stringToUTF16; + lengthBytesUTF = lengthBytesUTF16; + getHeap = (() => HEAPU16); + shift = 1; + } else if (charSize === 4) { + decodeString = UTF32ToString; + encodeString = stringToUTF32; + lengthBytesUTF = lengthBytesUTF32; + getHeap = (() => HEAPU32); + shift = 2; + } + registerType(rawType, { + name: name, + "fromWireType": function(value) { + var length = HEAPU32[value >> 2]; + var HEAP = getHeap(); + var str; + var decodeStartPtr = value + 4; + for (var i = 0; i <= length; ++i) { + var currentBytePtr = value + 4 + i * charSize; + if (i == length || HEAP[currentBytePtr >> shift] == 0) { + var maxReadBytes = currentBytePtr - decodeStartPtr; + var stringSegment = decodeString(decodeStartPtr, maxReadBytes); + if (str === undefined) { + str = stringSegment; + } else { + str += String.fromCharCode(0); + str += stringSegment; + } + decodeStartPtr = currentBytePtr + charSize; + } + } + _free(value); + return str; + }, + "toWireType": function(destructors, value) { + if (!(typeof value == "string")) { + throwBindingError("Cannot pass non-string to C++ string type " + name); + } + var length = lengthBytesUTF(value); + var ptr = _malloc(4 + length + charSize); + HEAPU32[ptr >> 2] = length >> shift; + encodeString(value, ptr + 4, length + charSize); + if (destructors !== null) { + destructors.push(_free, ptr); + } + return ptr; + }, + "argPackAdvance": 8, + "readValueFromPointer": simpleReadValueFromPointer, + destructorFunction: function(ptr) { + _free(ptr); + } + }); +} + +function __embind_register_value_object(rawType, name, constructorSignature, rawConstructor, destructorSignature, rawDestructor) { + structRegistrations[rawType] = { + name: readLatin1String(name), + rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), + rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), + fields: [] + }; +} + +function __embind_register_value_object_field(structType, fieldName, getterReturnType, getterSignature, getter, getterContext, setterArgumentType, setterSignature, setter, setterContext) { + structRegistrations[structType].fields.push({ + fieldName: readLatin1String(fieldName), + getterReturnType: getterReturnType, + getter: embind__requireFunction(getterSignature, getter), + getterContext: getterContext, + setterArgumentType: setterArgumentType, + setter: embind__requireFunction(setterSignature, setter), + setterContext: setterContext + }); +} + +function __embind_register_void(rawType, name) { + name = readLatin1String(name); + registerType(rawType, { + isVoid: true, + name: name, + "argPackAdvance": 0, + "fromWireType": function() { + return undefined; + }, + "toWireType": function(destructors, o) { + return undefined; + } + }); +} + +function __emscripten_date_now() { + return Date.now(); +} + +var nowIsMonotonic = true; + +function __emscripten_get_now_is_monotonic() { + return nowIsMonotonic; +} + +function requireRegisteredType(rawType, humanName) { + var impl = registeredTypes[rawType]; + if (undefined === impl) { + throwBindingError(humanName + " has unknown type " + getTypeName(rawType)); + } + return impl; +} + +function __emval_lookupTypes(argCount, argTypes) { + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + a[i] = requireRegisteredType(HEAP32[(argTypes >> 2) + i], "parameter " + i); + } + return a; +} + +function __emval_call(handle, argCount, argTypes, argv) { + handle = Emval.toValue(handle); + var types = __emval_lookupTypes(argCount, argTypes); + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var type = types[i]; + args[i] = type["readValueFromPointer"](argv); + argv += type["argPackAdvance"]; + } + var rv = handle.apply(undefined, args); + return Emval.toHandle(rv); +} + +function __emval_incref(handle) { + if (handle > 4) { + emval_handle_array[handle].refcount += 1; + } +} + +function __emval_take_value(type, argv) { + type = requireRegisteredType(type, "_emval_take_value"); + var v = type["readValueFromPointer"](argv); + return Emval.toHandle(v); +} + +function __localtime_js(time, tmPtr) { + var date = new Date(HEAP32[time >> 2] * 1e3); + HEAP32[tmPtr >> 2] = date.getSeconds(); + HEAP32[tmPtr + 4 >> 2] = date.getMinutes(); + HEAP32[tmPtr + 8 >> 2] = date.getHours(); + HEAP32[tmPtr + 12 >> 2] = date.getDate(); + HEAP32[tmPtr + 16 >> 2] = date.getMonth(); + HEAP32[tmPtr + 20 >> 2] = date.getFullYear() - 1900; + HEAP32[tmPtr + 24 >> 2] = date.getDay(); + var start = new Date(date.getFullYear(), 0, 1); + var yday = (date.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24) | 0; + HEAP32[tmPtr + 28 >> 2] = yday; + HEAP32[tmPtr + 36 >> 2] = -(date.getTimezoneOffset() * 60); + 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] = dst; +} + +function __mmap_js(addr, len, prot, flags, fd, off, allocated, builtin) { + return -52; +} + +function __munmap_js(addr, len, prot, flags, fd, offset) {} + +function _tzset_impl(timezone, daylight, tzname) { + 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(); + var stdTimezoneOffset = Math.max(winterOffset, summerOffset); + HEAP32[timezone >> 2] = stdTimezoneOffset * 60; + HEAP32[daylight >> 2] = Number(winterOffset != summerOffset); + function extractZone(date) { + var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); + return match ? match[1] : "GMT"; + } + var winterName = extractZone(winter); + var summerName = extractZone(summer); + var winterNamePtr = allocateUTF8(winterName); + var summerNamePtr = allocateUTF8(summerName); + if (summerOffset < winterOffset) { + HEAP32[tzname >> 2] = winterNamePtr; + HEAP32[tzname + 4 >> 2] = summerNamePtr; + } else { + HEAP32[tzname >> 2] = summerNamePtr; + HEAP32[tzname + 4 >> 2] = winterNamePtr; + } +} + +function __tzset_js(timezone, daylight, tzname) { + if (__tzset_js.called) return; + __tzset_js.called = true; + _tzset_impl(timezone, daylight, tzname); +} + +function _abort() { + abort(""); +} + +function _emscripten_get_heap_max() { + return 2147483648; +} + +var _emscripten_get_now; + +_emscripten_get_now = (() => performance.now()); + +function _emscripten_memcpy_big(dest, src, num) { + HEAPU8.copyWithin(dest, src, src + num); +} + +function emscripten_realloc_buffer(size) { + try { + wasmMemory.grow(size - buffer.byteLength + 65535 >>> 16); + updateGlobalBufferAndViews(wasmMemory.buffer); + return 1; + } catch (e) {} +} + +function _emscripten_resize_heap(requestedSize) { + var oldSize = HEAPU8.length; + requestedSize = requestedSize >>> 0; + var maxHeapSize = _emscripten_get_heap_max(); + if (requestedSize > maxHeapSize) { + return false; + } + let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + .2 / cutDown); + overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296); + var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)); + var replacement = emscripten_realloc_buffer(newSize); + if (replacement) { + return true; + } + } + return false; +} + +var ENV = {}; + +function getExecutableName() { + return thisProgram || "./this.program"; +} + +function getEnvStrings() { + if (!getEnvStrings.strings) { + var lang = (typeof navigator == "object" && navigator.languages && navigator.languages[0] || "C").replace("-", "_") + ".UTF-8"; + var env = { + "USER": "web_user", + "LOGNAME": "web_user", + "PATH": "/", + "PWD": "/", + "HOME": "/home/web_user", + "LANG": lang, + "_": getExecutableName() + }; + for (var x in ENV) { + 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) { + var bufSize = 0; + getEnvStrings().forEach(function(string, i) { + var ptr = environ_buf + bufSize; + HEAP32[__environ + i * 4 >> 2] = ptr; + writeAsciiToMemory(string, ptr); + bufSize += string.length + 1; + }); + return 0; +} + +function _environ_sizes_get(penviron_count, penviron_buf_size) { + var strings = getEnvStrings(); + HEAP32[penviron_count >> 2] = strings.length; + var bufSize = 0; + strings.forEach(function(string) { + bufSize += string.length + 1; + }); + HEAP32[penviron_buf_size >> 2] = bufSize; + return 0; +} + +function _exit(status) { + exit(status); +} + +function _fd_close(fd) { + return 0; +} + +function _fd_read(fd, iov, iovcnt, pnum) { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = SYSCALLS.doReadv(stream, iov, iovcnt); + HEAP32[pnum >> 2] = num; + return 0; +} + +function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {} + +function _fd_write(fd, iov, iovcnt, pnum) { + var num = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAP32[iov >> 2]; + var len = HEAP32[iov + 4 >> 2]; + iov += 8; + for (var j = 0; j < len; j++) { + SYSCALLS.printChar(fd, HEAPU8[ptr + j]); + } + num += len; + } + HEAP32[pnum >> 2] = num; + return 0; +} + +function getRandomDevice() { + if (typeof crypto == "object" && typeof crypto["getRandomValues"] == "function") { + var randomBuffer = new Uint8Array(1); + return function() { + crypto.getRandomValues(randomBuffer); + return randomBuffer[0]; + }; + } else return function() { + abort("randomDevice"); + }; +} + +function _getentropy(buffer, size) { + if (!_getentropy.randomDevice) { + _getentropy.randomDevice = getRandomDevice(); + } + for (var i = 0; i < size; i++) { + HEAP8[buffer + i >> 0] = _getentropy.randomDevice(); + } + return 0; +} + +function _pclose() { + err("missing function: pclose"); + abort(-1); +} + +function _setTempRet0(val) { + setTempRet0(val); +} + +function __isLeapYear(year) { + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); +} + +function __arraySum(array, index) { + var sum = 0; + for (var i = 0; i <= index; sum += array[i++]) {} + return sum; +} + +var __MONTH_DAYS_LEAP = [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; + +var __MONTH_DAYS_REGULAR = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; + +function __addDays(date, days) { + var newDate = new Date(date.getTime()); + while (days > 0) { + var leap = __isLeapYear(newDate.getFullYear()); + var currentMonth = newDate.getMonth(); + var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth]; + if (days > daysInCurrentMonth - newDate.getDate()) { + days -= daysInCurrentMonth - newDate.getDate() + 1; + newDate.setDate(1); + if (currentMonth < 11) { + newDate.setMonth(currentMonth + 1); + } else { + newDate.setMonth(0); + newDate.setFullYear(newDate.getFullYear() + 1); + } + } else { + newDate.setDate(newDate.getDate() + days); + return newDate; + } + } + return newDate; +} + +function _strftime(s, maxsize, format, tm) { + var tm_zone = HEAP32[tm + 40 >> 2]; + var date = { + tm_sec: HEAP32[tm >> 2], + tm_min: HEAP32[tm + 4 >> 2], + tm_hour: HEAP32[tm + 8 >> 2], + tm_mday: HEAP32[tm + 12 >> 2], + tm_mon: HEAP32[tm + 16 >> 2], + tm_year: HEAP32[tm + 20 >> 2], + tm_wday: HEAP32[tm + 24 >> 2], + tm_yday: HEAP32[tm + 28 >> 2], + tm_isdst: HEAP32[tm + 32 >> 2], + tm_gmtoff: HEAP32[tm + 36 >> 2], + tm_zone: tm_zone ? UTF8ToString(tm_zone) : "" + }; + var pattern = UTF8ToString(format); + var EXPANSION_RULES_1 = { + "%c": "%a %b %d %H:%M:%S %Y", + "%D": "%m/%d/%y", + "%F": "%Y-%m-%d", + "%h": "%b", + "%r": "%I:%M:%S %p", + "%R": "%H:%M", + "%T": "%H:%M:%S", + "%x": "%m/%d/%y", + "%X": "%H:%M:%S", + "%Ec": "%c", + "%EC": "%C", + "%Ex": "%m/%d/%y", + "%EX": "%H:%M:%S", + "%Ey": "%y", + "%EY": "%Y", + "%Od": "%d", + "%Oe": "%e", + "%OH": "%H", + "%OI": "%I", + "%Om": "%m", + "%OM": "%M", + "%OS": "%S", + "%Ou": "%u", + "%OU": "%U", + "%OV": "%V", + "%Ow": "%w", + "%OW": "%W", + "%Oy": "%y" + }; + for (var rule in EXPANSION_RULES_1) { + pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_1[rule]); + } + var WEEKDAYS = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; + var MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; + function leadingSomething(value, digits, character) { + var str = typeof value == "number" ? value.toString() : value || ""; + while (str.length < digits) { + str = character[0] + str; + } + return str; + } + function leadingNulls(value, digits) { + return leadingSomething(value, digits, "0"); + } + function compareByDay(date1, date2) { + function sgn(value) { + return value < 0 ? -1 : value > 0 ? 1 : 0; + } + var compare; + if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) { + if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) { + compare = sgn(date1.getDate() - date2.getDate()); + } + } + return compare; + } + function getFirstWeekStartDate(janFourth) { + switch (janFourth.getDay()) { + case 0: + return new Date(janFourth.getFullYear() - 1, 11, 29); + + case 1: + return janFourth; + + case 2: + return new Date(janFourth.getFullYear(), 0, 3); + + case 3: + return new Date(janFourth.getFullYear(), 0, 2); + + case 4: + return new Date(janFourth.getFullYear(), 0, 1); + + case 5: + return new Date(janFourth.getFullYear() - 1, 11, 31); + + case 6: + return new Date(janFourth.getFullYear() - 1, 11, 30); + } + } + function getWeekBasedYear(date) { + var thisDate = __addDays(new Date(date.tm_year + 1900, 0, 1), date.tm_yday); + var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4); + var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4); + var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear); + var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear); + if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) { + if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) { + return thisDate.getFullYear() + 1; + } else { + return thisDate.getFullYear(); + } + } else { + return thisDate.getFullYear() - 1; + } + } + var EXPANSION_RULES_2 = { + "%a": function(date) { + return WEEKDAYS[date.tm_wday].substring(0, 3); + }, + "%A": function(date) { + return WEEKDAYS[date.tm_wday]; + }, + "%b": function(date) { + return MONTHS[date.tm_mon].substring(0, 3); + }, + "%B": function(date) { + return MONTHS[date.tm_mon]; + }, + "%C": function(date) { + var year = date.tm_year + 1900; + return leadingNulls(year / 100 | 0, 2); + }, + "%d": function(date) { + return leadingNulls(date.tm_mday, 2); + }, + "%e": function(date) { + return leadingSomething(date.tm_mday, 2, " "); + }, + "%g": function(date) { + return getWeekBasedYear(date).toString().substring(2); + }, + "%G": function(date) { + return getWeekBasedYear(date); + }, + "%H": function(date) { + return leadingNulls(date.tm_hour, 2); + }, + "%I": function(date) { + var twelveHour = date.tm_hour; + if (twelveHour == 0) twelveHour = 12; else if (twelveHour > 12) twelveHour -= 12; + return leadingNulls(twelveHour, 2); + }, + "%j": function(date) { + return leadingNulls(date.tm_mday + __arraySum(__isLeapYear(date.tm_year + 1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon - 1), 3); + }, + "%m": function(date) { + return leadingNulls(date.tm_mon + 1, 2); + }, + "%M": function(date) { + return leadingNulls(date.tm_min, 2); + }, + "%n": function() { + return "\n"; + }, + "%p": function(date) { + if (date.tm_hour >= 0 && date.tm_hour < 12) { + return "AM"; + } else { + return "PM"; + } + }, + "%S": function(date) { + return leadingNulls(date.tm_sec, 2); + }, + "%t": function() { + return "\t"; + }, + "%u": function(date) { + return date.tm_wday || 7; + }, + "%U": function(date) { + var days = date.tm_yday + 7 - date.tm_wday; + return leadingNulls(Math.floor(days / 7), 2); + }, + "%V": function(date) { + var val = Math.floor((date.tm_yday + 7 - (date.tm_wday + 6) % 7) / 7); + if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) { + val++; + } + if (!val) { + val = 52; + var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7; + if (dec31 == 4 || dec31 == 5 && __isLeapYear(date.tm_year % 400 - 1)) { + val++; + } + } else if (val == 53) { + var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7; + if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1; + } + return leadingNulls(val, 2); + }, + "%w": function(date) { + return date.tm_wday; + }, + "%W": function(date) { + var days = date.tm_yday + 7 - (date.tm_wday + 6) % 7; + return leadingNulls(Math.floor(days / 7), 2); + }, + "%y": function(date) { + return (date.tm_year + 1900).toString().substring(2); + }, + "%Y": function(date) { + return date.tm_year + 1900; + }, + "%z": function(date) { + var off = date.tm_gmtoff; + var ahead = off >= 0; + off = Math.abs(off) / 60; + off = off / 60 * 100 + off % 60; + return (ahead ? "+" : "-") + String("0000" + off).slice(-4); + }, + "%Z": function(date) { + return date.tm_zone; + }, + "%%": function() { + return "%"; + } + }; + pattern = pattern.replace(/%%/g, "\0\0"); + for (var rule in EXPANSION_RULES_2) { + if (pattern.includes(rule)) { + pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_2[rule](date)); + } + } + pattern = pattern.replace(/\0\0/g, "%"); + var bytes = intArrayFromString(pattern, false); + if (bytes.length > maxsize) { + return 0; + } + writeArrayToMemory(bytes, s); + return bytes.length - 1; +} + +function _strftime_l(s, maxsize, format, tm) { + return _strftime(s, maxsize, format, tm); +} + +InternalError = Module["InternalError"] = extendError(Error, "InternalError"); + +embind_init_charCodes(); + +BindingError = Module["BindingError"] = extendError(Error, "BindingError"); + +init_ClassHandle(); + +init_embind(); + +init_RegisteredPointer(); + +UnboundTypeError = Module["UnboundTypeError"] = extendError(Error, "UnboundTypeError"); + +init_emval(); + +function 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 asmLibraryArg = { + "__assert_fail": ___assert_fail, + "__cxa_allocate_exception": ___cxa_allocate_exception, + "__cxa_rethrow": ___cxa_rethrow, + "__cxa_throw": ___cxa_throw, + "__syscall_faccessat": ___syscall_faccessat, + "__syscall_fcntl64": ___syscall_fcntl64, + "__syscall_fstat64": ___syscall_fstat64, + "__syscall_getcwd": ___syscall_getcwd, + "__syscall_ioctl": ___syscall_ioctl, + "__syscall_lstat64": ___syscall_lstat64, + "__syscall_newfstatat": ___syscall_newfstatat, + "__syscall_openat": ___syscall_openat, + "__syscall_renameat": ___syscall_renameat, + "__syscall_rmdir": ___syscall_rmdir, + "__syscall_stat64": ___syscall_stat64, + "__syscall_unlinkat": ___syscall_unlinkat, + "_embind_finalize_value_object": __embind_finalize_value_object, + "_embind_register_bigint": __embind_register_bigint, + "_embind_register_bool": __embind_register_bool, + "_embind_register_class": __embind_register_class, + "_embind_register_class_constructor": __embind_register_class_constructor, + "_embind_register_class_function": __embind_register_class_function, + "_embind_register_emval": __embind_register_emval, + "_embind_register_float": __embind_register_float, + "_embind_register_integer": __embind_register_integer, + "_embind_register_memory_view": __embind_register_memory_view, + "_embind_register_smart_ptr": __embind_register_smart_ptr, + "_embind_register_std_string": __embind_register_std_string, + "_embind_register_std_wstring": __embind_register_std_wstring, + "_embind_register_value_object": __embind_register_value_object, + "_embind_register_value_object_field": __embind_register_value_object_field, + "_embind_register_void": __embind_register_void, + "_emscripten_date_now": __emscripten_date_now, + "_emscripten_get_now_is_monotonic": __emscripten_get_now_is_monotonic, + "_emval_call": __emval_call, + "_emval_decref": __emval_decref, + "_emval_incref": __emval_incref, + "_emval_take_value": __emval_take_value, + "_localtime_js": __localtime_js, + "_mmap_js": __mmap_js, + "_munmap_js": __munmap_js, + "_tzset_js": __tzset_js, + "abort": _abort, + "emscripten_get_heap_max": _emscripten_get_heap_max, + "emscripten_get_now": _emscripten_get_now, + "emscripten_memcpy_big": _emscripten_memcpy_big, + "emscripten_resize_heap": _emscripten_resize_heap, + "environ_get": _environ_get, + "environ_sizes_get": _environ_sizes_get, + "exit": _exit, + "fd_close": _fd_close, + "fd_read": _fd_read, + "fd_seek": _fd_seek, + "fd_write": _fd_write, + "getentropy": _getentropy, + "memory": wasmMemory, + "pclose": _pclose, + "setTempRet0": _setTempRet0, + "strftime_l": _strftime_l +}; + +var asm = createWasm(); + +var calledRun; + +function ExitStatus(status) { + this.name = "ExitStatus"; + this.message = "Program terminated with exit(" + status + ")"; + this.status = status; +} + +dependenciesFulfilled = function runCaller() { + if (!calledRun) run(); + if (!calledRun) dependenciesFulfilled = runCaller; +}; + +function run(args) { + args = args || arguments_; + if (runDependencies > 0) { + return; + } + preRun(); + if (runDependencies > 0) { + return; + } + function doRun() { + if (calledRun) return; + calledRun = true; + Module["calledRun"] = true; + if (ABORT) return; + initRuntime(); + if (Module["onRuntimeInitialized"]) Module["onRuntimeInitialized"](); + postRun(); + } + if (Module["setStatus"]) { + Module["setStatus"]("Running..."); + setTimeout(function() { + setTimeout(function() { + Module["setStatus"](""); + }, 1); + doRun(); + }, 1); + } else { + doRun(); + } +} + +Module["run"] = run; + +function exit(status, implicit) { + EXITSTATUS = status; + procExit(status); +} + +function procExit(code) { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + if (Module["onExit"]) Module["onExit"](code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); +} + +if (Module["preInit"]) { + if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ]; + while (Module["preInit"].length > 0) { + Module["preInit"].pop()(); + } +} + +run(); diff --git a/public/assets/bergamot-translator-worker.wasm b/public/assets/bergamot-translator-worker.wasm new file mode 100644 index 00000000..43777ab2 Binary files /dev/null and b/public/assets/bergamot-translator-worker.wasm differ diff --git a/public/assets/translator-worker.js b/public/assets/translator-worker.js new file mode 100644 index 00000000..24ff29ad --- /dev/null +++ b/public/assets/translator-worker.js @@ -0,0 +1,475 @@ +/** + * Wrapper around the dirty bits of Bergamot's WASM bindings. + */ + +// Global because importScripts is global. +var Module = {}; + +/** + * node.js compatibility: Fake GlobalWorkerScope that emulates being inside a + * WebWorker + */ +if (typeof self === 'undefined') { + global.Module = Module; + + global.self = new class GlobalWorkerScope { + /** @type {import("node:worker_threads").MessagePort} */ + #port; + + constructor() { + const {parentPort} = require(/* webpackIgnore: true */ 'node:worker_threads'); + this.#port = parentPort; + } + + /** + * Add event listener to listen for messages posted to the worker. + * @param {string} eventName + * @param {(object)} callback + */ + addEventListener(eventName, callback) { + this.#port.on(eventName, (data) => callback({data})); + } + + /** + * Post message outside, to the owner of the Worker. + * @param {any} message + */ + postMessage(message) { + this.#port.postMessage(message); + } + + /** + * @param {...string} scripts - Paths to scripts to import in that order + */ + importScripts(...scripts) { + const {readFileSync} = require(/* webpackIgnore: true */ 'node:fs'); + const {join} = require(/* webpackIgnore: true */ 'node:path'); + for (let pathname of scripts) { + const script = readFileSync(join(__dirname, pathname), {encoding: 'utf-8'}); + eval.call(global, script); + } + } + + /** + * Adds support for local file urls. Assumes anything that doesn't start + * with "http" to be a local path. + * @param {string} url - path or url + * @param {object?} options - See `fetch()` options + * @return {Promise} + */ + async fetch(url, options) { + if (url.protocol === 'file:') { + const {readFile} = require(/* webpackIgnore: true */ 'node:fs/promises'); + const buffer = await readFile(url.pathname); + const blob = new Blob([buffer]); + return new Response(blob, { + status: 200, + statusText: 'OK', + headers: { + 'Content-Type': 'application/wasm', + 'Content-Length': blob.size.toString() + } + }); + } + + return await fetch(url, options); + } + + get location() { + return new URL(`file://${__filename}`); + } + } +} + +class YAML { + /** + * Parses YAML into dictionary. Does not interpret types, all values are a + * string or a list of strings. No support for objects other than the top + * level. + * @param {string} yaml + * @return {{[string]: string | string[]}} + */ + static parse(yaml) { + const out = {}; + + yaml.split('\n').reduce((key, line, i) => { + let match; + if (match = line.match(/^\s*-\s+(.+?)$/)) { + if (!Array.isArray(out[key])) + out[key] = out[key].trim() ? [out[key]] : []; + out[key].push(match[1].trim()); + } + else if (match = line.match(/^\s*([A-Za-z0-9_][A-Za-z0-9_-]*):\s*(.*)$/)) { + key = match[1]; + out[key] = match[2].trim(); + } + else if (!line.trim()) { + // whitespace, ignore + } + else { + throw Error(`Could not parse line ${i+1}: "${line}"`); + } + return key; + }, null); + + return out; + } + + /** + * Turns an object into a YAML string. No support for objects, only simple + * types and lists of simple types. + * @param {{[string]: string | number | boolean | string[]}} data + * @return {string} + */ + static stringify(data) { + return Object.entries(data).reduce((str, [key, value]) => { + let valstr = ''; + if (Array.isArray(value)) + valstr = value.map(val => `\n - ${val}`).join(''); + else if (typeof value === 'number' || typeof value === 'boolean' || value.match(/^\d*(\.\d+)?$/)) + valstr = `${value}`; + else + valstr = `${value}`; // Quote? + + return `${str}${key}: ${valstr}\n`; + }, ''); + } +} + +/** + * Wrapper around the bergamot-translator exported module that hides the need + * of working with C++ style data structures and does model management. + */ +class BergamotTranslatorWorker { + /** + * Map of expected symbol -> name of fallback symbol for functions that can + * be swizzled for a faster implementation. Firefox Nightly makes use of + * this. + */ + static GEMM_TO_FALLBACK_FUNCTIONS_MAP = { + 'int8_prepare_a': 'int8PrepareAFallback', + 'int8_prepare_b': 'int8PrepareBFallback', + 'int8_prepare_b_from_transposed': 'int8PrepareBFromTransposedFallback', + 'int8_prepare_b_from_quantized_transposed': 'int8PrepareBFromQuantizedTransposedFallback', + 'int8_prepare_bias': 'int8PrepareBiasFallback', + 'int8_multiply_and_add_bias': 'int8MultiplyAndAddBiasFallback', + 'int8_select_columns_of_b': 'int8SelectColumnsOfBFallback' + }; + + /** + * Name of module exported by Firefox Nightly that exports an optimised + * implementation of the symbols mentioned above. + */ + static NATIVE_INT_GEMM = 'mozIntGemm'; + + /** + * Empty because we can't do async constructors yet. It is the + * responsibility of whoever owns this WebWorker to call `initialize()`. + */ + constructor(options) {} + + /** + * Instantiates a new translation worker with optional options object. + * If this call succeeds, the WASM runtime is loaded and ready. + * + * Available options are: + * useNativeIntGemm: {true | false} defaults to false. If true, it will + * attempt to link to the intgemm module available in + * Firefox Nightly which makes translations much faster. + * cacheSize: {Number} defaults to 0 which disables translation + * cache entirely. Note that this is a theoretical + * upper bound. In practice it will use about 1/3th of + * the cache specified here. 2^14 is not a bad starting + * value. + * @param {{useNativeIntGemm: boolean, cacheSize: number}} options + */ + async initialize(options) { + this.options = options || {}; + this.models = new Map(); // Map> + this.module = await this.loadModule(); + this.service = await this.loadTranslationService(); + } + + /** + * Tries to load native IntGEMM module for bergamot-translator. If that + * fails because it or any of the expected functions is not available, it + * falls back to using the naive implementations that come with the wasm + * binary itself through `linkFallbackIntGemm()`. + * @param {{env: {memory: WebAssembly.Memory}}} info + * @return {{[method:string]: (...any) => any}} + */ + linkNativeIntGemm(info) { + if (!WebAssembly['mozIntGemm']) { + console.warn('Native gemm requested but not available, falling back to embedded gemm'); + return this.linkFallbackIntGemm(info); + } + + const instance = new WebAssembly.Instance(WebAssembly['mozIntGemm'](), { + '': {memory: info['env']['memory']} + }); + + if (!Array.from(Object.keys(BergamotTranslatorWorker.GEMM_TO_FALLBACK_FUNCTIONS_MAP)).every(fun => instance.exports[fun])) { + console.warn('Native gemm is missing expected functions, falling back to embedded gemm'); + return this.linkFallbackIntGemm(info); + } + + return instance.exports; + } + + /** + * Links intgemm functions that are already available in the wasm binary, + * but just exports them under the name that is expected by + * bergamot-translator. + * @param {{env: {memory: WebAssembly.Memory}}} info + * @return {{[method:string]: (...any) => any}} + */ + linkFallbackIntGemm(info) { + const mapping = Object.entries(BergamotTranslatorWorker.GEMM_TO_FALLBACK_FUNCTIONS_MAP).map(([key, name]) => { + return [key, (...args) => Module['asm'][name](...args)] + }); + + return Object.fromEntries(mapping); + } + + /** + * Internal method. Reads and instantiates the WASM binary. Returns a + * promise for the exported Module object that contains all the classes + * and functions exported by bergamot-translator. + * @return {Promise} + */ + loadModule() { + return new Promise(async (resolve, reject) => { + try { + const response = await self.fetch(new URL('./bergamot-translator-worker.wasm', self.location)); + + Object.assign(Module, { + instantiateWasm: (info, accept) => { + try { + WebAssembly.instantiateStreaming(response, { + ...info, + 'wasm_gemm': this.options.useNativeIntGemm + ? this.linkNativeIntGemm(info) + : this.linkFallbackIntGemm(info) + }).then(({instance}) => accept(instance)).catch(reject); + } catch (err) { + reject(err); + } + return {}; + }, + onRuntimeInitialized: () => { + resolve(Module); + } + }); + + // Emscripten glue code. Webpack et al. should not mangle the `Module` property name! + self.Module = Module; + self.importScripts('bergamot-translator-worker.js'); + } catch (err) { + reject(err); + } + }); + } + + /** + * Internal method. Instantiates a BlockingService() + * @return {BergamotTranslator.BlockingService} + */ + loadTranslationService() { + return new this.module.BlockingService({ + cacheSize: Math.max(this.options.cacheSize || 0, 0) + }); + } + + /** + * Returns whether a model has already been loaded in this worker. Marked + * async because the message passing interface we use expects async methods. + * @param {{from:string, to:string}} + * @return boolean + */ + hasTranslationModel({from,to}) { + const key = JSON.stringify({from,to}); + return this.models.has(key); + } + + /** + * Loads a translation model from a set of file buffers. After this, the + * model is available to translate with and `hasTranslationModel()` will + * return true for this pair. + * @param {{from:string, to:string}} + * @param {{ + * model: ArrayBuffer, + * shortlist: ArrayBuffer, + * vocabs: ArrayBuffer[], + * qualityModel: ArrayBuffer?, + * config?: { + * [key:string]: string + * } + * }} buffers + */ + loadTranslationModel({from, to}, buffers) { + // This because service_bindings.cpp:prepareVocabsSmartMemories :( + const uniqueVocabs = buffers.vocabs.filter((vocab, index, vocabs) => { + return !vocabs.slice(0, index).includes(vocab); + }); + + const [modelMemory, shortlistMemory, qualityModel, ...vocabMemory] = [ + this.prepareAlignedMemoryFromBuffer(buffers.model, 256), + this.prepareAlignedMemoryFromBuffer(buffers.shortlist, 64), + buffers.qualityModel // optional quality model + ? this.prepareAlignedMemoryFromBuffer(buffers.qualityModel, 64) + : null, + ...uniqueVocabs.map(vocab => this.prepareAlignedMemoryFromBuffer(vocab, 64)) + ]; + + const vocabs = new this.module.AlignedMemoryList(); + vocabMemory.forEach(vocab => vocabs.push_back(vocab)); + + // Defaults + let modelConfig = YAML.parse(` + beam-size: 1 + normalize: 1.0 + word-penalty: 0 + cpu-threads: 0 + gemm-precision: int8shiftAlphaAll + skip-cost: true + `); + + if (buffers.config) + Object.assign(modelConfig, buffers.config); + + // WASM marian is only compiled with support for shiftedAll. + if (modelConfig['gemm-precision'] === 'int8') + modelConfig['gemm-precision'] = 'int8shiftAll'; + + // Override these + Object.assign(modelConfig, YAML.parse(` + alignment: soft + quiet: true + quiet-translation: true + max-length-break: 128 + mini-batch-words: 1024 + workspace: 128 + max-length-factor: 2.0 + `)); + + const key = JSON.stringify({from,to}); + this.models.set(key, new this.module.TranslationModel(YAML.stringify(modelConfig), modelMemory, shortlistMemory, vocabs, qualityModel)); + } + + /** + * Frees up memory used by old translation model. Does nothing if model is + * already deleted. + * @param {{from:string, to:string}} + */ + freeTranslationModel({from, to}) { + const key = JSON.stringify({from,to}); + + if (!this.models.has(key)) + return; + + const model = this.models.get(key); + this.models.delete(key); + + model.delete(); + } + + /** + * Internal function. Copies the data from an ArrayBuffer into memory that + * can be used inside the WASM vm by Marian. + * @param {{ArrayBuffer}} buffer + * @param {number} alignmentSize + * @return {BergamotTranslator.AlignedMemory} + */ + prepareAlignedMemoryFromBuffer(buffer, alignmentSize) { + const bytes = new Int8Array(buffer); + const memory = new this.module.AlignedMemory(bytes.byteLength, alignmentSize); + memory.getByteArrayView().set(bytes); + return memory; + } + + /** + * Public. Does actual translation work. You have to make sure that the + * models necessary for translating text are already loaded before calling + * this method. Returns a promise with translation responses. + * @param {{models: {from:string, to:string}[], texts: {text: string, html: boolean}[]}} + * @return {Promise<{target: {text: string}}[]>} + */ + translate({models, texts}) { + // Convert texts array into a std::vector. + let input = new this.module.VectorString(); + texts.forEach(({text}) => input.push_back(text)); + + // Extracts the texts[].html options into ResponseOption objects + let options = new this.module.VectorResponseOptions(); + texts.forEach(({html, qualityScores}) => options.push_back({alignment: false, html, qualityScores})); + + // Turn our model names into a list of TranslationModel pointers + const translationModels = models.map(({from,to}) => { + const key = JSON.stringify({from,to}); + return this.models.get(key); + }); + + // translate the input, which is a vector; the result is a vector + const responses = models.length > 1 + ? this.service.translateViaPivoting(...translationModels, input, options) + : this.service.translate(...translationModels, input, options); + + input.delete(); + options.delete(); + + // Convert the Response WASM wrappers into native JavaScript types we + // can send over the 'wire' (message passing) in the same format as we + // use in bergamot-translator. + const translations = texts.map((_, i) => ({ + target: { + text: responses.get(i).getTranslatedText() + } + })); + + responses.delete(); + + return translations; + } +} + +/** + * Because you can't put an Error object in a message. But you can post a + * generic object! + * @param {Error} error + * @return {{ + * name: string?, + * message: string?, + * stack: string? + * }} + */ +function cloneError(error) { + return { + name: error.name, + message: error.message, + stack: error.stack + }; +} + +// (Constructor doesn't really do anything, we need to call `initialize()` +// first before using it. That happens from outside the worker.) +const worker = new BergamotTranslatorWorker(); + +self.addEventListener('message', async function({data: {id, name, args}}) { + if (!id) + console.error('Received message without id', arguments[0]); + + try { + if (typeof worker[name] !== 'function') + throw TypeError(`worker[${name}] is not a function`); + + // Using `Promise.resolve` to await any promises that worker[name] + // possibly returns. + const result = await Promise.resolve(Reflect.apply(worker[name], worker, args)); + self.postMessage({id, result}); + } catch (error) { + self.postMessage({ + id, + error: cloneError(error) + }) + } +}); diff --git a/src/ts/translator/bergamotTranslator.ts b/src/ts/translator/bergamotTranslator.ts new file mode 100644 index 00000000..a7b3ca1b --- /dev/null +++ b/src/ts/translator/bergamotTranslator.ts @@ -0,0 +1,145 @@ +import { LatencyOptimisedTranslator, TranslatorBacking } from "@browsermt/bergamot-translator"; +import { gunzipSync } from 'fflate'; + +// Cache Translations Models +class CacheDB { + private readonly dbName: string; + private readonly storeName: string = "cache"; + + constructor(dbName: string = "cache") { + this.dbName = dbName; + } + + private async getDB(): Promise { + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.dbName, 1); + + request.onupgradeneeded = (event: IDBVersionChangeEvent) => { + const db = (event.target as IDBOpenDBRequest).result; + if (!db.objectStoreNames.contains(this.storeName)) { + db.createObjectStore(this.storeName, { keyPath: "url" }); + } + }; + + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); + } + + async load(url: string, checksum: string): Promise { + const db = await this.getDB(); + return new Promise((resolve, reject) => { + const transaction = db.transaction(this.storeName, "readonly"); + const store = transaction.objectStore(this.storeName); + const request = store.get(url); + + request.onsuccess = () => { + const result = request.result; + if (result && result.checksum === checksum) { + resolve(result.buffer); + } else { + resolve(null); + } + }; + + request.onerror = () => reject(request.error); + }); + } + + async save(url: string, checksum: string, buffer: ArrayBuffer): Promise { + const db = await this.getDB(); + return new Promise((resolve, reject) => { + const transaction = db.transaction(this.storeName, "readwrite"); + const store = transaction.objectStore(this.storeName); + const request = store.put({ url, checksum, buffer }); + + request.onsuccess = () => resolve(); + request.onerror = () => reject(request.error); + }); + } + + async clear(): Promise { + const db = await this.getDB(); + return new Promise((resolve, reject) => { + const transaction = db.transaction(this.storeName, "readwrite"); + const store = transaction.objectStore(this.storeName); + const request = store.clear(); + + request.onsuccess = () => resolve(); + request.onerror = () => reject(request.error); + }); + } +} + +// Mozilla Firefox Translations Models +class FirefoxBacking extends TranslatorBacking { + private cache: CacheDB; + downloadTimeout: number; + + constructor(options?) { + const registryUrl = 'https://raw.githubusercontent.com/mozilla/firefox-translations-models/refs/heads/main/registry.json'; + options = options || {}; + options.registryUrl = options.registryUrl || registryUrl; + super(options); + this.cache = new CacheDB("firefox-translations-models"); + } + + async loadModelRegistery() { + const modelUrl = 'https://media.githubusercontent.com/media/mozilla/firefox-translations-models/refs/heads/main/models'; + const registry = await super.loadModelRegistery(); + for (const entry of registry) { + for(const name in entry.files) { + const file = entry.files[name]; + file.name = `${modelUrl}/${file.modelType}/${entry.from}${entry.to}/${file.name}.gz`; + } + } + return registry; + } + + async fetch(url, checksum, extra) { + const cacheBuffer = await this.cache.load(url, checksum); + if (cacheBuffer) { return cacheBuffer; } + const res = await fetch(url, { + credentials: 'omit', + }); + // Decompress GZip + const buffer = await res.arrayBuffer(); + const decomp = await decompressGZip(buffer); + await this.cache.save(url, checksum, decomp); + return decomp; + } +} + +async function decompressGZip(buffer:ArrayBuffer) { + if (typeof DecompressionStream !== "undefined") { + const decompressor = new DecompressionStream('gzip'); + const stream = new Response(buffer).body.pipeThrough(decompressor); + return await new Response(stream).arrayBuffer(); + } else { // GZip decompression fallback + return gunzipSync(new Uint8Array(buffer)).buffer; + } +} + +let translator = null; +let translateTask = null; + +// Translate +export async function bergamotTranslate(text:string, from:string, to:string, html:boolean|null) { + translator ??= new LatencyOptimisedTranslator({}, new FirefoxBacking()) + const result = await (translateTask = translate()); + return result.target.text; + + // Wait for previous tasks... + async function translate() { + await translateTask; + return translator.translate({ + from: from, to: to, + text: text, html: html, + }); + } +} + +// Clear Cache +export async function clearCache() { + await new CacheDB("firefox-translations-models").clear(); +} \ No newline at end of file diff --git a/src/ts/translator/translator.ts b/src/ts/translator/translator.ts index 9a8ea999..463872d1 100644 --- a/src/ts/translator/translator.ts +++ b/src/ts/translator/translator.ts @@ -10,6 +10,7 @@ import { selectedCharID } from "../stores.svelte" import { getModuleRegexScripts } from "../process/modules" import { getNodetextToSentence, sleep } from "../util" import { processScriptFull } from "../process/scripts" +import { bergamotTranslate } from "./bergamotTranslator" import localforage from "localforage" import sendSound from '../../etc/send.mp3' @@ -165,6 +166,9 @@ async function translateMain(text:string, arg:{from:string, to:string, host:stri return f.data.data; } + if(db.translatorType == "bergamot") { + return bergamotTranslate(text, arg.from, arg.to, false); + } if(db.useExperimentalGoogleTranslator){ const hqAvailable = isTauri || isNodeServer || userScriptFetch @@ -274,6 +278,11 @@ export async function translateHTML(html: string, reverse:boolean, charArg:simpl return r } + if(db.translatorType == "bergamot" && db.htmlTranslation) { + const from = db.aiModel.startsWith('novellist') ? 'ja' : 'en' + const to = db.translator || 'en' + return bergamotTranslate(html, from, to, true) + } const dom = new DOMParser().parseFromString(html, 'text/html'); console.log(html) diff --git a/vite.config.ts b/vite.config.ts index cbebe63e..b74359fc 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -52,6 +52,9 @@ export default defineConfig(({command, mode}) => { }, optimizeDeps:{ + exclude: [ + "@browsermt/bergamot-translator" + ], needsInterop:[ "@mlc-ai/web-tokenizers" ]