☰

EhHyperlink

受 TranslatedJump 启发的 E-Hentai / ExHentai 画廊关联脚本:除了其他语言版本,也找同系列、原刊杂志与收录作品,并用 Google、DuckDuckGo、DLsite、pixiv 搜索来源

当前为 2026-10-25 提交的版本,查看 最新版本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴、Greasemonkey 油猴子 或 Violentmonkey 暴力猴,才能安装此脚本。

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴 或 Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴 或 Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name               EhHyperlink
// @namespace          https://github.com/Tsuyumi25/EhHyperlink
// @version            0.2.0
// @author             tsuyumi
// @description        Inspired by TranslatedJump: besides other language editions, also finds the series, source magazine and chapters of an E-Hentai / ExHentai gallery, and searches Google, DuckDuckGo, DLsite and pixiv for its source
// @description:zh-TW  受 TranslatedJump 啟發的 E-Hentai / ExHentai 畫廊關聯腳本:除了其他語言版本,也找同系列、原刊雜誌與收錄作品,並用 Google、DuckDuckGo、DLsite、pixiv 找來源
// @description:zh-CN  受 TranslatedJump 启发的 E-Hentai / ExHentai 画廊关联脚本:除了其他语言版本,也找同系列、原刊杂志与收录作品,并用 Google、DuckDuckGo、DLsite、pixiv 搜索来源
// @description:ja     TranslatedJump に着想を得た E-Hentai / ExHentai ギャラリー関連スクリプト:他言語版に加え、同シリーズ・掲載誌・収録作品も探し、Google・DuckDuckGo・DLsite・pixiv で出典を検索
// @description:ko     TranslatedJump에서 영감을 받은 E-Hentai / ExHentai 갤러리 연결 스크립트: 다른 언어판뿐 아니라 같은 시리즈, 원본 잡지와 수록작도 찾고, Google·DuckDuckGo·DLsite·pixiv로 출처를 검색
// @license            MIT
// @icon               https://e-hentai.org/favicon.ico
// @homepageURL        https://github.com/Tsuyumi25/EhHyperlink
// @supportURL         https://github.com/Tsuyumi25/EhHyperlink/issues
// @include            /^https:\/\/www\.google\.[a-z.]+\/search/
// @include            /^https:\/\/www\.pixiv\.net\/(en\/)?search/
// @match              https://exhentai.org/g/*
// @match              https://e-hentai.org/g/*
// @match              https://www.dlsite.com/*/fsr/*
// @match              https://html.duckduckgo.com/html/*
// @connect            i.pximg.net
// @connect            self
// @grant              GM.deleteValue
// @grant              GM.getValue
// @grant              GM.listValues
// @grant              GM.setValue
// @grant              GM_addStyle
// @grant              GM_addValueChangeListener
// @grant              GM_openInTab
// @grant              GM_removeValueChangeListener
// @grant              GM_xmlhttpRequest
// @run-at             document-end
// ==/UserScript==

(async function() {
	"use strict";
	var s = new Set();
	var _css = async (t) => {
		if (s.has(t)) return;
		s.add(t);
		((c) => {
			if (typeof GM_addStyle === "function") GM_addStyle(c);
			else (document.head || document.documentElement).appendChild(document.createElement("style")).append(c);
		})(t);
	};
	_css(" .ehl-settings{top:100%;right:var(--ehl-inset,0);box-sizing:border-box;text-align:left;background:var(--ehl-bg,#fff);border:1px solid var(--ehl-border,currentColor);z-index:21;border-radius:0 0 9px 9px;width:300px;max-width:calc(100vw - 20px);margin:0;padding:4px 12px 10px;font-size:12px;font-weight:400;line-height:1.4;position:absolute;box-shadow:0 6px 18px #00000038}.ehl-settings__group+.ehl-settings__group{border-top:1px solid color-mix(in srgb, currentColor 15%, transparent)}.ehl-settings__heading{letter-spacing:.06em;text-transform:uppercase;opacity:.55;margin:8px 0 2px;padding:0;font-size:10px;font-weight:700}.ehl-settings__row{justify-content:space-between;align-items:center;gap:12px;min-height:28px;display:flex}.ehl-settings__row--toggle{cursor:pointer}.ehl-settings__label{flex:1;min-width:0}.ehl-settings__segments{background:color-mix(in srgb, currentColor 8%, transparent);border-radius:6px;flex:none;padding:2px;display:inline-flex}.ehl-settings__segment{cursor:pointer;position:relative}.ehl-settings__segment input{opacity:0;pointer-events:none;position:absolute}.ehl-settings__segment span{opacity:.65;white-space:nowrap;border-radius:4px;padding:2px 9px;display:block}.ehl-settings__segment:hover span{opacity:1}.ehl-settings__segment input:checked+span{background:var(--ehl-bg,#fff);opacity:1;font-weight:700;box-shadow:0 1px 2px #0000002e}.ehl-settings__segment input:focus-visible+span{outline:2px solid color-mix(in srgb, currentColor 45%, transparent);outline-offset:1px}.ehl-settings__switch{width:28px;height:16px;color:inherit;background:color-mix(in srgb, currentColor 20%, transparent);cursor:pointer;appearance:none;border:0;border-radius:8px;flex:none;margin:0;padding:0;transition:background .15s;position:relative}.ehl-settings__switch:before{background:var(--ehl-bg,#fff);content:\"\";border-radius:50%;width:12px;height:12px;transition:transform .15s;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #00000040}.ehl-settings__switch:checked{background:currentColor}.ehl-settings__switch:checked:before{transform:translate(12px)}.ehl-settings__switch:focus-visible{outline:2px solid color-mix(in srgb, currentColor 45%, transparent);outline-offset:2px}.ehl-settings__stepper{border:1px solid color-mix(in srgb, currentColor 30%, transparent);border-radius:6px;flex:none;align-items:center;display:inline-flex}.ehl-settings__stepper button{width:22px;height:20px;color:inherit;cursor:pointer;opacity:.7;background:0 0;border:0;justify-content:center;align-items:center;margin:0;padding:0;display:inline-flex}.ehl-settings__stepper button:hover:not(:disabled){opacity:1}.ehl-settings__stepper button:disabled{cursor:default;opacity:.25}.ehl-settings__stepper output{text-align:center;font-variant-numeric:tabular-nums;min-width:2ch;font-weight:700}.ehl-settings__help{color:inherit;vertical-align:-2px;cursor:pointer;opacity:.5;background:0 0;border:0;border-radius:50%;margin:0 0 0 2px;padding:1px;display:inline-flex}.ehl-settings__help:hover,.ehl-settings__help--open{opacity:1}.ehl-settings__language{padding-top:6px}.ehl-settings__language .ehl-settings__label{align-items:center;gap:4px;display:inline-flex}.ehl-settings__select{height:22px;font:inherit;color:inherit;background:var(--ehl-bg,#fff);border:1px solid color-mix(in srgb, currentColor 30%, transparent);cursor:pointer;border-radius:6px;margin:0;padding:0 4px}.ehl-settings__note{background:color-mix(in srgb, currentColor 6%, transparent);border-radius:6px;margin:2px 0 4px;padding:6px 8px;font-size:11px}.ehl-settings__note p{opacity:.85;margin:0;padding:0}.ehl-settings__note p+p{margin-top:4px}.ehl-settings__links{gap:10px;display:flex}.ehl-settings__links a{text-underline-offset:2px;text-decoration:underline}.ehl-debug__actions{gap:6px;display:flex}.ehl-debug__actions .ehl-pages__more{margin:0}.ehl-debug__request{margin-top:8px}.ehl-debug__id{margin:0 0 2px;font-size:11px}.ehl-debug table{border-collapse:collapse;font-family:monospace;font-size:11px}.ehl-debug td{vertical-align:top;padding:0 8px 0 0}.ehl-debug__time{text-align:right;white-space:nowrap;opacity:.7}.ehl-debug__where{white-space:nowrap;opacity:.7}.ehl-debug__event{white-space:nowrap;font-weight:700}.ehl-debug__detail{word-break:break-all}.ehl-result-thumb{aspect-ratio:1;background:color-mix(in srgb, currentColor 8%, transparent);border-radius:4px;overflow:hidden}.ehl-result-thumb img{object-fit:cover;width:100%;height:100%;display:block}.ehl-mark{color:inherit;background:color-mix(in srgb, currentColor 16%, transparent);border-radius:2px;padding:0 1px;font-weight:700}.ehl-pages__page-head{opacity:.7;margin:6px 0 0;font-size:11px;font-weight:700}.ehl-pages__spin{animation:1s linear infinite ehl-pages-spin}@keyframes ehl-pages-spin{to{transform:rotate(360deg)}}.ehl-pages__note{opacity:.7;margin:4px 0 0}.ehl-pages__results{margin:4px 0 0;padding:0;list-style:none}.ehl-pages__results>li{flex-direction:column;padding:3px 0;display:flex}.ehl-pages__results>li+li{border-top:1px dashed color-mix(in srgb, currentColor 25%, transparent)}.ehl-pages__results a{font-weight:700;text-decoration:none}.ehl-pages__results>li{position:relative}.ehl-pages__results>li:hover>.ehl-copy{opacity:.8}.ehl-pages__results>li>.ehl-copy{z-index:1}.ehl-pages__results--list>li>.ehl-copy,.ehl-pages__results--rows>li>.ehl-copy{aspect-ratio:1;width:auto;height:auto;top:4px;bottom:4px;right:4px}.ehl-pages__text{flex-direction:column;min-width:0;display:flex}.ehl-pages__results--grid{grid-template-columns:repeat(auto-fill,104px);gap:8px;display:grid}.ehl-pages__results--grid>li{gap:2px;padding:0;font-size:11px}.ehl-pages__results--grid>li+li{border-top:0}.ehl-pages__results--grid .ehl-pages__title{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.ehl-pages__results--rows>li{flex-direction:row;align-items:center;gap:10px;padding:6px 0}.ehl-pages__results--rows .ehl-pages__thumb{flex:0 0 48px}.ehl-pages__results--rows .ehl-pages__thumb .ehl-result-thumb{border-radius:50%}.ehl-pages__results--rows .ehl-pages__text{flex:0 0 140px}.ehl-pages__works{gap:4px;margin:0;padding:0;list-style:none;display:flex}.ehl-pages__works li{flex:0 0 72px}.ehl-pages__byline{opacity:.7;font-size:8pt}.ehl-pages__snippet{opacity:.85;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:8pt;display:-webkit-box;overflow:hidden}.ehl-pages__more{font:inherit;color:inherit;cursor:pointer;opacity:.7;background:0 0;border:1px solid;border-radius:3px;align-items:center;gap:3px;margin:6px 0 0;padding:0 6px;font-size:11px;display:inline-flex}.ehl-pages__more:hover{opacity:1}.ehl-pages__more:disabled{cursor:default}.ehl-search{box-sizing:border-box;text-align:left;background:var(--ehl-bg,#fff);border:1px solid var(--ehl-border,currentColor);border-radius:9px;grid-template-columns:150px minmax(0,1fr);min-height:330px;font-size:12px;font-weight:400;display:grid}.ehl-search__nav{border-right:1px solid var(--ehl-border,currentColor);flex-direction:column;gap:2px;padding:8px 6px;display:flex}.ehl-search__site-tab{font:inherit;color:inherit;text-align:left;cursor:pointer;opacity:.7;background:0 0;border:0;border-radius:5px;align-items:center;gap:2px;margin:0;padding:5px 6px;font-weight:700;display:flex}.ehl-search__site-tab:hover{opacity:1}.ehl-search__site-tab--selected{opacity:1;background:color-mix(in srgb, currentColor 12%, transparent)}.ehl-search__site-name{flex:1}.ehl-search__count{opacity:.7;font-size:10px}.ehl-search__close{color:inherit;cursor:pointer;opacity:.7;background:0 0;border:0;align-self:flex-start;margin:auto 0 0;padding:4px 6px;display:inline-flex}.ehl-search__close:hover{opacity:1}.ehl-search__content{min-width:0;padding:8px 12px 12px}.ehl-search__search{flex-wrap:wrap;align-items:baseline;column-gap:10px;display:flex}.ehl-search__search>.ehl-pages{display:contents}.ehl-search__search .ehl-pages__page{flex:1 0 100%;min-width:0}.ehl-search__search .ehl-pages__page--note{flex:0 auto}.ehl-search__search .ehl-pages__page--note .ehl-pages__note{margin:0}.ehl-search__search+.ehl-search__search{border-top:1px dashed var(--ehl-border,currentColor);margin-top:10px;padding-top:8px}.ehl-search__query{font-size:13px;font-weight:700;text-decoration:none}.ehl-search__kind{opacity:.7;border:1px solid;border-radius:3px;margin-right:6px;padding:0 4px;font-size:10px;font-weight:700;display:inline-block}#ehl-app{box-sizing:border-box;min-width:720px;max-width:1200px;margin:10px auto 0}#ehl-app+.gm{margin-top:0}@media screen and (width<=1230px){#ehl-app{max-width:960px}}@media screen and (width<=990px){#ehl-app{max-width:720px}}.ehl-box{--ehl-inset:9px;padding:0 var(--ehl-inset);text-align:left;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:end;column-gap:8px;font-size:12px;font-weight:700;display:grid;position:relative}.ehl-tabs{box-sizing:border-box;background:var(--ehl-bg,#fff);border:1px solid var(--ehl-border,currentColor);border-bottom:0;border-radius:9px 9px 0 0;align-items:stretch;min-width:0;max-width:100%;display:flex}.ehl-tabs--start{grid-column:1;justify-self:start}.ehl-tabs--center{grid-column:2}.ehl-tabs--end{grid-column:3;justify-self:end}.ehl-status{opacity:.7;white-space:nowrap;text-overflow:ellipsis;min-width:0;padding:0 8px;line-height:22px;overflow:hidden}.ehl-unit{display:flex}.ehl-badge,.ehl-icon{height:22px;font:inherit;color:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;align-items:center;margin:0;line-height:1;display:flex}.ehl-tabs>:not(:first-child)>.ehl-badge,.ehl-tabs>:not(:first-child)>.ehl-icon,.ehl-tabs>:not(:first-child).ehl-status{border-left:1px solid var(--ehl-border,currentColor)}.ehl-badge{letter-spacing:.04em;gap:4px;padding:0 8px;font-size:11px}.ehl-icon{opacity:.6;padding:0 6px}.ehl-icon:hover,.ehl-icon--active{opacity:1}.ehl-tab--pinned{opacity:1;box-shadow:inset 0 -2px}.ehl-list{--ehl-cover-h:10em;white-space:nowrap;background:var(--ehl-bg,#fff);border:1px solid var(--ehl-border,currentColor);z-index:20;border-radius:0 0 9px 9px;width:max-content;margin:0 auto;padding:4px 10px 8px;display:none;position:absolute;top:100%;left:0;right:0;box-shadow:0 3px 8px #00000040}.ehl-unit--open .ehl-list{display:block}.ehl-tabs--start .ehl-list{right:auto;left:var(--ehl-inset);margin:0}.ehl-asof{border-bottom:1px dashed var(--ehl-border,currentColor);justify-content:space-between;align-items:center;gap:12px;padding-bottom:4px;display:flex}.ehl-refetch{font:inherit;color:inherit;cursor:pointer;opacity:.8;background:0 0;border:1px solid;border-radius:3px;align-items:center;gap:3px;padding:1px 5px;font-size:10px;font-weight:700;display:flex}.ehl-refetch:hover:not(:disabled){opacity:1}.ehl-refetch:disabled{opacity:.35;cursor:default}.ehl-section+.ehl-section{border-top:1px dashed var(--ehl-border,currentColor);margin-top:6px;padding-top:6px}.ehl-head{margin:0 0 2px;font-size:11px;font-weight:700;line-height:18px}.ehl-language{box-sizing:border-box;color:#fff;letter-spacing:0;vertical-align:middle;background:#64748b;border-radius:3px;flex-shrink:0;justify-content:center;align-items:center;min-width:22px;height:18px;padding:0 4px;font-size:11px;font-weight:700;line-height:1;display:inline-flex}.ehl-language[data-language=chinese]{background:#be185d}.ehl-language[data-language=japanese]{background:#7c3aed}.ehl-language[data-language=english]{background:#b45309}.ehl-language[data-language=korean]{background:#2563eb}.ehl-head>.ehl-language{margin-right:4px}.ehl-count{opacity:.7;margin-left:4px;font-weight:400}.ehl-list ul{margin:0;padding:0;list-style:none}.ehl-list li{padding:2px 0;display:block}.ehl-list li.ehl-row{padding:0;position:relative}.ehl-rowlink{min-height:var(--ehl-cover-h);border-radius:3px;align-items:stretch;gap:6px;padding:2px 36px 2px 3px;display:flex}.ehl-rowlink:hover{background:color-mix(in srgb, currentColor 12%, transparent)}.ehl-thumb{width:calc(var(--ehl-cover-h) * 5 / 7);flex:none;position:relative}.ehl-thumb img,.ehl-cover-art img{box-sizing:border-box;border:1px solid var(--ehl-border,currentColor);border-radius:2px;max-width:100%;max-height:100%;position:absolute;top:0;left:50%;transform:translate(-50%)}.ehl-covers{grid-template-columns:repeat(6, calc(var(--ehl-cover-h) * 5 / 7));gap:4px;display:grid}.ehl-cover-cell{display:flex;position:relative}.ehl-cover{flex-direction:column;flex:auto;gap:2px;display:flex}.ehl-cover-art{height:var(--ehl-cover-h);flex:none;position:relative}.ehl-cover-cell:hover .ehl-cover-art img{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 30%, transparent);border-color:currentColor}.ehl-copy{width:20px;height:20px;color:inherit;background:var(--ehl-bg,#fff);cursor:pointer;opacity:0;border:1px solid;border-radius:3px;justify-content:center;align-items:center;padding:0;display:flex;position:absolute;top:2px;right:2px}.ehl-row:hover .ehl-copy,.ehl-cover-cell:hover .ehl-copy,.ehl-copy:focus-visible,.ehl-copy--done{opacity:.8}.ehl-copy:hover{opacity:1}.ehl-row .ehl-copy{width:28px;height:28px}.ehl-row .ehl-copy svg{width:16px;height:16px}.ehl-rowtext{min-width:0;display:block}.ehl-title{white-space:normal;overflow-wrap:anywhere;max-width:520px;display:block}.ehl-facts{flex-wrap:wrap;align-items:baseline;gap:0 2px;display:flex}.ehl-facts>:first-child{margin-left:0}.ehl-preview{box-sizing:border-box;border:1px solid var(--ehl-border,currentColor);background:var(--ehl-bg,#fff);pointer-events:none;z-index:22;border-radius:4px;flex-direction:column;gap:4px;padding:5px;display:flex;position:fixed;box-shadow:0 3px 8px #00000040}.ehl-preview img{object-fit:contain;object-position:top;width:100%;min-height:0}.ehl-preview-text{white-space:normal;overflow-wrap:anywhere;flex:0 auto;min-height:0;overflow:hidden}.ehl-preview-title{font-size:11px;line-height:1.25;display:block}.ehl-tags{grid-template-columns:auto 1fr;align-items:start;column-gap:6px;margin-top:3px;font-size:9pt;display:grid}.ehl-tags__row{display:contents}.ehl-tags__label{text-align:right;white-space:nowrap;opacity:.7;padding-top:3px}.ehl-tags__cells{flex-wrap:wrap;min-width:0;display:flex}.ehl-tags__chip{background:color-mix(in srgb, currentColor 8%, transparent);border:1px solid var(--ehl-border,currentColor);white-space:nowrap;border-radius:5px;margin:0 2px 3px;padding:1px 4px}.ehl-stars{letter-spacing:1px;color:color-mix(in srgb, currentColor 35%, transparent);-webkit-text-stroke:.5px currentColor;paint-order:stroke fill;white-space:nowrap;font-size:11px;line-height:14px;display:inline-block;position:relative}.ehl-stars-on{color:var(--ehl-star);position:absolute;top:0;left:0;overflow:hidden}.ehl-stars--r{--ehl-star:#e23636}.ehl-stars--g{--ehl-star:#34b25e}.ehl-stars--b{--ehl-star:#3c8cdd}.ehl-stars--y{--ehl-star:#f4c025}.ehl-books{display:block}.ehl-book{border:1px solid var(--ehl-book);background:color-mix(in srgb, var(--ehl-book) 14%, transparent);border-left-width:3px;border-radius:3px;margin:4px 0;padding:0 5px 0 0;display:block}.ehl-book ul{padding-left:8px}.ehl-book--0{--ehl-book:#4299d7}.ehl-book--1{--ehl-book:#3db870}.ehl-book--2{--ehl-book:#e29236}.ehl-book--3{--ehl-book:#b66ecf}.ehl-list a{text-decoration:none}.ehl-subtitle{opacity:.7;font-size:11px;display:block}.ehl-url{white-space:normal;overflow-wrap:anywhere;max-width:560px;display:block}.ehl-meta{opacity:.7;margin-left:6px}.ehl-flag{opacity:.85;border:1px solid;border-radius:3px;margin-left:6px;padding:0 4px;font-size:10px;line-height:14px}.ehl-labeled-button{gap:4px;font-weight:700}\n/*$vite$:1*/ ");
	function makeMap(str) {
		const map = Object.create(null);
		for (const key of str.split(",")) map[key] = 1;
		return (val) => val in map;
	}
	var EMPTY_OBJ = {};
	var EMPTY_ARR = [];
	var NOOP = () => {};
	var NO = () => false;
	var isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && (key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97);
	var isModelListener = (key) => key.startsWith("onUpdate:");
	var extend = Object.assign;
	var remove = (arr, el) => {
		const i = arr.indexOf(el);
		if (i > -1) arr.splice(i, 1);
	};
	var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
	var hasOwn = (val, key) => hasOwnProperty$1.call(val, key);
	var isArray = Array.isArray;
	var isMap = (val) => toTypeString(val) === "[object Map]";
	var isSet = (val) => toTypeString(val) === "[object Set]";
	var isDate = (val) => toTypeString(val) === "[object Date]";
	var isFunction = (val) => typeof val === "function";
	var isString = (val) => typeof val === "string";
	var isSymbol = (val) => typeof val === "symbol";
	var isObject = (val) => val !== null && typeof val === "object";
	var isPromise = (val) => {
		return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch);
	};
	var objectToString = Object.prototype.toString;
	var toTypeString = (value) => objectToString.call(value);
	var toRawType = (value) => {
		return toTypeString(value).slice(8, -1);
	};
	var isPlainObject = (val) => toTypeString(val) === "[object Object]";
	var isIntegerKey = (key) => isString(key) && key !== "NaN" && key[0] !== "-" && "" + parseInt(key, 10) === key;
	var isReservedProp = makeMap(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted");
	var cacheStringFunction = (fn) => {
		const cache = Object.create(null);
		return ((str) => {
			return cache[str] || (cache[str] = fn(str));
		});
	};
	var camelizeRE = /-\w/g;
	var camelize = cacheStringFunction((str) => {
		return str.replace(camelizeRE, (c) => c.slice(1).toUpperCase());
	});
	var hyphenateRE = /\B([A-Z])/g;
	var hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, "-$1").toLowerCase());
	var capitalize = cacheStringFunction((str) => {
		return str.charAt(0).toUpperCase() + str.slice(1);
	});
	var toHandlerKey = cacheStringFunction((str) => {
		return str ? `on${capitalize(str)}` : ``;
	});
	var hasChanged = (value, oldValue) => !Object.is(value, oldValue);
	var invokeArrayFns = (fns, ...arg) => {
		for (let i = 0; i < fns.length; i++) fns[i](...arg);
	};
	var def = (obj, key, value, writable = false) => {
		Object.defineProperty(obj, key, {
			configurable: true,
			enumerable: false,
			writable,
			value
		});
	};
	var looseToNumber = (val) => {
		const n = parseFloat(val);
		return isNaN(n) ? val : n;
	};
	var _globalThis;
	var getGlobalThis = () => {
		return _globalThis || (_globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {});
	};
	function normalizeStyle(value) {
		if (isArray(value)) {
			const res = {};
			for (let i = 0; i < value.length; i++) {
				const item = value[i];
				const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item);
				if (normalized) for (const key in normalized) res[key] = normalized[key];
			}
			return res;
		} else if (isString(value) || isObject(value)) return value;
	}
	var listDelimiterRE = /;(?![^(]*\))/g;
	var propertyDelimiterRE = /:([^]+)/;
	var styleCommentRE = /\/\*[^]*?\*\//g;
	function parseStringStyle(cssText) {
		const ret = {};
		cssText.replace(styleCommentRE, "").split(listDelimiterRE).forEach((item) => {
			if (item) {
				const tmp = item.split(propertyDelimiterRE);
				tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim());
			}
		});
		return ret;
	}
	function normalizeClass(value) {
		let res = "";
		if (isString(value)) res = value;
		else if (isArray(value)) for (let i = 0; i < value.length; i++) {
			const normalized = normalizeClass(value[i]);
			if (normalized) res += normalized + " ";
		}
		else if (isObject(value)) {
			for (const name in value) if (value[name]) res += name + " ";
		}
		return res.trim();
	}
	var specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;
	var isSpecialBooleanAttr = makeMap(specialBooleanAttrs);
	specialBooleanAttrs + "";
	function includeBooleanAttr(value) {
		return !!value || value === "";
	}
	function looseCompareArrays(a, b) {
		if (a.length !== b.length) return false;
		let equal = true;
		for (let i = 0; equal && i < a.length; i++) equal = looseEqual(a[i], b[i]);
		return equal;
	}
	function looseCompareCollections(a, b) {
		if (a.size !== b.size) return false;
		const candidates = Array.from(b);
		const matched = new Uint8Array(candidates.length);
		for (const item of a) {
			let index = -1;
			for (let i = 0; i < candidates.length; i++) if (!matched[i] && looseEqual(item, candidates[i])) {
				index = i;
				break;
			}
			if (index < 0) return false;
			matched[index] = 1;
		}
		return true;
	}
	function looseEqual(a, b) {
		if (a === b) return true;
		let aValidType = isDate(a);
		let bValidType = isDate(b);
		if (aValidType || bValidType) return aValidType && bValidType ? a.getTime() === b.getTime() : false;
		aValidType = isSymbol(a);
		bValidType = isSymbol(b);
		if (aValidType || bValidType) return a === b;
		aValidType = isArray(a);
		bValidType = isArray(b);
		if (aValidType || bValidType) return aValidType && bValidType ? looseCompareArrays(a, b) : false;
		aValidType = isObject(a);
		bValidType = isObject(b);
		if (aValidType || bValidType) {
			if (!aValidType || !bValidType) return false;
			aValidType = isMap(a);
			bValidType = isMap(b);
			if (aValidType || bValidType) return aValidType && bValidType ? looseCompareCollections(a, b) : false;
			aValidType = isSet(a);
			bValidType = isSet(b);
			if (aValidType || bValidType) return aValidType && bValidType ? looseCompareCollections(a, b) : false;
			if (Object.keys(a).length !== Object.keys(b).length) return false;
			for (const key in a) {
				const aHasKey = a.hasOwnProperty(key);
				const bHasKey = b.hasOwnProperty(key);
				if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) return false;
			}
		}
		return String(a) === String(b);
	}
	function looseIndexOf(arr, val) {
		return arr.findIndex((item) => looseEqual(item, val));
	}
	var isRef$1 = (val) => {
		return !!(val && val["__v_isRef"] === true);
	};
	var toDisplayString = (val) => {
		return isString(val) ? val : val == null ? "" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? isRef$1(val) ? toDisplayString(val.value) : JSON.stringify(val, replacer, 2) : String(val);
	};
	var replacer = (_key, val) => {
		if (isRef$1(val)) return replacer(_key, val.value);
		else if (isMap(val)) return { [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val2], i) => {
			entries[stringifySymbol(key, i) + " =>"] = val2;
			return entries;
		}, {}) };
		else if (isSet(val)) return { [`Set(${val.size})`]: [...val.values()].map((v) => stringifySymbol(v)) };
		else if (isSymbol(val)) return stringifySymbol(val);
		else if (isObject(val) && !isArray(val) && !isPlainObject(val)) return String(val);
		return val;
	};
	var stringifySymbol = (v, i = "") => {
		var _a;
		return isSymbol(v) ? `Symbol(${(_a = v.description) != null ? _a : i})` : v;
	};
	var activeEffectScope;
	var EffectScope = class {
		constructor(detached = false) {
			this.detached = detached;
			this._active = true;
			this._on = 0;
			this.effects = [];
			this.cleanups = [];
			this._isPaused = false;
			this._warnOnRun = true;
			this.__v_skip = true;
			if (!detached && activeEffectScope) {
				if (activeEffectScope.active) {
					this.parent = activeEffectScope;
					this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(this) - 1;
				} else {
					this._active = false;
					this._warnOnRun = false;
				}
			}
		}
		get active() {
			return this._active;
		}
		pause() {
			if (this._active) {
				this._isPaused = true;
				let i, l;
				if (this.scopes) {
					const scopes = this.scopes.slice();
					for (i = 0, l = scopes.length; i < l; i++) scopes[i].pause();
				}
				for (i = 0, l = this.effects.length; i < l; i++) this.effects[i].pause();
			}
		}
		resume() {
			if (this._active) {
				if (this._isPaused) {
					this._isPaused = false;
					let i, l;
					if (this.scopes) {
						const scopes = this.scopes.slice();
						for (i = 0, l = scopes.length; i < l; i++) scopes[i].resume();
					}
					const effects = this.effects.slice();
					for (i = 0, l = effects.length; i < l; i++) effects[i].resume();
				}
			}
		}
		run(fn) {
			if (this._active) {
				const currentEffectScope = activeEffectScope;
				try {
					activeEffectScope = this;
					return fn();
				} finally {
					activeEffectScope = currentEffectScope;
				}
			}
		}
		on() {
			if (++this._on === 1) {
				this.prevScope = activeEffectScope;
				activeEffectScope = this;
			}
		}
		off() {
			if (this._on > 0 && --this._on === 0) {
				if (activeEffectScope === this) activeEffectScope = this.prevScope;
				else {
					let current = activeEffectScope;
					while (current) {
						if (current.prevScope === this) {
							current.prevScope = this.prevScope;
							break;
						}
						current = current.prevScope;
					}
				}
				this.prevScope = void 0;
			}
		}
		stop(fromParent) {
			if (this._active) {
				this._active = false;
				let i, l;
				for (i = 0, l = this.effects.length; i < l; i++) this.effects[i].stop();
				this.effects.length = 0;
				for (i = 0, l = this.cleanups.length; i < l; i++) this.cleanups[i]();
				this.cleanups.length = 0;
				if (this.scopes) {
					const scopes = this.scopes.slice();
					for (i = 0, l = scopes.length; i < l; i++) scopes[i].stop(true);
					this.scopes.length = 0;
				}
				if (!this.detached && this.parent && !fromParent) {
					const last = this.parent.scopes.pop();
					if (last && last !== this) {
						this.parent.scopes[this.index] = last;
						last.index = this.index;
					}
				}
				this.parent = void 0;
			}
		}
	};
	function getCurrentScope() {
		return activeEffectScope;
	}
	var activeSub;
	var pausedQueueEffects = new WeakSet();
	var ReactiveEffect = class {
		constructor(fn) {
			this.fn = fn;
			this.deps = void 0;
			this.depsTail = void 0;
			this.flags = 5;
			this.next = void 0;
			this.cleanup = void 0;
			this.scheduler = void 0;
			if (activeEffectScope) {
				if (activeEffectScope.active) activeEffectScope.effects.push(this);
				else this.flags &= -2;
			}
		}
		pause() {
			this.flags |= 64;
		}
		resume() {
			if (this.flags & 64) {
				this.flags &= -65;
				if (pausedQueueEffects.has(this)) {
					pausedQueueEffects.delete(this);
					this.trigger();
				}
			}
		}
		notify() {
			if (this.flags & 2 && !(this.flags & 32)) return;
			if (!(this.flags & 8)) batch(this);
		}
		run() {
			if (!(this.flags & 1)) return this.fn();
			this.flags |= 2;
			cleanupEffect(this);
			prepareDeps(this);
			const prevEffect = activeSub;
			const prevShouldTrack = shouldTrack;
			activeSub = this;
			shouldTrack = true;
			try {
				return this.fn();
			} finally {
				cleanupDeps(this);
				activeSub = prevEffect;
				shouldTrack = prevShouldTrack;
				this.flags &= -3;
			}
		}
		stop() {
			if (this.flags & 1) {
				for (let link = this.deps; link; link = link.nextDep) removeSub(link);
				this.deps = this.depsTail = void 0;
				cleanupEffect(this);
				this.onStop && this.onStop();
				this.flags &= -2;
			}
		}
		trigger() {
			if (this.flags & 64) pausedQueueEffects.add(this);
			else if (this.scheduler) this.scheduler();
			else this.runIfDirty();
		}
		runIfDirty() {
			if (isDirty(this)) this.run();
		}
		get dirty() {
			return isDirty(this);
		}
	};
	var batchDepth = 0;
	var batchedSub;
	var batchedComputed;
	function batch(sub, isComputed = false) {
		sub.flags |= 8;
		if (isComputed) {
			sub.next = batchedComputed;
			batchedComputed = sub;
			return;
		}
		sub.next = batchedSub;
		batchedSub = sub;
	}
	function startBatch() {
		batchDepth++;
	}
	function endBatch() {
		if (--batchDepth > 0) return;
		if (batchedComputed) {
			let e = batchedComputed;
			batchedComputed = void 0;
			while (e) {
				const next = e.next;
				e.next = void 0;
				e.flags &= -9;
				e = next;
			}
		}
		let error;
		while (batchedSub) {
			let e = batchedSub;
			batchedSub = void 0;
			while (e) {
				const next = e.next;
				e.next = void 0;
				e.flags &= -9;
				if (e.flags & 1) try {
					e.trigger();
				} catch (err) {
					if (!error) error = err;
				}
				e = next;
			}
		}
		if (error) throw error;
	}
	function prepareDeps(sub) {
		for (let link = sub.deps; link; link = link.nextDep) {
			link.version = -1;
			link.prevActiveLink = link.dep.activeLink;
			link.dep.activeLink = link;
		}
	}
	function cleanupDeps(sub) {
		let head;
		let tail = sub.depsTail;
		let link = tail;
		while (link) {
			const prev = link.prevDep;
			if (link.version === -1) {
				if (link === tail) tail = prev;
				removeSub(link);
				removeDep(link);
			} else head = link;
			link.dep.activeLink = link.prevActiveLink;
			link.prevActiveLink = void 0;
			link = prev;
		}
		sub.deps = head;
		sub.depsTail = tail;
	}
	function isDirty(sub) {
		for (let link = sub.deps; link; link = link.nextDep) if (link.dep.version !== link.version || link.dep.computed && (refreshComputed(link.dep.computed) || link.dep.version !== link.version)) return true;
		if (sub._dirty) return true;
		return false;
	}
	function refreshComputed(computed) {
		if (computed.flags & 4 && !(computed.flags & 16)) return;
		computed.flags &= -17;
		if (computed.globalVersion === globalVersion) return;
		computed.globalVersion = globalVersion;
		if (!computed.isSSR && computed.flags & 128 && (!computed.deps && !computed._dirty || !isDirty(computed))) return;
		computed.flags |= 2;
		const dep = computed.dep;
		const prevSub = activeSub;
		const prevShouldTrack = shouldTrack;
		activeSub = computed;
		shouldTrack = true;
		try {
			prepareDeps(computed);
			const value = computed.fn(computed._value);
			if (dep.version === 0 || hasChanged(value, computed._value)) {
				computed.flags |= 128;
				computed._value = value;
				dep.version++;
			}
		} catch (err) {
			dep.version++;
			throw err;
		} finally {
			activeSub = prevSub;
			shouldTrack = prevShouldTrack;
			cleanupDeps(computed);
			computed.flags &= -3;
		}
	}
	function removeSub(link, soft = false) {
		const { dep, prevSub, nextSub } = link;
		if (prevSub) {
			prevSub.nextSub = nextSub;
			link.prevSub = void 0;
		}
		if (nextSub) {
			nextSub.prevSub = prevSub;
			link.nextSub = void 0;
		}
		if (dep.subs === link) {
			dep.subs = prevSub;
			if (!prevSub && dep.computed) {
				dep.computed.flags &= -5;
				for (let l = dep.computed.deps; l; l = l.nextDep) removeSub(l, true);
			}
		}
		if (!soft && !--dep.sc && dep.map) dep.map.delete(dep.key);
	}
	function removeDep(link) {
		const { prevDep, nextDep } = link;
		if (prevDep) {
			prevDep.nextDep = nextDep;
			link.prevDep = void 0;
		}
		if (nextDep) {
			nextDep.prevDep = prevDep;
			link.nextDep = void 0;
		}
	}
	var shouldTrack = true;
	var trackStack = [];
	function pauseTracking() {
		trackStack.push(shouldTrack);
		shouldTrack = false;
	}
	function resetTracking() {
		const last = trackStack.pop();
		shouldTrack = last === void 0 ? true : last;
	}
	function cleanupEffect(e) {
		const { cleanup } = e;
		e.cleanup = void 0;
		if (cleanup) {
			const prevSub = activeSub;
			activeSub = void 0;
			try {
				cleanup();
			} finally {
				activeSub = prevSub;
			}
		}
	}
	var globalVersion = 0;
	var Link = class {
		constructor(sub, dep) {
			this.sub = sub;
			this.dep = dep;
			this.version = dep.version;
			this.nextDep = this.prevDep = this.nextSub = this.prevSub = this.prevActiveLink = void 0;
		}
	};
	var Dep = class {
		constructor(computed) {
			this.computed = computed;
			this.version = 0;
			this.activeLink = void 0;
			this.subs = void 0;
			this.map = void 0;
			this.key = void 0;
			this.sc = 0;
			this.__v_skip = true;
		}
		track(debugInfo) {
			if (!activeSub || !shouldTrack || activeSub === this.computed) return;
			let link = this.activeLink;
			if (link === void 0 || link.sub !== activeSub) {
				link = this.activeLink = new Link(activeSub, this);
				if (!activeSub.deps) activeSub.deps = activeSub.depsTail = link;
				else {
					link.prevDep = activeSub.depsTail;
					activeSub.depsTail.nextDep = link;
					activeSub.depsTail = link;
				}
				addSub(link);
			} else if (link.version === -1) {
				link.version = this.version;
				if (link.nextDep) {
					const next = link.nextDep;
					next.prevDep = link.prevDep;
					if (link.prevDep) link.prevDep.nextDep = next;
					link.prevDep = activeSub.depsTail;
					link.nextDep = void 0;
					activeSub.depsTail.nextDep = link;
					activeSub.depsTail = link;
					if (activeSub.deps === link) activeSub.deps = next;
				}
			}
			return link;
		}
		trigger(debugInfo) {
			this.version++;
			globalVersion++;
			this.notify(debugInfo);
		}
		notify(debugInfo) {
			startBatch();
			try {
				for (let link = this.subs; link; link = link.prevSub) if (link.sub.notify()) link.sub.dep.notify();
			} finally {
				endBatch();
			}
		}
	};
	function addSub(link) {
		link.dep.sc++;
		if (link.sub.flags & 4) {
			const computed = link.dep.computed;
			if (computed && !link.dep.subs) {
				computed.flags |= 20;
				for (let l = computed.deps; l; l = l.nextDep) addSub(l);
			}
			const currentTail = link.dep.subs;
			if (currentTail !== link) {
				link.prevSub = currentTail;
				if (currentTail) currentTail.nextSub = link;
			}
			link.dep.subs = link;
		}
	}
	var targetMap = new WeakMap();
	var ITERATE_KEY = Symbol("");
	var MAP_KEY_ITERATE_KEY = Symbol("");
	var ARRAY_ITERATE_KEY = Symbol("");
	function track(target, type, key) {
		if (shouldTrack && activeSub) {
			let depsMap = targetMap.get(target);
			if (!depsMap) targetMap.set(target, depsMap = new Map());
			let dep = depsMap.get(key);
			if (!dep) {
				depsMap.set(key, dep = new Dep());
				dep.map = depsMap;
				dep.key = key;
			}
			dep.track();
		}
	}
	function trigger(target, type, key, newValue, oldValue, oldTarget) {
		const depsMap = targetMap.get(target);
		if (!depsMap) {
			globalVersion++;
			return;
		}
		const run = (dep) => {
			if (dep) dep.trigger();
		};
		startBatch();
		if (type === "clear") depsMap.forEach(run);
		else {
			const targetIsArray = isArray(target);
			const isArrayIndex = targetIsArray && isIntegerKey(key);
			if (targetIsArray && key === "length") {
				const newLength = Number(newValue);
				depsMap.forEach((dep, key2) => {
					if (key2 === "length" || key2 === ARRAY_ITERATE_KEY || !isSymbol(key2) && key2 >= newLength) run(dep);
				});
			} else {
				if (key !== void 0 || depsMap.has(void 0)) run(depsMap.get(key));
				if (isArrayIndex) run(depsMap.get(ARRAY_ITERATE_KEY));
				switch (type) {
					case "add":
						if (!targetIsArray) {
							run(depsMap.get(ITERATE_KEY));
							if (isMap(target)) run(depsMap.get(MAP_KEY_ITERATE_KEY));
						} else if (isArrayIndex) run(depsMap.get("length"));
						break;
					case "delete":
						if (!targetIsArray) {
							run(depsMap.get(ITERATE_KEY));
							if (isMap(target)) run(depsMap.get(MAP_KEY_ITERATE_KEY));
						}
						break;
					case "set": if (isMap(target)) run(depsMap.get(ITERATE_KEY));
				}
			}
		}
		endBatch();
	}
	function reactiveReadArray(array) {
		const raw = toRaw(array);
		if (raw === array) return raw;
		track(raw, "iterate", ARRAY_ITERATE_KEY);
		return isShallow(array) ? raw : raw.map(toReactive);
	}
	function shallowReadArray(arr) {
		track(arr = toRaw(arr), "iterate", ARRAY_ITERATE_KEY);
		return arr;
	}
	function toWrapped(target, item) {
		if (isReadonly(target)) return isReactive(target) ? toReadonly(toReactive(item)) : toReadonly(item);
		return toReactive(item);
	}
	var arrayInstrumentations = {
		__proto__: null,
		[Symbol.iterator]() {
			return iterator(this, Symbol.iterator, (item) => toWrapped(this, item));
		},
		concat(...args) {
			return reactiveReadArray(this).concat(...args.map((x) => isArray(x) ? reactiveReadArray(x) : x));
		},
		entries() {
			return iterator(this, "entries", (value) => {
				value[1] = toWrapped(this, value[1]);
				return value;
			});
		},
		every(fn, thisArg) {
			return apply(this, "every", fn, thisArg, void 0, arguments);
		},
		filter(fn, thisArg) {
			return apply(this, "filter", fn, thisArg, (v) => v.map((item) => toWrapped(this, item)), arguments);
		},
		find(fn, thisArg) {
			return apply(this, "find", fn, thisArg, (item) => toWrapped(this, item), arguments);
		},
		findIndex(fn, thisArg) {
			return apply(this, "findIndex", fn, thisArg, void 0, arguments);
		},
		findLast(fn, thisArg) {
			return apply(this, "findLast", fn, thisArg, (item) => toWrapped(this, item), arguments);
		},
		findLastIndex(fn, thisArg) {
			return apply(this, "findLastIndex", fn, thisArg, void 0, arguments);
		},
		forEach(fn, thisArg) {
			return apply(this, "forEach", fn, thisArg, void 0, arguments);
		},
		includes(...args) {
			return searchProxy(this, "includes", args);
		},
		indexOf(...args) {
			return searchProxy(this, "indexOf", args);
		},
		join(separator) {
			return reactiveReadArray(this).join(separator);
		},
		lastIndexOf(...args) {
			return searchProxy(this, "lastIndexOf", args);
		},
		map(fn, thisArg) {
			return apply(this, "map", fn, thisArg, void 0, arguments);
		},
		pop() {
			return noTracking(this, "pop");
		},
		push(...args) {
			return noTracking(this, "push", args);
		},
		reduce(fn, ...args) {
			return reduce(this, "reduce", fn, args);
		},
		reduceRight(fn, ...args) {
			return reduce(this, "reduceRight", fn, args);
		},
		shift() {
			return noTracking(this, "shift");
		},
		some(fn, thisArg) {
			return apply(this, "some", fn, thisArg, void 0, arguments);
		},
		splice(...args) {
			return noTracking(this, "splice", args);
		},
		toReversed() {
			return reactiveReadArray(this).toReversed();
		},
		toSorted(comparer) {
			return reactiveReadArray(this).toSorted(comparer);
		},
		toSpliced(...args) {
			return reactiveReadArray(this).toSpliced(...args);
		},
		unshift(...args) {
			return noTracking(this, "unshift", args);
		},
		values() {
			return iterator(this, "values", (item) => toWrapped(this, item));
		}
	};
	function iterator(self, method, wrapValue) {
		const arr = shallowReadArray(self);
		const iter = arr[method]();
		if (arr !== self && !isShallow(self)) {
			iter._next = iter.next;
			iter.next = () => {
				const result = iter._next();
				if (!result.done) result.value = wrapValue(result.value);
				return result;
			};
		}
		return iter;
	}
	var arrayProto = Array.prototype;
	function apply(self, method, fn, thisArg, wrappedRetFn, args) {
		const arr = shallowReadArray(self);
		const needsWrap = arr !== self && !isShallow(self);
		const methodFn = arr[method];
		if (methodFn !== arrayProto[method]) {
			const result2 = methodFn.apply(self, args);
			return needsWrap ? toReactive(result2) : result2;
		}
		let wrappedFn = fn;
		if (arr !== self) {
			if (needsWrap) wrappedFn = function(item, index) {
				return fn.call(this, toWrapped(self, item), index, self);
			};
			else if (fn.length > 2) wrappedFn = function(item, index) {
				return fn.call(this, item, index, self);
			};
		}
		const result = methodFn.call(arr, wrappedFn, thisArg);
		return needsWrap && wrappedRetFn ? wrappedRetFn(result) : result;
	}
	function reduce(self, method, fn, args) {
		const arr = shallowReadArray(self);
		const needsWrap = arr !== self && !isShallow(self);
		let wrappedFn = fn;
		let wrapInitialAccumulator = false;
		if (arr !== self) {
			if (needsWrap) {
				wrapInitialAccumulator = args.length === 0;
				wrappedFn = function(acc, item, index) {
					if (wrapInitialAccumulator) {
						wrapInitialAccumulator = false;
						acc = toWrapped(self, acc);
					}
					return fn.call(this, acc, toWrapped(self, item), index, self);
				};
			} else if (fn.length > 3) wrappedFn = function(acc, item, index) {
				return fn.call(this, acc, item, index, self);
			};
		}
		const result = arr[method](wrappedFn, ...args);
		return wrapInitialAccumulator ? toWrapped(self, result) : result;
	}
	function searchProxy(self, method, args) {
		const arr = toRaw(self);
		track(arr, "iterate", ARRAY_ITERATE_KEY);
		const res = arr[method](...args);
		if ((res === -1 || res === false) && isProxy(args[0])) {
			args[0] = toRaw(args[0]);
			return arr[method](...args);
		}
		return res;
	}
	function noTracking(self, method, args = []) {
		pauseTracking();
		startBatch();
		const res = toRaw(self)[method].apply(self, args);
		endBatch();
		resetTracking();
		return res;
	}
	var isNonTrackableKeys = makeMap(`__proto__,__v_isRef,__isVue`);
	var builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol).filter((key) => key !== "arguments" && key !== "caller").map((key) => Symbol[key]).filter(isSymbol));
	function hasOwnProperty(key) {
		if (!isSymbol(key)) key = String(key);
		const obj = toRaw(this);
		track(obj, "has", key);
		return obj.hasOwnProperty(key);
	}
	var BaseReactiveHandler = class {
		constructor(_isReadonly = false, _isShallow = false) {
			this._isReadonly = _isReadonly;
			this._isShallow = _isShallow;
		}
		get(target, key, receiver) {
			if (key === "__v_skip") return target["__v_skip"];
			const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow;
			if (key === "__v_isReactive") return !isReadonly2;
			else if (key === "__v_isReadonly") return isReadonly2;
			else if (key === "__v_isShallow") return isShallow2;
			else if (key === "__v_raw") {
				if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) return target;
				return;
			}
			const targetIsArray = isArray(target);
			if (!isReadonly2) {
				let fn;
				if (targetIsArray && (fn = arrayInstrumentations[key])) return fn;
				if (key === "hasOwnProperty") return hasOwnProperty;
			}
			const res = Reflect.get(target, key, isRef(target) ? target : receiver);
			if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) return res;
			if (!isReadonly2) track(target, "get", key);
			if (isShallow2) return res;
			if (isRef(res)) {
				const value = targetIsArray && isIntegerKey(key) ? res : res.value;
				return isReadonly2 && isObject(value) ? readonly(value) : value;
			}
			if (isObject(res)) return isReadonly2 ? readonly(res) : reactive(res);
			return res;
		}
	};
	var MutableReactiveHandler = class extends BaseReactiveHandler {
		constructor(isShallow2 = false) {
			super(false, isShallow2);
		}
		set(target, key, value, receiver) {
			let oldValue = target[key];
			const isArrayWithIntegerKey = isArray(target) && isIntegerKey(key);
			if (!this._isShallow) {
				const isOldValueReadonly = isReadonly(oldValue);
				if (!isShallow(value) && !isReadonly(value)) {
					oldValue = toRaw(oldValue);
					value = toRaw(value);
				}
				if (!isArrayWithIntegerKey && isRef(oldValue) && !isRef(value)) {
					if (isOldValueReadonly) return true;
					else {
						oldValue.value = value;
						return true;
					}
				}
			}
			const hadKey = isArrayWithIntegerKey ? Number(key) < target.length : hasOwn(target, key);
			const result = Reflect.set(target, key, value, isRef(target) ? target : receiver);
			if (target === toRaw(receiver) && result) {
				if (!hadKey) trigger(target, "add", key, value);
				else if (hasChanged(value, oldValue)) trigger(target, "set", key, value, oldValue);
			}
			return result;
		}
		deleteProperty(target, key) {
			const hadKey = hasOwn(target, key);
			const oldValue = target[key];
			const result = Reflect.deleteProperty(target, key);
			if (result && hadKey) trigger(target, "delete", key, void 0, oldValue);
			return result;
		}
		has(target, key) {
			const result = Reflect.has(target, key);
			if (!isSymbol(key) || !builtInSymbols.has(key)) track(target, "has", key);
			return result;
		}
		ownKeys(target) {
			track(target, "iterate", isArray(target) ? "length" : ITERATE_KEY);
			return Reflect.ownKeys(target);
		}
	};
	var ReadonlyReactiveHandler = class extends BaseReactiveHandler {
		constructor(isShallow2 = false) {
			super(true, isShallow2);
		}
		set(target, key) {
			return true;
		}
		deleteProperty(target, key) {
			return true;
		}
	};
	var mutableHandlers = new MutableReactiveHandler();
	var readonlyHandlers = new ReadonlyReactiveHandler();
	var shallowReactiveHandlers = new MutableReactiveHandler(true);
	var toShallow = (value) => value;
	var getProto = (v) => Reflect.getPrototypeOf(v);
	function createIterableMethod(method, isReadonly2, isShallow2) {
		return function(...args) {
			const target = this["__v_raw"];
			const rawTarget = toRaw(target);
			const targetIsMap = isMap(rawTarget);
			const isPair = method === "entries" || method === Symbol.iterator && targetIsMap;
			const isKeyOnly = method === "keys" && targetIsMap;
			const innerIterator = target[method](...args);
			const wrap = isShallow2 ? toShallow : isReadonly2 ? toReadonly : toReactive;
			!isReadonly2 && track(rawTarget, "iterate", isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY);
			return extend(Object.create(innerIterator), { next() {
				const { value, done } = innerIterator.next();
				return done ? {
					value,
					done
				} : {
					value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),
					done
				};
			} });
		};
	}
	function createReadonlyMethod(type) {
		return function(...args) {
			return type === "delete" ? false : type === "clear" ? void 0 : this;
		};
	}
	function createInstrumentations(readonly, shallow) {
		const instrumentations = {
			get(key) {
				const target = this["__v_raw"];
				const rawTarget = toRaw(target);
				const rawKey = toRaw(key);
				if (!readonly) {
					if (hasChanged(key, rawKey)) track(rawTarget, "get", key);
					track(rawTarget, "get", rawKey);
				}
				const { has } = getProto(rawTarget);
				const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive;
				if (has.call(rawTarget, key)) return wrap(target.get(key));
				else if (has.call(rawTarget, rawKey)) return wrap(target.get(rawKey));
				else if (target !== rawTarget) target.get(key);
			},
			get size() {
				const target = this["__v_raw"];
				!readonly && track(toRaw(target), "iterate", ITERATE_KEY);
				return target.size;
			},
			has(key) {
				const target = this["__v_raw"];
				const rawTarget = toRaw(target);
				const rawKey = toRaw(key);
				if (!readonly) {
					if (hasChanged(key, rawKey)) track(rawTarget, "has", key);
					track(rawTarget, "has", rawKey);
				}
				return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey);
			},
			forEach(callback, thisArg) {
				const observed = this;
				const target = observed["__v_raw"];
				const rawTarget = toRaw(target);
				const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive;
				!readonly && track(rawTarget, "iterate", ITERATE_KEY);
				return target.forEach((value, key) => {
					return callback.call(thisArg, wrap(value), wrap(key), observed);
				});
			}
		};
		extend(instrumentations, readonly ? {
			add: createReadonlyMethod("add"),
			set: createReadonlyMethod("set"),
			delete: createReadonlyMethod("delete"),
			clear: createReadonlyMethod("clear")
		} : {
			add(value) {
				const target = toRaw(this);
				const proto = getProto(target);
				const rawValue = toRaw(value);
				const valueToAdd = !shallow && !isShallow(value) && !isReadonly(value) ? rawValue : value;
				if (!(proto.has.call(target, valueToAdd) || hasChanged(value, valueToAdd) && proto.has.call(target, value) || hasChanged(rawValue, valueToAdd) && proto.has.call(target, rawValue))) {
					target.add(valueToAdd);
					trigger(target, "add", valueToAdd, valueToAdd);
				}
				return this;
			},
			set(key, value) {
				if (!shallow && !isShallow(value) && !isReadonly(value)) value = toRaw(value);
				const target = toRaw(this);
				const { has, get } = getProto(target);
				let hadKey = has.call(target, key);
				if (!hadKey) {
					key = toRaw(key);
					hadKey = has.call(target, key);
				}
				const oldValue = get.call(target, key);
				target.set(key, value);
				if (!hadKey) trigger(target, "add", key, value);
				else if (hasChanged(value, oldValue)) trigger(target, "set", key, value, oldValue);
				return this;
			},
			delete(key) {
				const target = toRaw(this);
				const { has, get } = getProto(target);
				let hadKey = has.call(target, key);
				if (!hadKey) {
					key = toRaw(key);
					hadKey = has.call(target, key);
				}
				const oldValue = get ? get.call(target, key) : void 0;
				const result = target.delete(key);
				if (hadKey) trigger(target, "delete", key, void 0, oldValue);
				return result;
			},
			clear() {
				const target = toRaw(this);
				const hadItems = target.size !== 0;
				const oldTarget = void 0;
				const result = target.clear();
				if (hadItems) trigger(target, "clear", void 0, void 0, oldTarget);
				return result;
			}
		});
		[
			"keys",
			"values",
			"entries",
			Symbol.iterator
		].forEach((method) => {
			instrumentations[method] = createIterableMethod(method, readonly, shallow);
		});
		return instrumentations;
	}
	function createInstrumentationGetter(isReadonly2, shallow) {
		const instrumentations = createInstrumentations(isReadonly2, shallow);
		return (target, key, receiver) => {
			if (key === "__v_isReactive") return !isReadonly2;
			else if (key === "__v_isReadonly") return isReadonly2;
			else if (key === "__v_raw") return target;
			return Reflect.get(hasOwn(instrumentations, key) && key in target ? instrumentations : target, key, receiver);
		};
	}
	var mutableCollectionHandlers = { get: createInstrumentationGetter(false, false) };
	var shallowCollectionHandlers = { get: createInstrumentationGetter(false, true) };
	var readonlyCollectionHandlers = { get: createInstrumentationGetter(true, false) };
	var reactiveMap = new WeakMap();
	var shallowReactiveMap = new WeakMap();
	var readonlyMap = new WeakMap();
	var shallowReadonlyMap = new WeakMap();
	function targetTypeMap(rawType) {
		switch (rawType) {
			case "Object":
			case "Array": return 1;
			case "Map":
			case "Set":
			case "WeakMap":
			case "WeakSet": return 2;
			default: return 0;
		}
	}
	function reactive(target) {
		if (isReadonly(target)) return target;
		return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
	}
	function shallowReactive(target) {
		return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap);
	}
	function readonly(target) {
		return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap);
	}
	function createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) {
		if (!isObject(target)) return target;
		if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) return target;
		if (target["__v_skip"] || !Object.isExtensible(target)) return target;
		const existingProxy = proxyMap.get(target);
		if (existingProxy) return existingProxy;
		const targetType = targetTypeMap(toRawType(target));
		if (targetType === 0) return target;
		const proxy = new Proxy(target, targetType === 2 ? collectionHandlers : baseHandlers);
		proxyMap.set(target, proxy);
		return proxy;
	}
	function isReactive(value) {
		if (isReadonly(value)) return isReactive(value["__v_raw"]);
		return !!(value && value["__v_isReactive"]);
	}
	function isReadonly(value) {
		return !!(value && value["__v_isReadonly"]);
	}
	function isShallow(value) {
		return !!(value && value["__v_isShallow"]);
	}
	function isProxy(value) {
		return value ? !!value["__v_raw"] : false;
	}
	function toRaw(observed) {
		const raw = observed && observed["__v_raw"];
		return raw ? toRaw(raw) : observed;
	}
	function markRaw(value) {
		if (!hasOwn(value, "__v_skip") && Object.isExtensible(value)) def(value, "__v_skip", true);
		return value;
	}
	var toReactive = (value) => isObject(value) ? reactive(value) : value;
	var toReadonly = (value) => isObject(value) ? readonly(value) : value;
	function isRef(r) {
		return r ? r["__v_isRef"] === true : false;
	}
	function ref(value) {
		return createRef(value, false);
	}
	function shallowRef(value) {
		return createRef(value, true);
	}
	function createRef(rawValue, shallow) {
		if (isRef(rawValue)) return rawValue;
		return new RefImpl(rawValue, shallow);
	}
	var RefImpl = class {
		constructor(value, isShallow2) {
			this.dep = new Dep();
			this["__v_isRef"] = true;
			this["__v_isShallow"] = false;
			this._rawValue = isShallow2 ? value : toRaw(value);
			this._value = isShallow2 ? value : toReactive(value);
			this["__v_isShallow"] = isShallow2;
		}
		get value() {
			this.dep.track();
			return this._value;
		}
		set value(newValue) {
			const oldValue = this._rawValue;
			const useDirectValue = this["__v_isShallow"] || isShallow(newValue) || isReadonly(newValue);
			newValue = useDirectValue ? newValue : toRaw(newValue);
			if (hasChanged(newValue, oldValue)) {
				this._rawValue = newValue;
				this._value = useDirectValue ? newValue : toReactive(newValue);
				this.dep.trigger();
			}
		}
	};
	function unref(ref2) {
		return isRef(ref2) ? ref2.value : ref2;
	}
	var shallowUnwrapHandlers = {
		get: (target, key, receiver) => key === "__v_raw" ? target : unref(Reflect.get(target, key, receiver)),
		set: (target, key, value, receiver) => {
			const oldValue = target[key];
			if (isRef(oldValue) && !isRef(value)) {
				oldValue.value = value;
				return true;
			} else return Reflect.set(target, key, value, receiver);
		}
	};
	function proxyRefs(objectWithRefs) {
		return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers);
	}
	var ComputedRefImpl = class {
		constructor(fn, setter, isSSR) {
			this.fn = fn;
			this.setter = setter;
			this._value = void 0;
			this.dep = new Dep(this);
			this.__v_isRef = true;
			this.deps = void 0;
			this.depsTail = void 0;
			this.flags = 16;
			this.globalVersion = globalVersion - 1;
			this.next = void 0;
			this.effect = this;
			this["__v_isReadonly"] = !setter;
			this.isSSR = isSSR;
		}
		notify() {
			this.flags |= 16;
			if (!(this.flags & 8) && activeSub !== this) {
				batch(this, true);
				return true;
			}
		}
		get value() {
			const link = this.dep.track();
			refreshComputed(this);
			if (link) link.version = this.dep.version;
			return this._value;
		}
		set value(newValue) {
			if (this.setter) this.setter(newValue);
		}
	};
	function computed$1(getterOrOptions, debugOptions, isSSR = false) {
		let getter;
		let setter;
		if (isFunction(getterOrOptions)) getter = getterOrOptions;
		else {
			getter = getterOrOptions.get;
			setter = getterOrOptions.set;
		}
		return new ComputedRefImpl(getter, setter, isSSR);
	}
	var INITIAL_WATCHER_VALUE = {};
	var cleanupMap = new WeakMap();
	var activeWatcher = void 0;
	function onWatcherCleanup(cleanupFn, failSilently = false, owner = activeWatcher) {
		if (owner) {
			let cleanups = cleanupMap.get(owner);
			if (!cleanups) cleanupMap.set(owner, cleanups = []);
			cleanups.push(cleanupFn);
		}
	}
	function watch$1(source, cb, options = EMPTY_OBJ) {
		const { immediate, deep, once, scheduler, augmentJob, call } = options;
		const reactiveGetter = (source2) => {
			if (deep) return source2;
			if (isShallow(source2) || deep === false || deep === 0) return traverse(source2, 1);
			return traverse(source2);
		};
		let effect;
		let getter;
		let cleanup;
		let boundCleanup;
		let forceTrigger = false;
		let isMultiSource = false;
		if (isRef(source)) {
			getter = () => source.value;
			forceTrigger = isShallow(source);
		} else if (isReactive(source)) {
			getter = () => reactiveGetter(source);
			forceTrigger = true;
		} else if (isArray(source)) {
			isMultiSource = true;
			forceTrigger = source.some((s) => isReactive(s) || isShallow(s));
			getter = () => source.map((s) => {
				if (isRef(s)) return s.value;
				else if (isReactive(s)) return reactiveGetter(s);
				else if (isFunction(s)) return call ? call(s, 2) : s();
			});
		} else if (isFunction(source)) {
			if (cb) getter = call ? () => call(source, 2) : source;
			else getter = () => {
				if (cleanup) {
					pauseTracking();
					try {
						cleanup();
					} finally {
						resetTracking();
					}
				}
				const currentEffect = activeWatcher;
				activeWatcher = effect;
				try {
					return call ? call(source, 3, [boundCleanup]) : source(boundCleanup);
				} finally {
					activeWatcher = currentEffect;
				}
			};
		} else getter = NOOP;
		if (cb && deep) {
			const baseGetter = getter;
			const depth = deep === true ? Infinity : deep;
			getter = () => traverse(baseGetter(), depth);
		}
		const scope = getCurrentScope();
		const watchHandle = () => {
			effect.stop();
			if (scope && scope.active) remove(scope.effects, effect);
		};
		if (once && cb) {
			const _cb = cb;
			cb = (...args) => {
				const res = _cb(...args);
				watchHandle();
				return res;
			};
		}
		let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE;
		const job = (immediateFirstRun) => {
			if (!(effect.flags & 1) || !effect.dirty && !immediateFirstRun) return;
			if (cb) {
				const newValue = effect.run();
				if (immediateFirstRun || deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => hasChanged(v, oldValue[i])) : hasChanged(newValue, oldValue))) {
					if (cleanup) cleanup();
					const currentWatcher = activeWatcher;
					activeWatcher = effect;
					try {
						const args = [
							newValue,
							oldValue === INITIAL_WATCHER_VALUE ? void 0 : isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE ? [] : oldValue,
							boundCleanup
						];
						oldValue = newValue;
						call ? call(cb, 3, args) : cb(...args);
					} finally {
						activeWatcher = currentWatcher;
					}
				}
			} else effect.run();
		};
		if (augmentJob) augmentJob(job);
		effect = new ReactiveEffect(getter);
		effect.scheduler = scheduler ? () => scheduler(job, false) : job;
		boundCleanup = (fn) => onWatcherCleanup(fn, false, effect);
		cleanup = effect.onStop = () => {
			const cleanups = cleanupMap.get(effect);
			if (cleanups) {
				if (call) call(cleanups, 4);
				else for (const cleanup2 of cleanups) cleanup2();
				cleanupMap.delete(effect);
			}
		};
		if (cb) {
			if (immediate) job(true);
			else oldValue = effect.run();
		} else if (scheduler) scheduler(job.bind(null, true), true);
		else effect.run();
		watchHandle.pause = effect.pause.bind(effect);
		watchHandle.resume = effect.resume.bind(effect);
		watchHandle.stop = watchHandle;
		return watchHandle;
	}
	function traverse(value, depth = Infinity, seen) {
		if (depth <= 0 || !isObject(value) || value["__v_skip"]) return value;
		seen = seen || new Map();
		if ((seen.get(value) || 0) >= depth) return value;
		seen.set(value, depth);
		depth--;
		if (isRef(value)) traverse(value.value, depth, seen);
		else if (isArray(value)) for (let i = 0; i < value.length; i++) traverse(value[i], depth, seen);
		else if (isSet(value) || isMap(value)) value.forEach((v) => {
			traverse(v, depth, seen);
		});
		else if (isPlainObject(value)) {
			for (const key in value) traverse(value[key], depth, seen);
			for (const key of Object.getOwnPropertySymbols(value)) if (Object.prototype.propertyIsEnumerable.call(value, key)) traverse(value[key], depth, seen);
		}
		return value;
	}
	function callWithErrorHandling(fn, instance, type, args) {
		try {
			return args ? fn(...args) : fn();
		} catch (err) {
			handleError(err, instance, type);
		}
	}
	function callWithAsyncErrorHandling(fn, instance, type, args) {
		if (isFunction(fn)) {
			const res = callWithErrorHandling(fn, instance, type, args);
			if (res && isPromise(res)) res.catch((err) => {
				handleError(err, instance, type);
			});
			return res;
		}
		if (isArray(fn)) {
			const values = [];
			for (let i = 0; i < fn.length; i++) values.push(callWithAsyncErrorHandling(fn[i], instance, type, args));
			return values;
		}
	}
	function handleError(err, instance, type, throwInDev = true) {
		const contextVNode = instance ? instance.vnode : null;
		const { errorHandler, throwUnhandledErrorInProduction } = instance && instance.appContext.config || EMPTY_OBJ;
		if (instance) {
			let cur = instance.parent;
			const exposedInstance = instance.proxy;
			const errorInfo = `https://vuejs.org/error-reference/#runtime-${type}`;
			while (cur) {
				const errorCapturedHooks = cur.ec;
				if (errorCapturedHooks) {
					for (let i = 0; i < errorCapturedHooks.length; i++) if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) return;
				}
				cur = cur.parent;
			}
			if (errorHandler) {
				pauseTracking();
				callWithErrorHandling(errorHandler, null, 10, [
					err,
					exposedInstance,
					errorInfo
				]);
				resetTracking();
				return;
			}
		}
		logError(err, type, contextVNode, throwInDev, throwUnhandledErrorInProduction);
	}
	function logError(err, type, contextVNode, throwInDev = true, throwInProd = false) {
		if (throwInProd) throw err;
		else console.error(err);
	}
	var queue = [];
	var flushIndex = -1;
	var pendingPostFlushCbs = [];
	var activePostFlushCbs = null;
	var postFlushIndex = 0;
	var resolvedPromise = Promise.resolve();
	var currentFlushPromise = null;
	function nextTick(fn) {
		const p = currentFlushPromise || resolvedPromise;
		return fn ? p.then(this ? fn.bind(this) : fn) : p;
	}
	function findInsertionIndex(id) {
		let start = flushIndex + 1;
		let end = queue.length;
		while (start < end) {
			const middle = start + end >>> 1;
			const middleJob = queue[middle];
			const middleJobId = getId(middleJob);
			if (middleJobId < id || middleJobId === id && middleJob.flags & 2) start = middle + 1;
			else end = middle;
		}
		return start;
	}
	function queueJob(job) {
		if (!(job.flags & 1)) {
			const jobId = getId(job);
			const lastJob = queue[queue.length - 1];
			if (!lastJob || !(job.flags & 2) && jobId >= getId(lastJob)) queue.push(job);
			else queue.splice(findInsertionIndex(jobId), 0, job);
			job.flags |= 1;
			queueFlush();
		}
	}
	function queueFlush() {
		if (!currentFlushPromise) currentFlushPromise = resolvedPromise.then(flushJobs);
	}
	function queuePostFlushCb(cb) {
		if (!isArray(cb)) {
			if (activePostFlushCbs && cb.id === -1) activePostFlushCbs.splice(postFlushIndex + 1, 0, cb);
			else if (!(cb.flags & 1)) {
				pendingPostFlushCbs.push(cb);
				cb.flags |= 1;
			}
		} else for (let i = 0; i < cb.length; i++) pendingPostFlushCbs.push(cb[i]);
		queueFlush();
	}
	function flushPreFlushCbs(instance, seen, i = flushIndex + 1) {
		for (; i < queue.length; i++) {
			const cb = queue[i];
			if (cb && cb.flags & 2) {
				if (instance && cb.id !== instance.uid) continue;
				queue.splice(i, 1);
				i--;
				if (cb.flags & 4) cb.flags &= -2;
				cb();
				if (!(cb.flags & 4)) cb.flags &= -2;
			}
		}
	}
	function flushPostFlushCbs(seen) {
		if (pendingPostFlushCbs.length) {
			const deduped = [...new Set(pendingPostFlushCbs)].sort((a, b) => getId(a) - getId(b));
			pendingPostFlushCbs.length = 0;
			if (activePostFlushCbs) {
				for (let i = 0; i < deduped.length; i++) activePostFlushCbs.push(deduped[i]);
				return;
			}
			activePostFlushCbs = deduped;
			for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) {
				const cb = activePostFlushCbs[postFlushIndex];
				if (cb.flags & 4) cb.flags &= -2;
				if (!(cb.flags & 8)) cb();
				cb.flags &= -2;
			}
			activePostFlushCbs = null;
			postFlushIndex = 0;
		}
	}
	var getId = (job) => job.id == null ? job.flags & 2 ? -1 : Infinity : job.id;
	function flushJobs(seen) {
		try {
			for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {
				const job = queue[flushIndex];
				if (job && !(job.flags & 8)) {
					if (job.flags & 4) job.flags &= -2;
					callWithErrorHandling(job, job.i, job.i ? 15 : 14);
					if (!(job.flags & 4)) job.flags &= -2;
				}
			}
		} finally {
			for (; flushIndex < queue.length; flushIndex++) {
				const job = queue[flushIndex];
				if (job) job.flags &= -2;
			}
			flushIndex = -1;
			queue.length = 0;
			flushPostFlushCbs(seen);
			currentFlushPromise = null;
			if (queue.length || pendingPostFlushCbs.length) flushJobs(seen);
		}
	}
	var currentRenderingInstance = null;
	var currentScopeId = null;
	function setCurrentRenderingInstance(instance) {
		const prev = currentRenderingInstance;
		currentRenderingInstance = instance;
		currentScopeId = instance && instance.type.__scopeId || null;
		return prev;
	}
	function withCtx(fn, ctx = currentRenderingInstance, isNonScopedSlot) {
		if (!ctx) return fn;
		if (fn._n) return fn;
		const renderFnWithContext = (...args) => {
			if (renderFnWithContext._d) setBlockTracking(-1);
			const prevInstance = setCurrentRenderingInstance(ctx);
			const prevStackSize = blockStack.length;
			let res;
			try {
				res = fn(...args);
			} finally {
				for (let i = blockStack.length; i > prevStackSize; i--) closeBlock();
				setCurrentRenderingInstance(prevInstance);
				if (renderFnWithContext._d) setBlockTracking(1);
			}
			return res;
		};
		renderFnWithContext._n = true;
		renderFnWithContext._c = true;
		renderFnWithContext._d = true;
		return renderFnWithContext;
	}
	function withDirectives(vnode, directives) {
		if (currentRenderingInstance === null) return vnode;
		const instance = getComponentPublicInstance(currentRenderingInstance);
		const bindings = vnode.dirs || (vnode.dirs = []);
		for (let i = 0; i < directives.length; i++) {
			let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i];
			if (dir) {
				if (isFunction(dir)) dir = {
					mounted: dir,
					updated: dir
				};
				if (dir.deep) traverse(value);
				bindings.push({
					dir,
					instance,
					value,
					oldValue: void 0,
					arg,
					modifiers
				});
			}
		}
		return vnode;
	}
	function invokeDirectiveHook(vnode, prevVNode, instance, name) {
		const bindings = vnode.dirs;
		const oldBindings = prevVNode && prevVNode.dirs;
		for (let i = 0; i < bindings.length; i++) {
			const binding = bindings[i];
			if (oldBindings) binding.oldValue = oldBindings[i].value;
			let hook = binding.dir[name];
			if (hook) {
				pauseTracking();
				callWithAsyncErrorHandling(hook, instance, 8, [
					vnode.el,
					binding,
					vnode,
					prevVNode
				]);
				resetTracking();
			}
		}
	}
	function provide(key, value) {
		if (currentInstance) {
			let provides = currentInstance.provides;
			const parentProvides = currentInstance.parent && currentInstance.parent.provides;
			if (parentProvides === provides) provides = currentInstance.provides = Object.create(parentProvides);
			provides[key] = value;
		}
	}
	function inject(key, defaultValue, treatDefaultAsFactory = false) {
		const instance = getCurrentInstance();
		if (instance || currentApp) {
			let provides = currentApp ? currentApp._context.provides : instance ? instance.parent == null || instance.ce ? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides : void 0;
			if (provides && key in provides) return provides[key];
			else if (arguments.length > 1) return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance && instance.proxy) : defaultValue;
		}
	}
	var ssrContextKey = Symbol.for("v-scx");
	var useSSRContext = () => {
		{
			const ctx = inject(ssrContextKey);
			if (!ctx) {}
			return ctx;
		}
	};
	function watchEffect(effect, options) {
		return doWatch(effect, null, options);
	}
	function watch(source, cb, options) {
		return doWatch(source, cb, options);
	}
	function doWatch(source, cb, options = EMPTY_OBJ) {
		const { immediate, deep, flush, once } = options;
		const baseWatchOptions = extend({}, options);
		const runsImmediately = cb && immediate || !cb && flush !== "post";
		let ssrCleanup;
		if (isInSSRComponentSetup) {
			if (flush === "sync") {
				const ctx = useSSRContext();
				ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = []);
			} else if (!runsImmediately) {
				const watchStopHandle = () => {};
				watchStopHandle.stop = NOOP;
				watchStopHandle.resume = NOOP;
				watchStopHandle.pause = NOOP;
				return watchStopHandle;
			}
		}
		const instance = currentInstance;
		baseWatchOptions.call = (fn, type, args) => callWithAsyncErrorHandling(fn, instance, type, args);
		let isPre = false;
		if (flush === "post") baseWatchOptions.scheduler = (job) => {
			queuePostRenderEffect(job, instance && instance.suspense);
		};
		else if (flush !== "sync") {
			isPre = true;
			baseWatchOptions.scheduler = (job, isFirstRun) => {
				if (isFirstRun) job();
				else queueJob(job);
			};
		}
		baseWatchOptions.augmentJob = (job) => {
			if (cb) job.flags |= 4;
			if (isPre) {
				job.flags |= 2;
				if (instance) {
					job.id = instance.uid;
					job.i = instance;
				}
			}
		};
		const watchHandle = watch$1(source, cb, baseWatchOptions);
		if (isInSSRComponentSetup) {
			if (ssrCleanup) ssrCleanup.push(watchHandle);
			else if (runsImmediately) watchHandle();
		}
		return watchHandle;
	}
	function instanceWatch(source, value, options) {
		const publicThis = this.proxy;
		const getter = isString(source) ? source.includes(".") ? createPathGetter(publicThis, source) : () => publicThis[source] : source.bind(publicThis, publicThis);
		let cb;
		if (isFunction(value)) cb = value;
		else {
			cb = value.handler;
			options = value;
		}
		const reset = setCurrentInstance(this);
		const res = doWatch(getter, cb.bind(publicThis), options);
		reset();
		return res;
	}
	function createPathGetter(ctx, path) {
		const segments = path.split(".");
		return () => {
			let cur = ctx;
			for (let i = 0; i < segments.length && cur; i++) cur = cur[segments[i]];
			return cur;
		};
	}
	var TeleportEndKey = Symbol("_vte");
	var isTeleport = (type) => type.__isTeleport;
	var leaveCbKey = Symbol("_leaveCb");
	function findNonCommentChild(children) {
		let child = children[0];
		if (children.length > 1) {
			for (const c of children) if (c.type !== Comment) {
				child = c;
				break;
			}
		}
		return child;
	}
	function getInnerChild$1(vnode) {
		if (!isKeepAlive(vnode)) {
			if (isTeleport(vnode.type) && vnode.children) return findNonCommentChild(vnode.children);
			return vnode;
		}
		if (vnode.component) return vnode.component.subTree;
		const { shapeFlag, children } = vnode;
		if (children) {
			if (shapeFlag & 16) return children[0];
			if (shapeFlag & 32 && isFunction(children.default)) return children.default();
		}
	}
	function setTransitionHooks(vnode, hooks) {
		if (vnode.shapeFlag & 6 && vnode.component) {
			vnode.transition = hooks;
			const subTree = vnode.component.subTree;
			setTransitionHooks(isTeleport(subTree.type) ? getInnerChild$1(subTree) || subTree : subTree, hooks);
		} else if (vnode.shapeFlag & 128) {
			vnode.ssContent.transition = hooks.clone(vnode.ssContent);
			vnode.ssFallback.transition = hooks.clone(vnode.ssFallback);
		} else vnode.transition = hooks;
	}
	function defineComponent(options, extraOptions) {
		return isFunction(options) ? (() => extend({ name: options.name }, extraOptions, { setup: options }))() : options;
	}
	function markAsyncBoundary(instance) {
		instance.ids = [
			instance.ids[0] + instance.ids[2]++ + "-",
			0,
			0
		];
	}
	function isTemplateRefKey(refs, key) {
		let desc;
		return !!((desc = Object.getOwnPropertyDescriptor(refs, key)) && !desc.configurable);
	}
	var pendingSetRefMap = new WeakMap();
	function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) {
		if (isArray(rawRef)) {
			rawRef.forEach((r, i) => setRef(r, oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef), parentSuspense, vnode, isUnmount));
			return;
		}
		if (isAsyncWrapper(vnode) && !isUnmount) {
			if (vnode.shapeFlag & 512 && vnode.type.__asyncResolved && vnode.component.subTree.component) setRef(rawRef, oldRawRef, parentSuspense, vnode.component.subTree);
			return;
		}
		const refValue = vnode.shapeFlag & 4 ? getComponentPublicInstance(vnode.component) : vnode.el;
		const value = isUnmount ? null : refValue;
		const { i: owner, r: ref } = rawRef;
		const oldRef = oldRawRef && oldRawRef.r;
		const refs = owner.refs === EMPTY_OBJ ? owner.refs = {} : owner.refs;
		const setupState = owner.setupState;
		const rawSetupState = toRaw(setupState);
		const canSetSetupRef = setupState === EMPTY_OBJ ? NO : (key) => {
			if (isTemplateRefKey(refs, key)) return false;
			return hasOwn(rawSetupState, key);
		};
		const canSetRef = (ref2, key) => {
			if (key && isTemplateRefKey(refs, key)) return false;
			return true;
		};
		if (oldRef != null && oldRef !== ref) {
			invalidatePendingSetRef(oldRawRef);
			if (isString(oldRef)) {
				refs[oldRef] = null;
				if (canSetSetupRef(oldRef)) setupState[oldRef] = null;
			} else if (isRef(oldRef)) {
				const oldRawRefAtom = oldRawRef;
				if (canSetRef(oldRef, oldRawRefAtom.k)) oldRef.value = null;
				if (oldRawRefAtom.k) refs[oldRawRefAtom.k] = null;
			}
		}
		if (isFunction(ref)) callWithErrorHandling(ref, owner, 12, [value, refs]);
		else {
			const _isString = isString(ref);
			const _isRef = isRef(ref);
			if (_isString || _isRef) {
				const doSet = () => {
					if (rawRef.f) {
						const existing = _isString ? canSetSetupRef(ref) ? setupState[ref] : refs[ref] : canSetRef(ref) || !rawRef.k ? ref.value : refs[rawRef.k];
						if (isUnmount) isArray(existing) && remove(existing, refValue);
						else if (!isArray(existing)) {
							if (_isString) {
								refs[ref] = [refValue];
								if (canSetSetupRef(ref)) setupState[ref] = refs[ref];
							} else {
								const newVal = [refValue];
								if (canSetRef(ref, rawRef.k)) ref.value = newVal;
								if (rawRef.k) refs[rawRef.k] = newVal;
							}
						} else if (!existing.includes(refValue)) existing.push(refValue);
					} else if (_isString) {
						refs[ref] = value;
						if (canSetSetupRef(ref)) setupState[ref] = value;
					} else if (_isRef) {
						if (canSetRef(ref, rawRef.k)) ref.value = value;
						if (rawRef.k) refs[rawRef.k] = value;
					}
				};
				if (value) {
					const job = () => {
						doSet();
						pendingSetRefMap.delete(rawRef);
					};
					job.id = -1;
					pendingSetRefMap.set(rawRef, job);
					queuePostRenderEffect(job, parentSuspense);
				} else {
					invalidatePendingSetRef(rawRef);
					doSet();
				}
			}
		}
	}
	function invalidatePendingSetRef(rawRef) {
		const pendingSetRef = pendingSetRefMap.get(rawRef);
		if (pendingSetRef) {
			pendingSetRef.flags |= 8;
			pendingSetRefMap.delete(rawRef);
		}
	}
	getGlobalThis().requestIdleCallback;
	getGlobalThis().cancelIdleCallback;
	var isAsyncWrapper = (i) => !!i.type.__asyncLoader;
	var isKeepAlive = (vnode) => vnode.type.__isKeepAlive;
	function onActivated(hook, target) {
		registerKeepAliveHook(hook, "a", target);
	}
	function onDeactivated(hook, target) {
		registerKeepAliveHook(hook, "da", target);
	}
	function registerKeepAliveHook(hook, type, target = currentInstance) {
		const wrappedHook = hook.__wdc || (hook.__wdc = () => {
			let current = target;
			while (current) {
				if (current.isDeactivated) return;
				current = current.parent;
			}
			return hook();
		});
		injectHook(type, wrappedHook, target);
		if (target) {
			let current = target.parent;
			while (current && current.parent) {
				if (isKeepAlive(current.parent.vnode)) injectToKeepAliveRoot(wrappedHook, type, target, current);
				current = current.parent;
			}
		}
	}
	function injectToKeepAliveRoot(hook, type, target, keepAliveRoot) {
		const injected = injectHook(type, hook, keepAliveRoot, true);
		onUnmounted(() => {
			remove(keepAliveRoot[type], injected);
		}, target);
	}
	function injectHook(type, hook, target = currentInstance, prepend = false) {
		if (target) {
			const hooks = target[type] || (target[type] = []);
			const wrappedHook = hook.__weh || (hook.__weh = (...args) => {
				pauseTracking();
				const reset = setCurrentInstance(target);
				const res = callWithAsyncErrorHandling(hook, target, type, args);
				reset();
				resetTracking();
				return res;
			});
			if (prepend) hooks.unshift(wrappedHook);
			else hooks.push(wrappedHook);
			return wrappedHook;
		}
	}
	var createHook = (lifecycle) => (hook, target = currentInstance) => {
		if (!isInSSRComponentSetup || lifecycle === "sp") injectHook(lifecycle, (...args) => hook(...args), target);
	};
	var onBeforeMount = createHook("bm");
	var onMounted = createHook("m");
	var onBeforeUpdate = createHook("bu");
	var onUpdated = createHook("u");
	var onBeforeUnmount = createHook("bum");
	var onUnmounted = createHook("um");
	var onServerPrefetch = createHook("sp");
	var onRenderTriggered = createHook("rtg");
	var onRenderTracked = createHook("rtc");
	function onErrorCaptured(hook, target = currentInstance) {
		injectHook("ec", hook, target);
	}
	var NULL_DYNAMIC_COMPONENT = Symbol.for("v-ndc");
	function renderList(source, renderItem, cache, index) {
		let ret;
		const cached = cache && cache[index];
		const sourceIsArray = isArray(source);
		if (sourceIsArray || isString(source)) {
			const sourceIsReactiveArray = sourceIsArray && isReactive(source);
			let needsWrap = false;
			let isReadonlySource = false;
			if (sourceIsReactiveArray) {
				needsWrap = !isShallow(source);
				isReadonlySource = isReadonly(source);
				source = shallowReadArray(source);
			}
			ret = new Array(source.length);
			for (let i = 0, l = source.length; i < l; i++) ret[i] = renderItem(needsWrap ? isReadonlySource ? toReadonly(toReactive(source[i])) : toReactive(source[i]) : source[i], i, void 0, cached && cached[i]);
		} else if (typeof source === "number") {
			ret = new Array(source);
			for (let i = 0; i < source; i++) ret[i] = renderItem(i + 1, i, void 0, cached && cached[i]);
		} else if (isObject(source)) {
			if (source[Symbol.iterator]) ret = Array.from(source, (item, i) => renderItem(item, i, void 0, cached && cached[i]));
			else {
				const keys = Object.keys(source);
				ret = new Array(keys.length);
				for (let i = 0, l = keys.length; i < l; i++) {
					const key = keys[i];
					ret[i] = renderItem(source[key], key, i, cached && cached[i]);
				}
			}
		} else ret = [];
		if (cache) cache[index] = ret;
		return ret;
	}
	var getPublicInstance = (i) => {
		if (!i) return null;
		if (isStatefulComponent(i)) return getComponentPublicInstance(i);
		return getPublicInstance(i.parent);
	};
	var publicPropertiesMap = extend(Object.create(null), {
		$: (i) => i,
		$el: (i) => i.vnode.el,
		$data: (i) => i.data,
		$props: (i) => i.props,
		$attrs: (i) => i.attrs,
		$slots: (i) => i.slots,
		$refs: (i) => i.refs,
		$parent: (i) => getPublicInstance(i.parent),
		$root: (i) => getPublicInstance(i.root),
		$host: (i) => i.ce,
		$emit: (i) => i.emit,
		$options: (i) => resolveMergedOptions(i),
		$forceUpdate: (i) => i.f || (i.f = () => {
			queueJob(i.update);
		}),
		$nextTick: (i) => i.n || (i.n = nextTick.bind(i.proxy)),
		$watch: (i) => instanceWatch.bind(i)
	});
	var hasSetupBinding = (state, key) => state !== EMPTY_OBJ && !state.__isScriptSetup && hasOwn(state, key);
	var PublicInstanceProxyHandlers = {
		get({ _: instance }, key) {
			if (key === "__v_skip") return true;
			const { ctx, setupState, data, props, accessCache, type, appContext } = instance;
			if (key[0] !== "$") {
				const n = accessCache[key];
				if (n !== void 0) switch (n) {
					case 1: return setupState[key];
					case 2: return data[key];
					case 4: return ctx[key];
					case 3: return props[key];
				}
				else if (hasSetupBinding(setupState, key)) {
					accessCache[key] = 1;
					return setupState[key];
				} else if (data !== EMPTY_OBJ && hasOwn(data, key)) {
					accessCache[key] = 2;
					return data[key];
				} else if (hasOwn(props, key)) {
					accessCache[key] = 3;
					return props[key];
				} else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {
					accessCache[key] = 4;
					return ctx[key];
				} else if (shouldCacheAccess) accessCache[key] = 0;
			}
			const publicGetter = publicPropertiesMap[key];
			let cssModule, globalProperties;
			if (publicGetter) {
				if (key === "$attrs") track(instance.attrs, "get", "");
				return publicGetter(instance);
			} else if ((cssModule = type.__cssModules) && (cssModule = cssModule[key])) return cssModule;
			else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {
				accessCache[key] = 4;
				return ctx[key];
			} else if (globalProperties = appContext.config.globalProperties, hasOwn(globalProperties, key)) return globalProperties[key];
		},
		set({ _: instance }, key, value) {
			const { data, setupState, ctx } = instance;
			if (hasSetupBinding(setupState, key)) {
				setupState[key] = value;
				return true;
			} else if (data !== EMPTY_OBJ && hasOwn(data, key)) {
				data[key] = value;
				return true;
			} else if (hasOwn(instance.props, key)) return false;
			if (key[0] === "$" && key.slice(1) in instance) return false;
			else ctx[key] = value;
			return true;
		},
		has({ _: { data, setupState, accessCache, ctx, appContext, props, type } }, key) {
			let cssModules;
			return !!(accessCache[key] || data !== EMPTY_OBJ && key[0] !== "$" && hasOwn(data, key) || hasSetupBinding(setupState, key) || hasOwn(props, key) || hasOwn(ctx, key) || hasOwn(publicPropertiesMap, key) || hasOwn(appContext.config.globalProperties, key) || (cssModules = type.__cssModules) && cssModules[key]);
		},
		defineProperty(target, key, descriptor) {
			if (descriptor.get != null) target._.accessCache[key] = 0;
			else if (hasOwn(descriptor, "value")) this.set(target, key, descriptor.value, null);
			return Reflect.defineProperty(target, key, descriptor);
		}
	};
	function normalizePropsOrEmits(props) {
		return isArray(props) ? props.reduce((normalized, p) => (normalized[p] = null, normalized), {}) : props;
	}
	var shouldCacheAccess = true;
	function applyOptions(instance) {
		const options = resolveMergedOptions(instance);
		const publicThis = instance.proxy;
		const ctx = instance.ctx;
		shouldCacheAccess = false;
		if (options.beforeCreate) callHook(options.beforeCreate, instance, "bc");
		const { data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, created, beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, expose, inheritAttrs, components, directives, filters } = options;
		const checkDuplicateProperties = null;
		if (injectOptions) resolveInjections(injectOptions, ctx, checkDuplicateProperties);
		if (methods) for (const key in methods) {
			const methodHandler = methods[key];
			if (isFunction(methodHandler)) ctx[key] = methodHandler.bind(publicThis);
		}
		if (dataOptions) {
			const data = dataOptions.call(publicThis, publicThis);
			if (!isObject(data)) {} else instance.data = reactive(data);
		}
		shouldCacheAccess = true;
		if (computedOptions) for (const key in computedOptions) {
			const opt = computedOptions[key];
			const c = computed({
				get: isFunction(opt) ? opt.bind(publicThis, publicThis) : isFunction(opt.get) ? opt.get.bind(publicThis, publicThis) : NOOP,
				set: !isFunction(opt) && isFunction(opt.set) ? opt.set.bind(publicThis) : NOOP
			});
			Object.defineProperty(ctx, key, {
				enumerable: true,
				configurable: true,
				get: () => c.value,
				set: (v) => c.value = v
			});
		}
		if (watchOptions) for (const key in watchOptions) createWatcher(watchOptions[key], ctx, publicThis, key);
		if (provideOptions) {
			const provides = isFunction(provideOptions) ? provideOptions.call(publicThis) : provideOptions;
			Reflect.ownKeys(provides).forEach((key) => {
				provide(key, provides[key]);
			});
		}
		if (created) callHook(created, instance, "c");
		function registerLifecycleHook(register, hook) {
			if (isArray(hook)) hook.forEach((_hook) => register(_hook.bind(publicThis)));
			else if (hook) register(hook.bind(publicThis));
		}
		registerLifecycleHook(onBeforeMount, beforeMount);
		registerLifecycleHook(onMounted, mounted);
		registerLifecycleHook(onBeforeUpdate, beforeUpdate);
		registerLifecycleHook(onUpdated, updated);
		registerLifecycleHook(onActivated, activated);
		registerLifecycleHook(onDeactivated, deactivated);
		registerLifecycleHook(onErrorCaptured, errorCaptured);
		registerLifecycleHook(onRenderTracked, renderTracked);
		registerLifecycleHook(onRenderTriggered, renderTriggered);
		registerLifecycleHook(onBeforeUnmount, beforeUnmount);
		registerLifecycleHook(onUnmounted, unmounted);
		registerLifecycleHook(onServerPrefetch, serverPrefetch);
		if (isArray(expose)) {
			if (expose.length) {
				const exposed = instance.exposed || (instance.exposed = {});
				expose.forEach((key) => {
					Object.defineProperty(exposed, key, {
						get: () => publicThis[key],
						set: (val) => publicThis[key] = val,
						enumerable: true
					});
				});
			} else if (!instance.exposed) instance.exposed = {};
		}
		if (render && instance.render === NOOP) instance.render = render;
		if (inheritAttrs != null) instance.inheritAttrs = inheritAttrs;
		if (components) instance.components = components;
		if (directives) instance.directives = directives;
		if (serverPrefetch) markAsyncBoundary(instance);
	}
	function resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) {
		if (isArray(injectOptions)) injectOptions = normalizeInject(injectOptions);
		for (const key in injectOptions) {
			const opt = injectOptions[key];
			let injected;
			if (isObject(opt)) {
				if ("default" in opt) injected = inject(opt.from || key, opt.default, true);
				else injected = inject(opt.from || key);
			} else injected = inject(opt);
			if (isRef(injected)) Object.defineProperty(ctx, key, {
				enumerable: true,
				configurable: true,
				get: () => injected.value,
				set: (v) => injected.value = v
			});
			else ctx[key] = injected;
		}
	}
	function callHook(hook, instance, type) {
		callWithAsyncErrorHandling(isArray(hook) ? hook.map((h) => h.bind(instance.proxy)) : hook.bind(instance.proxy), instance, type);
	}
	function createWatcher(raw, ctx, publicThis, key) {
		let getter = key.includes(".") ? createPathGetter(publicThis, key) : () => publicThis[key];
		if (isString(raw)) {
			const handler = ctx[raw];
			if (isFunction(handler)) watch(getter, handler);
		} else if (isFunction(raw)) watch(getter, raw.bind(publicThis));
		else if (isObject(raw)) {
			if (isArray(raw)) raw.forEach((r) => createWatcher(r, ctx, publicThis, key));
			else {
				const handler = isFunction(raw.handler) ? raw.handler.bind(publicThis) : ctx[raw.handler];
				if (isFunction(handler)) watch(getter, handler, raw);
			}
		}
	}
	function resolveMergedOptions(instance) {
		const base = instance.type;
		const { mixins, extends: extendsOptions } = base;
		const { mixins: globalMixins, optionsCache: cache, config: { optionMergeStrategies } } = instance.appContext;
		const cached = cache.get(base);
		let resolved;
		if (cached) resolved = cached;
		else if (!globalMixins.length && !mixins && !extendsOptions) resolved = base;
		else {
			resolved = {};
			if (globalMixins.length) globalMixins.forEach((m) => mergeOptions(resolved, m, optionMergeStrategies, true));
			mergeOptions(resolved, base, optionMergeStrategies);
		}
		if (isObject(base)) cache.set(base, resolved);
		return resolved;
	}
	function mergeOptions(to, from, strats, asMixin = false) {
		const { mixins, extends: extendsOptions } = from;
		if (extendsOptions) mergeOptions(to, extendsOptions, strats, true);
		if (mixins) mixins.forEach((m) => mergeOptions(to, m, strats, true));
		for (const key in from) if (asMixin && key === "expose") {} else {
			const strat = internalOptionMergeStrats[key] || strats && strats[key];
			to[key] = strat ? strat(to[key], from[key]) : from[key];
		}
		return to;
	}
	var internalOptionMergeStrats = {
		data: mergeDataFn,
		props: mergeEmitsOrPropsOptions,
		emits: mergeEmitsOrPropsOptions,
		methods: mergeObjectOptions,
		computed: mergeObjectOptions,
		beforeCreate: mergeAsArray,
		created: mergeAsArray,
		beforeMount: mergeAsArray,
		mounted: mergeAsArray,
		beforeUpdate: mergeAsArray,
		updated: mergeAsArray,
		beforeDestroy: mergeAsArray,
		beforeUnmount: mergeAsArray,
		destroyed: mergeAsArray,
		unmounted: mergeAsArray,
		activated: mergeAsArray,
		deactivated: mergeAsArray,
		errorCaptured: mergeAsArray,
		serverPrefetch: mergeAsArray,
		components: mergeObjectOptions,
		directives: mergeObjectOptions,
		watch: mergeWatchOptions,
		provide: mergeDataFn,
		inject: mergeInject
	};
	function mergeDataFn(to, from) {
		if (!from) return to;
		if (!to) return from;
		return function mergedDataFn() {
			return extend(isFunction(to) ? to.call(this, this) : to, isFunction(from) ? from.call(this, this) : from);
		};
	}
	function mergeInject(to, from) {
		return mergeObjectOptions(normalizeInject(to), normalizeInject(from));
	}
	function normalizeInject(raw) {
		if (isArray(raw)) {
			const res = {};
			for (let i = 0; i < raw.length; i++) res[raw[i]] = raw[i];
			return res;
		}
		return raw;
	}
	function mergeAsArray(to, from) {
		return to ? [...new Set([].concat(to, from))] : from;
	}
	function mergeObjectOptions(to, from) {
		return to ? extend(Object.create(null), to, from) : from;
	}
	function mergeEmitsOrPropsOptions(to, from) {
		if (to) {
			if (isArray(to) && isArray(from)) return [...new Set([...to, ...from])];
			return extend(Object.create(null), normalizePropsOrEmits(to), normalizePropsOrEmits(from != null ? from : {}));
		} else return from;
	}
	function mergeWatchOptions(to, from) {
		if (!to) return from;
		if (!from) return to;
		const merged = extend(Object.create(null), to);
		for (const key in from) merged[key] = mergeAsArray(to[key], from[key]);
		return merged;
	}
	function createAppContext() {
		return {
			app: null,
			config: {
				isNativeTag: NO,
				performance: false,
				globalProperties: {},
				optionMergeStrategies: {},
				errorHandler: void 0,
				warnHandler: void 0,
				compilerOptions: {}
			},
			mixins: [],
			components: {},
			directives: {},
			provides: Object.create(null),
			optionsCache: new WeakMap(),
			propsCache: new WeakMap(),
			emitsCache: new WeakMap()
		};
	}
	var uid$1 = 0;
	function createAppAPI(render, hydrate) {
		return function createApp(rootComponent, rootProps = null) {
			if (!isFunction(rootComponent)) rootComponent = extend({}, rootComponent);
			if (rootProps != null && !isObject(rootProps)) rootProps = null;
			const context = createAppContext();
			const installedPlugins = new WeakSet();
			const pluginCleanupFns = [];
			let isMounted = false;
			const app = context.app = {
				_uid: uid$1++,
				_component: rootComponent,
				_props: rootProps,
				_container: null,
				_context: context,
				_instance: null,
				version: version$1,
				get config() {
					return context.config;
				},
				set config(v) {},
				use(plugin, ...options) {
					if (installedPlugins.has(plugin)) {} else if (plugin && isFunction(plugin.install)) {
						installedPlugins.add(plugin);
						plugin.install(app, ...options);
					} else if (isFunction(plugin)) {
						installedPlugins.add(plugin);
						plugin(app, ...options);
					}
					return app;
				},
				mixin(mixin) {
					if (!context.mixins.includes(mixin)) context.mixins.push(mixin);
					return app;
				},
				component(name, component) {
					if (!component) return context.components[name];
					context.components[name] = component;
					return app;
				},
				directive(name, directive) {
					if (!directive) return context.directives[name];
					context.directives[name] = directive;
					return app;
				},
				mount(rootContainer, isHydrate, namespace) {
					if (!isMounted) {
						const vnode = app._ceVNode || createVNode(rootComponent, rootProps);
						vnode.appContext = context;
						if (namespace === true) namespace = "svg";
						else if (namespace === false) namespace = void 0;
						if (isHydrate && hydrate) hydrate(vnode, rootContainer);
						else render(vnode, rootContainer, namespace);
						isMounted = true;
						app._container = rootContainer;
						rootContainer.__vue_app__ = app;
						return getComponentPublicInstance(vnode.component);
					}
				},
				onUnmount(cleanupFn) {
					pluginCleanupFns.push(cleanupFn);
				},
				unmount() {
					if (isMounted) {
						callWithAsyncErrorHandling(pluginCleanupFns, app._instance, 16);
						render(null, app._container);
						delete app._container.__vue_app__;
					}
				},
				provide(key, value) {
					context.provides[key] = value;
					return app;
				},
				runWithContext(fn) {
					const lastApp = currentApp;
					currentApp = app;
					try {
						return fn();
					} finally {
						currentApp = lastApp;
					}
				}
			};
			return app;
		};
	}
	var currentApp = null;
	var getModelModifiers = (props, modelName) => {
		return modelName === "modelValue" || modelName === "model-value" ? props.modelModifiers : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] || props[`${hyphenate(modelName)}Modifiers`];
	};
	function emit(instance, event, ...rawArgs) {
		if (instance.isUnmounted) return;
		const props = instance.vnode.props || EMPTY_OBJ;
		let args = rawArgs;
		const isModelListener = event.startsWith("update:");
		const modifiers = isModelListener && getModelModifiers(props, event.slice(7));
		if (modifiers) {
			if (modifiers.trim) args = rawArgs.map((a) => isString(a) ? a.trim() : a);
			if (modifiers.number) args = args.map(looseToNumber);
		}
		let handlerName;
		let handler = props[handlerName = toHandlerKey(event)] || props[handlerName = toHandlerKey(camelize(event))];
		if (!handler && isModelListener) handler = props[handlerName = toHandlerKey(hyphenate(event))];
		if (handler) callWithAsyncErrorHandling(handler, instance, 6, args);
		const onceHandler = props[handlerName + `Once`];
		if (onceHandler) {
			if (!instance.emitted) instance.emitted = {};
			else if (instance.emitted[handlerName]) return;
			instance.emitted[handlerName] = true;
			callWithAsyncErrorHandling(onceHandler, instance, 6, args);
		}
	}
	var mixinEmitsCache = new WeakMap();
	function normalizeEmitsOptions(comp, appContext, asMixin = false) {
		const cache = asMixin ? mixinEmitsCache : appContext.emitsCache;
		const cached = cache.get(comp);
		if (cached !== void 0) return cached;
		const raw = comp.emits;
		let normalized = {};
		let hasExtends = false;
		if (!isFunction(comp)) {
			const extendEmits = (raw2) => {
				const normalizedFromExtend = normalizeEmitsOptions(raw2, appContext, true);
				if (normalizedFromExtend) {
					hasExtends = true;
					extend(normalized, normalizedFromExtend);
				}
			};
			if (!asMixin && appContext.mixins.length) appContext.mixins.forEach(extendEmits);
			if (comp.extends) extendEmits(comp.extends);
			if (comp.mixins) comp.mixins.forEach(extendEmits);
		}
		if (!raw && !hasExtends) {
			if (isObject(comp)) cache.set(comp, null);
			return null;
		}
		if (isArray(raw)) raw.forEach((key) => normalized[key] = null);
		else extend(normalized, raw);
		if (isObject(comp)) cache.set(comp, normalized);
		return normalized;
	}
	function isEmitListener(options, key) {
		if (!options || !isOn(key)) return false;
		key = key.slice(2);
		key = key === "Once" ? key : key.replace(/Once$/, "");
		return hasOwn(options, key[0].toLowerCase() + key.slice(1)) || hasOwn(options, hyphenate(key)) || hasOwn(options, key);
	}
	function renderComponentRoot(instance) {
		const { type: Component, vnode, proxy, withProxy, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, props, data, setupState, ctx, inheritAttrs } = instance;
		const prev = setCurrentRenderingInstance(instance);
		let result;
		let fallthroughAttrs;
		try {
			if (vnode.shapeFlag & 4) {
				const proxyToUse = withProxy || proxy;
				const thisProxy = proxyToUse;
				result = normalizeVNode(render.call(thisProxy, proxyToUse, renderCache, props, setupState, data, ctx));
				fallthroughAttrs = attrs;
			} else {
				const render2 = Component;
				result = normalizeVNode(render2.length > 1 ? render2(props, {
					attrs,
					slots,
					emit
				}) : render2(props, null));
				fallthroughAttrs = Component.props ? attrs : getFunctionalFallthrough(attrs);
			}
		} catch (err) {
			blockStack.length = 0;
			handleError(err, instance, 1);
			result = createVNode(Comment);
		}
		let root = result;
		if (fallthroughAttrs && inheritAttrs !== false) {
			const keys = Object.keys(fallthroughAttrs);
			const { shapeFlag } = root;
			if (keys.length) {
				if (shapeFlag & 7) {
					if (propsOptions && keys.some(isModelListener)) fallthroughAttrs = filterModelListeners(fallthroughAttrs, propsOptions);
					root = cloneVNode(root, fallthroughAttrs, false, true);
				}
			}
		}
		if (vnode.dirs) {
			root = cloneVNode(root, null, false, true);
			root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs;
		}
		if (vnode.transition) setTransitionHooks(isTeleport(root.type) ? getInnerChild$1(root) || root : root, vnode.transition);
		result = root;
		setCurrentRenderingInstance(prev);
		return result;
	}
	var getFunctionalFallthrough = (attrs) => {
		let res;
		for (const key in attrs) if (key === "class" || key === "style" || isOn(key)) (res || (res = {}))[key] = attrs[key];
		return res;
	};
	var filterModelListeners = (attrs, props) => {
		const res = {};
		for (const key in attrs) if (!isModelListener(key) || !(key.slice(9) in props)) res[key] = attrs[key];
		return res;
	};
	function shouldUpdateComponent(prevVNode, nextVNode, optimized) {
		const { props: prevProps, children: prevChildren, component } = prevVNode;
		const { props: nextProps, children: nextChildren, patchFlag } = nextVNode;
		const emits = component.emitsOptions;
		if (nextVNode.dirs || nextVNode.transition) return true;
		if (optimized && patchFlag >= 0) {
			if (patchFlag & 1024) return true;
			if (patchFlag & 16) {
				if (!prevProps) return !!nextProps;
				return hasPropsChanged(prevProps, nextProps, emits);
			} else if (patchFlag & 8) {
				const dynamicProps = nextVNode.dynamicProps;
				for (let i = 0; i < dynamicProps.length; i++) {
					const key = dynamicProps[i];
					if (hasPropValueChanged(nextProps, prevProps, key) && !isEmitListener(emits, key)) return true;
				}
			}
		} else {
			if (prevChildren || nextChildren) {
				if (!nextChildren || !nextChildren.$stable) return true;
			}
			if (prevProps === nextProps) return false;
			if (!prevProps) return !!nextProps;
			if (!nextProps) return true;
			return hasPropsChanged(prevProps, nextProps, emits);
		}
		return false;
	}
	function hasPropsChanged(prevProps, nextProps, emitsOptions) {
		const nextKeys = Object.keys(nextProps);
		if (nextKeys.length !== Object.keys(prevProps).length) return true;
		for (let i = 0; i < nextKeys.length; i++) {
			const key = nextKeys[i];
			if (hasPropValueChanged(nextProps, prevProps, key) && !isEmitListener(emitsOptions, key)) return true;
		}
		return false;
	}
	function hasPropValueChanged(nextProps, prevProps, key) {
		const nextProp = nextProps[key];
		const prevProp = prevProps[key];
		if (key === "style" && isObject(nextProp) && isObject(prevProp)) return !looseEqual(nextProp, prevProp);
		return nextProp !== prevProp;
	}
	function updateHOCHostEl({ vnode, parent, suspense }, el) {
		while (parent) {
			const root = parent.subTree;
			if (root.suspense && root.suspense.activeBranch === vnode) {
				root.suspense.vnode.el = root.el = el;
				vnode = root;
			}
			if (root === vnode) {
				(vnode = parent.vnode).el = el;
				parent = parent.parent;
			} else break;
		}
		if (suspense && suspense.activeBranch === vnode) suspense.vnode.el = el;
	}
	var internalObjectProto = {};
	var createInternalObject = () => Object.create(internalObjectProto);
	var isInternalObject = (obj) => Object.getPrototypeOf(obj) === internalObjectProto;
	function initProps(instance, rawProps, isStateful, isSSR = false) {
		const props = {};
		const attrs = createInternalObject();
		instance.propsDefaults = Object.create(null);
		setFullProps(instance, rawProps, props, attrs);
		for (const key in instance.propsOptions[0]) if (!(key in props)) props[key] = void 0;
		if (isStateful) instance.props = isSSR ? props : shallowReactive(props);
		else if (!instance.type.props) instance.props = attrs;
		else instance.props = props;
		instance.attrs = attrs;
	}
	function updateProps(instance, rawProps, rawPrevProps, optimized) {
		const { props, attrs, vnode: { patchFlag } } = instance;
		const rawCurrentProps = toRaw(props);
		const [options] = instance.propsOptions;
		let hasAttrsChanged = false;
		if ((optimized || patchFlag > 0) && !(patchFlag & 16)) {
			if (patchFlag & 8) {
				const propsToUpdate = instance.vnode.dynamicProps;
				for (let i = 0; i < propsToUpdate.length; i++) {
					let key = propsToUpdate[i];
					if (isEmitListener(instance.emitsOptions, key)) continue;
					const value = rawProps[key];
					if (options) {
						if (hasOwn(attrs, key)) {
							if (value !== attrs[key]) {
								attrs[key] = value;
								hasAttrsChanged = true;
							}
						} else {
							const camelizedKey = camelize(key);
							props[camelizedKey] = resolvePropValue(options, rawCurrentProps, camelizedKey, value, instance, false);
						}
					} else if (value !== attrs[key]) {
						attrs[key] = value;
						hasAttrsChanged = true;
					}
				}
			}
		} else {
			if (setFullProps(instance, rawProps, props, attrs)) hasAttrsChanged = true;
			let kebabKey;
			for (const key in rawCurrentProps) if (!rawProps || !hasOwn(rawProps, key) && ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey))) {
				if (options) {
					if (rawPrevProps && (rawPrevProps[key] !== void 0 || rawPrevProps[kebabKey] !== void 0)) props[key] = resolvePropValue(options, rawCurrentProps, key, void 0, instance, true);
				} else delete props[key];
			}
			if (attrs !== rawCurrentProps) {
				for (const key in attrs) if (!rawProps || !hasOwn(rawProps, key) && true) {
					delete attrs[key];
					hasAttrsChanged = true;
				}
			}
		}
		if (hasAttrsChanged) trigger(instance.attrs, "set", "");
	}
	function setFullProps(instance, rawProps, props, attrs) {
		const [options, needCastKeys] = instance.propsOptions;
		let hasAttrsChanged = false;
		let rawCastValues;
		if (rawProps) for (let key in rawProps) {
			if (isReservedProp(key)) continue;
			const value = rawProps[key];
			let camelKey;
			if (options && hasOwn(options, camelKey = camelize(key))) {
				if (!needCastKeys || !needCastKeys.includes(camelKey)) props[camelKey] = value;
				else (rawCastValues || (rawCastValues = {}))[camelKey] = value;
			} else if (!isEmitListener(instance.emitsOptions, key)) {
				if (!(key in attrs) || value !== attrs[key]) {
					attrs[key] = value;
					hasAttrsChanged = true;
				}
			}
		}
		if (needCastKeys) {
			const rawCurrentProps = toRaw(props);
			const castValues = rawCastValues || EMPTY_OBJ;
			for (let i = 0; i < needCastKeys.length; i++) {
				const key = needCastKeys[i];
				props[key] = resolvePropValue(options, rawCurrentProps, key, castValues[key], instance, !hasOwn(castValues, key));
			}
		}
		return hasAttrsChanged;
	}
	function resolvePropValue(options, props, key, value, instance, isAbsent) {
		const opt = options[key];
		if (opt != null) {
			const hasDefault = hasOwn(opt, "default");
			if (hasDefault && value === void 0) {
				const defaultValue = opt.default;
				if (opt.type !== Function && !opt.skipFactory && isFunction(defaultValue)) {
					const { propsDefaults } = instance;
					if (key in propsDefaults) value = propsDefaults[key];
					else {
						const reset = setCurrentInstance(instance);
						value = propsDefaults[key] = defaultValue.call(null, props);
						reset();
					}
				} else value = defaultValue;
				if (instance.ce) instance.ce._setProp(key, value);
			}
			if (opt[0]) {
				if (isAbsent && !hasDefault) value = false;
				else if (opt[1] && (value === "" || value === hyphenate(key))) value = true;
			}
		}
		return value;
	}
	var mixinPropsCache = new WeakMap();
	function normalizePropsOptions(comp, appContext, asMixin = false) {
		const cache = asMixin ? mixinPropsCache : appContext.propsCache;
		const cached = cache.get(comp);
		if (cached) return cached;
		const raw = comp.props;
		const normalized = {};
		const needCastKeys = [];
		let hasExtends = false;
		if (!isFunction(comp)) {
			const extendProps = (raw2) => {
				hasExtends = true;
				const [props, keys] = normalizePropsOptions(raw2, appContext, true);
				extend(normalized, props);
				if (keys) needCastKeys.push(...keys);
			};
			if (!asMixin && appContext.mixins.length) appContext.mixins.forEach(extendProps);
			if (comp.extends) extendProps(comp.extends);
			if (comp.mixins) comp.mixins.forEach(extendProps);
		}
		if (!raw && !hasExtends) {
			if (isObject(comp)) cache.set(comp, EMPTY_ARR);
			return EMPTY_ARR;
		}
		if (isArray(raw)) for (let i = 0; i < raw.length; i++) {
			const normalizedKey = camelize(raw[i]);
			if (validatePropName(normalizedKey)) normalized[normalizedKey] = EMPTY_OBJ;
		}
		else if (raw) for (const key in raw) {
			const normalizedKey = camelize(key);
			if (validatePropName(normalizedKey)) {
				const opt = raw[key];
				const prop = normalized[normalizedKey] = isArray(opt) || isFunction(opt) ? { type: opt } : extend({}, opt);
				const propType = prop.type;
				let shouldCast = false;
				let shouldCastTrue = true;
				if (isArray(propType)) for (let index = 0; index < propType.length; ++index) {
					const type = propType[index];
					const typeName = isFunction(type) && type.name;
					if (typeName === "Boolean") {
						shouldCast = true;
						break;
					} else if (typeName === "String") shouldCastTrue = false;
				}
				else shouldCast = isFunction(propType) && propType.name === "Boolean";
				prop[0] = shouldCast;
				prop[1] = shouldCastTrue;
				if (shouldCast || hasOwn(prop, "default")) needCastKeys.push(normalizedKey);
			}
		}
		const res = [normalized, needCastKeys];
		if (isObject(comp)) cache.set(comp, res);
		return res;
	}
	function validatePropName(key) {
		if (key[0] !== "$" && !isReservedProp(key)) return true;
		return false;
	}
	var isInternalKey = (key) => key === "_" || key === "_ctx" || key === "$stable";
	var normalizeSlotValue = (value) => isArray(value) ? value.map(normalizeVNode) : [normalizeVNode(value)];
	var normalizeSlot = (key, rawSlot, ctx) => {
		if (rawSlot._n) return rawSlot;
		const normalized = withCtx((...args) => {
			return normalizeSlotValue(rawSlot(...args));
		}, ctx);
		normalized._c = false;
		return normalized;
	};
	var normalizeObjectSlots = (rawSlots, slots, instance) => {
		const ctx = rawSlots._ctx;
		for (const key in rawSlots) {
			if (isInternalKey(key)) continue;
			const value = rawSlots[key];
			if (isFunction(value)) slots[key] = normalizeSlot(key, value, ctx);
			else if (value != null) {
				const normalized = normalizeSlotValue(value);
				slots[key] = () => normalized;
			}
		}
	};
	var normalizeVNodeSlots = (instance, children) => {
		const normalized = normalizeSlotValue(children);
		instance.slots.default = () => normalized;
	};
	var assignSlots = (slots, children, optimized) => {
		for (const key in children) if (optimized || !isInternalKey(key)) slots[key] = children[key];
	};
	var initSlots = (instance, children, optimized) => {
		const slots = instance.slots = createInternalObject();
		if (instance.vnode.shapeFlag & 32) {
			const type = children._;
			if (type) {
				assignSlots(slots, children, optimized);
				if (optimized) def(slots, "_", type, true);
			} else normalizeObjectSlots(children, slots);
		} else if (children) normalizeVNodeSlots(instance, children);
	};
	var updateSlots = (instance, children, optimized) => {
		const { vnode, slots } = instance;
		let needDeletionCheck = true;
		let deletionComparisonTarget = EMPTY_OBJ;
		if (vnode.shapeFlag & 32) {
			const type = children._;
			if (type) {
				if (optimized && type === 1) needDeletionCheck = false;
				else assignSlots(slots, children, optimized);
			} else {
				needDeletionCheck = !children.$stable;
				normalizeObjectSlots(children, slots);
			}
			deletionComparisonTarget = children;
		} else if (children) {
			normalizeVNodeSlots(instance, children);
			deletionComparisonTarget = { default: 1 };
		}
		if (needDeletionCheck) {
			for (const key in slots) if (!isInternalKey(key) && deletionComparisonTarget[key] == null) delete slots[key];
		}
	};
	var queuePostRenderEffect = queueEffectWithSuspense;
	function createRenderer(options) {
		return baseCreateRenderer(options);
	}
	function baseCreateRenderer(options, createHydrationFns) {
		const target = getGlobalThis();
		target.__VUE__ = true;
		const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, insertStaticContent: hostInsertStaticContent } = options;
		const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, namespace = void 0, slotScopeIds = null, optimized = !!n2.dynamicChildren) => {
			if (n1 === n2) return;
			if (n1 && !isSameVNodeType(n1, n2)) {
				anchor = getNextHostNode(n1);
				unmount(n1, parentComponent, parentSuspense, true);
				n1 = null;
			}
			if (n2.patchFlag === -2) {
				optimized = false;
				n2.dynamicChildren = null;
			}
			const { type, ref, shapeFlag } = n2;
			switch (type) {
				case Text:
					processText(n1, n2, container, anchor);
					break;
				case Comment:
					processCommentNode(n1, n2, container, anchor);
					break;
				case Static:
					if (n1 == null) mountStaticNode(n2, container, anchor, namespace);
					break;
				case Fragment:
					processFragment(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
					break;
				default: if (shapeFlag & 1) processElement(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
				else if (shapeFlag & 6) processComponent(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
				else if (shapeFlag & 64) type.process(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, internals);
				else if (shapeFlag & 128) type.process(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, internals);
			}
			if (ref != null && parentComponent) setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2);
			else if (ref == null && n1 && n1.ref != null) setRef(n1.ref, null, parentSuspense, n1, true);
		};
		const processText = (n1, n2, container, anchor) => {
			if (n1 == null) hostInsert(n2.el = hostCreateText(n2.children), container, anchor);
			else {
				const el = n2.el = n1.el;
				if (n2.children !== n1.children) hostSetText(el, n2.children);
			}
		};
		const processCommentNode = (n1, n2, container, anchor) => {
			if (n1 == null) hostInsert(n2.el = hostCreateComment(n2.children || ""), container, anchor);
			else n2.el = n1.el;
		};
		const mountStaticNode = (n2, container, anchor, namespace) => {
			[n2.el, n2.anchor] = hostInsertStaticContent(n2.children, container, anchor, namespace, n2.el, n2.anchor);
		};
		const moveStaticNode = ({ el, anchor }, container, nextSibling) => {
			let next;
			while (el && el !== anchor) {
				next = hostNextSibling(el);
				hostInsert(el, container, nextSibling);
				el = next;
			}
			hostInsert(anchor, container, nextSibling);
		};
		const removeStaticNode = ({ el, anchor }) => {
			let next;
			while (el && el !== anchor) {
				next = hostNextSibling(el);
				hostRemove(el);
				el = next;
			}
			hostRemove(anchor);
		};
		const processElement = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
			if (n2.type === "svg") namespace = "svg";
			else if (n2.type === "math") namespace = "mathml";
			if (n1 == null) mountElement(n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
			else {
				const customElement = n1.el && n1.el._isVueCE ? n1.el : null;
				try {
					if (customElement) customElement._beginPatch();
					patchElement(n1, n2, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
				} finally {
					if (customElement) customElement._endPatch();
				}
			}
		};
		const mountElement = (vnode, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
			let el;
			let vnodeHook;
			const { props, shapeFlag, transition, dirs } = vnode;
			el = vnode.el = hostCreateElement(vnode.type, namespace, props && props.is, props);
			if (shapeFlag & 8) hostSetElementText(el, vnode.children);
			else if (shapeFlag & 16) mountChildren(vnode.children, el, null, parentComponent, parentSuspense, resolveChildrenNamespace(vnode, namespace), slotScopeIds, optimized);
			if (dirs) invokeDirectiveHook(vnode, null, parentComponent, "created");
			setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent);
			if (props) {
				for (const key in props) if (key !== "value" && !isReservedProp(key)) hostPatchProp(el, key, null, props[key], namespace, parentComponent);
				if ("value" in props) hostPatchProp(el, "value", null, props.value, namespace);
				if (vnodeHook = props.onVnodeBeforeMount) invokeVNodeHook(vnodeHook, parentComponent, vnode);
			}
			if (dirs) invokeDirectiveHook(vnode, null, parentComponent, "beforeMount");
			const needCallTransitionHooks = needTransition(parentSuspense, transition);
			if (needCallTransitionHooks) transition.beforeEnter(el);
			hostInsert(el, container, anchor);
			if ((vnodeHook = props && props.onVnodeMounted) || needCallTransitionHooks || dirs) queuePostRenderEffect(() => {
				try {
					vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);
					needCallTransitionHooks && transition.enter(el);
					dirs && invokeDirectiveHook(vnode, null, parentComponent, "mounted");
				} finally {}
			}, parentSuspense);
		};
		const setScopeId = (el, vnode, scopeId, slotScopeIds, parentComponent) => {
			if (scopeId) hostSetScopeId(el, scopeId);
			if (slotScopeIds) for (let i = 0; i < slotScopeIds.length; i++) hostSetScopeId(el, slotScopeIds[i]);
			if (parentComponent) {
				let subTree = parentComponent.subTree;
				if (vnode === subTree || isSuspense(subTree.type) && (subTree.ssContent === vnode || subTree.ssFallback === vnode)) {
					const parentVNode = parentComponent.vnode;
					setScopeId(el, parentVNode, parentVNode.scopeId, parentVNode.slotScopeIds, parentComponent.parent);
				}
			}
		};
		const mountChildren = (children, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, start = 0) => {
			for (let i = start; i < children.length; i++) {
				const child = children[i] = optimized ? cloneIfMounted(children[i]) : normalizeVNode(children[i]);
				patch(null, child, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
			}
		};
		const patchElement = (n1, n2, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
			const el = n2.el = n1.el;
			let { patchFlag, dynamicChildren, dirs } = n2;
			patchFlag |= n1.patchFlag & 16;
			const oldProps = n1.props || EMPTY_OBJ;
			const newProps = n2.props || EMPTY_OBJ;
			let vnodeHook;
			parentComponent && toggleRecurse(parentComponent, false);
			if (vnodeHook = newProps.onVnodeBeforeUpdate) invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
			if (dirs) invokeDirectiveHook(n2, n1, parentComponent, "beforeUpdate");
			parentComponent && toggleRecurse(parentComponent, true);
			if (dynamicChildren && (!n1.dynamicChildren || n1.dynamicChildren.length !== dynamicChildren.length)) {
				patchFlag = 0;
				optimized = false;
				dynamicChildren = null;
			}
			if (oldProps.innerHTML && newProps.innerHTML == null || oldProps.textContent && newProps.textContent == null) hostSetElementText(el, "");
			if (dynamicChildren) patchBlockChildren(n1.dynamicChildren, dynamicChildren, el, parentComponent, parentSuspense, resolveChildrenNamespace(n2, namespace), slotScopeIds);
			else if (!optimized) patchChildren(n1, n2, el, null, parentComponent, parentSuspense, resolveChildrenNamespace(n2, namespace), slotScopeIds, false);
			if (patchFlag > 0) {
				if (patchFlag & 16) patchProps(el, oldProps, newProps, parentComponent, namespace);
				else {
					if (patchFlag & 2) {
						if (oldProps.class !== newProps.class) hostPatchProp(el, "class", null, newProps.class, namespace);
					}
					if (patchFlag & 4) hostPatchProp(el, "style", oldProps.style, newProps.style, namespace);
					if (patchFlag & 8) {
						const propsToUpdate = n2.dynamicProps;
						for (let i = 0; i < propsToUpdate.length; i++) {
							const key = propsToUpdate[i];
							const prev = oldProps[key];
							const next = newProps[key];
							if (next !== prev || key === "value") hostPatchProp(el, key, prev, next, namespace, parentComponent);
						}
					}
				}
				if (patchFlag & 1) {
					if (n1.children !== n2.children) hostSetElementText(el, n2.children);
				}
			} else if (!optimized && dynamicChildren == null) patchProps(el, oldProps, newProps, parentComponent, namespace);
			if ((vnodeHook = newProps.onVnodeUpdated) || dirs) queuePostRenderEffect(() => {
				vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
				dirs && invokeDirectiveHook(n2, n1, parentComponent, "updated");
			}, parentSuspense);
		};
		const patchBlockChildren = (oldChildren, newChildren, fallbackContainer, parentComponent, parentSuspense, namespace, slotScopeIds) => {
			for (let i = 0; i < newChildren.length; i++) {
				const oldVNode = oldChildren[i];
				const newVNode = newChildren[i];
				const container = oldVNode.el && (oldVNode.type === Fragment || !isSameVNodeType(oldVNode, newVNode) || oldVNode.shapeFlag & 198) ? hostParentNode(oldVNode.el) : fallbackContainer;
				patch(oldVNode, newVNode, container, null, parentComponent, parentSuspense, namespace, slotScopeIds, true);
			}
		};
		const patchProps = (el, oldProps, newProps, parentComponent, namespace) => {
			if (oldProps !== newProps) {
				if (oldProps !== EMPTY_OBJ) {
					for (const key in oldProps) if (!isReservedProp(key) && !(key in newProps)) hostPatchProp(el, key, oldProps[key], null, namespace, parentComponent);
				}
				for (const key in newProps) {
					if (isReservedProp(key)) continue;
					const next = newProps[key];
					const prev = oldProps[key];
					if (next !== prev && key !== "value") hostPatchProp(el, key, prev, next, namespace, parentComponent);
				}
				if ("value" in newProps) hostPatchProp(el, "value", oldProps.value, newProps.value, namespace);
			}
		};
		const processFragment = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
			const fragmentStartAnchor = n2.el = n1 ? n1.el : hostCreateText("");
			const fragmentEndAnchor = n2.anchor = n1 ? n1.anchor : hostCreateText("");
			let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2;
			if (fragmentSlotScopeIds) slotScopeIds = slotScopeIds ? slotScopeIds.concat(fragmentSlotScopeIds) : fragmentSlotScopeIds;
			if (n1 == null) {
				hostInsert(fragmentStartAnchor, container, anchor);
				hostInsert(fragmentEndAnchor, container, anchor);
				mountChildren(n2.children || [], container, fragmentEndAnchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
			} else if (patchFlag > 0 && patchFlag & 64 && dynamicChildren && n1.dynamicChildren && n1.dynamicChildren.length === dynamicChildren.length) {
				patchBlockChildren(n1.dynamicChildren, dynamicChildren, container, parentComponent, parentSuspense, namespace, slotScopeIds);
				if (n2.key != null || parentComponent && n2 === parentComponent.subTree) traverseStaticChildren(n1, n2, true);
			} else patchChildren(n1, n2, container, fragmentEndAnchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
		};
		const processComponent = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
			n2.slotScopeIds = slotScopeIds;
			if (n1 == null) {
				if (n2.shapeFlag & 512) parentComponent.ctx.activate(n2, container, anchor, namespace, optimized);
				else mountComponent(n2, container, anchor, parentComponent, parentSuspense, namespace, optimized);
			} else updateComponent(n1, n2, optimized);
		};
		const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, namespace, optimized) => {
			const instance = initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense);
			if (isKeepAlive(initialVNode)) instance.ctx.renderer = internals;
			setupComponent(instance, false, optimized);
			if (instance.asyncDep) {
				parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect, optimized);
				if (!initialVNode.el) {
					const placeholder = instance.subTree = createVNode(Comment);
					processCommentNode(null, placeholder, container, anchor);
					initialVNode.placeholder = placeholder.el;
				}
			} else setupRenderEffect(instance, initialVNode, container, anchor, parentSuspense, namespace, optimized);
		};
		const updateComponent = (n1, n2, optimized) => {
			const instance = n2.component = n1.component;
			if (shouldUpdateComponent(n1, n2, optimized)) {
				if (instance.asyncDep && !instance.asyncResolved) {
					updateComponentPreRender(instance, n2, optimized);
					return;
				} else {
					instance.next = n2;
					instance.update();
				}
			} else {
				n2.el = n1.el;
				instance.vnode = n2;
			}
		};
		const setupRenderEffect = (instance, initialVNode, container, anchor, parentSuspense, namespace, optimized) => {
			const componentUpdateFn = () => {
				if (!instance.isMounted) {
					let vnodeHook;
					const { el, props } = initialVNode;
					const { bm, m, parent, root, type } = instance;
					const isAsyncWrapperVNode = isAsyncWrapper(initialVNode);
					toggleRecurse(instance, false);
					if (bm) invokeArrayFns(bm);
					if (!isAsyncWrapperVNode && (vnodeHook = props && props.onVnodeBeforeMount)) invokeVNodeHook(vnodeHook, parent, initialVNode);
					toggleRecurse(instance, true);
					if (el && hydrateNode) {
						const hydrateSubTree = () => {
							instance.subTree = renderComponentRoot(instance);
							hydrateNode(el, instance.subTree, instance, parentSuspense, null);
						};
						if (isAsyncWrapperVNode && type.__asyncHydrate) type.__asyncHydrate(el, instance, hydrateSubTree);
						else hydrateSubTree();
					} else {
						if (root.ce && root.ce._hasShadowRoot()) root.ce._injectChildStyle(type, instance.parent ? instance.parent.type : void 0);
						const subTree = instance.subTree = renderComponentRoot(instance);
						patch(null, subTree, container, anchor, instance, parentSuspense, namespace);
						initialVNode.el = subTree.el;
					}
					if (m) queuePostRenderEffect(m, parentSuspense);
					if (!isAsyncWrapperVNode && (vnodeHook = props && props.onVnodeMounted)) {
						const scopedInitialVNode = initialVNode;
						queuePostRenderEffect(() => invokeVNodeHook(vnodeHook, parent, scopedInitialVNode), parentSuspense);
					}
					if (initialVNode.shapeFlag & 256 || parent && isAsyncWrapper(parent.vnode) && parent.vnode.shapeFlag & 256) instance.a && queuePostRenderEffect(instance.a, parentSuspense);
					instance.isMounted = true;
					initialVNode = container = anchor = null;
				} else {
					let { next, bu, u, parent, vnode } = instance;
					{
						const nonHydratedAsyncRoot = locateNonHydratedAsyncRoot(instance);
						if (nonHydratedAsyncRoot) {
							if (next) {
								next.el = vnode.el;
								updateComponentPreRender(instance, next, optimized);
							}
							nonHydratedAsyncRoot.asyncDep.then(() => {
								queuePostRenderEffect(() => {
									if (!instance.isUnmounted) update();
								}, parentSuspense);
							});
							return;
						}
					}
					let originNext = next;
					let vnodeHook;
					toggleRecurse(instance, false);
					if (next) {
						next.el = vnode.el;
						updateComponentPreRender(instance, next, optimized);
					} else next = vnode;
					if (bu) invokeArrayFns(bu);
					if (vnodeHook = next.props && next.props.onVnodeBeforeUpdate) invokeVNodeHook(vnodeHook, parent, next, vnode);
					toggleRecurse(instance, true);
					const nextTree = renderComponentRoot(instance);
					const prevTree = instance.subTree;
					instance.subTree = nextTree;
					patch(prevTree, nextTree, hostParentNode(prevTree.el), getNextHostNode(prevTree), instance, parentSuspense, namespace);
					next.el = nextTree.el;
					if (originNext === null) updateHOCHostEl(instance, nextTree.el);
					if (u) queuePostRenderEffect(u, parentSuspense);
					if (vnodeHook = next.props && next.props.onVnodeUpdated) queuePostRenderEffect(() => invokeVNodeHook(vnodeHook, parent, next, vnode), parentSuspense);
				}
			};
			instance.scope.on();
			const effect = instance.effect = new ReactiveEffect(componentUpdateFn);
			instance.scope.off();
			const update = instance.update = effect.run.bind(effect);
			const job = instance.job = effect.runIfDirty.bind(effect);
			job.i = instance;
			job.id = instance.uid;
			effect.scheduler = () => queueJob(job);
			toggleRecurse(instance, true);
			update();
		};
		const updateComponentPreRender = (instance, nextVNode, optimized) => {
			nextVNode.component = instance;
			const prevProps = instance.vnode.props;
			instance.vnode = nextVNode;
			instance.next = null;
			updateProps(instance, nextVNode.props, prevProps, optimized);
			updateSlots(instance, nextVNode.children, optimized);
			pauseTracking();
			flushPreFlushCbs(instance);
			resetTracking();
		};
		const patchChildren = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized = false) => {
			const c1 = n1 && n1.children;
			const prevShapeFlag = n1 ? n1.shapeFlag : 0;
			const c2 = n2.children;
			const { patchFlag, shapeFlag } = n2;
			if (patchFlag > 0) {
				if (patchFlag & 128) {
					patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
					return;
				} else if (patchFlag & 256) {
					patchUnkeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
					return;
				}
			}
			if (shapeFlag & 8) {
				if (prevShapeFlag & 16) unmountChildren(c1, parentComponent, parentSuspense);
				if (c2 !== c1) hostSetElementText(container, c2);
			} else if (prevShapeFlag & 16) {
				if (shapeFlag & 16) patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
				else unmountChildren(c1, parentComponent, parentSuspense, true);
			} else {
				if (prevShapeFlag & 8) hostSetElementText(container, "");
				if (shapeFlag & 16) mountChildren(c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
			}
		};
		const patchUnkeyedChildren = (c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
			c1 = c1 || EMPTY_ARR;
			c2 = c2 || EMPTY_ARR;
			const oldLength = c1.length;
			const newLength = c2.length;
			const commonLength = Math.min(oldLength, newLength);
			let i = 0;
			for (; i < commonLength; i++) {
				const nextChild = c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]);
				patch(c1[i], nextChild, container, null, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
			}
			if (oldLength > newLength) unmountChildren(c1, parentComponent, parentSuspense, true, false, commonLength);
			else mountChildren(c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, commonLength);
		};
		const patchKeyedChildren = (c1, c2, container, parentAnchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
			let i = 0;
			const l2 = c2.length;
			let e1 = c1.length - 1;
			let e2 = l2 - 1;
			while (i <= e1 && i <= e2) {
				const n1 = c1[i];
				const n2 = c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]);
				if (isSameVNodeType(n1, n2)) patch(n1, n2, container, null, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
				else break;
				i++;
			}
			while (i <= e1 && i <= e2) {
				const n1 = c1[e1];
				const n2 = c2[e2] = optimized ? cloneIfMounted(c2[e2]) : normalizeVNode(c2[e2]);
				if (isSameVNodeType(n1, n2)) patch(n1, n2, container, null, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
				else break;
				e1--;
				e2--;
			}
			if (i > e1) {
				if (i <= e2) {
					const nextPos = e2 + 1;
					const anchor = nextPos < l2 ? c2[nextPos].el : parentAnchor;
					while (i <= e2) {
						patch(null, c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]), container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
						i++;
					}
				}
			} else if (i > e2) while (i <= e1) {
				unmount(c1[i], parentComponent, parentSuspense, true);
				i++;
			}
			else {
				const s1 = i;
				const s2 = i;
				const keyToNewIndexMap = new Map();
				for (i = s2; i <= e2; i++) {
					const nextChild = c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i]);
					if (nextChild.key != null) keyToNewIndexMap.set(nextChild.key, i);
				}
				let j;
				let patched = 0;
				const toBePatched = e2 - s2 + 1;
				let moved = false;
				let maxNewIndexSoFar = 0;
				const newIndexToOldIndexMap = new Array(toBePatched);
				for (i = 0; i < toBePatched; i++) newIndexToOldIndexMap[i] = 0;
				for (i = s1; i <= e1; i++) {
					const prevChild = c1[i];
					if (patched >= toBePatched) {
						unmount(prevChild, parentComponent, parentSuspense, true);
						continue;
					}
					let newIndex;
					if (prevChild.key != null) newIndex = keyToNewIndexMap.get(prevChild.key);
					else for (j = s2; j <= e2; j++) if (newIndexToOldIndexMap[j - s2] === 0 && isSameVNodeType(prevChild, c2[j])) {
						newIndex = j;
						break;
					}
					if (newIndex === void 0) unmount(prevChild, parentComponent, parentSuspense, true);
					else {
						newIndexToOldIndexMap[newIndex - s2] = i + 1;
						if (newIndex >= maxNewIndexSoFar) maxNewIndexSoFar = newIndex;
						else moved = true;
						patch(prevChild, c2[newIndex], container, null, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
						patched++;
					}
				}
				const increasingNewIndexSequence = moved ? getSequence(newIndexToOldIndexMap) : EMPTY_ARR;
				j = increasingNewIndexSequence.length - 1;
				for (i = toBePatched - 1; i >= 0; i--) {
					const nextIndex = s2 + i;
					const nextChild = c2[nextIndex];
					const anchorVNode = c2[nextIndex + 1];
					const anchor = nextIndex + 1 < l2 ? anchorVNode.el || resolveAsyncComponentPlaceholder(anchorVNode) : parentAnchor;
					if (newIndexToOldIndexMap[i] === 0) patch(null, nextChild, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized);
					else if (moved) {
						if (j < 0 || i !== increasingNewIndexSequence[j]) move(nextChild, container, anchor, 2);
						else j--;
					}
				}
			}
		};
		const move = (vnode, container, anchor, moveType, parentSuspense = null) => {
			const { el, type, transition, children, shapeFlag } = vnode;
			if (shapeFlag & 6) {
				move(vnode.component.subTree, container, anchor, moveType);
				return;
			}
			if (shapeFlag & 128) {
				vnode.suspense.move(container, anchor, moveType);
				return;
			}
			if (shapeFlag & 64) {
				type.move(vnode, container, anchor, internals);
				return;
			}
			if (type === Fragment) {
				hostInsert(el, container, anchor);
				for (let i = 0; i < children.length; i++) move(children[i], container, anchor, moveType);
				hostInsert(vnode.anchor, container, anchor);
				return;
			}
			if (type === Static) {
				moveStaticNode(vnode, container, anchor);
				return;
			}
			if (moveType !== 2 && shapeFlag & 1 && transition) {
				if (moveType === 0) {
					if (transition.persisted && !el[leaveCbKey]) hostInsert(el, container, anchor);
					else {
						transition.beforeEnter(el);
						hostInsert(el, container, anchor);
						queuePostRenderEffect(() => transition.enter(el), parentSuspense);
					}
				} else {
					const { leave, delayLeave, afterLeave } = transition;
					const remove2 = () => {
						if (vnode.ctx.isUnmounted) hostRemove(el);
						else hostInsert(el, container, anchor);
					};
					const performLeave = () => {
						const wasLeaving = el._isLeaving || !!el[leaveCbKey];
						if (el._isLeaving) el[leaveCbKey](true);
						if (transition.persisted && !wasLeaving) remove2();
						else leave(el, () => {
							remove2();
							afterLeave && afterLeave();
						});
					};
					if (delayLeave) delayLeave(el, remove2, performLeave);
					else performLeave();
				}
			} else hostInsert(el, container, anchor);
		};
		const unmount = (vnode, parentComponent, parentSuspense, doRemove = false, optimized = false) => {
			const { type, props, ref, children, dynamicChildren, shapeFlag, patchFlag, dirs, cacheIndex, memo } = vnode;
			if (patchFlag === -2) optimized = false;
			if (ref != null) {
				pauseTracking();
				setRef(ref, null, parentSuspense, vnode, true);
				resetTracking();
			}
			if (cacheIndex != null) parentComponent.renderCache[cacheIndex] = void 0;
			if (shapeFlag & 256) {
				parentComponent.ctx.deactivate(vnode);
				return;
			}
			const shouldInvokeDirs = shapeFlag & 1 && dirs;
			const shouldInvokeVnodeHook = !isAsyncWrapper(vnode);
			let vnodeHook;
			if (shouldInvokeVnodeHook && (vnodeHook = props && props.onVnodeBeforeUnmount)) invokeVNodeHook(vnodeHook, parentComponent, vnode);
			if (shapeFlag & 6) unmountComponent(vnode.component, parentSuspense, doRemove);
			else {
				if (shapeFlag & 128) {
					vnode.suspense.unmount(parentSuspense, doRemove);
					return;
				}
				if (shouldInvokeDirs) invokeDirectiveHook(vnode, null, parentComponent, "beforeUnmount");
				if (shapeFlag & 64) vnode.type.remove(vnode, parentComponent, parentSuspense, internals, doRemove);
				else if (dynamicChildren && !dynamicChildren.hasOnce && (type !== Fragment || patchFlag > 0 && patchFlag & 64)) unmountChildren(dynamicChildren, parentComponent, parentSuspense, false, true);
				else if (type === Fragment && patchFlag & 384 || !optimized && shapeFlag & 16) unmountChildren(children, parentComponent, parentSuspense);
				if (doRemove) remove(vnode);
			}
			const shouldInvalidateMemo = memo != null && cacheIndex == null;
			if (shouldInvokeVnodeHook && (vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs || shouldInvalidateMemo) queuePostRenderEffect(() => {
				vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);
				shouldInvokeDirs && invokeDirectiveHook(vnode, null, parentComponent, "unmounted");
				if (shouldInvalidateMemo) vnode.el = null;
			}, parentSuspense);
		};
		const remove = (vnode) => {
			const { type, el, anchor, transition } = vnode;
			if (type === Fragment) {
				removeFragment(el, anchor);
				return;
			}
			if (type === Static) {
				removeStaticNode(vnode);
				return;
			}
			const performRemove = () => {
				hostRemove(el);
				if (transition && !transition.persisted && transition.afterLeave) transition.afterLeave();
			};
			if (vnode.shapeFlag & 1 && transition && !transition.persisted) {
				const { leave, delayLeave } = transition;
				const performLeave = () => leave(el, performRemove);
				if (delayLeave) delayLeave(vnode.el, performRemove, performLeave);
				else performLeave();
			} else performRemove();
		};
		const removeFragment = (cur, end) => {
			let next;
			while (cur !== end) {
				next = hostNextSibling(cur);
				hostRemove(cur);
				cur = next;
			}
			hostRemove(end);
		};
		const unmountComponent = (instance, parentSuspense, doRemove) => {
			const { bum, scope, job, subTree, um, m, a } = instance;
			invalidateMount(m);
			invalidateMount(a);
			if (bum) invokeArrayFns(bum);
			scope.stop();
			if (job) {
				job.flags |= 8;
				unmount(subTree, instance, parentSuspense, doRemove);
			}
			if (um) queuePostRenderEffect(um, parentSuspense);
			queuePostRenderEffect(() => {
				instance.isUnmounted = true;
			}, parentSuspense);
		};
		const unmountChildren = (children, parentComponent, parentSuspense, doRemove = false, optimized = false, start = 0) => {
			for (let i = start; i < children.length; i++) unmount(children[i], parentComponent, parentSuspense, doRemove, optimized);
		};
		const getNextHostNode = (vnode) => {
			if (vnode.shapeFlag & 6) return getNextHostNode(vnode.component.subTree);
			if (vnode.shapeFlag & 128) return vnode.suspense.next();
			const el = hostNextSibling(vnode.anchor || vnode.el);
			const teleportEnd = el && el[TeleportEndKey];
			return teleportEnd ? hostNextSibling(teleportEnd) : el;
		};
		let isFlushing = false;
		const render = (vnode, container, namespace) => {
			let instance;
			if (vnode == null) {
				if (container._vnode) {
					unmount(container._vnode, null, null, true);
					instance = container._vnode.component;
				}
			} else patch(container._vnode || null, vnode, container, null, null, null, namespace);
			container._vnode = vnode;
			if (!isFlushing) {
				isFlushing = true;
				flushPreFlushCbs(instance);
				flushPostFlushCbs();
				isFlushing = false;
			}
		};
		const internals = {
			p: patch,
			um: unmount,
			m: move,
			r: remove,
			mt: mountComponent,
			mc: mountChildren,
			pc: patchChildren,
			pbc: patchBlockChildren,
			n: getNextHostNode,
			o: options
		};
		let hydrate;
		let hydrateNode;
		if (createHydrationFns) [hydrate, hydrateNode] = createHydrationFns(internals);
		return {
			render,
			hydrate,
			createApp: createAppAPI(render, hydrate)
		};
	}
	function resolveChildrenNamespace({ type, props }, currentNamespace) {
		return currentNamespace === "svg" && type === "foreignObject" || currentNamespace === "mathml" && type === "annotation-xml" && props && props.encoding && props.encoding.includes("html") ? void 0 : currentNamespace;
	}
	function toggleRecurse({ effect, job }, allowed) {
		if (allowed) {
			effect.flags |= 32;
			job.flags |= 4;
		} else {
			effect.flags &= -33;
			job.flags &= -5;
		}
	}
	function needTransition(parentSuspense, transition) {
		return (!parentSuspense || parentSuspense && !parentSuspense.pendingBranch) && transition && !transition.persisted;
	}
	function traverseStaticChildren(n1, n2, shallow = false) {
		const ch1 = n1.children;
		const ch2 = n2.children;
		if (isArray(ch1) && isArray(ch2)) for (let i = 0; i < ch1.length; i++) {
			const c1 = ch1[i];
			let c2 = ch2[i];
			if (c2.shapeFlag & 1 && !c2.dynamicChildren) {
				if (c2.patchFlag <= 0 || c2.patchFlag === 32) {
					c2 = ch2[i] = cloneIfMounted(ch2[i]);
					c2.el = c1.el;
				}
				if (!shallow && c2.patchFlag !== -2) traverseStaticChildren(c1, c2);
			}
			if (c2.type === Text) {
				if (c2.patchFlag === -1) c2 = ch2[i] = cloneIfMounted(c2);
				c2.el = c1.el;
			}
			if (c2.type === Comment && !c2.el) c2.el = c1.el;
		}
	}
	function getSequence(arr) {
		const p = arr.slice();
		const result = [0];
		let i, j, u, v, c;
		const len = arr.length;
		for (i = 0; i < len; i++) {
			const arrI = arr[i];
			if (arrI !== 0) {
				j = result[result.length - 1];
				if (arr[j] < arrI) {
					p[i] = j;
					result.push(i);
					continue;
				}
				u = 0;
				v = result.length - 1;
				while (u < v) {
					c = u + v >> 1;
					if (arr[result[c]] < arrI) u = c + 1;
					else v = c;
				}
				if (arrI < arr[result[u]]) {
					if (u > 0) p[i] = result[u - 1];
					result[u] = i;
				}
			}
		}
		u = result.length;
		v = result[u - 1];
		while (u-- > 0) {
			result[u] = v;
			v = p[v];
		}
		return result;
	}
	function locateNonHydratedAsyncRoot(instance) {
		const subComponent = instance.subTree.component;
		if (subComponent) {
			if (subComponent.asyncDep && !subComponent.asyncResolved) return subComponent;
			else return locateNonHydratedAsyncRoot(subComponent);
		}
	}
	function invalidateMount(hooks) {
		if (hooks) for (let i = 0; i < hooks.length; i++) hooks[i].flags |= 8;
	}
	function resolveAsyncComponentPlaceholder(anchorVnode) {
		if (anchorVnode.placeholder) return anchorVnode.placeholder;
		const instance = anchorVnode.component;
		if (instance) return resolveAsyncComponentPlaceholder(instance.subTree);
		return null;
	}
	var isSuspense = (type) => type.__isSuspense;
	function queueEffectWithSuspense(fn, suspense) {
		if (suspense && suspense.pendingBranch) {
			if (isArray(fn)) suspense.effects.push(...fn);
			else suspense.effects.push(fn);
		} else queuePostFlushCb(fn);
	}
	var Fragment = Symbol.for("v-fgt");
	var Text = Symbol.for("v-txt");
	var Comment = Symbol.for("v-cmt");
	var Static = Symbol.for("v-stc");
	var blockStack = [];
	var currentBlock = null;
	function openBlock(disableTracking = false) {
		blockStack.push(currentBlock = disableTracking ? null : []);
	}
	function closeBlock() {
		blockStack.pop();
		currentBlock = blockStack[blockStack.length - 1] || null;
	}
	var isBlockTreeEnabled = 1;
	function setBlockTracking(value, inVOnce = false) {
		isBlockTreeEnabled += value;
		if (value < 0 && currentBlock && inVOnce) currentBlock.hasOnce = true;
	}
	function setupBlock(vnode) {
		vnode.dynamicChildren = isBlockTreeEnabled > 0 ? currentBlock || EMPTY_ARR : null;
		closeBlock();
		if (isBlockTreeEnabled > 0 && currentBlock) currentBlock.push(vnode);
		return vnode;
	}
	function createElementBlock(type, props, children, patchFlag, dynamicProps, shapeFlag) {
		return setupBlock(createBaseVNode(type, props, children, patchFlag, dynamicProps, shapeFlag, true));
	}
	function createBlock(type, props, children, patchFlag, dynamicProps) {
		return setupBlock(createVNode(type, props, children, patchFlag, dynamicProps, true));
	}
	function isVNode(value) {
		return value ? value.__v_isVNode === true : false;
	}
	function isSameVNodeType(n1, n2) {
		return n1.type === n2.type && n1.key === n2.key;
	}
	var normalizeKey = ({ key }) => key != null ? key : null;
	var normalizeRef = ({ ref, ref_key, ref_for }) => {
		if (typeof ref === "number") ref = "" + ref;
		return ref != null ? isString(ref) || isRef(ref) || isFunction(ref) ? {
			i: currentRenderingInstance,
			r: ref,
			k: ref_key,
			f: !!ref_for
		} : ref : null;
	};
	function createBaseVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, shapeFlag = type === Fragment ? 0 : 1, isBlockNode = false, needFullChildrenNormalization = false) {
		const vnode = {
			__v_isVNode: true,
			__v_skip: true,
			type,
			props,
			key: props && normalizeKey(props),
			ref: props && normalizeRef(props),
			scopeId: currentScopeId,
			slotScopeIds: null,
			children,
			component: null,
			suspense: null,
			ssContent: null,
			ssFallback: null,
			dirs: null,
			transition: null,
			el: null,
			anchor: null,
			target: null,
			targetStart: null,
			targetAnchor: null,
			staticCount: 0,
			shapeFlag,
			patchFlag,
			dynamicProps,
			dynamicChildren: null,
			appContext: null,
			ctx: currentRenderingInstance
		};
		if (needFullChildrenNormalization) {
			normalizeChildren(vnode, children);
			if (shapeFlag & 128) type.normalize(vnode);
		} else if (children) vnode.shapeFlag |= isString(children) ? 8 : 16;
		if (isBlockTreeEnabled > 0 && !isBlockNode && currentBlock && (vnode.patchFlag > 0 || shapeFlag & 6) && vnode.patchFlag !== 32) currentBlock.push(vnode);
		return vnode;
	}
	var createVNode = _createVNode;
	function _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false) {
		if (!type || type === NULL_DYNAMIC_COMPONENT) type = Comment;
		if (isVNode(type)) {
			const cloned = cloneVNode(type, props, true);
			if (children) normalizeChildren(cloned, children);
			if (isBlockTreeEnabled > 0 && !isBlockNode && currentBlock) {
				if (cloned.shapeFlag & 6) currentBlock[currentBlock.indexOf(type)] = cloned;
				else currentBlock.push(cloned);
			}
			cloned.patchFlag = -2;
			return cloned;
		}
		if (isClassComponent(type)) type = type.__vccOpts;
		if (props) {
			props = guardReactiveProps(props);
			let { class: klass, style } = props;
			if (klass && !isString(klass)) props.class = normalizeClass(klass);
			if (isObject(style)) {
				if (isProxy(style) && !isArray(style)) style = extend({}, style);
				props.style = normalizeStyle(style);
			}
		}
		const shapeFlag = isString(type) ? 1 : isSuspense(type) ? 128 : isTeleport(type) ? 64 : isObject(type) ? 4 : isFunction(type) ? 2 : 0;
		return createBaseVNode(type, props, children, patchFlag, dynamicProps, shapeFlag, isBlockNode, true);
	}
	function guardReactiveProps(props) {
		if (!props) return null;
		return isProxy(props) || isInternalObject(props) ? extend({}, props) : props;
	}
	function cloneVNode(vnode, extraProps, mergeRef = false, cloneTransition = false) {
		const { props, ref, patchFlag, children, transition } = vnode;
		const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props;
		const cloned = {
			__v_isVNode: true,
			__v_skip: true,
			type: vnode.type,
			props: mergedProps,
			key: mergedProps && normalizeKey(mergedProps),
			ref: extraProps && extraProps.ref ? mergeRef && ref ? isArray(ref) ? ref.concat(normalizeRef(extraProps)) : [ref, normalizeRef(extraProps)] : normalizeRef(extraProps) : ref,
			scopeId: vnode.scopeId,
			slotScopeIds: vnode.slotScopeIds,
			children,
			target: vnode.target,
			targetStart: vnode.targetStart,
			targetAnchor: vnode.targetAnchor,
			staticCount: vnode.staticCount,
			shapeFlag: vnode.shapeFlag,
			patchFlag: extraProps && vnode.type !== Fragment ? patchFlag === -1 ? 16 : patchFlag | 16 : patchFlag,
			dynamicProps: vnode.dynamicProps,
			dynamicChildren: vnode.dynamicChildren,
			appContext: vnode.appContext,
			dirs: vnode.dirs,
			transition,
			component: vnode.component,
			suspense: vnode.suspense,
			ssContent: vnode.ssContent && cloneVNode(vnode.ssContent),
			ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback),
			placeholder: vnode.placeholder,
			el: vnode.el,
			anchor: vnode.anchor,
			ctx: vnode.ctx,
			ce: vnode.ce
		};
		if (transition && cloneTransition) setTransitionHooks(cloned, transition.clone(cloned));
		return cloned;
	}
	function createTextVNode(text = " ", flag = 0) {
		return createVNode(Text, null, text, flag);
	}
	function createCommentVNode(text = "", asBlock = false) {
		return asBlock ? (openBlock(), createBlock(Comment, null, text)) : createVNode(Comment, null, text);
	}
	function normalizeVNode(child) {
		if (child == null || typeof child === "boolean") return createVNode(Comment);
		else if (isArray(child)) return createVNode(Fragment, null, child.slice());
		else if (isVNode(child)) return cloneIfMounted(child);
		else return createVNode(Text, null, String(child));
	}
	function cloneIfMounted(child) {
		return child.el === null && child.patchFlag !== -1 || child.memo ? child : cloneVNode(child);
	}
	function normalizeChildren(vnode, children) {
		let type = 0;
		const { shapeFlag } = vnode;
		if (children == null) children = null;
		else if (isArray(children)) type = 16;
		else if (typeof children === "object") {
			if (shapeFlag & 65) {
				const slot = children.default;
				if (slot) {
					slot._c && (slot._d = false);
					normalizeChildren(vnode, slot());
					slot._c && (slot._d = true);
				}
				return;
			} else {
				type = 32;
				const slotFlag = children._;
				if (!slotFlag && !isInternalObject(children)) children._ctx = currentRenderingInstance;
				else if (slotFlag === 3 && currentRenderingInstance) {
					if (currentRenderingInstance.slots._ === 1) children._ = 1;
					else {
						children._ = 2;
						vnode.patchFlag |= 1024;
					}
				}
			}
		} else if (isFunction(children)) {
			if (shapeFlag & 65) {
				normalizeChildren(vnode, { default: children });
				return;
			}
			children = {
				default: children,
				_ctx: currentRenderingInstance
			};
			type = 32;
		} else {
			children = String(children);
			if (shapeFlag & 64) {
				type = 16;
				children = [createTextVNode(children)];
			} else type = 8;
		}
		vnode.children = children;
		vnode.shapeFlag |= type;
	}
	function mergeProps(...args) {
		const ret = {};
		for (let i = 0; i < args.length; i++) {
			const toMerge = args[i];
			for (const key in toMerge) if (key === "class") {
				if (ret.class !== toMerge.class) ret.class = normalizeClass([ret.class, toMerge.class]);
			} else if (key === "style") ret.style = normalizeStyle([ret.style, toMerge.style]);
			else if (isOn(key)) {
				const existing = ret[key];
				const incoming = toMerge[key];
				if (incoming && existing !== incoming && !(isArray(existing) && existing.includes(incoming))) ret[key] = existing ? [].concat(existing, incoming) : incoming;
				else if (incoming == null && existing == null && !isModelListener(key)) ret[key] = incoming;
			} else if (key !== "") ret[key] = toMerge[key];
		}
		return ret;
	}
	function invokeVNodeHook(hook, instance, vnode, prevVNode = null) {
		callWithAsyncErrorHandling(hook, instance, 7, [vnode, prevVNode]);
	}
	var emptyAppContext = createAppContext();
	var uid = 0;
	function createComponentInstance(vnode, parent, suspense) {
		const type = vnode.type;
		const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
		const instance = {
			uid: uid++,
			vnode,
			type,
			parent,
			appContext,
			root: null,
			next: null,
			subTree: null,
			effect: null,
			update: null,
			job: null,
			scope: new EffectScope(true),
			render: null,
			proxy: null,
			exposed: null,
			exposeProxy: null,
			withProxy: null,
			provides: parent ? parent.provides : Object.create(appContext.provides),
			ids: parent ? parent.ids : [
				"",
				0,
				0
			],
			accessCache: null,
			renderCache: [],
			components: null,
			directives: null,
			propsOptions: normalizePropsOptions(type, appContext),
			emitsOptions: normalizeEmitsOptions(type, appContext),
			emit: null,
			emitted: null,
			propsDefaults: EMPTY_OBJ,
			inheritAttrs: type.inheritAttrs,
			ctx: EMPTY_OBJ,
			data: EMPTY_OBJ,
			props: EMPTY_OBJ,
			attrs: EMPTY_OBJ,
			slots: EMPTY_OBJ,
			refs: EMPTY_OBJ,
			setupState: EMPTY_OBJ,
			setupContext: null,
			suspense,
			suspenseId: suspense ? suspense.pendingId : 0,
			asyncDep: null,
			asyncResolved: false,
			isMounted: false,
			isUnmounted: false,
			isDeactivated: false,
			bc: null,
			c: null,
			bm: null,
			m: null,
			bu: null,
			u: null,
			um: null,
			bum: null,
			da: null,
			a: null,
			rtg: null,
			rtc: null,
			ec: null,
			sp: null
		};
		instance.ctx = { _: instance };
		instance.root = parent ? parent.root : instance;
		instance.emit = emit.bind(null, instance);
		if (vnode.ce) vnode.ce(instance);
		return instance;
	}
	var currentInstance = null;
	var getCurrentInstance = () => currentInstance || currentRenderingInstance;
	var internalSetCurrentInstance;
	var setInSSRSetupState;
	{
		const g = getGlobalThis();
		const registerGlobalSetter = (key, setter) => {
			let setters;
			if (!(setters = g[key])) setters = g[key] = [];
			setters.push(setter);
			return (v) => {
				if (setters.length > 1) setters.forEach((set) => set(v));
				else setters[0](v);
			};
		};
		internalSetCurrentInstance = registerGlobalSetter(`__VUE_INSTANCE_SETTERS__`, (v) => currentInstance = v);
		setInSSRSetupState = registerGlobalSetter(`__VUE_SSR_SETTERS__`, (v) => isInSSRComponentSetup = v);
	}
	var setCurrentInstance = (instance) => {
		const prev = currentInstance;
		internalSetCurrentInstance(instance);
		instance.scope.on();
		return () => {
			instance.scope.off();
			internalSetCurrentInstance(prev);
		};
	};
	var unsetCurrentInstance = () => {
		currentInstance && currentInstance.scope.off();
		internalSetCurrentInstance(null);
	};
	function isStatefulComponent(instance) {
		return instance.vnode.shapeFlag & 4;
	}
	var isInSSRComponentSetup = false;
	function setupComponent(instance, isSSR = false, optimized = false) {
		isSSR && setInSSRSetupState(isSSR);
		const { props, children } = instance.vnode;
		const isStateful = isStatefulComponent(instance);
		initProps(instance, props, isStateful, isSSR);
		initSlots(instance, children, optimized || isSSR);
		const setupResult = isStateful ? setupStatefulComponent(instance, isSSR) : void 0;
		isSSR && setInSSRSetupState(false);
		return setupResult;
	}
	function setupStatefulComponent(instance, isSSR) {
		const Component = instance.type;
		instance.accessCache = Object.create(null);
		instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers);
		const { setup } = Component;
		if (setup) {
			pauseTracking();
			const setupContext = instance.setupContext = setup.length > 1 ? createSetupContext(instance) : null;
			const reset = setCurrentInstance(instance);
			const setupResult = callWithErrorHandling(setup, instance, 0, [instance.props, setupContext]);
			const isAsyncSetup = isPromise(setupResult);
			resetTracking();
			reset();
			if ((isAsyncSetup || instance.sp) && !isAsyncWrapper(instance)) markAsyncBoundary(instance);
			if (isAsyncSetup) {
				setupResult.then(unsetCurrentInstance, unsetCurrentInstance);
				if (isSSR) return setupResult.then((resolvedResult) => {
					setInSSRSetupState(true);
					try {
						handleSetupResult(instance, resolvedResult, isSSR);
					} finally {
						setInSSRSetupState(false);
					}
				}).catch((e) => {
					handleError(e, instance, 0);
				});
				else instance.asyncDep = setupResult;
			} else handleSetupResult(instance, setupResult, isSSR);
		} else finishComponentSetup(instance, isSSR);
	}
	function handleSetupResult(instance, setupResult, isSSR) {
		if (isFunction(setupResult)) {
			if (instance.type.__ssrInlineRender) instance.ssrRender = setupResult;
			else instance.render = setupResult;
		} else if (isObject(setupResult)) instance.setupState = proxyRefs(setupResult);
		finishComponentSetup(instance, isSSR);
	}
	function finishComponentSetup(instance, isSSR, skipOptions) {
		const Component = instance.type;
		if (!instance.render) instance.render = Component.render || NOOP;
		{
			const reset = setCurrentInstance(instance);
			pauseTracking();
			try {
				applyOptions(instance);
			} finally {
				resetTracking();
				reset();
			}
		}
	}
	var attrsProxyHandlers = { get(target, key) {
		track(target, "get", "");
		return target[key];
	} };
	function createSetupContext(instance) {
		const expose = (exposed) => {
			instance.exposed = exposed || {};
		};
		return {
			attrs: new Proxy(instance.attrs, attrsProxyHandlers),
			slots: instance.slots,
			emit: instance.emit,
			expose
		};
	}
	function getComponentPublicInstance(instance) {
		if (instance.exposed) return instance.exposeProxy || (instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {
			get(target, key) {
				if (key in target) return target[key];
				else if (key in publicPropertiesMap) return publicPropertiesMap[key](instance);
			},
			has(target, key) {
				return key in target || key in publicPropertiesMap;
			}
		}));
		else return instance.proxy;
	}
	function isClassComponent(value) {
		return isFunction(value) && "__vccOpts" in value;
	}
	var computed = (getterOrOptions, debugOptions) => {
		return computed$1(getterOrOptions, debugOptions, isInSSRComponentSetup);
	};
	function h(type, propsOrChildren, children) {
		try {
			setBlockTracking(-1);
			const l = arguments.length;
			if (l === 2) {
				if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
					if (isVNode(propsOrChildren)) return createVNode(type, null, [propsOrChildren]);
					return createVNode(type, propsOrChildren);
				} else return createVNode(type, null, propsOrChildren);
			} else {
				if (l > 3) children = Array.prototype.slice.call(arguments, 2);
				else if (l === 3 && isVNode(children)) children = [children];
				return createVNode(type, propsOrChildren, children);
			}
		} finally {
			setBlockTracking(1);
		}
	}
	var version$1 = "3.5.42";
	var policy = void 0;
	var tt = typeof window !== "undefined" && window.trustedTypes;
	if (tt) try {
		policy = tt.createPolicy("vue", { createHTML: (val) => val });
	} catch (e) {}
	var unsafeToTrustedHTML = policy ? (val) => policy.createHTML(val) : (val) => val;
	var svgNS = "http://www.w3.org/2000/svg";
	var mathmlNS = "http://www.w3.org/1998/Math/MathML";
	var doc = typeof document !== "undefined" ? document : null;
	var templateContainer = doc && doc.createElement("template");
	var nodeOps = {
		insert: (child, parent, anchor) => {
			parent.insertBefore(child, anchor || null);
		},
		remove: (child) => {
			const parent = child.parentNode;
			if (parent) parent.removeChild(child);
		},
		createElement: (tag, namespace, is, props) => {
			const el = namespace === "svg" ? doc.createElementNS(svgNS, tag) : namespace === "mathml" ? doc.createElementNS(mathmlNS, tag) : is ? doc.createElement(tag, { is }) : doc.createElement(tag);
			if (tag === "select" && props && props.multiple != null) el.setAttribute("multiple", props.multiple);
			return el;
		},
		createText: (text) => doc.createTextNode(text),
		createComment: (text) => doc.createComment(text),
		setText: (node, text) => {
			node.nodeValue = text;
		},
		setElementText: (el, text) => {
			el.textContent = text;
		},
		parentNode: (node) => node.parentNode,
		nextSibling: (node) => node.nextSibling,
		querySelector: (selector) => doc.querySelector(selector),
		setScopeId(el, id) {
			el.setAttribute(id, "");
		},
		insertStaticContent(content, parent, anchor, namespace, start, end) {
			const before = anchor ? anchor.previousSibling : parent.lastChild;
			if (start && (start === end || start.nextSibling)) while (true) {
				parent.insertBefore(start.cloneNode(true), anchor);
				if (start === end || !(start = start.nextSibling)) break;
			}
			else {
				templateContainer.innerHTML = unsafeToTrustedHTML(namespace === "svg" ? `<svg>${content}</svg>` : namespace === "mathml" ? `<math>${content}</math>` : content);
				const template = templateContainer.content;
				if (namespace === "svg" || namespace === "mathml") {
					const wrapper = template.firstChild;
					while (wrapper.firstChild) template.appendChild(wrapper.firstChild);
					template.removeChild(wrapper);
				}
				parent.insertBefore(template, anchor);
			}
			return [before ? before.nextSibling : parent.firstChild, anchor ? anchor.previousSibling : parent.lastChild];
		}
	};
	var vtcKey = Symbol("_vtc");
	function patchClass(el, value, isSVG) {
		const transitionClasses = el[vtcKey];
		if (transitionClasses) value = (value ? [value, ...transitionClasses] : [...transitionClasses]).join(" ");
		if (value == null) el.removeAttribute("class");
		else if (isSVG) el.setAttribute("class", value);
		else el.className = value;
	}
	var vShowOriginalDisplay = Symbol("_vod");
	var vShowHidden = Symbol("_vsh");
	var vShow = {
		name: "show",
		beforeMount(el, { value }, { transition }) {
			el[vShowOriginalDisplay] = el.style.display === "none" ? "" : el.style.display;
			if (transition && value) transition.beforeEnter(el);
			else setDisplay(el, value);
		},
		mounted(el, { value }, { transition }) {
			if (transition && value) transition.enter(el);
		},
		updated(el, { value, oldValue }, { transition }) {
			if (!value === !oldValue) return;
			if (transition) {
				if (value) {
					transition.beforeEnter(el);
					setDisplay(el, true);
					transition.enter(el);
				} else transition.leave(el, () => {
					setDisplay(el, false);
				});
			} else setDisplay(el, value);
		},
		beforeUnmount(el, { value }) {
			setDisplay(el, value);
		}
	};
	function setDisplay(el, value) {
		el.style.display = value ? el[vShowOriginalDisplay] : "none";
		el[vShowHidden] = !value;
	}
	var CSS_VAR_TEXT = Symbol("");
	var displayRE = /(?:^|;)\s*display\s*:/;
	function patchStyle(el, prev, next) {
		const style = el.style;
		const isCssString = isString(next);
		let hasControlledDisplay = false;
		if (next && !isCssString) {
			if (prev) {
				if (!isString(prev)) {
					for (const key in prev) if (next[key] == null) setStyle(style, key, "");
				} else for (const prevStyle of prev.split(";")) {
					const key = prevStyle.slice(0, prevStyle.indexOf(":")).trim();
					if (next[key] == null) setStyle(style, key, "");
				}
			}
			for (const key in next) {
				if (key === "display") hasControlledDisplay = true;
				const value = next[key];
				if (value != null) {
					if (!shouldPreserveTextareaResizeStyle(el, key, !isString(prev) && prev ? prev[key] : void 0, value)) setStyle(style, key, value);
				} else setStyle(style, key, "");
			}
		} else if (isCssString) {
			if (prev !== next) {
				const cssVarText = style[CSS_VAR_TEXT];
				if (cssVarText) next += ";" + cssVarText;
				style.cssText = next;
				hasControlledDisplay = displayRE.test(next);
			}
		} else if (prev) el.removeAttribute("style");
		if (vShowOriginalDisplay in el) {
			el[vShowOriginalDisplay] = hasControlledDisplay ? style.display : "";
			if (el[vShowHidden]) style.display = "none";
		}
	}
	var importantRE = /\s*!important$/;
	function setStyle(style, name, val) {
		if (isArray(val)) val.forEach((v) => setStyle(style, name, v));
		else {
			if (val == null) val = "";
			if (name.startsWith("--")) {
				if (importantRE.test(val)) style.setProperty(name, val.replace(importantRE, ""), "important");
				else style.setProperty(name, val);
			} else {
				const prefixed = autoPrefix(style, name);
				if (importantRE.test(val)) style.setProperty(hyphenate(prefixed), val.replace(importantRE, ""), "important");
				else style[prefixed] = val;
			}
		}
	}
	var prefixes$1 = [
		"Webkit",
		"Moz",
		"ms"
	];
	var prefixCache = {};
	function autoPrefix(style, rawName) {
		const cached = prefixCache[rawName];
		if (cached) return cached;
		let name = camelize(rawName);
		if (name !== "filter" && name in style) return prefixCache[rawName] = name;
		name = capitalize(name);
		for (let i = 0; i < prefixes$1.length; i++) {
			const prefixed = prefixes$1[i] + name;
			if (prefixed in style) return prefixCache[rawName] = prefixed;
		}
		return rawName;
	}
	function shouldPreserveTextareaResizeStyle(el, key, prev, next) {
		return el.tagName === "TEXTAREA" && (key === "width" || key === "height") && isString(next) && prev === next;
	}
	var xlinkNS = "http://www.w3.org/1999/xlink";
	function patchAttr(el, key, value, isSVG, instance, isBoolean = isSpecialBooleanAttr(key)) {
		if (isSVG && key.startsWith("xlink:")) {
			if (value == null) el.removeAttributeNS(xlinkNS, key.slice(6, key.length));
			else el.setAttributeNS(xlinkNS, key, value);
		} else if (value == null || isBoolean && !includeBooleanAttr(value)) el.removeAttribute(key);
		else el.setAttribute(key, isBoolean ? "" : isSymbol(value) ? String(value) : value);
	}
	function patchDOMProp(el, key, value, parentComponent, attrName) {
		if (key === "innerHTML" || key === "textContent") {
			if (value != null) el[key] = key === "innerHTML" ? unsafeToTrustedHTML(value) : value;
			return;
		}
		const tag = el.tagName;
		if (key === "value" && tag !== "PROGRESS" && !tag.includes("-")) {
			const oldValue = tag === "OPTION" ? el.getAttribute("value") || "" : el.value;
			const newValue = value == null ? el.type === "checkbox" ? "on" : "" : String(value);
			if (oldValue !== newValue || !("_value" in el)) el.value = newValue;
			if (value == null) el.removeAttribute(key);
			el._value = value;
			return;
		}
		let needRemove = false;
		if (value === "" || value == null) {
			const type = typeof el[key];
			if (type === "boolean") value = includeBooleanAttr(value);
			else if (value == null && type === "string") {
				value = "";
				needRemove = true;
			} else if (type === "number") {
				value = 0;
				needRemove = true;
			}
		}
		try {
			el[key] = value;
		} catch (e) {}
		needRemove && el.removeAttribute(attrName || key);
	}
	function addEventListener(el, event, handler, options) {
		el.addEventListener(event, handler, options);
	}
	function removeEventListener(el, event, handler, options) {
		el.removeEventListener(event, handler, options);
	}
	var veiKey = Symbol("_vei");
	function patchEvent(el, rawName, prevValue, nextValue, instance = null) {
		const invokers = el[veiKey] || (el[veiKey] = {});
		const existingInvoker = invokers[rawName];
		if (nextValue && existingInvoker) existingInvoker.value = nextValue;
		else {
			const [name, options] = parseName(rawName);
			if (nextValue) addEventListener(el, name, invokers[rawName] = createInvoker(nextValue, instance), options);
			else if (existingInvoker) {
				removeEventListener(el, name, existingInvoker, options);
				invokers[rawName] = void 0;
			}
		}
	}
	var optionsModifierRE = /(Once|Passive|Capture)$/;
	var optionsModifierEventRE = /^on:?(?:Once|Passive|Capture)$/;
	function parseName(name) {
		let options;
		let m;
		while ((m = name.match(optionsModifierRE)) && !optionsModifierEventRE.test(name)) {
			if (!options) options = {};
			name = name.slice(0, name.length - m[1].length);
			options[m[1].toLowerCase()] = true;
		}
		return [name[2] === ":" ? name.slice(3) : hyphenate(name.slice(2)), options];
	}
	var cachedNow = 0;
	var p = Promise.resolve();
	var getNow = () => cachedNow || (p.then(() => cachedNow = 0), cachedNow = Date.now());
	function createInvoker(initialValue, instance) {
		const invoker = (e) => {
			if (!e._vts) e._vts = Date.now();
			else if (e._vts <= invoker.attached) return;
			const value = invoker.value;
			if (isArray(value)) {
				const originalStop = e.stopImmediatePropagation;
				e.stopImmediatePropagation = () => {
					originalStop.call(e);
					e._stopped = true;
				};
				const handlers = value.slice();
				const args = [e];
				for (let i = 0; i < handlers.length; i++) {
					if (e._stopped) break;
					const handler = handlers[i];
					if (handler) callWithAsyncErrorHandling(handler, instance, 5, args);
				}
			} else callWithAsyncErrorHandling(value, instance, 5, [e]);
		};
		invoker.value = initialValue;
		invoker.attached = getNow();
		return invoker;
	}
	var isNativeOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && key.charCodeAt(2) > 96 && key.charCodeAt(2) < 123;
	var patchProp = (el, key, prevValue, nextValue, namespace, parentComponent) => {
		const isSVG = namespace === "svg";
		if (key === "class") patchClass(el, nextValue, isSVG);
		else if (key === "style") patchStyle(el, prevValue, nextValue);
		else if (isOn(key)) {
			if (!isModelListener(key)) patchEvent(el, key, prevValue, nextValue, parentComponent);
		} else if (key[0] === "." ? (key = key.slice(1), true) : key[0] === "^" ? (key = key.slice(1), false) : shouldSetAsProp(el, key, nextValue, isSVG)) {
			patchDOMProp(el, key, nextValue);
			if (!el.tagName.includes("-") && (key === "value" || key === "checked" || key === "selected")) patchAttr(el, key, nextValue, isSVG, parentComponent, key !== "value");
		} else if (el._isVueCE && (shouldSetAsPropForVueCE(el, key) || el._def.__asyncLoader && (/[A-Z]/.test(key) || !isString(nextValue)))) patchDOMProp(el, camelize(key), nextValue, parentComponent, key);
		else {
			if (key === "true-value") el._trueValue = nextValue;
			else if (key === "false-value") el._falseValue = nextValue;
			patchAttr(el, key, nextValue, isSVG);
		}
	};
	function shouldSetAsProp(el, key, value, isSVG) {
		if (isSVG) {
			if (key === "innerHTML" || key === "textContent") return true;
			if (key in el && isNativeOn(key) && isFunction(value)) return true;
			return false;
		}
		if (key === "spellcheck" || key === "draggable" || key === "translate" || key === "autocorrect") return false;
		if (key === "sandbox" && el.tagName === "IFRAME") return false;
		if (key === "form") return false;
		if (key === "list" && el.tagName === "INPUT") return false;
		if (key === "type" && el.tagName === "TEXTAREA") return false;
		if (key === "width" || key === "height") {
			const tag = el.tagName;
			if (tag === "IMG" || tag === "VIDEO" || tag === "CANVAS" || tag === "SOURCE") return false;
		}
		if (isNativeOn(key) && isString(value)) return false;
		return key in el;
	}
	function shouldSetAsPropForVueCE(el, key) {
		const props = el._def.props;
		if (!props) return false;
		const camelKey = camelize(key);
		return Array.isArray(props) ? props.some((prop) => camelize(prop) === camelKey) : Object.keys(props).some((prop) => camelize(prop) === camelKey);
	}
	var getModelAssigner = (vnode) => {
		const fn = vnode.props["onUpdate:modelValue"] || false;
		return isArray(fn) ? (value) => invokeArrayFns(fn, value) : fn;
	};
	var assignKey = Symbol("_assign");
	var vModelCheckbox = {
		deep: true,
		created(el, _, vnode) {
			el[assignKey] = getModelAssigner(vnode);
			addEventListener(el, "change", () => {
				const modelValue = el._modelValue;
				const elementValue = getValue(el);
				const checked = el.checked;
				const assign = el[assignKey];
				if (isArray(modelValue)) {
					const index = looseIndexOf(modelValue, elementValue);
					const found = index !== -1;
					if (checked && !found) assign(modelValue.concat(elementValue));
					else if (!checked && found) {
						const filtered = [...modelValue];
						filtered.splice(index, 1);
						assign(filtered);
					}
				} else if (isSet(modelValue)) {
					const cloned = new Set(modelValue);
					if (checked) cloned.add(elementValue);
					else cloned.delete(elementValue);
					assign(cloned);
				} else assign(getCheckboxValue(el, checked));
			});
		},
		mounted: setChecked,
		beforeUpdate(el, binding, vnode) {
			el[assignKey] = getModelAssigner(vnode);
			setChecked(el, binding, vnode);
		}
	};
	function setChecked(el, { value, oldValue }, vnode) {
		el._modelValue = value;
		let checked;
		if (isArray(value)) checked = looseIndexOf(value, vnode.props.value) > -1;
		else if (isSet(value)) checked = value.has(vnode.props.value);
		else {
			if (value === oldValue) return;
			checked = looseEqual(value, getCheckboxValue(el, true));
		}
		if (el.checked !== checked) el.checked = checked;
	}
	var vModelRadio = {
		created(el, { value }, vnode) {
			el.checked = looseEqual(value, vnode.props.value);
			el[assignKey] = getModelAssigner(vnode);
			addEventListener(el, "change", () => {
				el[assignKey](getValue(el));
			});
		},
		beforeUpdate(el, { value, oldValue }, vnode) {
			el[assignKey] = getModelAssigner(vnode);
			if (value !== oldValue) el.checked = looseEqual(value, vnode.props.value);
		}
	};
	var vModelSelect = {
		deep: true,
		created(el, { value, modifiers: { number } }, vnode) {
			el._modelValue = value;
			addEventListener(el, "change", () => {
				const selectedVal = Array.prototype.filter.call(el.options, (o) => o.selected).map((o) => number ? looseToNumber(getValue(o)) : getValue(o));
				const multiple = el.multiple;
				const assignedValue = multiple ? isSet(el._modelValue) ? new Set(selectedVal) : selectedVal : selectedVal[0];
				const pending = el._pendingValue = [multiple, multiple ? isArray(assignedValue) ? selectedVal.slice() : selectedVal : assignedValue];
				try {
					el[assignKey](assignedValue);
				} finally {
					nextTick(() => {
						if (el._pendingValue === pending) el._pendingValue = void 0;
					});
				}
			});
			el[assignKey] = getModelAssigner(vnode);
		},
		mounted(el, { value }) {
			setSelected(el, value);
		},
		beforeUpdate(el, { value }, vnode) {
			el._modelValue = value;
			el[assignKey] = getModelAssigner(vnode);
		},
		updated(el, { value }) {
			const pending = el._pendingValue;
			el._pendingValue = void 0;
			if (!pending || pending[0] !== el.multiple || !isSameSelectValue(value, pending[1], pending[0])) setSelected(el, value);
		}
	};
	function isSameSelectValue(value, assignedValue, multiple) {
		if (!multiple) return looseEqual(value, assignedValue);
		if (isArray(value)) return looseEqual(value, assignedValue);
		if (isSet(value)) {
			if (value.size !== assignedValue.length) return false;
			for (const item of assignedValue) if (!value.has(item)) return false;
			return true;
		}
		return false;
	}
	function setSelected(el, value) {
		const isMultiple = el.multiple;
		const isArrayValue = isArray(value);
		if (isMultiple && !isArrayValue && !isSet(value)) return;
		for (let i = 0, l = el.options.length; i < l; i++) {
			const option = el.options[i];
			const optionValue = getValue(option);
			if (isMultiple) {
				if (isArrayValue) {
					const optionType = typeof optionValue;
					if (optionType === "string" || optionType === "number") option.selected = value.some((v) => String(v) === String(optionValue));
					else option.selected = looseIndexOf(value, optionValue) > -1;
				} else option.selected = value.has(optionValue);
			} else if (looseEqual(getValue(option), value)) {
				if (el.selectedIndex !== i) el.selectedIndex = i;
				return;
			}
		}
		if (!isMultiple && el.selectedIndex !== -1) el.selectedIndex = -1;
	}
	function getValue(el) {
		return "_value" in el ? el._value : el.value;
	}
	function getCheckboxValue(el, checked) {
		const key = checked ? "_trueValue" : "_falseValue";
		return key in el ? el[key] : checked;
	}
	var rendererOptions = extend({ patchProp }, nodeOps);
	var renderer;
	function ensureRenderer() {
		return renderer || (renderer = createRenderer(rendererOptions));
	}
	var createApp = ((...args) => {
		const app = ensureRenderer().createApp(...args);
		const { mount } = app;
		app.mount = (containerOrSelector) => {
			const container = normalizeContainer(containerOrSelector);
			if (!container) return;
			const component = app._component;
			if (!isFunction(component) && !component.render && !component.template) component.template = container.innerHTML;
			if (container.nodeType === 1) container.textContent = "";
			const proxy = mount(container, false, resolveRootNamespace(container));
			if (container instanceof Element) {
				container.removeAttribute("v-cloak");
				container.setAttribute("data-v-app", "");
			}
			return proxy;
		};
		return app;
	});
	function resolveRootNamespace(container) {
		if (container instanceof SVGElement) return "svg";
		if (typeof MathMLElement === "function" && container instanceof MathMLElement) return "mathml";
	}
	function normalizeContainer(container) {
		if (isString(container)) return document.querySelector(container);
		return container;
	}
	var _GM = (() => typeof GM != "undefined" ? GM : void 0)();
	var _GM_addValueChangeListener = (() => typeof GM_addValueChangeListener != "undefined" ? GM_addValueChangeListener : void 0)();
	var _GM_openInTab = (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)();
	var _GM_removeValueChangeListener = (() => typeof GM_removeValueChangeListener != "undefined" ? GM_removeValueChangeListener : void 0)();
	var _GM_xmlhttpRequest = (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
	var hasGM = typeof _GM?.getValue === "function";
	var canList = hasGM && typeof _GM.listValues === "function";
	var canDelete = hasGM && typeof _GM.deleteValue === "function";
	async function degrade(operation, run, fallback) {
		try {
			return await run();
		} catch (error) {
			console.warn(`[EhHyperlink] storage ${operation} failed`, error);
			return fallback;
		}
	}
	async function storageGet(key) {
		return degrade("read", async () => {
			if (hasGM) return await _GM.getValue(key, "") || null;
			return localStorage.getItem(key);
		}, null);
	}
	async function storageSet(key, value) {
		await degrade("write", async () => {
			if (hasGM) {
				await _GM.setValue(key, value);
				return;
			}
			localStorage.setItem(key, value);
		}, void 0);
	}
	async function storageKeys() {
		return degrade("list", async () => {
			if (canList) return await _GM.listValues();
			return Object.keys(localStorage);
		}, []);
	}
	async function storageRemove(key) {
		await degrade("delete", async () => {
			if (canDelete) {
				await _GM.deleteValue(key);
				return;
			}
			localStorage.removeItem(key);
		}, void 0);
	}
	var NO_WRAP_RE = /^(?:\(.*\)|\\?.)$/;
	function wrap(s) {
		const v = s.toString();
		return NO_WRAP_RE.test(v) ? v : `(?:${v})`;
	}
	var GROUPED_AS_REPLACE_RE = /^(?:\(\?:(.+)\)|(.+))$/;
	var GROUPED_REPLACE_RE = /^(?:\(\?:(.+)\)([?+*]|\{[\d,]+\})?|(.+))$/;
	function createInput(s) {
		const groupedAsFn = (key) => createInput(`(?<${key}>${`${s}`.replace(GROUPED_AS_REPLACE_RE, "$1$2")})`);
		return {
			toString: () => s.toString(),
			and: Object.assign((...inputs) => createInput(`${s}${exactly(...inputs)}`), { referenceTo: (groupName) => createInput(`${s}\\k<${groupName}>`) }),
			or: (...inputs) => createInput(`(?:${s}|${inputs.map((v) => exactly(v)).join("|")})`),
			after: (...input) => createInput(`(?<=${exactly(...input)})${s}`),
			before: (...input) => createInput(`${s}(?=${exactly(...input)})`),
			notAfter: (...input) => createInput(`(?<!${exactly(...input)})${s}`),
			notBefore: (...input) => createInput(`${s}(?!${exactly(...input)})`),
			times: Object.assign((number) => createInput(`${wrap(s)}{${number}}`), {
				any: () => createInput(`${wrap(s)}*`),
				atLeast: (min) => createInput(`${wrap(s)}{${min},}`),
				atMost: (max) => createInput(`${wrap(s)}{0,${max}}`),
				between: (min, max) => createInput(`${wrap(s)}{${min},${max}}`)
			}),
			optionally: () => createInput(`${wrap(s)}?`),
			as: groupedAsFn,
			groupedAs: groupedAsFn,
			grouped: () => createInput(`${s}`.replace(GROUPED_REPLACE_RE, "($1$3)$2")),
			at: {
				lineStart: () => createInput(`^${s}`),
				lineEnd: () => createInput(`${s}$`)
			}
		};
	}
	var ESCAPE_REPLACE_RE = /[.*+?^${}()|[\]\\/]/g;
	function createCharInput(raw) {
		const input = createInput(`[${raw}]`);
		const from = (charFrom, charTo) => createCharInput(`${raw}${escapeCharInput(charFrom)}-${escapeCharInput(charTo)}`);
		const orChar = Object.assign((chars) => createCharInput(`${raw}${escapeCharInput(chars)}`), { from });
		return Object.assign(input, {
			orChar,
			from
		});
	}
	function escapeCharInput(raw) {
		return raw.replace(/[-\\^\]]/g, "\\$&");
	}
	var charIn = Object.assign((chars) => {
		return createCharInput(escapeCharInput(chars));
	}, createCharInput(""));
	Object.assign((chars) => {
		return createCharInput(`^${escapeCharInput(chars)}`);
	}, createCharInput("^"));
	function anyOf(...inputs) {
		return createInput(`(?:${inputs.map((a) => exactly(a)).join("|")})`);
	}
	createInput(".");
	createInput("\\b\\w+\\b");
	createInput("\\w");
	createInput("\\b");
	createInput("\\d");
	createInput("\\s");
	Object.assign(createInput("[a-zA-Z]"), {
		lowercase: createInput("[a-z]"),
		uppercase: createInput("[A-Z]")
	});
	createInput("\\t");
	createInput("\\n");
	createInput("\\r");
	createInput("\\W+"), createInput("\\W"), createInput("\\B"), createInput("\\D"), createInput("\\S"), Object.assign(createInput("[^a-zA-Z]"), {
		lowercase: createInput("[^a-z]"),
		uppercase: createInput("[^A-Z]")
	}), createInput("[^\\t]"), createInput("[^\\n]"), createInput("[^\\r]");
	function maybe(...inputs) {
		return createInput(`${wrap(exactly(...inputs))}?`);
	}
	function exactly(...inputs) {
		return createInput(inputs.map((input) => typeof input === "string" ? input.replace(ESCAPE_REPLACE_RE, "\\$&") : input).join(""));
	}
	function oneOrMore(...inputs) {
		return createInput(`${wrap(exactly(...inputs))}+`);
	}
	var createRegExp = (...inputs) => {
		const flags = inputs.length > 1 && (Array.isArray(inputs[inputs.length - 1]) || inputs[inputs.length - 1] instanceof Set) ? inputs.pop() : void 0;
		return new RegExp(exactly(...inputs).toString(), [...flags || ""].join(""));
	};
	function raw(source) {
		return exactly({ toString: () => source });
	}
	function unicode(category) {
		return raw(`\\p{${category}}`);
	}
	function notUnicode(category) {
		return raw(`\\P{${category}}`);
	}
	var letter = unicode("L");
	var digit = unicode("Nd");
	var whitespace = unicode("White_Space");
	var cjkLetter = raw("[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}ー]");
	var han = raw("[\\p{Script=Han}]");
	raw("[\\p{Script=Hiragana}\\p{Script=Katakana}ー]");
	var start = raw("^");
	var end = raw("$");
	var punctuation = raw("[\\p{P}\\p{S}]");
	var optionalSpace = whitespace.times.any();
	function standalone(input) {
		return input.notAfter(letter).notBefore(anyOf(letter, digit));
	}
	function compile(input, flags = []) {
		return createRegExp(input, [...flags, "u"]);
	}
	var whitespaceRun = compile(oneOrMore(whitespace), ["g"]);
	var wordBreakRun = compile(oneOrMore(anyOf(whitespace, punctuation)), ["g"]);
	var title_markers_default = {
		version: 1,
		description: "Bracket-content markers that carry no work identity. Values are compared after NFKC + casefold + whitespace collapse. kind=exact: whole segment equals value. kind=prefix_number: segment starts with value, then optional separators (space ☆ ★ ・ - / ,), then digits, then an optional st/nd/rd/th, then end or a separator. kind=suffix: segment ends with value. Language entries carry lang: the ehwiki language tag name they indicate.",
		sources: [
			"https://ehwiki.org/wiki/Renaming (Special Indicators, Language Indicators, Conventions tables; GFDL 1.2+)",
			"https://ehwiki.org/wiki/Languages (83 language tags)",
			"EhViewer GalleryInfo.kt S_LANG_PATTERNS (Apache-2.0) for R/J language pairs",
			"ShiguReader packages/name-parser (MIT) for convention stems",
			"URenko/e-hentai-db full-corpus bracket-content ranking, 2026-09-17 snapshot"
		],
		roles: {
			"event": "convention or release event, e.g. (C81)",
			"language": "language indicator, e.g. [English] [英訳]",
			"translator": "translation group or translator credit, matched by suffix only, e.g. [○○汉化组] [○○個人翻譯] [○○ Translations]",
			"release": "special indicator or medium marker, e.g. [Decensored] [DL版] [3D]",
			"platform": "website or distribution platform, e.g. [Pixiv] [Patreon]",
			"placeholder": "non-identity stand-in, e.g. [Anthology] [Various] [Artist]",
			"ai": "AI-generated marker, e.g. [AI Generated] [AI生成]"
		},
		entries: [
			{
				"value": "c",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comic market",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comiket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "コミックマーケット",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "コミケ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "エアコミケ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "air comiket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ac",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comic1",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comic1",
				"role": "event",
				"kind": "exact"
			},
			{
				"value": "reitaisai",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "例大祭",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "shuuki reitaisai",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "秋季例大祭",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "air reitaisai",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "エア例大祭",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "sunshine creation",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "sc",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "サンクリ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "sankuri",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comitia",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "コミティア",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "csp",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "spark",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "super",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "superkansai",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "super関西",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "harucc",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ff",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "fancy frontier",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ct",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comic treasure",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "こみトレ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ccosaka",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "cc大阪",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comic city",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "cr",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "cレヴォ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comic revolution",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "futaket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ふたけっと",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comicomi",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "コミコミ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "puniket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ぷにケット",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "kouroumu",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "紅楼夢",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "shotaket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ショタケット",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "shota scratch",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ショタスクラッチ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "mimiket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "みみけっと",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "kemoket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "けもケット",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "mofuket",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "もふけっと",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "tora matsuri",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "とら祭り",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "fetishism",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "フェティシズム",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "fur-st",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ふぁーすと",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "koimari",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "こいまり",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "koharu komichi",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "小春小径",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "kyonyuukko",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "巨乳っ娘",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "lyrical magical",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "リリカルマジカル",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "makimaki",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "まきまき",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "mencomi",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "メンコミ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "coscafe",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "コスカ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "reisensai",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "鈴仙祭",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "sht",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "tengu-sama no oshigoto",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "天狗様のお仕事",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "tokipa",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ときパ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "komachi",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "東方不敗小町",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "ruuchakai",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "螺茶会",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "yarinsai",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "東方椰麟祭",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "akatsuki no utage",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "紅月ノ宴",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comichara",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "コミキャラ",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "abc",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "アブノーマル・カーニバル",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "bokura no love live!",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "僕らのラブライブ!",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "bang dreamer's party!",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "comic castle",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "idol survival",
				"role": "event",
				"kind": "prefix_number"
			},
			{
				"value": "japariket",
				"role": "event",
				"kind": "exact"
			},
			{
				"value": "ジャパリケット",
				"role": "event",
				"kind": "exact"
			},
			{
				"value": "rfosaka",
				"role": "event",
				"kind": "exact"
			},
			{
				"value": "レイフレ大阪",
				"role": "event",
				"kind": "exact"
			},
			{
				"value": "秋葉原超同人祭",
				"role": "event",
				"kind": "exact"
			},
			{
				"value": "akihabara chou doujinsai",
				"role": "event",
				"kind": "exact"
			},
			{
				"value": "afrikaans",
				"role": "language",
				"kind": "exact",
				"lang": "afrikaans"
			},
			{
				"value": "albanian",
				"role": "language",
				"kind": "exact",
				"lang": "albanian"
			},
			{
				"value": "arabic",
				"role": "language",
				"kind": "exact",
				"lang": "arabic"
			},
			{
				"value": "aramaic",
				"role": "language",
				"kind": "exact",
				"lang": "aramaic"
			},
			{
				"value": "armenian",
				"role": "language",
				"kind": "exact",
				"lang": "armenian"
			},
			{
				"value": "bengali",
				"role": "language",
				"kind": "exact",
				"lang": "bengali"
			},
			{
				"value": "bosnian",
				"role": "language",
				"kind": "exact",
				"lang": "bosnian"
			},
			{
				"value": "bulgarian",
				"role": "language",
				"kind": "exact",
				"lang": "bulgarian"
			},
			{
				"value": "burmese",
				"role": "language",
				"kind": "exact",
				"lang": "burmese"
			},
			{
				"value": "catalan",
				"role": "language",
				"kind": "exact",
				"lang": "catalan"
			},
			{
				"value": "cebuano",
				"role": "language",
				"kind": "exact",
				"lang": "cebuano"
			},
			{
				"value": "chinese",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "cree",
				"role": "language",
				"kind": "exact",
				"lang": "cree"
			},
			{
				"value": "creole",
				"role": "language",
				"kind": "exact",
				"lang": "creole"
			},
			{
				"value": "croatian",
				"role": "language",
				"kind": "exact",
				"lang": "croatian"
			},
			{
				"value": "czech",
				"role": "language",
				"kind": "exact",
				"lang": "czech"
			},
			{
				"value": "danish",
				"role": "language",
				"kind": "exact",
				"lang": "danish"
			},
			{
				"value": "dutch",
				"role": "language",
				"kind": "exact",
				"lang": "dutch"
			},
			{
				"value": "english",
				"role": "language",
				"kind": "exact",
				"lang": "english"
			},
			{
				"value": "esperanto",
				"role": "language",
				"kind": "exact",
				"lang": "esperanto"
			},
			{
				"value": "estonian",
				"role": "language",
				"kind": "exact",
				"lang": "estonian"
			},
			{
				"value": "finnish",
				"role": "language",
				"kind": "exact",
				"lang": "finnish"
			},
			{
				"value": "french",
				"role": "language",
				"kind": "exact",
				"lang": "french"
			},
			{
				"value": "georgian",
				"role": "language",
				"kind": "exact",
				"lang": "georgian"
			},
			{
				"value": "german",
				"role": "language",
				"kind": "exact",
				"lang": "german"
			},
			{
				"value": "greek",
				"role": "language",
				"kind": "exact",
				"lang": "greek"
			},
			{
				"value": "gujarati",
				"role": "language",
				"kind": "exact",
				"lang": "gujarati"
			},
			{
				"value": "hebrew",
				"role": "language",
				"kind": "exact",
				"lang": "hebrew"
			},
			{
				"value": "hindi",
				"role": "language",
				"kind": "exact",
				"lang": "hindi"
			},
			{
				"value": "hmong",
				"role": "language",
				"kind": "exact",
				"lang": "hmong"
			},
			{
				"value": "hungarian",
				"role": "language",
				"kind": "exact",
				"lang": "hungarian"
			},
			{
				"value": "icelandic",
				"role": "language",
				"kind": "exact",
				"lang": "icelandic"
			},
			{
				"value": "indonesian",
				"role": "language",
				"kind": "exact",
				"lang": "indonesian"
			},
			{
				"value": "irish",
				"role": "language",
				"kind": "exact",
				"lang": "irish"
			},
			{
				"value": "italian",
				"role": "language",
				"kind": "exact",
				"lang": "italian"
			},
			{
				"value": "japanese",
				"role": "language",
				"kind": "exact",
				"lang": "japanese"
			},
			{
				"value": "javanese",
				"role": "language",
				"kind": "exact",
				"lang": "javanese"
			},
			{
				"value": "kannada",
				"role": "language",
				"kind": "exact",
				"lang": "kannada"
			},
			{
				"value": "kazakh",
				"role": "language",
				"kind": "exact",
				"lang": "kazakh"
			},
			{
				"value": "khmer",
				"role": "language",
				"kind": "exact",
				"lang": "khmer"
			},
			{
				"value": "korean",
				"role": "language",
				"kind": "exact",
				"lang": "korean"
			},
			{
				"value": "kurdish",
				"role": "language",
				"kind": "exact",
				"lang": "kurdish"
			},
			{
				"value": "ladino",
				"role": "language",
				"kind": "exact",
				"lang": "ladino"
			},
			{
				"value": "lao",
				"role": "language",
				"kind": "exact",
				"lang": "lao"
			},
			{
				"value": "latin",
				"role": "language",
				"kind": "exact",
				"lang": "latin"
			},
			{
				"value": "latvian",
				"role": "language",
				"kind": "exact",
				"lang": "latvian"
			},
			{
				"value": "marathi",
				"role": "language",
				"kind": "exact",
				"lang": "marathi"
			},
			{
				"value": "mongolian",
				"role": "language",
				"kind": "exact",
				"lang": "mongolian"
			},
			{
				"value": "ndebele",
				"role": "language",
				"kind": "exact",
				"lang": "ndebele"
			},
			{
				"value": "nepali",
				"role": "language",
				"kind": "exact",
				"lang": "nepali"
			},
			{
				"value": "norwegian",
				"role": "language",
				"kind": "exact",
				"lang": "norwegian"
			},
			{
				"value": "oromo",
				"role": "language",
				"kind": "exact",
				"lang": "oromo"
			},
			{
				"value": "papiamento",
				"role": "language",
				"kind": "exact",
				"lang": "papiamento"
			},
			{
				"value": "pashto",
				"role": "language",
				"kind": "exact",
				"lang": "pashto"
			},
			{
				"value": "persian",
				"role": "language",
				"kind": "exact",
				"lang": "persian"
			},
			{
				"value": "polish",
				"role": "language",
				"kind": "exact",
				"lang": "polish"
			},
			{
				"value": "portuguese",
				"role": "language",
				"kind": "exact",
				"lang": "portuguese"
			},
			{
				"value": "punjabi",
				"role": "language",
				"kind": "exact",
				"lang": "punjabi"
			},
			{
				"value": "romanian",
				"role": "language",
				"kind": "exact",
				"lang": "romanian"
			},
			{
				"value": "russian",
				"role": "language",
				"kind": "exact",
				"lang": "russian"
			},
			{
				"value": "sango",
				"role": "language",
				"kind": "exact",
				"lang": "sango"
			},
			{
				"value": "sanskrit",
				"role": "language",
				"kind": "exact",
				"lang": "sanskrit"
			},
			{
				"value": "serbian",
				"role": "language",
				"kind": "exact",
				"lang": "serbian"
			},
			{
				"value": "shona",
				"role": "language",
				"kind": "exact",
				"lang": "shona"
			},
			{
				"value": "slovak",
				"role": "language",
				"kind": "exact",
				"lang": "slovak"
			},
			{
				"value": "slovenian",
				"role": "language",
				"kind": "exact",
				"lang": "slovenian"
			},
			{
				"value": "somali",
				"role": "language",
				"kind": "exact",
				"lang": "somali"
			},
			{
				"value": "spanish",
				"role": "language",
				"kind": "exact",
				"lang": "spanish"
			},
			{
				"value": "swahili",
				"role": "language",
				"kind": "exact",
				"lang": "swahili"
			},
			{
				"value": "swedish",
				"role": "language",
				"kind": "exact",
				"lang": "swedish"
			},
			{
				"value": "tagalog",
				"role": "language",
				"kind": "exact",
				"lang": "tagalog"
			},
			{
				"value": "tamil",
				"role": "language",
				"kind": "exact",
				"lang": "tamil"
			},
			{
				"value": "telugu",
				"role": "language",
				"kind": "exact",
				"lang": "telugu"
			},
			{
				"value": "thai",
				"role": "language",
				"kind": "exact",
				"lang": "thai"
			},
			{
				"value": "tibetan",
				"role": "language",
				"kind": "exact",
				"lang": "tibetan"
			},
			{
				"value": "tigrinya",
				"role": "language",
				"kind": "exact",
				"lang": "tigrinya"
			},
			{
				"value": "turkish",
				"role": "language",
				"kind": "exact",
				"lang": "turkish"
			},
			{
				"value": "ukrainian",
				"role": "language",
				"kind": "exact",
				"lang": "ukrainian"
			},
			{
				"value": "urdu",
				"role": "language",
				"kind": "exact",
				"lang": "urdu"
			},
			{
				"value": "vietnamese",
				"role": "language",
				"kind": "exact",
				"lang": "vietnamese"
			},
			{
				"value": "welsh",
				"role": "language",
				"kind": "exact",
				"lang": "welsh"
			},
			{
				"value": "yiddish",
				"role": "language",
				"kind": "exact",
				"lang": "yiddish"
			},
			{
				"value": "zulu",
				"role": "language",
				"kind": "exact",
				"lang": "zulu"
			},
			{
				"value": "eng",
				"role": "language",
				"kind": "exact",
				"lang": "english"
			},
			{
				"value": "rus",
				"role": "language",
				"kind": "exact",
				"lang": "russian"
			},
			{
				"value": "esp",
				"role": "language",
				"kind": "exact",
				"lang": "spanish"
			},
			{
				"value": "español",
				"role": "language",
				"kind": "exact",
				"lang": "spanish"
			},
			{
				"value": "espanol",
				"role": "language",
				"kind": "exact",
				"lang": "spanish"
			},
			{
				"value": "portuguese-br",
				"role": "language",
				"kind": "exact",
				"lang": "portuguese"
			},
			{
				"value": "português",
				"role": "language",
				"kind": "exact",
				"lang": "portuguese"
			},
			{
				"value": "thai ภาษาไทย",
				"role": "language",
				"kind": "exact",
				"lang": "thai"
			},
			{
				"value": "ภาษาไทย",
				"role": "language",
				"kind": "exact",
				"lang": "thai"
			},
			{
				"value": "แปลไทย",
				"role": "language",
				"kind": "exact",
				"lang": "thai"
			},
			{
				"value": "vietnamese tiếng việt",
				"role": "language",
				"kind": "exact",
				"lang": "vietnamese"
			},
			{
				"value": "tiếng việt",
				"role": "language",
				"kind": "exact",
				"lang": "vietnamese"
			},
			{
				"value": "japanese, english",
				"role": "language",
				"kind": "exact",
				"lang": "english"
			},
			{
				"value": "japanese, chinese",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "english, japanese",
				"role": "language",
				"kind": "exact",
				"lang": "english"
			},
			{
				"value": "chs",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "cht",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "fr",
				"role": "language",
				"kind": "exact",
				"lang": "french"
			},
			{
				"value": "br",
				"role": "language",
				"kind": "exact",
				"lang": "portuguese"
			},
			{
				"value": "de",
				"role": "language",
				"kind": "exact",
				"lang": "german"
			},
			{
				"value": "german/deutsch",
				"role": "language",
				"kind": "exact",
				"lang": "german"
			},
			{
				"value": "español/spanish",
				"role": "language",
				"kind": "exact",
				"lang": "spanish"
			},
			{
				"value": "spanish/español",
				"role": "language",
				"kind": "exact",
				"lang": "spanish"
			},
			{
				"value": "英訳",
				"role": "language",
				"kind": "exact",
				"lang": "english"
			},
			{
				"value": "英語",
				"role": "language",
				"kind": "exact",
				"lang": "english"
			},
			{
				"value": "中国翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中国翻译",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中國翻譯",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中国語",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中国语",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中國語",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中文",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中文翻译",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "中文翻譯",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "简体中文",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "繁體中文",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "韓国翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "korean"
			},
			{
				"value": "韓国語",
				"role": "language",
				"kind": "exact",
				"lang": "korean"
			},
			{
				"value": "한국어",
				"role": "language",
				"kind": "exact",
				"lang": "korean"
			},
			{
				"value": "日本語",
				"role": "language",
				"kind": "exact",
				"lang": "japanese"
			},
			{
				"value": "日本語、英語",
				"role": "language",
				"kind": "exact",
				"lang": "english"
			},
			{
				"value": "日本語、中国語",
				"role": "language",
				"kind": "exact",
				"lang": "chinese"
			},
			{
				"value": "フランス翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "french"
			},
			{
				"value": "ドイツ翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "german"
			},
			{
				"value": "イタリア翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "italian"
			},
			{
				"value": "ポルトガル翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "portuguese"
			},
			{
				"value": "ロシア翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "russian"
			},
			{
				"value": "スペイン翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "spanish"
			},
			{
				"value": "タイ翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "thai"
			},
			{
				"value": "ベトナム翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "vietnamese"
			},
			{
				"value": "ポーランド翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "polish"
			},
			{
				"value": "ハンガリー翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "hungarian"
			},
			{
				"value": "オランダ翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "dutch"
			},
			{
				"value": "ウクライナ翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "ukrainian"
			},
			{
				"value": "インドネシア翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "indonesian"
			},
			{
				"value": "トルコ翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "turkish"
			},
			{
				"value": "アラビア翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "arabic"
			},
			{
				"value": "チェコ翻訳",
				"role": "language",
				"kind": "exact",
				"lang": "czech"
			},
			{
				"value": "翻訳",
				"role": "language",
				"kind": "suffix"
			},
			{
				"value": "汉化",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "漢化",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "汉化组",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "漢化組",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "翻译",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "翻譯",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "翻译组",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "翻譯組",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "翻訳組",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "机翻",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "機翻",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "字幕组",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "字幕組",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "嵌字",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "润色",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "漫画组",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "漫畫組",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "日语社",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "translations",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "translation",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "translates",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "scans",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "scanlations",
				"role": "translator",
				"kind": "suffix"
			},
			{
				"value": "digital",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "mtl",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "dl版",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "dl",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "decensored",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "無修正",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "无修正",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "uncensored",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "去码",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "修正",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "修正版",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "ongoing",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "on going",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "on-going",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "進行中",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "in progress",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "wip",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "work in progress",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "unfinished",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "incomplete",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "ページ欠落",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "complete",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "完結",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "sample",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "見本",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "textless",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "無字",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "colorized",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "カラー化",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "rewrite",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "full color",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "fullcolor",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "フルカラー",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "フルカラー版",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "フルカラー成人版",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "全彩",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "完全版",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "別スキャン",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "別版",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "ページ補足",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "web再録",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "web sairoku",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "再録",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "総集編",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "request",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "oc",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "animated",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "3d",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "no gore",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "同人誌",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "同人cg集",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "同人cg",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "同人ソフト",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "同人ゲーム",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "同人音声",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "成年コミック",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "アダルトコミック",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "フルカラーコミック",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "一般コミック",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "コスプレ",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "cosplay",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "非エロ",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "エロ",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "hi-res",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "high quality",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "cg集",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "cg",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "画集",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "イラスト集",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "imageset",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "image set",
				"role": "release",
				"kind": "exact"
			},
			{
				"value": "pixiv",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "fanbox",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "pixiv fanbox",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "pixiv | twitter",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "patreon",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "twitter",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "twitter/e621",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "x",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "fantia",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "dmm.com",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "dmm",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "e621",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "hentai-foundry",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "hentai foundry",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "gumroad",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "skeb",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "booth",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "dlsite",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "nijie",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "deviantart",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "subscribestar",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "kemono",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "fakku",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "nhentai",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "ci-en",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "poipiku",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "tumblr",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "furaffinity",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "newgrounds",
				"role": "platform",
				"kind": "exact"
			},
			{
				"value": "artist",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "アーティスト",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "anthology",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "アンソロジー",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "various",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "various artists",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "よろず",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "tba",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "unknown",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "作者不詳",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "collection",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "original",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "オリジナル",
				"role": "placeholder",
				"kind": "exact"
			},
			{
				"value": "ai generated",
				"role": "ai",
				"kind": "exact"
			},
			{
				"value": "ai-generated",
				"role": "ai",
				"kind": "exact"
			},
			{
				"value": "ai_generated",
				"role": "ai",
				"kind": "exact"
			},
			{
				"value": "aigenerated",
				"role": "ai",
				"kind": "exact"
			},
			{
				"value": "ai生成",
				"role": "ai",
				"kind": "exact"
			},
			{
				"value": "ai",
				"role": "ai",
				"kind": "exact"
			}
		]
	};
	var PREFIX_SEPARATORS = " ☆★・-/,";
	var ORDINAL_SUFFIXES = [
		"st",
		"nd",
		"rd",
		"th"
	];
	var DIGIT_RE = compile(start.and(digit));
	function normalizeMarkerText(value) {
		return value.normalize("NFKC").toLowerCase().split(whitespaceRun).filter(Boolean).join(" ");
	}
	var exact = new Map();
	var prefixes = [];
	var suffixes = [];
	for (const entry of title_markers_default.entries) {
		const value = normalizeMarkerText(entry.value);
		const marker = entry.lang ? {
			role: entry.role,
			lang: entry.lang
		} : { role: entry.role };
		if (entry.kind === "exact") exact.set(value, marker);
		else if (entry.kind === "prefix_number") prefixes.push([value, marker]);
		else if (entry.kind === "suffix") suffixes.push([value, marker]);
		else throw new Error(`unknown marker kind ${entry.kind} for ${entry.value}`);
	}
	prefixes.sort((a, b) => b[0].length - a[0].length);
	suffixes.sort((a, b) => b[0].length - a[0].length);
	function isNumberedRemainder(remainder) {
		let start = 0;
		while (start < remainder.length && PREFIX_SEPARATORS.includes(remainder[start])) start += 1;
		let digits = start;
		while (digits < remainder.length && DIGIT_RE.test(remainder[digits])) digits += 1;
		if (digits === start) return false;
		let rest = remainder.slice(digits);
		for (const suffix of ORDINAL_SUFFIXES) if (rest.startsWith(suffix)) {
			rest = rest.slice(suffix.length);
			break;
		}
		return rest === "" || PREFIX_SEPARATORS.includes(rest[0]);
	}
	function markerOf(segment) {
		const text = normalizeMarkerText(segment);
		if (!text) return null;
		const direct = exact.get(text);
		if (direct) return direct;
		for (const [stem, marker] of prefixes) if (text.startsWith(stem) && isNumberedRemainder(text.slice(stem.length))) return marker;
		for (const [suffix, marker] of suffixes) if (text.endsWith(suffix)) return marker;
		return null;
	}
	var DIGIT_VALUES = {
		"〇": 0,
		"零": 0,
		"一": 1,
		"壱": 1,
		"壹": 1,
		"二": 2,
		"弐": 2,
		"貳": 2,
		"贰": 2,
		"两": 2,
		"兩": 2,
		"三": 3,
		"参": 3,
		"參": 3,
		"叁": 3,
		"四": 4,
		"肆": 4,
		"五": 5,
		"伍": 5,
		"六": 6,
		"陸": 6,
		"陆": 6,
		"七": 7,
		"柒": 7,
		"八": 8,
		"捌": 8,
		"九": 9,
		"玖": 9
	};
	var UNIT_VALUES = {
		"十": 10,
		"拾": 10,
		"百": 100,
		"佰": 100
	};
	var FIXED_TENS = {
		"廿": 20,
		"卅": 30
	};
	var CJK_NUMERAL_CHARACTERS = [
		...Object.keys(DIGIT_VALUES),
		...Object.keys(UNIT_VALUES),
		...Object.keys(FIXED_TENS)
	].join("");
	function positionalValue(characters) {
		if (characters.length > 3) return null;
		let value = 0;
		for (const character of characters) value = value * 10 + DIGIT_VALUES[character];
		return value;
	}
	function parseCjkNumeral(text) {
		const characters = [...text];
		if (characters.length === 0) return null;
		if (characters.every((character) => character in DIGIT_VALUES)) return positionalValue(characters);
		let value = 0;
		let pendingDigit = null;
		let lastUnit = Infinity;
		for (const character of characters) {
			if (character in DIGIT_VALUES) {
				if (pendingDigit !== null && pendingDigit !== 0) return null;
				pendingDigit = DIGIT_VALUES[character];
				continue;
			}
			const fixedTen = FIXED_TENS[character];
			if (fixedTen !== void 0) {
				if (pendingDigit !== null || lastUnit <= 10) return null;
				value += fixedTen;
				lastUnit = 10;
				continue;
			}
			const unit = UNIT_VALUES[character];
			if (unit === void 0 || unit >= lastUnit) return null;
			value += (pendingDigit === null || pendingDigit === 0 ? 1 : pendingDigit) * unit;
			pendingDigit = null;
			lastUnit = unit;
		}
		if (pendingDigit !== null) value += pendingDigit;
		return value;
	}
	var number = digit.times.between(1, 3).and(maybe(exactly(".").and(digit.times.between(1, 2))));
	var RANGE_SEPARATOR = charIn("-~–—-");
	var counter = number.and(maybe(RANGE_SEPARATOR.and(number)));
	var cjkCounter = charIn(CJK_NUMERAL_CHARACTERS).times.between(1, 5).as("cjkNumeral");
	var romanCounter = anyOf("ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "xi", "xii", "xiii");
	var latinChapter = standalone(anyOf(...[
		"chapter",
		"episode",
		"volume",
		"part",
		"sono",
		"vol",
		"set",
		"ch",
		"ep",
		"pt"
	]).and(maybe(".")).and(optionalSpace).and(counter));
	var hashChapter = exactly("#").and(optionalSpace).and(counter).notBefore(anyOf(letter, digit));
	var cjkChapter = exactly("第").and(anyOf(counter, cjkCounter)).and(charIn("話话巻卷"));
	var seriesWord = anyOf(anyOf("最終話", "番外編", "番外篇", "完結編", "完结篇", "総集編", "總集篇", "总集篇", "特別編", "特別篇", "特别篇", "完全版", "新装版", "続編", "前編", "後編", "中編", "前篇", "後篇", "后篇", "上篇", "中篇", "下篇", "上巻", "中巻", "下巻", "序章", "本編", "全編"), anyOf("soushuuhen", "bangaihen", "saishuuwa", "chuuhen", "zenpen", "kouhen", "joukan", "gekan").notAfter(letter).notBefore(letter));
	var CUT_POINT = compile(optionalSpace.and(anyOf(latinChapter, hashChapter, cjkChapter, seriesWord)), ["g", "i"]);
	var MID_COUNTER = compile(anyOf(counter, cjkCounter, romanCounter).after(whitespace).before(whitespace), ["g", "i"]);
	var positionOnlyWord = anyOf("続", "改", "上", "中", "下");
	var subjectPart = notUnicode("White_Space").times.between(1, 9).and(charIn("編篇"));
	var ellipsis = anyOf(exactly(".."), charIn("…"));
	var TRAILING_NUMBER = compile(anyOf(anyOf(counter, cjkCounter, romanCounter, seriesWord, positionOnlyWord, subjectPart).after(anyOf(whitespace, start, ellipsis)), counter.after(cjkLetter)).and(end), ["i"]);
	var GROUP_SEPARATOR = compile(charIn("。、!?〜~・").as("separator"));
	function unlessNotNumeral(replacement) {
		return (match, ...rest) => {
			const groups = rest[rest.length - 1];
			if (groups?.cjkNumeral !== void 0 && parseCjkNumeral(groups.cjkNumeral) === null) return match;
			return replacement;
		};
	}
	function stripGroupTails(text, alreadyStripped = false) {
		const parts = text.split(GROUP_SEPARATOR);
		const kept = [];
		let removed = "";
		for (let index = 0; index < parts.length; index += 2) {
			const group = parts[index].trim();
			let shorter = group;
			let found = false;
			for (;;) {
				const stripped = shorter.replace(TRAILING_NUMBER, unlessNotNumeral(""));
				if (stripped !== shorter) found = true;
				const next = trimTail(stripped).trim();
				if (next === shorter) break;
				shorter = next;
			}
			if (found) removed = group.slice(shorter.length).trim();
			if (!shorter) continue;
			if (kept.length > 0) kept.push(parts[index - 1]);
			kept.push(shorter);
		}
		if (!removed && !alreadyStripped) return {
			text,
			removed: ""
		};
		const stripped = kept.join("");
		return stripped ? {
			text: stripped,
			removed
		} : {
			text,
			removed: ""
		};
	}
	var MIN_PHRASE_LENGTH = 2;
	function firstCutPoint(text) {
		let best = null;
		for (const pattern of [CUT_POINT, MID_COUNTER]) {
			pattern.lastIndex = 0;
			for (let match = pattern.exec(text); match; match = pattern.exec(text)) {
				const numeral = match.groups?.cjkNumeral;
				if (numeral !== void 0 && parseCjkNumeral(numeral) === null) continue;
				const found = {
					index: match.index,
					length: match[0].length
				};
				if (best === null || found.index < best.index) best = found;
				break;
			}
		}
		return best;
	}
	var HAS_LETTER$1 = compile(letter);
	var COUNTER_IN_MARKER = compile(anyOf(counter, cjkCounter, standalone(romanCounter)), ["i"]);
	function counterIn(marker) {
		const found = COUNTER_IN_MARKER.exec(marker.trim());
		return found ? found[0] : marker.trim();
	}
	var edgeMark = anyOf(punctuation, whitespace, charIn("️︎ー"));
	var EDGE_NOISE = compile(anyOf(oneOrMore(edgeMark).after(start), oneOrMore(edgeMark).and(end)), ["g"]);
	var TRAILING_NOISE = compile(oneOrMore(edgeMark).and(end));
	var trimTail = (text) => text.replace(TRAILING_NOISE, "");
	var trimEdges = (text) => text.replace(EDGE_NOISE, "");
	function readWorkText(text) {
		const marker = firstCutPoint(text);
		if (marker === null) {
			const { text: phrase, removed } = stripGroupTails(text);
			return {
				phrase: trimEdges(phrase),
				counter: removed ? counterIn(removed) : ""
			};
		}
		const left = text.slice(0, marker.index).trim();
		const right = text.slice(marker.index + marker.length).trim();
		return {
			phrase: trimEdges(stripGroupTails(HAS_LETTER$1.test(left) && left.length >= MIN_PHRASE_LENGTH ? left : right, true).text),
			counter: counterIn(text.slice(marker.index, marker.index + marker.length))
		};
	}
	var DELIMITER_PAIRS = {
		"[": "]",
		"[": "]",
		"(": ")",
		"(": ")",
		"{": "}",
		"{": "}",
		"【": "】",
		"「": "」",
		"『": "』",
		"《": "》",
		"〈": "〉",
		"<": ">",
		"〔": "〕",
		"「": "」",
		"〖": "〗",
		"〝": "〟",
		"︵": "︶",
		"༼": "༽",
		"༺": "༻",
		"⟮": "⟯",
		"₍": "₎",
		"❲": "❳",
		"❬": "❭",
		"❰": "❱",
		"⟨": "⟩",
		"⟪": "⟫",
		"﹙": "﹚",
		"〘": "〙",
		"﴿": "﴾",
		"⁽": "⁾",
		"﹃": "﹄"
	};
	var OPEN_BY_CLOSE = Object.fromEntries(Object.entries(DELIMITER_PAIRS).map(([opening, closing]) => [closing, opening]));
	var IDENTITY_PAIRS = {
		"[]": true,
		"【】": true,
		"〔〕": true,
		"〖〗": true,
		"〘〙": true,
		"❲❳": true
	};
	var CONTEXT_PAIRS = {
		"()": true,
		"<>": true,
		"〈〉": true,
		"︵︶": true,
		"⟮⟯": true,
		"₍₎": true,
		"﹙﹚": true,
		"﴿﴾": true
	};
	var TITLE_QUOTE_PAIRS = {
		"「」": true,
		"『』": true,
		"《》": true,
		"〝〟": true,
		"❬❭": true,
		"❰❱": true,
		"⟨⟩": true,
		"⟪⟫": true,
		"༺༻": true
	};
	var ALNUM_RE = compile(anyOf(letter, unicode("N")));
	var MIRRORED_MARKS = "-~~〜―-●★◆=*❤♥";
	function stripMirroredBlocks(text, wrapped) {
		let out = text;
		for (const mark of MIRRORED_MARKS) {
			const first = out.indexOf(mark);
			const last = out.lastIndexOf(mark);
			if (first === -1 || first === last || out.indexOf(mark, first + 1) !== last) continue;
			if (first > 0 && ALNUM_RE.test(out.slice(first - 1, first))) continue;
			const afterLast = out.slice(last + 1, last + 2);
			if (afterLast && ALNUM_RE.test(afterLast)) continue;
			const inner = out.slice(first + 1, last);
			if (!ALNUM_RE.test(inner) || inner !== inner.trim()) continue;
			const before = out.slice(0, first).trim();
			const after = out.slice(last + 1).trim();
			if (!ALNUM_RE.test(before + after)) continue;
			const bar = out.indexOf(" | ");
			if (bar === -1 || first < bar) wrapped.push(inner);
			if (before && after) continue;
			out = before || after;
		}
		return out;
	}
	function normalizeTitleText(value) {
		const lowered = value.normalize("NFKC").toLowerCase();
		let out = "";
		for (const character of lowered) out += ALNUM_RE.test(character) ? character : " ";
		return out.split(whitespaceRun).filter(Boolean).join(" ");
	}
	function parseTitleSegments(value) {
		const normalized = value.normalize("NFKC");
		const segments = [];
		const stack = [];
		let textStart = 0;
		let blockStart = 0;
		const characters = [...normalized];
		for (let index = 0; index < characters.length; index += 1) {
			const character = characters[index];
			if (character in DELIMITER_PAIRS) {
				if (stack.length === 0) {
					if (index > textStart) segments.push({
						kind: "text",
						text: characters.slice(textStart, index).join(""),
						pair: ""
					});
					blockStart = index;
				}
				stack.push(character);
				continue;
			}
			const opening = OPEN_BY_CLOSE[character];
			if (!opening) continue;
			if (stack.length === 0 || stack[stack.length - 1] !== opening) return null;
			stack.pop();
			if (stack.length === 0) {
				segments.push({
					kind: "block",
					text: characters.slice(blockStart + 1, index).join(""),
					pair: opening + character
				});
				textStart = index + 1;
			}
		}
		if (stack.length > 0) return null;
		if (textStart < characters.length) segments.push({
			kind: "text",
			text: characters.slice(textStart).join(""),
			pair: ""
		});
		return segments;
	}
	function isClaimedMarker(segment) {
		if (segment.kind !== "block" || segment.pair in TITLE_QUOTE_PAIRS) return false;
		return markerOf(segment.text) !== null;
	}
	function analyzeTitle(value) {
		const parsed = parseTitleSegments(value);
		if (parsed === null) {
			const text = value.normalize("NFKC").trim();
			return {
				core: normalizeTitleText(value),
				identity: "",
				context: "",
				identityBlocks: [],
				coreSegments: text ? [text] : [],
				wrapped: [],
				contextBlocks: [],
				contextText: "",
				balanced: false
			};
		}
		const unclaimed = parsed.filter((segment) => ALNUM_RE.test(segment.text) && !isClaimedMarker(segment));
		const core = [];
		const identity = [];
		const context = [];
		let seenCore = false;
		for (const segment of unclaimed) if (segment.kind === "text" || segment.pair in TITLE_QUOTE_PAIRS) {
			core.push(segment.text);
			seenCore = true;
		} else if (segment.pair in IDENTITY_PAIRS && !seenCore) identity.push(segment.text);
		else if (segment.pair in CONTEXT_PAIRS && seenCore) context.push(segment.text);
		if (core.length === 0) {
			identity.length = 0;
			context.length = 0;
			if (unclaimed.length === 1) core.push(unclaimed[0].text);
			else {
				const firstIdentity = unclaimed.find((segment) => segment.pair in IDENTITY_PAIRS);
				if (firstIdentity) identity.push(firstIdentity.text);
			}
		}
		const written = core.map((text) => text.split(whitespaceRun).filter(Boolean).join(" ")).filter(Boolean);
		const wrapped = [];
		const coreSegments = written.map((text) => stripMirroredBlocks(text, wrapped)).filter(Boolean);
		const contextBlocks = context.map((text) => text.split(whitespaceRun).filter(Boolean).join(" ")).filter(Boolean);
		const identityBlocks = identity.map((text) => text.split(whitespaceRun).filter(Boolean).join(" ")).filter(Boolean);
		return {
			core: normalizeTitleText(written.join(" ")),
			identity: normalizeTitleText(identity.join(" ")),
			context: normalizeTitleText(contextBlocks.join(" ")),
			identityBlocks,
			coreSegments,
			wrapped,
			contextBlocks,
			contextText: contextBlocks.join(" "),
			balanced: true
		};
	}
	var SIMILARITY_THRESHOLD = .5;
	var IDENTITY_MISMATCH_FLOOR = .45;
	var CONTEXT_MISMATCH_FLOOR = .8;
	function hasAiGeneratedMarker(value) {
		const segments = parseTitleSegments(value);
		if (segments === null) return false;
		return segments.some((segment) => segment.kind === "block" && markerOf(segment.text)?.role === "ai");
	}
	function trigramCounts(value) {
		const counts = new Map();
		const characters = [...value.replaceAll(" ", "")];
		if (characters.length === 0) return counts;
		if (characters.length < 3) {
			counts.set(characters.join(""), 1);
			return counts;
		}
		for (let index = 0; index + 3 <= characters.length; index += 1) {
			const trigram = characters.slice(index, index + 3).join("");
			counts.set(trigram, (counts.get(trigram) ?? 0) + 1);
		}
		return counts;
	}
	function trigramDice(left, right) {
		const leftCounts = trigramCounts(left);
		const rightCounts = trigramCounts(right);
		let leftTotal = 0;
		let rightTotal = 0;
		let overlap = 0;
		for (const count of leftCounts.values()) leftTotal += count;
		for (const count of rightCounts.values()) rightTotal += count;
		const total = leftTotal + rightTotal;
		if (total === 0) return 0;
		for (const [trigram, count] of leftCounts) overlap += Math.min(count, rightCounts.get(trigram) ?? 0);
		return 2 * overlap / total;
	}
	function identitiesOf(title, titleJpn) {
		const identities = [];
		for (const value of [title, titleJpn]) {
			if (!value) continue;
			const identity = analyzeTitle(value).identity;
			if (identity) identities.push(identity);
		}
		return identities;
	}
	var CREATOR_NAMESPACES = ["artist:", "group:"];
	function creatorTags(tags) {
		return tags.filter((tag) => CREATOR_NAMESPACES.some((namespace) => tag.startsWith(namespace))).map((tag) => tag.replaceAll("_", " "));
	}
	function creatorVerdict(sourceTags, candidateTags) {
		const source = creatorTags(sourceTags);
		const candidate = creatorTags(candidateTags);
		if (source.length === 0 || candidate.length === 0) return "unknown";
		return source.some((tag) => candidate.includes(tag)) ? "same" : "different";
	}
	function hasAiGeneratedTag(tags) {
		return tags.some((tag) => tag.replaceAll("_", " ") === "other:ai generated");
	}
	function identityAgreement(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn) {
		const sourceIdentities = identitiesOf(sourceTitle, sourceTitleJpn);
		const candidateIdentities = identitiesOf(candidateTitle, candidateTitleJpn);
		if (sourceIdentities.length === 0 || candidateIdentities.length === 0) return null;
		let best = 0;
		for (const source of sourceIdentities) for (const candidate of candidateIdentities) best = Math.max(best, trigramDice(source, candidate));
		return best;
	}
	function relationshipIsBlocked(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn, creators = "unknown") {
		for (const value of [
			sourceTitle,
			sourceTitleJpn,
			candidateTitle,
			candidateTitleJpn
		]) if (value && hasAiGeneratedMarker(value)) return true;
		if (creators === "different") return true;
		if (creators === "same") return false;
		if (identitiesOf(sourceTitle, sourceTitleJpn).length === 0) return false;
		const agreement = identityAgreement(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn);
		return agreement === null || agreement < .5;
	}
	function creatorsAgree(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn, creators = "unknown") {
		if (creators !== "unknown") return creators === "same";
		const agreement = identityAgreement(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn);
		return agreement !== null && agreement >= .5;
	}
	function workTexts(title, titleJpn) {
		const texts = [];
		for (const value of [title, titleJpn]) {
			if (!value) continue;
			const parts = analyzeTitle(value);
			const core = parts.core.replaceAll(" ", "");
			if (core) texts.push({
				core,
				all: core + parts.context.replaceAll(" ", "")
			});
		}
		return texts;
	}
	var MENTION_MIN_LENGTH = 3;
	function mentionsWork(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn) {
		const sources = workTexts(sourceTitle, sourceTitleJpn);
		const candidates = workTexts(candidateTitle, candidateTitleJpn);
		for (const source of sources) for (const candidate of candidates) {
			if (source.core.length >= MENTION_MIN_LENGTH && candidate.all.includes(source.core)) return true;
			if (candidate.core.length >= MENTION_MIN_LENGTH && source.all.includes(candidate.core)) return true;
		}
		return false;
	}
	function workPhrases(title, titleJpn) {
		const phrases = [];
		for (const value of [title, titleJpn]) {
			if (!value) continue;
			for (const segment of analyzeTitle(value).coreSegments) for (const half of segment.split(" | ")) {
				const phrase = normalizeTitleText(readWorkText(half).phrase).replaceAll(" ", "");
				if (phrase.length >= MENTION_MIN_LENGTH) phrases.push(phrase);
			}
		}
		return phrases;
	}
	function sharesWorkPhrase(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn) {
		const sourceCores = workTexts(sourceTitle, sourceTitleJpn).map((text) => text.core);
		const candidateCores = workTexts(candidateTitle, candidateTitleJpn).map((text) => text.core);
		for (const phrase of workPhrases(sourceTitle, sourceTitleJpn)) if (candidateCores.some((core) => core.includes(phrase))) return true;
		for (const phrase of workPhrases(candidateTitle, candidateTitleJpn)) if (sourceCores.some((core) => core.includes(phrase))) return true;
		return false;
	}
	function titleSimilarity(left, right, creators = "unknown") {
		const leftParts = analyzeTitle(left);
		const rightParts = analyzeTitle(right);
		let score = trigramDice(leftParts.core, rightParts.core);
		if (creators !== "same" && leftParts.identity && rightParts.identity) score *= IDENTITY_MISMATCH_FLOOR + .55 * trigramDice(leftParts.identity, rightParts.identity);
		if (leftParts.context && rightParts.context) score *= CONTEXT_MISMATCH_FLOOR + .19999999999999996 * trigramDice(leftParts.context, rightParts.context);
		return score;
	}
	function galleryTitleSimilarity(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn, creators = "unknown") {
		if (relationshipIsBlocked(sourceTitle, sourceTitleJpn, candidateTitle, candidateTitleJpn, creators)) return 0;
		const score = (left, right) => titleSimilarity(left, right, creators);
		const sources = [sourceTitle, sourceTitleJpn].filter(Boolean);
		const candidates = [candidateTitle, candidateTitleJpn].filter(Boolean);
		if (sources.length === 0 || candidates.length === 0) return 0;
		if (sources.length < 2 || candidates.length < 2) {
			let best = 0;
			for (const source of sources) for (const candidate of candidates) best = Math.max(best, score(source, candidate));
			return best;
		}
		const primary = score(sources[0], candidates[0]);
		const direct = [primary, score(sources[1], candidates[1])];
		const cross = [score(sources[0], candidates[1]), score(sources[1], candidates[0])];
		let best = primary;
		for (const pair of [direct, cross]) if (Math.min(...pair) >= .15) best = Math.max(best, (pair[0] + pair[1]) / 2);
		return best;
	}
	var ANTHOLOGY_TAG = "other:anthology";
	var CONTAINER_REQUIRED_SIMILARITY = .85;
	var EMPTY_PLAN = {
		containerTerms: [],
		containerNames: [],
		isContainerCandidate: false,
		chapterTerms: []
	};
	function tagValues(tags, namespace) {
		return tags.filter((tag) => tag.startsWith(`${namespace}:`)).map((tag) => normalizeTitleText(tag.slice(namespace.length + 1).replaceAll("_", " ")));
	}
	function fieldsOf(gallery) {
		return [gallery.title, gallery.titleJpn].filter(Boolean);
	}
	function inContainerChain(source) {
		return source.category === "Manga" || source.tags.includes("other:anthology");
	}
	function planContainerSearch(source, hasLetters, editionTerms) {
		if (!inContainerChain(source)) return EMPTY_PLAN;
		const containerTerms = [];
		const containerNames = [];
		let hasContext = false;
		const parodies = tagValues(source.tags, "parody");
		for (const value of fieldsOf(source)) {
			const { contextBlocks } = analyzeTitle(value);
			if (contextBlocks.length === 0) continue;
			hasContext = true;
			for (const block of contextBlocks) {
				const name = normalizeTitleText(block);
				if (!name || !hasLetters(block) || parodies.includes(name) || containerNames.includes(name)) continue;
				containerTerms.push(block);
				containerNames.push(name);
			}
		}
		const isContainerCandidate = !hasContext;
		const chapterTerms = [];
		if (isContainerCandidate) {
			for (const value of fieldsOf(source)) for (const segment of analyzeTitle(value).coreSegments) if (hasLetters(segment) && !editionTerms.includes(segment) && !chapterTerms.includes(segment)) chapterTerms.push(segment);
		}
		return {
			containerTerms,
			containerNames,
			isContainerCandidate,
			chapterTerms
		};
	}
	function matchContainers(containerNames, hits) {
		return hits.filter((hit) => fieldsOf(hit).some((value) => containerNames.some((wanted) => trigramDice(analyzeTitle(value).core, wanted) >= CONTAINER_REQUIRED_SIMILARITY)));
	}
	function matchExtractedChapters(source, hits) {
		const names = fieldsOf(source).map((value) => analyzeTitle(value).core).filter(Boolean);
		if (names.length === 0) return [];
		return hits.filter((hit) => fieldsOf(hit).some((value) => analyzeTitle(value).contextBlocks.some((block) => names.includes(normalizeTitleText(block)))));
	}
	var NON_LANGUAGE_TAGS = {
		translated: true,
		rewrite: true,
		speechless: true,
		"text cleaned": true
	};
	function languagesFromTags(tags) {
		const languages = [];
		for (const tag of tags) {
			if (!tag.startsWith("language:")) continue;
			const value = tag.slice(9).replaceAll("_", " ");
			if (!(value in NON_LANGUAGE_TAGS)) languages.push(value);
		}
		return languages;
	}
	function languageFromTitle(title) {
		const segments = parseTitleSegments(title);
		if (segments === null) return null;
		for (const segment of segments) {
			if (segment.kind !== "block") continue;
			const marker = markerOf(segment.text);
			if (marker?.lang) return marker.lang;
		}
		return null;
	}
	function detectLanguage(title, tags) {
		const [tagged] = languagesFromTags(tags);
		if (tagged) return tagged;
		const marked = languageFromTitle(title);
		if (marked) return marked;
		if (tags.length > 0 && !tags.includes("language:translated") && !tags.includes("language:rewrite")) return "japanese";
		return "unknown";
	}
	var BY_VALUE = Object.fromEntries([
		{
			value: "chinese",
			code: "中",
			name: {
				en: "Chinese",
				"zh-TW": "中文",
				"zh-CN": "中文",
				ja: "中国語",
				ko: "중국어"
			}
		},
		{
			value: "japanese",
			code: "あ",
			name: {
				en: "Japanese",
				"zh-TW": "日文",
				"zh-CN": "日文",
				ja: "日本語",
				ko: "일본어"
			}
		},
		{
			value: "english",
			code: "EN",
			name: {
				en: "English",
				"zh-TW": "英文",
				"zh-CN": "英文",
				ja: "英語",
				ko: "영어"
			}
		},
		{
			value: "korean",
			code: "한",
			name: {
				en: "Korean",
				"zh-TW": "韓文",
				"zh-CN": "韩文",
				ja: "韓国語",
				ko: "한국어"
			}
		},
		{
			value: "spanish",
			code: "ES",
			name: {
				en: "Spanish",
				"zh-TW": "西班牙文",
				"zh-CN": "西班牙文",
				ja: "スペイン語",
				ko: "스페인어"
			}
		},
		{
			value: "russian",
			code: "RU",
			name: {
				en: "Russian",
				"zh-TW": "俄文",
				"zh-CN": "俄文",
				ja: "ロシア語",
				ko: "러시아어"
			}
		},
		{
			value: "french",
			code: "FR",
			name: {
				en: "French",
				"zh-TW": "法文",
				"zh-CN": "法文",
				ja: "フランス語",
				ko: "프랑스어"
			}
		},
		{
			value: "german",
			code: "DE",
			name: {
				en: "German",
				"zh-TW": "德文",
				"zh-CN": "德文",
				ja: "ドイツ語",
				ko: "독일어"
			}
		},
		{
			value: "italian",
			code: "IT",
			name: {
				en: "Italian",
				"zh-TW": "義大利文",
				"zh-CN": "意大利文",
				ja: "イタリア語",
				ko: "이탈리아어"
			}
		},
		{
			value: "portuguese",
			code: "PT",
			name: {
				en: "Portuguese",
				"zh-TW": "葡萄牙文",
				"zh-CN": "葡萄牙文",
				ja: "ポルトガル語",
				ko: "포르투갈어"
			}
		},
		{
			value: "thai",
			code: "TH",
			name: {
				en: "Thai",
				"zh-TW": "泰文",
				"zh-CN": "泰文",
				ja: "タイ語",
				ko: "태국어"
			}
		},
		{
			value: "vietnamese",
			code: "VI",
			name: {
				en: "Vietnamese",
				"zh-TW": "越南文",
				"zh-CN": "越南文",
				ja: "ベトナム語",
				ko: "베트남어"
			}
		},
		{
			value: "polish",
			code: "PL",
			name: {
				en: "Polish",
				"zh-TW": "波蘭文",
				"zh-CN": "波兰文",
				ja: "ポーランド語",
				ko: "폴란드어"
			}
		},
		{
			value: "hungarian",
			code: "HU",
			name: {
				en: "Hungarian",
				"zh-TW": "匈牙利文",
				"zh-CN": "匈牙利文",
				ja: "ハンガリー語",
				ko: "헝가리어"
			}
		},
		{
			value: "dutch",
			code: "NL",
			name: {
				en: "Dutch",
				"zh-TW": "荷蘭文",
				"zh-CN": "荷兰文",
				ja: "オランダ語",
				ko: "네덜란드어"
			}
		},
		{
			value: "indonesian",
			code: "ID",
			name: {
				en: "Indonesian",
				"zh-TW": "印尼文",
				"zh-CN": "印尼文",
				ja: "インドネシア語",
				ko: "인도네시아어"
			}
		},
		{
			value: "ukrainian",
			code: "UK",
			name: {
				en: "Ukrainian",
				"zh-TW": "烏克蘭文",
				"zh-CN": "乌克兰文",
				ja: "ウクライナ語",
				ko: "우크라이나어"
			}
		},
		{
			value: "turkish",
			code: "TR",
			name: {
				en: "Turkish",
				"zh-TW": "土耳其文",
				"zh-CN": "土耳其文",
				ja: "トルコ語",
				ko: "튀르키예어"
			}
		},
		{
			value: "arabic",
			code: "AR",
			name: {
				en: "Arabic",
				"zh-TW": "阿拉伯文",
				"zh-CN": "阿拉伯文",
				ja: "アラビア語",
				ko: "아랍어"
			}
		},
		{
			value: "czech",
			code: "CS",
			name: {
				en: "Czech",
				"zh-TW": "捷克文",
				"zh-CN": "捷克文",
				ja: "チェコ語",
				ko: "체코어"
			}
		},
		{
			value: "greek",
			code: "EL",
			name: {
				en: "Greek",
				"zh-TW": "希臘文",
				"zh-CN": "希腊文",
				ja: "ギリシャ語",
				ko: "그리스어"
			}
		},
		{
			value: "finnish",
			code: "FI",
			name: {
				en: "Finnish",
				"zh-TW": "芬蘭文",
				"zh-CN": "芬兰文",
				ja: "フィンランド語",
				ko: "핀란드어"
			}
		},
		{
			value: "swedish",
			code: "SV",
			name: {
				en: "Swedish",
				"zh-TW": "瑞典文",
				"zh-CN": "瑞典文",
				ja: "スウェーデン語",
				ko: "스웨덴어"
			}
		},
		{
			value: "norwegian",
			code: "NO",
			name: {
				en: "Norwegian",
				"zh-TW": "挪威文",
				"zh-CN": "挪威文",
				ja: "ノルウェー語",
				ko: "노르웨이어"
			}
		},
		{
			value: "danish",
			code: "DA",
			name: {
				en: "Danish",
				"zh-TW": "丹麥文",
				"zh-CN": "丹麦文",
				ja: "デンマーク語",
				ko: "덴마크어"
			}
		},
		{
			value: "romanian",
			code: "RO",
			name: {
				en: "Romanian",
				"zh-TW": "羅馬尼亞文",
				"zh-CN": "罗马尼亚文",
				ja: "ルーマニア語",
				ko: "루마니아어"
			}
		},
		{
			value: "hebrew",
			code: "HE",
			name: {
				en: "Hebrew",
				"zh-TW": "希伯來文",
				"zh-CN": "希伯来文",
				ja: "ヘブライ語",
				ko: "히브리어"
			}
		},
		{
			value: "hindi",
			code: "HI",
			name: {
				en: "Hindi",
				"zh-TW": "印地文",
				"zh-CN": "印地文",
				ja: "ヒンディー語",
				ko: "힌디어"
			}
		},
		{
			value: "tagalog",
			code: "TL",
			name: {
				en: "Tagalog",
				"zh-TW": "他加祿文",
				"zh-CN": "他加禄文",
				ja: "タガログ語",
				ko: "타갈로그어"
			}
		},
		{
			value: "mongolian",
			code: "MN",
			name: {
				en: "Mongolian",
				"zh-TW": "蒙古文",
				"zh-CN": "蒙古文",
				ja: "モンゴル語",
				ko: "몽골어"
			}
		},
		{
			value: "esperanto",
			code: "EO",
			name: {
				en: "Esperanto",
				"zh-TW": "世界語",
				"zh-CN": "世界语",
				ja: "エスペラント",
				ko: "에스페란토"
			}
		},
		{
			value: "speechless",
			code: "…",
			name: {
				en: "Speechless",
				"zh-TW": "無言",
				"zh-CN": "无言",
				ja: "無言",
				ko: "대사 없음"
			}
		},
		{
			value: "text cleaned",
			code: "□",
			name: {
				en: "Text cleaned",
				"zh-TW": "文字清除",
				"zh-CN": "文字清除",
				ja: "文字消去",
				ko: "글자 지움"
			}
		},
		{
			value: "rewrite",
			code: "RW",
			name: {
				en: "Rewrite",
				"zh-TW": "重寫",
				"zh-CN": "重写",
				ja: "リライト",
				ko: "개작"
			}
		},
		{
			value: "unknown",
			code: "?",
			name: {
				en: "Unknown",
				"zh-TW": "未知",
				"zh-CN": "未知",
				ja: "不明",
				ko: "알 수 없음"
			}
		}
	].map((language) => [language.value, language]));
	function languageOf(value) {
		return BY_VALUE[value] ?? {
			value,
			code: value.slice(0, 3).toUpperCase(),
			name: {
				en: value,
				"zh-TW": value,
				"zh-CN": value,
				ja: value,
				ko: value
			}
		};
	}
	function workKeysOf(gallery) {
		const keys = [];
		for (const value of [gallery.title, gallery.titleJpn]) {
			if (!value) continue;
			for (const segment of analyzeTitle(value).coreSegments) for (const part of segment.split(" | ")) {
				const { phrase, counter } = readWorkText(normalizeTitleText(part));
				if (!phrase) continue;
				keys.push({
					phrase,
					counter
				});
			}
		}
		return keys;
	}
	function relationOf(source, hit) {
		const hitKeys = workKeysOf(hit);
		for (const left of workKeysOf(source)) if (hitKeys.some((right) => right.phrase === left.phrase && right.counter === left.counter)) return "edition";
		return "series";
	}
	var FLAG_TAGS = {
		"language:rewrite": "rewrite",
		"other:rough translation": "rough translation",
		"other:extraneous ads": "extraneous ads"
	};
	function editionFlags(tags) {
		const flags = [];
		for (const tag of tags) {
			const flag = FLAG_TAGS[tag.replaceAll("_", " ")];
			if (flag && !flags.includes(flag)) flags.push(flag);
		}
		return flags;
	}
	function dedupe(hits, excludeGid) {
		const seen = new Set([excludeGid]);
		const unique = [];
		for (const hit of hits) {
			if (seen.has(hit.gid)) continue;
			seen.add(hit.gid);
			unique.push(hit);
		}
		return unique;
	}
	function counterNumber(counter) {
		let digits = "";
		for (const character of counter) if (character >= "0" && character <= "9") digits += character;
		else if (digits) break;
		if (digits) return Number(digits);
		return parseCjkNumeral(counter);
	}
	function orderOf(edition) {
		const halves = analyzeTitle(edition.hit.title || edition.hit.titleJpn).coreSegments.join(" ").split(" | ");
		let counter = readWorkText(halves[0]).counter;
		for (const half of halves.slice(1)) {
			if (counter) break;
			counter = readWorkText(half).counter;
		}
		return {
			number: counterNumber(counter),
			posted: edition.hit.posted ?? Number.MAX_SAFE_INTEGER
		};
	}
	function compareEditions(left, right) {
		const a = orderOf(left);
		const b = orderOf(right);
		if (a.number !== null && b.number !== null && a.number !== b.number) return a.number - b.number;
		return a.posted - b.posted;
	}
	function toEdition(hit, score) {
		return {
			hit,
			score,
			language: detectLanguage(hit.title, hit.tags),
			flags: editionFlags(hit.tags)
		};
	}
	function scoreEditions(source, hits, fixedRange = false) {
		const editions = [];
		const series = [];
		const related = [];
		for (const hit of hits) {
			if (hasAiGeneratedTag(hit.tags)) continue;
			const creators = creatorVerdict(source.tags, hit.tags);
			const titles = [
				source.title,
				source.titleJpn,
				hit.title,
				hit.titleJpn
			];
			const score = galleryTitleSimilarity(...titles, creators);
			const blocked = relationshipIsBlocked(...titles, creators);
			if (creators === "same" ? !blocked && sharesWorkPhrase(...titles) : score >= .5) (relationOf(source, hit) === "edition" ? editions : series).push(toEdition(hit, score));
			else if (!blocked && creatorsAgree(...titles, creators) && mentionsWork(...titles)) series.push(toEdition(hit, SIMILARITY_THRESHOLD));
			else if (fixedRange && creators === "same" && !blocked) related.push(toEdition(hit, score));
		}
		return {
			editions,
			series,
			related
		};
	}
	function numbersOf(text) {
		const numbers = [];
		let run = "";
		for (const character of text) if (character >= "0" && character <= "9") run += character;
		else if (run) {
			numbers.push(run);
			run = "";
		}
		if (run) numbers.push(run);
		return numbers;
	}
	function bookKeyOf(hit) {
		const parts = analyzeTitle(hit.title || hit.titleJpn);
		const halves = parts.coreSegments.join(" ").split(" | ");
		const head = readWorkText(halves[0]);
		let counter = head.counter;
		for (const half of halves.slice(1)) {
			if (counter) break;
			counter = readWorkText(half).counter;
		}
		return [
			parts.identity,
			normalizeMarkerText(head.phrase),
			counter,
			numbersOf(halves[0]).join("."),
			parts.wrapped.map(normalizeMarkerText).sort().join(".")
		].join("\0");
	}
	function groupReleases(editions) {
		const byBook = new Map();
		for (const edition of editions) {
			const key = bookKeyOf(edition.hit);
			const bucket = byBook.get(key) ?? [];
			bucket.push(edition);
			byBook.set(key, bucket);
		}
		return [...byBook.values()].map((releases) => ({ releases: [...releases].sort(compareEditions) })).sort((left, right) => compareEditions(left.releases[0], right.releases[0]));
	}
	function groupByLanguage(editions, priority) {
		const byLanguage = new Map();
		for (const edition of editions) {
			const bucket = byLanguage.get(edition.language) ?? [];
			bucket.push(edition);
			byLanguage.set(edition.language, bucket);
		}
		const rank = (language) => {
			const index = priority.indexOf(language);
			return index === -1 ? priority.length : index;
		};
		return [...byLanguage.entries()].map(([language, items]) => ({
			language: languageOf(language),
			books: groupReleases(items)
		})).sort((a, b) => rank(a.language.value) - rank(b.language.value) || b.books.length - a.books.length);
	}
	var TTL_MS = 864e5;
	var FAMILY = "ehl_cache_";
	var PREFIX = `${FAMILY}e649114df83b_`;
	var REVISION_MARK = "#";
	var MISSING = { state: "missing" };
	var UNUSABLE = { state: "unusable" };
	var snapshot = null;
	var writeSequence = 0;
	function newestFirst(left, right) {
		if (left.at !== right.at) return right.at - left.at;
		if (left.key === right.key) return 0;
		return left.key > right.key ? -1 : 1;
	}
	function store() {
		snapshot ??= scan();
		return snapshot;
	}
	async function scan() {
		const revisions = new Map();
		const foreign = [];
		for (const key of await storageKeys()) {
			if (!key.startsWith(FAMILY)) continue;
			const parsed = readKey(key);
			if (!parsed) {
				foreign.push(key);
				continue;
			}
			const known = revisions.get(parsed.logical);
			if (known) known.push({
				key,
				at: parsed.at
			});
			else revisions.set(parsed.logical, [{
				key,
				at: parsed.at
			}]);
		}
		for (const list of revisions.values()) list.sort(newestFirst);
		return {
			revisions,
			foreign
		};
	}
	function readKey(key) {
		if (!key.startsWith(PREFIX)) return null;
		const mark = key.lastIndexOf(REVISION_MARK);
		if (mark <= PREFIX.length) return null;
		const at = Number.parseInt(key.slice(mark + 1), 10);
		if (!Number.isFinite(at)) return null;
		return {
			logical: key.slice(PREFIX.length, mark),
			at
		};
	}
	function isEnvelope(value) {
		return typeof value === "object" && value !== null && "at" in value && typeof value.at === "number" && Number.isFinite(value.at) && "data" in value;
	}
	function isFresh$1(at) {
		const age = Date.now() - at;
		return age >= 0 && age <= TTL_MS;
	}
	async function readRevision(key) {
		const raw = await storageGet(key);
		if (!raw) return MISSING;
		let parsed;
		try {
			parsed = JSON.parse(raw);
		} catch {
			return UNUSABLE;
		}
		if (!isEnvelope(parsed)) return UNUSABLE;
		if (!isFresh$1(parsed.at)) return UNUSABLE;
		return {
			state: "usable",
			at: parsed.at,
			data: parsed.data
		};
	}
	async function discard$1(current, logical, key) {
		await storageRemove(key);
		const alive = (current.revisions.get(logical) ?? []).filter((revision) => revision.key !== key);
		if (alive.length === 0) current.revisions.delete(logical);
		else current.revisions.set(logical, alive);
	}
	async function cacheGet(key, validate) {
		const current = await store();
		for (const revision of current.revisions.get(key) ?? []) {
			const record = await readRevision(revision.key);
			if (record.state === "missing") continue;
			if (record.state === "usable") {
				const value = record.data;
				if (validate(value)) return {
					data: value,
					at: record.at
				};
			}
			await discard$1(current, key, revision.key);
		}
		return null;
	}
	async function cacheSet(key, data) {
		const at = Date.now();
		const physical = `${PREFIX}${key}${REVISION_MARK}${at}-${(++writeSequence).toString(36).padStart(11, "0")}-${crypto.randomUUID()}`;
		const current = await store();
		let payload;
		try {
			payload = JSON.stringify({
				at,
				data
			});
		} catch (error) {
			console.warn("[EhHyperlink] cache write skipped", error);
			return;
		}
		await storageSet(physical, payload);
		const previous = current.revisions.get(key) ?? [];
		const next = {
			key: physical,
			at
		};
		const newer = previous.filter((revision) => newestFirst(revision, next) < 0);
		current.revisions.set(key, [...newer, next]);
		for (const revision of previous) {
			if (newestFirst(revision, next) < 0) continue;
			await discard$1(current, key, revision.key);
		}
	}
	async function sweepCache() {
		const current = await store();
		for (const key of current.foreign.splice(0)) if ((await readRevision(key)).state === "unusable") await storageRemove(key);
		for (const [logical, revisions] of [...current.revisions]) {
			let kept = false;
			for (const revision of revisions) {
				if (kept) {
					await discard$1(current, logical, revision.key);
					continue;
				}
				const record = await readRevision(revision.key);
				if (record.state === "usable") {
					kept = true;
					continue;
				}
				if (record.state === "unusable") await discard$1(current, logical, revision.key);
			}
		}
	}
	var CATEGORY_BY_PATH = {
		doujinshi: "Doujinshi",
		manga: "Manga",
		artistcg: "Artist CG",
		gamecg: "Game CG",
		western: "Western",
		"non-h": "Non-H",
		imageset: "Image Set",
		cosplay: "Cosplay",
		asianporn: "Asian Porn",
		misc: "Misc"
	};
	var CATEGORY_BY_CLASS = {
		ct1: "Misc",
		ct2: "Doujinshi",
		ct3: "Manga",
		ct4: "Artist CG",
		ct5: "Game CG",
		ct6: "Image Set",
		ct7: "Cosplay",
		ct8: "Asian Porn",
		ct9: "Non-H",
		cta: "Western"
	};
	function fromOnclick(onclick) {
		const start = onclick.indexOf("document.location='");
		if (start === -1) return null;
		const rest = onclick.slice(start + 19);
		return CATEGORY_BY_PATH[(rest.slice(0, rest.indexOf("'")).split("/").filter(Boolean).pop() ?? "").toLowerCase()] ?? null;
	}
	function readCategory(element) {
		if (!element) return "";
		const byClick = fromOnclick(element.getAttribute("onclick") ?? "");
		if (byClick) return byClick;
		for (const name of element.classList) {
			const byClass = CATEGORY_BY_CLASS[name];
			if (byClass) return byClass;
		}
		return element.textContent?.trim() ?? "";
	}
	function galleryRef(hrefOrPath) {
		let pathname = hrefOrPath;
		if (hrefOrPath.includes("://")) try {
			pathname = new URL(hrefOrPath).pathname;
		} catch {
			return null;
		}
		const [, section, gid, token] = pathname.split("/");
		if (section !== "g" || !gid || !token) return null;
		if (![...gid].every((character) => character >= "0" && character <= "9")) return null;
		return {
			gid: Number(gid),
			token
		};
	}
	function pageCount(text) {
		const [count, unit, ...rest] = text.trim().split(whitespaceRun);
		if (rest.length > 0 || !count || unit !== "pages" && unit !== "page") return null;
		if (![...count].every((character) => character >= "0" && character <= "9")) return null;
		return Number(count);
	}
	var SEARCH_INTERVAL_MS = 1e3;
	function pause$2(ms) {
		const { promise, resolve } = Promise.withResolvers();
		setTimeout(resolve, ms);
		return promise;
	}
	function createThrottle({ intervalMs }) {
		let lastAt = 0;
		return { async next() {
			const wait = intervalMs - (Date.now() - lastAt);
			if (wait > 0) await pause$2(wait);
			lastAt = Date.now();
		} };
	}
	var searchThrottle = createThrottle({ intervalMs: SEARCH_INTERVAL_MS });
	function isRecord(value) {
		return typeof value === "object" && value !== null;
	}
	function isStrings(value) {
		return Array.isArray(value) && value.every((entry) => typeof entry === "string");
	}
	function isGalleryId(value) {
		return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
	}
	function isNullableNumber(value) {
		return value === null || typeof value === "number" && Number.isFinite(value);
	}
	function isRating(value) {
		return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= 5;
	}
	function isNullableRating(value) {
		return value === null || isRating(value);
	}
	function isNullableString(value) {
		return value === null || typeof value === "string";
	}
	var MAX_ATTEMPTS = 3;
	var DEADLINE_MS = 3e4;
	var FIRST_BACKOFF_MS = 1e3;
	var TRANSIENT_STATUS = [
		408,
		500,
		502,
		503,
		504
	];
	var RESTRICTED_STATUS = [
		401,
		403,
		429
	];
	var BODY_READERS = [
		"text",
		"json",
		"arrayBuffer",
		"blob",
		"formData"
	];
	var RequestError = class extends Error {
		kind;
		status;
		attempts = 1;
		retryAt;
		constructor(kind, message, status) {
			super(message);
			this.kind = kind;
			this.status = status;
			this.name = "RequestError";
		}
	};
	function stopsRequests(error) {
		if (error.kind === "invalid-response") return true;
		if (error.kind !== "http") return false;
		if (RESTRICTED_STATUS.includes(error.status ?? 0)) return true;
		return (error.retryAt ?? 0) > Date.now();
	}
	function worthRepeating(error) {
		if (error.kind === "network") return true;
		if (error.kind === "timeout") return true;
		if (error.kind === "http") return TRANSIENT_STATUS.includes(error.status ?? 0);
		return false;
	}
	var cooldown = new Map();
	function pause$1(ms) {
		const { promise, resolve } = Promise.withResolvers();
		setTimeout(resolve, ms);
		return promise;
	}
	function transportError(error) {
		if (error instanceof RequestError) return error;
		const name = isRecord(error) ? error.name : void 0;
		const detail = error instanceof Error ? error.message : String(error);
		if (name === "AbortError") return new RequestError("timeout", `no answer within ${DEADLINE_MS}ms`);
		if (name === "TypeError") return new RequestError("network", `request failed: ${detail}`);
		return new RequestError("invalid-response", `request failed: ${detail}`);
	}
	function isAbortError(error) {
		return isRecord(error) && error.name === "AbortError";
	}
	function watchBody(response) {
		return new Proxy(response, { get(target, key) {
			const value = Reflect.get(target, key, target);
			if (typeof value !== "function") return value;
			const call = value;
			if (typeof key !== "string") return call.bind(target);
			if (!BODY_READERS.includes(key)) return call.bind(target);
			return async (...args) => {
				try {
					return await call.apply(target, args);
				} catch (error) {
					throw transportError(error);
				}
			};
		} });
	}
	function retryAfterMs(response) {
		const header = response.headers.get("Retry-After");
		if (header === null) return null;
		const text = header.trim();
		if (text === "") return null;
		const seconds = Number(text);
		if (Number.isFinite(seconds)) {
			if (seconds < 0) return null;
			return seconds * 1e3;
		}
		const at = Date.parse(text);
		if (Number.isNaN(at)) return null;
		return Math.max(0, at - Date.now());
	}
	function retryDelay(asked, backoffMs) {
		if (asked === null) return backoffMs;
		if (asked > DEADLINE_MS) return null;
		return Math.max(asked, backoffMs);
	}
	function discard(response) {
		try {
			response.body?.cancel().catch(() => {});
		} catch {}
	}
	async function exchange(url, init, read) {
		let response;
		try {
			response = await fetch(url, init);
		} catch (error) {
			throw transportError(error);
		}
		if (!response.ok) {
			discard(response);
			const asked = retryAfterMs(response);
			const error = new RequestError("http", `HTTP ${response.status}`, response.status);
			if (asked !== null) error.retryAt = Date.now() + asked;
			return {
				kind: "failed",
				error,
				retryAfterMs: asked
			};
		}
		try {
			return {
				kind: "answered",
				data: await read(watchBody(response))
			};
		} catch (error) {
			if (error instanceof RequestError) throw error;
			if (isAbortError(error)) throw new RequestError("timeout", `body unfinished within ${DEADLINE_MS}ms`);
			throw error;
		}
	}
	async function attempt(url, init, read) {
		const controller = new AbortController();
		const expiry = Promise.withResolvers();
		const timer = setTimeout(() => {
			controller.abort();
			expiry.reject(new RequestError("timeout", `no answer within ${DEADLINE_MS}ms`));
		}, DEADLINE_MS);
		try {
			return await Promise.race([exchange(url, {
				...init,
				signal: controller.signal
			}, read), expiry.promise]);
		} catch (error) {
			if (error instanceof RequestError) return {
				kind: "failed",
				error,
				retryAfterMs: null
			};
			throw error;
		} finally {
			clearTimeout(timer);
			controller.abort();
		}
	}
	async function request(url, init, throttle, read) {
		let origin = url;
		try {
			origin = new URL(url).origin;
		} catch {}
		let attempts = 0;
		let backoffMs = FIRST_BACKOFF_MS;
		for (;;) {
			const holding = cooldown.get(origin);
			if (holding !== void 0) {
				const remainingMs = holding.until - Date.now();
				if (remainingMs > DEADLINE_MS) {
					const error = new RequestError("http", `host asked to wait ${remainingMs}ms`, holding.status);
					error.attempts = attempts;
					error.retryAt = holding.until;
					throw error;
				}
				if (remainingMs > 0) await pause$1(remainingMs);
				cooldown.delete(origin);
			}
			attempts += 1;
			await throttle.next();
			const outcome = await attempt(url, init, read);
			if (outcome.kind === "answered") return {
				data: outcome.data,
				attempts
			};
			const error = outcome.error;
			error.attempts = attempts;
			if (error.retryAt !== void 0) cooldown.set(origin, {
				until: error.retryAt,
				status: error.status ?? 0
			});
			if (!worthRepeating(error)) throw error;
			if (attempts >= MAX_ATTEMPTS) throw error;
			const waitMs = retryDelay(outcome.retryAfterMs, backoffMs);
			if (waitMs === null) throw error;
			await pause$1(waitMs);
			backoffMs *= 2;
		}
	}
	function searchUrl(origin, query, visibility = "published", languages = "account") {
		return `${origin}/?f_cats=0&inline_set=dm_e${visibility === "expunged" ? "&f_sh=on" : ""}&f_sfu=on&f_sft=on${languages === "all" ? "&f_sfl=on" : ""}&f_search=${encodeURIComponent(query)}`;
	}
	function postedSeconds(cell) {
		const text = cell?.textContent?.trim();
		if (!text) return null;
		const parsed = Date.parse(`${text.replace(" ", "T")}Z`);
		return Number.isFinite(parsed) ? Math.round(parsed / 1e3) : null;
	}
	function listedRating(row) {
		const stars = row.querySelector(".ir");
		if (!stars) return null;
		const [left, top] = stars.style.backgroundPosition.split(" ");
		if (!left?.endsWith("px")) return null;
		const x = Number.parseFloat(left);
		if (x > 0) return null;
		if (x % 16 !== 0) return null;
		let rating = 5 + x / 16;
		switch (top) {
			case "-1px": break;
			case "-21px":
				rating -= .5;
				break;
			default: return null;
		}
		return isRating(rating) ? rating : null;
	}
	function isSearchHit(value) {
		if (!isRecord(value)) return false;
		if (!isGalleryId(value.gid)) return false;
		for (const field of [
			"token",
			"href",
			"title",
			"titleJpn",
			"category",
			"thumb"
		]) if (typeof value[field] !== "string") return false;
		if (!isStrings(value.tags)) return false;
		if (!isNullableNumber(value.pages)) return false;
		if (!isNullableNumber(value.posted)) return false;
		if (!isNullableRating(value.rating)) return false;
		return isNullableString(value.torrentHref);
	}
	function isSearchHits(value) {
		return Array.isArray(value) && value.every(isSearchHit);
	}
	function parseSearchResults(html) {
		const rows = new DOMParser().parseFromString(html, "text/html").querySelectorAll(".itg > tbody > tr, .itg > tr, .itg .gl1t");
		const hits = [];
		for (const row of rows) {
			const titleElement = row.querySelector(".glink");
			if (!titleElement) continue;
			const href = row.querySelector(".glname a, .gl1e a, .gl2e a, .gl1t > a, a[href*=\"/g/\"]")?.getAttribute("href") ?? "";
			const ref = galleryRef(href);
			if (ref === null) continue;
			const pages = [...row.querySelectorAll("div")].filter((element) => element.children.length === 0).map((element) => pageCount(element.textContent ?? "")).find((count) => count !== null) ?? null;
			const torrent = row.querySelector(".gldown a");
			const cover = row.querySelector(".gl1e img, .glthumb img, .gl3t img");
			hits.push({
				gid: ref.gid,
				token: ref.token,
				href,
				title: titleElement.textContent?.trim() ?? "",
				titleJpn: "",
				category: readCategory(row.querySelector(".cn, .cs")),
				tags: [...row.querySelectorAll(".gt, .gtl, .gtw")].map((element) => element.getAttribute("title") ?? "").filter(Boolean),
				pages,
				posted: postedSeconds(row.querySelector(`#posted_${ref.gid}, #postedpop_${ref.gid}`)),
				thumb: cover?.getAttribute("data-src") || cover?.getAttribute("src") || "",
				rating: listedRating(row),
				torrentHref: torrent?.getAttribute("href") ?? null
			});
		}
		return hits;
	}
	async function fetchSearch(origin, query, visibility = "published", languages = "account", force = false) {
		const url = searchUrl(origin, query, visibility, languages);
		const cached = force ? null : await cacheGet(url, isSearchHits);
		if (cached) return {
			request: {
				kind: "search",
				url,
				term: query,
				hitCount: cached.data.length,
				cached: true,
				attempts: 0
			},
			hits: cached.data,
			at: cached.at
		};
		try {
			const response = await request(url, { credentials: "same-origin" }, searchThrottle, async (response) => parseSearchResults(await response.text()));
			await cacheSet(url, response.data);
			return {
				request: {
					kind: "search",
					url,
					term: query,
					hitCount: response.data.length,
					attempts: response.attempts
				},
				hits: response.data,
				at: Date.now()
			};
		} catch (error) {
			if (!(error instanceof RequestError)) throw error;
			return {
				request: {
					kind: "search",
					url,
					term: query,
					hitCount: null,
					attempts: error.attempts,
					error
				},
				hits: [],
				at: Date.now()
			};
		}
	}
	function requestFailed(entry) {
		return entry.error !== void 0;
	}
	function requestStopsRun(entry) {
		return entry.error ? stopsRequests(entry.error) : false;
	}
	function resultStatus(requests) {
		if (!requests.some(requestFailed)) return "complete";
		return requests.some((entry) => !entry.error) ? "partial" : "failed";
	}
	var HAN_PAIR = compile(han.times(2));
	var CJK = compile(cjkLetter);
	var HAS_LETTER = compile(letter);
	var NUMERIC = compile(start.and(oneOrMore(digit)).and(end));
	var SLICE = 2;
	function fragmentsOf(phrase) {
		const text = phrase.trim();
		if (!text || !HAS_LETTER.test(text)) return [];
		if (CJK.test(text)) return text.length < 4 ? [text] : unique(cjkSlices(text));
		const tokens = text.split(whitespaceRun).filter(Boolean);
		return tokens.length < 2 ? [text] : unique(tokenSlices(tokens));
	}
	function unique(slices) {
		return [...new Set(slices.filter(Boolean))];
	}
	var UNINDEXED = new Set([
		"a",
		"an",
		"ai",
		"to",
		"the",
		"and",
		"so",
		"on",
		"of",
		"in",
		"small",
		"big",
		"huge",
		"gigantic"
	]);
	function indexable(token) {
		const minimum = NUMERIC.test(token) ? 3 : SLICE;
		return !UNINDEXED.has(token.toLowerCase()) && token.length >= minimum;
	}
	function tokenSlices(tokens) {
		const usable = tokens.filter(indexable);
		if (usable.length === 0) return [tokens.join(" ")];
		const half = Math.ceil(usable.length / 2);
		return [longest(usable.slice(0, half)), longest(usable.slice(half))];
	}
	function longest(tokens) {
		return tokens.reduce((best, token) => token.length > best.length ? token : best, "");
	}
	function cjkSlices(text) {
		const half = Math.max(SLICE, Math.floor(text.length / 2));
		const lead = text.slice(0, half);
		const trail = text.slice(-half);
		let first = firstHanPair(lead) ?? text.slice(0, SLICE);
		let last = lastHanPair(trail) ?? text.slice(-2);
		for (let length = 3; isShortNumeric(first); length += 1) first = text.slice(0, length);
		for (let length = 3; isShortNumeric(last); length += 1) last = text.slice(-length);
		return [first, last];
	}
	function isShortNumeric(slice) {
		const token = slice.trim();
		return NUMERIC.test(token) && token.length < 3;
	}
	function firstHanPair(text) {
		for (let index = 0; index + SLICE <= text.length; index += 1) {
			const pair = text.slice(index, index + SLICE);
			if (HAN_PAIR.test(pair)) return pair;
		}
		return null;
	}
	function lastHanPair(text) {
		for (let index = text.length - SLICE; index >= 0; index -= 1) {
			const pair = text.slice(index, index + SLICE);
			if (HAN_PAIR.test(pair)) return pair;
		}
		return null;
	}
	var CREATOR_SCOPES = {
		artist: "a",
		group: "g"
	};
	function clauseOf(tag) {
		const colon = tag.indexOf(":");
		const prefix = CREATOR_SCOPES[tag.slice(0, colon)];
		return prefix ? `${prefix}:"${tag.slice(colon + 1).replaceAll("_", " ")}$"` : null;
	}
	function soleCreatorScope(tags) {
		const artists = tags.filter((tag) => tag.startsWith("artist:"));
		const groups = tags.filter((tag) => tag.startsWith("group:"));
		if (artists.length === 1) return clauseOf(artists[0]);
		if (artists.length === 0 && groups.length === 1) return clauseOf(groups[0]);
		return null;
	}
	function creatorScope(tags) {
		const clauses = tags.map(clauseOf).filter((clause) => clause !== null);
		if (clauses.length <= 1) return clauses.join("");
		return clauses.map((clause) => `~${clause}`).join(" ");
	}
	var PARODY_PREFIX = "parody:";
	function seriesQueriesOf(source) {
		const parodies = new Set();
		for (const tag of source.tags) {
			if (!tag.startsWith(PARODY_PREFIX)) continue;
			const name = tag.slice(7).replaceAll("_", " ");
			if (!name) continue;
			if (name === "original") continue;
			parodies.add(name);
		}
		if (parodies.size === 0) return [];
		const sole = soleCreatorScope(source.tags);
		const scopes = [];
		if (sole) scopes.push(sole);
		else {
			const creators = source.tags.filter((tag) => clauseOf(tag) !== null);
			const perQuery = 4;
			for (let index = 0; index < creators.length; index += perQuery) scopes.push(creatorScope(creators.slice(index, index + perQuery)));
		}
		const queries = [];
		for (const scope of scopes) for (const name of parodies) queries.push(`${scope} p:"${name}$"`);
		return queries;
	}
	var COSPLAYER_PREFIX = "cosplayer:";
	function cosplayerTags(tags) {
		const names = [];
		for (const tag of tags) {
			if (!tag.startsWith(COSPLAYER_PREFIX)) continue;
			const name = tag.slice(10).replaceAll("_", " ");
			if (!name) continue;
			if (!names.includes(name)) names.push(name);
		}
		return names;
	}
	var REALPORN_TAG = "other:realporn";
	var REALPORN_CLAUSE = "other:\"realporn$\"";
	var LETTER_RE = compile(letter);
	function editionTermsOf(coreSegment, keepCounter = false) {
		return coreSegment.split(" | ").map((part) => keepCounter ? part.trim() : readWorkText(part).phrase).filter((part) => LETTER_RE.test(part));
	}
	function fieldTerms(value, keepCounter) {
		const parts = analyzeTitle(value);
		const terms = [];
		for (const segment of parts.coreSegments) for (const term of editionTermsOf(segment, keepCounter)) if (!terms.includes(term)) terms.push(term);
		return {
			terms,
			identityBlocks: parts.identityBlocks,
			balanced: parts.balanced
		};
	}
	function planSearch(source) {
		const visibility = source.tags.includes(REALPORN_TAG) ? "expunged" : "published";
		const cosplayers = cosplayerTags(source.tags);
		if (cosplayers.length > 0) return directPlan("cosplayer", cosplayers.map((name) => `${COSPLAYER_PREFIX}"${name}$"`), visibility);
		const anthology = source.tags.includes(ANTHOLOGY_TAG);
		const roman = source.title ? fieldTerms(source.title, anthology) : {
			terms: [],
			identityBlocks: [],
			balanced: true
		};
		const japanese = source.titleJpn ? fieldTerms(source.titleJpn, anthology) : {
			terms: [],
			identityBlocks: [],
			balanced: true
		};
		if (visibility === "expunged") {
			const identities = [...new Set([...roman.identityBlocks, ...japanese.identityBlocks])];
			return directPlan("realporn", identities.length > 0 ? identities : sliceTerms(japanese, roman), visibility);
		}
		const phrases = [];
		for (const term of [...roman.terms, ...japanese.terms]) if (!phrases.includes(term)) phrases.push(term);
		const sole = anthology ? null : soleCreatorScope(source.tags);
		const slices = sole ? sliceTerms(japanese, roman) : [];
		return {
			mode: "work",
			visibility: "published",
			editionTerms: slices.length > 0 ? slices : phrases,
			scope: anthology ? "" : sole ?? creatorScope(source.tags),
			fixedRange: sole !== null && slices.length > 0,
			...planContainerSearch(source, (text) => LETTER_RE.test(text), phrases)
		};
	}
	function directPlan(mode, editionTerms, visibility) {
		return {
			mode,
			visibility,
			editionTerms,
			scope: "",
			fixedRange: false,
			containerTerms: [],
			containerNames: [],
			chapterTerms: [],
			isContainerCandidate: false
		};
	}
	function queryOf(plan, term) {
		const clauses = [plan.mode === "cosplayer" ? term : `title:"${term}"`];
		if (plan.scope) clauses.push(plan.scope);
		if (plan.visibility === "expunged") clauses.push(REALPORN_CLAUSE);
		return clauses.join(" ");
	}
	function sliceTerms(japanese, roman) {
		const fromJpn = japanese.balanced ? fragmentsOf(japanese.terms[0] ?? "") : [];
		const fromRoman = roman.balanced ? fragmentsOf(roman.terms[0] ?? "") : [];
		const left = fromJpn[0];
		const right = fromRoman.at(-1);
		if (left === void 0) return fromRoman;
		if (right === void 0) return fromJpn;
		return [...new Set([left, right])];
	}
	function fullTitles(gallery) {
		return [gallery.title, gallery.titleJpn].map(normalizeMarkerText).filter(Boolean);
	}
	function selectDiscoveries(source, hits) {
		const isCosplayerSource = cosplayerTags(source.tags).length > 0;
		const sourceTitles = new Set(isCosplayerSource ? fullTitles(source) : []);
		const seen = new Set([source.gid]);
		const selected = [];
		for (const hit of hits) {
			if (seen.has(hit.gid)) continue;
			seen.add(hit.gid);
			if (isCosplayerSource) {
				if (fullTitles(hit).some((title) => sourceTitles.has(title))) continue;
			}
			selected.push(hit);
		}
		return selected;
	}
	async function findEditions(source, origin, priority, { force = false, onProgress, onResult, maxRequests = 5, languages = "account" } = {}) {
		const plan = planSearch(source);
		sweepCache().catch(() => {});
		if (hasAiGeneratedTag(source.tags)) return {
			plan,
			status: "complete",
			requests: [],
			dataAt: Date.now(),
			editions: [],
			series: [],
			related: [],
			chapters: [],
			containers: []
		};
		const seriesQueries = plan.mode === "work" ? seriesQueriesOf(source) : [];
		let done = 0;
		let total = plan.editionTerms.length + plan.containerTerms.length + seriesQueries.length;
		const reportProgress = () => onProgress?.({
			done,
			total: Math.min(total, maxRequests)
		});
		const requests = [];
		const search = async (queries) => {
			const pages = [];
			for (const query of queries) {
				if (requests.some(requestStopsRun)) break;
				if (requests.length >= maxRequests) break;
				const page = await fetchSearch(origin, query, plan.visibility, languages, force);
				pages.push(page);
				requests.push(page.request);
				done += 1;
				reportProgress();
			}
			return pages;
		};
		reportProgress();
		const containerPages = await search(plan.containerTerms.map((term) => queryOf(plan, term)));
		const containerHits = dedupe(containerPages.flatMap((page) => page.hits), source.gid);
		const containers = groupByLanguage(matchContainers(plan.containerNames, containerHits).map((hit) => toEdition(hit, null)), priority);
		if (plan.containerTerms.length > 0) onResult?.({
			plan,
			status: resultStatus(requests),
			requests: [...requests],
			dataAt: containerPages.length > 0 ? Math.min(...containerPages.map((page) => page.at)) : Date.now(),
			editions: [],
			series: [],
			related: [],
			chapters: [],
			containers
		});
		const editionPages = await search(plan.editionTerms.map((term) => queryOf(plan, term)));
		const sourceOnEveryFirstPage = editionPages.length > 0 && editionPages.every((page) => page.hits.some((hit) => hit.gid === source.gid));
		let chapterPages = [];
		if (!sourceOnEveryFirstPage) {
			total += plan.chapterTerms.length;
			reportProgress();
			chapterPages = await search(plan.chapterTerms.map((term) => queryOf(plan, term)));
		}
		const candidates = new Map();
		const searchPages = [...containerPages];
		const resultFor = (pages) => {
			for (const page of pages) for (const hit of page.hits) {
				if (hit.gid === source.gid) continue;
				if (candidates.has(hit.gid)) continue;
				candidates.set(hit.gid, hit);
			}
			searchPages.push(...pages);
			const hits = [...candidates.values()];
			const chapters = plan.isContainerCandidate ? matchExtractedChapters(source, hits) : [];
			const chapterGids = new Set(chapters.map((hit) => hit.gid));
			const { editions, series, related } = plan.mode === "work" ? scoreEditions(source, hits.filter((hit) => !chapterGids.has(hit.gid)), plan.fixedRange) : {
				editions: [],
				series: [],
				related: selectDiscoveries(source, hits).map((hit) => toEdition(hit, null))
			};
			const dataAt = Math.min(...searchPages.map((page) => page.at));
			return {
				plan,
				status: resultStatus(requests),
				requests: [...requests],
				dataAt: Number.isFinite(dataAt) ? dataAt : Date.now(),
				editions: groupByLanguage(editions, priority),
				series: groupByLanguage(series, priority),
				related: groupByLanguage(related, priority),
				chapters: groupByLanguage(chapters.map((hit) => toEdition(hit, null)), priority),
				containers
			};
		};
		const ordinaryPages = [...editionPages, ...chapterPages];
		const ordinary = resultFor(ordinaryPages);
		if (seriesQueries.length === 0) return ordinary;
		if (requests.some(requestStopsRun)) return ordinary;
		if (ordinaryPages.length > 0) onResult?.(ordinary);
		return resultFor(await search(seriesQueries));
	}
	var LOCALES = [
		"zh-TW",
		"zh-CN",
		"en",
		"ja",
		"ko"
	];
	function isLocaleChoice(value) {
		return value === "auto" || LOCALES.includes(value);
	}
	var TRADITIONAL_REGIONS = [
		"tw",
		"hk",
		"mo"
	];
	function detectLocale(languages) {
		for (const language of languages) {
			const parts = language.toLowerCase().split("-");
			const primary = parts[0];
			if (primary === "zh") {
				if (parts.includes("hans")) return "zh-CN";
				if (parts.includes("hant")) return "zh-TW";
				return parts.some((part) => TRADITIONAL_REGIONS.includes(part)) ? "zh-TW" : "zh-CN";
			}
			if (primary === "en") return "en";
			if (primary === "ja") return "ja";
			if (primary === "ko") return "ko";
		}
		return "en";
	}
	function resolveLocale(choice, languages) {
		return choice === "auto" ? detectLocale(languages) : choice;
	}
	var MESSAGES = {
		en: {
			searching: "Searching…",
			notFound: "No results",
			noTitle: "No searchable title",
			failed: "Search failed",
			partial: "Some requests failed; results are incomplete",
			networkFailed: "Network error",
			requestTimedOut: "Request timed out",
			httpFailed: "HTTP error",
			invalidResponse: "Invalid response",
			requestAttempts: "Attempts",
			container: "Source",
			containerTitle: "Magazine or tankoubon this chapter came from",
			editionsTitle: "This book in other languages and releases",
			series: "Series",
			seriesTitle: "Other books of the same series",
			related: "Related",
			relatedTitle: "Same creator and wording, relation unproven",
			cosplayerRelatedTitle: "Other works by the same cosplayer",
			directRelatedTitle: "Results matching the search, without title similarity filtering",
			chapters: "Chapters",
			chaptersTitle: "Chapters cut from this magazine or tankoubon",
			requestsTitle: "URLs this script requested for this gallery",
			searchRequests: "Search pages",
			searchHits: "Hits",
			searchHitsTitle: "Galleries returned on this search page, before filtering",
			noRequests: "Nothing was requested",
			nothingSent: "Nothing left the browser; every response came from the cache",
			fromCache: "from cache",
			dataAsOf: "As of",
			refetch: "Refetch",
			refetchTitle: "Discard the cached responses for this gallery and ask the host again",
			pages: "p",
			copyLink: "Copy gallery link",
			linkCopied: "Link copied",
			rewrite: "rewrite",
			roughTranslation: "rough translation",
			extraneousAds: "extraneous ads",
			settings: "Settings",
			decrease: "Decrease",
			increase: "Increase",
			settingGroupRelated: "Related galleries on E-Hentai",
			settingGroupSources: "Searching outside sources",
			settingLanguage: "Language",
			settingLanguageAuto: "Browser default",
			settingShowExcludedLanguages: "Show languages excluded in E-Hentai settings",
			settingView: "View",
			settingMaxRequests: "Max searches per gallery",
			viewList: "List",
			viewCovers: "Covers",
			pagingPerksTitle: "Paging Enlargement",
			pagingPerksDescription: "Each search reads one page of results, 25 galleries by default; this perk raises that to 50 or 100.",
			pagingPerkI: "I: 50/page · 500 Hath",
			pagingPerkII: "II: 100/page · +1,000 Hath",
			hathPerks: "Hath Perks",
			pagingPerksDetails: "Details",
			search: "Search",
			searchTitle: "Search Google, DuckDuckGo, DLsite and pixiv for this gallery and list the results here",
			close: "Close",
			termTitle: "Title",
			termWork: "Work",
			termCircle: "Circle",
			termArtist: "Artist",
			previewPage: "Page {n}",
			previewNextPage: "Next page",
			settingDebug: "Debug log for searches",
			debugLog: "Log",
			debugCopy: "Copy",
			debugClear: "Clear",
			debugEmpty: "Nothing logged yet",
			copyResultLink: "Copy link",
			previewLoading: "Loading the search in a background tab…",
			previewTimeout: "The background tab did not answer in time",
			previewEmpty: "No results",
			previewUnreadable: "The page showed no results to read; it may want an age check or a sign-in, so open the search itself",
			previewBlocked: "The site asked to verify you are not a robot; open the search to continue",
			previewClosed: "The background tab was closed before it answered; another extension may be closing new tabs (a tab limit?)",
			previewUnavailable: "The userscript manager does not let this script open tabs; reinstall the script"
		},
		"zh-TW": {
			searching: "搜尋中…",
			notFound: "未找到",
			noTitle: "沒有可搜尋的標題",
			failed: "搜尋失敗",
			partial: "部分請求失敗,結果不完整",
			networkFailed: "網路錯誤",
			requestTimedOut: "請求逾時",
			httpFailed: "HTTP 錯誤",
			invalidResponse: "回應格式異常",
			requestAttempts: "嘗試次數",
			container: "原刊",
			containerTitle: "這一章來自的雜誌或單行本",
			editionsTitle: "同一本的其他語言/版本",
			series: "系列",
			seriesTitle: "同系列的其他集",
			related: "相關作品",
			relatedTitle: "同作者、用詞相同,關係未經確認",
			cosplayerRelatedTitle: "同一位 cosplayer 的其他作品",
			directRelatedTitle: "符合搜尋條件的結果,不以標題相似度篩選",
			chapters: "收錄作品",
			chaptersTitle: "從這本雜誌或單行本切出來的作品",
			requestsTitle: "這個腳本為這本畫廊發出的請求",
			searchRequests: "搜尋頁",
			searchHits: "Hits",
			searchHitsTitle: "此搜尋頁回傳的圖庫數,篩選前",
			noRequests: "一次請求都沒有發出",
			nothingSent: "沒有發出任何請求,全部來自快取",
			fromCache: "來自快取",
			dataAsOf: "資料時間",
			refetch: "重新抓取",
			refetchTitle: "丟掉這本的快取,重新向站方請求",
			pages: "頁",
			copyLink: "複製畫廊網址",
			linkCopied: "已複製網址",
			rewrite: "重寫",
			roughTranslation: "粗譯",
			extraneousAds: "外部廣告",
			settings: "設定",
			decrease: "減少",
			increase: "增加",
			settingGroupRelated: "E 站內部關聯",
			settingGroupSources: "搜索外部來源",
			settingLanguage: "語言",
			settingLanguageAuto: "跟隨瀏覽器",
			settingShowExcludedLanguages: "顯示 E-Hentai 設定中排除的語言",
			settingView: "檢視",
			settingMaxRequests: "每個畫廊最多搜尋次數",
			viewList: "清單",
			viewCovers: "封面",
			pagingPerksTitle: "Paging Enlargement",
			pagingPerksDescription: "每次搜尋只讀一頁結果,預設 25 筆;買了這個 perk 可以提高到 50 或 100 筆。",
			pagingPerkI: "I:50 筆/頁 · 500 Hath",
			pagingPerkII: "II:100 筆/頁 · +1,000 Hath",
			hathPerks: "Hath Perks",
			pagingPerksDetails: "說明",
			search: "搜索",
			searchTitle: "用這本的標題、社團、作者搜 Google、DuckDuckGo、DLsite、pixiv,結果列在這裡",
			close: "關閉",
			termTitle: "標題",
			termWork: "作品",
			termCircle: "社團",
			termArtist: "作者",
			previewPage: "第 {n} 頁",
			previewNextPage: "下一頁",
			settingDebug: "搜索的除錯 log",
			debugLog: "Log",
			debugCopy: "複製",
			debugClear: "清除",
			debugEmpty: "還沒有任何紀錄",
			copyResultLink: "複製網址",
			previewLoading: "正在背景分頁打開搜尋…",
			previewTimeout: "背景分頁沒有及時回應",
			previewEmpty: "沒有搜尋結果",
			previewUnreadable: "頁面上讀不到結果,可能要先確認年齡或登入;請直接打開那個搜尋",
			previewBlocked: "網站要求驗證不是機器人;請直接打開搜尋頁處理",
			previewClosed: "背景分頁還沒回答就被關掉了;可能是其他擴充套件關掉了新分頁(例如分頁數上限)",
			previewUnavailable: "腳本管理器沒有讓這個腳本開分頁;請重新安裝腳本"
		},
		"zh-CN": {
			searching: "搜索中…",
			notFound: "未找到",
			noTitle: "没有可搜索的标题",
			failed: "搜索失败",
			partial: "部分请求失败,结果不完整",
			networkFailed: "网络错误",
			requestTimedOut: "请求超时",
			httpFailed: "HTTP 错误",
			invalidResponse: "响应格式异常",
			requestAttempts: "尝试次数",
			container: "原刊",
			containerTitle: "这一章来自的杂志或单行本",
			editionsTitle: "同一本的其他语言/版本",
			series: "系列",
			seriesTitle: "同系列的其他集",
			related: "相关作品",
			relatedTitle: "同作者、用词相同,关系未经确认",
			cosplayerRelatedTitle: "同一位 cosplayer 的其他作品",
			directRelatedTitle: "符合搜索条件的结果,不以标题相似度筛选",
			chapters: "收录作品",
			chaptersTitle: "从这本杂志或单行本切出来的作品",
			requestsTitle: "这个脚本为这本画廊发出的请求",
			searchRequests: "搜索页",
			searchHits: "Hits",
			searchHitsTitle: "此搜索页返回的图库数,筛选前",
			noRequests: "一次请求都没有发出",
			nothingSent: "没有发出任何请求,全部来自缓存",
			fromCache: "来自缓存",
			dataAsOf: "数据时间",
			refetch: "重新抓取",
			refetchTitle: "丢掉这本的缓存,重新向站方请求",
			pages: "页",
			copyLink: "复制画廊网址",
			linkCopied: "已复制网址",
			rewrite: "重写",
			roughTranslation: "粗译",
			extraneousAds: "外部广告",
			settings: "设置",
			decrease: "减少",
			increase: "增加",
			settingGroupRelated: "E 站内部关联",
			settingGroupSources: "搜索外部来源",
			settingLanguage: "语言",
			settingLanguageAuto: "跟随浏览器",
			settingShowExcludedLanguages: "显示 E-Hentai 设置中排除的语言",
			settingView: "视图",
			settingMaxRequests: "每个画廊最多搜索次数",
			viewList: "列表",
			viewCovers: "封面",
			pagingPerksTitle: "Paging Enlargement",
			pagingPerksDescription: "每次搜索只读一页结果,默认 25 条;买了这个 perk 可以提高到 50 或 100 条。",
			pagingPerkI: "I:50 条/页 · 500 Hath",
			pagingPerkII: "II:100 条/页 · +1,000 Hath",
			hathPerks: "Hath Perks",
			pagingPerksDetails: "说明",
			search: "搜索",
			searchTitle: "用这本的标题、社团、作者搜 Google、DuckDuckGo、DLsite、pixiv,结果列在这里",
			close: "关闭",
			termTitle: "标题",
			termWork: "作品",
			termCircle: "社团",
			termArtist: "作者",
			previewPage: "第 {n} 页",
			previewNextPage: "下一页",
			settingDebug: "搜索的调试 log",
			debugLog: "Log",
			debugCopy: "复制",
			debugClear: "清除",
			debugEmpty: "还没有任何记录",
			copyResultLink: "复制网址",
			previewLoading: "正在后台标签页打开搜索…",
			previewTimeout: "后台标签页没有及时回应",
			previewEmpty: "没有搜索结果",
			previewUnreadable: "页面上读不到结果,可能要先确认年龄或登录;请直接打开那个搜索",
			previewBlocked: "网站要求验证不是机器人;请直接打开搜索页处理",
			previewClosed: "后台标签页还没回答就被关掉了;可能是其他扩展关掉了新标签页(例如标签页数量上限)",
			previewUnavailable: "脚本管理器没有让这个脚本打开标签页;请重新安装脚本"
		},
		ja: {
			searching: "検索中…",
			notFound: "見つかりません",
			noTitle: "検索できるタイトルなし",
			failed: "検索失敗",
			partial: "一部のリクエストに失敗しました。結果は不完全です",
			networkFailed: "ネットワークエラー",
			requestTimedOut: "リクエストがタイムアウトしました",
			httpFailed: "HTTP エラー",
			invalidResponse: "応答の形式が不正です",
			requestAttempts: "試行回数",
			container: "掲載元",
			containerTitle: "この話の掲載誌・単行本",
			editionsTitle: "同じ本の他言語版・別版",
			series: "シリーズ",
			seriesTitle: "同シリーズの他の巻・話",
			related: "関連作品",
			relatedTitle: "同じ作者・同じ語句だが関係は未確認",
			cosplayerRelatedTitle: "同じコスプレイヤーの他の作品",
			directRelatedTitle: "検索条件に一致した結果、タイトル類似度による絞り込みなし",
			chapters: "収録作品",
			chaptersTitle: "この掲載誌・単行本から切り出された作品",
			requestsTitle: "このギャラリーのために送ったリクエスト",
			searchRequests: "検索ページ",
			searchHits: "Hits",
			searchHitsTitle: "この検索ページで取得したギャラリー数(絞り込み前)",
			noRequests: "リクエストは送っていません",
			nothingSent: "リクエストは送らず、すべてキャッシュから",
			fromCache: "キャッシュから",
			dataAsOf: "データ時点",
			refetch: "再取得",
			refetchTitle: "このギャラリーのキャッシュを破棄して再取得",
			pages: "ページ",
			copyLink: "ギャラリーのリンクをコピー",
			linkCopied: "リンクをコピーしました",
			rewrite: "リライト",
			roughTranslation: "粗訳",
			extraneousAds: "広告混入",
			settings: "設定",
			decrease: "減らす",
			increase: "増やす",
			settingGroupRelated: "E-Hentai 内の関連",
			settingGroupSources: "外部ソースの検索",
			settingLanguage: "言語",
			settingLanguageAuto: "ブラウザに合わせる",
			settingShowExcludedLanguages: "E-Hentai の設定で除外した言語を表示",
			settingView: "表示",
			settingMaxRequests: "ギャラリーごとの最大検索回数",
			viewList: "リスト",
			viewCovers: "表紙",
			pagingPerksTitle: "Paging Enlargement",
			pagingPerksDescription: "各検索で読むのは結果の 1 ページだけで、標準は 25 件です。この特典で 50 件または 100 件に増やせます。",
			pagingPerkI: "I:50件/ページ · 500 Hath",
			pagingPerkII: "II:100件/ページ · +1,000 Hath",
			hathPerks: "Hath Perks",
			pagingPerksDetails: "詳細",
			search: "検索",
			searchTitle: "このギャラリーで Google、DuckDuckGo、DLsite、pixiv を検索し、結果をここに表示",
			close: "閉じる",
			termTitle: "タイトル",
			termWork: "作品",
			termCircle: "サークル",
			termArtist: "作家",
			previewPage: "{n} ページ目",
			previewNextPage: "次のページ",
			settingDebug: "検索のデバッグログ",
			debugLog: "ログ",
			debugCopy: "コピー",
			debugClear: "クリア",
			debugEmpty: "まだ記録がありません",
			copyResultLink: "リンクをコピー",
			previewLoading: "バックグラウンドのタブで検索を読み込み中…",
			previewTimeout: "バックグラウンドのタブから時間内に応答がありません",
			previewEmpty: "検索結果がありません",
			previewUnreadable: "ページから結果を読めませんでした。年齢確認かログインが必要かもしれません。検索ページを直接開いてください",
			previewBlocked: "サイトがロボット確認を求めています。検索ページを開いて続けてください",
			previewClosed: "バックグラウンドのタブが応答前に閉じられました。他の拡張機能が新しいタブを閉じているかもしれません(タブ数の上限など)",
			previewUnavailable: "スクリプトマネージャーがタブを開く権限を渡していません。スクリプトを再インストールしてください"
		},
		ko: {
			searching: "검색 중…",
			notFound: "찾을 수 없음",
			noTitle: "검색할 수 있는 제목이 없음",
			failed: "검색 실패",
			partial: "일부 요청이 실패해 결과가 불완전합니다",
			networkFailed: "네트워크 오류",
			requestTimedOut: "요청 시간 초과",
			httpFailed: "HTTP 오류",
			invalidResponse: "응답 형식이 올바르지 않음",
			requestAttempts: "시도 횟수",
			container: "원본",
			containerTitle: "이 화가 실린 잡지 또는 단행본",
			editionsTitle: "같은 책의 다른 언어판·다른 판",
			series: "시리즈",
			seriesTitle: "같은 시리즈의 다른 권",
			related: "관련 작품",
			relatedTitle: "작가와 문구가 같지만 관계는 확인되지 않음",
			cosplayerRelatedTitle: "같은 코스플레이어의 다른 작품",
			directRelatedTitle: "검색 조건에 맞는 결과, 제목 유사도로 거르지 않음",
			chapters: "수록작",
			chaptersTitle: "이 잡지 또는 단행본에서 나뉜 작품",
			requestsTitle: "이 스크립트가 이 갤러리를 위해 보낸 요청",
			searchRequests: "검색 페이지",
			searchHits: "Hits",
			searchHitsTitle: "이 검색 페이지가 돌려준 갤러리 수 (거르기 전)",
			noRequests: "보낸 요청이 없음",
			nothingSent: "아무 요청도 보내지 않았고, 모두 캐시에서 가져왔습니다",
			fromCache: "캐시",
			dataAsOf: "데이터 시점",
			refetch: "다시 가져오기",
			refetchTitle: "이 갤러리의 캐시를 버리고 사이트에 다시 요청",
			pages: "p",
			copyLink: "갤러리 링크 복사",
			linkCopied: "링크를 복사했습니다",
			rewrite: "개작",
			roughTranslation: "대충 번역",
			extraneousAds: "외부 광고",
			settings: "설정",
			decrease: "줄이기",
			increase: "늘리기",
			settingGroupRelated: "E-Hentai 내 관련 갤러리",
			settingGroupSources: "외부 출처 검색",
			settingLanguage: "언어",
			settingLanguageAuto: "브라우저 설정",
			settingShowExcludedLanguages: "E-Hentai 설정에서 제외한 언어도 표시",
			settingView: "보기",
			settingMaxRequests: "갤러리당 최대 검색 횟수",
			viewList: "목록",
			viewCovers: "표지",
			pagingPerksTitle: "Paging Enlargement",
			pagingPerksDescription: "검색마다 결과를 한 페이지만 읽으며 기본은 25개입니다. 이 퍽을 사면 50개나 100개로 늘어납니다.",
			pagingPerkI: "I: 페이지당 50개 · 500 Hath",
			pagingPerkII: "II: 페이지당 100개 · +1,000 Hath",
			hathPerks: "Hath Perks",
			pagingPerksDetails: "설명",
			search: "검색",
			searchTitle: "이 갤러리로 Google, DuckDuckGo, DLsite, pixiv를 검색해 결과를 여기에 표시",
			close: "닫기",
			termTitle: "제목",
			termWork: "작품",
			termCircle: "서클",
			termArtist: "작가",
			previewPage: "{n}페이지",
			previewNextPage: "다음 페이지",
			settingDebug: "검색 디버그 로그",
			debugLog: "로그",
			debugCopy: "복사",
			debugClear: "지우기",
			debugEmpty: "아직 기록이 없습니다",
			copyResultLink: "링크 복사",
			previewLoading: "백그라운드 탭에서 검색을 여는 중…",
			previewTimeout: "백그라운드 탭이 제때 응답하지 않았습니다",
			previewEmpty: "검색 결과 없음",
			previewUnreadable: "페이지에서 결과를 읽지 못했습니다. 연령 확인이나 로그인이 필요할 수 있으니 검색 페이지를 직접 여세요",
			previewBlocked: "사이트가 로봇이 아닌지 확인을 요구합니다. 검색 페이지를 열어 진행하세요",
			previewClosed: "백그라운드 탭이 응답하기 전에 닫혔습니다. 다른 확장 프로그램이 새 탭을 닫고 있을 수 있습니다 (탭 개수 제한 등)",
			previewUnavailable: "스크립트 관리자가 이 스크립트에 탭을 열 권한을 주지 않았습니다. 스크립트를 다시 설치하세요"
		}
	};
	var current = ref(detectLocale(navigator.languages));
	var locale = readonly(current);
	function setLocale(next) {
		current.value = next;
	}
	function t(key) {
		return MESSAGES[current.value][key];
	}
	var LANGUAGE_PRIORITY = {
		"zh-TW": [
			"chinese",
			"japanese",
			"english"
		],
		"zh-CN": [
			"chinese",
			"japanese",
			"english"
		],
		ja: [
			"japanese",
			"english",
			"chinese"
		],
		en: [
			"english",
			"japanese",
			"chinese"
		],
		ko: [
			"korean",
			"japanese",
			"english"
		]
	};
	var STORAGE_KEY = "ehl_settings_v1";
	var VIEWS = ["list", "covers"];
	var settings = reactive({
		locale: "auto",
		view: "list",
		maxRequests: 5,
		languages: "account",
		debug: false
	});
	function isView(value) {
		return typeof value === "string" && VIEWS.includes(value);
	}
	function isLanguageScope(value) {
		return value === "all" || value === "account";
	}
	function isMaxRequests(value) {
		return Number.isInteger(value) && value >= 1;
	}
	async function loadSettings() {
		const raw = await storageGet(STORAGE_KEY);
		if (raw) try {
			const parsed = JSON.parse(raw);
			if (typeof parsed === "object" && parsed !== null) {
				if ("locale" in parsed && isLocaleChoice(parsed.locale)) settings.locale = parsed.locale;
				if ("view" in parsed && isView(parsed.view)) settings.view = parsed.view;
				if ("maxRequests" in parsed && isMaxRequests(parsed.maxRequests)) settings.maxRequests = parsed.maxRequests;
				if ("languages" in parsed && isLanguageScope(parsed.languages)) settings.languages = parsed.languages;
				if ("debug" in parsed && typeof parsed.debug === "boolean") settings.debug = parsed.debug;
			}
		} catch {}
		watch(() => settings.locale, (choice) => setLocale(resolveLocale(choice, navigator.languages)), { immediate: true });
		watch(settings, (current) => void storageSet(STORAGE_KEY, JSON.stringify(current)), { deep: true });
	}
	var _hoisted_1$12 = ["title"];
	var STAR_COLOURS = "RRBYY";
	var StarRating_default = defineComponent({
		__name: "StarRating",
		props: { rating: {} },
		setup(__props) {
			const props = __props;
			const colour = computed(() => `ehl-stars--${STAR_COLOURS[Math.ceil(props.rating) - 1].toLowerCase()}`);
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("span", {
					class: normalizeClass(["ehl-stars", colour.value]),
					title: `${__props.rating.toFixed(2)} / 5`
				}, [createBaseVNode("span", {
					class: "ehl-stars-on",
					style: normalizeStyle({ width: `${__props.rating / 5 * 100}%` })
				}, "★★★★★", 4), _cache[0] || (_cache[0] = createTextVNode(" ★★★★★ ", -1))], 10, _hoisted_1$12);
			};
		}
	});
	var COMMENT = "#";
	var KEY_SEPARATOR = "	";
	var VALUE_SEPARATOR = " ";
	function parseOpenccDictionary(text) {
		const entries = new Map();
		let longest = 0;
		for (const line of text.split("\n")) {
			if (!line || line.startsWith(COMMENT)) continue;
			const [key, values] = line.split(KEY_SEPARATOR);
			const value = values?.trim().split(VALUE_SEPARATOR)[0];
			if (!key || !value) continue;
			entries.set(key, value);
			longest = Math.max(longest, [...key].length);
		}
		return {
			entries,
			longest
		};
	}
	function convertWith(text, dictionary) {
		const characters = [...text];
		let out = "";
		for (let at = 0; at < characters.length;) {
			let matched = false;
			for (let length = Math.min(dictionary.longest, characters.length - at); length > 0; length--) {
				const value = dictionary.entries.get(characters.slice(at, at + length).join(""));
				if (value === void 0) continue;
				out += value;
				at += length;
				matched = true;
				break;
			}
			if (!matched) {
				out += characters[at];
				at += 1;
			}
		}
		return out;
	}
	function convertChain(text, chain) {
		return chain.reduce((converted, dictionary) => convertWith(converted, dictionary), text);
	}
	var NAMESPACE_SECTION = "rows";
	function nameOf(entry) {
		return isRecord(entry) && typeof entry.name === "string" && entry.name ? entry.name : null;
	}
	function readTagNames(db) {
		if (!isRecord(db) || !Array.isArray(db.data)) return null;
		const names = {
			namespaces: {},
			tags: {}
		};
		for (const section of db.data) {
			if (!isRecord(section) || typeof section.namespace !== "string" || !isRecord(section.data)) return null;
			const namespace = section.namespace;
			for (const [raw, entry] of Object.entries(section.data)) {
				const name = nameOf(entry);
				if (name === null) continue;
				if (namespace === NAMESPACE_SECTION) names.namespaces[raw] = name;
				else names.tags[`${namespace}:${raw}`] = name;
			}
		}
		return names;
	}
	var TAG_DB_URL = "https://cdn.jsdelivr.net/gh/EhTagTranslation/DatabaseReleases@master/db.text.json";
	var OPENCC_BASE = "https://cdn.jsdelivr.net/gh/BYVoid/[email protected]/data/dictionary/";
	var TAIWAN_CHAIN = [
		"STCharacters.txt",
		"TWPhrases.txt",
		"TWVariants.txt"
	];
	var KEEP_MS$1 = 6048e5;
	var NAMES_KEY = "ehl_tag_names_v1";
	var OPENCC_KEY = "ehl_opencc_tw_v1";
	async function kept(key, fetchFresh) {
		const raw = await storageGet(key);
		if (raw) try {
			const stored = JSON.parse(raw);
			if (Date.now() - stored.at < KEEP_MS$1) return stored.data;
		} catch {}
		const data = await fetchFresh();
		if (data !== null) await storageSet(key, JSON.stringify({
			at: Date.now(),
			data
		}));
		return data;
	}
	async function fetchText(url) {
		try {
			const response = await fetch(url);
			return response.ok ? await response.text() : null;
		} catch {
			return null;
		}
	}
	async function fetchTagNames() {
		const text = await fetchText(TAG_DB_URL);
		if (text === null) return null;
		try {
			return readTagNames(JSON.parse(text));
		} catch {
			return null;
		}
	}
	async function fetchTaiwanChain() {
		const texts = await Promise.all(TAIWAN_CHAIN.map((file) => fetchText(`${OPENCC_BASE}${file}`)));
		return texts.every((text) => text !== null) ? texts : null;
	}
	var names = shallowRef(null);
	var taiwan = shallowRef(null);
	var namesLoading = null;
	var taiwanLoading = null;
	function isChinese(locale) {
		return locale === "zh-TW" || locale === "zh-CN";
	}
	async function prepareTagNames(locale) {
		if (!isChinese(locale)) return;
		namesLoading ??= kept(NAMES_KEY, fetchTagNames).then((loaded) => {
			names.value = loaded;
		});
		if (locale === "zh-TW") taiwanLoading ??= kept(OPENCC_KEY, fetchTaiwanChain).then((texts) => {
			taiwan.value = texts?.map(parseOpenccDictionary) ?? null;
		});
		await Promise.all([namesLoading, taiwanLoading]);
	}
	function localized(name, locale) {
		if (name === void 0 || !isChinese(locale)) return null;
		if (locale === "zh-CN") return name;
		return taiwan.value ? convertChain(name, taiwan.value) : null;
	}
	function namespaceName(namespace, locale) {
		return localized(names.value?.namespaces[namespace], locale) ?? namespace;
	}
	function tagName(namespace, tag, locale) {
		return localized(names.value?.tags[`${namespace}:${tag}`], locale) ?? tag;
	}
	var _hoisted_1$11 = { class: "ehl-tags" };
	var _hoisted_2$7 = { class: "ehl-tags__label" };
	var _hoisted_3$6 = { class: "ehl-tags__cells" };
	var _hoisted_4$6 = ["title"];
	var TagList_default = defineComponent({
		__name: "TagList",
		props: { tags: {} },
		setup(__props) {
			const props = __props;
			const groups = computed(() => {
				const byNamespace = new Map();
				for (const tag of props.tags) {
					const colon = tag.indexOf(":");
					const namespace = colon === -1 ? "" : tag.slice(0, colon);
					const value = colon === -1 ? tag : tag.slice(colon + 1);
					const bucket = byNamespace.get(namespace);
					if (bucket) bucket.push(value);
					else byNamespace.set(namespace, [value]);
				}
				return [...byNamespace].map(([namespace, values]) => ({
					namespace,
					values
				}));
			});
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("div", _hoisted_1$11, [(openBlock(true), createElementBlock(Fragment, null, renderList(groups.value, (group) => {
					return openBlock(), createElementBlock("div", {
						key: group.namespace,
						class: "ehl-tags__row"
					}, [createBaseVNode("span", _hoisted_2$7, toDisplayString(unref(namespaceName)(group.namespace, unref(locale))) + ":", 1), createBaseVNode("span", _hoisted_3$6, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.values, (value) => {
						return openBlock(), createElementBlock("span", {
							key: value,
							class: "ehl-tags__chip",
							title: `${group.namespace}:${value}`
						}, toDisplayString(unref(tagName)(group.namespace, value, unref(locale))), 9, _hoisted_4$6);
					}), 128))])]);
				}), 128))]);
			};
		}
	});
	var _hoisted_1$10 = [
		"data-language",
		"title",
		"aria-label"
	];
	var LanguageBadge_default = defineComponent({
		__name: "LanguageBadge",
		props: { language: {} },
		setup(__props) {
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("span", {
					class: "ehl-language",
					"data-language": __props.language.value,
					title: __props.language.name[unref(locale)],
					"aria-label": __props.language.name[unref(locale)]
				}, toDisplayString(__props.language.code), 9, _hoisted_1$10);
			};
		}
	});
	var defaultAttributes = {
		xmlns: "http://www.w3.org/2000/svg",
		width: 24,
		height: 24,
		viewBox: "0 0 24 24",
		fill: "none",
		stroke: "currentColor",
		"stroke-width": 2,
		"stroke-linecap": "round",
		"stroke-linejoin": "round"
	};
	var mergeClasses = (...classes) => classes.filter((className, index, array) => {
		return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
	}).join(" ").trim();
	function isDefined(value) {
		return value !== null && value !== void 0;
	}
	function buildLucideIconNode(icon, params = {}) {
		const attributeNames = params.attributeNames ?? {};
		const getAttributeName = (attributeName) => attributeNames[attributeName] ?? attributeName;
		const viewBoxWidth = icon.size ?? icon.width ?? defaultAttributes["width"];
		const viewBoxHeight = icon.size ?? icon.height ?? defaultAttributes["height"];
		const aliasClassNames = icon.aliases?.filter((alias) => typeof alias === "string" && alias.trim() !== "").map((alias) => `lucide-${alias}`) ?? [];
		const iconClassNames = [...icon.name ? [`lucide-${icon.name}`] : [], ...aliasClassNames];
		const classNamesFromClassName = params.className?.split(" ").filter(Boolean) ?? [];
		const className = params.includeDefaultClasses === false ? mergeClasses(...classNamesFromClassName) : mergeClasses("lucide", ...iconClassNames, ...classNamesFromClassName);
		const calculatedStrokeWidth = params.absoluteStrokeWidth ? Number(params.strokeWidth ?? defaultAttributes["stroke-width"]) * Number(icon.size ?? icon.width ?? defaultAttributes["width"]) / Number(params.size ?? params.width ?? defaultAttributes["width"]) : params.strokeWidth ?? defaultAttributes["stroke-width"];
		return [
			"svg",
			{
				...Object.entries(defaultAttributes).reduce((attrs, [attrName, value]) => {
					attrs[getAttributeName(attrName)] = value;
					return attrs;
				}, {}),
				..."color" in params && params.color && { [getAttributeName("stroke")]: params.color },
				..."size" in params && isDefined(params.size) && {
					[getAttributeName("width")]: params.size,
					[getAttributeName("height")]: params.size
				},
				..."width" in params && isDefined(params.width) && { [getAttributeName("width")]: params.width },
				..."height" in params && isDefined(params.height) && { [getAttributeName("height")]: params.height },
				[getAttributeName("stroke-width")]: calculatedStrokeWidth,
				...className && { [getAttributeName("class")]: className },
				[getAttributeName("viewBox")]: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
				...params.hasA11yProp === false ? { [getAttributeName("aria-hidden")]: "true" } : {},
				..."attributes" in params && params.attributes
			},
			icon.node.map((child) => {
				const [name, attrs, children] = child;
				const nextAttrs = params.nonScalingStroke ? {
					[getAttributeName("vector-effect")]: "non-scaling-stroke",
					...attrs
				} : attrs;
				return children ? [
					name,
					nextAttrs,
					children
				] : [name, nextAttrs];
			})
		];
	}
	var hasA11yProp = (props) => {
		for (const prop in props) if (prop.startsWith("aria-") || prop === "role" || prop === "title") return true;
		return false;
	};
	var isEmptyString = (value) => value === "";
	var toKebabCase = (string) => string?.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
	var LUCIDE_CONTEXT = Symbol("lucide-icons");
	function useLucideProps() {
		return inject(LUCIDE_CONTEXT, {});
	}
	var Icon = ({ name, iconNode, "icon-node": iconNodeKebabCase, icon = {
		name: toKebabCase(name),
		node: iconNode ?? iconNodeKebabCase,
		size: 24,
		aliases: []
	}, absoluteStrokeWidth, "absolute-stroke-width": absoluteStrokeWidthKebabCase, nonScalingStroke, "non-scaling-stroke": nonScalingStrokeKebabCase, strokeWidth, "stroke-width": strokeWidthKebabCase, size, width = size, height = size, color, ...props }, { slots }) => {
		const { size: contextSize, color: contextColor, strokeWidth: contextStrokeWidth = 2, absoluteStrokeWidth: contextAbsoluteStrokeWidth = false, nonScalingStroke: contextNonScalingStroke = false, class: contextClass = "" } = useLucideProps();
		const isAbsoluteStrokeWidth = isEmptyString(absoluteStrokeWidth) || isEmptyString(absoluteStrokeWidthKebabCase) || absoluteStrokeWidth === true || absoluteStrokeWidthKebabCase === true || contextAbsoluteStrokeWidth === true;
		const isNonScalingStroke = isEmptyString(nonScalingStroke) || isEmptyString(nonScalingStrokeKebabCase) || nonScalingStroke === true || nonScalingStrokeKebabCase === true || contextNonScalingStroke === true;
		delete props.class;
		const defaultSlot = slots.default?.();
		const [, svgAttributes, builtIconNode = []] = buildLucideIconNode(icon, {
			color: color ?? contextColor,
			width: width ?? size ?? contextSize,
			height: height ?? size ?? contextSize,
			strokeWidth: strokeWidth ?? strokeWidthKebabCase ?? contextStrokeWidth,
			absoluteStrokeWidth: isAbsoluteStrokeWidth,
			nonScalingStroke: isNonScalingStroke,
			className: contextClass,
			hasA11yProp: defaultSlot != null && defaultSlot.length > 0 || hasA11yProp(props),
			attributes: props
		});
		return h("svg", svgAttributes, [...builtIconNode.map((child) => h(...child)), ...defaultSlot ?? []]);
	};
	function createLucideIcon(iconDataOrName, iconNode = []) {
		const icon = typeof iconDataOrName === "string" ? {
			name: iconDataOrName,
			node: iconNode
		} : iconDataOrName;
		return (props, { slots }) => h(Icon, {
			...props,
			icon
		}, slots.default ? { default: slots.default } : void 0);
	}
	var Activity = createLucideIcon({
		name: "activity",
		size: 24,
		node: [["path", {
			d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",
			key: "169zse"
		}]]
	});
	var Check = createLucideIcon({
		name: "check",
		size: 24,
		node: [["path", {
			d: "M20 6 9 17l-5-5",
			key: "1gmf2c"
		}]]
	});
	var ChevronDown = createLucideIcon({
		name: "chevron-down",
		size: 24,
		node: [["path", {
			d: "m6 9 6 6 6-6",
			key: "qrunsl"
		}]]
	});
	var CircleSlash2 = createLucideIcon({
		name: "circle-slash-2",
		size: 24,
		node: [["circle", {
			cx: "12",
			cy: "12",
			r: "10",
			key: "1mglay"
		}], ["path", {
			d: "M22 2 2 22",
			key: "y4kqgn"
		}]],
		aliases: ["circle-slashed"]
	});
	var CircleQuestionMark = createLucideIcon({
		name: "circle-question-mark",
		size: 24,
		node: [
			["circle", {
				cx: "12",
				cy: "12",
				r: "10",
				key: "1mglay"
			}],
			["path", {
				d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",
				key: "1u773s"
			}],
			["path", {
				d: "M12 17h.01",
				key: "p32p05"
			}]
		],
		aliases: ["help-circle", "circle-help"]
	});
	var Copy = createLucideIcon({
		name: "copy",
		size: 24,
		node: [["rect", {
			width: "14",
			height: "14",
			x: "8",
			y: "8",
			rx: "2",
			ry: "2",
			key: "17jyea"
		}], ["path", {
			d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
			key: "zix9uf"
		}]]
	});
	var Globe = createLucideIcon({
		name: "globe",
		size: 24,
		node: [
			["circle", {
				cx: "12",
				cy: "12",
				r: "10",
				key: "1mglay"
			}],
			["path", {
				d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",
				key: "13o1zl"
			}],
			["path", {
				d: "M2 12h20",
				key: "9i4pu4"
			}]
		]
	});
	var Languages = createLucideIcon({
		name: "languages",
		size: 24,
		node: [
			["path", {
				d: "m5 8 6 6",
				key: "1wu5hv"
			}],
			["path", {
				d: "m4 14 6-6 2-3",
				key: "1k1g8d"
			}],
			["path", {
				d: "M2 5h12",
				key: "or177f"
			}],
			["path", {
				d: "M7 2h1",
				key: "1t2jsx"
			}],
			["path", {
				d: "m22 22-5-10-5 10",
				key: "don7ne"
			}],
			["path", {
				d: "M14 18h6",
				key: "1m8k6r"
			}]
		]
	});
	var LoaderCircle = createLucideIcon({
		name: "loader-circle",
		size: 24,
		node: [["path", {
			d: "M21 12a9 9 0 1 1-6.219-8.56",
			key: "13zald"
		}]],
		aliases: ["loader-2"]
	});
	var Minus = createLucideIcon({
		name: "minus",
		size: 24,
		node: [["path", {
			d: "M5 12h14",
			key: "1ays0h"
		}]]
	});
	var Plus = createLucideIcon({
		name: "plus",
		size: 24,
		node: [["path", {
			d: "M5 12h14",
			key: "1ays0h"
		}], ["path", {
			d: "M12 5v14",
			key: "s699le"
		}]]
	});
	var RefreshCw = createLucideIcon({
		name: "refresh-cw",
		size: 24,
		node: [
			["path", {
				d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",
				key: "v9h5vc"
			}],
			["path", {
				d: "M21 3v5h-5",
				key: "1q7to0"
			}],
			["path", {
				d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",
				key: "3uifl3"
			}],
			["path", {
				d: "M8 16H3v5",
				key: "1cv678"
			}]
		]
	});
	var ScrollText = createLucideIcon({
		name: "scroll-text",
		size: 24,
		node: [
			["path", {
				d: "M15 12h-5",
				key: "r7krc0"
			}],
			["path", {
				d: "M15 8h-5",
				key: "1khuty"
			}],
			["path", {
				d: "M19 17V5a2 2 0 0 0-2-2H4",
				key: "zz82l3"
			}],
			["path", {
				d: "M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3",
				key: "1ph1d7"
			}]
		]
	});
	var Settings = createLucideIcon({
		name: "settings",
		size: 24,
		node: [["path", {
			d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",
			key: "1i5ecw"
		}], ["circle", {
			cx: "12",
			cy: "12",
			r: "3",
			key: "1v7zrd"
		}]]
	});
	var X = createLucideIcon({
		name: "x",
		size: 24,
		node: [["path", {
			d: "M18 6 6 18",
			key: "1bl5f8"
		}], ["path", {
			d: "m6 6 12 12",
			key: "d8bk6v"
		}]]
	});
	var _hoisted_1$9 = ["title", "aria-label"];
	var COPIED_MS = 1500;
	var CopyLinkButton_default = defineComponent({
		__name: "CopyLinkButton",
		props: {
			href: {},
			label: { default: "copyLink" }
		},
		setup(__props) {
			const props = __props;
			const copied = ref(false);
			let reset;
			const url = computed(() => new URL(props.href, location.origin).href);
			async function copy() {
				await navigator.clipboard.writeText(url.value);
				copied.value = true;
				clearTimeout(reset);
				reset = setTimeout(() => copied.value = false, COPIED_MS);
			}
			onBeforeUnmount(() => clearTimeout(reset));
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("button", {
					type: "button",
					class: normalizeClass(["ehl-copy", { "ehl-copy--done": copied.value }]),
					title: copied.value ? unref(t)("linkCopied") : unref(t)(__props.label),
					"aria-label": copied.value ? unref(t)("linkCopied") : unref(t)(__props.label),
					onClick: copy
				}, [copied.value ? (openBlock(), createBlock(unref(Check), {
					key: 0,
					size: 12,
					"aria-hidden": "true"
				})) : (openBlock(), createBlock(unref(Copy), {
					key: 1,
					size: 12,
					"aria-hidden": "true"
				}))], 10, _hoisted_1$9);
			};
		}
	});
	var _hoisted_1$8 = { class: "ehl-head" };
	var _hoisted_2$6 = { class: "ehl-count" };
	var _hoisted_3$5 = {
		key: 0,
		class: "ehl-covers"
	};
	var _hoisted_4$5 = ["onMouseenter"];
	var _hoisted_5$5 = ["href"];
	var _hoisted_6$5 = { class: "ehl-cover-art" };
	var _hoisted_7$5 = ["src"];
	var _hoisted_8$5 = { class: "ehl-facts" };
	var _hoisted_9$4 = {
		key: 1,
		class: "ehl-meta"
	};
	var _hoisted_10$4 = { key: 1 };
	var _hoisted_11$3 = ["onMouseenter"];
	var _hoisted_12$3 = ["href"];
	var _hoisted_13$2 = { class: "ehl-thumb" };
	var _hoisted_14$2 = ["src"];
	var _hoisted_15$2 = { class: "ehl-rowtext" };
	var _hoisted_16$2 = { class: "ehl-title" };
	var _hoisted_17$2 = { class: "ehl-facts" };
	var _hoisted_18$2 = {
		key: 1,
		class: "ehl-meta"
	};
	var _hoisted_19$2 = ["src"];
	var _hoisted_20$2 = { class: "ehl-preview-text" };
	var _hoisted_21$2 = { class: "ehl-preview-title" };
	var _hoisted_22$2 = { class: "ehl-facts" };
	var BOOK_COLOURS = 4;
	var PREVIEW_MAX_WIDTH = 340;
	var PREVIEW_MIN_WIDTH = 160;
	var COVER_HEIGHT_OVER_WIDTH = 7 / 5;
	var GAP = 8;
	var GroupList_default = defineComponent({
		__name: "GroupList",
		props: { groups: {} },
		setup(__props) {
			const FLAG_LABELS = {
				rewrite: "rewrite",
				"rough translation": "roughTranslation",
				"extraneous ads": "extraneousAds"
			};
			function framed(book) {
				return book.releases.length > 1;
			}
			const listEl = ref(null);
			const preview = ref(null);
			const previewStyle = ref({});
			function showPreview(release) {
				preview.value = release;
				const box = listEl.value?.getBoundingClientRect();
				if (!release || !box) return;
				const height = window.innerHeight - 16;
				const beside = box.right + GAP;
				const room = window.innerWidth - beside - GAP;
				const width = Math.min(PREVIEW_MAX_WIDTH, Math.round(height / COVER_HEIGHT_OVER_WIDTH), Math.max(room, PREVIEW_MIN_WIDTH));
				previewStyle.value = {
					left: `${Math.round(room >= width ? beside : Math.max(GAP, window.innerWidth - width - GAP))}px`,
					top: `${GAP}px`,
					width: `${width}px`,
					maxHeight: `${Math.round(height)}px`
				};
			}
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("div", {
					ref_key: "listEl",
					ref: listEl,
					class: "ehl-list"
				}, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.groups, (group) => {
					return openBlock(), createElementBlock("section", {
						key: group.language.value,
						class: "ehl-section"
					}, [createBaseVNode("h4", _hoisted_1$8, [
						createVNode(LanguageBadge_default, { language: group.language }, null, 8, ["language"]),
						createTextVNode(" " + toDisplayString(group.language.name[unref(locale)]) + " ", 1),
						createBaseVNode("span", _hoisted_2$6, toDisplayString(group.books.length), 1)
					]), unref(settings).view === "covers" ? (openBlock(), createElementBlock("div", _hoisted_3$5, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.books.flatMap((book) => book.releases), (release) => {
						return openBlock(), createElementBlock("div", {
							key: release.hit.gid,
							class: "ehl-cover-cell",
							onMouseenter: ($event) => showPreview(release),
							onMouseleave: _cache[0] || (_cache[0] = ($event) => showPreview(null))
						}, [createBaseVNode("a", {
							class: "ehl-cover",
							href: release.hit.href,
							target: "_blank",
							rel: "noopener"
						}, [createBaseVNode("span", _hoisted_6$5, [release.hit.thumb ? (openBlock(), createElementBlock("img", {
							key: 0,
							src: release.hit.thumb,
							loading: "lazy",
							decoding: "async",
							fetchpriority: "low",
							referrerpolicy: "no-referrer",
							alt: ""
						}, null, 8, _hoisted_7$5)) : createCommentVNode("", true)]), createBaseVNode("span", _hoisted_8$5, [
							release.hit.rating !== null ? (openBlock(), createBlock(StarRating_default, {
								key: 0,
								rating: release.hit.rating
							}, null, 8, ["rating"])) : createCommentVNode("", true),
							release.hit.pages !== null ? (openBlock(), createElementBlock("span", _hoisted_9$4, toDisplayString(release.hit.pages) + toDisplayString(unref(t)("pages")), 1)) : createCommentVNode("", true),
							(openBlock(true), createElementBlock(Fragment, null, renderList(release.flags, (flag) => {
								return openBlock(), createElementBlock("span", {
									key: flag,
									class: "ehl-flag"
								}, toDisplayString(unref(t)(FLAG_LABELS[flag])), 1);
							}), 128))
						])], 8, _hoisted_5$5), createVNode(CopyLinkButton_default, { href: release.hit.href }, null, 8, ["href"])], 40, _hoisted_4$5);
					}), 128))])) : (openBlock(), createElementBlock("ul", _hoisted_10$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.books, (book, index) => {
						return openBlock(), createElementBlock("li", {
							key: book.releases[0].hit.gid,
							class: normalizeClass(framed(book) ? `ehl-book ehl-book--${index % BOOK_COLOURS}` : "ehl-books")
						}, [createBaseVNode("ul", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(book.releases, (release) => {
							return openBlock(), createElementBlock("li", {
								key: release.hit.gid,
								class: "ehl-row",
								onMouseenter: ($event) => showPreview(release),
								onMouseleave: _cache[1] || (_cache[1] = ($event) => showPreview(null))
							}, [createBaseVNode("a", {
								class: "ehl-rowlink",
								href: release.hit.href,
								target: "_blank",
								rel: "noopener"
							}, [createBaseVNode("span", _hoisted_13$2, [release.hit.thumb ? (openBlock(), createElementBlock("img", {
								key: 0,
								src: release.hit.thumb,
								loading: "lazy",
								decoding: "async",
								fetchpriority: "low",
								referrerpolicy: "no-referrer",
								alt: ""
							}, null, 8, _hoisted_14$2)) : createCommentVNode("", true)]), createBaseVNode("span", _hoisted_15$2, [createBaseVNode("span", _hoisted_16$2, toDisplayString(release.hit.title), 1), createBaseVNode("span", _hoisted_17$2, [
								release.hit.rating !== null ? (openBlock(), createBlock(StarRating_default, {
									key: 0,
									rating: release.hit.rating
								}, null, 8, ["rating"])) : createCommentVNode("", true),
								release.hit.pages !== null ? (openBlock(), createElementBlock("span", _hoisted_18$2, toDisplayString(release.hit.pages) + toDisplayString(unref(t)("pages")), 1)) : createCommentVNode("", true),
								(openBlock(true), createElementBlock(Fragment, null, renderList(release.flags, (flag) => {
									return openBlock(), createElementBlock("span", {
										key: flag,
										class: "ehl-flag"
									}, toDisplayString(unref(t)(FLAG_LABELS[flag])), 1);
								}), 128))
							])])], 8, _hoisted_12$3), createVNode(CopyLinkButton_default, { href: release.hit.href }, null, 8, ["href"])], 40, _hoisted_11$3);
						}), 128))])], 2);
					}), 128))]))]);
				}), 128)), preview.value ? (openBlock(), createElementBlock("div", {
					key: 0,
					class: "ehl-preview",
					style: normalizeStyle(previewStyle.value)
				}, [preview.value.hit.thumb ? (openBlock(), createElementBlock("img", {
					key: 0,
					src: preview.value.hit.thumb,
					alt: "",
					referrerpolicy: "no-referrer"
				}, null, 8, _hoisted_19$2)) : createCommentVNode("", true), createBaseVNode("div", _hoisted_20$2, [
					createBaseVNode("span", _hoisted_21$2, toDisplayString(preview.value.hit.title), 1),
					createBaseVNode("span", _hoisted_22$2, [preview.value.hit.rating !== null ? (openBlock(), createBlock(StarRating_default, {
						key: 0,
						rating: preview.value.hit.rating
					}, null, 8, ["rating"])) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(preview.value.flags, (flag) => {
						return openBlock(), createElementBlock("span", {
							key: flag,
							class: "ehl-flag"
						}, toDisplayString(unref(t)(FLAG_LABELS[flag])), 1);
					}), 128))]),
					preview.value.hit.tags.length > 0 ? (openBlock(), createBlock(TagList_default, {
						key: 0,
						tags: preview.value.hit.tags
					}, null, 8, ["tags"])) : createCommentVNode("", true)
				])], 4)) : createCommentVNode("", true)], 512);
			};
		}
	});
	var _hoisted_1$7 = {
		class: "ehl-settings",
		translate: "no"
	};
	var _hoisted_2$5 = { class: "ehl-settings__row ehl-settings__language" };
	var _hoisted_3$4 = { class: "ehl-settings__label" };
	var _hoisted_4$4 = { value: "auto" };
	var _hoisted_5$4 = ["value", "lang"];
	var _hoisted_6$4 = { class: "ehl-settings__group" };
	var _hoisted_7$4 = { class: "ehl-settings__heading" };
	var _hoisted_8$4 = { class: "ehl-settings__row" };
	var _hoisted_9$3 = { class: "ehl-settings__label" };
	var _hoisted_10$3 = ["aria-label"];
	var _hoisted_11$2 = ["onUpdate:modelValue", "value"];
	var _hoisted_12$2 = { class: "ehl-settings__row ehl-settings__row--toggle" };
	var _hoisted_13$1 = { class: "ehl-settings__label" };
	var _hoisted_14$1 = { class: "ehl-settings__row" };
	var _hoisted_15$1 = { class: "ehl-settings__label" };
	var _hoisted_16$1 = [
		"title",
		"aria-label",
		"aria-expanded"
	];
	var _hoisted_17$1 = { class: "ehl-settings__stepper" };
	var _hoisted_18$1 = ["aria-label", "disabled"];
	var _hoisted_19$1 = ["aria-label"];
	var _hoisted_20$1 = {
		key: 0,
		class: "ehl-settings__note"
	};
	var _hoisted_21$1 = { class: "ehl-settings__links" };
	var _hoisted_22$1 = {
		href: "https://e-hentai.org/hathperks.php",
		target: "_blank",
		rel: "noopener"
	};
	var _hoisted_23$1 = {
		href: "https://ehwiki.org/wiki/Hath_Perks",
		target: "_blank",
		rel: "noopener"
	};
	var _hoisted_24$1 = { class: "ehl-settings__group" };
	var _hoisted_25$1 = { class: "ehl-settings__heading" };
	var _hoisted_26$1 = { class: "ehl-settings__row ehl-settings__row--toggle" };
	var _hoisted_27$1 = { class: "ehl-settings__label" };
	var SettingsPopup_default = defineComponent({
		__name: "SettingsPopup",
		setup(__props) {
			const VIEW_KEY = {
				list: "viewList",
				covers: "viewCovers"
			};
			const LOCALE_OPTIONS = [
				{
					value: "zh-TW",
					label: "繁體中文"
				},
				{
					value: "zh-CN",
					label: "简体中文"
				},
				{
					value: "en",
					label: "English"
				},
				{
					value: "ja",
					label: "日本語"
				},
				{
					value: "ko",
					label: "한국어"
				}
			];
			const perkHelpOpen = ref(false);
			function stepMaxRequests(by) {
				const value = settings.maxRequests + by;
				if (isMaxRequests(value)) settings.maxRequests = value;
			}
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("div", _hoisted_1$7, [
					createBaseVNode("label", _hoisted_2$5, [createBaseVNode("span", _hoisted_3$4, [createVNode(unref(Languages), {
						size: 12,
						"aria-hidden": "true"
					}), createTextVNode(" " + toDisplayString(unref(t)("settingLanguage")), 1)]), withDirectives(createBaseVNode("select", {
						"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => unref(settings).locale = $event),
						class: "ehl-settings__select"
					}, [createBaseVNode("option", _hoisted_4$4, toDisplayString(unref(t)("settingLanguageAuto")), 1), (openBlock(), createElementBlock(Fragment, null, renderList(LOCALE_OPTIONS, (option) => {
						return createBaseVNode("option", {
							key: option.value,
							value: option.value,
							lang: option.value
						}, toDisplayString(option.label), 9, _hoisted_5$4);
					}), 64))], 512), [[vModelSelect, unref(settings).locale]])]),
					createBaseVNode("section", _hoisted_6$4, [
						createBaseVNode("h3", _hoisted_7$4, toDisplayString(unref(t)("settingGroupRelated")), 1),
						createBaseVNode("div", _hoisted_8$4, [createBaseVNode("span", _hoisted_9$3, toDisplayString(unref(t)("settingView")), 1), createBaseVNode("div", {
							class: "ehl-settings__segments",
							role: "radiogroup",
							"aria-label": unref(t)("settingView")
						}, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(VIEWS), (view) => {
							return openBlock(), createElementBlock("label", {
								key: view,
								class: "ehl-settings__segment"
							}, [withDirectives(createBaseVNode("input", {
								"onUpdate:modelValue": ($event) => unref(settings).view = $event,
								type: "radio",
								name: "ehl-view",
								value: view
							}, null, 8, _hoisted_11$2), [[vModelRadio, unref(settings).view]]), createBaseVNode("span", null, toDisplayString(unref(t)(VIEW_KEY[view])), 1)]);
						}), 128))], 8, _hoisted_10$3)]),
						createBaseVNode("label", _hoisted_12$2, [createBaseVNode("span", _hoisted_13$1, toDisplayString(unref(t)("settingShowExcludedLanguages")), 1), withDirectives(createBaseVNode("input", {
							"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => unref(settings).languages = $event),
							class: "ehl-settings__switch",
							type: "checkbox",
							role: "switch",
							"true-value": "all",
							"false-value": "account"
						}, null, 512), [[vModelCheckbox, unref(settings).languages]])]),
						createBaseVNode("div", _hoisted_14$1, [createBaseVNode("span", _hoisted_15$1, [createTextVNode(toDisplayString(unref(t)("settingMaxRequests")) + " ", 1), createBaseVNode("button", {
							type: "button",
							class: normalizeClass(["ehl-settings__help", { "ehl-settings__help--open": perkHelpOpen.value }]),
							title: unref(t)("pagingPerksTitle"),
							"aria-label": unref(t)("pagingPerksTitle"),
							"aria-expanded": perkHelpOpen.value,
							onClick: _cache[2] || (_cache[2] = ($event) => perkHelpOpen.value = !perkHelpOpen.value)
						}, [createVNode(unref(CircleQuestionMark), {
							size: 12,
							"aria-hidden": "true"
						})], 10, _hoisted_16$1)]), createBaseVNode("div", _hoisted_17$1, [
							createBaseVNode("button", {
								type: "button",
								"aria-label": unref(t)("decrease"),
								disabled: !unref(isMaxRequests)(unref(settings).maxRequests - 1),
								onClick: _cache[3] || (_cache[3] = ($event) => stepMaxRequests(-1))
							}, [createVNode(unref(Minus), {
								size: 11,
								"aria-hidden": "true"
							})], 8, _hoisted_18$1),
							createBaseVNode("output", null, toDisplayString(unref(settings).maxRequests), 1),
							createBaseVNode("button", {
								type: "button",
								"aria-label": unref(t)("increase"),
								onClick: _cache[4] || (_cache[4] = ($event) => stepMaxRequests(1))
							}, [createVNode(unref(Plus), {
								size: 11,
								"aria-hidden": "true"
							})], 8, _hoisted_19$1)
						])]),
						perkHelpOpen.value ? (openBlock(), createElementBlock("div", _hoisted_20$1, [
							createBaseVNode("p", null, [createBaseVNode("strong", null, toDisplayString(unref(t)("pagingPerksTitle")), 1), createTextVNode(" " + toDisplayString(unref(t)("pagingPerksDescription")), 1)]),
							createBaseVNode("p", null, [
								createTextVNode(toDisplayString(unref(t)("pagingPerkI")), 1),
								_cache[6] || (_cache[6] = createBaseVNode("br", null, null, -1)),
								createTextVNode(toDisplayString(unref(t)("pagingPerkII")), 1)
							]),
							createBaseVNode("p", _hoisted_21$1, [createBaseVNode("a", _hoisted_22$1, toDisplayString(unref(t)("hathPerks")), 1), createBaseVNode("a", _hoisted_23$1, toDisplayString(unref(t)("pagingPerksDetails")), 1)])
						])) : createCommentVNode("", true)
					]),
					createBaseVNode("section", _hoisted_24$1, [createBaseVNode("h3", _hoisted_25$1, toDisplayString(unref(t)("settingGroupSources")), 1), createBaseVNode("label", _hoisted_26$1, [createBaseVNode("span", _hoisted_27$1, toDisplayString(unref(t)("settingDebug")), 1), withDirectives(createBaseVNode("input", {
						"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => unref(settings).debug = $event),
						class: "ehl-settings__switch",
						type: "checkbox",
						role: "switch"
					}, null, 512), [[vModelCheckbox, unref(settings).debug]])])])
				]);
			};
		}
	});
	var LOG_PREFIX = "ehl_log_";
	async function logKeys() {
		return (await storageKeys()).filter((key) => key.startsWith(LOG_PREFIX));
	}
	var KEEP_MS = 864e5;
	function logKeyTime(key) {
		return Number(key.slice(8).split("_")[0]);
	}
	function isExpiredLogKey(key, now) {
		return !(now - logKeyTime(key) < KEEP_MS);
	}
	var pruned = false;
	async function pruneOnce(now) {
		if (pruned) return;
		pruned = true;
		await Promise.all((await logKeys()).filter((key) => isExpiredLogKey(key, now)).map((key) => storageRemove(key)));
	}
	async function debugLog(id, event, detail = "") {
		const at = Date.now();
		const entry = {
			at,
			where: location.hostname,
			id,
			event,
			detail
		};
		await storageSet(`${LOG_PREFIX}${at}_${Math.random().toString(36).slice(2, 8)}`, JSON.stringify(entry));
		await pruneOnce(at);
	}
	function parseEntry(raw) {
		if (!raw) return null;
		try {
			return JSON.parse(raw);
		} catch {
			return null;
		}
	}
	async function readDebugLog() {
		return (await Promise.all((await logKeys()).map(async (key) => parseEntry(await storageGet(key))))).filter((entry) => entry !== null).sort((a, b) => a.at - b.at);
	}
	async function clearDebugLog() {
		await Promise.all((await logKeys()).map((key) => storageRemove(key)));
	}
	function describeError(error) {
		return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
	}
	var _hoisted_1$6 = { class: "ehl-debug" };
	var _hoisted_2$4 = { class: "ehl-debug__actions" };
	var _hoisted_3$3 = {
		key: 0,
		class: "ehl-pages__note"
	};
	var _hoisted_4$3 = { class: "ehl-debug__id" };
	var _hoisted_5$3 = { class: "ehl-debug__time" };
	var _hoisted_6$3 = { class: "ehl-debug__where" };
	var _hoisted_7$3 = { class: "ehl-debug__event" };
	var _hoisted_8$3 = { class: "ehl-debug__detail" };
	var REFRESH_MS = 1e3;
	var DebugLog_default = defineComponent({
		__name: "DebugLog",
		setup(__props) {
			const entries = ref([]);
			async function refresh() {
				entries.value = await readDebugLog();
			}
			const timer = window.setInterval(() => void refresh(), REFRESH_MS);
			onBeforeUnmount(() => window.clearInterval(timer));
			refresh();
			const requests = computed(() => {
				const groups = new Map();
				for (const entry of entries.value) groups.set(entry.id, [...groups.get(entry.id) ?? [], entry]);
				return [...groups].map(([id, list]) => ({
					id,
					start: list[0].at,
					entries: list
				}));
			});
			function asText() {
				return requests.value.map(({ id, start, entries: list }) => [`# ${id} ${new Date(start).toISOString()}`, ...list.map((entry) => `+${entry.at - start}ms ${entry.where} ${entry.event} ${entry.detail}`)].join("\n")).join("\n\n");
			}
			async function copy() {
				await navigator.clipboard.writeText(asText());
			}
			async function clear() {
				await clearDebugLog();
				await refresh();
			}
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("div", _hoisted_1$6, [
					createBaseVNode("div", _hoisted_2$4, [createBaseVNode("button", {
						type: "button",
						class: "ehl-pages__more",
						onClick: copy
					}, toDisplayString(unref(t)("debugCopy")), 1), createBaseVNode("button", {
						type: "button",
						class: "ehl-pages__more",
						onClick: clear
					}, toDisplayString(unref(t)("debugClear")), 1)]),
					requests.value.length === 0 ? (openBlock(), createElementBlock("p", _hoisted_3$3, toDisplayString(unref(t)("debugEmpty")), 1)) : createCommentVNode("", true),
					(openBlock(true), createElementBlock(Fragment, null, renderList(requests.value, (request) => {
						return openBlock(), createElementBlock("section", {
							key: request.id,
							class: "ehl-debug__request"
						}, [createBaseVNode("h4", _hoisted_4$3, toDisplayString(request.id), 1), createBaseVNode("table", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(request.entries, (entry, index) => {
							return openBlock(), createElementBlock("tr", { key: index }, [
								createBaseVNode("td", _hoisted_5$3, "+" + toDisplayString(entry.at - request.start) + "ms", 1),
								createBaseVNode("td", _hoisted_6$3, toDisplayString(entry.where), 1),
								createBaseVNode("td", _hoisted_7$3, toDisplayString(entry.event), 1),
								createBaseVNode("td", _hoisted_8$3, toDisplayString(entry.detail), 1)
							]);
						}), 128))])]);
					}), 128))
				]);
			};
		}
	});
	var ORIGIN$2 = "https://html.duckduckgo.com";
	var PATH = "/html/";
	var SAFE_SEARCH_OFF = "-2";
	var PAGE_FIELD = "ehl-page";
	function duckDuckGoSearchUrl(query) {
		const url = new URL(PATH, ORIGIN$2);
		url.searchParams.set("q", query);
		url.searchParams.set("kp", SAFE_SEARCH_OFF);
		return url.href;
	}
	function duckDuckGoPageOf(url) {
		return Number(url.searchParams.get(PAGE_FIELD) ?? 0);
	}
	function duckDuckGoSearchOf(url) {
		const query = url.searchParams.get("q");
		if (url.origin !== ORIGIN$2 || url.pathname !== PATH || query === null) return null;
		return {
			key: `duckduckgo\u0000${query}\u0000${duckDuckGoPageOf(url)}`,
			blocked: false
		};
	}
	function duckDuckGoPageUrl(url, page) {
		const target = new URL(url);
		if (page > 0) target.searchParams.set(PAGE_FIELD, String(page));
		else target.searchParams.delete(PAGE_FIELD);
		return target.href;
	}
	function text$1(element) {
		return (element?.textContent ?? "").replace(whitespaceRun, " ").trim();
	}
	function targetOf(href) {
		const url = new URL(href, ORIGIN$2);
		return url.searchParams.get("uddg") ?? url.href;
	}
	function originOf(href) {
		try {
			return new URL(href).origin;
		} catch {
			return null;
		}
	}
	function duckDuckGoNextForm(root) {
		return root.querySelector("input[type=\"submit\"][value=\"Next\"]")?.closest("form") ?? null;
	}
	function isDuckDuckGoResultPage(root) {
		return root.querySelector(".results .result") !== null;
	}
	function readDuckDuckGoResults(root) {
		const results = [];
		for (const block of root.querySelectorAll(".results .result:not(.result--no-result)")) {
			const link = block.querySelector(".result__a");
			const raw = link?.getAttribute("href");
			if (!link || !raw) continue;
			const href = targetOf(raw);
			const icon = block.querySelector(".result__icon__img")?.getAttribute("src");
			results.push({
				title: text$1(link),
				href,
				origin: originOf(href),
				icon: icon ? new URL(icon, ORIGIN$2).href : null,
				byline: text$1(block.querySelector(".result__url")),
				snippet: text$1(block.querySelector(".result__snippet")),
				thumb: null,
				works: []
			});
		}
		return results;
	}
	var RESULTS_PER_PAGE = 10;
	function googleSearchUrl(query, page = 0) {
		const start = page > 0 ? `&start=${page * RESULTS_PER_PAGE}` : "";
		return `https://www.google.com/search?q=${encodeURIComponent(query)}${start}`;
	}
	function googlePageUrl(url, page) {
		return googleSearchUrl(new URL(url).searchParams.get("q") ?? "", page);
	}
	function searchKey(url) {
		const query = url.searchParams.get("q");
		if (query === null) return null;
		return `google\u0000${query}\u0000${url.searchParams.get("start") ?? "0"}`;
	}
	function isGoogleHost(url) {
		return url.hostname.startsWith("www.google.");
	}
	function googleSearchOf(url) {
		if (!isGoogleHost(url)) return null;
		if (url.pathname.startsWith("/sorry")) {
			const next = url.searchParams.get("continue");
			if (!next) return null;
			const key = searchKey(new URL(next));
			return key === null ? null : {
				key,
				blocked: true
			};
		}
		if (url.pathname !== "/search") return null;
		const key = searchKey(url);
		return key === null ? null : {
			key,
			blocked: false
		};
	}
	function resultBlock(link) {
		return link.closest("[data-hveid]") ?? link;
	}
	function snippetOf(block, title, cite) {
		let best = "";
		for (const element of block.querySelectorAll("div, span")) {
			if (element.querySelector("h3, cite")) continue;
			const text = (element.textContent ?? "").trim();
			if (text === title || text === cite) continue;
			if (text.length > best.length) best = text;
		}
		return best;
	}
	function citeOrigin(cite) {
		const [head] = cite.split(" ");
		try {
			return new URL(head).origin;
		} catch {
			return null;
		}
	}
	function googleResultsArea(root) {
		return root.querySelector("#search");
	}
	function siteLine(link) {
		const parts = [];
		const walker = link.ownerDocument.createTreeWalker(link, NodeFilter.SHOW_TEXT);
		for (let node = walker.nextNode(); node; node = walker.nextNode()) {
			if (node.parentElement?.closest("h3")) continue;
			parts.push(node.textContent ?? "");
		}
		return parts.join(" ").split(whitespaceRun).filter(Boolean).join(" ");
	}
	function isGoogleRedirect(href) {
		return new URL(href).pathname === "/goto";
	}
	function readGoogleResults(root) {
		const results = [];
		for (const heading of root.querySelectorAll("#search a h3")) {
			const link = heading.closest("a");
			if (!link) continue;
			const block = resultBlock(link);
			const title = (heading.textContent ?? "").trim();
			const cite = (block.querySelector("cite")?.textContent ?? "").trim();
			results.push({
				title,
				href: link.href,
				origin: citeOrigin(cite),
				icon: link.querySelector("img")?.getAttribute("src") || null,
				byline: siteLine(link),
				snippet: snippetOf(block, title, cite),
				thumb: null,
				works: []
			});
		}
		return results;
	}
	var encode = encodeURIComponent;
	function phrase(text) {
		return encode(`"${text}"`);
	}
	function isCreator(kind) {
		return kind !== "work";
	}
	var MELONBOOKS_TEXT_TYPE = {
		work: "all",
		circle: "maker",
		artist: "author"
	};
	var SEARCH_SITES = [
		{
			id: "dlsite",
			name: "DLsite",
			url: (term) => `https://www.dlsite.com/maniax/fsr/=/keyword/${encode(term.text).replaceAll("%20", "+")}/`
		},
		{
			id: "fanza",
			name: "FANZA",
			url: (term) => `https://www.dmm.co.jp/dc/doujin/-/list/search/=/searchstr=${encode(term.text)}/`
		},
		{
			id: "melonbooks",
			name: "Melonbooks",
			url: (term) => `https://www.melonbooks.co.jp/search/search.php?name=${encode(term.text)}&text_type=${MELONBOOKS_TEXT_TYPE[term.kind]}`
		},
		{
			id: "toranoana",
			name: "Toranoana",
			url: (term) => `https://ec.toranoana.jp/tora_r/ec/app/catalog/list?searchWord=${encode(term.text)}`
		},
		{
			id: "booth",
			name: "BOOTH",
			url: (term) => `https://booth.pm/ja/search/${encode(term.text)}`
		},
		{
			id: "pixiv",
			name: "pixiv",
			url: (term) => isCreator(term.kind) ? `https://www.pixiv.net/search/users?nick=${encode(term.text)}&s_mode=s_usr` : `https://www.pixiv.net/search?q=${encode(term.text)}&s_mode=tag_tc&type=artwork&r=1`
		},
		{
			id: "ci-en",
			name: "Ci-en",
			url: (term) => `https://ci-en.dlsite.com/search?keyword=${encode(term.text)}`
		},
		{
			id: "fantia",
			name: "Fantia",
			url: (term) => `https://fantia.jp/${isCreator(term.kind) ? "fanclubs" : "products"}?keyword=${encode(term.text)}`
		},
		{
			id: "x",
			name: "X",
			url: (term) => `https://x.com/search?q=${phrase(term.text)}&f=live`
		},
		{
			id: "misskey",
			name: "Misskey",
			url: (term) => `https://misskey.io/search?q=${encode(term.text)}`
		},
		{
			id: "google",
			name: "Google",
			url: (term) => `https://www.google.com/search?q=${phrase(term.text)}`
		}
	];
	function originalTitle(source) {
		return source.titleJpn || source.title;
	}
	var ARTIST_SEPARATORS = [",", "、"];
	function splitArtists(text) {
		let parts = [text];
		for (const separator of ARTIST_SEPARATORS) parts = parts.flatMap((part) => part.split(separator));
		return parts.map((part) => part.trim()).filter(Boolean);
	}
	function creatorTerms(block) {
		const segments = parseTitleSegments(block);
		if (segments === null) return [{
			kind: "circle",
			text: block.trim()
		}];
		const terms = [];
		const circle = segments.filter((segment) => segment.kind === "text").map((segment) => segment.text.trim()).filter(Boolean).join(" ");
		if (circle) terms.push({
			kind: "circle",
			text: circle
		});
		const artists = segments.filter((segment) => segment.kind === "block").flatMap((segment) => splitArtists(segment.text));
		for (const text of artists) terms.push({
			kind: "artist",
			text
		});
		return terms;
	}
	function tagTerms(tags) {
		const terms = [];
		for (const tag of tags) {
			const [namespace, ...rest] = tag.split(":");
			const text = rest.join(":").replaceAll("_", " ").trim();
			if (!text) continue;
			if (namespace === "group") terms.push({
				kind: "circle",
				text
			});
			if (namespace === "artist") terms.push({
				kind: "artist",
				text
			});
		}
		return terms;
	}
	function termKey(term) {
		return `${term.kind}\u0000${term.text.normalize("NFKC").toLowerCase()}`;
	}
	var MIN_WORK_CHARACTERS = 3;
	function isSearchableWork(text) {
		return [...text].length >= MIN_WORK_CHARACTERS;
	}
	function searchTerms(source) {
		const parts = analyzeTitle(originalTitle(source));
		const terms = parts.coreSegments.filter(isSearchableWork).map((text) => ({
			kind: "work",
			text
		}));
		const creators = parts.identityBlocks.flatMap(creatorTerms);
		terms.push(...creators.length > 0 ? creators : tagTerms(source.tags));
		const seen = new Set();
		const unique = terms.filter((term) => {
			const key = termKey(term);
			if (seen.has(key)) return false;
			seen.add(key);
			return true;
		});
		return hasManyArtists(source, unique) ? unique.filter((term) => term.kind !== "artist") : unique;
	}
	var MAX_ARTISTS = 3;
	function hasManyArtists(source, terms) {
		if (source.tags.includes("other:anthology")) return true;
		const fromTitle = terms.filter((term) => term.kind === "artist").length;
		const fromTags = source.tags.filter((tag) => tag.startsWith("artist:")).length;
		return Math.max(fromTitle, fromTags) > MAX_ARTISTS;
	}
	function googleQuery(source) {
		const parts = analyzeTitle(originalTitle(source));
		return [...parts.identityBlocks.map((block) => `[${block}]`), ...parts.coreSegments].join(" ");
	}
	var JP_SITES = "site:*.jp";
	function siteUrl(id, kind, text) {
		const site = SEARCH_SITES.find((candidate) => candidate.id === id);
		if (!site) throw new Error(`no search site ${id}`);
		return site.url({
			kind,
			text
		});
	}
	function searchRecipe(source) {
		const searches = [];
		const title = googleQuery(source);
		if (title) {
			searches.push({
				site: "google",
				kind: "title",
				text: title,
				url: googleSearchUrl(title)
			});
			const jp = `${title} ${JP_SITES}`;
			searches.push({
				site: "googleJp",
				kind: "title",
				text: jp,
				url: googleSearchUrl(jp)
			});
			searches.push({
				site: "duckduckgo",
				kind: "title",
				text: title,
				url: duckDuckGoSearchUrl(title)
			});
		}
		const terms = searchTerms(source);
		for (const site of ["dlsite", "pixiv"]) for (const term of terms) searches.push({
			site,
			kind: term.kind,
			text: term.text,
			url: siteUrl(site, term.kind, term.text)
		});
		const seen = new Set();
		return searches.filter((search) => {
			if (seen.has(search.url)) return false;
			seen.add(search.url);
			return true;
		});
	}
	var MIN_PIECE_CHARACTERS = 2;
	function fold(text) {
		let folded = "";
		const origin = [];
		let index = 0;
		for (const character of text) {
			const piece = character.normalize("NFKC").toLowerCase();
			folded += piece;
			for (let unit = 0; unit < piece.length; unit++) origin.push(index);
			index += character.length;
		}
		origin.push(index);
		return {
			folded,
			origin
		};
	}
	function matchWords(keywords) {
		const words = new Set();
		for (const keyword of keywords) {
			const whole = fold(keyword.trim()).folded;
			if (whole) words.add(whole);
			for (const piece of keyword.split(wordBreakRun)) if ([...piece].length >= MIN_PIECE_CHARACTERS) words.add(fold(piece).folded);
		}
		return [...words];
	}
	function markKeywords(text, words) {
		const { folded, origin } = fold(text);
		const hit = new Array(text.length).fill(false);
		for (const word of words) for (let at = folded.indexOf(word); at !== -1; at = folded.indexOf(word, at + 1)) for (let unit = origin[at]; unit < origin[at + word.length]; unit++) hit[unit] = true;
		const parts = [];
		for (let start = 0; start < text.length;) {
			let end = start;
			while (end < text.length && hit[end] === hit[start]) end++;
			parts.push({
				text: text.slice(start, end),
				hit: hit[start]
			});
			start = end;
		}
		return joinAcrossBreaks(parts);
	}
	function isBreakOnly(text) {
		return text.replace(wordBreakRun, "") === "";
	}
	function isBridge(parts, index) {
		const part = parts[index];
		return !part.hit && isBreakOnly(part.text) && parts[index - 1]?.hit === true && parts[index + 1]?.hit === true;
	}
	function joinAcrossBreaks(parts) {
		const joined = [];
		parts.forEach((part, index) => {
			const hit = part.hit || isBridge(parts, index);
			const last = joined.at(-1);
			if (last?.hit === hit) last.text += part.text;
			else joined.push({
				text: part.text,
				hit
			});
		});
		return joined;
	}
	var REFERRER_BY_HOST = { "i.pximg.net": "https://www.pixiv.net/" };
	var loaded = new Map();
	function fetchWithReferrer(url, referrer) {
		const { promise, resolve } = Promise.withResolvers();
		if (typeof _GM_xmlhttpRequest !== "function") {
			resolve(null);
			return promise;
		}
		_GM_xmlhttpRequest({
			url,
			method: "GET",
			responseType: "blob",
			headers: { Referer: referrer },
			onload: (response) => resolve(response.status === 200 ? URL.createObjectURL(response.response) : null),
			onerror: () => resolve(null),
			ontimeout: () => resolve(null)
		});
		return promise;
	}
	function thumbSource(url) {
		const known = loaded.get(url);
		if (known) return known;
		let host = "";
		try {
			host = new URL(url).hostname;
		} catch {
			return Promise.resolve(null);
		}
		const referrer = REFERRER_BY_HOST[host];
		const source = referrer ? fetchWithReferrer(url, referrer) : Promise.resolve(url);
		loaded.set(url, source);
		return source;
	}
	var _hoisted_1$5 = { class: "ehl-result-thumb" };
	var _hoisted_2$3 = ["src"];
	var ResultThumb_default = defineComponent({
		__name: "ResultThumb",
		props: { url: {} },
		setup(__props) {
			const props = __props;
			const src = ref(null);
			const failed = ref(false);
			watchEffect(() => {
				const url = props.url;
				src.value = null;
				thumbSource(url).then((resolved) => {
					if (props.url === url) src.value = resolved;
				});
			});
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("div", _hoisted_1$5, [src.value && !failed.value ? (openBlock(), createElementBlock("img", {
					key: 0,
					src: src.value,
					alt: "",
					loading: "lazy",
					referrerpolicy: "no-referrer",
					onError: _cache[0] || (_cache[0] = ($event) => failed.value = true)
				}, null, 40, _hoisted_2$3)) : createCommentVNode("", true)]);
			};
		}
	});
	var PREVIEW_TTL_MS = 6e4;
	function isFresh(request, now) {
		return now - request.at <= PREVIEW_TTL_MS;
	}
	var ID_FIELD = "ehl-preview";
	function withRequestId(url, id) {
		const target = new URL(url);
		target.hash = `${ID_FIELD}=${id}`;
		return target.href;
	}
	function newRequestId(now, salt) {
		return `${now.toString(36)}.${salt}`;
	}
	function requestIdOf(url) {
		return new URLSearchParams(url.hash.slice(1)).get(ID_FIELD);
	}
	var DEBUG_FIELD = "ehl-debug";
	function withDebugTrace(url) {
		const target = new URL(url);
		const fields = new URLSearchParams(target.hash.slice(1));
		fields.set(DEBUG_FIELD, "1");
		target.hash = fields.toString();
		return target.href;
	}
	function isTraced(url) {
		return new URLSearchParams(url.hash.slice(1)).has(DEBUG_FIELD);
	}
	function freshRequestIdOf(url, now) {
		const id = requestIdOf(url);
		if (id === null) return null;
		return isFresh({
			id,
			key: "",
			at: Number.parseInt(id.split(".")[0], 36)
		}, now) ? id : null;
	}
	function requestFor(requests, key, now) {
		return requests.filter((request) => request.key === key && isFresh(request, now)).at(-1) ?? null;
	}
	var WEB_SCHEMES = ["http:", "https:"];
	function isWebLink(href) {
		try {
			return WEB_SCHEMES.includes(new URL(href).protocol);
		} catch {
			return false;
		}
	}
	function withWebLinksOnly(answer) {
		const results = answer.results.filter((result) => isWebLink(result.href)).map((result) => ({
			...result,
			works: result.works.filter((work) => isWebLink(work.href))
		}));
		return {
			...answer,
			results
		};
	}
	var REQUEST_PREFIX = "ehl_preview_request_";
	var requestKey = (id) => `${REQUEST_PREFIX}${id}`;
	var answerKey = (id) => `ehl_preview_answer_${id}`;
	var ANSWER_TIMEOUT_MS = 2e4;
	function parseRequest(raw) {
		if (!raw) return null;
		try {
			const parsed = JSON.parse(raw);
			return typeof parsed.id === "string" && typeof parsed.key === "string" && typeof parsed.at === "number" ? parsed : null;
		} catch {
			return null;
		}
	}
	async function readAllRequests() {
		const keys = (await storageKeys()).filter((key) => key.startsWith(REQUEST_PREFIX));
		return (await Promise.all(keys.map(async (key) => parseRequest(await storageGet(key))))).filter((request) => request !== null);
	}
	async function requestIdFor(here, key) {
		const now = Date.now();
		if (requestIdOf(here) !== null) return freshRequestIdOf(here, now);
		return requestFor(await readAllRequests(), key, now)?.id ?? null;
	}
	async function dropExpiredRequests(now) {
		for (const request of await readAllRequests()) if (!isFresh(request, now)) await storageRemove(requestKey(request.id));
	}
	function readAnswer(raw) {
		if (!raw) return null;
		try {
			return withWebLinksOnly(JSON.parse(raw));
		} catch {
			return null;
		}
	}
	var untraced = () => {};
	function traceFor(id, enabled) {
		return enabled ? (event, detail) => void debugLog(id, event, detail) : untraced;
	}
	function waitForAnswer(id, trace, closed) {
		const { promise, resolve } = Promise.withResolvers();
		let listener;
		let poll;
		const finish = (answer) => {
			window.clearTimeout(timer);
			window.clearInterval(poll);
			if (listener !== void 0) _GM_removeValueChangeListener(listener);
			resolve(answer);
		};
		const timer = window.setTimeout(() => {
			trace("timeout", `${ANSWER_TIMEOUT_MS} ms without an answer`);
			finish(null);
		}, ANSWER_TIMEOUT_MS);
		closed.then(() => finish({
			status: "closed",
			results: []
		}));
		const hasListener = typeof _GM_addValueChangeListener === "function";
		if (hasListener) listener = _GM_addValueChangeListener(answerKey(id), (_name, _old, value, remote) => {
			trace("change event", `remote=${String(remote)} length=${typeof value === "string" ? value.length : typeof value}`);
			finish(readAnswer(value));
		});
		if (!hasListener || trace !== untraced) poll = window.setInterval(() => {
			storageGet(answerKey(id)).then((raw) => {
				const answer = readAnswer(raw);
				if (!answer) return;
				trace("answer read by polling", hasListener ? "the change event did not deliver it" : "no change events in this manager");
				finish(answer);
			});
		}, 500);
		return promise;
	}
	function isLiveTab(tab, result) {
		return result !== null && !tab.closed;
	}
	async function previewPage(site, url) {
		if (typeof _GM_openInTab !== "function") return {
			status: "unavailable",
			results: []
		};
		const key = site.searchOf(new URL(url))?.key ?? "";
		const now = Date.now();
		const id = newRequestId(now, Math.random().toString(36).slice(2, 8));
		const trace = traceFor(id, settings.debug);
		await dropExpiredRequests(now);
		await storageSet(requestKey(id), JSON.stringify({
			id,
			key,
			at: now
		}));
		trace("request stored", key);
		const closedEarly = Promise.withResolvers();
		const answer = waitForAnswer(id, trace, closedEarly.promise);
		const target = withRequestId(url, id);
		const tab = _GM_openInTab(trace === untraced ? target : withDebugTrace(target), {
			active: false,
			insert: true
		});
		trace("tab opened", target);
		let closing = false;
		tab.onclose = () => {
			trace(closing ? "tab closed" : "tab closed by something else", `closed=${String(tab.closed)}`);
			if (!closing) closedEarly.resolve();
		};
		const result = await answer;
		trace(result ? "answer received" : "gave up", result ? `${result.status}, ${result.results.length} results` : "");
		if (isLiveTab(tab, result) || trace === untraced) {
			closing = true;
			tab.close();
		}
		await storageRemove(requestKey(id));
		await storageRemove(answerKey(id));
		return result;
	}
	async function answerPreview(site) {
		const here = new URL(location.href);
		const trace = traceFor(requestIdOf(here) ?? "no fragment", isTraced(here));
		const asked = site.searchOf(here);
		if (!asked) {
			trace("not a search page", here.href);
			return;
		}
		const id = await requestIdFor(here, asked.key);
		if (id === null) {
			trace("no request to answer", `key=${asked.key}`);
			return;
		}
		trace("reading", `${site.id}${asked.blocked ? " (blocked page)" : ""}`);
		let answer;
		try {
			answer = asked.blocked ? {
				status: "blocked",
				results: []
			} : await site.read(here);
		} catch (error) {
			trace("read failed", describeError(error));
			answer = {
				status: "unreadable",
				results: []
			};
		}
		trace("read done", `${answer.status}, ${answer.results.length} results`);
		await storageSet(answerKey(id), JSON.stringify(answer));
		trace("answer written", `${answerKey(id)}`);
	}
	var ORIGIN$1 = "https://www.dlsite.com";
	function isDigits(text) {
		return text !== void 0 && text !== "" && [...text].every((character) => character >= "0" && character <= "9");
	}
	function splitPage(pathname) {
		const parts = pathname.split("/");
		const at = parts.lastIndexOf("page");
		let page = 1;
		if (isDigits(parts[at + 1])) {
			page = Number(parts[at + 1]);
			parts.splice(at, 2);
		}
		const base = parts.join("/");
		return {
			base: base.endsWith("/") ? base : `${base}/`,
			page
		};
	}
	function isDlsiteSearch(url) {
		const [, floor, section] = url.pathname.split("/");
		return url.origin === ORIGIN$1 && Boolean(floor) && section === "fsr";
	}
	function dlsiteSearchOf(url) {
		if (!isDlsiteSearch(url)) return null;
		const { base, page } = splitPage(url.pathname);
		return {
			key: `dlsite\u0000${base}\u0000${page}`,
			blocked: false
		};
	}
	function dlsitePageUrl(url, page) {
		const target = new URL(url);
		const { base } = splitPage(target.pathname);
		target.pathname = page > 0 ? `${base}page/${page + 1}/` : base;
		return target.href;
	}
	function dlsiteResultState(root) {
		if (root.querySelector("li[data-list_item_product_id]")) return "results";
		if (root.querySelector(".work_not_found")) return "none";
		if (root.querySelector(".error_box")) return "missing";
		return null;
	}
	function dlsiteHasNextPage(root) {
		const current = root.querySelector(".page_no li > strong")?.closest("li");
		return Boolean(current?.nextElementSibling?.querySelector("a"));
	}
	var IMAGE_FLOOR = {
		RJ: "doujin",
		BJ: "books"
	};
	function dlsiteThumb(id) {
		const prefix = id.slice(0, 2);
		const digits = id.slice(2);
		const floor = IMAGE_FLOOR[prefix];
		if (!floor || !isDigits(digits)) return null;
		return `https://img.dlsite.jp/resize/images2/work/${floor}/${prefix}${String(Math.ceil(Number(digits) / 1e3) * 1e3).padStart(digits.length, "0")}/${id}_img_main_240x240.jpg`;
	}
	function renderedThumb(item) {
		const src = item.querySelector(".work_thumb img")?.getAttribute("src") ?? "";
		const url = src.startsWith("//") ? `https:${src}` : src;
		return url.startsWith("https://img.dlsite.jp/") ? url : null;
	}
	function text(element) {
		return (element?.textContent ?? "").replace(whitespaceRun, " ").trim();
	}
	function readDlsiteResults(root) {
		const results = [];
		for (const item of root.querySelectorAll("li[data-list_item_product_id]")) {
			const link = item.querySelector(".work_name a");
			if (!link) continue;
			const circle = text(item.querySelector(".maker_name > a"));
			const authors = [...item.querySelectorAll(".author a")].map(text).filter(Boolean);
			const price = text(item.querySelector(".work_price_base"));
			const id = item.getAttribute("data-list_item_product_id") ?? "";
			results.push({
				title: link.getAttribute("title") ?? text(link),
				href: link.href,
				origin: ORIGIN$1,
				icon: null,
				byline: [circle, authors.join("、")].filter(Boolean).join(" / "),
				snippet: [
					text(item.querySelector(".work_category a")),
					price ? `${price}円` : "",
					id
				].filter(Boolean).join(" · "),
				thumb: renderedThumb(item) ?? dlsiteThumb(id),
				works: []
			});
		}
		return results;
	}
	var ORIGIN = "https://www.pixiv.net";
	function pathOf(url) {
		return url.pathname.startsWith("/en/") ? url.pathname.slice(3) : url.pathname;
	}
	function pageOf(url) {
		const page = Number(url.searchParams.get("p") ?? "1");
		return Number.isInteger(page) && page >= 1 ? page : 1;
	}
	function pixivSearch(url) {
		if (url.origin !== ORIGIN) return null;
		const path = pathOf(url);
		const query = url.searchParams.get("q");
		if (path === "/search" && query) return {
			kind: "artworks",
			word: query,
			page: pageOf(url),
			url
		};
		const nick = url.searchParams.get("nick");
		if (path === "/search/users" && nick) return {
			kind: "users",
			word: nick,
			page: pageOf(url),
			url
		};
		return null;
	}
	function isPixivUserSearch(url) {
		return pixivSearch(url)?.kind === "users";
	}
	function pixivSearchOf(url) {
		const search = pixivSearch(url);
		if (!search) return null;
		return {
			key: `pixiv\u0000${search.kind}\u0000${search.word}\u0000${search.page}`,
			blocked: false
		};
	}
	function pixivPageUrl(url, page) {
		const target = new URL(url);
		if (page > 0) target.searchParams.set("p", String(page + 1));
		else target.searchParams.delete("p");
		return target.href;
	}
	var API_SEARCH_MODE = {
		tag: "s_tag",
		tag_full: "s_tag_full",
		tc: "s_tc",
		tag_tc: "s_tag_tc"
	};
	function pixivApiUrl(url) {
		const search = pixivSearch(url);
		if (!search) return null;
		if (search.kind === "users") return `${ORIGIN}/touch/ajax/search/users?${new URLSearchParams({
			nick: search.word,
			s_mode: "s_usr",
			p: String(search.page),
			lang: "ja"
		})}`;
		const params = new URLSearchParams({
			word: search.word,
			order: "date_d",
			mode: "all",
			p: String(search.page),
			s_mode: API_SEARCH_MODE[url.searchParams.get("s_mode") ?? ""] ?? "s_tag",
			lang: "ja"
		});
		return `${ORIGIN}/ajax/search/artworks/${encodeURIComponent(search.word)}?${params}`;
	}
	function record(value) {
		return typeof value === "object" && value !== null ? value : {};
	}
	function readPixivResults(json, url) {
		const root = record(json);
		if (root.error !== false) return {
			status: "unreadable",
			results: []
		};
		const body = record(root.body);
		const kind = pixivSearch(url)?.kind;
		const results = [];
		if (kind === "users") {
			const users = Array.isArray(body.users) ? body.users : [];
			for (const user of users) {
				if (!user.user_id) continue;
				results.push({
					title: user.user_name ?? user.user_id,
					href: `${ORIGIN}/users/${user.user_id}`,
					origin: ORIGIN,
					icon: null,
					byline: "",
					snippet: "",
					thumb: user.profile_img?.main ?? null,
					works: []
				});
			}
		} else {
			const data = record(body.illustManga).data;
			const artworks = Array.isArray(data) ? data : [];
			for (const artwork of artworks) {
				if (!artwork.id) continue;
				results.push({
					title: artwork.title ?? artwork.id,
					href: `${ORIGIN}/artworks/${artwork.id}`,
					origin: ORIGIN,
					icon: null,
					byline: artwork.userName ?? "",
					snippet: (artwork.createDate ?? "").slice(0, 10),
					thumb: artwork.url ?? null,
					works: []
				});
			}
		}
		return {
			status: results.length > 0 ? "ok" : "empty",
			results
		};
	}
	function pixivUserWorksUrl(userHref) {
		const id = new URL(userHref).pathname.split("/").at(-1);
		return id ? `${ORIGIN}/ajax/user/${id}/profile/top?lang=ja` : null;
	}
	function readPixivUserWorks(json) {
		const root = record(json);
		if (root.error !== false) return [];
		const body = record(root.body);
		const works = [];
		for (const group of [body.illusts, body.manga]) for (const value of Object.values(record(group))) {
			const work = record(value);
			if (work.id && work.url) works.push(work);
		}
		return works.sort((a, b) => Number(b.id) - Number(a.id)).slice(0, 6).map((work) => ({
			href: `${ORIGIN}/artworks/${work.id}`,
			thumb: work.url,
			title: work.title ?? work.id
		}));
	}
	var RESOLVE_TIMEOUT_MS = 8e3;
	function resolveRedirect(url) {
		const { promise, resolve } = Promise.withResolvers();
		if (typeof _GM_xmlhttpRequest !== "function") {
			resolve(null);
			return promise;
		}
		const settle = (finalUrl) => resolve(finalUrl && finalUrl !== url ? finalUrl : null);
		const request = _GM_xmlhttpRequest({
			url,
			method: "GET",
			timeout: RESOLVE_TIMEOUT_MS,
			onreadystatechange: (response) => {
				if (response.readyState < XMLHttpRequest.HEADERS_RECEIVED) return;
				settle(response.finalUrl);
				request.abort();
			},
			onload: (response) => settle(response.finalUrl),
			onerror: () => resolve(null),
			ontimeout: () => resolve(null),
			onabort: () => resolve(null)
		});
		return promise;
	}
	var RENDER_TIMEOUT_MS = 8e3;
	async function pause(ms) {
		const { promise, resolve } = Promise.withResolvers();
		window.setTimeout(resolve, ms);
		await promise;
	}
	async function rendered(ready) {
		const started = Date.now();
		for (;;) {
			const value = ready();
			if (value !== null) return value;
			if (Date.now() - started > RENDER_TIMEOUT_MS) return null;
			await pause(250);
		}
	}
	var GOOGLE = {
		id: "google",
		searchOf: googleSearchOf,
		pageUrl: googlePageUrl,
		async read() {
			if (!await rendered(() => googleResultsArea(document))) return {
				status: "unreadable",
				results: []
			};
			await rendered(() => document.querySelector("#search a h3") ? true : null);
			const results = readGoogleResults(document);
			await Promise.all(results.filter((result) => isGoogleRedirect(result.href)).map(async (result) => {
				result.href = await resolveRedirect(result.href) ?? result.href;
			}));
			return {
				status: results.length > 0 ? "ok" : "empty",
				results
			};
		}
	};
	async function nextDuckDuckGoPage(page) {
		const form = duckDuckGoNextForm(page);
		if (!form) return null;
		const fields = [...new FormData(form)].map(([name, value]) => [name, String(value)]);
		const response = await fetch(form.action, {
			method: "POST",
			body: new URLSearchParams(fields)
		});
		return new DOMParser().parseFromString(await response.text(), "text/html");
	}
	var SITES = [
		GOOGLE,
		{
			id: "duckduckgo",
			searchOf: duckDuckGoSearchOf,
			pageUrl: duckDuckGoPageUrl,
			async read(url) {
				let page = document;
				for (let left = duckDuckGoPageOf(url); left > 0; left--) {
					let next;
					try {
						next = await nextDuckDuckGoPage(page);
					} catch {
						return {
							status: "unreadable",
							results: []
						};
					}
					if (!next) return {
						status: "empty",
						results: [],
						last: true
					};
					page = next;
				}
				if (!isDuckDuckGoResultPage(page)) return {
					status: "unreadable",
					results: []
				};
				const results = readDuckDuckGoResults(page);
				const answer = {
					status: results.length > 0 ? "ok" : "empty",
					results
				};
				if (!duckDuckGoNextForm(page)) answer.last = true;
				return answer;
			}
		},
		{
			id: "dlsite",
			searchOf: dlsiteSearchOf,
			pageUrl: dlsitePageUrl,
			async read() {
				const state = await rendered(() => dlsiteResultState(document));
				if (state === null) return {
					status: "unreadable",
					results: []
				};
				const results = state === "results" ? readDlsiteResults(document) : [];
				const answer = {
					status: results.length > 0 ? "ok" : "empty",
					results
				};
				if (!dlsiteHasNextPage(document)) answer.last = true;
				return answer;
			}
		},
		{
			id: "pixiv",
			searchOf: pixivSearchOf,
			pageUrl: pixivPageUrl,
			async read(url) {
				const api = pixivApiUrl(url);
				if (!api) return {
					status: "unreadable",
					results: []
				};
				try {
					const answer = readPixivResults(await (await fetch(api, { credentials: "include" })).json(), url);
					if (!isPixivUserSearch(url)) return answer;
					await Promise.all(answer.results.map(async (result) => {
						const worksUrl = pixivUserWorksUrl(result.href);
						if (!worksUrl) return;
						try {
							result.works = readPixivUserWorks(await (await fetch(worksUrl, { credentials: "include" })).json());
						} catch {}
					}));
					return answer;
				} catch {
					return {
						status: "unreadable",
						results: []
					};
				}
			}
		}
	];
	function previewSiteFor(url) {
		return SITES.find((site) => site.searchOf(url) !== null) ?? null;
	}
	var DECLARED_ICONS = { "https://www.dlsite.com": "https://www.dlsite.com/images/web/common/favicon.ico" };
	function faviconUrl(href) {
		let origin;
		try {
			origin = new URL(href).origin;
		} catch {
			return null;
		}
		return DECLARED_ICONS[origin] ?? `${origin}/favicon.ico`;
	}
	_css(".ehl-favicon{vertical-align:-.15em;object-fit:contain;border:0;width:1em;height:1em;margin:0 .25em 0 0}");
	var _hoisted_1$4 = ["src"];
	var SiteIcon_default = defineComponent({
		__name: "SiteIcon",
		props: { href: {} },
		setup(__props) {
			const props = __props;
			const src = computed(() => faviconUrl(props.href));
			const failed = ref(false);
			return (_ctx, _cache) => {
				return src.value !== null && !failed.value ? (openBlock(), createElementBlock("img", {
					key: 0,
					class: "ehl-favicon",
					src: src.value,
					alt: "",
					referrerpolicy: "no-referrer",
					onError: _cache[0] || (_cache[0] = ($event) => failed.value = true)
				}, null, 40, _hoisted_1$4)) : createCommentVNode("", true);
			};
		}
	});
	var _hoisted_1$3 = {
		key: 0,
		class: "ehl-mark"
	};
	var MarkedText_default = defineComponent({
		__name: "MarkedText",
		props: {
			text: {},
			words: {}
		},
		setup(__props) {
			const props = __props;
			const parts = computed(() => markKeywords(props.text, props.words));
			return (_ctx, _cache) => {
				return openBlock(true), createElementBlock(Fragment, null, renderList(parts.value, (part, index) => {
					return openBlock(), createElementBlock(Fragment, { key: index }, [part.hit ? (openBlock(), createElementBlock("mark", _hoisted_1$3, toDisplayString(part.text), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(part.text), 1)], 64))], 64);
				}), 128);
			};
		}
	});
	var _hoisted_1$2 = {
		key: 0,
		class: "ehl-pages"
	};
	var _hoisted_2$2 = {
		key: 0,
		class: "ehl-pages__page-head"
	};
	var _hoisted_3$2 = {
		key: 1,
		class: "ehl-pages__note"
	};
	var _hoisted_4$2 = ["href"];
	var _hoisted_5$2 = { class: "ehl-pages__text" };
	var _hoisted_6$2 = ["href"];
	var _hoisted_7$2 = ["src"];
	var _hoisted_8$2 = {
		key: 0,
		class: "ehl-pages__byline"
	};
	var _hoisted_9$2 = {
		key: 1,
		class: "ehl-pages__snippet"
	};
	var _hoisted_10$2 = {
		key: 1,
		class: "ehl-pages__works"
	};
	var _hoisted_11$1 = ["href", "title"];
	var _hoisted_12$1 = ["disabled"];
	var PreviewPages_default = defineComponent({
		__name: "PreviewPages",
		props: {
			url: {},
			words: {}
		},
		emits: ["progress"],
		setup(__props, { emit: __emit }) {
			const props = __props;
			const emit = __emit;
			const site = computed(() => previewSiteFor(new URL(props.url)));
			const pages = ref([]);
			const PAGE_STATUS = {
				timeout: "previewTimeout",
				empty: "previewEmpty",
				blocked: "previewBlocked",
				unreadable: "previewUnreadable",
				unavailable: "previewUnavailable",
				closed: "previewClosed"
			};
			function pageNote(page) {
				if (page.state === "loading") return "previewLoading";
				if (page.state === "timeout") return PAGE_STATUS.timeout;
				return page.status === "ok" ? null : PAGE_STATUS[page.status];
			}
			const loading = computed(() => pages.value.some((page) => page.state === "loading"));
			const count = computed(() => pages.value.reduce((total, page) => total + (page.state === "answered" ? page.results.length : 0), 0));
			watch([loading, count], () => emit("progress", loading.value, count.value), { immediate: true });
			function layoutOf(page) {
				if (page.results.some((result) => result.works.length > 0)) return "rows";
				if (page.results.some((result) => result.thumb !== null)) return "grid";
				return "list";
			}
			function isFollowedByMore(page) {
				return page?.state === "answered" && page.status === "ok" && page.last !== true;
			}
			const canPageOn = computed(() => isFollowedByMore(pages.value.at(-1)));
			async function fetchPage() {
				const target = site.value;
				if (!target) return;
				const index = pages.value.length;
				pages.value.push({ state: "loading" });
				const answer = await previewPage(target, target.pageUrl(props.url, index));
				pages.value[index] = answer ? {
					state: "answered",
					...answer
				} : { state: "timeout" };
			}
			function previewFirstPage() {
				pages.value = [];
				fetchPage();
			}
			watch(() => props.url, previewFirstPage);
			previewFirstPage();
			return (_ctx, _cache) => {
				return site.value ? (openBlock(), createElementBlock("div", _hoisted_1$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(pages.value, (page, index) => {
					return openBlock(), createElementBlock("div", {
						key: index,
						class: normalizeClass(["ehl-pages__page", { "ehl-pages__page--note": index === 0 && pageNote(page) !== null }])
					}, [index > 0 ? (openBlock(), createElementBlock("h4", _hoisted_2$2, toDisplayString(unref(t)("previewPage").replace("{n}", String(index + 1))), 1)) : createCommentVNode("", true), pageNote(page) ? (openBlock(), createElementBlock("p", _hoisted_3$2, [page.state === "loading" ? (openBlock(), createBlock(unref(LoaderCircle), {
						key: 0,
						size: 11,
						class: "ehl-pages__spin",
						"aria-hidden": "true"
					})) : createCommentVNode("", true), createTextVNode(" " + toDisplayString(unref(t)(pageNote(page))), 1)])) : page.state === "answered" ? (openBlock(), createElementBlock("ol", {
						key: 2,
						class: normalizeClass(["ehl-pages__results", `ehl-pages__results--${layoutOf(page)}`])
					}, [(openBlock(true), createElementBlock(Fragment, null, renderList(page.results, (result) => {
						return openBlock(), createElementBlock("li", { key: result.href }, [
							createVNode(CopyLinkButton_default, {
								href: result.href,
								label: "copyResultLink"
							}, null, 8, ["href"]),
							result.thumb ? (openBlock(), createElementBlock("a", {
								key: 0,
								class: "ehl-pages__thumb",
								href: result.href,
								target: "_blank",
								rel: "noopener",
								tabindex: "-1"
							}, [createVNode(ResultThumb_default, { url: result.thumb }, null, 8, ["url"])], 8, _hoisted_4$2)) : createCommentVNode("", true),
							createBaseVNode("div", _hoisted_5$2, [
								createBaseVNode("a", {
									class: "ehl-pages__title",
									href: result.href,
									target: "_blank",
									rel: "noopener"
								}, [result.icon ? (openBlock(), createElementBlock("img", {
									key: 0,
									class: "ehl-favicon",
									src: result.icon,
									alt: ""
								}, null, 8, _hoisted_7$2)) : result.origin ? (openBlock(), createBlock(SiteIcon_default, {
									key: 1,
									href: result.origin
								}, null, 8, ["href"])) : createCommentVNode("", true), createVNode(MarkedText_default, {
									text: result.title,
									words: __props.words
								}, null, 8, ["text", "words"])], 8, _hoisted_6$2),
								result.byline ? (openBlock(), createElementBlock("span", _hoisted_8$2, [createVNode(MarkedText_default, {
									text: result.byline,
									words: __props.words
								}, null, 8, ["text", "words"])])) : createCommentVNode("", true),
								result.snippet ? (openBlock(), createElementBlock("span", _hoisted_9$2, [createVNode(MarkedText_default, {
									text: result.snippet,
									words: __props.words
								}, null, 8, ["text", "words"])])) : createCommentVNode("", true)
							]),
							result.works.length > 0 ? (openBlock(), createElementBlock("ul", _hoisted_10$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(result.works, (work) => {
								return openBlock(), createElementBlock("li", { key: work.href }, [createBaseVNode("a", {
									href: work.href,
									title: work.title,
									target: "_blank",
									rel: "noopener"
								}, [createVNode(ResultThumb_default, { url: work.thumb }, null, 8, ["url"])], 8, _hoisted_11$1)]);
							}), 128))])) : createCommentVNode("", true)
						]);
					}), 128))], 2)) : createCommentVNode("", true)], 2);
				}), 128)), canPageOn.value ? (openBlock(), createElementBlock("button", {
					key: 0,
					type: "button",
					class: "ehl-pages__more",
					disabled: loading.value,
					onClick: _cache[0] || (_cache[0] = ($event) => fetchPage())
				}, [createVNode(unref(ChevronDown), {
					size: 11,
					"aria-hidden": "true"
				}), createTextVNode(" " + toDisplayString(unref(t)("previewNextPage")), 1)], 8, _hoisted_12$1)) : createCommentVNode("", true)])) : createCommentVNode("", true);
			};
		}
	});
	var _hoisted_1$1 = {
		class: "ehl-search",
		translate: "no"
	};
	var _hoisted_2$1 = { class: "ehl-search__nav" };
	var _hoisted_3$1 = ["onClick"];
	var _hoisted_4$1 = { class: "ehl-search__site-name" };
	var _hoisted_5$1 = {
		key: 1,
		class: "ehl-search__count"
	};
	var _hoisted_6$1 = { class: "ehl-search__site-name" };
	var _hoisted_7$1 = ["title"];
	var _hoisted_8$1 = ["href"];
	var _hoisted_9$1 = { class: "ehl-search__kind" };
	var _hoisted_10$1 = {
		key: 0,
		class: "ehl-search__content"
	};
	var SearchPanel_default = defineComponent({
		__name: "SearchPanel",
		props: { source: {} },
		emits: ["close"],
		setup(__props, { emit: __emit }) {
			const props = __props;
			const emit = __emit;
			const SITE_NAME = {
				google: "Google",
				googleJp: "Google .jp",
				duckduckgo: "DuckDuckGo",
				dlsite: "DLsite",
				pixiv: "Pixiv"
			};
			const KIND_LABEL = {
				title: "termTitle",
				work: "termWork",
				circle: "termCircle",
				artist: "termArtist"
			};
			const recipe = searchRecipe(props.source);
			const words = matchWords(searchTerms(props.source).map((term) => term.text));
			const sites = [
				"google",
				"googleJp",
				"duckduckgo",
				"dlsite",
				"pixiv"
			].map((id) => ({
				id,
				name: SITE_NAME[id],
				searches: recipe.filter((search) => search.site === id)
			})).filter((site) => site.searches.length > 0);
			const selected = ref(sites[0]?.id ?? null);
			const progress = reactive({});
			const siteState = computed(() => Object.fromEntries(sites.map((site) => {
				const states = site.searches.map((search) => progress[search.url]);
				return [site.id, {
					loading: states.some((state) => state?.loading !== false),
					count: states.reduce((total, state) => total + (state?.count ?? 0), 0)
				}];
			})));
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock("div", _hoisted_1$1, [
					createBaseVNode("nav", _hoisted_2$1, [
						(openBlock(true), createElementBlock(Fragment, null, renderList(unref(sites), (site) => {
							return openBlock(), createElementBlock("button", {
								key: site.id,
								type: "button",
								class: normalizeClass(["ehl-search__site-tab", { "ehl-search__site-tab--selected": selected.value === site.id }]),
								onClick: ($event) => selected.value = site.id
							}, [
								createVNode(SiteIcon_default, { href: site.searches[0].url }, null, 8, ["href"]),
								createBaseVNode("span", _hoisted_4$1, toDisplayString(site.name), 1),
								siteState.value[site.id].loading ? (openBlock(), createBlock(unref(LoaderCircle), {
									key: 0,
									size: 11,
									class: "ehl-pages__spin",
									"aria-hidden": "true"
								})) : (openBlock(), createElementBlock("span", _hoisted_5$1, toDisplayString(siteState.value[site.id].count), 1))
							], 10, _hoisted_3$1);
						}), 128)),
						unref(settings).debug ? (openBlock(), createElementBlock("button", {
							key: 0,
							type: "button",
							class: normalizeClass(["ehl-search__site-tab", { "ehl-search__site-tab--selected": selected.value === "log" }]),
							onClick: _cache[0] || (_cache[0] = ($event) => selected.value = "log")
						}, [createVNode(unref(ScrollText), {
							size: 12,
							"aria-hidden": "true"
						}), createBaseVNode("span", _hoisted_6$1, toDisplayString(unref(t)("debugLog")), 1)], 2)) : createCommentVNode("", true),
						createBaseVNode("button", {
							type: "button",
							class: "ehl-search__close",
							title: unref(t)("close"),
							onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
						}, [createVNode(unref(X), {
							size: 14,
							"aria-hidden": "true"
						})], 8, _hoisted_7$1)
					]),
					(openBlock(true), createElementBlock(Fragment, null, renderList(unref(sites), (site) => {
						return withDirectives((openBlock(), createElementBlock("section", {
							key: site.id,
							class: "ehl-search__content"
						}, [(openBlock(true), createElementBlock(Fragment, null, renderList(site.searches, (search) => {
							return openBlock(), createElementBlock("div", {
								key: search.url,
								class: "ehl-search__search"
							}, [createBaseVNode("a", {
								class: "ehl-search__query",
								href: search.url,
								target: "_blank",
								rel: "noopener"
							}, [createBaseVNode("span", _hoisted_9$1, toDisplayString(unref(t)(KIND_LABEL[search.kind])), 1), createTextVNode(toDisplayString(search.text), 1)], 8, _hoisted_8$1), createVNode(PreviewPages_default, {
								url: search.url,
								words: unref(words),
								onProgress: (loading, count) => progress[search.url] = {
									loading,
									count
								}
							}, null, 8, [
								"url",
								"words",
								"onProgress"
							])]);
						}), 128))])), [[vShow, selected.value === site.id]]);
					}), 128)),
					unref(settings).debug && selected.value === "log" ? (openBlock(), createElementBlock("section", _hoisted_10$1, [createVNode(DebugLog_default)])) : createCommentVNode("", true)
				]);
			};
		}
	});
	function readSourceGallery(root = document, pathname = location.pathname) {
		const ref = galleryRef(pathname);
		const title = root.querySelector("#gn")?.textContent?.trim() ?? "";
		if (ref === null || !title) return null;
		return {
			gid: ref.gid,
			title,
			titleJpn: root.querySelector("#gj")?.textContent?.trim() ?? "",
			category: readCategory(root.querySelector("#gdc .cs, #gdc .cn")),
			tags: [...root.querySelectorAll("#taglist [id^=\"td_\"]")].map((element) => element.id.slice(3))
		};
	}
	var _hoisted_1 = {
		class: "ehl-box",
		translate: "no"
	};
	var _hoisted_2 = {
		key: 0,
		class: "ehl-tabs ehl-tabs--start"
	};
	var _hoisted_3 = ["title"];
	var _hoisted_4 = { class: "ehl-list" };
	var _hoisted_5 = { class: "ehl-head ehl-asof" };
	var _hoisted_6 = { key: 0 };
	var _hoisted_7 = { key: 1 };
	var _hoisted_8 = ["disabled", "title"];
	var _hoisted_9 = {
		key: 0,
		class: "ehl-section"
	};
	var _hoisted_10 = { class: "ehl-head" };
	var _hoisted_11 = { class: "ehl-count" };
	var _hoisted_12 = ["href"];
	var _hoisted_13 = { class: "ehl-subtitle" };
	var _hoisted_14 = { class: "ehl-facts" };
	var _hoisted_15 = ["title"];
	var _hoisted_16 = {
		key: 1,
		class: "ehl-meta"
	};
	var _hoisted_17 = {
		key: 2,
		class: "ehl-meta"
	};
	var _hoisted_18 = {
		key: 3,
		class: "ehl-meta"
	};
	var _hoisted_19 = {
		key: 1,
		class: "ehl-head"
	};
	var _hoisted_20 = {
		key: 2,
		class: "ehl-head"
	};
	var _hoisted_21 = ["title"];
	var _hoisted_22 = {
		key: 1,
		class: "ehl-tabs ehl-tabs--center"
	};
	var _hoisted_23 = ["onMouseenter"];
	var _hoisted_24 = [
		"title",
		"aria-label",
		"onClick"
	];
	var _hoisted_25 = { class: "ehl-tabs ehl-tabs--end" };
	var _hoisted_26 = {
		key: 0,
		class: "ehl-unit"
	};
	var _hoisted_27 = ["title"];
	var _hoisted_28 = { class: "ehl-unit" };
	var _hoisted_29 = ["title"];
	var App_default = defineComponent({
		__name: "App",
		setup(__props) {
			const state = ref("searching");
			const result = ref(null);
			const progress = ref(null);
			const pinned = ref(null);
			const hovered = ref(null);
			const open = computed(() => pinned.value ?? hovered.value);
			const source = ref(null);
			async function run(force) {
				const gallery = source.value;
				if (!gallery) return;
				state.value = "searching";
				progress.value = null;
				try {
					const found = await findEditions(gallery, location.origin, LANGUAGE_PRIORITY[locale.value], {
						force,
						onProgress: (next) => progress.value = next,
						onResult: (next) => result.value = next,
						maxRequests: settings.maxRequests,
						languages: settings.languages
					});
					result.value = found;
					state.value = found.status === "failed" ? "failed" : hasNoSearchTerms(found) ? "noTitle" : "done";
				} catch (error) {
					console.error("[EhHyperlink]", error);
					state.value = "failed";
				} finally {
					progress.value = null;
				}
			}
			function hasNoSearchTerms(found) {
				return found.plan.editionTerms.length === 0 && found.plan.containerTerms.length === 0;
			}
			const FAILURE_MESSAGES = {
				network: "networkFailed",
				timeout: "requestTimedOut",
				http: "httpFailed",
				"invalid-response": "invalidResponse"
			};
			const hasActivity = computed(() => {
				if (result.value !== null) return true;
				return state.value === "failed";
			});
			onMounted(async () => {
				source.value = readSourceGallery();
				if (!source.value) {
					state.value = "noTitle";
					return;
				}
				await run(false);
			});
			const RELATED_TITLES = {
				work: "relatedTitle",
				cosplayer: "cosplayerRelatedTitle",
				realporn: "directRelatedTitle"
			};
			const badges = computed(() => {
				if (!result.value) return [];
				const list = [];
				if (result.value.editions.length > 0) list.push({
					id: "editions",
					label: result.value.editions.map((group) => group.language.name[locale.value]).join(" · "),
					title: t("editionsTitle"),
					groups: result.value.editions
				});
				if (result.value.series.length > 0) list.push({
					id: "series",
					label: t("series"),
					title: t("seriesTitle"),
					groups: result.value.series
				});
				if (result.value.related.length > 0) list.push({
					id: "related",
					label: t("related"),
					title: t(RELATED_TITLES[result.value.plan.mode]),
					groups: result.value.related
				});
				if (result.value.chapters.length > 0) list.push({
					id: "chapters",
					label: t("chapters"),
					title: t("chaptersTitle"),
					groups: result.value.chapters
				});
				if (result.value.containers.length > 0) list.push({
					id: "containers",
					label: t("container"),
					title: t("containerTitle"),
					groups: result.value.containers
				});
				return list;
			});
			const requests = computed(() => result.value?.requests ?? []);
			const sentCount = computed(() => requests.value.reduce((count, request) => count + request.attempts, 0));
			const allFromCache = computed(() => {
				if (sentCount.value > 0) return false;
				return !requests.value.some(requestFailed);
			});
			const hasResults = computed(() => badges.value.length > 0);
			const status = computed(() => {
				if (state.value === "searching") {
					const seen = progress.value;
					return seen && seen.total > 0 ? `${t("searching")} ${seen.done}/${seen.total}` : t("searching");
				}
				if (state.value === "noTitle") return t("noTitle");
				if (state.value === "failed") return t("failed");
				if (result.value?.status === "partial") return t("partial");
				return hasResults.value ? null : t("notFound");
			});
			const DATE_LOCALE = {
				en: "en-GB",
				"zh-TW": "zh-TW",
				"zh-CN": "zh-CN",
				ja: "ja-JP",
				ko: "ko-KR"
			};
			const dataAge = computed(() => {
				const at = result.value?.dataAt;
				if (at === void 0) return "";
				return new Date(at).toLocaleString(DATE_LOCALE[locale.value], {
					month: "short",
					day: "numeric",
					hour: "2-digit",
					minute: "2-digit"
				});
			});
			function toggle(id) {
				pinned.value = pinned.value === id ? null : id;
			}
			const settingsOpen = ref(false);
			const searchStarted = ref(false);
			const searchOpen = ref(false);
			function toggleSearch() {
				searchStarted.value = true;
				searchOpen.value = !searchOpen.value;
			}
			watch(searchOpen, (shown) => {
				const box = document.querySelector("#ehl-app + .gm");
				if (box) box.style.display = shown ? "none" : "";
			});
			return (_ctx, _cache) => {
				return openBlock(), createElementBlock(Fragment, null, [createBaseVNode("div", _hoisted_1, [
					hasActivity.value || status.value ? (openBlock(), createElementBlock("div", _hoisted_2, [hasActivity.value ? (openBlock(), createElementBlock("div", {
						key: 0,
						class: normalizeClass(["ehl-unit", { "ehl-unit--open": open.value === "requests" }]),
						onMouseenter: _cache[2] || (_cache[2] = ($event) => hovered.value = "requests"),
						onMouseleave: _cache[3] || (_cache[3] = ($event) => hovered.value = null)
					}, [createBaseVNode("button", {
						type: "button",
						class: normalizeClass(["ehl-icon", {
							"ehl-icon--active": open.value === "requests",
							"ehl-tab--pinned": pinned.value === "requests"
						}]),
						title: unref(t)("requestsTitle"),
						onClick: _cache[0] || (_cache[0] = ($event) => toggle("requests"))
					}, [requests.value.length === 0 ? (openBlock(), createBlock(unref(CircleSlash2), {
						key: 0,
						size: 14,
						"aria-hidden": "true"
					})) : (openBlock(), createBlock(unref(Activity), {
						key: 1,
						size: 14,
						"aria-hidden": "true"
					}))], 10, _hoisted_3), createBaseVNode("div", _hoisted_4, [
						createBaseVNode("h4", _hoisted_5, [result.value ? (openBlock(), createElementBlock("span", _hoisted_6, toDisplayString(unref(t)("dataAsOf")) + " " + toDisplayString(dataAge.value), 1)) : (openBlock(), createElementBlock("span", _hoisted_7, toDisplayString(unref(t)("failed")), 1)), createBaseVNode("button", {
							type: "button",
							class: "ehl-refetch",
							disabled: state.value === "searching",
							title: unref(t)("refetchTitle"),
							onClick: _cache[1] || (_cache[1] = ($event) => run(true))
						}, [createVNode(unref(RefreshCw), {
							size: 11,
							"aria-hidden": "true"
						}), createTextVNode(" " + toDisplayString(unref(t)("refetch")), 1)], 8, _hoisted_8)]),
						requests.value.length > 0 ? (openBlock(), createElementBlock("section", _hoisted_9, [createBaseVNode("h4", _hoisted_10, [createTextVNode(toDisplayString(unref(t)("searchRequests")), 1), createBaseVNode("span", _hoisted_11, toDisplayString(requests.value.length), 1)]), createBaseVNode("ul", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(requests.value, (request) => {
							return openBlock(), createElementBlock("li", { key: request.url }, [createBaseVNode("a", {
								class: "ehl-url",
								href: request.url,
								target: "_blank",
								rel: "noopener"
							}, [createTextVNode(toDisplayString(request.term) + " ", 1), createBaseVNode("span", _hoisted_13, toDisplayString(request.url), 1)], 8, _hoisted_12), createBaseVNode("span", _hoisted_14, [
								request.hitCount !== null ? (openBlock(), createElementBlock("span", {
									key: 0,
									class: "ehl-meta",
									title: unref(t)("searchHitsTitle")
								}, toDisplayString(unref(t)("searchHits")) + ": " + toDisplayString(request.hitCount), 9, _hoisted_15)) : createCommentVNode("", true),
								request.error ? (openBlock(), createElementBlock("span", _hoisted_16, toDisplayString(unref(t)(FAILURE_MESSAGES[request.error.kind])) + " " + toDisplayString(request.error.status ?? ""), 1)) : createCommentVNode("", true),
								request.attempts > 1 ? (openBlock(), createElementBlock("span", _hoisted_17, toDisplayString(unref(t)("requestAttempts")) + ": " + toDisplayString(request.attempts), 1)) : createCommentVNode("", true),
								request.cached ? (openBlock(), createElementBlock("span", _hoisted_18, toDisplayString(unref(t)("fromCache")), 1)) : createCommentVNode("", true)
							])]);
						}), 128))])])) : createCommentVNode("", true),
						requests.value.length === 0 ? (openBlock(), createElementBlock("p", _hoisted_19, toDisplayString(unref(t)("noRequests")), 1)) : allFromCache.value ? (openBlock(), createElementBlock("p", _hoisted_20, toDisplayString(unref(t)("nothingSent")), 1)) : createCommentVNode("", true)
					])], 34)) : createCommentVNode("", true), status.value ? (openBlock(), createElementBlock("span", {
						key: 1,
						class: "ehl-status",
						title: status.value
					}, toDisplayString(status.value), 9, _hoisted_21)) : createCommentVNode("", true)])) : createCommentVNode("", true),
					badges.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_22, [(openBlock(true), createElementBlock(Fragment, null, renderList(badges.value, (badge) => {
						return openBlock(), createElementBlock("div", {
							key: badge.id,
							class: normalizeClass(["ehl-unit", { "ehl-unit--open": open.value === badge.id }]),
							onMouseenter: ($event) => hovered.value = badge.id,
							onMouseleave: _cache[4] || (_cache[4] = ($event) => hovered.value = null)
						}, [createBaseVNode("button", {
							type: "button",
							class: normalizeClass(["ehl-badge", { "ehl-tab--pinned": pinned.value === badge.id }]),
							title: badge.title,
							"aria-label": badge.label,
							onClick: ($event) => toggle(badge.id)
						}, [badge.id === "editions" ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(badge.groups, (group) => {
							return openBlock(), createBlock(LanguageBadge_default, {
								key: group.language.value,
								language: group.language
							}, null, 8, ["language"]);
						}), 128)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(badge.label), 1)], 64))], 10, _hoisted_24), createVNode(GroupList_default, { groups: badge.groups }, null, 8, ["groups"])], 42, _hoisted_23);
					}), 128))])) : createCommentVNode("", true),
					createBaseVNode("div", _hoisted_25, [source.value ? (openBlock(), createElementBlock("div", _hoisted_26, [createBaseVNode("button", {
						type: "button",
						class: normalizeClass(["ehl-icon ehl-labeled-button", {
							"ehl-icon--active": searchOpen.value,
							"ehl-tab--pinned": searchOpen.value
						}]),
						title: unref(t)("searchTitle"),
						onClick: _cache[5] || (_cache[5] = ($event) => toggleSearch())
					}, [createVNode(unref(Globe), {
						size: 14,
						"aria-hidden": "true"
					}), createBaseVNode("span", null, toDisplayString(unref(t)("search")), 1)], 10, _hoisted_27)])) : createCommentVNode("", true), createBaseVNode("div", _hoisted_28, [createBaseVNode("button", {
						type: "button",
						class: normalizeClass(["ehl-icon ehl-labeled-button", {
							"ehl-icon--active": settingsOpen.value,
							"ehl-tab--pinned": settingsOpen.value
						}]),
						title: unref(t)("settings"),
						onClick: _cache[6] || (_cache[6] = ($event) => settingsOpen.value = !settingsOpen.value)
					}, [createVNode(unref(Settings), {
						size: 14,
						"aria-hidden": "true"
					}), createBaseVNode("span", null, toDisplayString(unref(t)("settings")), 1)], 10, _hoisted_29), settingsOpen.value ? (openBlock(), createBlock(SettingsPopup_default, { key: 0 })) : createCommentVNode("", true)])])
				]), searchStarted.value && source.value ? withDirectives((openBlock(), createBlock(SearchPanel_default, {
					key: 0,
					source: source.value,
					onClose: _cache[7] || (_cache[7] = ($event) => searchOpen.value = false)
				}, null, 8, ["source"])), [[vShow, searchOpen.value]]) : createCommentVNode("", true)], 64);
			};
		}
	});
	function isTransparent(color) {
		if (color === "transparent") return true;
		return color.startsWith("rgba(") && color.replaceAll(" ", "").endsWith(",0)");
	}
	function opaqueBackground(element) {
		for (let current = element; current; current = current.parentElement) {
			const color = getComputedStyle(current).backgroundColor;
			if (!isTransparent(color)) return color;
		}
		return "#fff";
	}
	async function mountGalleryPage() {
		const host = document.querySelector(".gm");
		if (!host) return;
		await loadSettings();
		const container = document.createElement("div");
		container.id = "ehl-app";
		container.style.setProperty("--ehl-bg", opaqueBackground(host));
		container.style.setProperty("--ehl-border", getComputedStyle(host).borderTopColor);
		host.before(container);
		createApp(App_default).mount(container);
		watch(locale, (current) => void prepareTagNames(current), { immediate: true });
	}
	function traceTab(here, siteId) {
		const id = requestIdOf(here);
		if (id === null || !isTraced(here)) return;
		debugLog(id, "script started", `${here.href} readyState=${document.readyState} visibility=${document.visibilityState} site=${siteId ?? "none matches this URL"}`);
		window.addEventListener("error", (event) => void debugLog(id, "page error", describeError(event.error ?? event.message)));
		window.addEventListener("unhandledrejection", (event) => void debugLog(id, "unhandled rejection", describeError(event.reason)));
	}
	var previewSite = previewSiteFor(new URL(location.href));
	traceTab(new URL(location.href), previewSite?.id ?? null);
	if (previewSite) await(answerPreview(previewSite));
	else await(mountGalleryPage());
})();