From 8cb782d1ffcdd439990a5e04e5d731c288319d11 Mon Sep 17 00:00:00 2001 From: mayx Date: Sat, 3 Oct 2026 07:57:00 +0000 Subject: Update 12 files - /vendor/libarchive/LICENSE - /vendor/libarchive/worker-bundle.js - /vendor/libarchive/wasm-gen/libarchive.js - /vendor/libarchive/wasm-gen/libarchive.wasm - /sw.js - /offline.md - /_layouts/default.html - /_tools/serv00_post-receive - /_tools/envs_post-receive - /_data/proxylist.yml - /assets/js/offline-page.js - /assets/js/offline-unpack.js --- _data/proxylist.yml | 1 - _layouts/default.html | 3 +- _tools/envs_post-receive | 5 +- _tools/serv00_post-receive | 4 +- assets/js/offline-page.js | 119 +++++++++++++ assets/js/offline-unpack.js | 269 +++++++++++++++++++++++++++++ offline.md | 37 ++++ sw.js | 140 +++++++++++++++ vendor/libarchive/LICENSE | 21 +++ vendor/libarchive/wasm-gen/libarchive.js | 15 ++ vendor/libarchive/wasm-gen/libarchive.wasm | Bin 0 -> 896488 bytes vendor/libarchive/worker-bundle.js | 1 + 12 files changed, 610 insertions(+), 5 deletions(-) create mode 100644 assets/js/offline-page.js create mode 100644 assets/js/offline-unpack.js create mode 100644 offline.md create mode 100644 sw.js create mode 100644 vendor/libarchive/LICENSE create mode 100644 vendor/libarchive/wasm-gen/libarchive.js create mode 100644 vendor/libarchive/wasm-gen/libarchive.wasm create mode 100644 vendor/libarchive/worker-bundle.js diff --git a/_data/proxylist.yml b/_data/proxylist.yml index 4cb705e..35ef0c9 100644 --- a/_data/proxylist.yml +++ b/_data/proxylist.yml @@ -17,7 +17,6 @@ mirrors: - https://mayx.vercel.app/ - https://mayx.netlify.app/ - https://mayx.gitnet.page/ -- https://mayx.stormkit.dev/ - https://mayx.grebedoc.dev/ - https://mayx.codeberg.page/ - https://mayx.tildepages.org/ diff --git a/_layouts/default.html b/_layouts/default.html index 616f962..13c7b59 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -98,7 +98,8 @@ layout: xslt_container
  • Download TAR Ball
  • View On GitHub
  • {% else %} -
  • Download 7-Zip File
  • +
  • Download 7-Zip File
  • +
  • Manage Offline Mode
  • {% endif %} diff --git a/_tools/envs_post-receive b/_tools/envs_post-receive index fa0f7c6..1df73b4 100644 --- a/_tools/envs_post-receive +++ b/_tools/envs_post-receive @@ -7,7 +7,8 @@ mkdir Mabbs curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md bundle exec jekyll build -d ../public_html python3 _tools/blogquine.py --src-dir blog --quine-dir blog ../public_html/ MayxBlog.7z -mv MayxBlog.7z ../public_html/ +7z a -mx9 -bd -bb0 MayxBlog-new.7z MayxBlog.7z +mv MayxBlog-new.7z ../public_html/MayxBlog.7z cd ../public_html/ unset GIT_DIR git init @@ -18,6 +19,6 @@ git branch pages git remote add codeberg ssh://git@codeberg.org/mayx/pages.git git remote add bitbucket ssh://git@bitbucket.org/unmayx/unmayx.bitbucket.io.git git push -f codeberg main -git push -f codeberg pages +git push -f codeberg pages git push -f bitbucket main /home/mayx/blog-env/node_modules/surge/bin/surge /home/mayx/public_html/ mayx.surge.sh \ No newline at end of file diff --git a/_tools/serv00_post-receive b/_tools/serv00_post-receive index f0192dc..4ad6077 100644 --- a/_tools/serv00_post-receive +++ b/_tools/serv00_post-receive @@ -7,13 +7,15 @@ mkdir Mabbs curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md bundle exec jekyll build -d ../domains/mayx.serv00.net/public_html/ python3 _tools/blogquine.py --src-dir blog --quine-dir blog ../domains/mayx.serv00.net/public_html/ MayxBlog.7z -mv MayxBlog.7z ../domains/mayx.serv00.net/public_html/ +7zz a -mx9 -bd -bb0 MayxBlog-new.7z MayxBlog.7z +mv MayxBlog-new.7z ../domains/mayx.serv00.net/public_html/MayxBlog.7z rsync -avz --delete ../domains/mayx.serv00.net/public_html/ mayx@web.sourceforge.net:/home/project-web/mayx/htdocs/ cd ../domains/mayx.serv00.net/public_html/ unset GIT_DIR git init git lfs install git lfs track "*.png" +git lfs track "*.webp" git lfs track "*.moc" git lfs track "*.tgz" git lfs track "*.jpg" diff --git a/assets/js/offline-page.js b/assets/js/offline-page.js new file mode 100644 index 0000000..8b0bdb1 --- /dev/null +++ b/assets/js/offline-page.js @@ -0,0 +1,119 @@ +/* + * Mayx的博客 · /offline.html 控制页控制器(classic script,PJAX 兼容) + * + * 本体是 IIFE,不含模块语法:PJAX 换页时 jQuery 会重新执行本文件, + * 每次执行都重新查询元素、重新绑定事件,天然幂等。真正的解包逻辑在 + * ES module /assets/js/offline-unpack.js 中,通过动态 import() 加载 + * (浏览器模块缓存保证 PJAX 反复进入本页也不会重复加载)。 + * 注意:本文件经 Liquid 原样输出,不能使用模板语法字符。 + */ + +(function () { + var MODULE_URL = '/assets/js/offline-unpack.js'; + // 压缩包大致量级(当前约 27MB),仅用于进度条比例,不影响正确性 + var EXPECTED_BYTES = 27 * 1024 * 1024; + var busy = false; + + function el(id) { return document.getElementById(id); } + function fmtMB(bytes) { return (bytes / 1048576).toFixed(1) + ' MB'; } + + function setMessage(text) { + el('offline-message').textContent = text || ''; + } + + function showProgress(show) { + el('offline-progress-box').hidden = !show; + } + + function render(meta) { + var online = !meta; + el('offline-state').textContent = online + ? '在线模式(离线未启用)' + : '离线模式(优先从本地缓存加载)'; + el('offline-version').textContent = online ? '-' : fmtMB(meta.payloadSize) + '(压缩包大小即版本号)'; + el('offline-files').textContent = online ? '-' : meta.files + ' 个文件 / ' + fmtMB(meta.bytes); + el('offline-time').textContent = online ? '-' : new Date(meta.unpackedAt).toLocaleString(); + el('offline-persist').textContent = online ? '-' : (meta.persisted ? '已授权(缓存不会被自动回收)' : '未授权(浏览器空间紧张时可能回收缓存)'); + el('offline-enable').disabled = busy || !online; + el('offline-disable').disabled = busy || online; + } + + function onProgress(info) { + if (info.done) return; + el('offline-progress').value = Math.min(100, (info.bytes / EXPECTED_BYTES) * 100); + el('offline-progress-text').textContent = + '已解包 ' + info.files + ' 个文件(' + fmtMB(info.bytes) + ')…'; + } + + function withModule(fn) { + return import(MODULE_URL).then(fn); + } + + function refresh() { + if (!('serviceWorker' in navigator) || !('caches' in window)) { + el('offline-state').textContent = '当前浏览器不支持离线模式(需要 Service Worker)'; + el('offline-enable').disabled = true; + el('offline-disable').disabled = true; + return; + } + withModule(function (mod) { return mod.ensureFresh(); }).then(function (fresh) { + render(fresh.ready ? fresh.meta : null); + if (fresh.stale) { + setMessage('检测到站点压缩包已更新,离线缓存已自动失效,当前处于在线模式。可重新启用离线模式。'); + } + }).catch(function (e) { + setMessage('状态检测失败:' + (e && e.message ? e.message : e)); + }); + } + + function onEnable() { + busy = true; + render(null); + showProgress(true); + setMessage('正在下载并解包站点压缩包,请保持网络连接…'); + withModule(function (mod) { return mod.activateOffline({ onProgress: onProgress }); }) + .then(function (meta) { + el('offline-progress').value = 100; + el('offline-progress-text').textContent = '解包完成'; + setMessage('离线模式已启用。之后访问本博客将优先使用本地缓存,断网也能阅读。'); + busy = false; + showProgress(false); + render(meta); // 立即展示离线状态,不必等后台刷新 + }) + .catch(function (e) { + setMessage('启用失败:' + (e && e.message ? e.message : e)); + busy = false; + showProgress(false); + refresh(); + }); + } + + function onDisable() { + busy = true; + setMessage(''); + withModule(function (mod) { return mod.deactivateOffline(); }) + .then(function () { + setMessage('已切回在线模式,之后页面将通过网络加载。'); + busy = false; + render(null); + if (navigator.onLine) { + setTimeout(function () { location.reload(); }, 800); + } + }) + .catch(function (e) { + setMessage('操作失败:' + (e && e.message ? e.message : e)); + busy = false; + refresh(); + }); + } + + function bind() { + var enable = el('offline-enable'); + if (!enable) return; // 不在控制页(PJAX 容错) + enable.addEventListener('click', onEnable); + el('offline-disable').addEventListener('click', onDisable); + refresh(); + } + + bind(); +})(); diff --git a/assets/js/offline-unpack.js b/assets/js/offline-unpack.js new file mode 100644 index 0000000..07893bd --- /dev/null +++ b/assets/js/offline-unpack.js @@ -0,0 +1,269 @@ +/* + * Mayx的博客 · 离线模式核心逻辑(/offline.html 控制页使用,ES module) + * + * - activateOffline():注册 SW,下载站点压缩包 /MayxBlog.7z,经 libarchive(WASM) + * 流式解包,把每个文件按站点路径写入 Cache Storage,最后写入就绪标记 + * (清单 + payloadSize 版本号),自此进入离线模式。 + * - ensureFresh():HEAD 探测线上压缩包大小,与标记中的 payloadSize 不一致 + * 说明站点已更新 → 清空缓存,回退在线模式。 + * - deactivateOffline():清空缓存,手动切回在线模式。 + * - readStatus():读取当前离线状态,供控制页展示。 + * + */ + +const ARCHIVE_URL = '/MayxBlog.7z'; +const ARCHIVE_ROOT = 'blog/'; +const CACHE_NAME = 'mayxblog-offline-v1'; +const READY_KEY = '/__offline_manifest__'; +const WORKER_URL = '/vendor/libarchive/worker-bundle.js'; + +const MIME = { + html: 'text/html; charset=utf-8', + htm: 'text/html; charset=utf-8', + css: 'text/css; charset=utf-8', + js: 'application/javascript; charset=utf-8', + mjs: 'application/javascript; charset=utf-8', + json: 'application/json; charset=utf-8', + xml: 'application/xml; charset=utf-8', + xsl: 'text/xsl; charset=utf-8', + opml: 'text/x-opml; charset=utf-8', + txt: 'text/plain; charset=utf-8', + md: 'text/markdown; charset=utf-8', + csv: 'text/csv; charset=utf-8', + svg: 'image/svg+xml', + png: 'image/png', + jpg: 'image/jpeg', + jpeg: 'image/jpeg', + gif: 'image/gif', + webp: 'image/webp', + avif: 'image/avif', + ico: 'image/x-icon', + bmp: 'image/bmp', + woff: 'font/woff', + woff2: 'font/woff2', + ttf: 'font/ttf', + otf: 'font/otf', + eot: 'application/vnd.ms-fontobject', + mp3: 'audio/mpeg', + mp4: 'video/mp4', + webm: 'video/webm', + '7z': 'application/x-7z-compressed', + zip: 'application/zip', + wasm: 'application/wasm', + mtn: 'application/octet-stream', + moc: 'application/octet-stream', + pdf: 'application/pdf', +}; + +function mimeFor(pathname) { + const dot = pathname.lastIndexOf('.'); + const ext = dot === -1 ? '' : pathname.slice(dot + 1).toLowerCase(); + return MIME[ext] || 'application/octet-stream'; +} + +function sitePathFor(entryPath) { + const normalized = entryPath.replace(/\\/g, '/'); + if (!normalized.startsWith(ARCHIVE_ROOT)) return null; + const relative = normalized.slice(ARCHIVE_ROOT.length); + if (!relative) return null; + + const segments = []; + for (const segment of relative.split('/')) { + if (!segment || segment === '.') continue; + if (segment === '..') return null; + segments.push(segment); + } + if (!segments.length) return null; + return '/' + segments.join('/'); +} + +/* + * 在独立 worker 中打开一层压缩包并流式吐出条目; + * 返回其中根级嵌套压缩包(下一层包装)的原始字节。 + */ +function extractLayer(file, onEntry) { + return new Promise((resolve, reject) => { + const worker = new Worker(WORKER_URL); + const nested = []; + let settled = false; + + const finish = (error) => { + if (settled) return; + settled = true; + worker.terminate(); + if (error) reject(error); + else resolve(nested); + }; + + worker.addEventListener('error', (event) => { + finish(new Error(event.message || 'libarchive worker failed')); + }); + + worker.addEventListener('message', ({ data }) => { + if (data.type === 'ERROR') { + finish(new Error(data.error && data.error.message ? data.error.message : 'libarchive failed')); + return; + } + if (data.type === 'READY') { + worker.postMessage({ type: 'OPEN', file }); + return; + } + if (data.type === 'OPENED') { + worker.postMessage({ type: 'EXTRACT_FILES' }); + return; + } + if (data.type === 'END') { + finish(null); + return; + } + if (data.type !== 'ENTRY') return; + + const entry = data.entry; + if (entry.type !== 'FILE' || !entry.fileData) return; + + // 根级压缩包是下一层包装,不是站点内容 + if (entry.path.replace(/\\/g, '/') === 'MayxBlog.7z') { + nested.push(entry.fileData); + return; + } + onEntry(entry); + }); + }); +} + +/* 几十 MB 的缓存是浏览器常见的回收对象,而重新解包代价高,尽量申请持久存储。 */ +async function requestPersistence() { + if (!navigator.storage || !navigator.storage.persist) return false; + try { + if (await navigator.storage.persisted()) return true; + return await navigator.storage.persist(); + } catch { + return false; + } +} + +/* 读取就绪标记(= 离线模式状态);损坏或缺清单的标记视为不存在。 */ +export async function readStatus() { + const cache = await caches.open(CACHE_NAME); + const hit = await cache.match(READY_KEY); + if (!hit) return null; + const meta = await hit.json().catch(() => null); + if (!meta || !Array.isArray(meta.keys) || !meta.keys.length) return null; + return meta; +} + +/* + * 线上压缩包的大小即版本号。HEAD 不被 SW 拦截,拿到的一定是线上真实值; + * 网络失败返回 null,调用方选择信任现有缓存而不是误伤。 + */ +async function payloadSize() { + try { + const response = await fetch(ARCHIVE_URL, { method: 'HEAD', cache: 'no-store' }); + if (!response.ok) return null; + const size = Number(response.headers.get('content-length')); + return Number.isFinite(size) && size > 0 ? size : null; + } catch { + return null; + } +} + +/* + * 控制页打开时调用:未启用 → {ready:false};已启用且版本一致 → {ready:true, meta}; + * 版本不一致 → 清空缓存并返回 {ready:false, stale:true}(已回退在线模式)。 + */ +export async function ensureFresh() { + const cache = await caches.open(CACHE_NAME); + const size = await payloadSize(); + const meta = await readStatus(); + + if (!meta) return { ready: false, size, stale: false }; + if (size && meta.payloadSize !== size) { + await caches.delete(CACHE_NAME); + return { ready: false, size, stale: true }; + } + return { ready: true, size, stale: false, meta }; +} + +/* + * 启用离线模式:注册 SW → 清空旧缓存(同时清掉上次中断的残留,保证随后 + * 的压缩包下载不会被旧缓存喂旧的 quine 副本)→ 下载并逐层解包 → 写标记。 + */ +export async function activateOffline({ onProgress } = {}) { + if (!('serviceWorker' in navigator)) { + throw new Error('当前浏览器不支持 Service Worker,无法启用离线模式。'); + } + await navigator.serviceWorker.register('/sw.js', { scope: '/' }); + await navigator.serviceWorker.ready; + await caches.delete(CACHE_NAME); + + const persisted = await requestPersistence(); + + // 写操作串行链,保证按到达顺序落盘且不产生无界并发 + const cache = await caches.open(CACHE_NAME); + let writes = Promise.resolve(); + const keys = new Set(); + let files = 0; + let bytes = 0; + let skipped = 0; + + const response = await fetch(ARCHIVE_URL, { cache: 'no-store' }); + if (!response.ok) throw new Error(`无法下载站点压缩包:HTTP ${response.status}`); + const outer = await response.arrayBuffer(); + const downloadedBytes = outer.byteLength; + + let layer = [outer]; + while (layer.length) { + const bytesThisLayer = layer.shift(); + const file = new File([bytesThisLayer], 'MayxBlog.7z'); + + layer = await extractLayer(file, (entry) => { + const key = sitePathFor(entry.path); + if (!key) { + skipped += 1; + return; + } + const body = entry.fileData; + files += 1; + bytes += body.byteLength; + + writes = writes.then(async () => { + await cache.put(key, new Response(body, { + status: 200, + headers: { 'Content-Type': mimeFor(key) }, + })); + keys.add(key); + }); + + if (onProgress) onProgress({ done: false, files, bytes, skipped }); + }); + } + + await writes; + + const meta = { + files, + bytes, + skipped, + persisted, + payloadSize: downloadedBytes, + failed: files - keys.size, + keys: [...keys], + unpackedAt: new Date().toISOString(), + }; + await cache.put( + READY_KEY, + new Response(JSON.stringify(meta), { + headers: { 'Content-Type': 'application/json; charset=utf-8' }, + }) + ); + + if (onProgress) onProgress({ done: true, cached: false, ...meta }); + return meta; +} + +/* 切回在线模式:删掉缓存(含标记),SW 随即恢复纯转发。返回之前是否处于离线模式。 */ +export async function deactivateOffline() { + const had = await readStatus(); + await caches.delete(CACHE_NAME); + return Boolean(had); +} diff --git a/offline.md b/offline.md new file mode 100644 index 0000000..f571a9f --- /dev/null +++ b/offline.md @@ -0,0 +1,37 @@ +--- +layout: default +title: 离线模式 +--- + +# 离线模式 + +本页用于管理本博客的离线阅读功能: + +- **启用离线模式**:浏览器会下载整站压缩包(`MayxBlog.7z`)并解包到本地缓存,之后即使没有网络也能正常浏览博客; +- **自动回退**:当站点压缩包更新(博客重新部署)时,离线缓存会自动失效并回退到在线模式,下次重新启用即可获取最新内容; +- **手动切换**:离线模式下可以随时在本页切回在线模式,切回后页面将重新通过网络加载。 + + + + + + + + + +
    当前状态检测中…
    缓存版本-
    文件统计-
    解包时间-
    持久存储-
    + + + +

    + +

    + + +

    + + diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..106a0f1 --- /dev/null +++ b/sw.js @@ -0,0 +1,140 @@ +/* + * Mayx的博客 · 离线模式 Service Worker + * + * 两种模式(由 Cache Storage 中是否存在就绪标记决定): + * - 在线模式(默认,无标记):所有请求原样转发网络,SW 形同虚设。 + * - 离线模式(/offline.html 启用后写入标记):同源 GET 请求缓存优先, + * 缓存未命中且清单里没有的路径才回源网络,实现断网阅读。 + * + * 版本控制:压缩包 /MayxBlog.7z 的 content-length 即版本号(每次重新部署 + * 都会变化)。SW 激活时、以及导航请求按 RECHECK_INTERVAL 节流复核; + * 一旦发现线上压缩包与已缓存版本不一致,立即清空缓存 → 自动回退在线模式。 + * 网络不可用时复核失败,保留缓存(离线阅读本来就是离线模式的目的)。 + */ + +const CACHE_NAME = 'mayxblog-offline-v1'; +const READY_KEY = '/__offline_manifest__'; +const ARCHIVE_URL = '/MayxBlog.7z'; +const RECHECK_INTERVAL = 5 * 60 * 1000; + +let lastRecheck = 0; + +self.addEventListener('install', () => { + self.skipWaiting(); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys() + .then((keys) => + Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))) + ) + .then(verifyPayloadVersion) + .then(() => self.clients.claim()) + ); +}); + +/* + * HEAD 请求不被下面的 fetch 处理器拦截,这里读到的一定是线上真实压缩包, + * 而不是缓存里的 quine 副本。网络失败返回 null,调用方选择信任现有缓存。 + */ +async function payloadSize() { + try { + const response = await fetch(ARCHIVE_URL, { method: 'HEAD', cache: 'no-store' }); + if (!response.ok) return null; + const size = Number(response.headers.get('content-length')); + return Number.isFinite(size) && size > 0 ? size : null; + } catch { + return null; + } +} + +/* + * 就绪标记同时是清单:记录了解包写入的所有路径。没有它就无法区分 + * “站点本来就没有这个页面”和“缓存条目被浏览器回收了”。 + */ +async function readManifest(cache) { + const hit = await cache.match(READY_KEY); + if (!hit) return null; + const meta = await hit.json().catch(() => null); + if (!meta || !Array.isArray(meta.keys) || !meta.keys.length) return null; + return meta; +} + +/* 压缩包更新 → 清空缓存(即回退在线模式);返回是否发生了失效。 */ +async function verifyPayloadVersion() { + const cache = await caches.open(CACHE_NAME); + const meta = await readManifest(cache); + if (!meta) return false; + const size = await payloadSize(); + if (size && meta.payloadSize !== size) { + await caches.delete(CACHE_NAME); + return true; + } + return false; +} + +/* 服务器对目录索引的处理与 Jekyll 产物一致,这里补齐候选路径。 */ +function candidatesFor(pathname) { + const keys = [pathname]; + if (pathname.endsWith('/')) { + keys.push(pathname + 'index.html'); + } else { + keys.push(pathname + '/index.html'); + keys.push(pathname + '.html'); + } + return keys; +} + +self.addEventListener('fetch', (event) => { + const request = event.request; + if (request.method !== 'GET') return; // HEAD 等直通网络(版本探测依赖这一点) + + const url = new URL(request.url); + if (url.origin !== self.location.origin) return; // 跨域请求不干预 + + // 显式 no-store 的请求(重新下载压缩包等)绕过缓存,避免吃到旧的 quine 副本 + if (request.cache === 'no-store') return; + + event.respondWith(respond(request, url, event)); +}); + +async function respond(request, url, event) { + const cache = await caches.open(CACHE_NAME); + + // 导航请求顺带做节流版本复核;失效发生在后台,本次响应不受影响, + // 下一次请求自然落入在线模式。 + if (request.mode === 'navigate' && Date.now() - lastRecheck > RECHECK_INTERVAL) { + lastRecheck = Date.now(); + event.waitUntil(verifyPayloadVersion()); + } + + const candidates = candidatesFor(url.pathname); + for (const key of candidates) { + const hit = await cache.match(key); + if (hit) return hit; + } + + const meta = await readManifest(cache); + if (!meta) return fetch(request); // 在线模式:纯转发 + + // 清单承诺过这个路径但缓存里没有 → 条目被浏览器回收,缓存已不可信, + // 整体作废并回退在线模式。 + if (candidates.some((key) => meta.keys.includes(key))) { + await caches.delete(CACHE_NAME); + return fetch(request); + } + + // 清单之外的路径回源网络;断网时的导航请求用站点 404 页兜底。 + try { + return await fetch(request); + } catch (error) { + if (request.mode === 'navigate') { + const notFound = await cache.match('/404.html'); + if (notFound) { + return new Response(notFound.body, { status: 404, headers: notFound.headers }); + } + } + throw error; + } +} diff --git a/vendor/libarchive/LICENSE b/vendor/libarchive/LICENSE new file mode 100644 index 0000000..d7e8a1d --- /dev/null +++ b/vendor/libarchive/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 ნიკა + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/libarchive/wasm-gen/libarchive.js b/vendor/libarchive/wasm-gen/libarchive.js new file mode 100644 index 0000000..6adea82 --- /dev/null +++ b/vendor/libarchive/wasm-gen/libarchive.js @@ -0,0 +1,15 @@ + +var libarchive = (function() { + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + return ( +function(libarchive) { + libarchive = libarchive || {}; + +var Module=typeof libarchive!=="undefined"?libarchive:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=function(status,toThrow){throw toThrow};Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}else{return scriptDirectory+path}}if(ENVIRONMENT_IS_NODE){scriptDirectory=__dirname+"/";var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename);return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);Module["quit"]=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){return read(f)}}Module["readBinary"]=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=function(status){quit(status)}}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=function(title){document.title=title}}else{}var out=Module["print"]||(typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null);var err=Module["printErr"]||(typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||out);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;function dynamicAlloc(size){var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;if(end<=_emscripten_get_heap_size()){HEAP32[DYNAMICTOP_PTR>>2]=end}else{var success=_emscripten_resize_heap(end);if(!success)return 0}return ret}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0,"getNativeTypeSize invalid bits "+bits+", type "+type);return bits/8}else{return 0}}}}var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){debugger}};var functionPointers=new Array(0);var tempRet0=0;var setTempRet0=function(value){tempRet0=value};if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable;var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var ALLOC_NORMAL=0;var ALLOC_NONE=3;function allocate(slab,types,allocator,ptr){var zeroinit,size;if(typeof slab==="number"){zeroinit=true;size=slab}else{zeroinit=false;size=slab.length}var singleType=typeof types==="string"?types:null;var ret;if(allocator==ALLOC_NONE){ret=ptr}else{ret=[_malloc,stackAlloc,dynamicAlloc][allocator](Math.max(size,singleType?1:types.length))}if(zeroinit){var stop;ptr=ret;assert((ret&3)==0);stop=ret+(size&~3);for(;ptr>2]=0}stop=ret+size;while(ptr>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[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=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 writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}function demangle(func){return func}function demangleAll(text){var regex=/__Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error(0)}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var DYNAMIC_BASE=5520464,DYNAMICTOP_PTR=277552;var TOTAL_STACK=5242880;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(INITIAL_TOTAL_MEMORY>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;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 ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();PIPEFS.root=FS.mount(PIPEFS,{},null);callRuntimeCallbacks(__ATINIT__)}function preMain(){FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){runtimeExited=true}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 addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}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"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="libarchive.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(Module["wasmBinary"]){return new Uint8Array(Module["wasmBinary"])}if(Module["readBinary"]){return Module["readBinary"](wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!Module["wasmBinary"]&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&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()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(env){var info={"env":env,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}if(!Module["wasmBinary"]&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){WebAssembly.instantiateStreaming(fetch(wasmBinaryFile,{credentials:"same-origin"}),info).then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})}else{instantiateArrayBuffer(receiveInstantiatedSource)}return{}}Module["asm"]=function(global,env,providedBuffer){env["memory"]=wasmMemory;env["table"]=wasmTable=new WebAssembly.Table({"initial":507,"maximum":507,"element":"anyfunc"});env["__memory_base"]=1024;env["__table_base"]=0;var exports=createWasm(env);return exports};__ATINIT__.push({func:function(){___emscripten_environ_constructor()}});var ENV={};function ___buildEnvironment(environ){var MAX_ENV_VALUES=64;var TOTAL_ENV_SIZE=1024;var poolPtr;var envPtr;if(!___buildEnvironment.called){___buildEnvironment.called=true;ENV["USER"]=ENV["LOGNAME"]="web_user";ENV["PATH"]="/";ENV["PWD"]="/";ENV["HOME"]="/home/web_user";ENV["LANG"]="C.UTF-8";ENV["_"]=Module["thisProgram"];poolPtr=getMemory(TOTAL_ENV_SIZE);envPtr=getMemory(MAX_ENV_VALUES*4);HEAP32[envPtr>>2]=poolPtr;HEAP32[environ>>2]=envPtr}else{envPtr=HEAP32[environ>>2];poolPtr=HEAP32[envPtr>>2]}var strings=[];var totalSize=0;for(var key in ENV){if(typeof ENV[key]==="string"){var line=key+"="+ENV[key];strings.push(line);totalSize+=line.length}}if(totalSize>TOTAL_ENV_SIZE){throw new Error("Environment size exceeded TOTAL_ENV_SIZE!")}var ptrSize=4;for(var i=0;i>2]=poolPtr;poolPtr+=line.length+1}HEAP32[envPtr+strings.length*ptrSize>>2]=0}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(from,to){from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(1)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(new ArrayBuffer(newSize));if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+lengthe2.timestamp){create.push(key);total++}});var remove=[];Object.keys(dst.entries).forEach(function(key){var e=dst.entries[key];var e2=src.entries[key];if(!e2){remove.push(key);total++}});if(!total){return callback(null)}var errored=false;var completed=0;var db=src.type==="remote"?src.db:dst.db;var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readwrite");var store=transaction.objectStore(IDBFS.DB_STORE_NAME);function done(err){if(err){if(!done.errored){done.errored=true;return callback(err)}return}if(++completed>=total){return callback(null)}}transaction.onerror=function(e){done(this.error);e.preventDefault()};create.sort().forEach(function(path){if(dst.type==="local"){IDBFS.loadRemoteEntry(store,path,function(err,entry){if(err)return done(err);IDBFS.storeLocalEntry(path,entry,done)})}else{IDBFS.loadLocalEntry(path,function(err,entry){if(err)return done(err);IDBFS.storeRemoteEntry(store,path,entry,done)})}});remove.sort().reverse().forEach(function(path){if(dst.type==="local"){IDBFS.removeLocalEntry(path,done)}else{IDBFS.removeRemoteEntry(store,path,done)}})}};var NODEFS={isWindows:false,staticInit:function(){NODEFS.isWindows=!!process.platform.match(/^win/);var flags=process["binding"]("constants");if(flags["fs"]){flags=flags["fs"]}NODEFS.flagsForNodeMap={1024:flags["O_APPEND"],64:flags["O_CREAT"],128:flags["O_EXCL"],0:flags["O_RDONLY"],2:flags["O_RDWR"],4096:flags["O_SYNC"],512:flags["O_TRUNC"],1:flags["O_WRONLY"]}},bufferFrom:function(arrayBuffer){return Buffer.alloc?Buffer.from(arrayBuffer):new Buffer(arrayBuffer)},mount:function(mount){assert(ENVIRONMENT_IS_NODE);return NODEFS.createNode(null,"/",NODEFS.getMode(mount.opts.root),0)},createNode:function(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(22)}var node=FS.createNode(parent,name,mode);node.node_ops=NODEFS.node_ops;node.stream_ops=NODEFS.stream_ops;return node},getMode:function(path){var stat;try{stat=fs.lstatSync(path);if(NODEFS.isWindows){stat.mode=stat.mode|(stat.mode&292)>>2}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(-e.errno)}return stat.mode},realPath:function(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join.apply(null,parts)},flagsForNode:function(flags){flags&=~2097152;flags&=~2048;flags&=~32768;flags&=~524288;var newFlags=0;for(var k in NODEFS.flagsForNodeMap){if(flags&k){newFlags|=NODEFS.flagsForNodeMap[k];flags^=k}}if(!flags){return newFlags}else{throw new FS.ErrnoError(22)}},node_ops:{getattr:function(node){var path=NODEFS.realPath(node);var stat;try{stat=fs.lstatSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(-e.errno)}if(NODEFS.isWindows&&!stat.blksize){stat.blksize=4096}if(NODEFS.isWindows&&!stat.blocks){stat.blocks=(stat.size+stat.blksize-1)/stat.blksize|0}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr:function(node,attr){var path=NODEFS.realPath(node);try{if(attr.mode!==undefined){fs.chmodSync(path,attr.mode);node.mode=attr.mode}if(attr.timestamp!==undefined){var date=new Date(attr.timestamp);fs.utimesSync(path,date,date)}if(attr.size!==undefined){fs.truncateSync(path,attr.size)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(-e.errno)}},lookup:function(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);var mode=NODEFS.getMode(path);return NODEFS.createNode(parent,name,mode)},mknod:function(parent,name,mode,dev){var node=N