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
This commit is contained in:
mayx
2026-10-03 07:57:00 +00:00
parent 7659d3e9d5
commit 8cb782d1ff
12 changed files with 610 additions and 5 deletions

View File

@@ -17,7 +17,6 @@ mirrors:
- https://mayx.vercel.app/ - https://mayx.vercel.app/
- https://mayx.netlify.app/ - https://mayx.netlify.app/
- https://mayx.gitnet.page/ - https://mayx.gitnet.page/
- https://mayx.stormkit.dev/
- https://mayx.grebedoc.dev/ - https://mayx.grebedoc.dev/
- https://mayx.codeberg.page/ - https://mayx.codeberg.page/
- https://mayx.tildepages.org/ - https://mayx.tildepages.org/

View File

@@ -98,7 +98,8 @@ layout: xslt_container
<li><a href="{{ site.github.tar_url }}">Download <strong>TAR Ball</strong></a></li> <li><a href="{{ site.github.tar_url }}">Download <strong>TAR Ball</strong></a></li>
<li><a href="{{ site.github.repository_url }}">View On <strong>GitHub</strong></a></li> <li><a href="{{ site.github.repository_url }}">View On <strong>GitHub</strong></a></li>
{% else %} {% else %}
<li style="width: 270px; border-right: none;"><a href="/MayxBlog.7z">Download <strong>7-Zip File</strong></a></li> <li style="width: 174px;"><a href="/MayxBlog.7z">Download <strong>7-Zip File</strong></a></li>
<li style="width: 174px;"><a href="/offline.html">Manage <strong>Offline Mode</strong></a></li>
{% endif %} {% endif %}
</ul> </ul>
</header> </header>

View File

@@ -7,7 +7,8 @@ mkdir Mabbs
curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md
bundle exec jekyll build -d ../public_html bundle exec jekyll build -d ../public_html
python3 _tools/blogquine.py --src-dir blog --quine-dir blog ../public_html/ MayxBlog.7z 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/ cd ../public_html/
unset GIT_DIR unset GIT_DIR
git init git init
@@ -18,6 +19,6 @@ git branch pages
git remote add codeberg ssh://git@codeberg.org/mayx/pages.git 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 remote add bitbucket ssh://git@bitbucket.org/unmayx/unmayx.bitbucket.io.git
git push -f codeberg main git push -f codeberg main
git push -f codeberg pages git push -f codeberg pages
git push -f bitbucket main git push -f bitbucket main
/home/mayx/blog-env/node_modules/surge/bin/surge /home/mayx/public_html/ mayx.surge.sh /home/mayx/blog-env/node_modules/surge/bin/surge /home/mayx/public_html/ mayx.surge.sh

View File

@@ -7,13 +7,15 @@ mkdir Mabbs
curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md 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/ 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 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/ 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/ cd ../domains/mayx.serv00.net/public_html/
unset GIT_DIR unset GIT_DIR
git init git init
git lfs install git lfs install
git lfs track "*.png" git lfs track "*.png"
git lfs track "*.webp"
git lfs track "*.moc" git lfs track "*.moc"
git lfs track "*.tgz" git lfs track "*.tgz"
git lfs track "*.jpg" git lfs track "*.jpg"

119
assets/js/offline-page.js Normal file
View File

@@ -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();
})();

269
assets/js/offline-unpack.js Normal file
View File

@@ -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);
}

37
offline.md Normal file
View File

@@ -0,0 +1,37 @@
---
layout: default
title: 离线模式
---
# 离线模式
本页用于管理本博客的离线阅读功能:
- **启用离线模式**:浏览器会下载整站压缩包(`MayxBlog.7z`)并解包到本地缓存,之后即使没有网络也能正常浏览博客;
- **自动回退**:当站点压缩包更新(博客重新部署)时,离线缓存会自动失效并回退到在线模式,下次重新启用即可获取最新内容;
- **手动切换**:离线模式下可以随时在本页切回在线模式,切回后页面将重新通过网络加载。
<table>
<tbody>
<tr><th>当前状态</th><td id="offline-state">检测中…</td></tr>
<tr><th>缓存版本</th><td id="offline-version">-</td></tr>
<tr><th>文件统计</th><td id="offline-files">-</td></tr>
<tr><th>解包时间</th><td id="offline-time">-</td></tr>
<tr><th>持久存储</th><td id="offline-persist">-</td></tr>
</tbody>
</table>
<p id="offline-progress-box" hidden="hidden">
<progress id="offline-progress" max="100" value="0"></progress>
<small id="offline-progress-text">准备中…</small>
</p>
<p><strong id="offline-message"></strong></p>
<p>
<button type="button" id="offline-enable">启用离线模式</button>
<button type="button" id="offline-disable">切换回在线模式</button>
</p>
<script src="/assets/js/offline-page.js"></script>

140
sw.js Normal file
View File

@@ -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;
}
}

21
vendor/libarchive/LICENSE vendored Normal file
View File

@@ -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.

File diff suppressed because one or more lines are too long

Binary file not shown.

1
vendor/libarchive/worker-bundle.js vendored Normal file

File diff suppressed because one or more lines are too long