☰

EhHyperlink

受 TranslatedJump 啟發的 E-Hentai / ExHentai 畫廊關聯腳本:除了其他語言版本,也找同系列、原刊雜誌與收錄作品,並用 Google、DuckDuckGo、DLsite、pixiv 找來源

您需要先安裝使用者腳本管理器擴展,如 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.4
// @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;margin:10px auto 0}#ehl-app+.gm{margin-top:0}.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}9450a9e6e1f3_`;
	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);
	}
	var untraced = () => {};
	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 googleResultsComplete(root) {
		return root.querySelector("#botstuff");
	}
	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;
		}
	}
	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, trace);
		} 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 locationOf(headers, url) {
		for (const line of headers.split("\n")) {
			const colon = line.indexOf(":");
			if (colon < 0) continue;
			if (line.slice(0, colon).trim().toLowerCase() !== "location") continue;
			return new URL(line.slice(colon + 1).trim(), url).href;
		}
		return null;
	}
	function resolveRedirect(url, trace) {
		const { promise, resolve } = Promise.withResolvers();
		if (typeof _GM_xmlhttpRequest !== "function") {
			resolve(null);
			return promise;
		}
		const started = Date.now();
		let settled = false;
		const settle = (how, target, status) => {
			if (settled) return;
			settled = true;
			window.clearTimeout(deadline);
			trace("redirect", `${how} after ${Date.now() - started} ms, status ${status ?? "-"} → ${target ? new URL(target).host : "nowhere"}`);
			resolve(target);
		};
		const targetOf = (response) => {
			const moved = response.finalUrl === url ? null : response.finalUrl;
			return locationOf(response.responseHeaders, url) ?? moved;
		};
		const deadline = window.setTimeout(() => {
			settle("timeout", null);
			request.abort();
		}, RESOLVE_TIMEOUT_MS);
		const request = _GM_xmlhttpRequest({
			url,
			method: "GET",
			redirect: "manual",
			onreadystatechange: (response) => {
				if (response.readyState < XMLHttpRequest.HEADERS_RECEIVED) return;
				settle("headers", targetOf(response), response.status);
				request.abort();
			},
			onload: (response) => settle("load", targetOf(response), response.status),
			onerror: (response) => settle("error", null, response.status),
			onabort: () => settle("abort", 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(_url, trace) {
			if (!await rendered(() => googleResultsComplete(document))) return {
				status: "unreadable",
				results: []
			};
			const results = readGoogleResults(document);
			await Promise.all(results.filter((result) => isGoogleRedirect(result.href)).map(async (result) => {
				result.href = await resolveRedirect(result.href, trace) ?? 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);
		new ResizeObserver(([entry]) => {
			const width = entry.borderBoxSize[0].inlineSize;
			if (width === 0) return;
			container.style.width = `${width}px`;
		}).observe(host, { box: "border-box" });
		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());
})();