JavDB Power Tools

JavDB/MissAV 双站增强工具箱:收藏管理、状态标签、屏蔽过滤、跨站同步、热播/Top250榜单、新作品检测、预告片、字幕搜索、WebDav云备份、演员信息、清单管理、截图墙、磁链聚合、以图识图等功能插件

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         JavDB Power Tools
// @namespace    zerobiubiu.top
// @version      1.30.4
// @author       zerobiubiu
// @description  JavDB/MissAV 双站增强工具箱:收藏管理、状态标签、屏蔽过滤、跨站同步、热播/Top250榜单、新作品检测、预告片、字幕搜索、WebDav云备份、演员信息、清单管理、截图墙、磁链聚合、以图识图等功能插件
// @license      MIT
// @copyright    2024-2026 zerobiubiu (https://github.com/zerobiubiu) — 基于 JAV-JHS 3.3.6 (MIT) 二次开发
// @icon         https://cdn.jsdelivr.net/gh/zerobiubiu/Figure-bed/b507c13a-9f4e-41b5-bbbb-129d0a21f97d.png
// @homepageURL  https://github.com/zerobiubiu/javdb-tools
// @match        https://javdb.com/*
// @match        https://missav.ws/*
// @match        https://missav.live/*
// @connect      xunlei.com
// @connect      missav.live
// @connect      javdb.com
// @connect      supjav.com
// @connect      127.0.0.1
// @connect      javstore.net
// @connect      u9a9.com
// @connect      u3c3.com
// @connect      sukebei.nyaa.si
// @connect      btsow.lol
// @connect      imgur.com
// @connect      api.imgur.com
// @connect      lens.google.com
// @connect      yandex.ru
// @connect      translate-pa.googleapis.com
// @connect      123av.com
// @connect      fc2ppvdb.com
// @connect      adult.contents.fc2.com
// @connect      *
// @grant        GM_addStyle
// @grant        GM_addValueChangeListener
// @grant        GM_getValue
// @grant        GM_info
// @grant        GM_openInTab
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @grant        window.close
// @run-at       document-idle
// ==/UserScript==

(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(" html #layuicss-skinlayercss{width:1989px;display:none;position:absolute}.layui-layer-shade,.layui-layer{_position:absolute;pointer-events:auto;position:fixed}.layui-layer-shade{width:100%;height:100%;top:0;left:0}.layui-layer{-webkit-overflow-scrolling:touch;background-color:#fff;-webkit-background-clip:content;margin:0;padding:0;top:150px;left:0;box-shadow:1px 1px 50px #0000004d}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #0000001a;box-shadow:1px 1px 5px #0003}.layui-layer-load{background:#eee url(data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=) 50% no-repeat}.layui-layer-ico{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANIAAAA9CAYAAADYizcVAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAACAASURBVHic7Z15fFvVmfe/92qzJMtrvCQ2jp09TuwsQCAkISwJDVAoW0hombaQhgKlnU5pmc60A+3M0FK6dxhoGghLC0PCEjJAIW8gISQhwWSzHcfO4tix41heZNmSLFnS1T3vH7IUy1qdmPfTd8a/z8cfS/ee5/zuvbq/e855znOeKwkhBEkg3FYC1j0Eug6i2upQHU0ITycAkjEfOaMMOXcWmrz5aAoXIZkKk1WZEs563ezstVLV10WNy8bJfgedPg8A+XojU8wZVKbnsiAzj6VZhUwwmEaFV7Xb8NXV4D95DKWliYC1DbW3FwA5KwtNYRHakjJ0U6ajn1WJnJ07KrzCd5aAYyeqqwrVXYM6cBLhH7zOunzktCnIpkrk9AVoMpYi6SeMCq/D4aCpqYmWlhasVis2mw2n0wmAxWIhNzeXwsJCSkpKKCsrIyMjY1R41Z5ufLWH8R8/ir+5kUB7G2pvDwByVg6a8UXoSiejm1aOvmIucs64UeG1+vvY42rkQH8zRz1nOeXtplMJnm++1sIkwzjKjRO42FzKovTJFOoyk9YpJRKSam9AaXoLpfld1J6jKR2knFOOtvRGtGW3IGfPSPHUIlHXb2dTRxObO5updfakZFNhyeHW/FLuLChjljn7vHiV1tMM7N2Jt2oPyummlGy0E8swLFhE2sKlaC+aeF68qrsOxbaJQM9m1P7alGxkcwWanFvR5t6JbJp1XrwdHR3U1NRQV1dHe3t7Sjbjx49n1qxZVFZWUlBQcF68SksTA7u2M7D3Y5TmxpRstKWTSVt4JWlLrkFbUnZevA0DVt6yH+Sd3hqOes6mZFNunMAXsyq5JXs+M9LiNxBxhCTwNzyPv/4lVFstctZUNIWLkPPno8kuR7KUIBmyEV47wtlCwH4UtfMgAese1N4TAMi5FehmfhXdjHsAKaWDFsAfzzSwvq2eQw4bM8xZLM0pZEFGPhXp2ZQZLeRoDfQoXpo8TmpddqocnezssdLQH2wx5mXksrZoJvcXz0iRFRACz7Z38XzwV/xNJ9EWlaArr0A3ZQbaiWVo8guQ0zNQXQ4CnR0op5vwn2zAf7QWpa0FAF3ZFIzLbsC4/EaQUmUWKB1/xN+xHtV1CNk0AzljKZr0BcimCqS0MiRtDkLpQQw0obprCbiqUB07Ud0NweucPg9dwVq0Bfenfp2FoKqqik8//ZS2tjby8/MpKyujpKSEwsJCsrOzMZlMuN1u7HY7VquVlpYWmpqa6OwMtpBFRUVcdtllLFiwACnV8xUC93tv4dn6Nv7G42gvmoh+9jx002aiLZ2EpmACssWC6nQS6DiL0nwK//F6fEcOobSeDl7nydMwfuEmTNffkvJ1Fgie797DS92fUOM+w9S0AhalT2G+uZRZxvGU6HPJ1pqwK25afDbqPO0c7G9mj+skJwY6AKg0FfPVcVdwz7hFSDGuc5SQhKcTX+1/4K95GjlvLrpJt6It+xJS+kXJD9jTiXJyE/5Tm1G7DgdPvPJB9BXfRjLmJ7S1+jz88nQtv2mu4ZLMPFYVTGJlQRkT09KT8lp9Hv7SfpKNHafY39cFwPdKK/nBxAoK9caEtmqvnf7/3oT77TfQTZ5G2hVXYVh4JZq8xMcbsh34+EMGPvkIf+NxAEw33Y755juRsxK3isJvxX/2l/jbfoNsuQRt7iq0uSuRDMlbNeG3onT9BcW2EdW5HwBd0ffQTfgBki5xt9rpdLJz50527dpFcXExc+bMoaKiguzs5K240+nk0KFDVFdXc+bMGQCWLFnC0qVLsVgsCW1Vew/9b75C/+ZX0U2dSdqSa0hbfDWa/OTDANXeg2fHVgZ2bcd/oh4A862rMd/2ZeTsnIS2nX4Hf+j8kKc7djDXVMJt2fP5UvZcLtIntgvZburZz5v2gxx2Bx+YDxZczXfyryVfF9m91fzkJz/5SeiL8HTiO/AE/rpn0c28F8MlP0I78UYkffI+IoCkM6MpWICm6CpQ/ajdh1A7PgO/C03ePCSdOaad1efhscYDPNVSxwMXzeTxyZdwS/5EsrT6lHjTNTquyCpgeU4RPqGy39HN3t4OnAE/l2bmka7RxbRTe+24Nr2E570tmL5wE+l33YNhwRXI5tjHGXW+aUZ008vRV86HgIK/8Tj+4/WIAQ+6ydOR0mKLWPit+FofQ2l/Ct34B9Bf9DjanFuQtFmp8WrS0ViuQJu1HPChuvajOvciVCea9EuRNLEfPk6nk23btvHJJ5+wcOFCVqxYwaxZszAaEz9sQjAYDEycOJGpU6eiqipnzpyhpaUFr9dLcXExBoMhpp1q78H18nO433kD0w23YvnqWtIWXolsTv6QBJCMRvQzKzDMuxQUBf+JBvwNRxAeN7qpM5HiHH+n38HP29/j2a6PuTdvMT+e8EVuzKokU5Pa+Zo1Bhakl3FVxnT8IsAhdwuf9TfjVL3MN5Vg1pw73yFCEvgO/QLl+CvoL34Ew6WPIhnzUiKMOnFDFtqS5aDRoXYdINC5HySBtuhqhnc/BPCTU4d4oe04j06+mCemXkpBklYkHrJ1Bm4YV4JO1lDV18Xevk6EJHFdblF0YywErtdeYmDH/yF95d2kf3kNcub5ja1kczqGeQuQtFr8J4/hP34UEBgqL47R/RD4z/yEQNcL6C96FH3JE0i68xtrSNpsNNk3IMk61P4qVMdekASarOuIus5CsG3bNvbv38+yZctYsWIF6emp3cjDYTQamT59OhqNhtbWVlpaWhBCMHXq1OhunhC4XtmA54O/YrnrXixfvx85K3lrEAtyugXDJQuRtLqgg6LhCCCCApOG31eCJ6zv8YrtUx4Zfz2PFd1Eni5xqxkPWRoTyzPL0UlaDvSfZn9/E6okuDpjRribFxaSv+F5fJ/9DP3Fj6Cf8z1S7W/Hh4SmcCFIEDi7C7XjMyRTHppx8yJK/fFMAz8++RmPTr6YH5XNGQVWuDK7EIHE9p6z7O3toMBg4tKMSI+PZ9u7uP7rBdJX3o35ti+PYFwTj1hCP7MCEPiOHMZ/vB5NVg66ydMiiikdf8R3+sfoL3oUXdGPGJXrnHElIAj0bUd17kXWFyCnXxpRqqqqiq1bt7Js2TKuueaa1Mc18VglibKy4KC/sbGRlpYWMjIyKC4ujijnfu8tXH9ej+WuezGv+uroXOfZc5AE+GoO4G84gpydg27qzIhiz3fv4fGz7/LI+Ot5uPC6mOOaEdEicUX6ZASwy3mcz/qbyddlMM9UAgwKSbU34Nv/ONrSL2K49FGS/biuZ3PxHXwS38En0U6+HSkt/hNGU3g5wtON2n0I0W9FU3g5kjF4U9f12/lx435uzS/liamXXvAtNRRLsgvp9HvY7+jmrK+fxdmF5A+2dErrafpffYG0yxaR/uU1ET+u0taC0tqcUt8dVcV7sArZaAp3L/QzZiMcffgbj6PabehmzEbODHbZVHcdvtYfo829FX3JEyS6zsJ3FqVzA0rX86h9HyB87UhpU5Dk2N0nTcYSUDpRXfsR/rNoLIuRdMFxXkdHB1u3bmX27NmsWLEioYjcbjdbtmzh/fffp6GhAbPZTG5ufPd+aWkp/f39nDlzBofDQWlpabilU1qacP15PWkLr8Ty9fsvXERDoJ9VidrXi/9EA2qPLTgNMdijaBiw8vjZd7gxq5LHim66YBENxcL0SXQrLg65W7D6+7g8fTLjtOnIAErTWyBr0JXfy4U/IYdDQlf5EHLeXFRbbZBrEJs6mtBIMg8Wl48Ka31/L58OOhsk4AcTK7kkM49DDhubOs65swf27gRZxviFmyJ+XLXXjvvtN+h/4xUC7WeS8nmrD9D/2p/xbH+fQHfn4OlKmG5eiW7yNPxNJ4Ncg1Bsm0DSoC14kETXOdCzGc/hcnxN30Wx/gn/2T/gPbkGz+FyAn3b41hJ6Cb8ANlyCarrUJBrEDU1NUiSxMKFCxOKqKWlhccff5yOjg5mzJiBTqfjxRdf5NVXX41rI0kSV155JcXFxbS1tVFTUxPeN7BrO8gaTDfeGlNEgY52+t94hYGd2xCKP2q/6ujD/e5m3O9uRnU5hxNjvv3L6KbOxN94PMg1iLfsB5GRWTNuyaiKCIIt07cLrmWuqYQa9xnesh8EQBZuK0rzu+gm3YqcPTNJNecH2TIR3aRbAVCa30W4rZz1utnc2cyqgknMTj+/sclQ1Lrs3Fb9AbdWb2NfX/CmLjNaWFUwCYDNnc2c9bpR7Ta8VXtIu+IqtBeVRtThqz2E58P38NUewvHc0wQ6rXH5fEcO43pxHf7G4/Rv/i8Gtm8N79PkF5J2xVUAeKv2oNptwcnWns1oc1chm2bHrVftP8xAw+0IpS+4QdaDHHSWCO8ZBupXoHrqY9pKhjK0uauAoBiF7ywOh4O6ujrmzJmTdN5nw4YNXHXVVXzrW9/ihhtu4O677+ZHP/oRtbW11NfH5gTIyclhzpw5ANTV1eFwOFB7uhnY+3Fw3mfipBgnqjKwcxvu/36N/rc24a8/ElXEe2Af/Vs24v7v1/Dt3xu1X1MwnrQl1wAwsPdj1J5urP4+3umt4bbs+cw0jo+y2Ww/xEXVPyDn4HeYWP2PbO2ri9ivCJVvn36FcQf/npyD32H5sd/QrbgiykzU53Jb9nwA3umtwervQw5Y94DqR1v2pbgXajSgnXInctZU1J6jBKx72Nlrxa+qrCw4v8m1oTjstLGy5kMa+ntp97r59rFzF/3u8VOYYc6i1tnDzl4rvroaUAIYFl4ZfYxlUzBcthgAX/V+nM8+FVNMvrpqnM89hdLWgqTTY7zmevRzL4kok3bltWiLSlBON+GrqyHg2AnCjzZ3ZcJz8bX+M0EXjIy+9BeY5jdhmn8KXfEjgASqH3/rv8S11+bdjWyagdpfS8Cxk6amJgKBABUVFQl5jx8/TiAQYPny5RHbTSYTc+bMYdu2bQnt582bR35+Pu3t7TQ1NeGrPQwBhbTFV8c+z5oDuP7reQK2Lvwn6nG99CfU/nM3rNLajOvP6wmcPYPS1oLzz+tRWpuj6jFe/QW0F01EaW7EV3uYPa5G/CLAl7LnRnOKAOu6dtIf8ALgDHh4qvPDiDINA+28bNuHSnBW6EB/M+/1RYv8zpxLmJpWwFHPWfa4GpEDXQeDYT0pzBNdCCRjPprCRQAEug5S1dfF0pzClOaJEuGw08ZdtTs4Njgha9Ho+M5F52b6C/VGluYExztVfV34Tx5DV14Rc55IW1xCxpqHSBsUmfdQVVBMHedm/X1HDuN87j9RzrQg6Q2YbriF9LvXoJsW2ZrLWdnoyoM3r//kMVRXFXLG0sTzRKoX1fUZAJrsZegmPIKkn4CkL0Zf8gtkY/ChE3Dui1uFpCtEzlgarM5VRUtLC2VlZUnnibq7uzHHcfsXFxfjdrsT2lsslrDzoaWlBf/xo+hnz4s71gx0dyH8/iHfOxFOR/i72tdHoKvz3Hd7D6o9OspFzs5BPzvowPIfP8qB/mYWpU+JOU8kI6GXNBHb9JI24rt22H4AXYxt+boMFqVPAYJik1VbHXL+/JgnO9oI8ai2OmpcNhZkxJ70PODo5pi7L2l9Na4e7q77KBzVkK7R8Uz5Yv5u/JSIciGeGpcNpaUJ3ZT4oUtydg6Wex4g7fIlwKCYnn8Gpa0V39EanBueRmltRtLpMd14G+Y7/w5JH9sBEOJRWppQ3TVo0hckPB+h9CB83QBRghNKD0KxJ7QPIcSjumuwWq2UlJSkZHehCPFYrVb8zY1RD5eh0M+ei27S1PB3w+VL0OSd63pqJ5aStnDJuf0XX4Z2mAc0hBCPv7mRo56zzDeXxiynlWT+vmA5BYOxc0X6bB4u/EJEmelpBfx94bKweJZnzmJFZuwQrBDPUc9ZtKqjCU12edwTHk2EeFRHEyctDiqGjY0EsNNu5a7a7YzTG3ijchnTTLEng2tcPdx95CPqnMGby6LRsW7WEu4qiO6Ph3hO9jsIWNvQTkzcnZSzc7Hc8wBCCLyf7sZ7YB+qsw/hHQiKSKvFdMMtmG+/K66IgDBPwNqGOnAS2ZS4eyVpMzFMeRZEANk8J7xddVXhbbwX4Q+eqyZzWeLjH+RRB05is9koLBydIOJkCPHYbDYC7W1oS2OMjQahKZxA1g//De+hKiSTmbTLFoPm3JNftmSS8cDDGC6+HKGqpC1cEncCN8QTaG/jlDebWTHGRiFcmzGD96d/l5MDXcw0FjJBFzkJLiHx2ISbuSlzDv2qnwXmiRjk2BP6IZ5T3m60wtOJZPl/88QK8QhPJ50+D2XGyAkyu9/LQ8f2YPW6sXrdrKrdzqsV1zB9mJhqXD3cVbODo/3BGytDq+NP5VeyKs54K8TT6fOg9vaiyU8+ASrnjCPj3gdxpRnx7NyG/3hwsC2nWzCuuBnzzSuRDGkJ6wjxqL29CH8nUlqS8aBsQpu/JmKTv/23+JoehsE+u2ycgn7ikwmrCfEIfydOpzNpt+73v/89TqcTt9vNr3/966j9Ho8nvO+aa65h3rx5MWohzON0OlF7e9AUJI5O10woxjShOO5+OTsn6FlNghCP2ttDp+KkRJ84Gn+iPpeJScrMNycP1QrxdCpOtACS4cK9ZqlgOE+ONvJpbtJoebC4nEeOf0p/QOGww8aq2u28Mvtqys3BJ8dhp41VNds5Ptj1y9TqWT9rCSvz49+kw3nk9NSWAcg54zBcuhDP7u0QCATPwZxO2uVLkIzJl2wM55G0I5vRVz3H8DV9L/xdm/dl9GVPIWkT/17DeUymxMfa3t7OqlWrkh7Pzp07qa+vjyuk4Txykvi70cJwnmzt6CynSYahPLJkzEd4U+t7XyhCPJIxn3y9kR7FG7E/TdbwYPFMfjfjCkya4CCw2mHj7iM7OOVxUt/fy+raHWERZWh1rCtPLCIgzJOvNyJnZaG6HAnLh+Crq6Z/86thEQGoPTZcr/2ZgDV5GH6IR87KQtLlI5TUloSEILzN4c/agq9jmPpyUhEBYR5Jl4/FYknqKJAkiXnz5oX/AoEAW7Zs4eDBgxHbkwWmhngsFgtyVg6q05mw/GghxCNn5ZCvtWBXEp/vaCHEk6+1oJUzyhDOFqS00VmclgjCGYyglTPKmGLOoMnjZJwuunv0jQnTCAiVf2jYi0cNcMhh47aaD3ArCicGRWTR6Hhm5uK43bmhaPIEL/QUcwaawiICnR3IlsSBuL4jh3E+O+ji1hswLrsB1dnHwK7teD/dA34/lnu/haYgfn880BkMwdcUFiGnTUEMNCGlj2BxmiSHP2qyvpCgYCTEQHDyWU6bQm5uLna7Pa5HLhb27dtHTk4OJ06cSP1YAbs9+KDMzc1FM76IQMdZ5IzUAp4h2DVTXU5QFNDpkDMyk/5OAIGO4ENNM76ISYZxtPhs5GpTP9/zRYvPBsAkwzi0cu4sAvajyHmxm+tYSP+G7byIA/bg4kA5dxaV6bnUuuxcmhE7MPabRTOQkfjusb24AwrVjnOcGVodfyyP7ViIhVpX8AeuTM9FW1KGcropKgZuKHx11Tif/Q+UtlaQ5aBj4bYvIwY84PczsG8X3kOfIZ79DzK+8e24YgotDtSWlCGbfKju2qgYuIQQyrnPgdSf7qo7uDhQNlVSWFiI1WqNioFLhOuuu44NGzYwffr0lG0g6K2DoNNBhwel+VRUDFzUsTr7GNizE1/1AZRTJ1B7exBCIMky8ri84JKLhUvQz78MSRt70K80nwJAVzqZcuME6jzt4Ri4oWgYsPKh4yhr85ZGucHjoS/g4Xcd21honsJ1mZFOuTpPcFqk3DgBWZM3H7XzYEqVXihCPJq8+SzIzKPK0Zmw/Nqi6fx6+uVR29eNQERAmGdBZh66KdPxn2yIW9bfcATn+kERaTSYb7oD821fRjIaw65xw2WLQAh81QdwrP9DxDxTRF2DPLop05HTFxBwVaV8zACy+WLSyt8nbdZWNJmpt0ghHjl9ASUlJbS0tIyId9q0aVRWVnLbbbeNyC7EU1JSgm5aedhBEwuqy4l7yyZs3/0GjqeeZGDXhwRsXaDXB1sxnY6A9Syebe9i/9cfYv/JD/DVHopZV4hHN62ci82lHOxvjlnursZ1/MuZt7jz5B855E58TVwBL6/2fMaKY7/l99YP+H7rJmxKf0SZEM/F5lK0msJFKI2bEa7WlCdlXc+e6waaVn6KnDklQekghKuVgHUPck45msJFLNVksNHayOkBV8JJ2fuLZmD1evhp4wEA/lS+hNUjENHpARc7e6xUWHJYmlWIflYmA5/sJNDVGTUp66urxrHu98E4O40W8xdvw7zy7gjvnJwzjow1D+GUNQzs/RhfzUEcT/8a47UrSLvynFs60NWJ/2gt2oll6GdVIpmno9g2IrynU1q8B8ExjvA2IwJONJnLkxsAwnsa1bEzuBQ9Yyll+nSqq6ux2+1xvXdCiKh4OlmWee+99yK2Wa3W8KTrcNjtdpqamhg/fjxlZWXolaKgODqtUZOy/lMncP7p9/iODC7+nDkbw/zL0JdXIueOQzKkIbwDBLo68NUewrt3F77D+7E3HCH97rWYbznnGAl0WvEdOYS2dDL6irksStex2X6AVl9P1KTsV3Ov4FfWrXzsPMbyYye4KWsOV1umM8M4nkyNEa+qcNrXQ427lb/21VI/uBx9nNbCA/lXYdGcuw9afT3scZ2k3DiBRemT0UqmQuTc2ShNW9BVPJToN7ogKE1bUHtPoJ//AyRTIROAOZZcXuto4vsTE8+v/GTSPNJkDTk6A2uLRtbdeK2jiYb+Xh6dPD+YHMVgQls6Ce/ejzHdfEdEWeHpR+3uDM4T3bwS8x1fQdJFLy6Us3Ox3PstkKSgKDvOojoiHRjevR+jtLVgXnl3ODmKbJqDYnsN3YTvp3Tsgb4P8DbeD4Cky0Ob97WkNortNVR3A7qLHkXSTyBDH8yzUFtby5VXRodFAVx77bXYbMm765MnT+b666+Pua+2tpbOzk6WLVsWTo6iLZvCwO4dmG+7K6KscDrw1deiGV9E+sq/w3DZ4nCE/FBoiydimLcA0/Iv0v/GK7i3vYPa0x1RZmD3DpTW06TfdQ9yzjgKgdnGIrbYD/NQwTURZf+hcDmLLVN5sv19PnQcZYv9EFvsh9BIMmmyDkWoeNVz0RZZWhM3Z83lOwXLmGSIHNtusR/mxEAHj4xfQaEuM+j+1pbdgq/6d2js9Z9L4Kpqr8d/ajNybgXaslvC2+8sKOOJ5mqOuOxJA1d/WFo5Yt4jLjsbO04xLyOXO4c4JdIWLqX/rVdRWpsjAlf1FRdjWfttVFs3puu/FFNEIchZ2aR/ZQ1ybh6GOfPRzTgXiKq0NjPwyUfoyqaQtnBpeLs29078Z59AdR9JGLga5kibipRWAoF+ZFN07NhwqO4jKLaNyOnz0ObeGd5eWVnJRx99REdHR8zA1eHxdSNFR0cH1dXVFBUVUVl57ndKW3IN/a/9BeX0qYjAVf2sOeT89FfIWTloSycnrV8zvgjLfd/BuOz6iHqU06cY2LU9mCJgyTnR3JI9n99Zt1HvaY8KXL3UXMprU+5nj6uRrX1H2O6op83Xi08oaCWZLF0ms4wTuDZjJsszypmSFh19U+9p5037QSpNxdwyGLyKGISv/jkxsPv7QghVjC5UMbD7+8K5Pkf46p+L2vt0a714oH7358AqxAP1uwX/Z714urU+ar9769vCsf4PQqijzKyqwrH+D8J6x3Lh3vp21G6/9WnhPfWASPk6B9xCVfpSIRbeUw8I1x6E3/p01N59+/aJzZs3C3WUz1dVVbF582bxyCOPiH379kXt73/3TdH3n7/6XK5z33/+SrTfuEj0v/tm1O7nunaJh1s2CjXJdVaFKuxKv2ga6BZnvHYxoPqTln+4ZaPIPvBt8VzXrvD2sH9VN+Me0KUR6BjZgDgZfNW/xV+/AV3lg4MZhSJxf/EMjBode3o7RpX3Z03VPNNaz/dKK7m/ODq2zrj8RtDrB5eFjx76N/8X7q1vY7rp9iDHMGgL7gfZSMC5J7UKZSOSJvkEsr/tZ/jbn0FX9L3BjEKRWLBgAVqtdsSOh2TYsWMHe/fuZcmSJSxYEB1LaLr+FiSDAV9DdAT1haB/059x/3Uz5ltXBzMKDcM94xaRJuuociVOqyYhkaUxUWrIpUifhWFYEOtw/Ma6jQ1du3mw4GruGbfo3I4ItXl7hepzjeS5kFC73sO/Fq4XisXArn8Qqrsjbkm73yucim+UWIX491OHRfqHL4j7ju4S7V53/LIup1A98fePjFgVrjdeFh133yz61v1OBOw98Yv67UJVnKPDK1ThO/Pvov/TdDHQeJ9Qfe1xS7rdbuH1ekeHVVXFhx9+KH784x+LN954QzgcjrhlA6N9nV99UVhvXyb6/uNJEeixxS3aq7iFKzAwOrRCFb9q3yqKDn1ffPf0q6LDF9lLSJggkoAXNPGDMuNBtdfjP7oh3BKlko5rKLxqAIOcmp9/KI647Dx95mi4JUolHddQCL8fSRd7riIRlNZmPFvfDrdEqaTjioDqhThLyBOauY+gdDwdbolSSccVcdyKglab+AkcCx0dHezduzfcEqWSjmsozvs6nz4VXDE72BKlko5rKLxCSdrixEK9p53nuneFW6JY6bjiC0lV8DdsgIAv9bx2rlaUpi34T20GNTDiBJEQXKH49JkGfGog5bx2pwdcvNbRxMaOUwSEOvIEkQCBAO6tb4OipJzXLtDViXfvxwx88hGo6nkkiASEgr/jaVB9qee1855Gsb2GYtsIIjDiBJEAqqqyd+/e8KK/VPLa2e12amtrqa6uRggx8gSRELzO725GKP6U89oFOq0M7N4RXE6uBkacIBKC99Vz3bvwq4GU89q1+nrYYj/Mm/aDqKgjSxA5FKGUxartCJKxIKVMq8i6UUtZXO20UWgwppRpVSfLo5ayWGk+FVyYl0KmVbSaUUtZrLqrFPi7jAAADFNJREFUkXSFKWVaRdKNWsri9vZ20tPTU8q0qtFoRi1lsdJ0Ejk7N6VMq2i0o5ay+IinjXxtRkqZVnWS5kJSFkdiLIn+WBL9sST6iZGSkMYwhjEkxshHXmMYQ2zEHLAkGz+pqroUWAyUAIVAAOiSJKkJ2C1J0u5RPs7PhVsaa5DG8HkilpCEEHOFEA8At0qSlDAvthCiDdgMPCPL8gVP+n1e3GNCGsOoI14rJIQoEUI8IEnSD8+nXiHEYwRv6q7zsP1cuceENIZRR5xWaJkQ4jVJkiKiU7u6uqitraW3txeXy4UkSZjNZnJycqisrCQnJ2d4Pe3AalmWP071eOJxd/R5+bRFwTYgc6ZPBWDaOJk8k+DyEh2mNN3weuJyjwlpDKOO4UJSVfVrkiS9MHRbTU0NH3zwQfjFZfEwYcIErrvuOmbMiJxKEULcLMvy28mOJRb3p80DPLvfT1VLdJrkEEw6iWum6vnGJTrKxkUGL8fiHhPSGEYdQ4WkquoXJEl6P/Td6XTy8ssv09zcPKI6p06dyl133RWRYEUIsTRRyzScu6df4dFtHnadii+g4dBp4OuXGLn/cgNazbml/8O5x4Q0hlFHSEiqqpYBtZIkmQHa2tp48cUXcThSSz4zHLm5uaxZsybc3RNCnJYkaY4kSVHZRAe5qyVJsgA0dfv4zn97aOkNDC+aEhaV6vj1F00Y9ZqY3HJC6zGM4cLwQEhEDofjgkQEwcSTzz33XDhbkSRJE4EHEnBbAGz9Ab61xX3eIgLY0+znh+95CKgiJveYkMbwuUAIcbEkST8Iff/LX/5yQSIKwWazsWnTpqGbfq6qakSug+HcP3zPTdugM+FC8FGjj2erBmJyX/CE7B0b2/5ZkliSvOQ5CMGuN1YX/wxg2pRL/lkgjcheQuw6duKzn4W/D+mT37HxTOwMGTHw+qriqNRJ06ZekrL9seOfpZ566X8ZBl3NABw+fDjmOqgJEyZw9mz8/IB6vR6TyUTvYHhWCA0NDRw/fpxp08KZoB4AHo7Fve24L6ZTYXqehmNd8Vsok04iM02i3RkpwOeqBrh1toH89HAb9ADwsLayYrEEPFJTu/sXcWsFKisW/yPwZE3t7ohBlSSxUpZ4WBWklKNLlshV4ddAUAgSK0E8rKoiNXtZymWo/TBIEsnXZCeEdIH2YwCQJCmce/nDDz+M2j937lxWr15NY2MjL7zwAn5/5M1eWFjImjVrMJlM/PSnP8Xn80Xs37ZtW1hIg1xhIQ3lfmqPJ4r7hhl6fn5DOlUtfh56y4VXifQTTB2n4Y+3W8hMk7nyaTtu/7n9XkWwbp+Hf1lmjuDWAo8Aj1dWLJZranf/PNZFqaxY/E/Avw1+jRKcKvx1r68qi1rieturZ8fJcqA2sqwyFyL98xqNqDtx4kCUfVlZ5TitVl87rOxcNTDabxUcw2hCVdVwEojm5ma6uqLnMBsbG3E4HEyePJmvf/3rEWLKz89n7dq1mM1mTpw4ESUigNbWVqxWayhxf6aqqgtkWa4ayl3drtBsj251DrUpdPerLCjR8dQt6RFimpSrYf3KDLKNEntP+yNEFML7x3w8cpUJg1Y6x01QGP8C/KyyYvFPhxsNbvvZYJmErdZwvLl6Qvfrd140XlY0V0tC6peEFJ0qJgGammq6T5zYP14I+WoJqV8iub0QzE30l8w+oKpzE/2N5Pj/F2Nx6EO8bK1Op5N169ZFiEmn05Gfn883v/lNzGYzp06d4qWXXopLMqzuxcP+s+90bDd3u1Nl7evOCDEZtBKTcjVsuDMoov1nFP5+iyumvcsrONoRIdDF2pra3QA/r6xYnAY8WlmxmJra3Y9BWESPAv8ar7VKhttfPTtTyIF3VJVvSDKvMEJv+6RJl86UUd8RSN8A8Uqy8q+vKq5OtH/lpsTvhm1sPJDQftrUEWRK/d+LcM60WK1RCDabjXXr1vHNb36TyZMns2bNGvLy8sIiev7556O6fEMxrO7pw/7TaIs/BjplC7D2dSfr77CwoETHutstlOZowiJ68E1nVJdvKBq6FOYVhV0M08Ofamp3P1ZZsRiCYgqllAyJ6LG4NSbAqk2nywME3lFV1ryx+qIdd2xqHZH99EmXlKuyeEdI0poTJz7bMXXqJTHLpeJgiOVYCCEVB8PxE/vHHAspQpKk8II0lyv2Uz0Em83G+vXrWbt2LaWlpQApiShG3YXDuW39iT11Q8UUEkUqIgKwuyP2F0Z47QbF1M+5Ltw/1tTuTvwynjhY+XrLrIAqvS0GRQQgVLE41dXB06dfPEsN8DaDIgLQKPJiNNFPmTEHw//fkCQpwvMqy6MzKxM4j1gDzXkOvy/4iAf0hiWv31ka5SgQqrx0qIgA3lhd0hhVDu2ShoZoR4OqykuHigigoakqyn4Mf3sQQoTfYJ2enjjnRl5eHmvXrsVisdDc3IzT6aS0tJQ1a9agS5IgZVjd1uHc48yJb+/SbA3r77AwziyHHRDzirSsu90SciTERbYpYr81okUaMib6x8FNv6isWGxO1LUzeL33r3ytrYghYw9VVatev7P46YRHMghJBO6fOuWSoshtVB0/8VlK9mP4m8Sx0Ie8vPhLfvLy8rjvvvuwWCzh7lxWVhb33XdfWEwbNmyI6bWLUfexYf+ZlBM/E1Vptobn7gyKKNSdK8qUw928dbdbePBNZ0yvXch+KHdYssMcC08Odun+leCYKcqbF4Ik8RWEqEewD8E+wCNL0nVxzyCqAvEVCaleIO8TyPskJI+QR2A/hr9FhFeWTp06NWaBkGCGisjv99PV1cWf/vSncMv0ta99LW5Xb1jdu4f9Z+HE2C3aeIscJSKvIsJjplDL9PsvpSPHaJgMWon5RRFt0G65smJxaJ4oyrEw+Dkkpn8adEZEQaBseW1V8cbXVhVvVFV1Z8xCCSBr1S0nT1ZtPHmyaqOKGLH9GP62IEnS9tDnkpKSqDVFAEVFRVgsFhobG6McCyExORwOSktLY+beKyoqGvqS6T5ZlquGc8+ZoKUoM1qEMwu0jDPLVLX4oxwLITF1ulTmFelIi9HFu2GGfmjXr0+W5SotwW7cvwH/HMvFPeiAGBgsozLCuaS/NaQyl5QIY3NJySFJUkBV1b2SJC2UZZlly5YNj4+jrq6O3/zmN3HXI3V1dfHLX/4So9EYs2s3NPG/EOKFmNwSPLTIxD/9NdJzuP2kj1tf7ONUHPf4KVuAL27oIzNNiura6TRw74Jzr3cJcWuBJwEShQjV1O7+eWXFYjVUdjgCssHwdxuaDAADGlnHYIRsaNtQuGSDQaMOd0tqDUVFiw0AsvDoxKAHJ7QtEn5DMEfF+SHZPFMyJJtnGkMYDwOfQDAcaM+ePbS1tUUUSLaoz+/3x3SBT5o0afhCv2fica+Yruflg1qOWJWIAvFEFIJXEXS6osdHX5mXRklWxPjoGQDtYOxc0lYmgdDOatXAzgHzYPOrCoTE6wADZm3Uq/G0agAkaWt4g5DOBpTATpMxeGIimIzmdQCTcSDKPqAAEluHbx/D3xZkWd47tFVavXo1zzzzTNIXQydDRkYGq1evDn8XQjwuy/KxoWUiuCX47c3p3PWyg+4k80rJsKBEx0OLIhYWhrn/RyzsW7mpbU6yMolaosmTL05qH6sl+p9w7T4PDFnYNweokiRJD8GFfS+88EI4+eRIkZWVxb333kt+fjCdtBDCBsyRZblteNlB7k8lSTIAHO1Q+PZbrvMW07wiLb+92UK2UYrJ/T9CSGP428Kwpea3S5L0euh7b28vL730UsLlE7FQWlrKV77ylYhk/UKIFbIsx+2dDOfu7lf5/jsuDrUp8Uxi4o5KAz+82oxuSI9uOPeYkMYw6kgl+clnn33Gjh076OnpSVhXXl4ey5cvj3gTIIAQYpUsy5vimCXk3n7Sx/pPBzjakVhQV03W8+AVRqbnRc5HxeIeE9IYRh2x0nGpqnoDsEWSIt+r0tbWxtGjR3E6nXR2diLLMuPGjSMzM5NZs2YNdXEDIITolSRppSRJH6R6PPG4z/YpfHI6QH3nOUEZdRKzCzRcVqIl2xQloLjcY0Iaw6gjXoJIVVXLCeZSOK+3fgshnpAk6RlJkkb82sHPm3tMSGMYdaSQ73shwSXad0iSlOxNcH1CiNcHb+IDF3psnxf3mJDGMOoYyYvHBle0Lia4DKJckqSAEOIY0AbslmV5e8IKLgCjyf1/AfzC3EiJBPQWAAAAAElFTkSuQmCC) no-repeat}.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a,.layui-layer-btn a{vertical-align:top}.layui-layer-move{cursor:move;opacity:0;width:100%;height:100%;filter:alpha(opacity=0);z-index:2147483647;background-color:#fff;top:0;left:0}.layui-layer-resize{cursor:se-resize;width:15px;height:15px;position:absolute;bottom:0;right:0}.layui-layer{border-radius:2px;animation-duration:.3s;animation-fill-mode:both}@keyframes bounceIn{0%{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.layer-anim{animation-name:bounceIn}@keyframes zoomInDown{0%{opacity:0;animation-timing-function:ease-in-out;transform:scale(.1)translateY(-2000px)}60%{opacity:1;animation-timing-function:ease-out;transform:scale(.475)translateY(60px)}}.layer-anim-01{animation-name:zoomInDown}@keyframes fadeInUpBig{0%{opacity:0;transform:translateY(2000px)}to{opacity:1;transform:translateY(0)}}.layer-anim-02{animation-name:fadeInUpBig}@keyframes zoomInLeft{0%{opacity:0;animation-timing-function:ease-in-out;transform:scale(.1)translate(-2000px)}60%{opacity:1;animation-timing-function:ease-out;transform:scale(.475)translate(48px)}}.layer-anim-03{animation-name:zoomInLeft}@keyframes rollIn{0%{opacity:0;transform:translate(-100%)rotate(-120deg)}to{opacity:1;transform:translate(0)rotate(0)}}.layer-anim-04{animation-name:rollIn}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.layer-anim-05{animation-name:fadeIn}@keyframes shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-10px)}20%,40%,60%,80%{transform:translate(10px)}}.layer-anim-06{animation-name:shake}@keyframes bounceOut{to{opacity:0;transform:scale(.7)}30%{transform:scale(1.05)}0%{transform:scale(1)}}.layer-anim-close{animation-name:bounceOut;animation-duration:.2s}.layui-layer-title{color:#333;text-overflow:ellipsis;white-space:nowrap;background-color:#f8f8f8;border-bottom:1px solid #eee;border-radius:2px 2px 0 0;height:42px;padding:0 80px 0 20px;font-size:14px;line-height:42px;overflow:hidden}.layui-layer-setwin{font-size:0;line-height:initial;top:15px}.layui-layer-setwin a{_overflow:hidden;width:16px;height:16px;margin-left:10px;font-size:12px;position:relative}.layui-layer-setwin .layui-layer-min cite{cursor:pointer;_overflow:hidden;background-color:#2e2d3c;width:14px;height:2px;margin-top:-1px;position:absolute;top:50%;left:0}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2d93ca}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{cursor:pointer;background-position:0 -40px}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;pointer-events:auto;-webkit-user-select:none;user-select:none;padding:0 10px 12px}.layui-layer-btn a{color:#333;cursor:pointer;background-color:#f1f1f1;border:1px solid #dedede;border-radius:2px;height:28px;margin:0 6px;padding:0 15px;font-weight:400;line-height:28px;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{color:#fff;background-color:#2e8ded;border-color:#4898d5}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{word-break:break-all;padding:20px;font-size:14px;line-height:24px;position:relative;overflow:hidden auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{width:30px;height:30px;position:absolute;top:16px;left:15px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{box-shadow:none;border:6px solid #0000004d;border-radius:5px}.layui-layer-msg{min-width:180px;box-shadow:none;border:1px solid #d3d4d3}.layui-layer-hui{min-width:100px;filter:alpha(opacity=60);color:#fff;background-color:#0009;border:none}.layui-layer-hui .layui-layer-content{text-align:center;padding:12px 25px}.layui-layer-dialog .layui-layer-padding{text-align:left;padding:20px 20px 20px 55px}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-page .layui-layer-btn,.layui-layer-iframe .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{width:100%;display:block}.layui-layer-loading{box-shadow:none;background:0 0;border:none;border-radius:100%}.layui-layer-loading .layui-layer-content{background:url(data:image/gif;base64,R0lGODlhPAAYALMPAPPJp/HYxfSwkf50Df5TD/+HAPe5bvqHR/twOviZavyrMu/m3f9EAP9mAP+ZAO7u7iH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wUmlnaHRzPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvcmlnaHRzLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcFJpZ2h0czpNYXJrZWQ9IkZhbHNlIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6QUNDRERBRjMxRTIwNjgxMTg4QzZERjVGQ0I0MDI1NDkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTlDMEI5MzU5RTY2MTFFMTkxRDY5NkVCMDBGOTBFRUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTlDMEI5MzQ5RTY2MTFFMTkxRDY5NkVCMDBGOTBFRUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpENzU2N0YwMTMyMjA2ODExODhDNkRGNUZDQjQwMjU0OSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQ0NEREFGMzFFMjA2ODExODhDNkRGNUZDQjQwMjU0OSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAkFAA8ALAAAAAA8ABgAAATy8MlJq7046827/2AWCEdpCkGodkHSvHCcLGttLUOsw0NqW4EDYog4+CyInbJxwAQMiqjCcMQkGNgsNmFxLZXcisFBLpMNGYF2zRBQAt9vFWCuOwCXAJt9FMSXbhILdnY0FQd7a00SB39Kiw9jhGZoFQSJWgQTjksTCpNmChaYa5ucOxOgdaOkWaanMamqZRaXrZoSObAvA56zDqKHrQyQjbtME5KqlW/DRwbHDcwBv1UTV5hhEnDHVcqEzF2J2te75BLflBsCCFoIgRU4pwOGFQCfZQp4PxUBSX8IrPELscDLkhkDB7bQxQthwocQI0rMEAEAIfkECQUADwAsAAAAADwAGAAABOjwyUmrvTjrzbv/ILcAiWCUQKh+y9G88DsIa40JcQ4ji30JCIZQeAhcAgOdMvEYKZ5PQA8UHFoZtEpSuVQ4vmCHwuhJXK+EqcTA5YbfYrUmcD4jKNt2rAB/GzoHdWdTAXo6fXByGASCV1k4hjADiG8pG41XTA9skS98lGB/l5hDmgmdnqChHIykWBKQnZOqDpYaVaRkAKgvtA6KFwCudxO8DZ+UCh64grYPp7yqwBgLzFYEWRNIvAlecGMhAq1DCGQVu7JNBn7THQDvAObBeVwJ7T4gLW2i+P0PAQkOCBQoxZ/BgwgTYogAACH5BAkFAA8ALAAAAAA8ABgAAATV8MlJq7046827/2AojmMgHE2aIslCckAcb8Kg3umQvFhCMEAgYXcR4HCFpEJhCPAkiKAUiLAEbMdGwcHtcg28w3R8qKCyA6/aASABxvC2JJBNrdcuURQ+rUqMWVt3XmAhC3xweWdHg2oKIm+IU3KLOI1qkJKTEpU3l14iAZpSTg+dKp9cjyKjQRMGdYKXhSFio2VzdQ2ppSEBP5IEvQ9YR7J3tCICmgIVALrHhE+/cMIXCboDxwpy0z5BQ8POxUcD3U88CwnkKQni6E8yMXnw9fb3+BURACH5BAkFAA8ALAAAAAA8ABgAAATe8MlJq7046827/2AojqQUCEeaJkC5CUgcJ0G2JE2u60jrVgICY0gcIhaXQ25QaDp1vt8jUKwaLbhGwcHtcgeNQe23EFqrAkogt/W6cwlp4mwlICW4gXvvyI1LZnRFaRJgfHtghCRUglUIJjmHbgUNBy4AjY4SAGGSXpSWJZiZRI8PnHqeXKAujKQMpmsNqquVP4GZioa0iT8Hrwx/Sqmefj8BuHRxE5xanmChPwKZRxVKznxgDX8/AAh00RQL18S1YYpSDzffpVEXAjvxB9zpiwnaOQfo9fz9/v8ApUQAACH5BAkFAA8ALAAAAAA8ABgAAATO8MlJq7046827/2AojmS1AIkhJEBQasFBMDRDHC62JE3v97iXJVEr1hKThUHBdBQGv99gIZwIjFiG4AFweL/eQtSHqD4Cs2yR0AW7xeOGoXpQYwvuPHQ8FabtNA15g3ENWyUBgEUDg3mFBy8AijV4jWB7UZAlkpMMlZZemD+aJImdjKBej0KdDIKpDoWHJXWdn42iPzmIrQagcGOkL0SKSG15wFF9ZgJ/WLMBvpeFCLtmMVhBOjxxB1RmJgDiAN8bAQkH6Qcs4O3u7/Dx4BEAIfkECQUADwAsAAAAADwAGAAABMrwyUmrvTjrzbv/YCiOV5AgKCosZIsFCCPPc5KZQ6M3QxK4lgWBRuMVFEgDS5LYOXc24CRGlBUc2CwW8BA8vw2BtFuVDbRoByAHdg6WrmG1kU63v9EWoMy41rVsdzoDQAllBH9oBYJOPy2GVYiJWYuMOlyPh5OUlpcuApqbDpWWjiQBfH6TgYxSVER0m50NeS2gZap1BrOmLpBVuVpcTYy1QLdzuQamAqxuYmMTMGUJcBYmeL3REgAJ3gkC2hgLAOUA1tvp6uvs7R8RACH5BAkFAA8ALAAAAAA8ABgAAATs8MlJq7046827/2AojpmQICgqBGSLCQgjz3OyZEFy7LvgXoDZoEAsDBoyxGWRaDifzgHgNwkQGA2HdqstyBKWA3TsZFEPDAJ37RjIzBIBmTy4uQKyAnuNPEwWR3NjPi4CWHtrXgQTcoJjAz8xA4hrbxJijmNwIzF6lFtXUw+YmU+iJJ2foAyipKUNp5wMk6oOV2aupZsihlmqioyvUT94DJ6USEoSAcINYJGHlF6sFE2lA7sjxQ3HXNN+FAu5ZIRUAlcEtF1IDAh2FQaC2FQUATE0NOVACYENAyv0LMCgQeBAtoAIEypcyLDhhAgAIfkECQUADwAsAAAAADwAGAAABODwyUmrvTjrzbv/YCiOWiAgTJoiSUC+V0KodEokZWIIugtPAYNCUSgMZjWV4BI4NJ7QxsH3Mjiu2OsgqaJKFoOoeLB4AbJoR4PLQFQQ4rh7tEin2QyqIM5fiqx2WVtcfg9hfGMjCoFZBWxzC4h8Xh6MaI8SAJJxACKWWZgPmptRnSGLn45ccwGkUWUhgJaDSTgSh6QDIwGfDkhJeq4Ntn+zbAQUYLmwI7Joa2ymQLhxA5QiAKhXBdBcBxcLcHEHzD+Zv0kEhRcACQfvCdLmFAEytdfzZgD7AOX5/wADCrwQAQAh+QQJBQAPACwAAAAAPAAYAAAE6fDJSau9OOvNu/8gFiQkKSxh+gkE474uEqj0tSBw/gq1twCKYBCAOuiOhJllkRg0no0BDxRQOK5YhyJx7BIsAKj4ifgsrNlsodtNUBbOsdjgMaTvA7buOznI5UoaC3eELXowSgF/cm4bAIR3DYcwUwKLYwMcdpBZkpMujQaXY5qcnZ+gEgmjYhyPpleen42WrFEcg7AOqC4AEoq2Bx1onGu8FAi2vriwvAzCE2Gj0B1VhApGqEkVAnFyByhmm1gGKDifUxULfmN0PerZbATLGD8A9+8ZLF0y+f4PAhAIFJgg0L+DCBMqrBABACH5BAkFAA8ALAAAAAA8ABgAAATz8MlJq7046827/2AWCEhpCkGodkHCvHCcpGtdBUSswwRt3waFUGHwVRC7JAOBaR2eh9nG4KhaqwaLS5lMaBvgMNiLAVzPDgAlwOUaBeJ4Q3BZoNGLiaCtpEsWcnJGElR3V1kSSHw7TBIJgXFkFAqGVwoTi0oTA5BiAxaVZ5iZOxOdcaChVqOkMaanYRaUqpcSOa0vBJuwDZ8VhaGID4q4jQ+PsJITAaoOPlu4kgG8g4TBa7gvRsiQyr+GwhMHuAcWBpDhFwCzVQpqFgu3iwR5FgAHYgfvP2vEXAj7+K1YMI7LgXoCf7SQx4CAlIQQI0qcmCECACH5BAkFAA8ALAAAAAA8ABgAAATe8MlJq7046827/2AXACQZnuCSEEzrEkmAzpjAunhLCDRmKI5g0LC4BHJIl+wRSByeh1hKSBUWKYtbMkdQNb7gb+IDrFIVlcR2iwi7GzwOwGwGTI7r5Pu91NDpEwJ5SAR7bmMaC39mVweDOYZuAxsBi1VLCI84kW6UllSYmi6cYZ6fQaGiDKRfkxunQRNqqoWkiBoGpwaBqi2sfRmKn1cPWb21hreUZWYKwA+zogkGhrsguVVEF5maCBIAB2EHdicLAecBxBYL3HkI6j0zgmvK8T1NWgwwz/b9/v8AMUQAACH5BAkFAA8ALAAAAAA8ABgAAATY8MlJq7046827/+AXACQQhCi4CATjvoSwpFww2nMWtG/vEieaZQFwGI8ORbCy4Pl6hMZhmlimFMiswypBPKGNsDicoBm02pxE8IWN3w0BaoHWGijOLxzO5RTrWRMBbT97b2UgWIBIQQmEDIZvAyGKi0aNj5FvlJZHmISaYyFnnVtrmaENkyCknRMAj1GhiB90nXcTeU+pfRytgGoPjoSyhrQqlWgATLo+xW+4NH9ZCsGCzT5vB8tCEkQG4Aa9EwtehAjW3TQLCdgJ6erdAgn0CXLx+Pn6+xwRACH5BAkFAA8ALAAAAAA8ABgAAATM8MlJq7046827/2AojuSzCAeiqsJSaoChzIoBaALB7DyfvJaAwkEsEhWBS6LHIDQaTt0PKFkMjViFiwLoOZ/gJ0FAfVyx2Ypu9w2HB9QAeu5ISgQ9t75BfhnoaAYTCDxte08HQIBzE2sMh25wL4toE3mQYYqURpY8mJmTm0WdO59gQH+ighKEbKaJLwCiDjd3l5h9L2eAChQBjoZ7di9ylMMSS4WHBFNUVnRaSkx6DM1lDwC7CgBbFwCOTAy51yQLCeDM3eTr7O3u7yMRACH5BAkFAA8ALAAAAAA8ABgAAATO8MlJq7046827/2AojiQVCEmaCEGpLYbizI5iLFlwMHzPHy1XJSCjGRVBU6JBYDZ8PEJSuCgaj7jJssHtMqGIrKt6LdeyAq/660sIHwaz2fBYrNdQxnRkldMUD1t3XQRQAi4BfmYBA4NqYIiKZQGOjz4IkZJGlJVdkCULmkYLjZ1Pl0KiNIGmhT6HLnGidJyVeXsioaJZgneuPZhviZJicIO/UcVjfVgWAAeWl7hjskY3GQsIeTxhbxcLAeEByhjPCOcIBwDe7O3u7/DxEhEAIfkECQUADwAsAAAAADwAGAAABMHwyUmrvTjrzbv/YCiOWGACgbcALEpygeHMtGNoAsLsPCG8GEBt6FAAEofkIRE48J68A7ASIBILjay2QYB6f9PHQmElDrbarveZmsrKRLR2/USE4dazXE1ntElVeENYcg19O2CAgoOFhocJQIGLM4RyhwyQL5KTlWiXiSSTNHpofHR/JG+TjZcEYQuinWmfYQ9CgrJZpmtStQ+bRAYAB1sHAAKHoLUxVjcZOV4+vhYxBtYACx0CCdwJytPg4eLj5B8RACH5BAkFAA8ALAAAAAA8ABgAAATI8MlJq7046827/2AojtgCGKgBLGSbLYojz7LClgnC7AyS3C7KgkacJQKWAIHHZBCQQQmsSG0khMsmkwB0GajUQkMg1WmbiO5oCKYOGsjE+Xz1tt3WR3a+DX7vRGIDAXxnUCQxgDRiDQCFWgAuiYoyjI6PTJEtk5SChJg8hyMAlDNvV3uPBEFspQ1wD3KgdZKlYnULqXNcUa2ADQYUn3xPURIBnFQHmkJmWmnGE1NUNi+yTD/RFQEGCt4KBqIvAOQr2ufo6errIhEAIfkECQUADwAsAAAAADwAGAAABLTwyUmrvTjrzbv/YCiO2QIYSqoYxkK+GODMdG1owoHsyCHAF0NtSLtZAgiGcqlEBIATGXEKqCwIzCyD4IIqplNFJanNIqBSMLEqAZTL7NdXTRRLDm/tAUgHT7B5TAR8fUQTgVqEhTWHiEyKizN/jkqDMHORdg9kjmcwaYtxApQMPzALkTNdEpx5nkBCi0YTAYgEcbCFsxQLrUwIq1APAXS4Fjm/AsHCDwsoQy3M0tPU1dbXGBEAIfkECQUADwAsAAAAADwAGAAABNbwyUmrvTjrzbv/4BWMZGiCC+CsrKMYyyljQWuvSqAFQA/os0kgcSjejoqYRYBgOJ8EQDDRqDYKR6Ql8ew+EzKBtTHIZqUTgHfNQKPGDXNWQWmyuwgTdSzPAgN3a0AfA2NYfTcGEgKBXgIhcIeILYoPXI1fkIaTNpWXmAxgIIVWZZwsaIygDI8ge1Wmpw5/qwyDHgFwsisUBKAEJ69XspUSapitJgabk0kVB40HQQAHsJy3ab5eUUEWCwpyzhkCCeUJbt0VCwZZMOnvxgbyBujw9vf4+RcRACH5BAUFAA8ALAAAAAA8ABgAAATi8MlJq7046827/2AWjGRogovirKyjAMspY0Zrr0owe0Fy/IeE7gG4GRWxS4LAaDIIiaQn0ahaq0KjVmEJMJ1gwpAjuJob2jSgggC7GYjO4nwdpLcUwfst4FDpVQV3WlJfe04EHAOAVYNaaw8Bh29jGIyNjjcGEgCTbpAZl2iZNptEnmCgGIuMpKUSkqhNlUqXgq4roIaTiRsBtrgrUgmyCR1/dHa4XBMLu28EUhsGgAYqrrReh2IgAAdXB2sLrqYWS24H0juR13flFwsA8jDr8DVq9fkB9ywKBur5AgocSPBCBAA7) no-repeat;width:60px;height:24px}.layui-layer-loading .layui-layer-loading1{background:url(data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=) no-repeat;width:37px;height:37px}.layui-layer-loading .layui-layer-loading2,.layui-layer-ico16{background:url(data:image/gif;base64,R0lGODlhIAAgALMAAP///7Ozs/v7+9bW1uHh4fLy8rq6uoGBgTQ0NAEBARsbG8TExJeXl/39/VRUVAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBQAAACwAAAAAIAAgAAAE5xDISSlLrOrNp0pKNRCdFhxVolJLEJQUoSgOpSYT4RowNSsvyW1icA16k8MMMRkCBjskBTFDAZyuAEkqCfxIQ2hgQRFvAQEEIjNxVDW6XNE4YagRjuBCwe60smQUDnd4Rz1ZAQZnFAGDd0hihh12CEE9kjAEVlycXIg7BAsMB6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YEvpJivxNaGmLHT0VnOgGYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ/V/nmOM82XiHQjYKhKP1oZmADdEAAAh+QQFBQAAACwAAAAAGAAXAAAEchDISasKNeuJFKoHs4mUYlJIkmjIV54Soypsa0wmLSnqoTEtBw52mG0AjhYpBxioEqRNy8V0qFzNw+GGwlJki4lBqx1IBgjMkRIghwjrzcDti2/Gh7D9qN774wQGAYOEfwCChIV/gYmDho+QkZKTR3p7EQAh+QQFBQAAACwBAAAAHQAOAAAEchDISWdANesNHHJZwE2DUSEo5SjKKB2HOKGYFLD1CB/DnEoIlkti2PlyuKGEATMBaAACSyGbEDYD4zN1YIEmh0SCQQgYehNmTNNaKsQJXmBuuEYPi9ECAU/UFnNzeUp9VBQEBoFOLmFxWHNoQw6RWEocEQAh+QQFBQAAACwHAAAAGQARAAAEaRDICdZZNOvNDsvfBhBDdpwZgohBgE3nQaki0AYEjEqOGmqDlkEnAzBUjhrA0CoBYhLVSkm4SaAAWkahCFAWTU0A4RxzFWJnzXFWJJWb9pTihRu5dvghl+/7NQmBggo/fYKHCX8AiAmEEQAh+QQFBQAAACwOAAAAEgAYAAAEZXCwAaq9ODAMDOUAI17McYDhWA3mCYpb1RooXBktmsbt944BU6zCQCBQiwPB4jAihiCK86irTB20qvWp7Xq/FYV4TNWNz4oqWoEIgL0HX/eQSLi69boCikTkE2VVDAp5d1p0CW4RACH5BAUFAAAALA4AAAASAB4AAASAkBgCqr3YBIMXvkEIMsxXhcFFpiZqBaTXisBClibgAnd+ijYGq2I4HAamwXBgNHJ8BEbzgPNNjz7LwpnFDLvgLGJMdnw/5DRCrHaE3xbKm6FQwOt1xDnpwCvcJgcJMgEIeCYOCQlrF4YmBIoJVV2CCXZvCooHbwGRcAiKcmFUJhEAIfkEBQUAAAAsDwABABEAHwAABHsQyAkGoRivELInnOFlBjeM1BCiFBdcbMUtKQdTN0CUJru5NJQrYMh5VIFTTKJcOj2HqJQRhEqvqGuU+uw6AwgEwxkOO55lxIihoDjKY8pBoThPxmpAYi+hKzoeewkTdHkZghMIdCOIhIuHfBMOjxiNLR4KCW1ODAlxSxEAIfkEBQUAAAAsCAAOABgAEgAABGwQyEkrCDgbYvvMoOF5ILaNaIoGKroch9hacD3MFMHUBzMHiBtgwJMBFolDB4GoGGBCACKRcAAUWAmzOWJQExysQsJgWj0KqvKalTiYPhp1LBFTtp10Is6mT5gdVFx1bRN8FTsVCAqDOB9+KhEAIfkEBQUAAAAsAgASAB0ADgAABHgQyEmrBePS4bQdQZBdR5IcHmWEgUFQgWKaKbWwwSIhc4LonsXhBSCsQoOSScGQDJiWwOHQnAxWBIYJNXEoFCiEWDI9jCzESey7GwMM5doEwW4jJoypQQ743u1WcTV0CgFzbhJ5XClfHYd/EwZnHoYVDgiOfHKQNREAIfkEBQUAAAAsAAAPABkAEQAABGeQqUQruDjrW3vaYCZ5X2ie6EkcKaooTAsi7ytnTq046BBsNcTvItz4AotMwKZBIC6H6CVAJaCcT0CUBTgaTg5nTCu9GKiDEMPJg5YBBOpwlnVzLwtqyKnZagZWahoMB2M3GgsHSRsRACH5BAUFAAAALAEACAARABgAAARcMKR0gL34npkUyyCAcAmyhBijkGi2UW02VHFt33iu7yiDIDaD4/erEYGDlu/nuBAOJ9Dvc2EcDgFAYIuaXS3bbOh6MIC5IAP5Eh5fk2exC4tpgwZyiyFgvhEMBBEAIfkEBQUAAAAsAAACAA4AHQAABHMQyAnYoViSlFDGXBJ808Ep5KRwV8qEg+pRCOeoioKMwJK0Ekcu54h9AoghKgXIMZgAApQZcCCu2Ax2O6NUud2pmJcyHA4L0uDM/ljYDCnGfGakJQE5YH0wUBYBAUYfBIFkHwaBgxkDgX5lgXpHAXcpBIsRADs=) no-repeat;width:32px;height:32px}.layui-layer-tips{box-shadow:none;background:0 0;border:none}.layui-layer-tips .layui-layer-content{_float:left;color:#fff;background-color:#000;border-radius:2px;min-width:12px;padding:5px 10px;font-size:12px;line-height:22px;position:relative;box-shadow:1px 1px 3px #0003}.layui-layer-tips .layui-layer-close{top:-1px;right:-2px}.layui-layer-tips i.layui-layer-TipsT,.layui-layer-tips i.layui-layer-TipsB{border-right-style:solid;border-right-color:#000;left:5px}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsR,.layui-layer-tips i.layui-layer-TipsL{border-bottom-style:solid;border-bottom-color:#000;top:1px}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{color:#fff;background:#4476a7;border:none}.layui-layer-lan .layui-layer-btn{text-align:right;border-top:1px solid #e9e7e7;padding:10px}.layui-layer-lan .layui-layer-btn a{background:#bbb5b5;border:none}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#c9c5c5}.layui-layer-molv .layui-layer-title{color:#fff;background:#009f95;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92b8b1}.layui-layer-iconext{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAABkCAYAAAAv8xodAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNS8xMS8xNNdPc0oAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAWb0lEQVR4nO2de2wU172Av5l92t4Hti/YQHmVmFcSE7+WR0h0uRRVVC2pKldpCFJQEJAiFwg4diikgLEghEhpVLVQNblBSFEUVYoi+hc0FQoE87B52JQAiQnBJDY2wfix633O7P1jdwbbxe9d7yx3PgnJc87iM2M+js+cx+8nhMNhdHQeFcRE34COTizRhdZ5pNCF1nmk0IXWeaQwPqxQEIRYtpEKOABL9NoLtAKhWDbSDRF4EsgAbEBHtL3LAIN9CV6+fHlSvS0fOXLkof9oj8pzDJZ499A2YCxgWbJkiSUnJ8cApADZgCEO7ZmAImAyYFuxYsV4Iv+ZpgIFcWhPR2PEU2gbkAlQU1Mz67PPPvvvq1ev/s/f/va3LCIyp8e4PROQD4wrLi7Oam9vP/Dhhx/+9f79+3/Kz8+3AxPi0KaOxoiX0KrM169ff6KgoGAKgMFgEF944YWZ0c9Y+vrLw8BEpAceV1xcnHX48OE3HQ7HRIAxY8ZM2bdv39Lo5zJi2KaOBomH0D1knjFjxsTulX6/Pxj9Uo5Re4rMY1esWDH+8OHDb6akpGR2/4Db7fZEv4zXuF1HI8Ra6H5lDgQC0ttvv/1l9NIfg/Z6yPzee+/t6S1zY2PjpdWrV/8retkagzZ1NEwshR5Q5j179pzfu3dvOxBg5HINKHNTU1Ody+WqbG1tDQENQOcI29TROA+dthsGGYAd+pd5165d94nIfHeE7Q1K5qKioorvv/8+ANwGakfYZlwIh8MEg0F1OtFoNGIwxGMCKL4Eg0G6urqQJAlRFElNTcVsNo/6fcSih84A7BaLRRiCzCMZy5qAQoYm86URtBc3FJnNZjMzZswgKyuLQCCAJEmJvrUhEQwGcbvdZGdn88ILL5CTk0NnZ2dCnmOkPbQqc11d3eMPk3n37t01lZWVbcRW5v966aWXJh44cKAyWWWWZZlgMIjD4aCoqIj09HRkWeb48eO0tbUlTS+tyDxz5kz2799Peno6LS0trFq1Cr/fT2pq6qjez0iE1mUeJorM6enpFBUVkZaWRigUIhgMEgwGB/4GGiEQCOB2u5kzZw779u0jPT0yze/xeJAkKdYrzoNiuELrMg8TSZIIBoNkZWVRWFiI2WwmHA7j8/k4d+4cnZ2dCRl7DhWlZ37iiSd46623cDgcANy5c4c33ngDj8eD0+kc9fsajtC6zMMkGAwiSRKTJk0iLy9PHVZ4PB7Onj1LR0cHZrMZUdT2njGlZ87Ly2P//v1YrVYAmpqaKC0tpaGhAbvdnpBh01CFHm2ZzURmMx4ZmadNm0Zubi6iKCIIAm1tbZw5cwav14vJZNK8zH6/H7fbTWFhIXv27Okh85YtW7h9+zY2mw2TyZSQ+xuK0KrMly9ffiInJ2dC98pEyNzY2HjJ5XJVJoPMoVCI2bNnM2vWLCCyo/Hu3bucPXuWUCiE2WxOyJhzKCgyL1y4kMrKSiyWyO6Fb7/9li1bttDS0pJQmWHwQidU5oMHD+6xWq09NhYlg8zKtJwsy+Tm5vLYY48RDocRRZGmpiaqq6uRZRmTyaR5mX0+Hx6Ph2eeeYbdu3er0jY0NFBaWqoJmWFwQg8kc2j37t3ndZl70l3mvLw8pk6dSjgcxmAw8O2333LhwgVEUUyKF0C/36/KXFFRoUpbX19PaWkp9+7dw263YzTGap1u+Ax0B7rMwyAcDhMIBDAajbhcLsaPH48sy4iiyNdff01tbS1GozHhvdlgUHrmpUuXsmPHDvU3ybVr1ygtLaW9vV0zMkP/QusyDwNljtlsNlNUVMS4ceNUma9evcrVq1eTSma3282yZcvYvn27KvP169cpKyujo6NDUzJD30Kn8UDmJ3NycsZ3r4yDzABzeURkTklJweVykZGRQTgcRhAEamtr+eabbzCZTJoSoC+UnvnnP/85W7duVWWuq6ujtLQUn8+XsKm5/ujrJ2sDuHDhwpxRktkJZC9evDg92WV2OBy4XC5sNhuyLCPLMpcuXaKhoQGj0ZgUMnu9XtxuN7/61a947bXX1PLa2lrKy8s1KzP0LbR18uTJ4uzZs3vMM0uSJMdBZohuOy0rK1vUW+bm5uZ/a11mgFAohM1mY8GCBaSmpiJJEj6fj9raWpqbmzGZTJoUoDfBYBCPx/MfMl+8eJGtW7fS1dWlWZmhn912zc3N4WCvjQUGg0H85S9/mR29NEf/xAIvQGNj43/skU5PT//xypUrp0YvHUQO2WoOWZZxOp04HA4kScJgMNDS0sKdO3cQRVGzAvQmGAwyZswY1q5dq5bduHGD9evX4/F4cDgcmn6WvoTu8vv94YMHD16WJKnHUamCgoIpNTU1s6KXY4mEKRgprQAlJSWn6+vrP+9eYTabUysqKirKy8tnEBmaFKFBqUVR5M6dO9y+fRuj0YgkSUyePJk5c+aoG4+SAYPBgMfj4cqVK2rZhAkT+NnPfoYsywQCgQTe3cD0JXQrENq4ceMPf/7zny+OgtR+4JbX65Vzc3PfSUapTSYTsixz7tw5Ghoa1F5s5syZ5Ofnq2NsraM8x86dO6mpqQEgJSWF7du3s3z5ctxuN16vN8F32Td9CS0BzYyu1HUksdSCIKiLJDU1Ndy4cQODwUA4HGbatGkUFhYC9DidokVEUcThcODz+Xj99deprq4GIs9XXl5OcXExbrebrq6uBN/pw+lvJ0wIXeoho2wwunTpEteuXUMURWRZZtKkSbhcLkRR1LzUBoMBu91OIBDg97//PefOnVPrNm/ezPPPP4/H49Gk1ANt7dKlHgbKXPOVK1e4fPkygiAgyzLZ2dksXLgQq9WaFFI7HA78fj9btmzhxIkTat2mTZt48cUXNSn1YPYq6lIPA5PJhMlk4uuvv+bChQuqvJmZmcyfP5/U1FQCgQCyHKvwJLFHGX4IgsCOHTt6SF1SUsKqVavweDx4PJ5+vsvoMtjNt7rUw0BZ4r516xbV1dWEQiHC4TBOp5OFCxfidDrVDUxaRZFalmXeeOMNjh8/rtatW7eOl19+ma6uLs1IPZTd5LrUw8BgMGAymWhsbOTs2bP4/ZH4OmlpaSxcuJCxY8eqm/+1iiiK2O12ALZv386xY8fUujVr1rBu3To8Hg9utztRt6gy1OMRutTDwGAwYDabaWlpoaqqSh13WiwWXC4X2dnZSSO10Whk9+7dHD16VK1btWoVJSUlmuiph3PeR5d6GCh7n9vb2zl16hSdnZ0IgoDRaKSoqIgpU6aoJ1u0ijL8EEWRHTt2cOTIEbVu5cqVbNiwIeE99XAPsOlSDwNRFDGZTHg8Hqqqqrh37x6CIGAwGMjPz2f69OlIkqRpqQVBwG63Y7Va2bt3L59++qlat2LFCkpLS+nq6kqY1CM5kalLPQyUntrn81FVVUVzc7N6MDY3N1cNOKNllOGHxWJh3759fPLJJ2pdcXExr776Kj6fLyHL5CM9YqxLPQwEQVCXmM+cOUNDQwMQ2bap5d65O0pPrUj90UcfqXW/+MUvyMjISMizxOLMvC71MFCkFgSB6upqTp06xcmTJ+no6EiKPdPwQOqUlBTeffddDh48yHfffcfHH39MW1tbQk7lxCoIxHCkHmkE/6FKnTvC9uKCsgBz7949fD5fUgSa6Y4gCDgcDiwWC4cOHWLdunUcOHAAs9mc1ELDIKU+fvz4tOilPQZtDkrq4uLiLGAcGk1JocxVJ0Ogmb5wOp2MGzcOg8FAdnY2NpstIfcR65/egFIXFRVNjn4ZqxwrA0q9fv36Z6KXmhRaJ3bEozvoV+qOjg5l5j2Wm4P7lbq+vv776JeJX8rSiSvxevtQpM7auHHjD62trTWrV6+e5vP5gqWlpV9HPxOLHCvdqQPwer1TcnNz3zly5MjN3Nxc16VLl86sXbv2dLQ9PcfKI47wsC2MMQxLZSTyAtj77KEXaIlVI73IBaY8pPwk0KZnktU2I80kG+/5oRDQRORwq5VIKjcf8f3VX0fkdHg2kTFza/Qe2uLYpo5GiHcPrTm0vKleZ+T010ObiaQStkavfUR6uViPfbujJJ13EOnFlaTzo74W/Kj8qn5UnmOw9DXLYQbGA9a8vDxTXl6eiYjY2TwQPNYUEEky74gmnbcRSUJfRCSKv47OgPQl9BiAo0ePTjl//vzi8+fPL/7nP/+pLIhkEXup04EJ+fn59vv37//pww8//Gt7e/uBbgsi+ehS6wyCvoROcTqdwpIlS2YIUX7yk5/M+Pzzz6dH62MtdQbAvn37lo4ZM2YKgMPhmHj48OE3dal1hkKfCys+nw9Jknpsl3r22Wcfi5PUIeiRZB6AlJSUzF5SF6BLrdMP/YYC++CDD/4d7jUt8Oyzzz526tSpx6KXsZK6FWD16tX/amxs7BGMUZE6Oq4eiy61Tj/0FwpMeuWVV+6+//77tb2lXrhw4fQYS90JNLS2toZcLldlU1NTXffKlJSUzPfee2+PLrXOQAwUCkxas2ZN8/vvv1/be5NRHKSuBW5///33gaKioopklFqSJPx+P36/n0AgkLRz3oFAgLa2NlpbW2lvb0+KmHwK/W1OCtJN6g8++KBuEFKPdBP9JZJUakmSCAQCZGVlkZOTg8lk0nx0pIchSRJut5ucnBx+85vfkJWVhdvtThqpB9ptFwTuMHipxzH6UheiAaklSSIzM5Onn36auXPnsmjRIjU+nNbPCHbH7/fjdDrZu3cvJSUlHDhwgJycnKSRerChwAaUuqqqKid6OWpSv/TSSxOB/0IjUgeDQfx+P6FQCKfTyfz580lPT9d8dKTuCIKAJElq7JDMzEz279/PrFmz6OzsTNr40L0ZUOoFCxb8eLSlPnDgQKVWpDYajbjdbk6fPo3f7yccDpOamsqCBQsYN24cgUBA04FkFMxmM263mz/84Q+0tEQ2RGZmZvL222/z+OOPa76nHmooMF3qPlBibrS2tlJVVaVGEDKbzcybN48f/ehHBINBTcsAD0Lp3rx5k82bN9Pc3AxEjli9++67PPXUU5ruqYcTCiyhUj9snlprUnd0dPDFF1/Q0dGhBpIpKChg6tSpSJKkealNJhM2m41bt26xefNm7ty5A4DVauXNN98kPz8ft9utxunTEsMNBZYwqV0uV+UgpU5IzmFFap/PxxdffMEPP/yAIAgIgsBTTz3FzJkzkyLniiJ1Q0MDJSUl3Lp1CwCbzcZbb73FvHnz8Hg8mpN6JKHAtC51AQmSWom5EQwGOX36tJoJC2DOnDk8+eSThEIhzc9VK1I3Nzfz2muvcfv2bQA1DNjTTz+N2+3G5/Ml+E4fMNJQYANKfe7cuVGV+uDBg3u0IrXZbEaWZU6fPq0mEgqHw+Tk5JCXl6cmEtK61Ha7naamJjZu3Mg333wDRN4NKioqWLRokaZ66liEAutX6qKiolGV2mq1pmtFaniQc6Wmpob6+no1PcW0adOYN28eoihqvqc2Go3Y7Xbu3r3Lpk2buH79OhAJB7x3716WLFmimZ46VqHAdKn7Qcki2z2RUDgcZuLEicybNw+z2az5BRhF6ra2NsrKyvjqq6+AyDvDrl27+OlPf4rH40m41LEMBTZUqUcaaGaoUs8dYXsjQomMdPXqVerq6hAEgXA4TFZWFvPnz1cTCSWD1Pfv3+d3v/sdly9fBiLDq+3bt7Ns2bKESx3rUGADSt0tFJgjBm32kPq777670L1SkXrx4sXpRI6POWPQ5rBRktffuHGDCxcuIEkSsiyTkZHBokWLcDgcmpdamaf2er2UlZVRVxdZGhBFkW3btiU8OWc8QoH1kLr3B+bNm6fEzIhVKDBV6vnz5+9pbm7+d/dKq9WaXlZWtih6mRmjNoeNkkiooaGB6upqvF4vsixjt9uZP38+NptN8yF1Fak9Hg/l5eXU1tYCkZ66rKyM5557Do/Hk5CpyXiEAnMABovFIixZsiS7d6XX61Veh2O1DpwSbZOVK1dOTU9P/3HvDzQ2NioRkzSR09dgMCCKIk1NTbS0tGAwGJAkCafTidPp1HQPraDkMXS73fz2t7/lxo0bQETqdevWqRm+RptYC50B2C0Wi3D16tXcadOm9RA6EAgEKysrlazosRhopRA5Fe4sLy+fUVFRUWE2m3vEnq6vr/+8pKTkdPRSE6HAlFwqc+bMYfLkyUiShNFo5Pbt2zQ1NSVNBFLlRXbZsmVMmDBBLf/yyy/p6upS852PJrGMnDSgzK+//nrNO++800Ektsf9EbY3KJlzc3Pf8Xq9MnCL+MYUGRTKGDk/P5+pU6ciyzIGg4GGhgY1QWci4ioPFa/Xi8fj4bnnnqOsrEwNTlRTU8POnTuRZTkhzxEroYcq890Rtjccmf9jPD+ahMNhdWxcWFjIpEmTVJlv3LhBXV2dmn9F6yjp237961+zefNmtby6upqtW7cSCATUbFmjTSyEzgRsQ5R5JOPnpJQ5GAxiMBgoLCxk/PjxyLKMKIpcu3aNK1euqC+LWkeR+fnnn2fTpk1q+blz59i2bRuBQAC73Z6Q4QaMXOhMwOZ0OoWLFy/qMj8ERWar1UpRUREZGRnIsowgCFy+fJmvvvoq6WR+8cUXKSkpUctPnDjBtm3b1PQUiXwHGInQuswDoOzVSEtLw+VyMWbMGMLhMOFwmIsXL3Lr1i1MJlNSJAnyeDx0dXWxatUq1q1bp5afOHGCHTt2aEJmGL7QuswDoMjsdDpxuVykpaWp4+jz58/T2NioLolrHUXml19+mTVr1qjlx48fZ+fOnQCakBmGJ7Qu8wAo2WDHjh1LYWEhFktkDcnv91NTU0NLS0vSyOx2u+nq6uKVV15h1apVavmxY8fYtWuXuhyuBZlh6ELrMg+AciJl/PjxFBQUqGPjrq4uzp49S1tbW9KkblN65pKSElauXKmWHz16lMrKSs3JDEMTWpd5AEKhEKFQiClTpjB37lxEUUQQBDo6Ojhz5gwejydpZFZ65g0bNrBixQq1/MiRI+zZsweLxYLD4dBccPzBCq3LPAChUAhJkpg+fTq5uQ9yfN67d0/ds5EseQgVmUtLSykuLlbLP/30U/bt24fVasVms2lOZhic0LrMg0CWZdLT01WZlb0a1dXVSJKE2WzWpAC9CQQC+P1+Xn311R4yf/LJJ+zfvx+LxYLdbtfsswwktC7zEAiFQni9XlJSUmhoaOD8+fM9cnonA6FQiIyMDJYvX66WffTRR/zxj38kJSVF0zJD/0LrMg8Bo9FIZ2cnJ0+eJC0tTd1FlwwLJt0xmUy0tbXx8ccfs3TpUv7xj39w6NChpJAZ+hY6jdGVGSL5BZNSZugZvsDn8yXNtFxvlJM1f/nLX/j73/9Oa2ur+gKYDPQltA2gqqpqzijJnAGMKy4uzkpGmRVEUUyKl76BsNlsavL5sWPHJvhuhkZfP32r0+kUZs+ePbF7YZxkhmiOlfXr1z+TrDLraIO+hA62t7eHOzo6upSCOMoM0cyy3ZLME73WZdYZEn0J7QcoLy+/ePPmzeabN2/e2bBhw9k4yQyRkyT+tWvXnj527Nj/trS0fPnZZ58d0mXWGSp9pUYWiIQa6J1mwgf8QGxlVhgDPPOQ8pjKrCev1zbxSl4fJpKOwsGD09l+oGMkjQ1AG3CSSAZbJen8HUZ+VEvn/xEP7aF1dJKV5J9j0tHphi60ziOFLrTOI4UutM4jhS60ziPF/wHgvbfirVNMHAAAAABJRU5ErkJggg==) no-repeat}.layui-layer-prompt .layui-layer-input{color:#333;border:1px solid #ccc;width:220px;height:30px;margin:0 auto;padding:0 5px;line-height:30px;display:block;box-shadow:inset 1px 1px 5px #0000001a}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px #0006}.layui-layer-tab .layui-layer-title{background-color:#eee;border-bottom:1px solid #ccc;padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{float:left;text-align:center;cursor:default;text-overflow:ellipsis;white-space:nowrap;min-width:80px;max-width:260px;padding:0 20px;position:relative;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{z-index:10;background-color:#fff;border-left:1px solid #ccc;border-right:1px solid #ccc;height:43px}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{clear:both;line-height:24px}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{cursor:pointer;position:absolute;top:5px;right:10px}.layui-layer-photos{animation-duration:1s}.layui-layer-photos .layui-layer-content{text-align:center;overflow:hidden}.layui-layer-photos .layui-layer-phimg img{vertical-align:top}.layui-layer-imguide,.layui-layer-imgbar{display:none}.layui-layer-imgprev,.layui-layer-imgnext{_width:44px;blr:expression(this.onFocus=this.blur());outline:none;width:27px;height:44px;margin-top:-22px;position:absolute;top:50%}.layui-layer-imgprev{background-position:-5px -5px;left:10px}.layui-layer-imgprev:hover{background-position:-33px -5px}.layui-layer-imgnext{background-position:-5px -50px;right:10px}.layui-layer-imgnext:hover{background-position:-33px -50px}.layui-layer-imgbar{background-color:#000c;background-color:#000 \\9 ;width:100%;height:32px;filter:Alpha(opacity=80);color:#fff;text-overflow:ellipsis;white-space:nowrap;font-size:0;line-height:32px;position:absolute;bottom:0;left:0;overflow:hidden}.layui-layer-imgtit *{vertical-align:top;font-size:12px}.layui-layer-imgtit a{text-overflow:ellipsis;white-space:nowrap;color:#fff;max-width:65%;overflow:hidden}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@media screen and (width<=1100px){.layui-layer-iframe{-webkit-overflow-scrolling:touch;overflow-y:auto}}\n/*$vite$:1*/ ");
	var __create = Object.create;
	var __defProp = Object.defineProperty;
	var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
	var __getOwnPropNames = Object.getOwnPropertyNames;
	var __getProtoOf = Object.getPrototypeOf;
	var __hasOwnProp = Object.prototype.hasOwnProperty;
	var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
	var __copyProps = (to, from, except, desc) => {
		if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
			key = keys[i];
			if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
				get: ((k) => from[k]).bind(null, key),
				enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
			});
		}
		return to;
	};
	var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
		value: mod,
		enumerable: true
	}) : target, mod));
	var __require = ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
		if (typeof require !== "undefined") return require.apply(this, arguments);
		throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
	});
	var import_jquery = __toESM(__commonJSMin(((exports, module) => {
		(function(global, factory) {
			"use strict";
			if (typeof module === "object" && typeof module.exports === "object") module.exports = global.document ? factory(global, true) : function(w) {
				if (!w.document) throw new Error("jQuery requires a window with a document");
				return factory(w);
			};
			else factory(global);
		})(typeof window !== "undefined" ? window : exports, function(window, noGlobal) {
			"use strict";
			var arr = [];
			var getProto = Object.getPrototypeOf;
			var slice = arr.slice;
			var flat = arr.flat ? function(array) {
				return arr.flat.call(array);
			} : function(array) {
				return arr.concat.apply([], array);
			};
			var push = arr.push;
			var indexOf = arr.indexOf;
			var class2type = {};
			var toString = class2type.toString;
			var hasOwn = class2type.hasOwnProperty;
			var fnToString = hasOwn.toString;
			var ObjectFunctionString = fnToString.call(Object);
			var support = {};
			var isFunction = function isFunction(obj) {
				return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function";
			};
			var isWindow = function isWindow(obj) {
				return obj != null && obj === obj.window;
			};
			var document = window.document;
			var preservedScriptAttributes = {
				type: true,
				src: true,
				nonce: true,
				noModule: true
			};
			function DOMEval(code, node, doc) {
				doc = doc || document;
				var i, val, script = doc.createElement("script");
				script.text = code;
				if (node) for (i in preservedScriptAttributes) {
					val = node[i] || node.getAttribute && node.getAttribute(i);
					if (val) script.setAttribute(i, val);
				}
				doc.head.appendChild(script).parentNode.removeChild(script);
			}
			function toType(obj) {
				if (obj == null) return obj + "";
				return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj;
			}
			var version = "3.7.1", rhtmlSuffix = /HTML$/i, jQuery = function(selector, context) {
				return new jQuery.fn.init(selector, context);
			};
			jQuery.fn = jQuery.prototype = {
				jquery: version,
				constructor: jQuery,
				length: 0,
				toArray: function() {
					return slice.call(this);
				},
				get: function(num) {
					if (num == null) return slice.call(this);
					return num < 0 ? this[num + this.length] : this[num];
				},
				pushStack: function(elems) {
					var ret = jQuery.merge(this.constructor(), elems);
					ret.prevObject = this;
					return ret;
				},
				each: function(callback) {
					return jQuery.each(this, callback);
				},
				map: function(callback) {
					return this.pushStack(jQuery.map(this, function(elem, i) {
						return callback.call(elem, i, elem);
					}));
				},
				slice: function() {
					return this.pushStack(slice.apply(this, arguments));
				},
				first: function() {
					return this.eq(0);
				},
				last: function() {
					return this.eq(-1);
				},
				even: function() {
					return this.pushStack(jQuery.grep(this, function(_elem, i) {
						return (i + 1) % 2;
					}));
				},
				odd: function() {
					return this.pushStack(jQuery.grep(this, function(_elem, i) {
						return i % 2;
					}));
				},
				eq: function(i) {
					var len = this.length, j = +i + (i < 0 ? len : 0);
					return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
				},
				end: function() {
					return this.prevObject || this.constructor();
				},
				push,
				sort: arr.sort,
				splice: arr.splice
			};
			jQuery.extend = jQuery.fn.extend = function() {
				var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false;
				if (typeof target === "boolean") {
					deep = target;
					target = arguments[i] || {};
					i++;
				}
				if (typeof target !== "object" && !isFunction(target)) target = {};
				if (i === length) {
					target = this;
					i--;
				}
				for (; i < length; i++) if ((options = arguments[i]) != null) for (name in options) {
					copy = options[name];
					if (name === "__proto__" || target === copy) continue;
					if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
						src = target[name];
						if (copyIsArray && !Array.isArray(src)) clone = [];
						else if (!copyIsArray && !jQuery.isPlainObject(src)) clone = {};
						else clone = src;
						copyIsArray = false;
						target[name] = jQuery.extend(deep, clone, copy);
					} else if (copy !== void 0) target[name] = copy;
				}
				return target;
			};
			jQuery.extend({
				expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),
				isReady: true,
				error: function(msg) {
					throw new Error(msg);
				},
				noop: function() {},
				isPlainObject: function(obj) {
					var proto, Ctor;
					if (!obj || toString.call(obj) !== "[object Object]") return false;
					proto = getProto(obj);
					if (!proto) return true;
					Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
					return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
				},
				isEmptyObject: function(obj) {
					var name;
					for (name in obj) return false;
					return true;
				},
				globalEval: function(code, options, doc) {
					DOMEval(code, { nonce: options && options.nonce }, doc);
				},
				each: function(obj, callback) {
					var length, i = 0;
					if (isArrayLike(obj)) {
						length = obj.length;
						for (; i < length; i++) if (callback.call(obj[i], i, obj[i]) === false) break;
					} else for (i in obj) if (callback.call(obj[i], i, obj[i]) === false) break;
					return obj;
				},
				text: function(elem) {
					var node, ret = "", i = 0, nodeType = elem.nodeType;
					if (!nodeType) while (node = elem[i++]) ret += jQuery.text(node);
					if (nodeType === 1 || nodeType === 11) return elem.textContent;
					if (nodeType === 9) return elem.documentElement.textContent;
					if (nodeType === 3 || nodeType === 4) return elem.nodeValue;
					return ret;
				},
				makeArray: function(arr, results) {
					var ret = results || [];
					if (arr != null) if (isArrayLike(Object(arr))) jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
					else push.call(ret, arr);
					return ret;
				},
				inArray: function(elem, arr, i) {
					return arr == null ? -1 : indexOf.call(arr, elem, i);
				},
				isXMLDoc: function(elem) {
					var namespace = elem && elem.namespaceURI, docElem = elem && (elem.ownerDocument || elem).documentElement;
					return !rhtmlSuffix.test(namespace || docElem && docElem.nodeName || "HTML");
				},
				merge: function(first, second) {
					var len = +second.length, j = 0, i = first.length;
					for (; j < len; j++) first[i++] = second[j];
					first.length = i;
					return first;
				},
				grep: function(elems, callback, invert) {
					var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert;
					for (; i < length; i++) {
						callbackInverse = !callback(elems[i], i);
						if (callbackInverse !== callbackExpect) matches.push(elems[i]);
					}
					return matches;
				},
				map: function(elems, callback, arg) {
					var length, value, i = 0, ret = [];
					if (isArrayLike(elems)) {
						length = elems.length;
						for (; i < length; i++) {
							value = callback(elems[i], i, arg);
							if (value != null) ret.push(value);
						}
					} else for (i in elems) {
						value = callback(elems[i], i, arg);
						if (value != null) ret.push(value);
					}
					return flat(ret);
				},
				guid: 1,
				support
			});
			if (typeof Symbol === "function") jQuery.fn[Symbol.iterator] = arr[Symbol.iterator];
			jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function(_i, name) {
				class2type["[object " + name + "]"] = name.toLowerCase();
			});
			function isArrayLike(obj) {
				var length = !!obj && "length" in obj && obj.length, type = toType(obj);
				if (isFunction(obj) || isWindow(obj)) return false;
				return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj;
			}
			function nodeName(elem, name) {
				return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
			}
			var pop = arr.pop;
			var sort = arr.sort;
			var splice = arr.splice;
			var whitespace = "[\\x20\\t\\r\\n\\f]";
			var rtrimCSS = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g");
			jQuery.contains = function(a, b) {
				var bup = b && b.parentNode;
				return a === bup || !!(bup && bup.nodeType === 1 && (a.contains ? a.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
			};
			var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
			function fcssescape(ch, asCodePoint) {
				if (asCodePoint) {
					if (ch === "\0") return "�";
					return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
				}
				return "\\" + ch;
			}
			jQuery.escapeSelector = function(sel) {
				return (sel + "").replace(rcssescape, fcssescape);
			};
			var preferredDoc = document, pushNative = push;
			(function() {
				var i, Expr, outermostContext, sortInput, hasDuplicate, push = pushNative, document, documentElement, documentIsHTML, rbuggyQSA, matches, expando = jQuery.expando, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), nonnativeSelectorCache = createCache(), sortOrder = function(a, b) {
					if (a === b) hasDuplicate = true;
					return 0;
				}, booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + "*([*^$|!~]?=)" + whitespace + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", pseudos = ":(" + identifier + ")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|.*)\\)|)", rwhitespace = new RegExp(whitespace + "+", "g"), rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"), rleadingCombinator = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"), rdescend = new RegExp(whitespace + "|>"), rpseudo = new RegExp(pseudos), ridentifier = new RegExp("^" + identifier + "$"), matchExpr = {
					ID: new RegExp("^#(" + identifier + ")"),
					CLASS: new RegExp("^\\.(" + identifier + ")"),
					TAG: new RegExp("^(" + identifier + "|[*])"),
					ATTR: new RegExp("^" + attributes),
					PSEUDO: new RegExp("^" + pseudos),
					CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
					bool: new RegExp("^(?:" + booleans + ")$", "i"),
					needsContext: new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
				}, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, runescape = new RegExp("\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g"), funescape = function(escape, nonHex) {
					var high = "0x" + escape.slice(1) - 65536;
					if (nonHex) return nonHex;
					return high < 0 ? String.fromCharCode(high + 65536) : String.fromCharCode(high >> 10 | 55296, high & 1023 | 56320);
				}, unloadHandler = function() {
					setDocument();
				}, inDisabledFieldset = addCombinator(function(elem) {
					return elem.disabled === true && nodeName(elem, "fieldset");
				}, {
					dir: "parentNode",
					next: "legend"
				});
				function safeActiveElement() {
					try {
						return document.activeElement;
					} catch (err) {}
				}
				try {
					push.apply(arr = slice.call(preferredDoc.childNodes), preferredDoc.childNodes);
					arr[preferredDoc.childNodes.length].nodeType;
				} catch (e) {
					push = {
						apply: function(target, els) {
							pushNative.apply(target, slice.call(els));
						},
						call: function(target) {
							pushNative.apply(target, slice.call(arguments, 1));
						}
					};
				}
				function find(selector, context, results, seed) {
					var m, i, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, nodeType = context ? context.nodeType : 9;
					results = results || [];
					if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) return results;
					if (!seed) {
						setDocument(context);
						context = context || document;
						if (documentIsHTML) {
							if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {
								if (m = match[1]) {
									if (nodeType === 9) if (elem = context.getElementById(m)) {
										if (elem.id === m) {
											push.call(results, elem);
											return results;
										}
									} else return results;
									else if (newContext && (elem = newContext.getElementById(m)) && find.contains(context, elem) && elem.id === m) {
										push.call(results, elem);
										return results;
									}
								} else if (match[2]) {
									push.apply(results, context.getElementsByTagName(selector));
									return results;
								} else if ((m = match[3]) && context.getElementsByClassName) {
									push.apply(results, context.getElementsByClassName(m));
									return results;
								}
							}
							if (!nonnativeSelectorCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
								newSelector = selector;
								newContext = context;
								if (nodeType === 1 && (rdescend.test(selector) || rleadingCombinator.test(selector))) {
									newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
									if (newContext != context || !support.scope) if (nid = context.getAttribute("id")) nid = jQuery.escapeSelector(nid);
									else context.setAttribute("id", nid = expando);
									groups = tokenize(selector);
									i = groups.length;
									while (i--) groups[i] = (nid ? "#" + nid : ":scope") + " " + toSelector(groups[i]);
									newSelector = groups.join(",");
								}
								try {
									push.apply(results, newContext.querySelectorAll(newSelector));
									return results;
								} catch (qsaError) {
									nonnativeSelectorCache(selector, true);
								} finally {
									if (nid === expando) context.removeAttribute("id");
								}
							}
						}
					}
					return select(selector.replace(rtrimCSS, "$1"), context, results, seed);
				}
				function createCache() {
					var keys = [];
					function cache(key, value) {
						if (keys.push(key + " ") > Expr.cacheLength) delete cache[keys.shift()];
						return cache[key + " "] = value;
					}
					return cache;
				}
				function markFunction(fn) {
					fn[expando] = true;
					return fn;
				}
				function assert(fn) {
					var el = document.createElement("fieldset");
					try {
						return !!fn(el);
					} catch (e) {
						return false;
					} finally {
						if (el.parentNode) el.parentNode.removeChild(el);
						el = null;
					}
				}
				function createInputPseudo(type) {
					return function(elem) {
						return nodeName(elem, "input") && elem.type === type;
					};
				}
				function createButtonPseudo(type) {
					return function(elem) {
						return (nodeName(elem, "input") || nodeName(elem, "button")) && elem.type === type;
					};
				}
				function createDisabledPseudo(disabled) {
					return function(elem) {
						if ("form" in elem) {
							if (elem.parentNode && elem.disabled === false) {
								if ("label" in elem) if ("label" in elem.parentNode) return elem.parentNode.disabled === disabled;
								else return elem.disabled === disabled;
								return elem.isDisabled === disabled || elem.isDisabled !== !disabled && inDisabledFieldset(elem) === disabled;
							}
							return elem.disabled === disabled;
						} else if ("label" in elem) return elem.disabled === disabled;
						return false;
					};
				}
				function createPositionalPseudo(fn) {
					return markFunction(function(argument) {
						argument = +argument;
						return markFunction(function(seed, matches) {
							var j, matchIndexes = fn([], seed.length, argument), i = matchIndexes.length;
							while (i--) if (seed[j = matchIndexes[i]]) seed[j] = !(matches[j] = seed[j]);
						});
					});
				}
				function testContext(context) {
					return context && typeof context.getElementsByTagName !== "undefined" && context;
				}
				function setDocument(node) {
					var subWindow, doc = node ? node.ownerDocument || node : preferredDoc;
					if (doc == document || doc.nodeType !== 9 || !doc.documentElement) return document;
					document = doc;
					documentElement = document.documentElement;
					documentIsHTML = !jQuery.isXMLDoc(document);
					matches = documentElement.matches || documentElement.webkitMatchesSelector || documentElement.msMatchesSelector;
					if (documentElement.msMatchesSelector && preferredDoc != document && (subWindow = document.defaultView) && subWindow.top !== subWindow) subWindow.addEventListener("unload", unloadHandler);
					support.getById = assert(function(el) {
						documentElement.appendChild(el).id = jQuery.expando;
						return !document.getElementsByName || !document.getElementsByName(jQuery.expando).length;
					});
					support.disconnectedMatch = assert(function(el) {
						return matches.call(el, "*");
					});
					support.scope = assert(function() {
						return document.querySelectorAll(":scope");
					});
					support.cssHas = assert(function() {
						try {
							document.querySelector(":has(*,:jqfake)");
							return false;
						} catch (e) {
							return true;
						}
					});
					if (support.getById) {
						Expr.filter.ID = function(id) {
							var attrId = id.replace(runescape, funescape);
							return function(elem) {
								return elem.getAttribute("id") === attrId;
							};
						};
						Expr.find.ID = function(id, context) {
							if (typeof context.getElementById !== "undefined" && documentIsHTML) {
								var elem = context.getElementById(id);
								return elem ? [elem] : [];
							}
						};
					} else {
						Expr.filter.ID = function(id) {
							var attrId = id.replace(runescape, funescape);
							return function(elem) {
								var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
								return node && node.value === attrId;
							};
						};
						Expr.find.ID = function(id, context) {
							if (typeof context.getElementById !== "undefined" && documentIsHTML) {
								var node, i, elems, elem = context.getElementById(id);
								if (elem) {
									node = elem.getAttributeNode("id");
									if (node && node.value === id) return [elem];
									elems = context.getElementsByName(id);
									i = 0;
									while (elem = elems[i++]) {
										node = elem.getAttributeNode("id");
										if (node && node.value === id) return [elem];
									}
								}
								return [];
							}
						};
					}
					Expr.find.TAG = function(tag, context) {
						if (typeof context.getElementsByTagName !== "undefined") return context.getElementsByTagName(tag);
						else return context.querySelectorAll(tag);
					};
					Expr.find.CLASS = function(className, context) {
						if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) return context.getElementsByClassName(className);
					};
					rbuggyQSA = [];
					assert(function(el) {
						var input;
						documentElement.appendChild(el).innerHTML = "<a id='" + expando + "' href='' disabled='disabled'></a><select id='" + expando + "-\r\\' disabled='disabled'><option selected=''></option></select>";
						if (!el.querySelectorAll("[selected]").length) rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
						if (!el.querySelectorAll("[id~=" + expando + "-]").length) rbuggyQSA.push("~=");
						if (!el.querySelectorAll("a#" + expando + "+*").length) rbuggyQSA.push(".#.+[+~]");
						if (!el.querySelectorAll(":checked").length) rbuggyQSA.push(":checked");
						input = document.createElement("input");
						input.setAttribute("type", "hidden");
						el.appendChild(input).setAttribute("name", "D");
						documentElement.appendChild(el).disabled = true;
						if (el.querySelectorAll(":disabled").length !== 2) rbuggyQSA.push(":enabled", ":disabled");
						input = document.createElement("input");
						input.setAttribute("name", "");
						el.appendChild(input);
						if (!el.querySelectorAll("[name='']").length) rbuggyQSA.push("\\[" + whitespace + "*name" + whitespace + "*=" + whitespace + "*(?:''|\"\")");
					});
					if (!support.cssHas) rbuggyQSA.push(":has");
					rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
					sortOrder = function(a, b) {
						if (a === b) {
							hasDuplicate = true;
							return 0;
						}
						var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
						if (compare) return compare;
						compare = (a.ownerDocument || a) == (b.ownerDocument || b) ? a.compareDocumentPosition(b) : 1;
						if (compare & 1 || !support.sortDetached && b.compareDocumentPosition(a) === compare) {
							if (a === document || a.ownerDocument == preferredDoc && find.contains(preferredDoc, a)) return -1;
							if (b === document || b.ownerDocument == preferredDoc && find.contains(preferredDoc, b)) return 1;
							return sortInput ? indexOf.call(sortInput, a) - indexOf.call(sortInput, b) : 0;
						}
						return compare & 4 ? -1 : 1;
					};
					return document;
				}
				find.matches = function(expr, elements) {
					return find(expr, null, null, elements);
				};
				find.matchesSelector = function(elem, expr) {
					setDocument(elem);
					if (documentIsHTML && !nonnativeSelectorCache[expr + " "] && (!rbuggyQSA || !rbuggyQSA.test(expr))) try {
						var ret = matches.call(elem, expr);
						if (ret || support.disconnectedMatch || elem.document && elem.document.nodeType !== 11) return ret;
					} catch (e) {
						nonnativeSelectorCache(expr, true);
					}
					return find(expr, document, null, [elem]).length > 0;
				};
				find.contains = function(context, elem) {
					if ((context.ownerDocument || context) != document) setDocument(context);
					return jQuery.contains(context, elem);
				};
				find.attr = function(elem, name) {
					if ((elem.ownerDocument || elem) != document) setDocument(elem);
					var fn = Expr.attrHandle[name.toLowerCase()], val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : void 0;
					if (val !== void 0) return val;
					return elem.getAttribute(name);
				};
				find.error = function(msg) {
					throw new Error("Syntax error, unrecognized expression: " + msg);
				};
				jQuery.uniqueSort = function(results) {
					var elem, duplicates = [], j = 0, i = 0;
					hasDuplicate = !support.sortStable;
					sortInput = !support.sortStable && slice.call(results, 0);
					sort.call(results, sortOrder);
					if (hasDuplicate) {
						while (elem = results[i++]) if (elem === results[i]) j = duplicates.push(i);
						while (j--) splice.call(results, duplicates[j], 1);
					}
					sortInput = null;
					return results;
				};
				jQuery.fn.uniqueSort = function() {
					return this.pushStack(jQuery.uniqueSort(slice.apply(this)));
				};
				Expr = jQuery.expr = {
					cacheLength: 50,
					createPseudo: markFunction,
					match: matchExpr,
					attrHandle: {},
					find: {},
					relative: {
						">": {
							dir: "parentNode",
							first: true
						},
						" ": { dir: "parentNode" },
						"+": {
							dir: "previousSibling",
							first: true
						},
						"~": { dir: "previousSibling" }
					},
					preFilter: {
						ATTR: function(match) {
							match[1] = match[1].replace(runescape, funescape);
							match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
							if (match[2] === "~=") match[3] = " " + match[3] + " ";
							return match.slice(0, 4);
						},
						CHILD: function(match) {
							match[1] = match[1].toLowerCase();
							if (match[1].slice(0, 3) === "nth") {
								if (!match[3]) find.error(match[0]);
								match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
								match[5] = +(match[7] + match[8] || match[3] === "odd");
							} else if (match[3]) find.error(match[0]);
							return match;
						},
						PSEUDO: function(match) {
							var excess, unquoted = !match[6] && match[2];
							if (matchExpr.CHILD.test(match[0])) return null;
							if (match[3]) match[2] = match[4] || match[5] || "";
							else if (unquoted && rpseudo.test(unquoted) && (excess = tokenize(unquoted, true)) && (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
								match[0] = match[0].slice(0, excess);
								match[2] = unquoted.slice(0, excess);
							}
							return match.slice(0, 3);
						}
					},
					filter: {
						TAG: function(nodeNameSelector) {
							var expectedNodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
							return nodeNameSelector === "*" ? function() {
								return true;
							} : function(elem) {
								return nodeName(elem, expectedNodeName);
							};
						},
						CLASS: function(className) {
							var pattern = classCache[className + " "];
							return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function(elem) {
								return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "");
							});
						},
						ATTR: function(name, operator, check) {
							return function(elem) {
								var result = find.attr(elem, name);
								if (result == null) return operator === "!=";
								if (!operator) return true;
								result += "";
								if (operator === "=") return result === check;
								if (operator === "!=") return result !== check;
								if (operator === "^=") return check && result.indexOf(check) === 0;
								if (operator === "*=") return check && result.indexOf(check) > -1;
								if (operator === "$=") return check && result.slice(-check.length) === check;
								if (operator === "~=") return (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1;
								if (operator === "|=") return result === check || result.slice(0, check.length + 1) === check + "-";
								return false;
							};
						},
						CHILD: function(type, what, _argument, first, last) {
							var simple = type.slice(0, 3) !== "nth", forward = type.slice(-4) !== "last", ofType = what === "of-type";
							return first === 1 && last === 0 ? function(elem) {
								return !!elem.parentNode;
							} : function(elem, _context, xml) {
								var cache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType, diff = false;
								if (parent) {
									if (simple) {
										while (dir) {
											node = elem;
											while (node = node[dir]) if (ofType ? nodeName(node, name) : node.nodeType === 1) return false;
											start = dir = type === "only" && !start && "nextSibling";
										}
										return true;
									}
									start = [forward ? parent.firstChild : parent.lastChild];
									if (forward && useCache) {
										outerCache = parent[expando] || (parent[expando] = {});
										cache = outerCache[type] || [];
										nodeIndex = cache[0] === dirruns && cache[1];
										diff = nodeIndex && cache[2];
										node = nodeIndex && parent.childNodes[nodeIndex];
										while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) if (node.nodeType === 1 && ++diff && node === elem) {
											outerCache[type] = [
												dirruns,
												nodeIndex,
												diff
											];
											break;
										}
									} else {
										if (useCache) {
											outerCache = elem[expando] || (elem[expando] = {});
											cache = outerCache[type] || [];
											nodeIndex = cache[0] === dirruns && cache[1];
											diff = nodeIndex;
										}
										if (diff === false) {
											while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) if ((ofType ? nodeName(node, name) : node.nodeType === 1) && ++diff) {
												if (useCache) {
													outerCache = node[expando] || (node[expando] = {});
													outerCache[type] = [dirruns, diff];
												}
												if (node === elem) break;
											}
										}
									}
									diff -= last;
									return diff === first || diff % first === 0 && diff / first >= 0;
								}
							};
						},
						PSEUDO: function(pseudo, argument) {
							var args, fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || find.error("unsupported pseudo: " + pseudo);
							if (fn[expando]) return fn(argument);
							if (fn.length > 1) {
								args = [
									pseudo,
									pseudo,
									"",
									argument
								];
								return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function(seed, matches) {
									var idx, matched = fn(seed, argument), i = matched.length;
									while (i--) {
										idx = indexOf.call(seed, matched[i]);
										seed[idx] = !(matches[idx] = matched[i]);
									}
								}) : function(elem) {
									return fn(elem, 0, args);
								};
							}
							return fn;
						}
					},
					pseudos: {
						not: markFunction(function(selector) {
							var input = [], results = [], matcher = compile(selector.replace(rtrimCSS, "$1"));
							return matcher[expando] ? markFunction(function(seed, matches, _context, xml) {
								var elem, unmatched = matcher(seed, null, xml, []), i = seed.length;
								while (i--) if (elem = unmatched[i]) seed[i] = !(matches[i] = elem);
							}) : function(elem, _context, xml) {
								input[0] = elem;
								matcher(input, null, xml, results);
								input[0] = null;
								return !results.pop();
							};
						}),
						has: markFunction(function(selector) {
							return function(elem) {
								return find(selector, elem).length > 0;
							};
						}),
						contains: markFunction(function(text) {
							text = text.replace(runescape, funescape);
							return function(elem) {
								return (elem.textContent || jQuery.text(elem)).indexOf(text) > -1;
							};
						}),
						lang: markFunction(function(lang) {
							if (!ridentifier.test(lang || "")) find.error("unsupported lang: " + lang);
							lang = lang.replace(runescape, funescape).toLowerCase();
							return function(elem) {
								var elemLang;
								do
									if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) {
										elemLang = elemLang.toLowerCase();
										return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
									}
								while ((elem = elem.parentNode) && elem.nodeType === 1);
								return false;
							};
						}),
						target: function(elem) {
							var hash = window.location && window.location.hash;
							return hash && hash.slice(1) === elem.id;
						},
						root: function(elem) {
							return elem === documentElement;
						},
						focus: function(elem) {
							return elem === safeActiveElement() && document.hasFocus() && !!(elem.type || elem.href || ~elem.tabIndex);
						},
						enabled: createDisabledPseudo(false),
						disabled: createDisabledPseudo(true),
						checked: function(elem) {
							return nodeName(elem, "input") && !!elem.checked || nodeName(elem, "option") && !!elem.selected;
						},
						selected: function(elem) {
							if (elem.parentNode) elem.parentNode.selectedIndex;
							return elem.selected === true;
						},
						empty: function(elem) {
							for (elem = elem.firstChild; elem; elem = elem.nextSibling) if (elem.nodeType < 6) return false;
							return true;
						},
						parent: function(elem) {
							return !Expr.pseudos.empty(elem);
						},
						header: function(elem) {
							return rheader.test(elem.nodeName);
						},
						input: function(elem) {
							return rinputs.test(elem.nodeName);
						},
						button: function(elem) {
							return nodeName(elem, "input") && elem.type === "button" || nodeName(elem, "button");
						},
						text: function(elem) {
							var attr;
							return nodeName(elem, "input") && elem.type === "text" && ((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
						},
						first: createPositionalPseudo(function() {
							return [0];
						}),
						last: createPositionalPseudo(function(_matchIndexes, length) {
							return [length - 1];
						}),
						eq: createPositionalPseudo(function(_matchIndexes, length, argument) {
							return [argument < 0 ? argument + length : argument];
						}),
						even: createPositionalPseudo(function(matchIndexes, length) {
							var i = 0;
							for (; i < length; i += 2) matchIndexes.push(i);
							return matchIndexes;
						}),
						odd: createPositionalPseudo(function(matchIndexes, length) {
							var i = 1;
							for (; i < length; i += 2) matchIndexes.push(i);
							return matchIndexes;
						}),
						lt: createPositionalPseudo(function(matchIndexes, length, argument) {
							var i;
							if (argument < 0) i = argument + length;
							else if (argument > length) i = length;
							else i = argument;
							for (; --i >= 0;) matchIndexes.push(i);
							return matchIndexes;
						}),
						gt: createPositionalPseudo(function(matchIndexes, length, argument) {
							var i = argument < 0 ? argument + length : argument;
							for (; ++i < length;) matchIndexes.push(i);
							return matchIndexes;
						})
					}
				};
				Expr.pseudos.nth = Expr.pseudos.eq;
				for (i in {
					radio: true,
					checkbox: true,
					file: true,
					password: true,
					image: true
				}) Expr.pseudos[i] = createInputPseudo(i);
				for (i in {
					submit: true,
					reset: true
				}) Expr.pseudos[i] = createButtonPseudo(i);
				function setFilters() {}
				setFilters.prototype = Expr.filters = Expr.pseudos;
				Expr.setFilters = new setFilters();
				function tokenize(selector, parseOnly) {
					var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[selector + " "];
					if (cached) return parseOnly ? 0 : cached.slice(0);
					soFar = selector;
					groups = [];
					preFilters = Expr.preFilter;
					while (soFar) {
						if (!matched || (match = rcomma.exec(soFar))) {
							if (match) soFar = soFar.slice(match[0].length) || soFar;
							groups.push(tokens = []);
						}
						matched = false;
						if (match = rleadingCombinator.exec(soFar)) {
							matched = match.shift();
							tokens.push({
								value: matched,
								type: match[0].replace(rtrimCSS, " ")
							});
							soFar = soFar.slice(matched.length);
						}
						for (type in Expr.filter) if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
							matched = match.shift();
							tokens.push({
								value: matched,
								type,
								matches: match
							});
							soFar = soFar.slice(matched.length);
						}
						if (!matched) break;
					}
					if (parseOnly) return soFar.length;
					return soFar ? find.error(selector) : tokenCache(selector, groups).slice(0);
				}
				function toSelector(tokens) {
					var i = 0, len = tokens.length, selector = "";
					for (; i < len; i++) selector += tokens[i].value;
					return selector;
				}
				function addCombinator(matcher, combinator, base) {
					var dir = combinator.dir, skip = combinator.next, key = skip || dir, checkNonElements = base && key === "parentNode", doneName = done++;
					return combinator.first ? function(elem, context, xml) {
						while (elem = elem[dir]) if (elem.nodeType === 1 || checkNonElements) return matcher(elem, context, xml);
						return false;
					} : function(elem, context, xml) {
						var oldCache, outerCache, newCache = [dirruns, doneName];
						if (xml) {
							while (elem = elem[dir]) if (elem.nodeType === 1 || checkNonElements) {
								if (matcher(elem, context, xml)) return true;
							}
						} else while (elem = elem[dir]) if (elem.nodeType === 1 || checkNonElements) {
							outerCache = elem[expando] || (elem[expando] = {});
							if (skip && nodeName(elem, skip)) elem = elem[dir] || elem;
							else if ((oldCache = outerCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) return newCache[2] = oldCache[2];
							else {
								outerCache[key] = newCache;
								if (newCache[2] = matcher(elem, context, xml)) return true;
							}
						}
						return false;
					};
				}
				function elementMatcher(matchers) {
					return matchers.length > 1 ? function(elem, context, xml) {
						var i = matchers.length;
						while (i--) if (!matchers[i](elem, context, xml)) return false;
						return true;
					} : matchers[0];
				}
				function multipleContexts(selector, contexts, results) {
					var i = 0, len = contexts.length;
					for (; i < len; i++) find(selector, contexts[i], results);
					return results;
				}
				function condense(unmatched, map, filter, context, xml) {
					var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null;
					for (; i < len; i++) if (elem = unmatched[i]) {
						if (!filter || filter(elem, context, xml)) {
							newUnmatched.push(elem);
							if (mapped) map.push(i);
						}
					}
					return newUnmatched;
				}
				function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
					if (postFilter && !postFilter[expando]) postFilter = setMatcher(postFilter);
					if (postFinder && !postFinder[expando]) postFinder = setMatcher(postFinder, postSelector);
					return markFunction(function(seed, results, context, xml) {
						var temp, i, elem, matcherOut, preMap = [], postMap = [], preexisting = results.length, elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []), matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems;
						if (matcher) {
							matcherOut = postFinder || (seed ? preFilter : preexisting || postFilter) ? [] : results;
							matcher(matcherIn, matcherOut, context, xml);
						} else matcherOut = matcherIn;
						if (postFilter) {
							temp = condense(matcherOut, postMap);
							postFilter(temp, [], context, xml);
							i = temp.length;
							while (i--) if (elem = temp[i]) matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
						}
						if (seed) {
							if (postFinder || preFilter) {
								if (postFinder) {
									temp = [];
									i = matcherOut.length;
									while (i--) if (elem = matcherOut[i]) temp.push(matcherIn[i] = elem);
									postFinder(null, matcherOut = [], temp, xml);
								}
								i = matcherOut.length;
								while (i--) if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf.call(seed, elem) : preMap[i]) > -1) seed[temp] = !(results[temp] = elem);
							}
						} else {
							matcherOut = condense(matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut);
							if (postFinder) postFinder(null, results, matcherOut, xml);
							else push.apply(results, matcherOut);
						}
					});
				}
				function matcherFromTokens(tokens) {
					var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[tokens[0].type], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, matchContext = addCombinator(function(elem) {
						return elem === checkContext;
					}, implicitRelative, true), matchAnyContext = addCombinator(function(elem) {
						return indexOf.call(checkContext, elem) > -1;
					}, implicitRelative, true), matchers = [function(elem, context, xml) {
						var ret = !leadingRelative && (xml || context != outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
						checkContext = null;
						return ret;
					}];
					for (; i < len; i++) if (matcher = Expr.relative[tokens[i].type]) matchers = [addCombinator(elementMatcher(matchers), matcher)];
					else {
						matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
						if (matcher[expando]) {
							j = ++i;
							for (; j < len; j++) if (Expr.relative[tokens[j].type]) break;
							return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" })).replace(rtrimCSS, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens(tokens = tokens.slice(j)), j < len && toSelector(tokens));
						}
						matchers.push(matcher);
					}
					return elementMatcher(matchers);
				}
				function matcherFromGroupMatchers(elementMatchers, setMatchers) {
					var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function(seed, context, xml, results, outermost) {
						var elem, j, matcher, matchedCount = 0, i = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, elems = seed || byElement && Expr.find.TAG("*", outermost), dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || .1, len = elems.length;
						if (outermost) outermostContext = context == document || context || outermost;
						for (; i !== len && (elem = elems[i]) != null; i++) {
							if (byElement && elem) {
								j = 0;
								if (!context && elem.ownerDocument != document) {
									setDocument(elem);
									xml = !documentIsHTML;
								}
								while (matcher = elementMatchers[j++]) if (matcher(elem, context || document, xml)) {
									push.call(results, elem);
									break;
								}
								if (outermost) dirruns = dirrunsUnique;
							}
							if (bySet) {
								if (elem = !matcher && elem) matchedCount--;
								if (seed) unmatched.push(elem);
							}
						}
						matchedCount += i;
						if (bySet && i !== matchedCount) {
							j = 0;
							while (matcher = setMatchers[j++]) matcher(unmatched, setMatched, context, xml);
							if (seed) {
								if (matchedCount > 0) {
									while (i--) if (!(unmatched[i] || setMatched[i])) setMatched[i] = pop.call(results);
								}
								setMatched = condense(setMatched);
							}
							push.apply(results, setMatched);
							if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) jQuery.uniqueSort(results);
						}
						if (outermost) {
							dirruns = dirrunsUnique;
							outermostContext = contextBackup;
						}
						return unmatched;
					};
					return bySet ? markFunction(superMatcher) : superMatcher;
				}
				function compile(selector, match) {
					var i, setMatchers = [], elementMatchers = [], cached = compilerCache[selector + " "];
					if (!cached) {
						if (!match) match = tokenize(selector);
						i = match.length;
						while (i--) {
							cached = matcherFromTokens(match[i]);
							if (cached[expando]) setMatchers.push(cached);
							else elementMatchers.push(cached);
						}
						cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
						cached.selector = selector;
					}
					return cached;
				}
				function select(selector, context, results, seed) {
					var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize(selector = compiled.selector || selector);
					results = results || [];
					if (match.length === 1) {
						tokens = match[0] = match[0].slice(0);
						if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) {
							context = (Expr.find.ID(token.matches[0].replace(runescape, funescape), context) || [])[0];
							if (!context) return results;
							else if (compiled) context = context.parentNode;
							selector = selector.slice(tokens.shift().value.length);
						}
						i = matchExpr.needsContext.test(selector) ? 0 : tokens.length;
						while (i--) {
							token = tokens[i];
							if (Expr.relative[type = token.type]) break;
							if (find = Expr.find[type]) {
								if (seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context)) {
									tokens.splice(i, 1);
									selector = seed.length && toSelector(tokens);
									if (!selector) {
										push.apply(results, seed);
										return results;
									}
									break;
								}
							}
						}
					}
					(compiled || compile(selector, match))(seed, context, !documentIsHTML, results, !context || rsibling.test(selector) && testContext(context.parentNode) || context);
					return results;
				}
				support.sortStable = expando.split("").sort(sortOrder).join("") === expando;
				setDocument();
				support.sortDetached = assert(function(el) {
					return el.compareDocumentPosition(document.createElement("fieldset")) & 1;
				});
				jQuery.find = find;
				jQuery.expr[":"] = jQuery.expr.pseudos;
				jQuery.unique = jQuery.uniqueSort;
				find.compile = compile;
				find.select = select;
				find.setDocument = setDocument;
				find.tokenize = tokenize;
				find.escape = jQuery.escapeSelector;
				find.getText = jQuery.text;
				find.isXML = jQuery.isXMLDoc;
				find.selectors = jQuery.expr;
				find.support = jQuery.support;
				find.uniqueSort = jQuery.uniqueSort;
			})();
			var dir = function(elem, dir, until) {
				var matched = [], truncate = until !== void 0;
				while ((elem = elem[dir]) && elem.nodeType !== 9) if (elem.nodeType === 1) {
					if (truncate && jQuery(elem).is(until)) break;
					matched.push(elem);
				}
				return matched;
			};
			var siblings = function(n, elem) {
				var matched = [];
				for (; n; n = n.nextSibling) if (n.nodeType === 1 && n !== elem) matched.push(n);
				return matched;
			};
			var rneedsContext = jQuery.expr.match.needsContext;
			var rsingleTag = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;
			function winnow(elements, qualifier, not) {
				if (isFunction(qualifier)) return jQuery.grep(elements, function(elem, i) {
					return !!qualifier.call(elem, i, elem) !== not;
				});
				if (qualifier.nodeType) return jQuery.grep(elements, function(elem) {
					return elem === qualifier !== not;
				});
				if (typeof qualifier !== "string") return jQuery.grep(elements, function(elem) {
					return indexOf.call(qualifier, elem) > -1 !== not;
				});
				return jQuery.filter(qualifier, elements, not);
			}
			jQuery.filter = function(expr, elems, not) {
				var elem = elems[0];
				if (not) expr = ":not(" + expr + ")";
				if (elems.length === 1 && elem.nodeType === 1) return jQuery.find.matchesSelector(elem, expr) ? [elem] : [];
				return jQuery.find.matches(expr, jQuery.grep(elems, function(elem) {
					return elem.nodeType === 1;
				}));
			};
			jQuery.fn.extend({
				find: function(selector) {
					var i, ret, len = this.length, self = this;
					if (typeof selector !== "string") return this.pushStack(jQuery(selector).filter(function() {
						for (i = 0; i < len; i++) if (jQuery.contains(self[i], this)) return true;
					}));
					ret = this.pushStack([]);
					for (i = 0; i < len; i++) jQuery.find(selector, self[i], ret);
					return len > 1 ? jQuery.uniqueSort(ret) : ret;
				},
				filter: function(selector) {
					return this.pushStack(winnow(this, selector || [], false));
				},
				not: function(selector) {
					return this.pushStack(winnow(this, selector || [], true));
				},
				is: function(selector) {
					return !!winnow(this, typeof selector === "string" && rneedsContext.test(selector) ? jQuery(selector) : selector || [], false).length;
				}
			});
			var rootjQuery, rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, init = jQuery.fn.init = function(selector, context, root) {
				var match, elem;
				if (!selector) return this;
				root = root || rootjQuery;
				if (typeof selector === "string") {
					if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) match = [
						null,
						selector,
						null
					];
					else match = rquickExpr.exec(selector);
					if (match && (match[1] || !context)) if (match[1]) {
						context = context instanceof jQuery ? context[0] : context;
						jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true));
						if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) for (match in context) if (isFunction(this[match])) this[match](context[match]);
						else this.attr(match, context[match]);
						return this;
					} else {
						elem = document.getElementById(match[2]);
						if (elem) {
							this[0] = elem;
							this.length = 1;
						}
						return this;
					}
					else if (!context || context.jquery) return (context || root).find(selector);
					else return this.constructor(context).find(selector);
				} else if (selector.nodeType) {
					this[0] = selector;
					this.length = 1;
					return this;
				} else if (isFunction(selector)) return root.ready !== void 0 ? root.ready(selector) : selector(jQuery);
				return jQuery.makeArray(selector, this);
			};
			init.prototype = jQuery.fn;
			rootjQuery = jQuery(document);
			var rparentsprev = /^(?:parents|prev(?:Until|All))/, guaranteedUnique = {
				children: true,
				contents: true,
				next: true,
				prev: true
			};
			jQuery.fn.extend({
				has: function(target) {
					var targets = jQuery(target, this), l = targets.length;
					return this.filter(function() {
						var i = 0;
						for (; i < l; i++) if (jQuery.contains(this, targets[i])) return true;
					});
				},
				closest: function(selectors, context) {
					var cur, i = 0, l = this.length, matched = [], targets = typeof selectors !== "string" && jQuery(selectors);
					if (!rneedsContext.test(selectors)) {
						for (; i < l; i++) for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) if (cur.nodeType < 11 && (targets ? targets.index(cur) > -1 : cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors))) {
							matched.push(cur);
							break;
						}
					}
					return this.pushStack(matched.length > 1 ? jQuery.uniqueSort(matched) : matched);
				},
				index: function(elem) {
					if (!elem) return this[0] && this[0].parentNode ? this.first().prevAll().length : -1;
					if (typeof elem === "string") return indexOf.call(jQuery(elem), this[0]);
					return indexOf.call(this, elem.jquery ? elem[0] : elem);
				},
				add: function(selector, context) {
					return this.pushStack(jQuery.uniqueSort(jQuery.merge(this.get(), jQuery(selector, context))));
				},
				addBack: function(selector) {
					return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector));
				}
			});
			function sibling(cur, dir) {
				while ((cur = cur[dir]) && cur.nodeType !== 1);
				return cur;
			}
			jQuery.each({
				parent: function(elem) {
					var parent = elem.parentNode;
					return parent && parent.nodeType !== 11 ? parent : null;
				},
				parents: function(elem) {
					return dir(elem, "parentNode");
				},
				parentsUntil: function(elem, _i, until) {
					return dir(elem, "parentNode", until);
				},
				next: function(elem) {
					return sibling(elem, "nextSibling");
				},
				prev: function(elem) {
					return sibling(elem, "previousSibling");
				},
				nextAll: function(elem) {
					return dir(elem, "nextSibling");
				},
				prevAll: function(elem) {
					return dir(elem, "previousSibling");
				},
				nextUntil: function(elem, _i, until) {
					return dir(elem, "nextSibling", until);
				},
				prevUntil: function(elem, _i, until) {
					return dir(elem, "previousSibling", until);
				},
				siblings: function(elem) {
					return siblings((elem.parentNode || {}).firstChild, elem);
				},
				children: function(elem) {
					return siblings(elem.firstChild);
				},
				contents: function(elem) {
					if (elem.contentDocument != null && getProto(elem.contentDocument)) return elem.contentDocument;
					if (nodeName(elem, "template")) elem = elem.content || elem;
					return jQuery.merge([], elem.childNodes);
				}
			}, function(name, fn) {
				jQuery.fn[name] = function(until, selector) {
					var matched = jQuery.map(this, fn, until);
					if (name.slice(-5) !== "Until") selector = until;
					if (selector && typeof selector === "string") matched = jQuery.filter(selector, matched);
					if (this.length > 1) {
						if (!guaranteedUnique[name]) jQuery.uniqueSort(matched);
						if (rparentsprev.test(name)) matched.reverse();
					}
					return this.pushStack(matched);
				};
			});
			var rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
			function createOptions(options) {
				var object = {};
				jQuery.each(options.match(rnothtmlwhite) || [], function(_, flag) {
					object[flag] = true;
				});
				return object;
			}
			jQuery.Callbacks = function(options) {
				options = typeof options === "string" ? createOptions(options) : jQuery.extend({}, options);
				var firing, memory, fired, locked, list = [], queue = [], firingIndex = -1, fire = function() {
					locked = locked || options.once;
					fired = firing = true;
					for (; queue.length; firingIndex = -1) {
						memory = queue.shift();
						while (++firingIndex < list.length) if (list[firingIndex].apply(memory[0], memory[1]) === false && options.stopOnFalse) {
							firingIndex = list.length;
							memory = false;
						}
					}
					if (!options.memory) memory = false;
					firing = false;
					if (locked) if (memory) list = [];
					else list = "";
				}, self = {
					add: function() {
						if (list) {
							if (memory && !firing) {
								firingIndex = list.length - 1;
								queue.push(memory);
							}
							(function add(args) {
								jQuery.each(args, function(_, arg) {
									if (isFunction(arg)) {
										if (!options.unique || !self.has(arg)) list.push(arg);
									} else if (arg && arg.length && toType(arg) !== "string") add(arg);
								});
							})(arguments);
							if (memory && !firing) fire();
						}
						return this;
					},
					remove: function() {
						jQuery.each(arguments, function(_, arg) {
							var index;
							while ((index = jQuery.inArray(arg, list, index)) > -1) {
								list.splice(index, 1);
								if (index <= firingIndex) firingIndex--;
							}
						});
						return this;
					},
					has: function(fn) {
						return fn ? jQuery.inArray(fn, list) > -1 : list.length > 0;
					},
					empty: function() {
						if (list) list = [];
						return this;
					},
					disable: function() {
						locked = queue = [];
						list = memory = "";
						return this;
					},
					disabled: function() {
						return !list;
					},
					lock: function() {
						locked = queue = [];
						if (!memory && !firing) list = memory = "";
						return this;
					},
					locked: function() {
						return !!locked;
					},
					fireWith: function(context, args) {
						if (!locked) {
							args = args || [];
							args = [context, args.slice ? args.slice() : args];
							queue.push(args);
							if (!firing) fire();
						}
						return this;
					},
					fire: function() {
						self.fireWith(this, arguments);
						return this;
					},
					fired: function() {
						return !!fired;
					}
				};
				return self;
			};
			function Identity(v) {
				return v;
			}
			function Thrower(ex) {
				throw ex;
			}
			function adoptValue(value, resolve, reject, noValue) {
				var method;
				try {
					if (value && isFunction(method = value.promise)) method.call(value).done(resolve).fail(reject);
					else if (value && isFunction(method = value.then)) method.call(value, resolve, reject);
					else resolve.apply(void 0, [value].slice(noValue));
				} catch (value) {
					reject.apply(void 0, [value]);
				}
			}
			jQuery.extend({
				Deferred: function(func) {
					var tuples = [
						[
							"notify",
							"progress",
							jQuery.Callbacks("memory"),
							jQuery.Callbacks("memory"),
							2
						],
						[
							"resolve",
							"done",
							jQuery.Callbacks("once memory"),
							jQuery.Callbacks("once memory"),
							0,
							"resolved"
						],
						[
							"reject",
							"fail",
							jQuery.Callbacks("once memory"),
							jQuery.Callbacks("once memory"),
							1,
							"rejected"
						]
					], state = "pending", promise = {
						state: function() {
							return state;
						},
						always: function() {
							deferred.done(arguments).fail(arguments);
							return this;
						},
						"catch": function(fn) {
							return promise.then(null, fn);
						},
						pipe: function() {
							var fns = arguments;
							return jQuery.Deferred(function(newDefer) {
								jQuery.each(tuples, function(_i, tuple) {
									var fn = isFunction(fns[tuple[4]]) && fns[tuple[4]];
									deferred[tuple[1]](function() {
										var returned = fn && fn.apply(this, arguments);
										if (returned && isFunction(returned.promise)) returned.promise().progress(newDefer.notify).done(newDefer.resolve).fail(newDefer.reject);
										else newDefer[tuple[0] + "With"](this, fn ? [returned] : arguments);
									});
								});
								fns = null;
							}).promise();
						},
						then: function(onFulfilled, onRejected, onProgress) {
							var maxDepth = 0;
							function resolve(depth, deferred, handler, special) {
								return function() {
									var that = this, args = arguments, mightThrow = function() {
										var returned, then;
										if (depth < maxDepth) return;
										returned = handler.apply(that, args);
										if (returned === deferred.promise()) throw new TypeError("Thenable self-resolution");
										then = returned && (typeof returned === "object" || typeof returned === "function") && returned.then;
										if (isFunction(then)) if (special) then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special));
										else {
											maxDepth++;
											then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special), resolve(maxDepth, deferred, Identity, deferred.notifyWith));
										}
										else {
											if (handler !== Identity) {
												that = void 0;
												args = [returned];
											}
											(special || deferred.resolveWith)(that, args);
										}
									}, process = special ? mightThrow : function() {
										try {
											mightThrow();
										} catch (e) {
											if (jQuery.Deferred.exceptionHook) jQuery.Deferred.exceptionHook(e, process.error);
											if (depth + 1 >= maxDepth) {
												if (handler !== Thrower) {
													that = void 0;
													args = [e];
												}
												deferred.rejectWith(that, args);
											}
										}
									};
									if (depth) process();
									else {
										if (jQuery.Deferred.getErrorHook) process.error = jQuery.Deferred.getErrorHook();
										else if (jQuery.Deferred.getStackHook) process.error = jQuery.Deferred.getStackHook();
										window.setTimeout(process);
									}
								};
							}
							return jQuery.Deferred(function(newDefer) {
								tuples[0][3].add(resolve(0, newDefer, isFunction(onProgress) ? onProgress : Identity, newDefer.notifyWith));
								tuples[1][3].add(resolve(0, newDefer, isFunction(onFulfilled) ? onFulfilled : Identity));
								tuples[2][3].add(resolve(0, newDefer, isFunction(onRejected) ? onRejected : Thrower));
							}).promise();
						},
						promise: function(obj) {
							return obj != null ? jQuery.extend(obj, promise) : promise;
						}
					}, deferred = {};
					jQuery.each(tuples, function(i, tuple) {
						var list = tuple[2], stateString = tuple[5];
						promise[tuple[1]] = list.add;
						if (stateString) list.add(function() {
							state = stateString;
						}, tuples[3 - i][2].disable, tuples[3 - i][3].disable, tuples[0][2].lock, tuples[0][3].lock);
						list.add(tuple[3].fire);
						deferred[tuple[0]] = function() {
							deferred[tuple[0] + "With"](this === deferred ? void 0 : this, arguments);
							return this;
						};
						deferred[tuple[0] + "With"] = list.fireWith;
					});
					promise.promise(deferred);
					if (func) func.call(deferred, deferred);
					return deferred;
				},
				when: function(singleValue) {
					var remaining = arguments.length, i = remaining, resolveContexts = Array(i), resolveValues = slice.call(arguments), primary = jQuery.Deferred(), updateFunc = function(i) {
						return function(value) {
							resolveContexts[i] = this;
							resolveValues[i] = arguments.length > 1 ? slice.call(arguments) : value;
							if (!--remaining) primary.resolveWith(resolveContexts, resolveValues);
						};
					};
					if (remaining <= 1) {
						adoptValue(singleValue, primary.done(updateFunc(i)).resolve, primary.reject, !remaining);
						if (primary.state() === "pending" || isFunction(resolveValues[i] && resolveValues[i].then)) return primary.then();
					}
					while (i--) adoptValue(resolveValues[i], updateFunc(i), primary.reject);
					return primary.promise();
				}
			});
			var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
			jQuery.Deferred.exceptionHook = function(error, asyncError) {
				if (window.console && window.console.warn && error && rerrorNames.test(error.name)) window.console.warn("jQuery.Deferred exception: " + error.message, error.stack, asyncError);
			};
			jQuery.readyException = function(error) {
				window.setTimeout(function() {
					throw error;
				});
			};
			var readyList = jQuery.Deferred();
			jQuery.fn.ready = function(fn) {
				readyList.then(fn).catch(function(error) {
					jQuery.readyException(error);
				});
				return this;
			};
			jQuery.extend({
				isReady: false,
				readyWait: 1,
				ready: function(wait) {
					if (wait === true ? --jQuery.readyWait : jQuery.isReady) return;
					jQuery.isReady = true;
					if (wait !== true && --jQuery.readyWait > 0) return;
					readyList.resolveWith(document, [jQuery]);
				}
			});
			jQuery.ready.then = readyList.then;
			function completed() {
				document.removeEventListener("DOMContentLoaded", completed);
				window.removeEventListener("load", completed);
				jQuery.ready();
			}
			if (document.readyState === "complete" || document.readyState !== "loading" && !document.documentElement.doScroll) window.setTimeout(jQuery.ready);
			else {
				document.addEventListener("DOMContentLoaded", completed);
				window.addEventListener("load", completed);
			}
			var access = function(elems, fn, key, value, chainable, emptyGet, raw) {
				var i = 0, len = elems.length, bulk = key == null;
				if (toType(key) === "object") {
					chainable = true;
					for (i in key) access(elems, fn, i, key[i], true, emptyGet, raw);
				} else if (value !== void 0) {
					chainable = true;
					if (!isFunction(value)) raw = true;
					if (bulk) if (raw) {
						fn.call(elems, value);
						fn = null;
					} else {
						bulk = fn;
						fn = function(elem, _key, value) {
							return bulk.call(jQuery(elem), value);
						};
					}
					if (fn) for (; i < len; i++) fn(elems[i], key, raw ? value : value.call(elems[i], i, fn(elems[i], key)));
				}
				if (chainable) return elems;
				if (bulk) return fn.call(elems);
				return len ? fn(elems[0], key) : emptyGet;
			};
			var rmsPrefix = /^-ms-/, rdashAlpha = /-([a-z])/g;
			function fcamelCase(_all, letter) {
				return letter.toUpperCase();
			}
			function camelCase(string) {
				return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase);
			}
			var acceptData = function(owner) {
				return owner.nodeType === 1 || owner.nodeType === 9 || !+owner.nodeType;
			};
			function Data() {
				this.expando = jQuery.expando + Data.uid++;
			}
			Data.uid = 1;
			Data.prototype = {
				cache: function(owner) {
					var value = owner[this.expando];
					if (!value) {
						value = {};
						if (acceptData(owner)) if (owner.nodeType) owner[this.expando] = value;
						else Object.defineProperty(owner, this.expando, {
							value,
							configurable: true
						});
					}
					return value;
				},
				set: function(owner, data, value) {
					var prop, cache = this.cache(owner);
					if (typeof data === "string") cache[camelCase(data)] = value;
					else for (prop in data) cache[camelCase(prop)] = data[prop];
					return cache;
				},
				get: function(owner, key) {
					return key === void 0 ? this.cache(owner) : owner[this.expando] && owner[this.expando][camelCase(key)];
				},
				access: function(owner, key, value) {
					if (key === void 0 || key && typeof key === "string" && value === void 0) return this.get(owner, key);
					this.set(owner, key, value);
					return value !== void 0 ? value : key;
				},
				remove: function(owner, key) {
					var i, cache = owner[this.expando];
					if (cache === void 0) return;
					if (key !== void 0) {
						if (Array.isArray(key)) key = key.map(camelCase);
						else {
							key = camelCase(key);
							key = key in cache ? [key] : key.match(rnothtmlwhite) || [];
						}
						i = key.length;
						while (i--) delete cache[key[i]];
					}
					if (key === void 0 || jQuery.isEmptyObject(cache)) if (owner.nodeType) owner[this.expando] = void 0;
					else delete owner[this.expando];
				},
				hasData: function(owner) {
					var cache = owner[this.expando];
					return cache !== void 0 && !jQuery.isEmptyObject(cache);
				}
			};
			var dataPriv = new Data();
			var dataUser = new Data();
			var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /[A-Z]/g;
			function getData(data) {
				if (data === "true") return true;
				if (data === "false") return false;
				if (data === "null") return null;
				if (data === +data + "") return +data;
				if (rbrace.test(data)) return JSON.parse(data);
				return data;
			}
			function dataAttr(elem, key, data) {
				var name;
				if (data === void 0 && elem.nodeType === 1) {
					name = "data-" + key.replace(rmultiDash, "-$&").toLowerCase();
					data = elem.getAttribute(name);
					if (typeof data === "string") {
						try {
							data = getData(data);
						} catch (e) {}
						dataUser.set(elem, key, data);
					} else data = void 0;
				}
				return data;
			}
			jQuery.extend({
				hasData: function(elem) {
					return dataUser.hasData(elem) || dataPriv.hasData(elem);
				},
				data: function(elem, name, data) {
					return dataUser.access(elem, name, data);
				},
				removeData: function(elem, name) {
					dataUser.remove(elem, name);
				},
				_data: function(elem, name, data) {
					return dataPriv.access(elem, name, data);
				},
				_removeData: function(elem, name) {
					dataPriv.remove(elem, name);
				}
			});
			jQuery.fn.extend({
				data: function(key, value) {
					var i, name, data, elem = this[0], attrs = elem && elem.attributes;
					if (key === void 0) {
						if (this.length) {
							data = dataUser.get(elem);
							if (elem.nodeType === 1 && !dataPriv.get(elem, "hasDataAttrs")) {
								i = attrs.length;
								while (i--) if (attrs[i]) {
									name = attrs[i].name;
									if (name.indexOf("data-") === 0) {
										name = camelCase(name.slice(5));
										dataAttr(elem, name, data[name]);
									}
								}
								dataPriv.set(elem, "hasDataAttrs", true);
							}
						}
						return data;
					}
					if (typeof key === "object") return this.each(function() {
						dataUser.set(this, key);
					});
					return access(this, function(value) {
						var data;
						if (elem && value === void 0) {
							data = dataUser.get(elem, key);
							if (data !== void 0) return data;
							data = dataAttr(elem, key);
							if (data !== void 0) return data;
							return;
						}
						this.each(function() {
							dataUser.set(this, key, value);
						});
					}, null, value, arguments.length > 1, null, true);
				},
				removeData: function(key) {
					return this.each(function() {
						dataUser.remove(this, key);
					});
				}
			});
			jQuery.extend({
				queue: function(elem, type, data) {
					var queue;
					if (elem) {
						type = (type || "fx") + "queue";
						queue = dataPriv.get(elem, type);
						if (data) if (!queue || Array.isArray(data)) queue = dataPriv.access(elem, type, jQuery.makeArray(data));
						else queue.push(data);
						return queue || [];
					}
				},
				dequeue: function(elem, type) {
					type = type || "fx";
					var queue = jQuery.queue(elem, type), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks(elem, type), next = function() {
						jQuery.dequeue(elem, type);
					};
					if (fn === "inprogress") {
						fn = queue.shift();
						startLength--;
					}
					if (fn) {
						if (type === "fx") queue.unshift("inprogress");
						delete hooks.stop;
						fn.call(elem, next, hooks);
					}
					if (!startLength && hooks) hooks.empty.fire();
				},
				_queueHooks: function(elem, type) {
					var key = type + "queueHooks";
					return dataPriv.get(elem, key) || dataPriv.access(elem, key, { empty: jQuery.Callbacks("once memory").add(function() {
						dataPriv.remove(elem, [type + "queue", key]);
					}) });
				}
			});
			jQuery.fn.extend({
				queue: function(type, data) {
					var setter = 2;
					if (typeof type !== "string") {
						data = type;
						type = "fx";
						setter--;
					}
					if (arguments.length < setter) return jQuery.queue(this[0], type);
					return data === void 0 ? this : this.each(function() {
						var queue = jQuery.queue(this, type, data);
						jQuery._queueHooks(this, type);
						if (type === "fx" && queue[0] !== "inprogress") jQuery.dequeue(this, type);
					});
				},
				dequeue: function(type) {
					return this.each(function() {
						jQuery.dequeue(this, type);
					});
				},
				clearQueue: function(type) {
					return this.queue(type || "fx", []);
				},
				promise: function(type, obj) {
					var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function() {
						if (!--count) defer.resolveWith(elements, [elements]);
					};
					if (typeof type !== "string") {
						obj = type;
						type = void 0;
					}
					type = type || "fx";
					while (i--) {
						tmp = dataPriv.get(elements[i], type + "queueHooks");
						if (tmp && tmp.empty) {
							count++;
							tmp.empty.add(resolve);
						}
					}
					resolve();
					return defer.promise(obj);
				}
			});
			var pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source;
			var rcssNum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i");
			var cssExpand = [
				"Top",
				"Right",
				"Bottom",
				"Left"
			];
			var documentElement = document.documentElement;
			var isAttached = function(elem) {
				return jQuery.contains(elem.ownerDocument, elem);
			}, composed = { composed: true };
			if (documentElement.getRootNode) isAttached = function(elem) {
				return jQuery.contains(elem.ownerDocument, elem) || elem.getRootNode(composed) === elem.ownerDocument;
			};
			var isHiddenWithinTree = function(elem, el) {
				elem = el || elem;
				return elem.style.display === "none" || elem.style.display === "" && isAttached(elem) && jQuery.css(elem, "display") === "none";
			};
			function adjustCSS(elem, prop, valueParts, tween) {
				var adjusted, scale, maxIterations = 20, currentValue = tween ? function() {
					return tween.cur();
				} : function() {
					return jQuery.css(elem, prop, "");
				}, initial = currentValue(), unit = valueParts && valueParts[3] || (jQuery.cssNumber[prop] ? "" : "px"), initialInUnit = elem.nodeType && (jQuery.cssNumber[prop] || unit !== "px" && +initial) && rcssNum.exec(jQuery.css(elem, prop));
				if (initialInUnit && initialInUnit[3] !== unit) {
					initial = initial / 2;
					unit = unit || initialInUnit[3];
					initialInUnit = +initial || 1;
					while (maxIterations--) {
						jQuery.style(elem, prop, initialInUnit + unit);
						if ((1 - scale) * (1 - (scale = currentValue() / initial || .5)) <= 0) maxIterations = 0;
						initialInUnit = initialInUnit / scale;
					}
					initialInUnit = initialInUnit * 2;
					jQuery.style(elem, prop, initialInUnit + unit);
					valueParts = valueParts || [];
				}
				if (valueParts) {
					initialInUnit = +initialInUnit || +initial || 0;
					adjusted = valueParts[1] ? initialInUnit + (valueParts[1] + 1) * valueParts[2] : +valueParts[2];
					if (tween) {
						tween.unit = unit;
						tween.start = initialInUnit;
						tween.end = adjusted;
					}
				}
				return adjusted;
			}
			var defaultDisplayMap = {};
			function getDefaultDisplay(elem) {
				var temp, doc = elem.ownerDocument, nodeName = elem.nodeName, display = defaultDisplayMap[nodeName];
				if (display) return display;
				temp = doc.body.appendChild(doc.createElement(nodeName));
				display = jQuery.css(temp, "display");
				temp.parentNode.removeChild(temp);
				if (display === "none") display = "block";
				defaultDisplayMap[nodeName] = display;
				return display;
			}
			function showHide(elements, show) {
				var display, elem, values = [], index = 0, length = elements.length;
				for (; index < length; index++) {
					elem = elements[index];
					if (!elem.style) continue;
					display = elem.style.display;
					if (show) {
						if (display === "none") {
							values[index] = dataPriv.get(elem, "display") || null;
							if (!values[index]) elem.style.display = "";
						}
						if (elem.style.display === "" && isHiddenWithinTree(elem)) values[index] = getDefaultDisplay(elem);
					} else if (display !== "none") {
						values[index] = "none";
						dataPriv.set(elem, "display", display);
					}
				}
				for (index = 0; index < length; index++) if (values[index] != null) elements[index].style.display = values[index];
				return elements;
			}
			jQuery.fn.extend({
				show: function() {
					return showHide(this, true);
				},
				hide: function() {
					return showHide(this);
				},
				toggle: function(state) {
					if (typeof state === "boolean") return state ? this.show() : this.hide();
					return this.each(function() {
						if (isHiddenWithinTree(this)) jQuery(this).show();
						else jQuery(this).hide();
					});
				}
			});
			var rcheckableType = /^(?:checkbox|radio)$/i;
			var rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i;
			var rscriptType = /^$|^module$|\/(?:java|ecma)script/i;
			(function() {
				var div = document.createDocumentFragment().appendChild(document.createElement("div")), input = document.createElement("input");
				input.setAttribute("type", "radio");
				input.setAttribute("checked", "checked");
				input.setAttribute("name", "t");
				div.appendChild(input);
				support.checkClone = div.cloneNode(true).cloneNode(true).lastChild.checked;
				div.innerHTML = "<textarea>x</textarea>";
				support.noCloneChecked = !!div.cloneNode(true).lastChild.defaultValue;
				div.innerHTML = "<option></option>";
				support.option = !!div.lastChild;
			})();
			var wrapMap = {
				thead: [
					1,
					"<table>",
					"</table>"
				],
				col: [
					2,
					"<table><colgroup>",
					"</colgroup></table>"
				],
				tr: [
					2,
					"<table><tbody>",
					"</tbody></table>"
				],
				td: [
					3,
					"<table><tbody><tr>",
					"</tr></tbody></table>"
				],
				_default: [
					0,
					"",
					""
				]
			};
			wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
			wrapMap.th = wrapMap.td;
			if (!support.option) wrapMap.optgroup = wrapMap.option = [
				1,
				"<select multiple='multiple'>",
				"</select>"
			];
			function getAll(context, tag) {
				var ret;
				if (typeof context.getElementsByTagName !== "undefined") ret = context.getElementsByTagName(tag || "*");
				else if (typeof context.querySelectorAll !== "undefined") ret = context.querySelectorAll(tag || "*");
				else ret = [];
				if (tag === void 0 || tag && nodeName(context, tag)) return jQuery.merge([context], ret);
				return ret;
			}
			function setGlobalEval(elems, refElements) {
				var i = 0, l = elems.length;
				for (; i < l; i++) dataPriv.set(elems[i], "globalEval", !refElements || dataPriv.get(refElements[i], "globalEval"));
			}
			var rhtml = /<|&#?\w+;/;
			function buildFragment(elems, context, scripts, selection, ignored) {
				var elem, tmp, tag, wrap, attached, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, l = elems.length;
				for (; i < l; i++) {
					elem = elems[i];
					if (elem || elem === 0) if (toType(elem) === "object") jQuery.merge(nodes, elem.nodeType ? [elem] : elem);
					else if (!rhtml.test(elem)) nodes.push(context.createTextNode(elem));
					else {
						tmp = tmp || fragment.appendChild(context.createElement("div"));
						tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase();
						wrap = wrapMap[tag] || wrapMap._default;
						tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter(elem) + wrap[2];
						j = wrap[0];
						while (j--) tmp = tmp.lastChild;
						jQuery.merge(nodes, tmp.childNodes);
						tmp = fragment.firstChild;
						tmp.textContent = "";
					}
				}
				fragment.textContent = "";
				i = 0;
				while (elem = nodes[i++]) {
					if (selection && jQuery.inArray(elem, selection) > -1) {
						if (ignored) ignored.push(elem);
						continue;
					}
					attached = isAttached(elem);
					tmp = getAll(fragment.appendChild(elem), "script");
					if (attached) setGlobalEval(tmp);
					if (scripts) {
						j = 0;
						while (elem = tmp[j++]) if (rscriptType.test(elem.type || "")) scripts.push(elem);
					}
				}
				return fragment;
			}
			var rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
			function returnTrue() {
				return true;
			}
			function returnFalse() {
				return false;
			}
			function on(elem, types, selector, data, fn, one) {
				var origFn, type;
				if (typeof types === "object") {
					if (typeof selector !== "string") {
						data = data || selector;
						selector = void 0;
					}
					for (type in types) on(elem, type, selector, data, types[type], one);
					return elem;
				}
				if (data == null && fn == null) {
					fn = selector;
					data = selector = void 0;
				} else if (fn == null) if (typeof selector === "string") {
					fn = data;
					data = void 0;
				} else {
					fn = data;
					data = selector;
					selector = void 0;
				}
				if (fn === false) fn = returnFalse;
				else if (!fn) return elem;
				if (one === 1) {
					origFn = fn;
					fn = function(event) {
						jQuery().off(event);
						return origFn.apply(this, arguments);
					};
					fn.guid = origFn.guid || (origFn.guid = jQuery.guid++);
				}
				return elem.each(function() {
					jQuery.event.add(this, types, fn, data, selector);
				});
			}
			jQuery.event = {
				global: {},
				add: function(elem, types, handler, data, selector) {
					var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.get(elem);
					if (!acceptData(elem)) return;
					if (handler.handler) {
						handleObjIn = handler;
						handler = handleObjIn.handler;
						selector = handleObjIn.selector;
					}
					if (selector) jQuery.find.matchesSelector(documentElement, selector);
					if (!handler.guid) handler.guid = jQuery.guid++;
					if (!(events = elemData.events)) events = elemData.events = Object.create(null);
					if (!(eventHandle = elemData.handle)) eventHandle = elemData.handle = function(e) {
						return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply(elem, arguments) : void 0;
					};
					types = (types || "").match(rnothtmlwhite) || [""];
					t = types.length;
					while (t--) {
						tmp = rtypenamespace.exec(types[t]) || [];
						type = origType = tmp[1];
						namespaces = (tmp[2] || "").split(".").sort();
						if (!type) continue;
						special = jQuery.event.special[type] || {};
						type = (selector ? special.delegateType : special.bindType) || type;
						special = jQuery.event.special[type] || {};
						handleObj = jQuery.extend({
							type,
							origType,
							data,
							handler,
							guid: handler.guid,
							selector,
							needsContext: selector && jQuery.expr.match.needsContext.test(selector),
							namespace: namespaces.join(".")
						}, handleObjIn);
						if (!(handlers = events[type])) {
							handlers = events[type] = [];
							handlers.delegateCount = 0;
							if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) {
								if (elem.addEventListener) elem.addEventListener(type, eventHandle);
							}
						}
						if (special.add) {
							special.add.call(elem, handleObj);
							if (!handleObj.handler.guid) handleObj.handler.guid = handler.guid;
						}
						if (selector) handlers.splice(handlers.delegateCount++, 0, handleObj);
						else handlers.push(handleObj);
						jQuery.event.global[type] = true;
					}
				},
				remove: function(elem, types, handler, selector, mappedTypes) {
					var j, origCount, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.hasData(elem) && dataPriv.get(elem);
					if (!elemData || !(events = elemData.events)) return;
					types = (types || "").match(rnothtmlwhite) || [""];
					t = types.length;
					while (t--) {
						tmp = rtypenamespace.exec(types[t]) || [];
						type = origType = tmp[1];
						namespaces = (tmp[2] || "").split(".").sort();
						if (!type) {
							for (type in events) jQuery.event.remove(elem, type + types[t], handler, selector, true);
							continue;
						}
						special = jQuery.event.special[type] || {};
						type = (selector ? special.delegateType : special.bindType) || type;
						handlers = events[type] || [];
						tmp = tmp[2] && new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)");
						origCount = j = handlers.length;
						while (j--) {
							handleObj = handlers[j];
							if ((mappedTypes || origType === handleObj.origType) && (!handler || handler.guid === handleObj.guid) && (!tmp || tmp.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**" && handleObj.selector)) {
								handlers.splice(j, 1);
								if (handleObj.selector) handlers.delegateCount--;
								if (special.remove) special.remove.call(elem, handleObj);
							}
						}
						if (origCount && !handlers.length) {
							if (!special.teardown || special.teardown.call(elem, namespaces, elemData.handle) === false) jQuery.removeEvent(elem, type, elemData.handle);
							delete events[type];
						}
					}
					if (jQuery.isEmptyObject(events)) dataPriv.remove(elem, "handle events");
				},
				dispatch: function(nativeEvent) {
					var i, j, ret, matched, handleObj, handlerQueue, args = new Array(arguments.length), event = jQuery.event.fix(nativeEvent), handlers = (dataPriv.get(this, "events") || Object.create(null))[event.type] || [], special = jQuery.event.special[event.type] || {};
					args[0] = event;
					for (i = 1; i < arguments.length; i++) args[i] = arguments[i];
					event.delegateTarget = this;
					if (special.preDispatch && special.preDispatch.call(this, event) === false) return;
					handlerQueue = jQuery.event.handlers.call(this, event, handlers);
					i = 0;
					while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) {
						event.currentTarget = matched.elem;
						j = 0;
						while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) if (!event.rnamespace || handleObj.namespace === false || event.rnamespace.test(handleObj.namespace)) {
							event.handleObj = handleObj;
							event.data = handleObj.data;
							ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args);
							if (ret !== void 0) {
								if ((event.result = ret) === false) {
									event.preventDefault();
									event.stopPropagation();
								}
							}
						}
					}
					if (special.postDispatch) special.postDispatch.call(this, event);
					return event.result;
				},
				handlers: function(event, handlers) {
					var i, handleObj, sel, matchedHandlers, matchedSelectors, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target;
					if (delegateCount && cur.nodeType && !(event.type === "click" && event.button >= 1)) {
						for (; cur !== this; cur = cur.parentNode || this) if (cur.nodeType === 1 && !(event.type === "click" && cur.disabled === true)) {
							matchedHandlers = [];
							matchedSelectors = {};
							for (i = 0; i < delegateCount; i++) {
								handleObj = handlers[i];
								sel = handleObj.selector + " ";
								if (matchedSelectors[sel] === void 0) matchedSelectors[sel] = handleObj.needsContext ? jQuery(sel, this).index(cur) > -1 : jQuery.find(sel, this, null, [cur]).length;
								if (matchedSelectors[sel]) matchedHandlers.push(handleObj);
							}
							if (matchedHandlers.length) handlerQueue.push({
								elem: cur,
								handlers: matchedHandlers
							});
						}
					}
					cur = this;
					if (delegateCount < handlers.length) handlerQueue.push({
						elem: cur,
						handlers: handlers.slice(delegateCount)
					});
					return handlerQueue;
				},
				addProp: function(name, hook) {
					Object.defineProperty(jQuery.Event.prototype, name, {
						enumerable: true,
						configurable: true,
						get: isFunction(hook) ? function() {
							if (this.originalEvent) return hook(this.originalEvent);
						} : function() {
							if (this.originalEvent) return this.originalEvent[name];
						},
						set: function(value) {
							Object.defineProperty(this, name, {
								enumerable: true,
								configurable: true,
								writable: true,
								value
							});
						}
					});
				},
				fix: function(originalEvent) {
					return originalEvent[jQuery.expando] ? originalEvent : new jQuery.Event(originalEvent);
				},
				special: {
					load: { noBubble: true },
					click: {
						setup: function(data) {
							var el = this || data;
							if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) leverageNative(el, "click", true);
							return false;
						},
						trigger: function(data) {
							var el = this || data;
							if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) leverageNative(el, "click");
							return true;
						},
						_default: function(event) {
							var target = event.target;
							return rcheckableType.test(target.type) && target.click && nodeName(target, "input") && dataPriv.get(target, "click") || nodeName(target, "a");
						}
					},
					beforeunload: { postDispatch: function(event) {
						if (event.result !== void 0 && event.originalEvent) event.originalEvent.returnValue = event.result;
					} }
				}
			};
			function leverageNative(el, type, isSetup) {
				if (!isSetup) {
					if (dataPriv.get(el, type) === void 0) jQuery.event.add(el, type, returnTrue);
					return;
				}
				dataPriv.set(el, type, false);
				jQuery.event.add(el, type, {
					namespace: false,
					handler: function(event) {
						var result, saved = dataPriv.get(this, type);
						if (event.isTrigger & 1 && this[type]) {
							if (!saved) {
								saved = slice.call(arguments);
								dataPriv.set(this, type, saved);
								this[type]();
								result = dataPriv.get(this, type);
								dataPriv.set(this, type, false);
								if (saved !== result) {
									event.stopImmediatePropagation();
									event.preventDefault();
									return result;
								}
							} else if ((jQuery.event.special[type] || {}).delegateType) event.stopPropagation();
						} else if (saved) {
							dataPriv.set(this, type, jQuery.event.trigger(saved[0], saved.slice(1), this));
							event.stopPropagation();
							event.isImmediatePropagationStopped = returnTrue;
						}
					}
				});
			}
			jQuery.removeEvent = function(elem, type, handle) {
				if (elem.removeEventListener) elem.removeEventListener(type, handle);
			};
			jQuery.Event = function(src, props) {
				if (!(this instanceof jQuery.Event)) return new jQuery.Event(src, props);
				if (src && src.type) {
					this.originalEvent = src;
					this.type = src.type;
					this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === void 0 && src.returnValue === false ? returnTrue : returnFalse;
					this.target = src.target && src.target.nodeType === 3 ? src.target.parentNode : src.target;
					this.currentTarget = src.currentTarget;
					this.relatedTarget = src.relatedTarget;
				} else this.type = src;
				if (props) jQuery.extend(this, props);
				this.timeStamp = src && src.timeStamp || Date.now();
				this[jQuery.expando] = true;
			};
			jQuery.Event.prototype = {
				constructor: jQuery.Event,
				isDefaultPrevented: returnFalse,
				isPropagationStopped: returnFalse,
				isImmediatePropagationStopped: returnFalse,
				isSimulated: false,
				preventDefault: function() {
					var e = this.originalEvent;
					this.isDefaultPrevented = returnTrue;
					if (e && !this.isSimulated) e.preventDefault();
				},
				stopPropagation: function() {
					var e = this.originalEvent;
					this.isPropagationStopped = returnTrue;
					if (e && !this.isSimulated) e.stopPropagation();
				},
				stopImmediatePropagation: function() {
					var e = this.originalEvent;
					this.isImmediatePropagationStopped = returnTrue;
					if (e && !this.isSimulated) e.stopImmediatePropagation();
					this.stopPropagation();
				}
			};
			jQuery.each({
				altKey: true,
				bubbles: true,
				cancelable: true,
				changedTouches: true,
				ctrlKey: true,
				detail: true,
				eventPhase: true,
				metaKey: true,
				pageX: true,
				pageY: true,
				shiftKey: true,
				view: true,
				"char": true,
				code: true,
				charCode: true,
				key: true,
				keyCode: true,
				button: true,
				buttons: true,
				clientX: true,
				clientY: true,
				offsetX: true,
				offsetY: true,
				pointerId: true,
				pointerType: true,
				screenX: true,
				screenY: true,
				targetTouches: true,
				toElement: true,
				touches: true,
				which: true
			}, jQuery.event.addProp);
			jQuery.each({
				focus: "focusin",
				blur: "focusout"
			}, function(type, delegateType) {
				function focusMappedHandler(nativeEvent) {
					if (document.documentMode) {
						var handle = dataPriv.get(this, "handle"), event = jQuery.event.fix(nativeEvent);
						event.type = nativeEvent.type === "focusin" ? "focus" : "blur";
						event.isSimulated = true;
						handle(nativeEvent);
						if (event.target === event.currentTarget) handle(event);
					} else jQuery.event.simulate(delegateType, nativeEvent.target, jQuery.event.fix(nativeEvent));
				}
				jQuery.event.special[type] = {
					setup: function() {
						var attaches;
						leverageNative(this, type, true);
						if (document.documentMode) {
							attaches = dataPriv.get(this, delegateType);
							if (!attaches) this.addEventListener(delegateType, focusMappedHandler);
							dataPriv.set(this, delegateType, (attaches || 0) + 1);
						} else return false;
					},
					trigger: function() {
						leverageNative(this, type);
						return true;
					},
					teardown: function() {
						var attaches;
						if (document.documentMode) {
							attaches = dataPriv.get(this, delegateType) - 1;
							if (!attaches) {
								this.removeEventListener(delegateType, focusMappedHandler);
								dataPriv.remove(this, delegateType);
							} else dataPriv.set(this, delegateType, attaches);
						} else return false;
					},
					_default: function(event) {
						return dataPriv.get(event.target, type);
					},
					delegateType
				};
				jQuery.event.special[delegateType] = {
					setup: function() {
						var doc = this.ownerDocument || this.document || this, dataHolder = document.documentMode ? this : doc, attaches = dataPriv.get(dataHolder, delegateType);
						if (!attaches) if (document.documentMode) this.addEventListener(delegateType, focusMappedHandler);
						else doc.addEventListener(type, focusMappedHandler, true);
						dataPriv.set(dataHolder, delegateType, (attaches || 0) + 1);
					},
					teardown: function() {
						var doc = this.ownerDocument || this.document || this, dataHolder = document.documentMode ? this : doc, attaches = dataPriv.get(dataHolder, delegateType) - 1;
						if (!attaches) {
							if (document.documentMode) this.removeEventListener(delegateType, focusMappedHandler);
							else doc.removeEventListener(type, focusMappedHandler, true);
							dataPriv.remove(dataHolder, delegateType);
						} else dataPriv.set(dataHolder, delegateType, attaches);
					}
				};
			});
			jQuery.each({
				mouseenter: "mouseover",
				mouseleave: "mouseout",
				pointerenter: "pointerover",
				pointerleave: "pointerout"
			}, function(orig, fix) {
				jQuery.event.special[orig] = {
					delegateType: fix,
					bindType: fix,
					handle: function(event) {
						var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj;
						if (!related || related !== target && !jQuery.contains(target, related)) {
							event.type = handleObj.origType;
							ret = handleObj.handler.apply(this, arguments);
							event.type = fix;
						}
						return ret;
					}
				};
			});
			jQuery.fn.extend({
				on: function(types, selector, data, fn) {
					return on(this, types, selector, data, fn);
				},
				one: function(types, selector, data, fn) {
					return on(this, types, selector, data, fn, 1);
				},
				off: function(types, selector, fn) {
					var handleObj, type;
					if (types && types.preventDefault && types.handleObj) {
						handleObj = types.handleObj;
						jQuery(types.delegateTarget).off(handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler);
						return this;
					}
					if (typeof types === "object") {
						for (type in types) this.off(type, selector, types[type]);
						return this;
					}
					if (selector === false || typeof selector === "function") {
						fn = selector;
						selector = void 0;
					}
					if (fn === false) fn = returnFalse;
					return this.each(function() {
						jQuery.event.remove(this, types, fn, selector);
					});
				}
			});
			var rnoInnerhtml = /<script|<style|<link/i, rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, rcleanScript = /^\s*<!\[CDATA\[|\]\]>\s*$/g;
			function manipulationTarget(elem, content) {
				if (nodeName(elem, "table") && nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr")) return jQuery(elem).children("tbody")[0] || elem;
				return elem;
			}
			function disableScript(elem) {
				elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
				return elem;
			}
			function restoreScript(elem) {
				if ((elem.type || "").slice(0, 5) === "true/") elem.type = elem.type.slice(5);
				else elem.removeAttribute("type");
				return elem;
			}
			function cloneCopyEvent(src, dest) {
				var i, l, type, pdataOld, udataOld, udataCur, events;
				if (dest.nodeType !== 1) return;
				if (dataPriv.hasData(src)) {
					pdataOld = dataPriv.get(src);
					events = pdataOld.events;
					if (events) {
						dataPriv.remove(dest, "handle events");
						for (type in events) for (i = 0, l = events[type].length; i < l; i++) jQuery.event.add(dest, type, events[type][i]);
					}
				}
				if (dataUser.hasData(src)) {
					udataOld = dataUser.access(src);
					udataCur = jQuery.extend({}, udataOld);
					dataUser.set(dest, udataCur);
				}
			}
			function fixInput(src, dest) {
				var nodeName = dest.nodeName.toLowerCase();
				if (nodeName === "input" && rcheckableType.test(src.type)) dest.checked = src.checked;
				else if (nodeName === "input" || nodeName === "textarea") dest.defaultValue = src.defaultValue;
			}
			function domManip(collection, args, callback, ignored) {
				args = flat(args);
				var fragment, first, scripts, hasScripts, node, doc, i = 0, l = collection.length, iNoClone = l - 1, value = args[0], valueIsFunction = isFunction(value);
				if (valueIsFunction || l > 1 && typeof value === "string" && !support.checkClone && rchecked.test(value)) return collection.each(function(index) {
					var self = collection.eq(index);
					if (valueIsFunction) args[0] = value.call(this, index, self.html());
					domManip(self, args, callback, ignored);
				});
				if (l) {
					fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored);
					first = fragment.firstChild;
					if (fragment.childNodes.length === 1) fragment = first;
					if (first || ignored) {
						scripts = jQuery.map(getAll(fragment, "script"), disableScript);
						hasScripts = scripts.length;
						for (; i < l; i++) {
							node = fragment;
							if (i !== iNoClone) {
								node = jQuery.clone(node, true, true);
								if (hasScripts) jQuery.merge(scripts, getAll(node, "script"));
							}
							callback.call(collection[i], node, i);
						}
						if (hasScripts) {
							doc = scripts[scripts.length - 1].ownerDocument;
							jQuery.map(scripts, restoreScript);
							for (i = 0; i < hasScripts; i++) {
								node = scripts[i];
								if (rscriptType.test(node.type || "") && !dataPriv.access(node, "globalEval") && jQuery.contains(doc, node)) if (node.src && (node.type || "").toLowerCase() !== "module") {
									if (jQuery._evalUrl && !node.noModule) jQuery._evalUrl(node.src, { nonce: node.nonce || node.getAttribute("nonce") }, doc);
								} else DOMEval(node.textContent.replace(rcleanScript, ""), node, doc);
							}
						}
					}
				}
				return collection;
			}
			function remove(elem, selector, keepData) {
				var node, nodes = selector ? jQuery.filter(selector, elem) : elem, i = 0;
				for (; (node = nodes[i]) != null; i++) {
					if (!keepData && node.nodeType === 1) jQuery.cleanData(getAll(node));
					if (node.parentNode) {
						if (keepData && isAttached(node)) setGlobalEval(getAll(node, "script"));
						node.parentNode.removeChild(node);
					}
				}
				return elem;
			}
			jQuery.extend({
				htmlPrefilter: function(html) {
					return html;
				},
				clone: function(elem, dataAndEvents, deepDataAndEvents) {
					var i, l, srcElements, destElements, clone = elem.cloneNode(true), inPage = isAttached(elem);
					if (!support.noCloneChecked && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem)) {
						destElements = getAll(clone);
						srcElements = getAll(elem);
						for (i = 0, l = srcElements.length; i < l; i++) fixInput(srcElements[i], destElements[i]);
					}
					if (dataAndEvents) if (deepDataAndEvents) {
						srcElements = srcElements || getAll(elem);
						destElements = destElements || getAll(clone);
						for (i = 0, l = srcElements.length; i < l; i++) cloneCopyEvent(srcElements[i], destElements[i]);
					} else cloneCopyEvent(elem, clone);
					destElements = getAll(clone, "script");
					if (destElements.length > 0) setGlobalEval(destElements, !inPage && getAll(elem, "script"));
					return clone;
				},
				cleanData: function(elems) {
					var data, elem, type, special = jQuery.event.special, i = 0;
					for (; (elem = elems[i]) !== void 0; i++) if (acceptData(elem)) {
						if (data = elem[dataPriv.expando]) {
							if (data.events) for (type in data.events) if (special[type]) jQuery.event.remove(elem, type);
							else jQuery.removeEvent(elem, type, data.handle);
							elem[dataPriv.expando] = void 0;
						}
						if (elem[dataUser.expando]) elem[dataUser.expando] = void 0;
					}
				}
			});
			jQuery.fn.extend({
				detach: function(selector) {
					return remove(this, selector, true);
				},
				remove: function(selector) {
					return remove(this, selector);
				},
				text: function(value) {
					return access(this, function(value) {
						return value === void 0 ? jQuery.text(this) : this.empty().each(function() {
							if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) this.textContent = value;
						});
					}, null, value, arguments.length);
				},
				append: function() {
					return domManip(this, arguments, function(elem) {
						if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) manipulationTarget(this, elem).appendChild(elem);
					});
				},
				prepend: function() {
					return domManip(this, arguments, function(elem) {
						if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
							var target = manipulationTarget(this, elem);
							target.insertBefore(elem, target.firstChild);
						}
					});
				},
				before: function() {
					return domManip(this, arguments, function(elem) {
						if (this.parentNode) this.parentNode.insertBefore(elem, this);
					});
				},
				after: function() {
					return domManip(this, arguments, function(elem) {
						if (this.parentNode) this.parentNode.insertBefore(elem, this.nextSibling);
					});
				},
				empty: function() {
					var elem, i = 0;
					for (; (elem = this[i]) != null; i++) if (elem.nodeType === 1) {
						jQuery.cleanData(getAll(elem, false));
						elem.textContent = "";
					}
					return this;
				},
				clone: function(dataAndEvents, deepDataAndEvents) {
					dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
					deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
					return this.map(function() {
						return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
					});
				},
				html: function(value) {
					return access(this, function(value) {
						var elem = this[0] || {}, i = 0, l = this.length;
						if (value === void 0 && elem.nodeType === 1) return elem.innerHTML;
						if (typeof value === "string" && !rnoInnerhtml.test(value) && !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
							value = jQuery.htmlPrefilter(value);
							try {
								for (; i < l; i++) {
									elem = this[i] || {};
									if (elem.nodeType === 1) {
										jQuery.cleanData(getAll(elem, false));
										elem.innerHTML = value;
									}
								}
								elem = 0;
							} catch (e) {}
						}
						if (elem) this.empty().append(value);
					}, null, value, arguments.length);
				},
				replaceWith: function() {
					var ignored = [];
					return domManip(this, arguments, function(elem) {
						var parent = this.parentNode;
						if (jQuery.inArray(this, ignored) < 0) {
							jQuery.cleanData(getAll(this));
							if (parent) parent.replaceChild(elem, this);
						}
					}, ignored);
				}
			});
			jQuery.each({
				appendTo: "append",
				prependTo: "prepend",
				insertBefore: "before",
				insertAfter: "after",
				replaceAll: "replaceWith"
			}, function(name, original) {
				jQuery.fn[name] = function(selector) {
					var elems, ret = [], insert = jQuery(selector), last = insert.length - 1, i = 0;
					for (; i <= last; i++) {
						elems = i === last ? this : this.clone(true);
						jQuery(insert[i])[original](elems);
						push.apply(ret, elems.get());
					}
					return this.pushStack(ret);
				};
			});
			var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i");
			var rcustomProp = /^--/;
			var getStyles = function(elem) {
				var view = elem.ownerDocument.defaultView;
				if (!view || !view.opener) view = window;
				return view.getComputedStyle(elem);
			};
			var swap = function(elem, options, callback) {
				var ret, name, old = {};
				for (name in options) {
					old[name] = elem.style[name];
					elem.style[name] = options[name];
				}
				ret = callback.call(elem);
				for (name in options) elem.style[name] = old[name];
				return ret;
			};
			var rboxStyle = new RegExp(cssExpand.join("|"), "i");
			(function() {
				function computeStyleTests() {
					if (!div) return;
					container.style.cssText = "position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0";
					div.style.cssText = "position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%";
					documentElement.appendChild(container).appendChild(div);
					var divStyle = window.getComputedStyle(div);
					pixelPositionVal = divStyle.top !== "1%";
					reliableMarginLeftVal = roundPixelMeasures(divStyle.marginLeft) === 12;
					div.style.right = "60%";
					pixelBoxStylesVal = roundPixelMeasures(divStyle.right) === 36;
					boxSizingReliableVal = roundPixelMeasures(divStyle.width) === 36;
					div.style.position = "absolute";
					scrollboxSizeVal = roundPixelMeasures(div.offsetWidth / 3) === 12;
					documentElement.removeChild(container);
					div = null;
				}
				function roundPixelMeasures(measure) {
					return Math.round(parseFloat(measure));
				}
				var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, reliableTrDimensionsVal, reliableMarginLeftVal, container = document.createElement("div"), div = document.createElement("div");
				if (!div.style) return;
				div.style.backgroundClip = "content-box";
				div.cloneNode(true).style.backgroundClip = "";
				support.clearCloneStyle = div.style.backgroundClip === "content-box";
				jQuery.extend(support, {
					boxSizingReliable: function() {
						computeStyleTests();
						return boxSizingReliableVal;
					},
					pixelBoxStyles: function() {
						computeStyleTests();
						return pixelBoxStylesVal;
					},
					pixelPosition: function() {
						computeStyleTests();
						return pixelPositionVal;
					},
					reliableMarginLeft: function() {
						computeStyleTests();
						return reliableMarginLeftVal;
					},
					scrollboxSize: function() {
						computeStyleTests();
						return scrollboxSizeVal;
					},
					reliableTrDimensions: function() {
						var table, tr, trChild, trStyle;
						if (reliableTrDimensionsVal == null) {
							table = document.createElement("table");
							tr = document.createElement("tr");
							trChild = document.createElement("div");
							table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate";
							tr.style.cssText = "box-sizing:content-box;border:1px solid";
							tr.style.height = "1px";
							trChild.style.height = "9px";
							trChild.style.display = "block";
							documentElement.appendChild(table).appendChild(tr).appendChild(trChild);
							trStyle = window.getComputedStyle(tr);
							reliableTrDimensionsVal = parseInt(trStyle.height, 10) + parseInt(trStyle.borderTopWidth, 10) + parseInt(trStyle.borderBottomWidth, 10) === tr.offsetHeight;
							documentElement.removeChild(table);
						}
						return reliableTrDimensionsVal;
					}
				});
			})();
			function curCSS(elem, name, computed) {
				var width, minWidth, maxWidth, ret, isCustomProp = rcustomProp.test(name), style = elem.style;
				computed = computed || getStyles(elem);
				if (computed) {
					ret = computed.getPropertyValue(name) || computed[name];
					if (isCustomProp && ret) ret = ret.replace(rtrimCSS, "$1") || void 0;
					if (ret === "" && !isAttached(elem)) ret = jQuery.style(elem, name);
					if (!support.pixelBoxStyles() && rnumnonpx.test(ret) && rboxStyle.test(name)) {
						width = style.width;
						minWidth = style.minWidth;
						maxWidth = style.maxWidth;
						style.minWidth = style.maxWidth = style.width = ret;
						ret = computed.width;
						style.width = width;
						style.minWidth = minWidth;
						style.maxWidth = maxWidth;
					}
				}
				return ret !== void 0 ? ret + "" : ret;
			}
			function addGetHookIf(conditionFn, hookFn) {
				return { get: function() {
					if (conditionFn()) {
						delete this.get;
						return;
					}
					return (this.get = hookFn).apply(this, arguments);
				} };
			}
			var cssPrefixes = [
				"Webkit",
				"Moz",
				"ms"
			], emptyStyle = document.createElement("div").style, vendorProps = {};
			function vendorPropName(name) {
				var capName = name[0].toUpperCase() + name.slice(1), i = cssPrefixes.length;
				while (i--) {
					name = cssPrefixes[i] + capName;
					if (name in emptyStyle) return name;
				}
			}
			function finalPropName(name) {
				var final = jQuery.cssProps[name] || vendorProps[name];
				if (final) return final;
				if (name in emptyStyle) return name;
				return vendorProps[name] = vendorPropName(name) || name;
			}
			var rdisplayswap = /^(none|table(?!-c[ea]).+)/, cssShow = {
				position: "absolute",
				visibility: "hidden",
				display: "block"
			}, cssNormalTransform = {
				letterSpacing: "0",
				fontWeight: "400"
			};
			function setPositiveNumber(_elem, value, subtract) {
				var matches = rcssNum.exec(value);
				return matches ? Math.max(0, matches[2] - (subtract || 0)) + (matches[3] || "px") : value;
			}
			function boxModelAdjustment(elem, dimension, box, isBorderBox, styles, computedVal) {
				var i = dimension === "width" ? 1 : 0, extra = 0, delta = 0, marginDelta = 0;
				if (box === (isBorderBox ? "border" : "content")) return 0;
				for (; i < 4; i += 2) {
					if (box === "margin") marginDelta += jQuery.css(elem, box + cssExpand[i], true, styles);
					if (!isBorderBox) {
						delta += jQuery.css(elem, "padding" + cssExpand[i], true, styles);
						if (box !== "padding") delta += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
						else extra += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
					} else {
						if (box === "content") delta -= jQuery.css(elem, "padding" + cssExpand[i], true, styles);
						if (box !== "margin") delta -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
					}
				}
				if (!isBorderBox && computedVal >= 0) delta += Math.max(0, Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - computedVal - delta - extra - .5)) || 0;
				return delta + marginDelta;
			}
			function getWidthOrHeight(elem, dimension, extra) {
				var styles = getStyles(elem), isBorderBox = (!support.boxSizingReliable() || extra) && jQuery.css(elem, "boxSizing", false, styles) === "border-box", valueIsBorderBox = isBorderBox, val = curCSS(elem, dimension, styles), offsetProp = "offset" + dimension[0].toUpperCase() + dimension.slice(1);
				if (rnumnonpx.test(val)) {
					if (!extra) return val;
					val = "auto";
				}
				if ((!support.boxSizingReliable() && isBorderBox || !support.reliableTrDimensions() && nodeName(elem, "tr") || val === "auto" || !parseFloat(val) && jQuery.css(elem, "display", false, styles) === "inline") && elem.getClientRects().length) {
					isBorderBox = jQuery.css(elem, "boxSizing", false, styles) === "border-box";
					valueIsBorderBox = offsetProp in elem;
					if (valueIsBorderBox) val = elem[offsetProp];
				}
				val = parseFloat(val) || 0;
				return val + boxModelAdjustment(elem, dimension, extra || (isBorderBox ? "border" : "content"), valueIsBorderBox, styles, val) + "px";
			}
			jQuery.extend({
				cssHooks: { opacity: { get: function(elem, computed) {
					if (computed) {
						var ret = curCSS(elem, "opacity");
						return ret === "" ? "1" : ret;
					}
				} } },
				cssNumber: {
					animationIterationCount: true,
					aspectRatio: true,
					borderImageSlice: true,
					columnCount: true,
					flexGrow: true,
					flexShrink: true,
					fontWeight: true,
					gridArea: true,
					gridColumn: true,
					gridColumnEnd: true,
					gridColumnStart: true,
					gridRow: true,
					gridRowEnd: true,
					gridRowStart: true,
					lineHeight: true,
					opacity: true,
					order: true,
					orphans: true,
					scale: true,
					widows: true,
					zIndex: true,
					zoom: true,
					fillOpacity: true,
					floodOpacity: true,
					stopOpacity: true,
					strokeMiterlimit: true,
					strokeOpacity: true
				},
				cssProps: {},
				style: function(elem, name, value, extra) {
					if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) return;
					var ret, type, hooks, origName = camelCase(name), isCustomProp = rcustomProp.test(name), style = elem.style;
					if (!isCustomProp) name = finalPropName(origName);
					hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
					if (value !== void 0) {
						type = typeof value;
						if (type === "string" && (ret = rcssNum.exec(value)) && ret[1]) {
							value = adjustCSS(elem, name, ret);
							type = "number";
						}
						if (value == null || value !== value) return;
						if (type === "number" && !isCustomProp) value += ret && ret[3] || (jQuery.cssNumber[origName] ? "" : "px");
						if (!support.clearCloneStyle && value === "" && name.indexOf("background") === 0) style[name] = "inherit";
						if (!hooks || !("set" in hooks) || (value = hooks.set(elem, value, extra)) !== void 0) if (isCustomProp) style.setProperty(name, value);
						else style[name] = value;
					} else {
						if (hooks && "get" in hooks && (ret = hooks.get(elem, false, extra)) !== void 0) return ret;
						return style[name];
					}
				},
				css: function(elem, name, extra, styles) {
					var val, num, hooks, origName = camelCase(name);
					if (!rcustomProp.test(name)) name = finalPropName(origName);
					hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
					if (hooks && "get" in hooks) val = hooks.get(elem, true, extra);
					if (val === void 0) val = curCSS(elem, name, styles);
					if (val === "normal" && name in cssNormalTransform) val = cssNormalTransform[name];
					if (extra === "" || extra) {
						num = parseFloat(val);
						return extra === true || isFinite(num) ? num || 0 : val;
					}
					return val;
				}
			});
			jQuery.each(["height", "width"], function(_i, dimension) {
				jQuery.cssHooks[dimension] = {
					get: function(elem, computed, extra) {
						if (computed) return rdisplayswap.test(jQuery.css(elem, "display")) && (!elem.getClientRects().length || !elem.getBoundingClientRect().width) ? swap(elem, cssShow, function() {
							return getWidthOrHeight(elem, dimension, extra);
						}) : getWidthOrHeight(elem, dimension, extra);
					},
					set: function(elem, value, extra) {
						var matches, styles = getStyles(elem), scrollboxSizeBuggy = !support.scrollboxSize() && styles.position === "absolute", isBorderBox = (scrollboxSizeBuggy || extra) && jQuery.css(elem, "boxSizing", false, styles) === "border-box", subtract = extra ? boxModelAdjustment(elem, dimension, extra, isBorderBox, styles) : 0;
						if (isBorderBox && scrollboxSizeBuggy) subtract -= Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - parseFloat(styles[dimension]) - boxModelAdjustment(elem, dimension, "border", false, styles) - .5);
						if (subtract && (matches = rcssNum.exec(value)) && (matches[3] || "px") !== "px") {
							elem.style[dimension] = value;
							value = jQuery.css(elem, dimension);
						}
						return setPositiveNumber(elem, value, subtract);
					}
				};
			});
			jQuery.cssHooks.marginLeft = addGetHookIf(support.reliableMarginLeft, function(elem, computed) {
				if (computed) return (parseFloat(curCSS(elem, "marginLeft")) || elem.getBoundingClientRect().left - swap(elem, { marginLeft: 0 }, function() {
					return elem.getBoundingClientRect().left;
				})) + "px";
			});
			jQuery.each({
				margin: "",
				padding: "",
				border: "Width"
			}, function(prefix, suffix) {
				jQuery.cssHooks[prefix + suffix] = { expand: function(value) {
					var i = 0, expanded = {}, parts = typeof value === "string" ? value.split(" ") : [value];
					for (; i < 4; i++) expanded[prefix + cssExpand[i] + suffix] = parts[i] || parts[i - 2] || parts[0];
					return expanded;
				} };
				if (prefix !== "margin") jQuery.cssHooks[prefix + suffix].set = setPositiveNumber;
			});
			jQuery.fn.extend({ css: function(name, value) {
				return access(this, function(elem, name, value) {
					var styles, len, map = {}, i = 0;
					if (Array.isArray(name)) {
						styles = getStyles(elem);
						len = name.length;
						for (; i < len; i++) map[name[i]] = jQuery.css(elem, name[i], false, styles);
						return map;
					}
					return value !== void 0 ? jQuery.style(elem, name, value) : jQuery.css(elem, name);
				}, name, value, arguments.length > 1);
			} });
			function Tween(elem, options, prop, end, easing) {
				return new Tween.prototype.init(elem, options, prop, end, easing);
			}
			jQuery.Tween = Tween;
			Tween.prototype = {
				constructor: Tween,
				init: function(elem, options, prop, end, easing, unit) {
					this.elem = elem;
					this.prop = prop;
					this.easing = easing || jQuery.easing._default;
					this.options = options;
					this.start = this.now = this.cur();
					this.end = end;
					this.unit = unit || (jQuery.cssNumber[prop] ? "" : "px");
				},
				cur: function() {
					var hooks = Tween.propHooks[this.prop];
					return hooks && hooks.get ? hooks.get(this) : Tween.propHooks._default.get(this);
				},
				run: function(percent) {
					var eased, hooks = Tween.propHooks[this.prop];
					if (this.options.duration) this.pos = eased = jQuery.easing[this.easing](percent, this.options.duration * percent, 0, 1, this.options.duration);
					else this.pos = eased = percent;
					this.now = (this.end - this.start) * eased + this.start;
					if (this.options.step) this.options.step.call(this.elem, this.now, this);
					if (hooks && hooks.set) hooks.set(this);
					else Tween.propHooks._default.set(this);
					return this;
				}
			};
			Tween.prototype.init.prototype = Tween.prototype;
			Tween.propHooks = { _default: {
				get: function(tween) {
					var result;
					if (tween.elem.nodeType !== 1 || tween.elem[tween.prop] != null && tween.elem.style[tween.prop] == null) return tween.elem[tween.prop];
					result = jQuery.css(tween.elem, tween.prop, "");
					return !result || result === "auto" ? 0 : result;
				},
				set: function(tween) {
					if (jQuery.fx.step[tween.prop]) jQuery.fx.step[tween.prop](tween);
					else if (tween.elem.nodeType === 1 && (jQuery.cssHooks[tween.prop] || tween.elem.style[finalPropName(tween.prop)] != null)) jQuery.style(tween.elem, tween.prop, tween.now + tween.unit);
					else tween.elem[tween.prop] = tween.now;
				}
			} };
			Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { set: function(tween) {
				if (tween.elem.nodeType && tween.elem.parentNode) tween.elem[tween.prop] = tween.now;
			} };
			jQuery.easing = {
				linear: function(p) {
					return p;
				},
				swing: function(p) {
					return .5 - Math.cos(p * Math.PI) / 2;
				},
				_default: "swing"
			};
			jQuery.fx = Tween.prototype.init;
			jQuery.fx.step = {};
			var fxNow, inProgress, rfxtypes = /^(?:toggle|show|hide)$/, rrun = /queueHooks$/;
			function schedule() {
				if (inProgress) {
					if (document.hidden === false && window.requestAnimationFrame) window.requestAnimationFrame(schedule);
					else window.setTimeout(schedule, jQuery.fx.interval);
					jQuery.fx.tick();
				}
			}
			function createFxNow() {
				window.setTimeout(function() {
					fxNow = void 0;
				});
				return fxNow = Date.now();
			}
			function genFx(type, includeWidth) {
				var which, i = 0, attrs = { height: type };
				includeWidth = includeWidth ? 1 : 0;
				for (; i < 4; i += 2 - includeWidth) {
					which = cssExpand[i];
					attrs["margin" + which] = attrs["padding" + which] = type;
				}
				if (includeWidth) attrs.opacity = attrs.width = type;
				return attrs;
			}
			function createTween(value, prop, animation) {
				var tween, collection = (Animation.tweeners[prop] || []).concat(Animation.tweeners["*"]), index = 0, length = collection.length;
				for (; index < length; index++) if (tween = collection[index].call(animation, prop, value)) return tween;
			}
			function defaultPrefilter(elem, props, opts) {
				var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, isBox = "width" in props || "height" in props, anim = this, orig = {}, style = elem.style, hidden = elem.nodeType && isHiddenWithinTree(elem), dataShow = dataPriv.get(elem, "fxshow");
				if (!opts.queue) {
					hooks = jQuery._queueHooks(elem, "fx");
					if (hooks.unqueued == null) {
						hooks.unqueued = 0;
						oldfire = hooks.empty.fire;
						hooks.empty.fire = function() {
							if (!hooks.unqueued) oldfire();
						};
					}
					hooks.unqueued++;
					anim.always(function() {
						anim.always(function() {
							hooks.unqueued--;
							if (!jQuery.queue(elem, "fx").length) hooks.empty.fire();
						});
					});
				}
				for (prop in props) {
					value = props[prop];
					if (rfxtypes.test(value)) {
						delete props[prop];
						toggle = toggle || value === "toggle";
						if (value === (hidden ? "hide" : "show")) if (value === "show" && dataShow && dataShow[prop] !== void 0) hidden = true;
						else continue;
						orig[prop] = dataShow && dataShow[prop] || jQuery.style(elem, prop);
					}
				}
				propTween = !jQuery.isEmptyObject(props);
				if (!propTween && jQuery.isEmptyObject(orig)) return;
				if (isBox && elem.nodeType === 1) {
					opts.overflow = [
						style.overflow,
						style.overflowX,
						style.overflowY
					];
					restoreDisplay = dataShow && dataShow.display;
					if (restoreDisplay == null) restoreDisplay = dataPriv.get(elem, "display");
					display = jQuery.css(elem, "display");
					if (display === "none") if (restoreDisplay) display = restoreDisplay;
					else {
						showHide([elem], true);
						restoreDisplay = elem.style.display || restoreDisplay;
						display = jQuery.css(elem, "display");
						showHide([elem]);
					}
					if (display === "inline" || display === "inline-block" && restoreDisplay != null) {
						if (jQuery.css(elem, "float") === "none") {
							if (!propTween) {
								anim.done(function() {
									style.display = restoreDisplay;
								});
								if (restoreDisplay == null) {
									display = style.display;
									restoreDisplay = display === "none" ? "" : display;
								}
							}
							style.display = "inline-block";
						}
					}
				}
				if (opts.overflow) {
					style.overflow = "hidden";
					anim.always(function() {
						style.overflow = opts.overflow[0];
						style.overflowX = opts.overflow[1];
						style.overflowY = opts.overflow[2];
					});
				}
				propTween = false;
				for (prop in orig) {
					if (!propTween) {
						if (dataShow) {
							if ("hidden" in dataShow) hidden = dataShow.hidden;
						} else dataShow = dataPriv.access(elem, "fxshow", { display: restoreDisplay });
						if (toggle) dataShow.hidden = !hidden;
						if (hidden) showHide([elem], true);
						anim.done(function() {
							if (!hidden) showHide([elem]);
							dataPriv.remove(elem, "fxshow");
							for (prop in orig) jQuery.style(elem, prop, orig[prop]);
						});
					}
					propTween = createTween(hidden ? dataShow[prop] : 0, prop, anim);
					if (!(prop in dataShow)) {
						dataShow[prop] = propTween.start;
						if (hidden) {
							propTween.end = propTween.start;
							propTween.start = 0;
						}
					}
				}
			}
			function propFilter(props, specialEasing) {
				var index, name, easing, value, hooks;
				for (index in props) {
					name = camelCase(index);
					easing = specialEasing[name];
					value = props[index];
					if (Array.isArray(value)) {
						easing = value[1];
						value = props[index] = value[0];
					}
					if (index !== name) {
						props[name] = value;
						delete props[index];
					}
					hooks = jQuery.cssHooks[name];
					if (hooks && "expand" in hooks) {
						value = hooks.expand(value);
						delete props[name];
						for (index in value) if (!(index in props)) {
							props[index] = value[index];
							specialEasing[index] = easing;
						}
					} else specialEasing[name] = easing;
				}
			}
			function Animation(elem, properties, options) {
				var result, stopped, index = 0, length = Animation.prefilters.length, deferred = jQuery.Deferred().always(function() {
					delete tick.elem;
				}), tick = function() {
					if (stopped) return false;
					var currentTime = fxNow || createFxNow(), remaining = Math.max(0, animation.startTime + animation.duration - currentTime), percent = 1 - (remaining / animation.duration || 0), index = 0, length = animation.tweens.length;
					for (; index < length; index++) animation.tweens[index].run(percent);
					deferred.notifyWith(elem, [
						animation,
						percent,
						remaining
					]);
					if (percent < 1 && length) return remaining;
					if (!length) deferred.notifyWith(elem, [
						animation,
						1,
						0
					]);
					deferred.resolveWith(elem, [animation]);
					return false;
				}, animation = deferred.promise({
					elem,
					props: jQuery.extend({}, properties),
					opts: jQuery.extend(true, {
						specialEasing: {},
						easing: jQuery.easing._default
					}, options),
					originalProperties: properties,
					originalOptions: options,
					startTime: fxNow || createFxNow(),
					duration: options.duration,
					tweens: [],
					createTween: function(prop, end) {
						var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing);
						animation.tweens.push(tween);
						return tween;
					},
					stop: function(gotoEnd) {
						var index = 0, length = gotoEnd ? animation.tweens.length : 0;
						if (stopped) return this;
						stopped = true;
						for (; index < length; index++) animation.tweens[index].run(1);
						if (gotoEnd) {
							deferred.notifyWith(elem, [
								animation,
								1,
								0
							]);
							deferred.resolveWith(elem, [animation, gotoEnd]);
						} else deferred.rejectWith(elem, [animation, gotoEnd]);
						return this;
					}
				}), props = animation.props;
				propFilter(props, animation.opts.specialEasing);
				for (; index < length; index++) {
					result = Animation.prefilters[index].call(animation, elem, props, animation.opts);
					if (result) {
						if (isFunction(result.stop)) jQuery._queueHooks(animation.elem, animation.opts.queue).stop = result.stop.bind(result);
						return result;
					}
				}
				jQuery.map(props, createTween, animation);
				if (isFunction(animation.opts.start)) animation.opts.start.call(elem, animation);
				animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always);
				jQuery.fx.timer(jQuery.extend(tick, {
					elem,
					anim: animation,
					queue: animation.opts.queue
				}));
				return animation;
			}
			jQuery.Animation = jQuery.extend(Animation, {
				tweeners: { "*": [function(prop, value) {
					var tween = this.createTween(prop, value);
					adjustCSS(tween.elem, prop, rcssNum.exec(value), tween);
					return tween;
				}] },
				tweener: function(props, callback) {
					if (isFunction(props)) {
						callback = props;
						props = ["*"];
					} else props = props.match(rnothtmlwhite);
					var prop, index = 0, length = props.length;
					for (; index < length; index++) {
						prop = props[index];
						Animation.tweeners[prop] = Animation.tweeners[prop] || [];
						Animation.tweeners[prop].unshift(callback);
					}
				},
				prefilters: [defaultPrefilter],
				prefilter: function(callback, prepend) {
					if (prepend) Animation.prefilters.unshift(callback);
					else Animation.prefilters.push(callback);
				}
			});
			jQuery.speed = function(speed, easing, fn) {
				var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
					complete: fn || !fn && easing || isFunction(speed) && speed,
					duration: speed,
					easing: fn && easing || easing && !isFunction(easing) && easing
				};
				if (jQuery.fx.off) opt.duration = 0;
				else if (typeof opt.duration !== "number") if (opt.duration in jQuery.fx.speeds) opt.duration = jQuery.fx.speeds[opt.duration];
				else opt.duration = jQuery.fx.speeds._default;
				if (opt.queue == null || opt.queue === true) opt.queue = "fx";
				opt.old = opt.complete;
				opt.complete = function() {
					if (isFunction(opt.old)) opt.old.call(this);
					if (opt.queue) jQuery.dequeue(this, opt.queue);
				};
				return opt;
			};
			jQuery.fn.extend({
				fadeTo: function(speed, to, easing, callback) {
					return this.filter(isHiddenWithinTree).css("opacity", 0).show().end().animate({ opacity: to }, speed, easing, callback);
				},
				animate: function(prop, speed, easing, callback) {
					var empty = jQuery.isEmptyObject(prop), optall = jQuery.speed(speed, easing, callback), doAnimation = function() {
						var anim = Animation(this, jQuery.extend({}, prop), optall);
						if (empty || dataPriv.get(this, "finish")) anim.stop(true);
					};
					doAnimation.finish = doAnimation;
					return empty || optall.queue === false ? this.each(doAnimation) : this.queue(optall.queue, doAnimation);
				},
				stop: function(type, clearQueue, gotoEnd) {
					var stopQueue = function(hooks) {
						var stop = hooks.stop;
						delete hooks.stop;
						stop(gotoEnd);
					};
					if (typeof type !== "string") {
						gotoEnd = clearQueue;
						clearQueue = type;
						type = void 0;
					}
					if (clearQueue) this.queue(type || "fx", []);
					return this.each(function() {
						var dequeue = true, index = type != null && type + "queueHooks", timers = jQuery.timers, data = dataPriv.get(this);
						if (index) {
							if (data[index] && data[index].stop) stopQueue(data[index]);
						} else for (index in data) if (data[index] && data[index].stop && rrun.test(index)) stopQueue(data[index]);
						for (index = timers.length; index--;) if (timers[index].elem === this && (type == null || timers[index].queue === type)) {
							timers[index].anim.stop(gotoEnd);
							dequeue = false;
							timers.splice(index, 1);
						}
						if (dequeue || !gotoEnd) jQuery.dequeue(this, type);
					});
				},
				finish: function(type) {
					if (type !== false) type = type || "fx";
					return this.each(function() {
						var index, data = dataPriv.get(this), queue = data[type + "queue"], hooks = data[type + "queueHooks"], timers = jQuery.timers, length = queue ? queue.length : 0;
						data.finish = true;
						jQuery.queue(this, type, []);
						if (hooks && hooks.stop) hooks.stop.call(this, true);
						for (index = timers.length; index--;) if (timers[index].elem === this && timers[index].queue === type) {
							timers[index].anim.stop(true);
							timers.splice(index, 1);
						}
						for (index = 0; index < length; index++) if (queue[index] && queue[index].finish) queue[index].finish.call(this);
						delete data.finish;
					});
				}
			});
			jQuery.each([
				"toggle",
				"show",
				"hide"
			], function(_i, name) {
				var cssFn = jQuery.fn[name];
				jQuery.fn[name] = function(speed, easing, callback) {
					return speed == null || typeof speed === "boolean" ? cssFn.apply(this, arguments) : this.animate(genFx(name, true), speed, easing, callback);
				};
			});
			jQuery.each({
				slideDown: genFx("show"),
				slideUp: genFx("hide"),
				slideToggle: genFx("toggle"),
				fadeIn: { opacity: "show" },
				fadeOut: { opacity: "hide" },
				fadeToggle: { opacity: "toggle" }
			}, function(name, props) {
				jQuery.fn[name] = function(speed, easing, callback) {
					return this.animate(props, speed, easing, callback);
				};
			});
			jQuery.timers = [];
			jQuery.fx.tick = function() {
				var timer, i = 0, timers = jQuery.timers;
				fxNow = Date.now();
				for (; i < timers.length; i++) {
					timer = timers[i];
					if (!timer() && timers[i] === timer) timers.splice(i--, 1);
				}
				if (!timers.length) jQuery.fx.stop();
				fxNow = void 0;
			};
			jQuery.fx.timer = function(timer) {
				jQuery.timers.push(timer);
				jQuery.fx.start();
			};
			jQuery.fx.interval = 13;
			jQuery.fx.start = function() {
				if (inProgress) return;
				inProgress = true;
				schedule();
			};
			jQuery.fx.stop = function() {
				inProgress = null;
			};
			jQuery.fx.speeds = {
				slow: 600,
				fast: 200,
				_default: 400
			};
			jQuery.fn.delay = function(time, type) {
				time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
				type = type || "fx";
				return this.queue(type, function(next, hooks) {
					var timeout = window.setTimeout(next, time);
					hooks.stop = function() {
						window.clearTimeout(timeout);
					};
				});
			};
			(function() {
				var input = document.createElement("input"), opt = document.createElement("select").appendChild(document.createElement("option"));
				input.type = "checkbox";
				support.checkOn = input.value !== "";
				support.optSelected = opt.selected;
				input = document.createElement("input");
				input.value = "t";
				input.type = "radio";
				support.radioValue = input.value === "t";
			})();
			var boolHook, attrHandle = jQuery.expr.attrHandle;
			jQuery.fn.extend({
				attr: function(name, value) {
					return access(this, jQuery.attr, name, value, arguments.length > 1);
				},
				removeAttr: function(name) {
					return this.each(function() {
						jQuery.removeAttr(this, name);
					});
				}
			});
			jQuery.extend({
				attr: function(elem, name, value) {
					var ret, hooks, nType = elem.nodeType;
					if (nType === 3 || nType === 8 || nType === 2) return;
					if (typeof elem.getAttribute === "undefined") return jQuery.prop(elem, name, value);
					if (nType !== 1 || !jQuery.isXMLDoc(elem)) hooks = jQuery.attrHooks[name.toLowerCase()] || (jQuery.expr.match.bool.test(name) ? boolHook : void 0);
					if (value !== void 0) {
						if (value === null) {
							jQuery.removeAttr(elem, name);
							return;
						}
						if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== void 0) return ret;
						elem.setAttribute(name, value + "");
						return value;
					}
					if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) return ret;
					ret = jQuery.find.attr(elem, name);
					return ret == null ? void 0 : ret;
				},
				attrHooks: { type: { set: function(elem, value) {
					if (!support.radioValue && value === "radio" && nodeName(elem, "input")) {
						var val = elem.value;
						elem.setAttribute("type", value);
						if (val) elem.value = val;
						return value;
					}
				} } },
				removeAttr: function(elem, value) {
					var name, i = 0, attrNames = value && value.match(rnothtmlwhite);
					if (attrNames && elem.nodeType === 1) while (name = attrNames[i++]) elem.removeAttribute(name);
				}
			});
			boolHook = { set: function(elem, value, name) {
				if (value === false) jQuery.removeAttr(elem, name);
				else elem.setAttribute(name, name);
				return name;
			} };
			jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function(_i, name) {
				var getter = attrHandle[name] || jQuery.find.attr;
				attrHandle[name] = function(elem, name, isXML) {
					var ret, handle, lowercaseName = name.toLowerCase();
					if (!isXML) {
						handle = attrHandle[lowercaseName];
						attrHandle[lowercaseName] = ret;
						ret = getter(elem, name, isXML) != null ? lowercaseName : null;
						attrHandle[lowercaseName] = handle;
					}
					return ret;
				};
			});
			var rfocusable = /^(?:input|select|textarea|button)$/i, rclickable = /^(?:a|area)$/i;
			jQuery.fn.extend({
				prop: function(name, value) {
					return access(this, jQuery.prop, name, value, arguments.length > 1);
				},
				removeProp: function(name) {
					return this.each(function() {
						delete this[jQuery.propFix[name] || name];
					});
				}
			});
			jQuery.extend({
				prop: function(elem, name, value) {
					var ret, hooks, nType = elem.nodeType;
					if (nType === 3 || nType === 8 || nType === 2) return;
					if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
						name = jQuery.propFix[name] || name;
						hooks = jQuery.propHooks[name];
					}
					if (value !== void 0) {
						if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== void 0) return ret;
						return elem[name] = value;
					}
					if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) return ret;
					return elem[name];
				},
				propHooks: { tabIndex: { get: function(elem) {
					var tabindex = jQuery.find.attr(elem, "tabindex");
					if (tabindex) return parseInt(tabindex, 10);
					if (rfocusable.test(elem.nodeName) || rclickable.test(elem.nodeName) && elem.href) return 0;
					return -1;
				} } },
				propFix: {
					"for": "htmlFor",
					"class": "className"
				}
			});
			if (!support.optSelected) jQuery.propHooks.selected = {
				get: function(elem) {
					var parent = elem.parentNode;
					if (parent && parent.parentNode) parent.parentNode.selectedIndex;
					return null;
				},
				set: function(elem) {
					var parent = elem.parentNode;
					if (parent) {
						parent.selectedIndex;
						if (parent.parentNode) parent.parentNode.selectedIndex;
					}
				}
			};
			jQuery.each([
				"tabIndex",
				"readOnly",
				"maxLength",
				"cellSpacing",
				"cellPadding",
				"rowSpan",
				"colSpan",
				"useMap",
				"frameBorder",
				"contentEditable"
			], function() {
				jQuery.propFix[this.toLowerCase()] = this;
			});
			function stripAndCollapse(value) {
				return (value.match(rnothtmlwhite) || []).join(" ");
			}
			function getClass(elem) {
				return elem.getAttribute && elem.getAttribute("class") || "";
			}
			function classesToArray(value) {
				if (Array.isArray(value)) return value;
				if (typeof value === "string") return value.match(rnothtmlwhite) || [];
				return [];
			}
			jQuery.fn.extend({
				addClass: function(value) {
					var classNames, cur, curValue, className, i, finalValue;
					if (isFunction(value)) return this.each(function(j) {
						jQuery(this).addClass(value.call(this, j, getClass(this)));
					});
					classNames = classesToArray(value);
					if (classNames.length) return this.each(function() {
						curValue = getClass(this);
						cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
						if (cur) {
							for (i = 0; i < classNames.length; i++) {
								className = classNames[i];
								if (cur.indexOf(" " + className + " ") < 0) cur += className + " ";
							}
							finalValue = stripAndCollapse(cur);
							if (curValue !== finalValue) this.setAttribute("class", finalValue);
						}
					});
					return this;
				},
				removeClass: function(value) {
					var classNames, cur, curValue, className, i, finalValue;
					if (isFunction(value)) return this.each(function(j) {
						jQuery(this).removeClass(value.call(this, j, getClass(this)));
					});
					if (!arguments.length) return this.attr("class", "");
					classNames = classesToArray(value);
					if (classNames.length) return this.each(function() {
						curValue = getClass(this);
						cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
						if (cur) {
							for (i = 0; i < classNames.length; i++) {
								className = classNames[i];
								while (cur.indexOf(" " + className + " ") > -1) cur = cur.replace(" " + className + " ", " ");
							}
							finalValue = stripAndCollapse(cur);
							if (curValue !== finalValue) this.setAttribute("class", finalValue);
						}
					});
					return this;
				},
				toggleClass: function(value, stateVal) {
					var classNames, className, i, self, type = typeof value, isValidValue = type === "string" || Array.isArray(value);
					if (isFunction(value)) return this.each(function(i) {
						jQuery(this).toggleClass(value.call(this, i, getClass(this), stateVal), stateVal);
					});
					if (typeof stateVal === "boolean" && isValidValue) return stateVal ? this.addClass(value) : this.removeClass(value);
					classNames = classesToArray(value);
					return this.each(function() {
						if (isValidValue) {
							self = jQuery(this);
							for (i = 0; i < classNames.length; i++) {
								className = classNames[i];
								if (self.hasClass(className)) self.removeClass(className);
								else self.addClass(className);
							}
						} else if (value === void 0 || type === "boolean") {
							className = getClass(this);
							if (className) dataPriv.set(this, "__className__", className);
							if (this.setAttribute) this.setAttribute("class", className || value === false ? "" : dataPriv.get(this, "__className__") || "");
						}
					});
				},
				hasClass: function(selector) {
					var className, elem, i = 0;
					className = " " + selector + " ";
					while (elem = this[i++]) if (elem.nodeType === 1 && (" " + stripAndCollapse(getClass(elem)) + " ").indexOf(className) > -1) return true;
					return false;
				}
			});
			var rreturn = /\r/g;
			jQuery.fn.extend({ val: function(value) {
				var hooks, ret, valueIsFunction, elem = this[0];
				if (!arguments.length) {
					if (elem) {
						hooks = jQuery.valHooks[elem.type] || jQuery.valHooks[elem.nodeName.toLowerCase()];
						if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== void 0) return ret;
						ret = elem.value;
						if (typeof ret === "string") return ret.replace(rreturn, "");
						return ret == null ? "" : ret;
					}
					return;
				}
				valueIsFunction = isFunction(value);
				return this.each(function(i) {
					var val;
					if (this.nodeType !== 1) return;
					if (valueIsFunction) val = value.call(this, i, jQuery(this).val());
					else val = value;
					if (val == null) val = "";
					else if (typeof val === "number") val += "";
					else if (Array.isArray(val)) val = jQuery.map(val, function(value) {
						return value == null ? "" : value + "";
					});
					hooks = jQuery.valHooks[this.type] || jQuery.valHooks[this.nodeName.toLowerCase()];
					if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === void 0) this.value = val;
				});
			} });
			jQuery.extend({ valHooks: {
				option: { get: function(elem) {
					var val = jQuery.find.attr(elem, "value");
					return val != null ? val : stripAndCollapse(jQuery.text(elem));
				} },
				select: {
					get: function(elem) {
						var value, option, i, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one", values = one ? null : [], max = one ? index + 1 : options.length;
						if (index < 0) i = max;
						else i = one ? index : 0;
						for (; i < max; i++) {
							option = options[i];
							if ((option.selected || i === index) && !option.disabled && (!option.parentNode.disabled || !nodeName(option.parentNode, "optgroup"))) {
								value = jQuery(option).val();
								if (one) return value;
								values.push(value);
							}
						}
						return values;
					},
					set: function(elem, value) {
						var optionSet, option, options = elem.options, values = jQuery.makeArray(value), i = options.length;
						while (i--) {
							option = options[i];
							if (option.selected = jQuery.inArray(jQuery.valHooks.option.get(option), values) > -1) optionSet = true;
						}
						if (!optionSet) elem.selectedIndex = -1;
						return values;
					}
				}
			} });
			jQuery.each(["radio", "checkbox"], function() {
				jQuery.valHooks[this] = { set: function(elem, value) {
					if (Array.isArray(value)) return elem.checked = jQuery.inArray(jQuery(elem).val(), value) > -1;
				} };
				if (!support.checkOn) jQuery.valHooks[this].get = function(elem) {
					return elem.getAttribute("value") === null ? "on" : elem.value;
				};
			});
			var location = window.location;
			var nonce = { guid: Date.now() };
			var rquery = /\?/;
			jQuery.parseXML = function(data) {
				var xml, parserErrorElem;
				if (!data || typeof data !== "string") return null;
				try {
					xml = new window.DOMParser().parseFromString(data, "text/xml");
				} catch (e) {}
				parserErrorElem = xml && xml.getElementsByTagName("parsererror")[0];
				if (!xml || parserErrorElem) jQuery.error("Invalid XML: " + (parserErrorElem ? jQuery.map(parserErrorElem.childNodes, function(el) {
					return el.textContent;
				}).join("\n") : data));
				return xml;
			};
			var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, stopPropagationCallback = function(e) {
				e.stopPropagation();
			};
			jQuery.extend(jQuery.event, {
				trigger: function(event, data, elem, onlyHandlers) {
					var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, eventPath = [elem || document], type = hasOwn.call(event, "type") ? event.type : event, namespaces = hasOwn.call(event, "namespace") ? event.namespace.split(".") : [];
					cur = lastElement = tmp = elem = elem || document;
					if (elem.nodeType === 3 || elem.nodeType === 8) return;
					if (rfocusMorph.test(type + jQuery.event.triggered)) return;
					if (type.indexOf(".") > -1) {
						namespaces = type.split(".");
						type = namespaces.shift();
						namespaces.sort();
					}
					ontype = type.indexOf(":") < 0 && "on" + type;
					event = event[jQuery.expando] ? event : new jQuery.Event(type, typeof event === "object" && event);
					event.isTrigger = onlyHandlers ? 2 : 3;
					event.namespace = namespaces.join(".");
					event.rnamespace = event.namespace ? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
					event.result = void 0;
					if (!event.target) event.target = elem;
					data = data == null ? [event] : jQuery.makeArray(data, [event]);
					special = jQuery.event.special[type] || {};
					if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) return;
					if (!onlyHandlers && !special.noBubble && !isWindow(elem)) {
						bubbleType = special.delegateType || type;
						if (!rfocusMorph.test(bubbleType + type)) cur = cur.parentNode;
						for (; cur; cur = cur.parentNode) {
							eventPath.push(cur);
							tmp = cur;
						}
						if (tmp === (elem.ownerDocument || document)) eventPath.push(tmp.defaultView || tmp.parentWindow || window);
					}
					i = 0;
					while ((cur = eventPath[i++]) && !event.isPropagationStopped()) {
						lastElement = cur;
						event.type = i > 1 ? bubbleType : special.bindType || type;
						handle = (dataPriv.get(cur, "events") || Object.create(null))[event.type] && dataPriv.get(cur, "handle");
						if (handle) handle.apply(cur, data);
						handle = ontype && cur[ontype];
						if (handle && handle.apply && acceptData(cur)) {
							event.result = handle.apply(cur, data);
							if (event.result === false) event.preventDefault();
						}
					}
					event.type = type;
					if (!onlyHandlers && !event.isDefaultPrevented()) {
						if ((!special._default || special._default.apply(eventPath.pop(), data) === false) && acceptData(elem)) {
							if (ontype && isFunction(elem[type]) && !isWindow(elem)) {
								tmp = elem[ontype];
								if (tmp) elem[ontype] = null;
								jQuery.event.triggered = type;
								if (event.isPropagationStopped()) lastElement.addEventListener(type, stopPropagationCallback);
								elem[type]();
								if (event.isPropagationStopped()) lastElement.removeEventListener(type, stopPropagationCallback);
								jQuery.event.triggered = void 0;
								if (tmp) elem[ontype] = tmp;
							}
						}
					}
					return event.result;
				},
				simulate: function(type, elem, event) {
					var e = jQuery.extend(new jQuery.Event(), event, {
						type,
						isSimulated: true
					});
					jQuery.event.trigger(e, null, elem);
				}
			});
			jQuery.fn.extend({
				trigger: function(type, data) {
					return this.each(function() {
						jQuery.event.trigger(type, data, this);
					});
				},
				triggerHandler: function(type, data) {
					var elem = this[0];
					if (elem) return jQuery.event.trigger(type, data, elem, true);
				}
			});
			var rbracket = /\[\]$/, rCRLF = /\r?\n/g, rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, rsubmittable = /^(?:input|select|textarea|keygen)/i;
			function buildParams(prefix, obj, traditional, add) {
				var name;
				if (Array.isArray(obj)) jQuery.each(obj, function(i, v) {
					if (traditional || rbracket.test(prefix)) add(prefix, v);
					else buildParams(prefix + "[" + (typeof v === "object" && v != null ? i : "") + "]", v, traditional, add);
				});
				else if (!traditional && toType(obj) === "object") for (name in obj) buildParams(prefix + "[" + name + "]", obj[name], traditional, add);
				else add(prefix, obj);
			}
			jQuery.param = function(a, traditional) {
				var prefix, s = [], add = function(key, valueOrFunction) {
					var value = isFunction(valueOrFunction) ? valueOrFunction() : valueOrFunction;
					s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value);
				};
				if (a == null) return "";
				if (Array.isArray(a) || a.jquery && !jQuery.isPlainObject(a)) jQuery.each(a, function() {
					add(this.name, this.value);
				});
				else for (prefix in a) buildParams(prefix, a[prefix], traditional, add);
				return s.join("&");
			};
			jQuery.fn.extend({
				serialize: function() {
					return jQuery.param(this.serializeArray());
				},
				serializeArray: function() {
					return this.map(function() {
						var elements = jQuery.prop(this, "elements");
						return elements ? jQuery.makeArray(elements) : this;
					}).filter(function() {
						var type = this.type;
						return this.name && !jQuery(this).is(":disabled") && rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && (this.checked || !rcheckableType.test(type));
					}).map(function(_i, elem) {
						var val = jQuery(this).val();
						if (val == null) return null;
						if (Array.isArray(val)) return jQuery.map(val, function(val) {
							return {
								name: elem.name,
								value: val.replace(rCRLF, "\r\n")
							};
						});
						return {
							name: elem.name,
							value: val.replace(rCRLF, "\r\n")
						};
					}).get();
				}
			});
			var r20 = /%20/g, rhash = /#.*$/, rantiCache = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)$/gm, rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, prefilters = {}, transports = {}, allTypes = "*/".concat("*"), originAnchor = document.createElement("a");
			originAnchor.href = location.href;
			function addToPrefiltersOrTransports(structure) {
				return function(dataTypeExpression, func) {
					if (typeof dataTypeExpression !== "string") {
						func = dataTypeExpression;
						dataTypeExpression = "*";
					}
					var dataType, i = 0, dataTypes = dataTypeExpression.toLowerCase().match(rnothtmlwhite) || [];
					if (isFunction(func)) while (dataType = dataTypes[i++]) if (dataType[0] === "+") {
						dataType = dataType.slice(1) || "*";
						(structure[dataType] = structure[dataType] || []).unshift(func);
					} else (structure[dataType] = structure[dataType] || []).push(func);
				};
			}
			function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
				var inspected = {}, seekingTransport = structure === transports;
				function inspect(dataType) {
					var selected;
					inspected[dataType] = true;
					jQuery.each(structure[dataType] || [], function(_, prefilterOrFactory) {
						var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
						if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
							options.dataTypes.unshift(dataTypeOrTransport);
							inspect(dataTypeOrTransport);
							return false;
						} else if (seekingTransport) return !(selected = dataTypeOrTransport);
					});
					return selected;
				}
				return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
			}
			function ajaxExtend(target, src) {
				var key, deep, flatOptions = jQuery.ajaxSettings.flatOptions || {};
				for (key in src) if (src[key] !== void 0) (flatOptions[key] ? target : deep || (deep = {}))[key] = src[key];
				if (deep) jQuery.extend(true, target, deep);
				return target;
			}
			function ajaxHandleResponses(s, jqXHR, responses) {
				var ct, type, finalDataType, firstDataType, contents = s.contents, dataTypes = s.dataTypes;
				while (dataTypes[0] === "*") {
					dataTypes.shift();
					if (ct === void 0) ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
				}
				if (ct) {
					for (type in contents) if (contents[type] && contents[type].test(ct)) {
						dataTypes.unshift(type);
						break;
					}
				}
				if (dataTypes[0] in responses) finalDataType = dataTypes[0];
				else {
					for (type in responses) {
						if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
							finalDataType = type;
							break;
						}
						if (!firstDataType) firstDataType = type;
					}
					finalDataType = finalDataType || firstDataType;
				}
				if (finalDataType) {
					if (finalDataType !== dataTypes[0]) dataTypes.unshift(finalDataType);
					return responses[finalDataType];
				}
			}
			function ajaxConvert(s, response, jqXHR, isSuccess) {
				var conv2, current, conv, tmp, prev, converters = {}, dataTypes = s.dataTypes.slice();
				if (dataTypes[1]) for (conv in s.converters) converters[conv.toLowerCase()] = s.converters[conv];
				current = dataTypes.shift();
				while (current) {
					if (s.responseFields[current]) jqXHR[s.responseFields[current]] = response;
					if (!prev && isSuccess && s.dataFilter) response = s.dataFilter(response, s.dataType);
					prev = current;
					current = dataTypes.shift();
					if (current) {
						if (current === "*") current = prev;
						else if (prev !== "*" && prev !== current) {
							conv = converters[prev + " " + current] || converters["* " + current];
							if (!conv) for (conv2 in converters) {
								tmp = conv2.split(" ");
								if (tmp[1] === current) {
									conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]];
									if (conv) {
										if (conv === true) conv = converters[conv2];
										else if (converters[conv2] !== true) {
											current = tmp[0];
											dataTypes.unshift(tmp[1]);
										}
										break;
									}
								}
							}
							if (conv !== true) if (conv && s.throws) response = conv(response);
							else try {
								response = conv(response);
							} catch (e) {
								return {
									state: "parsererror",
									error: conv ? e : "No conversion from " + prev + " to " + current
								};
							}
						}
					}
				}
				return {
					state: "success",
					data: response
				};
			}
			jQuery.extend({
				active: 0,
				lastModified: {},
				etag: {},
				ajaxSettings: {
					url: location.href,
					type: "GET",
					isLocal: rlocalProtocol.test(location.protocol),
					global: true,
					processData: true,
					async: true,
					contentType: "application/x-www-form-urlencoded; charset=UTF-8",
					accepts: {
						"*": allTypes,
						text: "text/plain",
						html: "text/html",
						xml: "application/xml, text/xml",
						json: "application/json, text/javascript"
					},
					contents: {
						xml: /\bxml\b/,
						html: /\bhtml/,
						json: /\bjson\b/
					},
					responseFields: {
						xml: "responseXML",
						text: "responseText",
						json: "responseJSON"
					},
					converters: {
						"* text": String,
						"text html": true,
						"text json": JSON.parse,
						"text xml": jQuery.parseXML
					},
					flatOptions: {
						url: true,
						context: true
					}
				},
				ajaxSetup: function(target, settings) {
					return settings ? ajaxExtend(ajaxExtend(target, jQuery.ajaxSettings), settings) : ajaxExtend(jQuery.ajaxSettings, target);
				},
				ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
				ajaxTransport: addToPrefiltersOrTransports(transports),
				ajax: function(url, options) {
					if (typeof url === "object") {
						options = url;
						url = void 0;
					}
					options = options || {};
					var transport, cacheURL, responseHeadersString, responseHeaders, timeoutTimer, urlAnchor, completed, fireGlobals, i, uncached, s = jQuery.ajaxSetup({}, options), callbackContext = s.context || s, globalEventContext = s.context && (callbackContext.nodeType || callbackContext.jquery) ? jQuery(callbackContext) : jQuery.event, deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks("once memory"), statusCode = s.statusCode || {}, requestHeaders = {}, requestHeadersNames = {}, strAbort = "canceled", jqXHR = {
						readyState: 0,
						getResponseHeader: function(key) {
							var match;
							if (completed) {
								if (!responseHeaders) {
									responseHeaders = {};
									while (match = rheaders.exec(responseHeadersString)) responseHeaders[match[1].toLowerCase() + " "] = (responseHeaders[match[1].toLowerCase() + " "] || []).concat(match[2]);
								}
								match = responseHeaders[key.toLowerCase() + " "];
							}
							return match == null ? null : match.join(", ");
						},
						getAllResponseHeaders: function() {
							return completed ? responseHeadersString : null;
						},
						setRequestHeader: function(name, value) {
							if (completed == null) {
								name = requestHeadersNames[name.toLowerCase()] = requestHeadersNames[name.toLowerCase()] || name;
								requestHeaders[name] = value;
							}
							return this;
						},
						overrideMimeType: function(type) {
							if (completed == null) s.mimeType = type;
							return this;
						},
						statusCode: function(map) {
							var code;
							if (map) if (completed) jqXHR.always(map[jqXHR.status]);
							else for (code in map) statusCode[code] = [statusCode[code], map[code]];
							return this;
						},
						abort: function(statusText) {
							var finalText = statusText || strAbort;
							if (transport) transport.abort(finalText);
							done(0, finalText);
							return this;
						}
					};
					deferred.promise(jqXHR);
					s.url = ((url || s.url || location.href) + "").replace(rprotocol, location.protocol + "//");
					s.type = options.method || options.type || s.method || s.type;
					s.dataTypes = (s.dataType || "*").toLowerCase().match(rnothtmlwhite) || [""];
					if (s.crossDomain == null) {
						urlAnchor = document.createElement("a");
						try {
							urlAnchor.href = s.url;
							urlAnchor.href = urlAnchor.href;
							s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host;
						} catch (e) {
							s.crossDomain = true;
						}
					}
					if (s.data && s.processData && typeof s.data !== "string") s.data = jQuery.param(s.data, s.traditional);
					inspectPrefiltersOrTransports(prefilters, s, options, jqXHR);
					if (completed) return jqXHR;
					fireGlobals = jQuery.event && s.global;
					if (fireGlobals && jQuery.active++ === 0) jQuery.event.trigger("ajaxStart");
					s.type = s.type.toUpperCase();
					s.hasContent = !rnoContent.test(s.type);
					cacheURL = s.url.replace(rhash, "");
					if (!s.hasContent) {
						uncached = s.url.slice(cacheURL.length);
						if (s.data && (s.processData || typeof s.data === "string")) {
							cacheURL += (rquery.test(cacheURL) ? "&" : "?") + s.data;
							delete s.data;
						}
						if (s.cache === false) {
							cacheURL = cacheURL.replace(rantiCache, "$1");
							uncached = (rquery.test(cacheURL) ? "&" : "?") + "_=" + nonce.guid++ + uncached;
						}
						s.url = cacheURL + uncached;
					} else if (s.data && s.processData && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0) s.data = s.data.replace(r20, "+");
					if (s.ifModified) {
						if (jQuery.lastModified[cacheURL]) jqXHR.setRequestHeader("If-Modified-Since", jQuery.lastModified[cacheURL]);
						if (jQuery.etag[cacheURL]) jqXHR.setRequestHeader("If-None-Match", jQuery.etag[cacheURL]);
					}
					if (s.data && s.hasContent && s.contentType !== false || options.contentType) jqXHR.setRequestHeader("Content-Type", s.contentType);
					jqXHR.setRequestHeader("Accept", s.dataTypes[0] && s.accepts[s.dataTypes[0]] ? s.accepts[s.dataTypes[0]] + (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") : s.accepts["*"]);
					for (i in s.headers) jqXHR.setRequestHeader(i, s.headers[i]);
					if (s.beforeSend && (s.beforeSend.call(callbackContext, jqXHR, s) === false || completed)) return jqXHR.abort();
					strAbort = "abort";
					completeDeferred.add(s.complete);
					jqXHR.done(s.success);
					jqXHR.fail(s.error);
					transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
					if (!transport) done(-1, "No Transport");
					else {
						jqXHR.readyState = 1;
						if (fireGlobals) globalEventContext.trigger("ajaxSend", [jqXHR, s]);
						if (completed) return jqXHR;
						if (s.async && s.timeout > 0) timeoutTimer = window.setTimeout(function() {
							jqXHR.abort("timeout");
						}, s.timeout);
						try {
							completed = false;
							transport.send(requestHeaders, done);
						} catch (e) {
							if (completed) throw e;
							done(-1, e);
						}
					}
					function done(status, nativeStatusText, responses, headers) {
						var isSuccess, success, error, response, modified, statusText = nativeStatusText;
						if (completed) return;
						completed = true;
						if (timeoutTimer) window.clearTimeout(timeoutTimer);
						transport = void 0;
						responseHeadersString = headers || "";
						jqXHR.readyState = status > 0 ? 4 : 0;
						isSuccess = status >= 200 && status < 300 || status === 304;
						if (responses) response = ajaxHandleResponses(s, jqXHR, responses);
						if (!isSuccess && jQuery.inArray("script", s.dataTypes) > -1 && jQuery.inArray("json", s.dataTypes) < 0) s.converters["text script"] = function() {};
						response = ajaxConvert(s, response, jqXHR, isSuccess);
						if (isSuccess) {
							if (s.ifModified) {
								modified = jqXHR.getResponseHeader("Last-Modified");
								if (modified) jQuery.lastModified[cacheURL] = modified;
								modified = jqXHR.getResponseHeader("etag");
								if (modified) jQuery.etag[cacheURL] = modified;
							}
							if (status === 204 || s.type === "HEAD") statusText = "nocontent";
							else if (status === 304) statusText = "notmodified";
							else {
								statusText = response.state;
								success = response.data;
								error = response.error;
								isSuccess = !error;
							}
						} else {
							error = statusText;
							if (status || !statusText) {
								statusText = "error";
								if (status < 0) status = 0;
							}
						}
						jqXHR.status = status;
						jqXHR.statusText = (nativeStatusText || statusText) + "";
						if (isSuccess) deferred.resolveWith(callbackContext, [
							success,
							statusText,
							jqXHR
						]);
						else deferred.rejectWith(callbackContext, [
							jqXHR,
							statusText,
							error
						]);
						jqXHR.statusCode(statusCode);
						statusCode = void 0;
						if (fireGlobals) globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [
							jqXHR,
							s,
							isSuccess ? success : error
						]);
						completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);
						if (fireGlobals) {
							globalEventContext.trigger("ajaxComplete", [jqXHR, s]);
							if (!--jQuery.active) jQuery.event.trigger("ajaxStop");
						}
					}
					return jqXHR;
				},
				getJSON: function(url, data, callback) {
					return jQuery.get(url, data, callback, "json");
				},
				getScript: function(url, callback) {
					return jQuery.get(url, void 0, callback, "script");
				}
			});
			jQuery.each(["get", "post"], function(_i, method) {
				jQuery[method] = function(url, data, callback, type) {
					if (isFunction(data)) {
						type = type || callback;
						callback = data;
						data = void 0;
					}
					return jQuery.ajax(jQuery.extend({
						url,
						type: method,
						dataType: type,
						data,
						success: callback
					}, jQuery.isPlainObject(url) && url));
				};
			});
			jQuery.ajaxPrefilter(function(s) {
				var i;
				for (i in s.headers) if (i.toLowerCase() === "content-type") s.contentType = s.headers[i] || "";
			});
			jQuery._evalUrl = function(url, options, doc) {
				return jQuery.ajax({
					url,
					type: "GET",
					dataType: "script",
					cache: true,
					async: false,
					global: false,
					converters: { "text script": function() {} },
					dataFilter: function(response) {
						jQuery.globalEval(response, options, doc);
					}
				});
			};
			jQuery.fn.extend({
				wrapAll: function(html) {
					var wrap;
					if (this[0]) {
						if (isFunction(html)) html = html.call(this[0]);
						wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true);
						if (this[0].parentNode) wrap.insertBefore(this[0]);
						wrap.map(function() {
							var elem = this;
							while (elem.firstElementChild) elem = elem.firstElementChild;
							return elem;
						}).append(this);
					}
					return this;
				},
				wrapInner: function(html) {
					if (isFunction(html)) return this.each(function(i) {
						jQuery(this).wrapInner(html.call(this, i));
					});
					return this.each(function() {
						var self = jQuery(this), contents = self.contents();
						if (contents.length) contents.wrapAll(html);
						else self.append(html);
					});
				},
				wrap: function(html) {
					var htmlIsFunction = isFunction(html);
					return this.each(function(i) {
						jQuery(this).wrapAll(htmlIsFunction ? html.call(this, i) : html);
					});
				},
				unwrap: function(selector) {
					this.parent(selector).not("body").each(function() {
						jQuery(this).replaceWith(this.childNodes);
					});
					return this;
				}
			});
			jQuery.expr.pseudos.hidden = function(elem) {
				return !jQuery.expr.pseudos.visible(elem);
			};
			jQuery.expr.pseudos.visible = function(elem) {
				return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
			};
			jQuery.ajaxSettings.xhr = function() {
				try {
					return new window.XMLHttpRequest();
				} catch (e) {}
			};
			var xhrSuccessStatus = {
				0: 200,
				1223: 204
			}, xhrSupported = jQuery.ajaxSettings.xhr();
			support.cors = !!xhrSupported && "withCredentials" in xhrSupported;
			support.ajax = xhrSupported = !!xhrSupported;
			jQuery.ajaxTransport(function(options) {
				var callback, errorCallback;
				if (support.cors || xhrSupported && !options.crossDomain) return {
					send: function(headers, complete) {
						var i, xhr = options.xhr();
						xhr.open(options.type, options.url, options.async, options.username, options.password);
						if (options.xhrFields) for (i in options.xhrFields) xhr[i] = options.xhrFields[i];
						if (options.mimeType && xhr.overrideMimeType) xhr.overrideMimeType(options.mimeType);
						if (!options.crossDomain && !headers["X-Requested-With"]) headers["X-Requested-With"] = "XMLHttpRequest";
						for (i in headers) xhr.setRequestHeader(i, headers[i]);
						callback = function(type) {
							return function() {
								if (callback) {
									callback = errorCallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = xhr.onreadystatechange = null;
									if (type === "abort") xhr.abort();
									else if (type === "error") if (typeof xhr.status !== "number") complete(0, "error");
									else complete(xhr.status, xhr.statusText);
									else complete(xhrSuccessStatus[xhr.status] || xhr.status, xhr.statusText, (xhr.responseType || "text") !== "text" || typeof xhr.responseText !== "string" ? { binary: xhr.response } : { text: xhr.responseText }, xhr.getAllResponseHeaders());
								}
							};
						};
						xhr.onload = callback();
						errorCallback = xhr.onerror = xhr.ontimeout = callback("error");
						if (xhr.onabort !== void 0) xhr.onabort = errorCallback;
						else xhr.onreadystatechange = function() {
							if (xhr.readyState === 4) window.setTimeout(function() {
								if (callback) errorCallback();
							});
						};
						callback = callback("abort");
						try {
							xhr.send(options.hasContent && options.data || null);
						} catch (e) {
							if (callback) throw e;
						}
					},
					abort: function() {
						if (callback) callback();
					}
				};
			});
			jQuery.ajaxPrefilter(function(s) {
				if (s.crossDomain) s.contents.script = false;
			});
			jQuery.ajaxSetup({
				accepts: { script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" },
				contents: { script: /\b(?:java|ecma)script\b/ },
				converters: { "text script": function(text) {
					jQuery.globalEval(text);
					return text;
				} }
			});
			jQuery.ajaxPrefilter("script", function(s) {
				if (s.cache === void 0) s.cache = false;
				if (s.crossDomain) s.type = "GET";
			});
			jQuery.ajaxTransport("script", function(s) {
				if (s.crossDomain || s.scriptAttrs) {
					var script, callback;
					return {
						send: function(_, complete) {
							script = jQuery("<script>").attr(s.scriptAttrs || {}).prop({
								charset: s.scriptCharset,
								src: s.url
							}).on("load error", callback = function(evt) {
								script.remove();
								callback = null;
								if (evt) complete(evt.type === "error" ? 404 : 200, evt.type);
							});
							document.head.appendChild(script[0]);
						},
						abort: function() {
							if (callback) callback();
						}
					};
				}
			});
			var oldCallbacks = [], rjsonp = /(=)\?(?=&|$)|\?\?/;
			jQuery.ajaxSetup({
				jsonp: "callback",
				jsonpCallback: function() {
					var callback = oldCallbacks.pop() || jQuery.expando + "_" + nonce.guid++;
					this[callback] = true;
					return callback;
				}
			});
			jQuery.ajaxPrefilter("json jsonp", function(s, originalSettings, jqXHR) {
				var callbackName, overwritten, responseContainer, jsonProp = s.jsonp !== false && (rjsonp.test(s.url) ? "url" : typeof s.data === "string" && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0 && rjsonp.test(s.data) && "data");
				if (jsonProp || s.dataTypes[0] === "jsonp") {
					callbackName = s.jsonpCallback = isFunction(s.jsonpCallback) ? s.jsonpCallback() : s.jsonpCallback;
					if (jsonProp) s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName);
					else if (s.jsonp !== false) s.url += (rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName;
					s.converters["script json"] = function() {
						if (!responseContainer) jQuery.error(callbackName + " was not called");
						return responseContainer[0];
					};
					s.dataTypes[0] = "json";
					overwritten = window[callbackName];
					window[callbackName] = function() {
						responseContainer = arguments;
					};
					jqXHR.always(function() {
						if (overwritten === void 0) jQuery(window).removeProp(callbackName);
						else window[callbackName] = overwritten;
						if (s[callbackName]) {
							s.jsonpCallback = originalSettings.jsonpCallback;
							oldCallbacks.push(callbackName);
						}
						if (responseContainer && isFunction(overwritten)) overwritten(responseContainer[0]);
						responseContainer = overwritten = void 0;
					});
					return "script";
				}
			});
			support.createHTMLDocument = (function() {
				var body = document.implementation.createHTMLDocument("").body;
				body.innerHTML = "<form></form><form></form>";
				return body.childNodes.length === 2;
			})();
			jQuery.parseHTML = function(data, context, keepScripts) {
				if (typeof data !== "string") return [];
				if (typeof context === "boolean") {
					keepScripts = context;
					context = false;
				}
				var base, parsed, scripts;
				if (!context) if (support.createHTMLDocument) {
					context = document.implementation.createHTMLDocument("");
					base = context.createElement("base");
					base.href = document.location.href;
					context.head.appendChild(base);
				} else context = document;
				parsed = rsingleTag.exec(data);
				scripts = !keepScripts && [];
				if (parsed) return [context.createElement(parsed[1])];
				parsed = buildFragment([data], context, scripts);
				if (scripts && scripts.length) jQuery(scripts).remove();
				return jQuery.merge([], parsed.childNodes);
			};
			jQuery.fn.load = function(url, params, callback) {
				var selector, type, response, self = this, off = url.indexOf(" ");
				if (off > -1) {
					selector = stripAndCollapse(url.slice(off));
					url = url.slice(0, off);
				}
				if (isFunction(params)) {
					callback = params;
					params = void 0;
				} else if (params && typeof params === "object") type = "POST";
				if (self.length > 0) jQuery.ajax({
					url,
					type: type || "GET",
					dataType: "html",
					data: params
				}).done(function(responseText) {
					response = arguments;
					self.html(selector ? jQuery("<div>").append(jQuery.parseHTML(responseText)).find(selector) : responseText);
				}).always(callback && function(jqXHR, status) {
					self.each(function() {
						callback.apply(this, response || [
							jqXHR.responseText,
							status,
							jqXHR
						]);
					});
				});
				return this;
			};
			jQuery.expr.pseudos.animated = function(elem) {
				return jQuery.grep(jQuery.timers, function(fn) {
					return elem === fn.elem;
				}).length;
			};
			jQuery.offset = { setOffset: function(elem, options, i) {
				var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = jQuery.css(elem, "position"), curElem = jQuery(elem), props = {};
				if (position === "static") elem.style.position = "relative";
				curOffset = curElem.offset();
				curCSSTop = jQuery.css(elem, "top");
				curCSSLeft = jQuery.css(elem, "left");
				calculatePosition = (position === "absolute" || position === "fixed") && (curCSSTop + curCSSLeft).indexOf("auto") > -1;
				if (calculatePosition) {
					curPosition = curElem.position();
					curTop = curPosition.top;
					curLeft = curPosition.left;
				} else {
					curTop = parseFloat(curCSSTop) || 0;
					curLeft = parseFloat(curCSSLeft) || 0;
				}
				if (isFunction(options)) options = options.call(elem, i, jQuery.extend({}, curOffset));
				if (options.top != null) props.top = options.top - curOffset.top + curTop;
				if (options.left != null) props.left = options.left - curOffset.left + curLeft;
				if ("using" in options) options.using.call(elem, props);
				else curElem.css(props);
			} };
			jQuery.fn.extend({
				offset: function(options) {
					if (arguments.length) return options === void 0 ? this : this.each(function(i) {
						jQuery.offset.setOffset(this, options, i);
					});
					var rect, win, elem = this[0];
					if (!elem) return;
					if (!elem.getClientRects().length) return {
						top: 0,
						left: 0
					};
					rect = elem.getBoundingClientRect();
					win = elem.ownerDocument.defaultView;
					return {
						top: rect.top + win.pageYOffset,
						left: rect.left + win.pageXOffset
					};
				},
				position: function() {
					if (!this[0]) return;
					var offsetParent, offset, doc, elem = this[0], parentOffset = {
						top: 0,
						left: 0
					};
					if (jQuery.css(elem, "position") === "fixed") offset = elem.getBoundingClientRect();
					else {
						offset = this.offset();
						doc = elem.ownerDocument;
						offsetParent = elem.offsetParent || doc.documentElement;
						while (offsetParent && (offsetParent === doc.body || offsetParent === doc.documentElement) && jQuery.css(offsetParent, "position") === "static") offsetParent = offsetParent.parentNode;
						if (offsetParent && offsetParent !== elem && offsetParent.nodeType === 1) {
							parentOffset = jQuery(offsetParent).offset();
							parentOffset.top += jQuery.css(offsetParent, "borderTopWidth", true);
							parentOffset.left += jQuery.css(offsetParent, "borderLeftWidth", true);
						}
					}
					return {
						top: offset.top - parentOffset.top - jQuery.css(elem, "marginTop", true),
						left: offset.left - parentOffset.left - jQuery.css(elem, "marginLeft", true)
					};
				},
				offsetParent: function() {
					return this.map(function() {
						var offsetParent = this.offsetParent;
						while (offsetParent && jQuery.css(offsetParent, "position") === "static") offsetParent = offsetParent.offsetParent;
						return offsetParent || documentElement;
					});
				}
			});
			jQuery.each({
				scrollLeft: "pageXOffset",
				scrollTop: "pageYOffset"
			}, function(method, prop) {
				var top = "pageYOffset" === prop;
				jQuery.fn[method] = function(val) {
					return access(this, function(elem, method, val) {
						var win;
						if (isWindow(elem)) win = elem;
						else if (elem.nodeType === 9) win = elem.defaultView;
						if (val === void 0) return win ? win[prop] : elem[method];
						if (win) win.scrollTo(!top ? val : win.pageXOffset, top ? val : win.pageYOffset);
						else elem[method] = val;
					}, method, val, arguments.length);
				};
			});
			jQuery.each(["top", "left"], function(_i, prop) {
				jQuery.cssHooks[prop] = addGetHookIf(support.pixelPosition, function(elem, computed) {
					if (computed) {
						computed = curCSS(elem, prop);
						return rnumnonpx.test(computed) ? jQuery(elem).position()[prop] + "px" : computed;
					}
				});
			});
			jQuery.each({
				Height: "height",
				Width: "width"
			}, function(name, type) {
				jQuery.each({
					padding: "inner" + name,
					content: type,
					"": "outer" + name
				}, function(defaultExtra, funcName) {
					jQuery.fn[funcName] = function(margin, value) {
						var chainable = arguments.length && (defaultExtra || typeof margin !== "boolean"), extra = defaultExtra || (margin === true || value === true ? "margin" : "border");
						return access(this, function(elem, type, value) {
							var doc;
							if (isWindow(elem)) return funcName.indexOf("outer") === 0 ? elem["inner" + name] : elem.document.documentElement["client" + name];
							if (elem.nodeType === 9) {
								doc = elem.documentElement;
								return Math.max(elem.body["scroll" + name], doc["scroll" + name], elem.body["offset" + name], doc["offset" + name], doc["client" + name]);
							}
							return value === void 0 ? jQuery.css(elem, type, extra) : jQuery.style(elem, type, value, extra);
						}, type, chainable ? margin : void 0, chainable);
					};
				});
			});
			jQuery.each([
				"ajaxStart",
				"ajaxStop",
				"ajaxComplete",
				"ajaxError",
				"ajaxSuccess",
				"ajaxSend"
			], function(_i, type) {
				jQuery.fn[type] = function(fn) {
					return this.on(type, fn);
				};
			});
			jQuery.fn.extend({
				bind: function(types, data, fn) {
					return this.on(types, null, data, fn);
				},
				unbind: function(types, fn) {
					return this.off(types, null, fn);
				},
				delegate: function(selector, types, data, fn) {
					return this.on(types, selector, data, fn);
				},
				undelegate: function(selector, types, fn) {
					return arguments.length === 1 ? this.off(selector, "**") : this.off(types, selector || "**", fn);
				},
				hover: function(fnOver, fnOut) {
					return this.on("mouseenter", fnOver).on("mouseleave", fnOut || fnOver);
				}
			});
			jQuery.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(_i, name) {
				jQuery.fn[name] = function(data, fn) {
					return arguments.length > 0 ? this.on(name, null, data, fn) : this.trigger(name);
				};
			});
			var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;
			jQuery.proxy = function(fn, context) {
				var tmp, args, proxy;
				if (typeof context === "string") {
					tmp = fn[context];
					context = fn;
					fn = tmp;
				}
				if (!isFunction(fn)) return;
				args = slice.call(arguments, 2);
				proxy = function() {
					return fn.apply(context || this, args.concat(slice.call(arguments)));
				};
				proxy.guid = fn.guid = fn.guid || jQuery.guid++;
				return proxy;
			};
			jQuery.holdReady = function(hold) {
				if (hold) jQuery.readyWait++;
				else jQuery.ready(true);
			};
			jQuery.isArray = Array.isArray;
			jQuery.parseJSON = JSON.parse;
			jQuery.nodeName = nodeName;
			jQuery.isFunction = isFunction;
			jQuery.isWindow = isWindow;
			jQuery.camelCase = camelCase;
			jQuery.type = toType;
			jQuery.now = Date.now;
			jQuery.isNumeric = function(obj) {
				var type = jQuery.type(obj);
				return (type === "number" || type === "string") && !isNaN(obj - parseFloat(obj));
			};
			jQuery.trim = function(text) {
				return text == null ? "" : (text + "").replace(rtrim, "$1");
			};
			if (typeof define === "function" && define.amd) define("jquery", [], function() {
				return jQuery;
			});
			var _jQuery = window.jQuery, _$ = window.$;
			jQuery.noConflict = function(deep) {
				if (window.$ === jQuery) window.$ = _$;
				if (deep && window.jQuery === jQuery) window.jQuery = _jQuery;
				return jQuery;
			};
			if (typeof noGlobal === "undefined") window.jQuery = window.$ = jQuery;
			return jQuery;
		});
	}))(), 1);
	window.jQuery = import_jquery.default;
	window.$ = import_jquery.default;
	var require_layer$1 = __commonJSMin((() => {}));
	var import_layer = __toESM(__commonJSMin(((exports, module) => {
		require_layer$1();
		var isLayui = window.layui && layui.define, $, win, ready = {
			getPath: function() {
				var js = document.scripts, script = js[js.length - 1], jsPath = script.src;
				if (script.getAttribute("merge")) return;
				return jsPath.substring(0, jsPath.lastIndexOf("/") + 1);
			}(),
			config: {},
			end: {},
			minIndex: 0,
			minLeft: [],
			btn: ["&#x786E;&#x5B9A;", "&#x53D6;&#x6D88;"],
			type: [
				"dialog",
				"page",
				"iframe",
				"loading",
				"tips"
			]
		};
		var layer = {
			v: "3.0.1",
			ie: function() {
				var agent = navigator.userAgent.toLowerCase();
				return !!window.ActiveXObject || "ActiveXObject" in window ? (agent.match(/msie\s(\d+)/) || [])[1] || "11" : false;
			}(),
			index: window.layer && window.layer.v ? 1e5 : 0,
			path: ready.getPath,
			config: function(options, fn) {
				options = options || {};
				layer.cache = ready.config = $.extend({}, ready.config, options);
				layer.path = ready.config.path || layer.path;
				typeof options.extend === "string" && (options.extend = [options.extend]);
				if (ready.config.path) layer.ready();
				if (!options.extend) return this;
				isLayui ? layui.addcss("modules/layer/" + options.extend) : layer.link("skin/" + options.extend);
				return this;
			},
			link: function(href, fn, cssname) {
				if (!layer.path) return;
				var head = $("head")[0], link = document.createElement("link");
				if (typeof fn === "string") cssname = fn;
				var id = "layuicss-" + (cssname || href).replace(/\.|\//g, ""), timeout = 0;
				link.rel = "stylesheet";
				link.href = layer.path + href;
				link.id = id;
				if (!$("#" + id)[0]) head.appendChild(link);
				if (typeof fn !== "function") return;
				(function poll() {
					if (++timeout > 8 * 1e3 / 100) return window.console && console.error("layer.css: Invalid");
					parseInt($("#" + id).css("width")) === 1989 ? fn() : setTimeout(poll, 100);
				})();
			},
			ready: function(callback) {
				var cssname = "skinlayercss", ver = "1110";
				isLayui ? layui.addcss("modules/layer/default/layer.css?v=" + layer.v + ver, callback, cssname) : layer.link("skin/default/layer.css?v=" + layer.v + ver, callback, cssname);
				return this;
			},
			alert: function(content, options, yes) {
				var type = typeof options === "function";
				if (type) yes = options;
				return layer.open($.extend({
					content,
					yes
				}, type ? {} : options));
			},
			confirm: function(content, options, yes, cancel) {
				var type = typeof options === "function";
				if (type) {
					cancel = yes;
					yes = options;
				}
				return layer.open($.extend({
					content,
					btn: ready.btn,
					yes,
					btn2: cancel
				}, type ? {} : options));
			},
			msg: function(content, options, end) {
				var type = typeof options === "function", rskin = ready.config.skin;
				var skin = (rskin ? rskin + " " + rskin + "-msg" : "") || "layui-layer-msg";
				var anim = doms.anim.length - 1;
				if (type) end = options;
				return layer.open($.extend({
					content,
					time: 3e3,
					shade: false,
					skin,
					title: false,
					closeBtn: false,
					btn: false,
					resize: false,
					end
				}, type && !ready.config.skin ? {
					skin: skin + " layui-layer-hui",
					anim
				} : function() {
					options = options || {};
					if (options.icon === -1 || options.icon === void 0 && !ready.config.skin) options.skin = skin + " " + (options.skin || "layui-layer-hui");
					return options;
				}()));
			},
			load: function(icon, options) {
				return layer.open($.extend({
					type: 3,
					icon: icon || 0,
					resize: false,
					shade: .01
				}, options));
			},
			tips: function(content, follow, options) {
				return layer.open($.extend({
					type: 4,
					content: [content, follow],
					closeBtn: false,
					time: 3e3,
					shade: false,
					resize: false,
					fixed: false,
					maxWidth: 210
				}, options));
			}
		};
		var Class = function(setings) {
			var that = this;
			that.index = ++layer.index;
			that.config = $.extend({}, that.config, ready.config, setings);
			document.body ? that.creat() : setTimeout(function() {
				that.creat();
			}, 50);
		};
		Class.pt = Class.prototype;
		var doms = [
			"layui-layer",
			".layui-layer-title",
			".layui-layer-main",
			".layui-layer-dialog",
			"layui-layer-iframe",
			"layui-layer-content",
			"layui-layer-btn",
			"layui-layer-close"
		];
		doms.anim = [
			"layer-anim",
			"layer-anim-01",
			"layer-anim-02",
			"layer-anim-03",
			"layer-anim-04",
			"layer-anim-05",
			"layer-anim-06"
		];
		Class.pt.config = {
			type: 0,
			shade: .3,
			fixed: true,
			move: doms[1],
			title: "&#x4FE1;&#x606F;",
			offset: "auto",
			area: "auto",
			closeBtn: 1,
			time: 0,
			zIndex: 19891014,
			maxWidth: 360,
			anim: 0,
			icon: -1,
			moveType: 1,
			resize: true,
			scrollbar: true,
			tips: 2
		};
		Class.pt.vessel = function(conType, callback) {
			var that = this, times = that.index, config = that.config;
			var zIndex = config.zIndex + times, titype = typeof config.title === "object";
			var ismax = config.maxmin && (config.type === 1 || config.type === 2);
			var titleHTML = config.title ? "<div class=\"layui-layer-title\" style=\"" + (titype ? config.title[1] : "") + "\">" + (titype ? config.title[0] : config.title) + "</div>" : "";
			config.zIndex = zIndex;
			callback([config.shade ? "<div class=\"layui-layer-shade\" id=\"layui-layer-shade" + times + "\" times=\"" + times + "\" style=\"" + ("z-index:" + (zIndex - 1) + "; background-color:" + (config.shade[1] || "#000") + "; opacity:" + (config.shade[0] || config.shade) + "; filter:alpha(opacity=" + (config.shade[0] * 100 || config.shade * 100) + ");") + "\"></div>" : "", "<div class=\"" + doms[0] + (" layui-layer-" + ready.type[config.type]) + ((config.type == 0 || config.type == 2) && !config.shade ? " layui-layer-border" : "") + " " + (config.skin || "") + "\" id=\"" + doms[0] + times + "\" type=\"" + ready.type[config.type] + "\" times=\"" + times + "\" showtime=\"" + config.time + "\" conType=\"" + (conType ? "object" : "string") + "\" style=\"z-index: " + zIndex + "; width:" + config.area[0] + ";height:" + config.area[1] + (config.fixed ? "" : ";position:absolute;") + "\">" + (conType && config.type != 2 ? "" : titleHTML) + "<div id=\"" + (config.id || "") + "\" class=\"layui-layer-content" + (config.type == 0 && config.icon !== -1 ? " layui-layer-padding" : "") + (config.type == 3 ? " layui-layer-loading" + config.icon : "") + "\">" + (config.type == 0 && config.icon !== -1 ? "<i class=\"layui-layer-ico layui-layer-ico" + config.icon + "\"></i>" : "") + (config.type == 1 && conType ? "" : config.content || "") + "</div><span class=\"layui-layer-setwin\">" + function() {
				var closebtn = ismax ? "<a class=\"layui-layer-min\" href=\"javascript:;\"><cite></cite></a><a class=\"layui-layer-ico layui-layer-max\" href=\"javascript:;\"></a>" : "";
				config.closeBtn && (closebtn += "<a class=\"layui-layer-ico " + doms[7] + " " + doms[7] + (config.title ? config.closeBtn : config.type == 4 ? "1" : "2") + "\" href=\"javascript:;\"></a>");
				return closebtn;
			}() + "</span>" + (config.btn ? function() {
				var button = "";
				typeof config.btn === "string" && (config.btn = [config.btn]);
				for (var i = 0, len = config.btn.length; i < len; i++) button += "<a class=\"" + doms[6] + i + "\">" + config.btn[i] + "</a>";
				return "<div class=\"" + doms[6] + " layui-layer-btn-" + (config.btnAlign || "") + "\">" + button + "</div>";
			}() : "") + (config.resize ? "<span class=\"layui-layer-resize\"></span>" : "") + "</div>"], titleHTML, $("<div class=\"layui-layer-move\"></div>"));
			return that;
		};
		Class.pt.creat = function() {
			var that = this, config = that.config, times = that.index, content = config.content, conType = typeof content === "object", body = $("body");
			if ($("#" + config.id)[0]) return;
			if (typeof config.area === "string") config.area = config.area === "auto" ? ["", ""] : [config.area, ""];
			if (config.shift) config.anim = config.shift;
			if (layer.ie == 6) config.fixed = false;
			switch (config.type) {
				case 0:
					config.btn = "btn" in config ? config.btn : ready.btn[0];
					layer.closeAll("dialog");
					break;
				case 2:
					var content = config.content = conType ? config.content : [config.content || "http://layer.layui.com", "auto"];
					config.content = "<iframe scrolling=\"" + (config.content[1] || "auto") + "\" allowtransparency=\"true\" id=\"" + doms[4] + times + "\" name=\"" + doms[4] + times + "\" onload=\"this.className='';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"" + config.content[0] + "\"></iframe>";
					break;
				case 3:
					delete config.title;
					delete config.closeBtn;
					config.icon === -1 && config.icon;
					layer.closeAll("loading");
					break;
				case 4:
					conType || (config.content = [config.content, "body"]);
					config.follow = config.content[1];
					config.content = config.content[0] + "<i class=\"layui-layer-TipsG\"></i>";
					delete config.title;
					config.tips = typeof config.tips === "object" ? config.tips : [config.tips, true];
					config.tipsMore || layer.closeAll("tips");
					break;
			}
			that.vessel(conType, function(html, titleHTML, moveElem) {
				body.append(html[0]);
				conType ? function() {
					config.type == 2 || config.type == 4 ? function() {
						$("body").append(html[1]);
					}() : function() {
						if (!content.parents("." + doms[0])[0]) {
							content.data("display", content.css("display")).show().addClass("layui-layer-wrap").wrap(html[1]);
							$("#" + doms[0] + times).find("." + doms[5]).before(titleHTML);
						}
					}();
				}() : body.append(html[1]);
				$(".layui-layer-move")[0] || body.append(ready.moveElem = moveElem);
				that.layero = $("#" + doms[0] + times);
				config.scrollbar || doms.html.css("overflow", "hidden").attr("layer-full", times);
			}).auto(times);
			config.type == 2 && layer.ie == 6 && that.layero.find("iframe").attr("src", content[0]);
			config.type == 4 ? that.tips() : that.offset();
			if (config.fixed) win.on("resize", function() {
				that.offset();
				(/^\d+%$/.test(config.area[0]) || /^\d+%$/.test(config.area[1])) && that.auto(times);
				config.type == 4 && that.tips();
			});
			config.time <= 0 || setTimeout(function() {
				layer.close(that.index);
			}, config.time);
			that.move().callback();
			if (doms.anim[config.anim]) that.layero.addClass(doms.anim[config.anim]).data("anim", true);
		};
		Class.pt.auto = function(index) {
			var that = this, config = that.config, layero = $("#" + doms[0] + index);
			if (config.area[0] === "" && config.maxWidth > 0) {
				if (layer.ie && layer.ie < 8 && config.btn) layero.width(layero.innerWidth());
				layero.outerWidth() > config.maxWidth && layero.width(config.maxWidth);
			}
			var area = [layero.innerWidth(), layero.innerHeight()];
			var titHeight = layero.find(doms[1]).outerHeight() || 0;
			var btnHeight = layero.find("." + doms[6]).outerHeight() || 0;
			function setHeight(elem) {
				elem = layero.find(elem);
				elem.height(area[1] - titHeight - btnHeight - 2 * (parseFloat(elem.css("padding")) | 0));
			}
			switch (config.type) {
				case 2:
					setHeight("iframe");
					break;
				default:
					if (config.area[1] === "") {
						if (config.fixed && area[1] >= win.height()) {
							area[1] = win.height();
							setHeight("." + doms[5]);
						}
					} else setHeight("." + doms[5]);
					break;
			}
			return that;
		};
		Class.pt.offset = function() {
			var that = this, config = that.config, layero = that.layero;
			var area = [layero.outerWidth(), layero.outerHeight()];
			var type = typeof config.offset === "object";
			that.offsetTop = (win.height() - area[1]) / 2;
			that.offsetLeft = (win.width() - area[0]) / 2;
			if (type) {
				that.offsetTop = config.offset[0];
				that.offsetLeft = config.offset[1] || that.offsetLeft;
			} else if (config.offset !== "auto") if (config.offset === "t") that.offsetTop = 0;
			else if (config.offset === "r") that.offsetLeft = win.width() - area[0];
			else if (config.offset === "b") that.offsetTop = win.height() - area[1];
			else if (config.offset === "l") that.offsetLeft = 0;
			else if (config.offset === "lt") {
				that.offsetTop = 0;
				that.offsetLeft = 0;
			} else if (config.offset === "lb") {
				that.offsetTop = win.height() - area[1];
				that.offsetLeft = 0;
			} else if (config.offset === "rt") {
				that.offsetTop = 0;
				that.offsetLeft = win.width() - area[0];
			} else if (config.offset === "rb") {
				that.offsetTop = win.height() - area[1];
				that.offsetLeft = win.width() - area[0];
			} else that.offsetTop = config.offset;
			if (!config.fixed) {
				that.offsetTop = /%$/.test(that.offsetTop) ? win.height() * parseFloat(that.offsetTop) / 100 : parseFloat(that.offsetTop);
				that.offsetLeft = /%$/.test(that.offsetLeft) ? win.width() * parseFloat(that.offsetLeft) / 100 : parseFloat(that.offsetLeft);
				that.offsetTop += win.scrollTop();
				that.offsetLeft += win.scrollLeft();
			}
			if (layero.attr("minLeft")) {
				that.offsetTop = win.height() - (layero.find(doms[1]).outerHeight() || 0);
				that.offsetLeft = layero.css("left");
			}
			layero.css({
				top: that.offsetTop,
				left: that.offsetLeft
			});
		};
		Class.pt.tips = function() {
			var that = this, config = that.config, layero = that.layero;
			var layArea = [layero.outerWidth(), layero.outerHeight()], follow = $(config.follow);
			if (!follow[0]) follow = $("body");
			var goal = {
				width: follow.outerWidth(),
				height: follow.outerHeight(),
				top: follow.offset().top,
				left: follow.offset().left
			}, tipsG = layero.find(".layui-layer-TipsG");
			var guide = config.tips[0];
			config.tips[1] || tipsG.remove();
			goal.autoLeft = function() {
				if (goal.left + layArea[0] - win.width() > 0) {
					goal.tipLeft = goal.left + goal.width - layArea[0];
					tipsG.css({
						right: 12,
						left: "auto"
					});
				} else goal.tipLeft = goal.left;
			};
			goal.where = [
				function() {
					goal.autoLeft();
					goal.tipTop = goal.top - layArea[1] - 10;
					tipsG.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color", config.tips[1]);
				},
				function() {
					goal.tipLeft = goal.left + goal.width + 10;
					goal.tipTop = goal.top;
					tipsG.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color", config.tips[1]);
				},
				function() {
					goal.autoLeft();
					goal.tipTop = goal.top + goal.height + 10;
					tipsG.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color", config.tips[1]);
				},
				function() {
					goal.tipLeft = goal.left - layArea[0] - 10;
					goal.tipTop = goal.top;
					tipsG.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color", config.tips[1]);
				}
			];
			goal.where[guide - 1]();
			if (guide === 1) goal.top - (win.scrollTop() + layArea[1] + 16) < 0 && goal.where[2]();
			else if (guide === 2) win.width() - (goal.left + goal.width + layArea[0] + 16) > 0 || goal.where[3]();
			else if (guide === 3) goal.top - win.scrollTop() + goal.height + layArea[1] + 16 - win.height() > 0 && goal.where[0]();
			else if (guide === 4) layArea[0] + 16 - goal.left > 0 && goal.where[1]();
			layero.find("." + doms[5]).css({
				"background-color": config.tips[1],
				"padding-right": config.closeBtn ? "30px" : ""
			});
			layero.css({
				left: goal.tipLeft - (config.fixed ? win.scrollLeft() : 0),
				top: goal.tipTop - (config.fixed ? win.scrollTop() : 0)
			});
		};
		Class.pt.move = function() {
			var that = this, config = that.config, _DOC = $(document), layero = that.layero, moveElem = layero.find(config.move), resizeElem = layero.find(".layui-layer-resize"), dict = {};
			if (config.move) moveElem.css("cursor", "move");
			moveElem.on("mousedown", function(e) {
				e.preventDefault();
				if (config.move) {
					dict.moveStart = true;
					dict.offset = [e.clientX - parseFloat(layero.css("left")), e.clientY - parseFloat(layero.css("top"))];
					ready.moveElem.css("cursor", "move").show();
				}
			});
			resizeElem.on("mousedown", function(e) {
				e.preventDefault();
				dict.resizeStart = true;
				dict.offset = [e.clientX, e.clientY];
				dict.area = [layero.outerWidth(), layero.outerHeight()];
				ready.moveElem.css("cursor", "se-resize").show();
			});
			_DOC.on("mousemove", function(e) {
				if (dict.moveStart) {
					var X = e.clientX - dict.offset[0], Y = e.clientY - dict.offset[1], fixed = layero.css("position") === "fixed";
					e.preventDefault();
					dict.stX = fixed ? 0 : win.scrollLeft();
					dict.stY = fixed ? 0 : win.scrollTop();
					if (!config.moveOut) {
						var setRig = win.width() - layero.outerWidth() + dict.stX, setBot = win.height() - layero.outerHeight() + dict.stY;
						X < dict.stX && (X = dict.stX);
						X > setRig && (X = setRig);
						Y < dict.stY && (Y = dict.stY);
						Y > setBot && (Y = setBot);
					}
					layero.css({
						left: X,
						top: Y
					});
				}
				if (config.resize && dict.resizeStart) {
					var X = e.clientX - dict.offset[0], Y = e.clientY - dict.offset[1];
					e.preventDefault();
					layer.style(that.index, {
						width: dict.area[0] + X,
						height: dict.area[1] + Y
					});
					dict.isResize = true;
				}
			}).on("mouseup", function(e) {
				if (dict.moveStart) {
					delete dict.moveStart;
					ready.moveElem.hide();
					config.moveEnd && config.moveEnd();
				}
				if (dict.resizeStart) {
					delete dict.resizeStart;
					ready.moveElem.hide();
				}
			});
			return that;
		};
		Class.pt.callback = function() {
			var that = this, layero = that.layero, config = that.config;
			that.openLayer();
			if (config.success) if (config.type == 2) layero.find("iframe").on("load", function() {
				config.success(layero, that.index);
			});
			else config.success(layero, that.index);
			layer.ie == 6 && that.IE6(layero);
			layero.find("." + doms[6]).children("a").on("click", function() {
				var index = $(this).index();
				if (index === 0) if (config.yes) config.yes(that.index, layero);
				else if (config["btn1"]) config["btn1"](that.index, layero);
				else layer.close(that.index);
				else (config["btn" + (index + 1)] && config["btn" + (index + 1)](that.index, layero)) === false || layer.close(that.index);
			});
			function cancel() {
				(config.cancel && config.cancel(that.index, layero)) === false || layer.close(that.index);
			}
			layero.find("." + doms[7]).on("click", cancel);
			if (config.shadeClose) $("#layui-layer-shade" + that.index).on("click", function() {
				layer.close(that.index);
			});
			layero.find(".layui-layer-min").on("click", function() {
				(config.min && config.min(layero)) === false || layer.min(that.index, config);
			});
			layero.find(".layui-layer-max").on("click", function() {
				if ($(this).hasClass("layui-layer-maxmin")) {
					layer.restore(that.index);
					config.restore && config.restore(layero);
				} else {
					layer.full(that.index, config);
					setTimeout(function() {
						config.full && config.full(layero);
					}, 100);
				}
			});
			config.end && (ready.end[that.index] = config.end);
		};
		ready.reselect = function() {
			$.each($("select"), function(index, value) {
				var sthis = $(this);
				if (!sthis.parents("." + doms[0])[0]) sthis.attr("layer") == 1 && $("." + doms[0]).length < 1 && sthis.removeAttr("layer").show();
				sthis = null;
			});
		};
		Class.pt.IE6 = function(layero) {
			$("select").each(function(index, value) {
				var sthis = $(this);
				if (!sthis.parents("." + doms[0])[0]) sthis.css("display") === "none" || sthis.attr({ "layer": "1" }).hide();
				sthis = null;
			});
		};
		Class.pt.openLayer = function() {
			layer.zIndex = this.config.zIndex;
			layer.setTop = function(layero) {
				var setZindex = function() {
					layer.zIndex++;
					layero.css("z-index", layer.zIndex + 1);
				};
				layer.zIndex = parseInt(layero[0].style.zIndex);
				layero.on("mousedown", setZindex);
				return layer.zIndex;
			};
		};
		ready.record = function(layero) {
			var area = [
				layero.width(),
				layero.height(),
				layero.position().top,
				layero.position().left + parseFloat(layero.css("margin-left"))
			];
			layero.find(".layui-layer-max").addClass("layui-layer-maxmin");
			layero.attr({ area });
		};
		ready.rescollbar = function(index) {
			if (doms.html.attr("layer-full") == index) {
				if (doms.html[0].style.removeProperty) doms.html[0].style.removeProperty("overflow");
				else doms.html[0].style.removeAttribute("overflow");
				doms.html.removeAttr("layer-full");
			}
		};
		window.layer = layer;
		layer.getChildFrame = function(selector, index) {
			index = index || $("." + doms[4]).attr("times");
			return $("#" + doms[0] + index).find("iframe").contents().find(selector);
		};
		layer.getFrameIndex = function(name) {
			return $("#" + name).parents("." + doms[4]).attr("times");
		};
		layer.iframeAuto = function(index) {
			if (!index) return;
			var heg = layer.getChildFrame("html", index).outerHeight();
			var layero = $("#" + doms[0] + index);
			var titHeight = layero.find(doms[1]).outerHeight() || 0;
			var btnHeight = layero.find("." + doms[6]).outerHeight() || 0;
			layero.css({ height: heg + titHeight + btnHeight });
			layero.find("iframe").css({ height: heg });
		};
		layer.iframeSrc = function(index, url) {
			$("#" + doms[0] + index).find("iframe").attr("src", url);
		};
		layer.style = function(index, options, limit) {
			var layero = $("#" + doms[0] + index), contElem = layero.find(".layui-layer-content"), type = layero.attr("type"), titHeight = layero.find(doms[1]).outerHeight() || 0, btnHeight = layero.find("." + doms[6]).outerHeight() || 0;
			layero.attr("minLeft");
			if (type === ready.type[3] || type === ready.type[4]) return;
			if (!limit) {
				if (parseFloat(options.width) <= 260) options.width = 260;
				if (parseFloat(options.height) - titHeight - btnHeight <= 64) options.height = 64 + titHeight + btnHeight;
			}
			layero.css(options);
			btnHeight = layero.find("." + doms[6]).outerHeight();
			if (type === ready.type[2]) layero.find("iframe").css({ height: parseFloat(options.height) - titHeight - btnHeight });
			else contElem.css({ height: parseFloat(options.height) - titHeight - btnHeight - parseFloat(contElem.css("padding-top")) - parseFloat(contElem.css("padding-bottom")) });
		};
		layer.min = function(index, options) {
			var layero = $("#" + doms[0] + index), titHeight = layero.find(doms[1]).outerHeight() || 0, left = layero.attr("minLeft") || 181 * ready.minIndex + "px", position = layero.css("position");
			ready.record(layero);
			if (ready.minLeft[0]) {
				left = ready.minLeft[0];
				ready.minLeft.shift();
			}
			layero.attr("position", position);
			layer.style(index, {
				width: 180,
				height: titHeight,
				left,
				top: win.height() - titHeight,
				position: "fixed",
				overflow: "hidden"
			}, true);
			layero.find(".layui-layer-min").hide();
			layero.attr("type") === "page" && layero.find(doms[4]).hide();
			ready.rescollbar(index);
			if (!layero.attr("minLeft")) ready.minIndex++;
			layero.attr("minLeft", left);
		};
		layer.restore = function(index) {
			var layero = $("#" + doms[0] + index), area = layero.attr("area").split(",");
			layero.attr("type");
			layer.style(index, {
				width: parseFloat(area[0]),
				height: parseFloat(area[1]),
				top: parseFloat(area[2]),
				left: parseFloat(area[3]),
				position: layero.attr("position"),
				overflow: "visible"
			}, true);
			layero.find(".layui-layer-max").removeClass("layui-layer-maxmin");
			layero.find(".layui-layer-min").show();
			layero.attr("type") === "page" && layero.find(doms[4]).show();
			ready.rescollbar(index);
		};
		layer.full = function(index) {
			var layero = $("#" + doms[0] + index), timer;
			ready.record(layero);
			if (!doms.html.attr("layer-full")) doms.html.css("overflow", "hidden").attr("layer-full", index);
			clearTimeout(timer);
			timer = setTimeout(function() {
				var isfix = layero.css("position") === "fixed";
				layer.style(index, {
					top: isfix ? 0 : win.scrollTop(),
					left: isfix ? 0 : win.scrollLeft(),
					width: win.width(),
					height: win.height()
				}, true);
				layero.find(".layui-layer-min").hide();
			}, 100);
		};
		layer.title = function(name, index) {
			$("#" + doms[0] + (index || layer.index)).find(doms[1]).html(name);
		};
		layer.close = function(index) {
			var layero = $("#" + doms[0] + index), type = layero.attr("type"), closeAnim = "layer-anim-close";
			if (!layero[0]) return;
			var WRAP = "layui-layer-wrap", remove = function() {
				if (type === ready.type[1] && layero.attr("conType") === "object") {
					layero.children(":not(." + doms[5] + ")").remove();
					var wrap = layero.find("." + WRAP);
					for (var i = 0; i < 2; i++) wrap.unwrap();
					wrap.css("display", wrap.data("display")).removeClass(WRAP);
				} else {
					if (type === ready.type[2]) try {
						var iframe = $("#" + doms[4] + index)[0];
						iframe.contentWindow.document.write("");
						iframe.contentWindow.close();
						layero.find("." + doms[5])[0].removeChild(iframe);
					} catch (e) {}
					layero[0].innerHTML = "";
					layero.remove();
				}
				typeof ready.end[index] === "function" && ready.end[index]();
				delete ready.end[index];
			};
			if (layero.data("anim")) layero.addClass(closeAnim);
			$("#layui-layer-moves, #layui-layer-shade" + index).remove();
			layer.ie == 6 && ready.reselect();
			ready.rescollbar(index);
			if (layero.attr("minLeft")) {
				ready.minIndex--;
				ready.minLeft.push(layero.attr("minLeft"));
			}
			setTimeout(function() {
				remove();
			}, layer.ie && layer.ie < 10 || !layero.data("anim") ? 0 : 200);
		};
		layer.closeAll = function(type) {
			$.each($("." + doms[0]), function() {
				var othis = $(this);
				var is = type ? othis.attr("type") === type : 1;
				is && layer.close(othis.attr("times"));
				is = null;
			});
		};
		var cache = layer.cache || {}, skin = function(type) {
			return cache.skin ? " " + cache.skin + " " + cache.skin + "-" + type : "";
		};
		layer.prompt = function(options, yes) {
			var style = "";
			options = options || {};
			if (typeof options === "function") yes = options;
			if (options.area) {
				var area = options.area;
				style = "style=\"width: " + area[0] + "; height: " + area[1] + ";\"";
				delete options.area;
			}
			var prompt, content = options.formType == 2 ? "<textarea class=\"layui-layer-input\"" + style + ">" + (options.value || "") + "</textarea>" : function() {
				return "<input type=\"" + (options.formType == 1 ? "password" : "text") + "\" class=\"layui-layer-input\" value=\"" + (options.value || "") + "\">";
			}();
			return layer.open($.extend({
				type: 1,
				btn: ["&#x786E;&#x5B9A;", "&#x53D6;&#x6D88;"],
				content,
				skin: "layui-layer-prompt" + skin("prompt"),
				maxWidth: win.width(),
				success: function(layero) {
					prompt = layero.find(".layui-layer-input");
					prompt.focus();
				},
				resize: false,
				yes: function(index) {
					var value = prompt.val();
					if (value === "") prompt.focus();
					else if (value.length > (options.maxlength || 500)) layer.tips("&#x6700;&#x591A;&#x8F93;&#x5165;" + (options.maxlength || 500) + "&#x4E2A;&#x5B57;&#x6570;", prompt, { tips: 1 });
					else yes && yes(value, index, prompt);
				}
			}, options));
		};
		layer.tab = function(options) {
			options = options || {};
			var tab = options.tab || {};
			return layer.open($.extend({
				type: 1,
				skin: "layui-layer-tab" + skin("tab"),
				resize: false,
				title: function() {
					var len = tab.length, ii = 1, str = "";
					if (len > 0) {
						str = "<span class=\"layui-layer-tabnow\">" + tab[0].title + "</span>";
						for (; ii < len; ii++) str += "<span>" + tab[ii].title + "</span>";
					}
					return str;
				}(),
				content: "<ul class=\"layui-layer-tabmain\">" + function() {
					var len = tab.length, ii = 1, str = "";
					if (len > 0) {
						str = "<li class=\"layui-layer-tabli xubox_tab_layer\">" + (tab[0].content || "no content") + "</li>";
						for (; ii < len; ii++) str += "<li class=\"layui-layer-tabli\">" + (tab[ii].content || "no  content") + "</li>";
					}
					return str;
				}() + "</ul>",
				success: function(layero) {
					var btn = layero.find(".layui-layer-title").children();
					var main = layero.find(".layui-layer-tabmain").children();
					btn.on("mousedown", function(e) {
						e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
						var othis = $(this), index = othis.index();
						othis.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow");
						main.eq(index).show().siblings().hide();
						typeof options.change === "function" && options.change(index);
					});
				}
			}, options));
		};
		layer.photos = function(options, loop, key) {
			var dict = {};
			options = options || {};
			if (!options.photos) return;
			var type = options.photos.constructor === Object;
			var photos = type ? options.photos : {}, data = photos.data || [];
			var start = photos.start || 0;
			dict.imgIndex = (start | 0) + 1;
			options.img = options.img || "img";
			if (!type) {
				var parent = $(options.photos), pushData = function() {
					data = [];
					parent.find(options.img).each(function(index) {
						var othis = $(this);
						othis.attr("layer-index", index);
						data.push({
							alt: othis.attr("alt"),
							pid: othis.attr("layer-pid"),
							src: othis.attr("layer-src") || othis.attr("src"),
							thumb: othis.attr("src")
						});
					});
				};
				pushData();
				if (data.length === 0) return;
				loop || parent.on("click", options.img, function() {
					var index = $(this).attr("layer-index");
					layer.photos($.extend(options, {
						photos: {
							start: index,
							data,
							tab: options.tab
						},
						full: options.full
					}), true);
					pushData();
				});
				if (!loop) return;
			} else if (data.length === 0) return layer.msg("&#x6CA1;&#x6709;&#x56FE;&#x7247;");
			dict.imgprev = function(key) {
				dict.imgIndex--;
				if (dict.imgIndex < 1) dict.imgIndex = data.length;
				dict.tabimg(key);
			};
			dict.imgnext = function(key, errorMsg) {
				dict.imgIndex++;
				if (dict.imgIndex > data.length) {
					dict.imgIndex = 1;
					if (errorMsg) return;
				}
				dict.tabimg(key);
			};
			dict.keyup = function(event) {
				if (!dict.end) {
					var code = event.keyCode;
					event.preventDefault();
					if (code === 37) dict.imgprev(true);
					else if (code === 39) dict.imgnext(true);
					else if (code === 27) layer.close(dict.index);
				}
			};
			dict.tabimg = function(key) {
				if (data.length <= 1) return;
				photos.start = dict.imgIndex - 1;
				layer.close(dict.index);
				layer.photos(options, true, key);
			};
			dict.event = function() {
				dict.bigimg.hover(function() {
					dict.imgsee.show();
				}, function() {
					dict.imgsee.hide();
				});
				dict.bigimg.find(".layui-layer-imgprev").on("click", function(event) {
					event.preventDefault();
					dict.imgprev();
				});
				dict.bigimg.find(".layui-layer-imgnext").on("click", function(event) {
					event.preventDefault();
					dict.imgnext();
				});
				$(document).on("keyup", dict.keyup);
			};
			function loadImage(url, callback, error) {
				var img = new Image();
				img.src = url;
				if (img.complete) return callback(img);
				img.onload = function() {
					img.onload = null;
					callback(img);
				};
				img.onerror = function(e) {
					img.onerror = null;
					error(e);
				};
			}
			dict.loadi = layer.load(1, {
				shade: "shade" in options ? false : .9,
				scrollbar: false
			});
			loadImage(data[start].src, function(img) {
				layer.close(dict.loadi);
				dict.index = layer.open($.extend({
					type: 1,
					area: function() {
						var imgarea = [img.width, img.height];
						var winarea = [$(window).width() - 100, $(window).height() - 100];
						if (!options.full && (imgarea[0] > winarea[0] || imgarea[1] > winarea[1])) {
							var wh = [imgarea[0] / winarea[0], imgarea[1] / winarea[1]];
							if (wh[0] > wh[1]) {
								imgarea[0] = imgarea[0] / wh[0];
								imgarea[1] = imgarea[1] / wh[0];
							} else if (wh[0] < wh[1]) {
								imgarea[0] = imgarea[0] / wh[1];
								imgarea[1] = imgarea[1] / wh[1];
							}
						}
						return [imgarea[0] + "px", imgarea[1] + "px"];
					}(),
					title: false,
					shade: .9,
					shadeClose: true,
					closeBtn: false,
					move: ".layui-layer-phimg img",
					moveType: 1,
					scrollbar: false,
					moveOut: true,
					anim: Math.random() * 5 | 0,
					skin: "layui-layer-photos" + skin("photos"),
					content: "<div class=\"layui-layer-phimg\"><img src=\"" + data[start].src + "\" alt=\"" + (data[start].alt || "") + "\" layer-pid=\"" + data[start].pid + "\"><div class=\"layui-layer-imgsee\">" + (data.length > 1 ? "<span class=\"layui-layer-imguide\"><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgprev\"></a><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgnext\"></a></span>" : "") + "<div class=\"layui-layer-imgbar\" style=\"display:" + (key ? "block" : "") + "\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">" + (data[start].alt || "") + "</a><em>" + dict.imgIndex + "/" + data.length + "</em></span></div></div></div>",
					success: function(layero, index) {
						dict.bigimg = layero.find(".layui-layer-phimg");
						dict.imgsee = layero.find(".layui-layer-imguide,.layui-layer-imgbar");
						dict.event(layero);
						options.tab && options.tab(data[start], layero);
					},
					end: function() {
						dict.end = true;
						$(document).off("keyup", dict.keyup);
					}
				}, options));
			}, function() {
				layer.close(dict.loadi);
				layer.msg("&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;", {
					time: 3e4,
					btn: ["&#x4E0B;&#x4E00;&#x5F20;", "&#x4E0D;&#x770B;&#x4E86;"],
					yes: function() {
						data.length > 1 && dict.imgnext(true, true);
					}
				});
			});
		};
		ready.run = function(_$) {
			$ = _$;
			win = $(window);
			doms.html = $("html");
			layer.open = function(deliver) {
				return new Class(deliver).index;
			};
		};
		ready.run(jQuery);
		module.exports = layer;
	}))(), 1);
	var CoreFeature = class {
		constructor(table) {
			this.table = table;
		}
		reloadData(data, silent, columnsChanged) {
			return this.table.dataLoader.load(data, void 0, void 0, void 0, silent, columnsChanged);
		}
		langText() {
			return this.table.modules.localize.getText(...arguments);
		}
		langBind() {
			return this.table.modules.localize.bind(...arguments);
		}
		langLocale() {
			return this.table.modules.localize.getLocale(...arguments);
		}
		commsConnections() {
			return this.table.modules.comms.getConnections(...arguments);
		}
		commsSend() {
			return this.table.modules.comms.send(...arguments);
		}
		layoutMode() {
			return this.table.modules.layout.getMode();
		}
		layoutRefresh(force) {
			return this.table.modules.layout.layout(force);
		}
		subscribe() {
			return this.table.eventBus.subscribe(...arguments);
		}
		unsubscribe() {
			return this.table.eventBus.unsubscribe(...arguments);
		}
		subscribed(key) {
			return this.table.eventBus.subscribed(key);
		}
		subscriptionChange() {
			return this.table.eventBus.subscriptionChange(...arguments);
		}
		dispatch() {
			return this.table.eventBus.dispatch(...arguments);
		}
		chain() {
			return this.table.eventBus.chain(...arguments);
		}
		confirm() {
			return this.table.eventBus.confirm(...arguments);
		}
		dispatchExternal() {
			return this.table.externalEvents.dispatch(...arguments);
		}
		subscribedExternal(key) {
			return this.table.externalEvents.subscribed(key);
		}
		subscriptionChangeExternal() {
			return this.table.externalEvents.subscriptionChange(...arguments);
		}
		options(key) {
			return this.table.options[key];
		}
		setOption(key, value) {
			if (typeof value !== "undefined") this.table.options[key] = value;
			return this.table.options[key];
		}
		deprecationCheck(oldOption, newOption, convert) {
			return this.table.deprecationAdvisor.check(oldOption, newOption, convert);
		}
		deprecationCheckMsg(oldOption, msg) {
			return this.table.deprecationAdvisor.checkMsg(oldOption, msg);
		}
		deprecationMsg(msg) {
			return this.table.deprecationAdvisor.msg(msg);
		}
		module(key) {
			return this.table.module(key);
		}
	};
	var Helpers = class {
		static elVisible(el) {
			return !(el.offsetWidth <= 0 && el.offsetHeight <= 0);
		}
		static elOffset(el) {
			var box = el.getBoundingClientRect();
			return {
				top: box.top + window.pageYOffset - document.documentElement.clientTop,
				left: box.left + window.pageXOffset - document.documentElement.clientLeft
			};
		}
		static retrieveNestedData(separator, field, data) {
			var structure = separator ? field.split(separator) : [field], length = structure.length, output;
			for (let i = 0; i < length; i++) {
				data = data[structure[i]];
				output = data;
				if (!data) break;
			}
			return output;
		}
		static deepClone(obj, clone, list = []) {
			var objectProto = {}.__proto__, arrayProto = [].__proto__;
			if (!clone) clone = Object.assign(Array.isArray(obj) ? [] : {}, obj);
			for (var i in obj) {
				let subject = obj[i], match, copy;
				if (subject != null && typeof subject === "object" && (subject.__proto__ === objectProto || subject.__proto__ === arrayProto)) {
					match = list.findIndex((item) => {
						return item.subject === subject;
					});
					if (match > -1) clone[i] = list[match].copy;
					else {
						copy = Object.assign(Array.isArray(subject) ? [] : {}, subject);
						list.unshift({
							subject,
							copy
						});
						clone[i] = this.deepClone(subject, copy, list);
					}
				}
			}
			return clone;
		}
	};
	var Popup$1 = class Popup extends CoreFeature {
		constructor(table, element, parent) {
			super(table);
			this.element = element;
			this.container = this._lookupContainer();
			this.parent = parent;
			this.reversedX = false;
			this.childPopup = null;
			this.blurable = false;
			this.blurCallback = null;
			this.blurEventsBound = false;
			this.renderedCallback = null;
			this.visible = false;
			this.hideable = true;
			this.element.classList.add("tabulator-popup-container");
			this.blurEvent = this.hide.bind(this, false);
			this.escEvent = this._escapeCheck.bind(this);
			this.destroyBinding = this.tableDestroyed.bind(this);
			this.destroyed = false;
		}
		tableDestroyed() {
			this.destroyed = true;
			this.hide(true);
		}
		_lookupContainer() {
			var container = this.table.options.popupContainer;
			if (typeof container === "string") {
				container = document.querySelector(container);
				if (!container) console.warn("Menu Error - no container element found matching selector:", this.table.options.popupContainer, "(defaulting to document body)");
			} else if (container === true) container = this.table.element;
			if (container && !this._checkContainerIsParent(container)) {
				container = false;
				console.warn("Menu Error - container element does not contain this table:", this.table.options.popupContainer, "(defaulting to document body)");
			}
			if (!container) container = document.body;
			return container;
		}
		_checkContainerIsParent(container, element = this.table.element) {
			if (container === element) return true;
			else return element.parentNode ? this._checkContainerIsParent(container, element.parentNode) : false;
		}
		renderCallback(callback) {
			this.renderedCallback = callback;
		}
		containerEventCoords(e) {
			var touch = !(e instanceof MouseEvent);
			var x = touch ? e.touches[0].pageX : e.pageX;
			var y = touch ? e.touches[0].pageY : e.pageY;
			if (this.container !== document.body) {
				let parentOffset = Helpers.elOffset(this.container);
				x -= parentOffset.left;
				y -= parentOffset.top;
			}
			return {
				x,
				y
			};
		}
		elementPositionCoords(element, position = "right") {
			var offset = Helpers.elOffset(element), containerOffset, x, y;
			if (this.container !== document.body) {
				containerOffset = Helpers.elOffset(this.container);
				offset.left -= containerOffset.left;
				offset.top -= containerOffset.top;
			}
			switch (position) {
				case "right":
					x = offset.left + element.offsetWidth;
					y = offset.top - 1;
					break;
				case "bottom":
					x = offset.left;
					y = offset.top + element.offsetHeight;
					break;
				case "left":
					x = offset.left;
					y = offset.top - 1;
					break;
				case "top":
					x = offset.left;
					y = offset.top;
					break;
				case "center":
					x = offset.left + element.offsetWidth / 2;
					y = offset.top + element.offsetHeight / 2;
					break;
			}
			return {
				x,
				y,
				offset
			};
		}
		show(origin, position) {
			var x, y, parentEl, parentOffset, coords;
			if (this.destroyed || this.table.destroyed) return this;
			if (origin instanceof HTMLElement) {
				parentEl = origin;
				coords = this.elementPositionCoords(origin, position);
				parentOffset = coords.offset;
				x = coords.x;
				y = coords.y;
			} else if (typeof origin === "number") {
				parentOffset = {
					top: 0,
					left: 0
				};
				x = origin;
				y = position;
			} else {
				coords = this.containerEventCoords(origin);
				x = coords.x;
				y = coords.y;
				this.reversedX = false;
			}
			this.element.style.top = y + "px";
			this.element.style.left = x + "px";
			this.container.appendChild(this.element);
			if (typeof this.renderedCallback === "function") this.renderedCallback();
			this._fitToScreen(x, y, parentEl, parentOffset, position);
			this.visible = true;
			this.subscribe("table-destroy", this.destroyBinding);
			this.element.addEventListener("mousedown", (e) => {
				e.stopPropagation();
			});
			return this;
		}
		_fitToScreen(x, y, parentEl, parentOffset, position) {
			var scrollTop = this.container === document.body ? document.documentElement.scrollTop : this.container.scrollTop;
			if (x + this.element.offsetWidth >= this.container.offsetWidth || this.reversedX) {
				this.element.style.left = "";
				if (parentEl) this.element.style.right = this.container.offsetWidth - parentOffset.left + "px";
				else this.element.style.right = this.container.offsetWidth - x + "px";
				this.reversedX = true;
			}
			let offsetHeight = Math.max(this.container.offsetHeight, scrollTop ? this.container.scrollHeight : 0);
			if (y + this.element.offsetHeight > offsetHeight) if (parentEl) switch (position) {
				case "bottom":
					this.element.style.top = parseInt(this.element.style.top) - this.element.offsetHeight - parentEl.offsetHeight - 1 + "px";
					break;
				default: this.element.style.top = parseInt(this.element.style.top) - this.element.offsetHeight + parentEl.offsetHeight + 1 + "px";
			}
			else this.element.style.height = offsetHeight + "px";
		}
		isVisible() {
			return this.visible;
		}
		hideOnBlur(callback) {
			this.blurable = true;
			if (this.visible) {
				setTimeout(() => {
					if (this.visible) {
						this.table.rowManager.element.addEventListener("scroll", this.blurEvent);
						this.subscribe("cell-editing", this.blurEvent);
						document.body.addEventListener("click", this.blurEvent);
						document.body.addEventListener("contextmenu", this.blurEvent);
						document.body.addEventListener("mousedown", this.blurEvent);
						window.addEventListener("resize", this.blurEvent);
						document.body.addEventListener("keydown", this.escEvent);
						this.blurEventsBound = true;
					}
				}, 100);
				this.blurCallback = callback;
			}
			return this;
		}
		_escapeCheck(e) {
			if (e.keyCode == 27) this.hide();
		}
		blockHide() {
			this.hideable = false;
		}
		restoreHide() {
			this.hideable = true;
		}
		hide(silent = false) {
			if (this.visible && this.hideable) {
				if (this.blurable && this.blurEventsBound) {
					document.body.removeEventListener("keydown", this.escEvent);
					document.body.removeEventListener("click", this.blurEvent);
					document.body.removeEventListener("contextmenu", this.blurEvent);
					document.body.removeEventListener("mousedown", this.blurEvent);
					window.removeEventListener("resize", this.blurEvent);
					this.table.rowManager.element.removeEventListener("scroll", this.blurEvent);
					this.unsubscribe("cell-editing", this.blurEvent);
					this.blurEventsBound = false;
				}
				if (this.childPopup) this.childPopup.hide();
				if (this.parent) this.parent.childPopup = null;
				if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
				this.visible = false;
				if (this.blurCallback && !silent) this.blurCallback();
				this.unsubscribe("table-destroy", this.destroyBinding);
			}
			return this;
		}
		child(element) {
			if (this.childPopup) this.childPopup.hide();
			this.childPopup = new Popup(this.table, element, this);
			return this.childPopup;
		}
	};
	var Module = class extends CoreFeature {
		constructor(table, name) {
			super(table);
			this._handler = null;
		}
		initialize() {}
		registerTableOption(key, value) {
			this.table.optionsList.register(key, value);
		}
		registerColumnOption(key, value) {
			this.table.columnManager.optionsList.register(key, value);
		}
		registerTableFunction(name, func) {
			if (typeof this.table[name] === "undefined") this.table[name] = (...args) => {
				this.table.initGuard(name);
				return func(...args);
			};
			else console.warn("Unable to bind table function, name already in use", name);
		}
		registerComponentFunction(component, func, handler) {
			return this.table.componentFunctionBinder.bind(component, func, handler);
		}
		registerDataHandler(handler, priority) {
			this.table.rowManager.registerDataPipelineHandler(handler, priority);
			this._handler = handler;
		}
		registerDisplayHandler(handler, priority) {
			this.table.rowManager.registerDisplayPipelineHandler(handler, priority);
			this._handler = handler;
		}
		displayRows(adjust) {
			var index = this.table.rowManager.displayRows.length - 1, lookupIndex;
			if (this._handler) {
				lookupIndex = this.table.rowManager.displayPipeline.findIndex((item) => {
					return item.handler === this._handler;
				});
				if (lookupIndex > -1) index = lookupIndex;
			}
			if (adjust) index = index + adjust;
			if (this._handler) if (index > -1) return this.table.rowManager.getDisplayRows(index);
			else return this.activeRows();
		}
		activeRows() {
			return this.table.rowManager.activeRows;
		}
		refreshData(renderInPosition, handler) {
			if (!handler) handler = this._handler;
			if (handler) this.table.rowManager.refreshActiveData(handler, false, renderInPosition);
		}
		footerAppend(element) {
			return this.table.footerManager.append(element);
		}
		footerPrepend(element) {
			return this.table.footerManager.prepend(element);
		}
		footerRemove(element) {
			return this.table.footerManager.remove(element);
		}
		popup(menuEl, menuContainer) {
			return new Popup$1(this.table, menuEl, menuContainer);
		}
		alert(content, type) {
			return this.table.alertManager.alert(content, type);
		}
		clearAlert() {
			return this.table.alertManager.clear();
		}
	};
	var defaultAccessors = { rownum: function(value, data, type, params, column, row) {
		return row.getPosition();
	} };
	var Accessor = class Accessor extends Module {
		static moduleName = "accessor";
		static accessors = defaultAccessors;
		constructor(table) {
			super(table);
			this.allowedTypes = [
				"",
				"data",
				"download",
				"clipboard",
				"print",
				"htmlOutput"
			];
			this.registerColumnOption("accessor");
			this.registerColumnOption("accessorParams");
			this.registerColumnOption("accessorData");
			this.registerColumnOption("accessorDataParams");
			this.registerColumnOption("accessorDownload");
			this.registerColumnOption("accessorDownloadParams");
			this.registerColumnOption("accessorClipboard");
			this.registerColumnOption("accessorClipboardParams");
			this.registerColumnOption("accessorPrint");
			this.registerColumnOption("accessorPrintParams");
			this.registerColumnOption("accessorHtmlOutput");
			this.registerColumnOption("accessorHtmlOutputParams");
		}
		initialize() {
			this.subscribe("column-layout", this.initializeColumn.bind(this));
			this.subscribe("row-data-retrieve", this.transformRow.bind(this));
		}
		initializeColumn(column) {
			var match = false, config = {};
			this.allowedTypes.forEach((type) => {
				var key = "accessor" + (type.charAt(0).toUpperCase() + type.slice(1)), accessor;
				if (column.definition[key]) {
					accessor = this.lookupAccessor(column.definition[key]);
					if (accessor) {
						match = true;
						config[key] = {
							accessor,
							params: column.definition[key + "Params"] || {}
						};
					}
				}
			});
			if (match) column.modules.accessor = config;
		}
		lookupAccessor(value) {
			var accessor = false;
			switch (typeof value) {
				case "string":
					if (Accessor.accessors[value]) accessor = Accessor.accessors[value];
					else console.warn("Accessor Error - No such accessor found, ignoring: ", value);
					break;
				case "function":
					accessor = value;
					break;
			}
			return accessor;
		}
		transformRow(row, type) {
			var key = "accessor" + (type.charAt(0).toUpperCase() + type.slice(1)), rowComponent = row.getComponent();
			var data = Helpers.deepClone(row.data || {});
			this.table.columnManager.traverse(function(column) {
				var value, accessor, params, colComponent;
				if (column.modules.accessor) {
					accessor = column.modules.accessor[key] || column.modules.accessor.accessor || false;
					if (accessor) {
						value = column.getFieldValue(data);
						if (value != "undefined") {
							colComponent = column.getComponent();
							params = typeof accessor.params === "function" ? accessor.params(value, data, type, colComponent, rowComponent) : accessor.params;
							column.setFieldValue(data, accessor.accessor(value, data, type, params, colComponent, rowComponent));
						}
					}
				}
			});
			return data;
		}
	};
	var defaultConfig = { method: "GET" };
	function generateParamsList$1(data, prefix) {
		var output = [];
		prefix = prefix || "";
		if (Array.isArray(data)) data.forEach((item, i) => {
			output = output.concat(generateParamsList$1(item, prefix ? prefix + "[" + i + "]" : i));
		});
		else if (typeof data === "object") for (var key in data) output = output.concat(generateParamsList$1(data[key], prefix ? prefix + "[" + key + "]" : key));
		else output.push({
			key: prefix,
			value: data
		});
		return output;
	}
	function serializeParams(params) {
		var output = generateParamsList$1(params), encoded = [];
		output.forEach(function(item) {
			encoded.push(encodeURIComponent(item.key) + "=" + encodeURIComponent(item.value));
		});
		return encoded.join("&");
	}
	function urlBuilder(url, config, params) {
		if (url) {
			if (params && Object.keys(params).length) {
				if (!config.method || config.method.toLowerCase() == "get") {
					config.method = "get";
					url += (url.includes("?") ? "&" : "?") + serializeParams(params);
				}
			}
		}
		return url;
	}
	function defaultLoaderPromise(url, config, params) {
		var contentType;
		return new Promise((resolve, reject) => {
			url = this.urlGenerator.call(this.table, url, config, params);
			if (config.method.toUpperCase() != "GET") {
				contentType = typeof this.table.options.ajaxContentType === "object" ? this.table.options.ajaxContentType : this.contentTypeFormatters[this.table.options.ajaxContentType];
				if (contentType) {
					for (var key in contentType.headers) {
						if (!config.headers) config.headers = {};
						if (typeof config.headers[key] === "undefined") config.headers[key] = contentType.headers[key];
					}
					config.body = contentType.body.call(this, url, config, params);
				} else console.warn("Ajax Error - Invalid ajaxContentType value:", this.table.options.ajaxContentType);
			}
			if (url) {
				if (typeof config.headers === "undefined") config.headers = {};
				if (typeof config.headers.Accept === "undefined") config.headers.Accept = "application/json";
				if (typeof config.headers["X-Requested-With"] === "undefined") config.headers["X-Requested-With"] = "XMLHttpRequest";
				if (typeof config.mode === "undefined") config.mode = "cors";
				if (config.mode == "cors") {
					if (typeof config.headers["Origin"] === "undefined") config.headers["Origin"] = window.location.origin;
					if (typeof config.credentials === "undefined") config.credentials = "same-origin";
				} else if (typeof config.credentials === "undefined") config.credentials = "include";
				fetch(url, config).then((response) => {
					if (response.ok) response.json().then((data) => {
						resolve(data);
					}).catch((error) => {
						reject(error);
						console.warn("Ajax Load Error - Invalid JSON returned", error);
					});
					else {
						console.error("Ajax Load Error - Connection Error: " + response.status, response.statusText);
						reject(response);
					}
				}).catch((error) => {
					console.error("Ajax Load Error - Connection Error: ", error);
					reject(error);
				});
			} else {
				console.warn("Ajax Load Error - No URL Set");
				resolve([]);
			}
		});
	}
	function generateParamsList(data, prefix) {
		var output = [];
		prefix = prefix || "";
		if (Array.isArray(data)) data.forEach((item, i) => {
			output = output.concat(generateParamsList(item, prefix ? prefix + "[" + i + "]" : i));
		});
		else if (typeof data === "object") for (var key in data) output = output.concat(generateParamsList(data[key], prefix ? prefix + "[" + key + "]" : key));
		else output.push({
			key: prefix,
			value: data
		});
		return output;
	}
	var defaultContentTypeFormatters = {
		"json": {
			headers: { "Content-Type": "application/json" },
			body: function(url, config, params) {
				return JSON.stringify(params);
			}
		},
		"form": {
			headers: {},
			body: function(url, config, params) {
				var output = generateParamsList(params), form = new FormData();
				output.forEach(function(item) {
					form.append(item.key, item.value);
				});
				return form;
			}
		}
	};
	var Ajax = class Ajax extends Module {
		static moduleName = "ajax";
		static defaultConfig = defaultConfig;
		static defaultURLGenerator = urlBuilder;
		static defaultLoaderPromise = defaultLoaderPromise;
		static contentTypeFormatters = defaultContentTypeFormatters;
		constructor(table) {
			super(table);
			this.config = {};
			this.url = "";
			this.urlGenerator = false;
			this.params = false;
			this.loaderPromise = false;
			this.registerTableOption("ajaxURL", false);
			this.registerTableOption("ajaxURLGenerator", false);
			this.registerTableOption("ajaxParams", {});
			this.registerTableOption("ajaxConfig", "get");
			this.registerTableOption("ajaxContentType", "form");
			this.registerTableOption("ajaxRequestFunc", false);
			this.registerTableOption("ajaxRequesting", function() {});
			this.registerTableOption("ajaxResponse", false);
			this.contentTypeFormatters = Ajax.contentTypeFormatters;
		}
		initialize() {
			this.loaderPromise = this.table.options.ajaxRequestFunc || Ajax.defaultLoaderPromise;
			this.urlGenerator = this.table.options.ajaxURLGenerator || Ajax.defaultURLGenerator;
			if (this.table.options.ajaxURL) this.setUrl(this.table.options.ajaxURL);
			this.setDefaultConfig(this.table.options.ajaxConfig);
			this.registerTableFunction("getAjaxUrl", this.getUrl.bind(this));
			this.subscribe("data-loading", this.requestDataCheck.bind(this));
			this.subscribe("data-params", this.requestParams.bind(this));
			this.subscribe("data-load", this.requestData.bind(this));
		}
		requestParams(data, config, silent, params) {
			var ajaxParams = this.table.options.ajaxParams;
			if (ajaxParams) {
				if (typeof ajaxParams === "function") ajaxParams = ajaxParams.call(this.table);
				params = Object.assign(Object.assign({}, ajaxParams), params);
			}
			return params;
		}
		requestDataCheck(data, params, config, silent) {
			return !!(!data && this.url || typeof data === "string");
		}
		requestData(url, params, config, silent, previousData) {
			var ajaxConfig;
			if (!previousData && this.requestDataCheck(url)) {
				if (url) this.setUrl(url);
				ajaxConfig = this.generateConfig(config);
				return this.sendRequest(this.url, params, ajaxConfig);
			} else return previousData;
		}
		setDefaultConfig(config = {}) {
			this.config = Object.assign({}, Ajax.defaultConfig);
			if (typeof config == "string") this.config.method = config;
			else Object.assign(this.config, config);
		}
		generateConfig(config = {}) {
			var ajaxConfig = Object.assign({}, this.config);
			if (typeof config == "string") ajaxConfig.method = config;
			else Object.assign(ajaxConfig, config);
			return ajaxConfig;
		}
		setUrl(url) {
			this.url = url;
		}
		getUrl() {
			return this.url;
		}
		sendRequest(url, params, config) {
			if (this.table.options.ajaxRequesting.call(this.table, url, params) !== false) return this.loaderPromise(url, config, params).then((data) => {
				if (this.table.options.ajaxResponse) data = this.table.options.ajaxResponse.call(this.table, url, params, data);
				return data;
			});
			else return Promise.reject();
		}
	};
	var defaultPasteActions = {
		replace: function(data) {
			return this.table.setData(data);
		},
		update: function(data) {
			return this.table.updateOrAddData(data);
		},
		insert: function(data) {
			return this.table.addData(data);
		}
	};
	var defaultPasteParsers = { table: function(clipboard) {
		var data = [], headerFindSuccess = true, columns = this.table.columnManager.columns, columnMap = [], rows = [];
		clipboard = clipboard.split("\n");
		clipboard.forEach(function(row) {
			data.push(row.split("	"));
		});
		if (data.length && !(data.length === 1 && data[0].length < 2)) {
			data[0].forEach(function(value) {
				var column = columns.find(function(column) {
					return value && column.definition.title && value.trim() && column.definition.title.trim() === value.trim();
				});
				if (column) columnMap.push(column);
				else headerFindSuccess = false;
			});
			if (!headerFindSuccess) {
				headerFindSuccess = true;
				columnMap = [];
				data[0].forEach(function(value) {
					var column = columns.find(function(column) {
						return value && column.field && value.trim() && column.field.trim() === value.trim();
					});
					if (column) columnMap.push(column);
					else headerFindSuccess = false;
				});
				if (!headerFindSuccess) columnMap = this.table.columnManager.columnsByIndex;
			}
			if (headerFindSuccess) data.shift();
			data.forEach(function(item) {
				var row = {};
				item.forEach(function(value, i) {
					if (columnMap[i]) row[columnMap[i].field] = value;
				});
				rows.push(row);
			});
			return rows;
		} else return false;
	} };
	var extensions$4 = { keybindings: {
		bindings: { copyToClipboard: ["ctrl + 67", "meta + 67"] },
		actions: { copyToClipboard: function(e) {
			if (!this.table.modules.edit.currentCell) {
				if (this.table.modExists("clipboard", true)) this.table.modules.clipboard.copy(false, true);
			}
		} }
	} };
	var Clipboard = class Clipboard extends Module {
		static moduleName = "clipboard";
		static moduleExtensions = extensions$4;
		static pasteActions = defaultPasteActions;
		static pasteParsers = defaultPasteParsers;
		constructor(table) {
			super(table);
			this.mode = true;
			this.pasteParser = function() {};
			this.pasteAction = function() {};
			this.customSelection = false;
			this.rowRange = false;
			this.blocked = true;
			this.registerTableOption("clipboard", false);
			this.registerTableOption("clipboardCopyStyled", true);
			this.registerTableOption("clipboardCopyConfig", false);
			this.registerTableOption("clipboardCopyFormatter", false);
			this.registerTableOption("clipboardCopyRowRange", "active");
			this.registerTableOption("clipboardPasteParser", "table");
			this.registerTableOption("clipboardPasteAction", "insert");
			this.registerColumnOption("clipboard");
			this.registerColumnOption("titleClipboard");
		}
		initialize() {
			this.mode = this.table.options.clipboard;
			this.rowRange = this.table.options.clipboardCopyRowRange;
			if (this.mode === true || this.mode === "copy") this.table.element.addEventListener("copy", (e) => {
				var plain, html, list;
				if (!this.blocked) {
					e.preventDefault();
					if (this.customSelection) {
						plain = this.customSelection;
						if (this.table.options.clipboardCopyFormatter) plain = this.table.options.clipboardCopyFormatter("plain", plain);
					} else {
						list = this.table.modules.export.generateExportList(this.table.options.clipboardCopyConfig, this.table.options.clipboardCopyStyled, this.rowRange, "clipboard");
						html = this.table.modules.export.generateHTMLTable(list);
						plain = html ? this.generatePlainContent(list) : "";
						if (this.table.options.clipboardCopyFormatter) {
							plain = this.table.options.clipboardCopyFormatter("plain", plain);
							html = this.table.options.clipboardCopyFormatter("html", html);
						}
					}
					if (window.clipboardData && window.clipboardData.setData) window.clipboardData.setData("Text", plain);
					else if (e.clipboardData && e.clipboardData.setData) {
						e.clipboardData.setData("text/plain", plain);
						if (html) e.clipboardData.setData("text/html", html);
					} else if (e.originalEvent && e.originalEvent.clipboardData.setData) {
						e.originalEvent.clipboardData.setData("text/plain", plain);
						if (html) e.originalEvent.clipboardData.setData("text/html", html);
					}
					this.dispatchExternal("clipboardCopied", plain, html);
					this.reset();
				}
			});
			if (this.mode === true || this.mode === "paste") this.table.element.addEventListener("paste", (e) => {
				this.paste(e);
			});
			this.setPasteParser(this.table.options.clipboardPasteParser);
			this.setPasteAction(this.table.options.clipboardPasteAction);
			this.registerTableFunction("copyToClipboard", this.copy.bind(this));
		}
		reset() {
			this.blocked = true;
			this.customSelection = false;
		}
		generatePlainContent(list) {
			var output = [];
			list.forEach((row) => {
				var rowData = [];
				row.columns.forEach((col) => {
					var value = "";
					if (col) {
						if (row.type === "group") col.value = col.component.getKey();
						if (col.value === null) value = "";
						else switch (typeof col.value) {
							case "object":
								value = JSON.stringify(col.value);
								break;
							case "undefined":
								value = "";
								break;
							default: value = col.value;
						}
					}
					rowData.push(value);
				});
				output.push(rowData.join("	"));
			});
			return output.join("\n");
		}
		copy(range, internal) {
			var sel, textRange;
			this.blocked = false;
			this.customSelection = false;
			if (this.mode === true || this.mode === "copy") {
				this.rowRange = range || this.table.options.clipboardCopyRowRange;
				if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") {
					range = document.createRange();
					range.selectNodeContents(this.table.element);
					sel = window.getSelection();
					if (sel.toString() && internal) this.customSelection = sel.toString();
					sel.removeAllRanges();
					sel.addRange(range);
				} else if (typeof document.selection != "undefined" && typeof document.body.createTextRange != "undefined") {
					textRange = document.body.createTextRange();
					textRange.moveToElementText(this.table.element);
					textRange.select();
				}
				document.execCommand("copy");
				if (sel) sel.removeAllRanges();
			}
		}
		setPasteAction(action) {
			switch (typeof action) {
				case "string":
					this.pasteAction = Clipboard.pasteActions[action];
					if (!this.pasteAction) console.warn("Clipboard Error - No such paste action found:", action);
					break;
				case "function":
					this.pasteAction = action;
					break;
			}
		}
		setPasteParser(parser) {
			switch (typeof parser) {
				case "string":
					this.pasteParser = Clipboard.pasteParsers[parser];
					if (!this.pasteParser) console.warn("Clipboard Error - No such paste parser found:", parser);
					break;
				case "function":
					this.pasteParser = parser;
					break;
			}
		}
		paste(e) {
			var data, rowData, rows;
			if (this.checkPasteOrigin(e)) {
				data = this.getPasteData(e);
				rowData = this.pasteParser.call(this, data);
				if (rowData) {
					e.preventDefault();
					if (this.table.modExists("mutator")) rowData = this.mutateData(rowData);
					rows = this.pasteAction.call(this, rowData);
					this.dispatchExternal("clipboardPasted", data, rowData, rows);
				} else this.dispatchExternal("clipboardPasteError", data);
			}
		}
		mutateData(data) {
			var output = [];
			if (Array.isArray(data)) data.forEach((row) => {
				output.push(this.table.modules.mutator.transformRow(row, "clipboard"));
			});
			else output = data;
			return output;
		}
		checkPasteOrigin(e) {
			var valid = true;
			if (this.confirm("clipboard-paste", [e]) || !["DIV", "SPAN"].includes(e.target.tagName)) valid = false;
			return valid;
		}
		getPasteData(e) {
			var data;
			if (window.clipboardData && window.clipboardData.getData) data = window.clipboardData.getData("Text");
			else if (e.clipboardData && e.clipboardData.getData) data = e.clipboardData.getData("text/plain");
			else if (e.originalEvent && e.originalEvent.clipboardData.getData) data = e.originalEvent.clipboardData.getData("text/plain");
			return data;
		}
	};
	var CalcComponent = class {
		constructor(row) {
			this._row = row;
			return new Proxy(this, { get: function(target, name, receiver) {
				if (typeof target[name] !== "undefined") return target[name];
				else return target._row.table.componentFunctionBinder.handle("row", target._row, name);
			} });
		}
		getData(transform) {
			return this._row.getData(transform);
		}
		getElement() {
			return this._row.getElement();
		}
		getTable() {
			return this._row.table;
		}
		getCells() {
			var cells = [];
			this._row.getCells().forEach(function(cell) {
				cells.push(cell.getComponent());
			});
			return cells;
		}
		getCell(column) {
			var cell = this._row.getCell(column);
			return cell ? cell.getComponent() : false;
		}
		_getSelf() {
			return this._row;
		}
	};
	var CellComponent = class {
		constructor(cell) {
			this._cell = cell;
			return new Proxy(this, { get: function(target, name, receiver) {
				if (typeof target[name] !== "undefined") return target[name];
				else return target._cell.table.componentFunctionBinder.handle("cell", target._cell, name);
			} });
		}
		getValue() {
			return this._cell.getValue();
		}
		getOldValue() {
			return this._cell.getOldValue();
		}
		getInitialValue() {
			return this._cell.initialValue;
		}
		getElement() {
			return this._cell.getElement();
		}
		getRow() {
			return this._cell.row.getComponent();
		}
		getData(transform) {
			return this._cell.row.getData(transform);
		}
		getType() {
			return "cell";
		}
		getField() {
			return this._cell.column.getField();
		}
		getColumn() {
			return this._cell.column.getComponent();
		}
		setValue(value, mutate) {
			if (typeof mutate == "undefined") mutate = true;
			this._cell.setValue(value, mutate);
		}
		restoreOldValue() {
			this._cell.setValueActual(this._cell.getOldValue());
		}
		restoreInitialValue() {
			this._cell.setValueActual(this._cell.initialValue);
		}
		checkHeight() {
			this._cell.checkHeight();
		}
		getTable() {
			return this._cell.table;
		}
		_getSelf() {
			return this._cell;
		}
	};
	var Cell = class extends CoreFeature {
		constructor(column, row) {
			super(column.table);
			this.table = column.table;
			this.column = column;
			this.row = row;
			this.element = null;
			this.value = null;
			this.initialValue;
			this.oldValue = null;
			this.modules = {};
			this.height = null;
			this.width = null;
			this.minWidth = null;
			this.component = null;
			this.loaded = false;
			this.build();
		}
		build() {
			this.generateElement();
			this.setWidth();
			this._configureCell();
			this.setValueActual(this.column.getFieldValue(this.row.data));
			this.initialValue = this.value;
		}
		generateElement() {
			this.element = document.createElement("div");
			this.element.className = "tabulator-cell";
			this.element.setAttribute("role", "gridcell");
			if (this.column.isRowHeader) this.element.classList.add("tabulator-row-header");
		}
		_configureCell() {
			var element = this.element, field = this.column.getField(), vertAligns = {
				top: "flex-start",
				bottom: "flex-end",
				middle: "center"
			}, hozAligns = {
				left: "flex-start",
				right: "flex-end",
				center: "center"
			};
			element.style.textAlign = this.column.hozAlign;
			if (this.column.vertAlign) {
				element.style.display = "inline-flex";
				element.style.alignItems = vertAligns[this.column.vertAlign] || "";
				if (this.column.hozAlign) element.style.justifyContent = hozAligns[this.column.hozAlign] || "";
			}
			if (field) element.setAttribute("tabulator-field", field);
			if (this.column.definition.cssClass) this.column.definition.cssClass.split(" ").forEach((className) => {
				element.classList.add(className);
			});
			this.dispatch("cell-init", this);
			if (!this.column.visible) this.hide();
		}
		_generateContents() {
			var val = this.chain("cell-format", this, null, () => {
				return this.element.innerHTML = this.value;
			});
			switch (typeof val) {
				case "object":
					if (val instanceof Node) {
						while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
						this.element.appendChild(val);
					} else {
						this.element.innerHTML = "";
						if (val != null) console.warn("Format Error - Formatter has returned a type of object, the only valid formatter object return is an instance of Node, the formatter returned:", val);
					}
					break;
				case "undefined":
					this.element.innerHTML = "";
					break;
				default: this.element.innerHTML = val;
			}
		}
		cellRendered() {
			this.dispatch("cell-rendered", this);
		}
		getElement(containerOnly) {
			if (!this.loaded) {
				this.loaded = true;
				if (!containerOnly) this.layoutElement();
			}
			return this.element;
		}
		getValue() {
			return this.value;
		}
		getOldValue() {
			return this.oldValue;
		}
		setValue(value, mutate, force) {
			if (this.setValueProcessData(value, mutate, force)) {
				this.dispatch("cell-value-updated", this);
				this.cellRendered();
				if (this.column.definition.cellEdited) this.column.definition.cellEdited.call(this.table, this.getComponent());
				this.dispatchExternal("cellEdited", this.getComponent());
				if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.table.rowManager.getData());
			}
		}
		setValueProcessData(value, mutate, force) {
			var changed = false;
			if (this.value !== value || force) {
				changed = true;
				if (mutate) value = this.chain("cell-value-changing", [this, value], null, value);
			}
			this.setValueActual(value);
			if (changed) this.dispatch("cell-value-changed", this);
			return changed;
		}
		setValueActual(value) {
			this.oldValue = this.value;
			this.value = value;
			this.dispatch("cell-value-save-before", this);
			this.column.setFieldValue(this.row.data, value);
			this.dispatch("cell-value-save-after", this);
			if (this.loaded) this.layoutElement();
		}
		layoutElement() {
			this._generateContents();
			this.dispatch("cell-layout", this);
		}
		setWidth() {
			this.width = this.column.width;
			this.element.style.width = this.column.widthStyled;
		}
		clearWidth() {
			this.width = "";
			this.element.style.width = "";
		}
		getWidth() {
			return this.width || this.element.offsetWidth;
		}
		setMinWidth() {
			this.minWidth = this.column.minWidth;
			this.element.style.minWidth = this.column.minWidthStyled;
		}
		setMaxWidth() {
			this.maxWidth = this.column.maxWidth;
			this.element.style.maxWidth = this.column.maxWidthStyled;
		}
		checkHeight() {
			this.row.reinitializeHeight();
		}
		clearHeight() {
			this.element.style.height = "";
			this.height = null;
			this.dispatch("cell-height", this, "");
		}
		setHeight() {
			this.height = this.row.height;
			this.element.style.height = this.row.heightStyled;
			this.dispatch("cell-height", this, this.row.heightStyled);
		}
		getHeight() {
			return this.height || this.element.offsetHeight;
		}
		show() {
			this.element.style.display = this.column.vertAlign ? "inline-flex" : "";
		}
		hide() {
			this.element.style.display = "none";
		}
		delete() {
			this.dispatch("cell-delete", this);
			if (!this.table.rowManager.redrawBlock && this.element.parentNode) this.element.parentNode.removeChild(this.element);
			this.element = false;
			this.column.deleteCell(this);
			this.row.deleteCell(this);
			this.calcs = {};
		}
		getIndex() {
			return this.row.getCellIndex(this);
		}
		getComponent() {
			if (!this.component) this.component = new CellComponent(this);
			return this.component;
		}
	};
	var ColumnComponent = class {
		constructor(column) {
			this._column = column;
			this.type = "ColumnComponent";
			return new Proxy(this, { get: function(target, name, receiver) {
				if (typeof target[name] !== "undefined") return target[name];
				else return target._column.table.componentFunctionBinder.handle("column", target._column, name);
			} });
		}
		getElement() {
			return this._column.getElement();
		}
		getDefinition() {
			return this._column.getDefinition();
		}
		getField() {
			return this._column.getField();
		}
		getTitleDownload() {
			return this._column.getTitleDownload();
		}
		getCells() {
			var cells = [];
			this._column.cells.forEach(function(cell) {
				cells.push(cell.getComponent());
			});
			return cells;
		}
		isVisible() {
			return this._column.visible;
		}
		show() {
			if (this._column.isGroup) this._column.columns.forEach(function(column) {
				column.show();
			});
			else this._column.show();
		}
		hide() {
			if (this._column.isGroup) this._column.columns.forEach(function(column) {
				column.hide();
			});
			else this._column.hide();
		}
		toggle() {
			if (this._column.visible) this.hide();
			else this.show();
		}
		delete() {
			return this._column.delete();
		}
		getSubColumns() {
			var output = [];
			if (this._column.columns.length) this._column.columns.forEach(function(column) {
				output.push(column.getComponent());
			});
			return output;
		}
		getParentColumn() {
			return this._column.getParentComponent();
		}
		_getSelf() {
			return this._column;
		}
		scrollTo(position, ifVisible) {
			return this._column.table.columnManager.scrollToColumn(this._column, position, ifVisible);
		}
		getTable() {
			return this._column.table;
		}
		move(to, after) {
			var toColumn = this._column.table.columnManager.findColumn(to);
			if (toColumn) this._column.table.columnManager.moveColumn(this._column, toColumn, after);
			else console.warn("Move Error - No matching column found:", toColumn);
		}
		getNextColumn() {
			var nextCol = this._column.nextColumn();
			return nextCol ? nextCol.getComponent() : false;
		}
		getPrevColumn() {
			var prevCol = this._column.prevColumn();
			return prevCol ? prevCol.getComponent() : false;
		}
		updateDefinition(updates) {
			return this._column.updateDefinition(updates);
		}
		getWidth() {
			return this._column.getWidth();
		}
		setWidth(width) {
			var result;
			if (width === true) result = this._column.reinitializeWidth(true);
			else result = this._column.setWidth(width);
			this._column.table.columnManager.rerenderColumns(true);
			return result;
		}
	};
	var defaultColumnOptions = {
		"title": void 0,
		"field": void 0,
		"columns": void 0,
		"visible": void 0,
		"hozAlign": void 0,
		"vertAlign": void 0,
		"width": void 0,
		"minWidth": 40,
		"maxWidth": void 0,
		"maxInitialWidth": void 0,
		"cssClass": void 0,
		"variableHeight": void 0,
		"headerVertical": void 0,
		"headerHozAlign": void 0,
		"headerWordWrap": false,
		"editableTitle": void 0
	};
	var Column = class Column extends CoreFeature {
		static defaultOptionList = defaultColumnOptions;
		constructor(def, parent, rowHeader) {
			super(parent.table);
			this.definition = def;
			this.parent = parent;
			this.type = "column";
			this.columns = [];
			this.cells = [];
			this.isGroup = false;
			this.isRowHeader = rowHeader;
			this.element = this.createElement();
			this.contentElement = false;
			this.titleHolderElement = false;
			this.titleElement = false;
			this.groupElement = this.createGroupElement();
			this.hozAlign = "";
			this.vertAlign = "";
			this.field = "";
			this.fieldStructure = "";
			this.getFieldValue = "";
			this.setFieldValue = "";
			this.titleDownload = null;
			this.titleFormatterRendered = false;
			this.mapDefinitions();
			this.setField(this.definition.field);
			this.modules = {};
			this.width = null;
			this.widthStyled = "";
			this.maxWidth = null;
			this.maxWidthStyled = "";
			this.maxInitialWidth = null;
			this.minWidth = null;
			this.minWidthStyled = "";
			this.widthFixed = false;
			this.visible = true;
			this.component = null;
			if (this.definition.columns) {
				this.isGroup = true;
				this.definition.columns.forEach((def, i) => {
					var newCol = new Column(def, this);
					this.attachColumn(newCol);
				});
				this.checkColumnVisibility();
			} else parent.registerColumnField(this);
			this._initialize();
		}
		createElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-col");
			el.setAttribute("role", "columnheader");
			el.setAttribute("aria-sort", "none");
			if (this.isRowHeader) el.classList.add("tabulator-row-header");
			switch (this.table.options.columnHeaderVertAlign) {
				case "middle":
					el.style.justifyContent = "center";
					break;
				case "bottom":
					el.style.justifyContent = "flex-end";
					break;
			}
			return el;
		}
		createGroupElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-col-group-cols");
			return el;
		}
		mapDefinitions() {
			var defaults = this.table.options.columnDefaults;
			if (defaults) {
				for (let key in defaults) if (typeof this.definition[key] === "undefined") this.definition[key] = defaults[key];
			}
			this.definition = this.table.columnManager.optionsList.generate(Column.defaultOptionList, this.definition);
		}
		checkDefinition() {
			Object.keys(this.definition).forEach((key) => {
				if (Column.defaultOptionList.indexOf(key) === -1) console.warn("Invalid column definition option in '" + (this.field || this.definition.title) + "' column:", key);
			});
		}
		setField(field) {
			this.field = field;
			this.fieldStructure = field ? this.table.options.nestedFieldSeparator ? field.split(this.table.options.nestedFieldSeparator) : [field] : [];
			this.getFieldValue = this.fieldStructure.length > 1 ? this._getNestedData : this._getFlatData;
			this.setFieldValue = this.fieldStructure.length > 1 ? this._setNestedData : this._setFlatData;
		}
		registerColumnPosition(column) {
			this.parent.registerColumnPosition(column);
		}
		registerColumnField(column) {
			this.parent.registerColumnField(column);
		}
		reRegisterPosition() {
			if (this.isGroup) this.columns.forEach(function(column) {
				column.reRegisterPosition();
			});
			else this.registerColumnPosition(this);
		}
		_initialize() {
			var def = this.definition;
			while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
			if (def.headerVertical) {
				this.element.classList.add("tabulator-col-vertical");
				if (def.headerVertical === "flip") this.element.classList.add("tabulator-col-vertical-flip");
			}
			this.contentElement = this._buildColumnHeaderContent();
			this.element.appendChild(this.contentElement);
			if (this.isGroup) this._buildGroupHeader();
			else this._buildColumnHeader();
			this.dispatch("column-init", this);
		}
		_buildColumnHeader() {
			var def = this.definition;
			this.dispatch("column-layout", this);
			if (typeof def.visible != "undefined") if (def.visible) this.show(true);
			else this.hide(true);
			if (def.cssClass) def.cssClass.split(" ").forEach((className) => {
				this.element.classList.add(className);
			});
			if (def.field) this.element.setAttribute("tabulator-field", def.field);
			this.setMinWidth(parseInt(def.minWidth));
			if (def.maxInitialWidth) this.maxInitialWidth = parseInt(def.maxInitialWidth);
			if (def.maxWidth) this.setMaxWidth(parseInt(def.maxWidth));
			this.reinitializeWidth();
			this.hozAlign = this.definition.hozAlign;
			this.vertAlign = this.definition.vertAlign;
			this.titleElement.style.textAlign = this.definition.headerHozAlign;
		}
		_buildColumnHeaderContent() {
			var contentElement = document.createElement("div");
			contentElement.classList.add("tabulator-col-content");
			this.titleHolderElement = document.createElement("div");
			this.titleHolderElement.classList.add("tabulator-col-title-holder");
			contentElement.appendChild(this.titleHolderElement);
			this.titleElement = this._buildColumnHeaderTitle();
			this.titleHolderElement.appendChild(this.titleElement);
			return contentElement;
		}
		_buildColumnHeaderTitle() {
			var def = this.definition;
			var titleHolderElement = document.createElement("div");
			titleHolderElement.classList.add("tabulator-col-title");
			if (def.headerWordWrap) titleHolderElement.classList.add("tabulator-col-title-wrap");
			if (def.editableTitle) {
				var titleElement = document.createElement("input");
				titleElement.classList.add("tabulator-title-editor");
				titleElement.addEventListener("click", (e) => {
					e.stopPropagation();
					titleElement.focus();
				});
				titleElement.addEventListener("mousedown", (e) => {
					e.stopPropagation();
				});
				titleElement.addEventListener("change", () => {
					def.title = titleElement.value;
					this.dispatchExternal("columnTitleChanged", this.getComponent());
				});
				titleHolderElement.appendChild(titleElement);
				if (def.field) this.langBind("columns|" + def.field, (text) => {
					titleElement.value = text || def.title || "&nbsp;";
				});
				else titleElement.value = def.title || "&nbsp;";
			} else if (def.field) this.langBind("columns|" + def.field, (text) => {
				this._formatColumnHeaderTitle(titleHolderElement, text || def.title || "&nbsp;");
			});
			else this._formatColumnHeaderTitle(titleHolderElement, def.title || "&nbsp;");
			return titleHolderElement;
		}
		_formatColumnHeaderTitle(el, title) {
			var contents = this.chain("column-format", [
				this,
				title,
				el
			], null, () => {
				return title;
			});
			switch (typeof contents) {
				case "object":
					if (contents instanceof Node) el.appendChild(contents);
					else {
						el.innerHTML = "";
						console.warn("Format Error - Title formatter has returned a type of object, the only valid formatter object return is an instance of Node, the formatter returned:", contents);
					}
					break;
				case "undefined":
					el.innerHTML = "";
					break;
				default: el.innerHTML = contents;
			}
		}
		_buildGroupHeader() {
			this.element.classList.add("tabulator-col-group");
			this.element.setAttribute("role", "columngroup");
			this.element.setAttribute("aria-title", this.definition.title);
			if (this.definition.cssClass) this.definition.cssClass.split(" ").forEach((className) => {
				this.element.classList.add(className);
			});
			this.titleElement.style.textAlign = this.definition.headerHozAlign;
			this.element.appendChild(this.groupElement);
		}
		_getFlatData(data) {
			return data[this.field];
		}
		_getNestedData(data) {
			var dataObj = data, structure = this.fieldStructure, length = structure.length, output;
			for (let i = 0; i < length; i++) {
				dataObj = dataObj[structure[i]];
				output = dataObj;
				if (!dataObj) break;
			}
			return output;
		}
		_setFlatData(data, value) {
			if (this.field) data[this.field] = value;
		}
		_setNestedData(data, value) {
			var dataObj = data, structure = this.fieldStructure, length = structure.length;
			for (let i = 0; i < length; i++) if (i == length - 1) dataObj[structure[i]] = value;
			else {
				if (!dataObj[structure[i]]) if (typeof value !== "undefined") dataObj[structure[i]] = {};
				else break;
				dataObj = dataObj[structure[i]];
			}
		}
		attachColumn(column) {
			if (this.groupElement) {
				this.columns.push(column);
				this.groupElement.appendChild(column.getElement());
				column.columnRendered();
			} else console.warn("Column Warning - Column being attached to another column instead of column group");
		}
		verticalAlign(alignment, height) {
			var parentHeight = this.parent.isGroup ? this.parent.getGroupElement().clientHeight : height || this.parent.getHeadersElement().clientHeight;
			this.element.style.height = parentHeight + "px";
			this.dispatch("column-height", this, this.element.style.height);
			if (this.isGroup) this.groupElement.style.minHeight = parentHeight - this.contentElement.offsetHeight + "px";
			this.columns.forEach(function(column) {
				column.verticalAlign(alignment);
			});
		}
		clearVerticalAlign() {
			this.element.style.paddingTop = "";
			this.element.style.height = "";
			this.element.style.minHeight = "";
			this.groupElement.style.minHeight = "";
			this.columns.forEach(function(column) {
				column.clearVerticalAlign();
			});
			this.dispatch("column-height", this, "");
		}
		getElement() {
			return this.element;
		}
		getGroupElement() {
			return this.groupElement;
		}
		getField() {
			return this.field;
		}
		getTitleDownload() {
			return this.titleDownload;
		}
		getFirstColumn() {
			if (!this.isGroup) return this;
			else if (this.columns.length) return this.columns[0].getFirstColumn();
			else return false;
		}
		getLastColumn() {
			if (!this.isGroup) return this;
			else if (this.columns.length) return this.columns[this.columns.length - 1].getLastColumn();
			else return false;
		}
		getColumns(traverse) {
			var columns = [];
			if (traverse) this.columns.forEach((column) => {
				columns.push(column);
				columns = columns.concat(column.getColumns(true));
			});
			else columns = this.columns;
			return columns;
		}
		getCells() {
			return this.cells;
		}
		getTopColumn() {
			if (this.parent.isGroup) return this.parent.getTopColumn();
			else return this;
		}
		getDefinition(updateBranches) {
			var colDefs = [];
			if (this.isGroup && updateBranches) {
				this.columns.forEach(function(column) {
					colDefs.push(column.getDefinition(true));
				});
				this.definition.columns = colDefs;
			}
			return this.definition;
		}
		checkColumnVisibility() {
			var visible = false;
			this.columns.forEach(function(column) {
				if (column.visible) visible = true;
			});
			if (visible) {
				this.show();
				this.dispatchExternal("columnVisibilityChanged", this.getComponent(), false);
			} else this.hide();
		}
		show(silent, responsiveToggle) {
			if (!this.visible) {
				this.visible = true;
				this.element.style.display = "";
				if (this.parent.isGroup) this.parent.checkColumnVisibility();
				this.cells.forEach(function(cell) {
					cell.show();
				});
				if (!this.isGroup && this.width === null) this.reinitializeWidth();
				this.table.columnManager.verticalAlignHeaders();
				this.dispatch("column-show", this, responsiveToggle);
				if (!silent) this.dispatchExternal("columnVisibilityChanged", this.getComponent(), true);
				if (this.parent.isGroup) this.parent.matchChildWidths();
				if (!this.silent) this.table.columnManager.rerenderColumns();
			}
		}
		hide(silent, responsiveToggle) {
			if (this.visible) {
				this.visible = false;
				this.element.style.display = "none";
				this.table.columnManager.verticalAlignHeaders();
				if (this.parent.isGroup) this.parent.checkColumnVisibility();
				this.cells.forEach(function(cell) {
					cell.hide();
				});
				this.dispatch("column-hide", this, responsiveToggle);
				if (!silent) this.dispatchExternal("columnVisibilityChanged", this.getComponent(), false);
				if (this.parent.isGroup) this.parent.matchChildWidths();
				if (!this.silent) this.table.columnManager.rerenderColumns();
			}
		}
		matchChildWidths() {
			var childWidth = 0;
			if (this.contentElement && this.columns.length) {
				this.columns.forEach(function(column) {
					if (column.visible) childWidth += column.getWidth();
				});
				this.contentElement.style.maxWidth = childWidth - 1 + "px";
				if (this.table.initialized) this.element.style.width = childWidth + "px";
				if (this.parent.isGroup) this.parent.matchChildWidths();
			}
		}
		removeChild(child) {
			var index = this.columns.indexOf(child);
			if (index > -1) this.columns.splice(index, 1);
			if (!this.columns.length) this.delete();
		}
		setWidth(width) {
			this.widthFixed = true;
			this.setWidthActual(width);
		}
		setWidthActual(width) {
			if (isNaN(width)) width = Math.floor(this.table.element.clientWidth / 100 * parseInt(width));
			width = Math.max(this.minWidth, width);
			if (this.maxWidth) width = Math.min(this.maxWidth, width);
			this.width = width;
			this.widthStyled = width ? width + "px" : "";
			this.element.style.width = this.widthStyled;
			if (!this.isGroup) this.cells.forEach(function(cell) {
				cell.setWidth();
			});
			if (this.parent.isGroup) this.parent.matchChildWidths();
			this.dispatch("column-width", this);
			if (this.subscribedExternal("columnWidth")) this.dispatchExternal("columnWidth", this.getComponent());
		}
		checkCellHeights() {
			var rows = [];
			this.cells.forEach(function(cell) {
				if (cell.row.heightInitialized) if (cell.row.getElement().offsetParent !== null) {
					rows.push(cell.row);
					cell.row.clearCellHeight();
				} else cell.row.heightInitialized = false;
			});
			rows.forEach(function(row) {
				row.calcHeight();
			});
			rows.forEach(function(row) {
				row.setCellHeight();
			});
		}
		getWidth() {
			var width = 0;
			if (this.isGroup) this.columns.forEach(function(column) {
				if (column.visible) width += column.getWidth();
			});
			else width = this.width;
			return width;
		}
		getLeftOffset() {
			var offset = this.element.offsetLeft;
			if (this.parent.isGroup) offset += this.parent.getLeftOffset();
			return offset;
		}
		getHeight() {
			return Math.ceil(this.element.getBoundingClientRect().height);
		}
		setMinWidth(minWidth) {
			if (this.maxWidth && minWidth > this.maxWidth) {
				minWidth = this.maxWidth;
				console.warn("the minWidth (" + minWidth + "px) for column '" + this.field + "' cannot be bigger that its maxWidth (" + this.maxWidthStyled + ")");
			}
			this.minWidth = minWidth;
			this.minWidthStyled = minWidth ? minWidth + "px" : "";
			this.element.style.minWidth = this.minWidthStyled;
			this.cells.forEach(function(cell) {
				cell.setMinWidth();
			});
		}
		setMaxWidth(maxWidth) {
			if (this.minWidth && maxWidth < this.minWidth) {
				maxWidth = this.minWidth;
				console.warn("the maxWidth (" + maxWidth + "px) for column '" + this.field + "' cannot be smaller that its minWidth (" + this.minWidthStyled + ")");
			}
			this.maxWidth = maxWidth;
			this.maxWidthStyled = maxWidth ? maxWidth + "px" : "";
			this.element.style.maxWidth = this.maxWidthStyled;
			this.cells.forEach(function(cell) {
				cell.setMaxWidth();
			});
		}
		delete() {
			return new Promise((resolve, reject) => {
				if (this.isGroup) this.columns.forEach(function(column) {
					column.delete();
				});
				this.dispatch("column-delete", this);
				var cellCount = this.cells.length;
				for (let i = 0; i < cellCount; i++) this.cells[0].delete();
				if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
				this.element = false;
				this.contentElement = false;
				this.titleElement = false;
				this.groupElement = false;
				if (this.parent.isGroup) this.parent.removeChild(this);
				this.table.columnManager.deregisterColumn(this);
				this.table.columnManager.rerenderColumns(true);
				this.dispatch("column-deleted", this);
				resolve();
			});
		}
		columnRendered() {
			if (this.titleFormatterRendered) this.titleFormatterRendered();
			this.dispatch("column-rendered", this);
		}
		generateCell(row) {
			var cell = new Cell(this, row);
			this.cells.push(cell);
			return cell;
		}
		nextColumn() {
			var index = this.table.columnManager.findColumnIndex(this);
			return index > -1 ? this._nextVisibleColumn(index + 1) : false;
		}
		_nextVisibleColumn(index) {
			var column = this.table.columnManager.getColumnByIndex(index);
			return !column || column.visible ? column : this._nextVisibleColumn(index + 1);
		}
		prevColumn() {
			var index = this.table.columnManager.findColumnIndex(this);
			return index > -1 ? this._prevVisibleColumn(index - 1) : false;
		}
		_prevVisibleColumn(index) {
			var column = this.table.columnManager.getColumnByIndex(index);
			return !column || column.visible ? column : this._prevVisibleColumn(index - 1);
		}
		reinitializeWidth(force) {
			this.widthFixed = false;
			if (typeof this.definition.width !== "undefined" && !force) this.setWidth(this.definition.width);
			this.dispatch("column-width-fit-before", this);
			this.fitToData(force);
			this.dispatch("column-width-fit-after", this);
		}
		fitToData(force) {
			if (this.isGroup) return;
			if (!this.widthFixed) {
				this.element.style.width = "";
				this.cells.forEach((cell) => {
					cell.clearWidth();
				});
			}
			var maxWidth = this.element.offsetWidth;
			if (!this.width || !this.widthFixed) {
				this.cells.forEach((cell) => {
					var width = cell.getWidth();
					if (width > maxWidth) maxWidth = width;
				});
				if (maxWidth) {
					var setTo = maxWidth + 1;
					if (force) this.setWidth(setTo);
					else {
						if (this.maxInitialWidth && !force) setTo = Math.min(setTo, this.maxInitialWidth);
						this.setWidthActual(setTo);
					}
				}
			}
		}
		updateDefinition(updates) {
			var definition;
			if (!this.isGroup) if (!this.parent.isGroup) {
				definition = Object.assign({}, this.getDefinition());
				definition = Object.assign(definition, updates);
				return this.table.columnManager.addColumn(definition, false, this).then((column) => {
					if (definition.field == this.field) this.field = false;
					return this.delete().then(() => {
						return column.getComponent();
					});
				});
			} else {
				console.error("Column Update Error - The updateDefinition function is only available on ungrouped columns");
				return Promise.reject("Column Update Error - The updateDefinition function is only available on columns, not column groups");
			}
			else {
				console.error("Column Update Error - The updateDefinition function is only available on ungrouped columns");
				return Promise.reject("Column Update Error - The updateDefinition function is only available on columns, not column groups");
			}
		}
		deleteCell(cell) {
			var index = this.cells.indexOf(cell);
			if (index > -1) this.cells.splice(index, 1);
		}
		getComponent() {
			if (!this.component) this.component = new ColumnComponent(this);
			return this.component;
		}
		getPosition() {
			return this.table.columnManager.getVisibleColumnsByIndex().indexOf(this) + 1;
		}
		getParentComponent() {
			return this.parent instanceof Column ? this.parent.getComponent() : false;
		}
	};
	var RowComponent = class {
		constructor(row) {
			this._row = row;
			return new Proxy(this, { get: function(target, name, receiver) {
				if (typeof target[name] !== "undefined") return target[name];
				else return target._row.table.componentFunctionBinder.handle("row", target._row, name);
			} });
		}
		getData(transform) {
			return this._row.getData(transform);
		}
		getElement() {
			return this._row.getElement();
		}
		getCells() {
			var cells = [];
			this._row.getCells().forEach(function(cell) {
				cells.push(cell.getComponent());
			});
			return cells;
		}
		getCell(column) {
			var cell = this._row.getCell(column);
			return cell ? cell.getComponent() : false;
		}
		getIndex() {
			return this._row.getData("data")[this._row.table.options.index];
		}
		getPosition() {
			return this._row.getPosition();
		}
		watchPosition(callback) {
			return this._row.watchPosition(callback);
		}
		delete() {
			return this._row.delete();
		}
		scrollTo(position, ifVisible) {
			return this._row.table.rowManager.scrollToRow(this._row, position, ifVisible);
		}
		move(to, after) {
			this._row.moveToRow(to, after);
		}
		update(data) {
			return this._row.updateData(data);
		}
		normalizeHeight() {
			this._row.normalizeHeight(true);
		}
		_getSelf() {
			return this._row;
		}
		reformat() {
			return this._row.reinitialize();
		}
		getTable() {
			return this._row.table;
		}
		getNextRow() {
			var row = this._row.nextRow();
			return row ? row.getComponent() : row;
		}
		getPrevRow() {
			var row = this._row.prevRow();
			return row ? row.getComponent() : row;
		}
	};
	var Row$1 = class extends CoreFeature {
		constructor(data, parent, type = "row") {
			super(parent.table);
			this.parent = parent;
			this.data = {};
			this.type = type;
			this.element = false;
			this.modules = {};
			this.cells = [];
			this.height = 0;
			this.heightStyled = "";
			this.manualHeight = false;
			this.outerHeight = 0;
			this.initialized = false;
			this.heightInitialized = false;
			this.position = 0;
			this.positionWatchers = [];
			this.component = null;
			this.created = false;
			this.setData(data);
		}
		create() {
			if (!this.created) {
				this.created = true;
				this.generateElement();
			}
		}
		createElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-row");
			el.setAttribute("role", "row");
			this.element = el;
		}
		getElement() {
			this.create();
			return this.element;
		}
		detachElement() {
			if (this.element && this.element.parentNode) this.element.parentNode.removeChild(this.element);
		}
		generateElement() {
			this.createElement();
			this.dispatch("row-init", this);
		}
		generateCells() {
			this.cells = this.table.columnManager.generateCells(this);
		}
		initialize(force, inFragment) {
			this.create();
			if (!this.initialized || force) {
				this.deleteCells();
				while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
				this.dispatch("row-layout-before", this);
				this.generateCells();
				this.initialized = true;
				this.table.columnManager.renderer.renderRowCells(this, inFragment);
				if (force) this.normalizeHeight();
				this.dispatch("row-layout", this);
				if (this.table.options.rowFormatter) this.table.options.rowFormatter(this.getComponent());
				this.dispatch("row-layout-after", this);
			} else this.table.columnManager.renderer.rerenderRowCells(this, inFragment);
		}
		rendered() {
			this.cells.forEach((cell) => {
				cell.cellRendered();
			});
		}
		reinitializeHeight() {
			this.heightInitialized = false;
			if (this.element && this.element.offsetParent !== null) this.normalizeHeight(true);
		}
		deinitialize() {
			this.initialized = false;
		}
		deinitializeHeight() {
			this.heightInitialized = false;
		}
		reinitialize(children) {
			this.initialized = false;
			this.heightInitialized = false;
			if (!this.manualHeight) {
				this.height = 0;
				this.heightStyled = "";
			}
			if (this.element && this.element.offsetParent !== null) this.initialize(true);
			this.dispatch("row-relayout", this);
		}
		calcHeight(force) {
			var maxHeight = 0, minHeight = 0;
			if (this.table.options.rowHeight) this.height = this.table.options.rowHeight;
			else {
				minHeight = this.calcMinHeight();
				maxHeight = this.calcMaxHeight();
				if (force) this.height = Math.max(maxHeight, minHeight);
				else this.height = this.manualHeight ? this.height : Math.max(maxHeight, minHeight);
			}
			this.heightStyled = this.height ? this.height + "px" : "";
			this.outerHeight = this.element.offsetHeight;
		}
		calcMinHeight() {
			return this.table.options.resizableRows ? this.element.clientHeight : 0;
		}
		calcMaxHeight() {
			var maxHeight = 0;
			this.cells.forEach(function(cell) {
				var height = cell.getHeight();
				if (height > maxHeight) maxHeight = height;
			});
			return maxHeight;
		}
		setCellHeight() {
			this.cells.forEach(function(cell) {
				cell.setHeight();
			});
			this.heightInitialized = true;
		}
		clearCellHeight() {
			this.cells.forEach(function(cell) {
				cell.clearHeight();
			});
		}
		normalizeHeight(force) {
			if (force && !this.table.options.rowHeight) this.clearCellHeight();
			this.calcHeight(force);
			this.setCellHeight();
		}
		setHeight(height, force) {
			if (this.height != height || force) {
				this.manualHeight = true;
				this.height = height;
				this.heightStyled = height ? height + "px" : "";
				this.setCellHeight();
				this.outerHeight = this.element.offsetHeight;
				if (this.subscribedExternal("rowHeight")) this.dispatchExternal("rowHeight", this.getComponent());
			}
		}
		getHeight() {
			return this.outerHeight;
		}
		getWidth() {
			return this.element.offsetWidth;
		}
		deleteCell(cell) {
			var index = this.cells.indexOf(cell);
			if (index > -1) this.cells.splice(index, 1);
		}
		setData(data) {
			this.data = this.chain("row-data-init-before", [this, data], void 0, data);
			this.dispatch("row-data-init-after", this);
		}
		updateData(updatedData) {
			var visible = this.element && Helpers.elVisible(this.element), tempData = {}, newRowData;
			return new Promise((resolve, reject) => {
				if (typeof updatedData === "string") updatedData = JSON.parse(updatedData);
				this.dispatch("row-data-save-before", this);
				if (this.subscribed("row-data-changing")) {
					tempData = Object.assign(tempData, this.data);
					tempData = Object.assign(tempData, updatedData);
				}
				newRowData = this.chain("row-data-changing", [
					this,
					tempData,
					updatedData
				], null, updatedData);
				for (let attrname in newRowData) this.data[attrname] = newRowData[attrname];
				this.dispatch("row-data-save-after", this);
				for (let attrname in updatedData) this.table.columnManager.getColumnsByFieldRoot(attrname).forEach((column) => {
					let cell = this.getCell(column.getField());
					if (cell) {
						let value = column.getFieldValue(newRowData);
						if (cell.getValue() !== value) {
							cell.setValueProcessData(value);
							if (visible) cell.cellRendered();
						}
					}
				});
				if (visible) {
					this.normalizeHeight(true);
					if (this.table.options.rowFormatter) this.table.options.rowFormatter(this.getComponent());
				} else {
					this.initialized = false;
					this.height = 0;
					this.heightStyled = "";
				}
				this.dispatch("row-data-changed", this, visible, updatedData);
				this.dispatchExternal("rowUpdated", this.getComponent());
				if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.table.rowManager.getData());
				resolve();
			});
		}
		getData(transform) {
			if (transform) return this.chain("row-data-retrieve", [this, transform], null, this.data);
			return this.data;
		}
		getCell(column) {
			var match = false;
			column = this.table.columnManager.findColumn(column);
			if (!this.initialized && this.cells.length === 0) this.generateCells();
			match = this.cells.find(function(cell) {
				return cell.column === column;
			});
			return match;
		}
		getCellIndex(findCell) {
			return this.cells.findIndex(function(cell) {
				return cell === findCell;
			});
		}
		findCell(subject) {
			return this.cells.find((cell) => {
				return cell.element === subject;
			});
		}
		getCells() {
			if (!this.initialized && this.cells.length === 0) this.generateCells();
			return this.cells;
		}
		nextRow() {
			return this.table.rowManager.nextDisplayRow(this, true) || false;
		}
		prevRow() {
			return this.table.rowManager.prevDisplayRow(this, true) || false;
		}
		moveToRow(to, before) {
			var toRow = this.table.rowManager.findRow(to);
			if (toRow) {
				this.table.rowManager.moveRowActual(this, toRow, !before);
				this.table.rowManager.refreshActiveData("display", false, true);
			} else console.warn("Move Error - No matching row found:", to);
		}
		delete() {
			this.dispatch("row-delete", this);
			this.deleteActual();
			return Promise.resolve();
		}
		deleteActual(blockRedraw) {
			this.detachModules();
			this.table.rowManager.deleteRow(this, blockRedraw);
			this.deleteCells();
			this.initialized = false;
			this.heightInitialized = false;
			this.element = false;
			this.dispatch("row-deleted", this);
		}
		detachModules() {
			this.dispatch("row-deleting", this);
		}
		deleteCells() {
			var cellCount = this.cells.length;
			for (let i = 0; i < cellCount; i++) this.cells[0].delete();
		}
		wipe() {
			this.detachModules();
			this.deleteCells();
			if (this.element) {
				while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
				if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
			}
			this.element = false;
			this.modules = {};
		}
		isDisplayed() {
			return this.table.rowManager.getDisplayRows().includes(this);
		}
		getPosition() {
			return this.isDisplayed() ? this.position : false;
		}
		setPosition(position) {
			if (position != this.position) {
				this.position = position;
				this.positionWatchers.forEach((callback) => {
					callback(this.position);
				});
			}
		}
		watchPosition(callback) {
			this.positionWatchers.push(callback);
			callback(this.position);
		}
		getGroup() {
			return this.modules.group || false;
		}
		getComponent() {
			if (!this.component) this.component = new RowComponent(this);
			return this.component;
		}
	};
	var defaultCalculations = {
		"avg": function(values, data, calcParams) {
			var output = 0, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : 2;
			if (values.length) {
				output = values.reduce(function(sum, value) {
					return Number(sum) + Number(value);
				});
				output = output / values.length;
				output = precision !== false ? output.toFixed(precision) : output;
			}
			return parseFloat(output).toString();
		},
		"max": function(values, data, calcParams) {
			var output = null, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
			values.forEach(function(value) {
				value = Number(value);
				if (value > output || output === null) output = value;
			});
			return output !== null ? precision !== false ? output.toFixed(precision) : output : "";
		},
		"min": function(values, data, calcParams) {
			var output = null, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
			values.forEach(function(value) {
				value = Number(value);
				if (value < output || output === null) output = value;
			});
			return output !== null ? precision !== false ? output.toFixed(precision) : output : "";
		},
		"sum": function(values, data, calcParams) {
			var output = 0, precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
			if (values.length) values.forEach(function(value) {
				value = Number(value);
				output += !isNaN(value) ? Number(value) : 0;
			});
			return precision !== false ? output.toFixed(precision) : output;
		},
		"concat": function(values, data, calcParams) {
			var output = 0;
			if (values.length) output = values.reduce(function(sum, value) {
				return String(sum) + String(value);
			});
			return output;
		},
		"count": function(values, data, calcParams) {
			var output = 0;
			if (values.length) values.forEach(function(value) {
				if (value) output++;
			});
			return output;
		},
		"unique": function(values, data, calcParams) {
			return values.filter((value, index) => {
				return (values || value === 0) && values.indexOf(value) === index;
			}).length;
		}
	};
	var ColumnCalcs = class ColumnCalcs extends Module {
		static moduleName = "columnCalcs";
		static calculations = defaultCalculations;
		constructor(table) {
			super(table);
			this.topCalcs = [];
			this.botCalcs = [];
			this.genColumn = false;
			this.topElement = this.createElement();
			this.botElement = this.createElement();
			this.topRow = false;
			this.botRow = false;
			this.topInitialized = false;
			this.botInitialized = false;
			this.blocked = false;
			this.recalcAfterBlock = false;
			this.registerTableOption("columnCalcs", true);
			this.registerColumnOption("topCalc");
			this.registerColumnOption("topCalcParams");
			this.registerColumnOption("topCalcFormatter");
			this.registerColumnOption("topCalcFormatterParams");
			this.registerColumnOption("bottomCalc");
			this.registerColumnOption("bottomCalcParams");
			this.registerColumnOption("bottomCalcFormatter");
			this.registerColumnOption("bottomCalcFormatterParams");
		}
		createElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-calcs-holder");
			return el;
		}
		initialize() {
			this.genColumn = new Column({ field: "value" }, this);
			this.subscribe("cell-value-changed", this.cellValueChanged.bind(this));
			this.subscribe("column-init", this.initializeColumnCheck.bind(this));
			this.subscribe("row-deleted", this.rowsUpdated.bind(this));
			this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
			this.subscribe("row-added", this.rowsUpdated.bind(this));
			this.subscribe("column-moved", this.recalcActiveRows.bind(this));
			this.subscribe("column-add", this.recalcActiveRows.bind(this));
			this.subscribe("data-refreshed", this.recalcActiveRowsRefresh.bind(this));
			this.subscribe("table-redraw", this.tableRedraw.bind(this));
			this.subscribe("rows-visible", this.visibleRows.bind(this));
			this.subscribe("scrollbar-vertical", this.adjustForScrollbar.bind(this));
			this.subscribe("redraw-blocked", this.blockRedraw.bind(this));
			this.subscribe("redraw-restored", this.restoreRedraw.bind(this));
			this.subscribe("table-redrawing", this.resizeHolderWidth.bind(this));
			this.subscribe("column-resized", this.resizeHolderWidth.bind(this));
			this.subscribe("column-show", this.resizeHolderWidth.bind(this));
			this.subscribe("column-hide", this.resizeHolderWidth.bind(this));
			this.registerTableFunction("getCalcResults", this.getResults.bind(this));
			this.registerTableFunction("recalc", this.userRecalc.bind(this));
			this.resizeHolderWidth();
		}
		resizeHolderWidth() {
			this.topElement.style.minWidth = this.table.columnManager.headersElement.offsetWidth + "px";
		}
		tableRedraw(force) {
			this.recalc(this.table.rowManager.activeRows);
			if (force) this.redraw();
		}
		blockRedraw() {
			this.blocked = true;
			this.recalcAfterBlock = false;
		}
		restoreRedraw() {
			this.blocked = false;
			if (this.recalcAfterBlock) {
				this.recalcAfterBlock = false;
				this.recalcActiveRowsRefresh();
			}
		}
		userRecalc() {
			this.recalc(this.table.rowManager.activeRows);
		}
		blockCheck() {
			if (this.blocked) this.recalcAfterBlock = true;
			return this.blocked;
		}
		visibleRows(viewable, rows) {
			if (this.topRow) rows.unshift(this.topRow);
			if (this.botRow) rows.push(this.botRow);
			return rows;
		}
		rowsUpdated(row) {
			if (this.table.options.groupBy) this.recalcRowGroup(row);
			else this.recalcActiveRows();
		}
		recalcActiveRowsRefresh() {
			if (this.table.options.groupBy && this.table.options.dataTreeStartExpanded && this.table.options.dataTree) this.recalcAll();
			else this.recalcActiveRows();
		}
		recalcActiveRows() {
			this.recalc(this.table.rowManager.activeRows);
		}
		cellValueChanged(cell) {
			if (cell.column.definition.topCalc || cell.column.definition.bottomCalc) if (this.table.options.groupBy) {
				if (this.table.options.columnCalcs == "table" || this.table.options.columnCalcs == "both") this.recalcActiveRows();
				if (this.table.options.columnCalcs != "table") this.recalcRowGroup(cell.row);
			} else this.recalcActiveRows();
		}
		initializeColumnCheck(column) {
			if (column.definition.topCalc || column.definition.bottomCalc) this.initializeColumn(column);
		}
		initializeColumn(column) {
			var def = column.definition;
			var config = {
				topCalcParams: def.topCalcParams || {},
				botCalcParams: def.bottomCalcParams || {}
			};
			if (def.topCalc) {
				switch (typeof def.topCalc) {
					case "string":
						if (ColumnCalcs.calculations[def.topCalc]) config.topCalc = ColumnCalcs.calculations[def.topCalc];
						else console.warn("Column Calc Error - No such calculation found, ignoring: ", def.topCalc);
						break;
					case "function":
						config.topCalc = def.topCalc;
						break;
				}
				if (config.topCalc) {
					column.modules.columnCalcs = config;
					this.topCalcs.push(column);
					if (this.table.options.columnCalcs != "group") this.initializeTopRow();
				}
			}
			if (def.bottomCalc) {
				switch (typeof def.bottomCalc) {
					case "string":
						if (ColumnCalcs.calculations[def.bottomCalc]) config.botCalc = ColumnCalcs.calculations[def.bottomCalc];
						else console.warn("Column Calc Error - No such calculation found, ignoring: ", def.bottomCalc);
						break;
					case "function":
						config.botCalc = def.bottomCalc;
						break;
				}
				if (config.botCalc) {
					column.modules.columnCalcs = config;
					this.botCalcs.push(column);
					if (this.table.options.columnCalcs != "group") this.initializeBottomRow();
				}
			}
		}
		registerColumnField() {}
		removeCalcs() {
			var changed = false;
			if (this.topInitialized) {
				this.topInitialized = false;
				this.topElement.parentNode.removeChild(this.topElement);
				changed = true;
			}
			if (this.botInitialized) {
				this.botInitialized = false;
				this.footerRemove(this.botElement);
				changed = true;
			}
			if (changed) this.table.rowManager.adjustTableSize();
		}
		reinitializeCalcs() {
			if (this.topCalcs.length) this.initializeTopRow();
			if (this.botCalcs.length) this.initializeBottomRow();
		}
		initializeTopRow() {
			var fragment = document.createDocumentFragment();
			if (!this.topInitialized) {
				fragment.appendChild(document.createElement("br"));
				fragment.appendChild(this.topElement);
				this.table.columnManager.getContentsElement().insertBefore(fragment, this.table.columnManager.headersElement.nextSibling);
				this.topInitialized = true;
			}
		}
		initializeBottomRow() {
			if (!this.botInitialized) {
				this.footerPrepend(this.botElement);
				this.botInitialized = true;
			}
		}
		scrollHorizontal(left) {
			if (this.botInitialized && this.botRow) this.botElement.scrollLeft = left;
		}
		recalc(rows) {
			var data, row;
			if (!this.blockCheck()) {
				if (this.topInitialized || this.botInitialized) {
					data = this.rowsToData(rows);
					if (this.topInitialized) {
						if (this.topRow) this.topRow.deleteCells();
						row = this.generateRow("top", data);
						this.topRow = row;
						while (this.topElement.firstChild) this.topElement.removeChild(this.topElement.firstChild);
						this.topElement.appendChild(row.getElement());
						row.initialize(true);
					}
					if (this.botInitialized) {
						if (this.botRow) this.botRow.deleteCells();
						row = this.generateRow("bottom", data);
						this.botRow = row;
						while (this.botElement.firstChild) this.botElement.removeChild(this.botElement.firstChild);
						this.botElement.appendChild(row.getElement());
						row.initialize(true);
					}
					this.table.rowManager.adjustTableSize();
					if (this.table.modExists("frozenColumns")) this.table.modules.frozenColumns.layout();
				}
			}
		}
		recalcRowGroup(row) {
			this.recalcGroup(this.table.modules.groupRows.getRowGroup(row));
		}
		recalcAll() {
			if (this.topCalcs.length || this.botCalcs.length) {
				if (this.table.options.columnCalcs !== "group") this.recalcActiveRows();
				if (this.table.options.groupBy && this.table.options.columnCalcs !== "table") this.table.modules.groupRows.getChildGroups().forEach((group) => {
					this.recalcGroup(group);
				});
			}
		}
		recalcGroup(group) {
			var data, rowData;
			if (!this.blockCheck()) {
				if (group) {
					if (group.calcs) {
						if (group.calcs.bottom) {
							data = this.rowsToData(group.rows);
							rowData = this.generateRowData("bottom", data);
							group.calcs.bottom.updateData(rowData);
							group.calcs.bottom.reinitialize();
						}
						if (group.calcs.top) {
							data = this.rowsToData(group.rows);
							rowData = this.generateRowData("top", data);
							group.calcs.top.updateData(rowData);
							group.calcs.top.reinitialize();
						}
					}
				}
			}
		}
		generateTopRow(rows) {
			return this.generateRow("top", this.rowsToData(rows));
		}
		generateBottomRow(rows) {
			return this.generateRow("bottom", this.rowsToData(rows));
		}
		rowsToData(rows) {
			var data = [], hasDataTreeColumnCalcs = this.table.options.dataTree && this.table.options.dataTreeChildColumnCalcs, dataTree = this.table.modules.dataTree;
			rows.forEach((row) => {
				data.push(row.getData());
				if (hasDataTreeColumnCalcs && row.modules.dataTree?.open) this.rowsToData(dataTree.getFilteredTreeChildren(row)).forEach((dataRow) => {
					data.push(row);
				});
			});
			return data;
		}
		generateRow(pos, data) {
			var rowData = this.generateRowData(pos, data), row;
			if (this.table.modExists("mutator")) this.table.modules.mutator.disable();
			row = new Row$1(rowData, this, "calc");
			if (this.table.modExists("mutator")) this.table.modules.mutator.enable();
			row.getElement().classList.add("tabulator-calcs", "tabulator-calcs-" + pos);
			row.component = false;
			row.getComponent = () => {
				if (!row.component) row.component = new CalcComponent(row);
				return row.component;
			};
			row.generateCells = () => {
				var cells = [];
				this.table.columnManager.columnsByIndex.forEach((column) => {
					this.genColumn.setField(column.getField());
					this.genColumn.hozAlign = column.hozAlign;
					if (column.definition[pos + "CalcFormatter"] && this.table.modExists("format")) this.genColumn.modules.format = {
						formatter: this.table.modules.format.lookupFormatter(column.definition[pos + "CalcFormatter"]),
						params: column.definition[pos + "CalcFormatterParams"] || {}
					};
					else this.genColumn.modules.format = {
						formatter: this.table.modules.format.lookupFormatter("plaintext"),
						params: {}
					};
					this.genColumn.definition.cssClass = column.definition.cssClass;
					var cell = new Cell(this.genColumn, row);
					cell.getElement();
					cell.column = column;
					cell.setWidth();
					column.cells.push(cell);
					cells.push(cell);
					if (!column.visible) cell.hide();
				});
				row.cells = cells;
			};
			return row;
		}
		generateRowData(pos, data) {
			var rowData = {}, calcs = pos == "top" ? this.topCalcs : this.botCalcs, type = pos == "top" ? "topCalc" : "botCalc", params, paramKey;
			calcs.forEach(function(column) {
				var values = [];
				if (column.modules.columnCalcs && column.modules.columnCalcs[type]) {
					data.forEach(function(item) {
						values.push(column.getFieldValue(item));
					});
					paramKey = type + "Params";
					params = typeof column.modules.columnCalcs[paramKey] === "function" ? column.modules.columnCalcs[paramKey](values, data) : column.modules.columnCalcs[paramKey];
					column.setFieldValue(rowData, column.modules.columnCalcs[type](values, data, params));
				}
			});
			return rowData;
		}
		hasTopCalcs() {
			return !!this.topCalcs.length;
		}
		hasBottomCalcs() {
			return !!this.botCalcs.length;
		}
		redraw() {
			if (this.topRow) this.topRow.normalizeHeight(true);
			if (this.botRow) this.botRow.normalizeHeight(true);
		}
		getResults() {
			var results = {}, groups;
			if (this.table.options.groupBy && this.table.modExists("groupRows")) {
				groups = this.table.modules.groupRows.getGroups(true);
				groups.forEach((group) => {
					results[group.getKey()] = this.getGroupResults(group);
				});
			} else results = {
				top: this.topRow ? this.topRow.getData() : {},
				bottom: this.botRow ? this.botRow.getData() : {}
			};
			return results;
		}
		getGroupResults(group) {
			var groupObj = group._getSelf(), subGroups = group.getSubGroups(), subGroupResults = {}, results = {};
			subGroups.forEach((subgroup) => {
				subGroupResults[subgroup.getKey()] = this.getGroupResults(subgroup);
			});
			results = {
				top: groupObj.calcs.top ? groupObj.calcs.top.getData() : {},
				bottom: groupObj.calcs.bottom ? groupObj.calcs.bottom.getData() : {},
				groups: subGroupResults
			};
			return results;
		}
		adjustForScrollbar(width) {
			if (this.botRow) if (this.table.rtl) this.botElement.style.paddingLeft = width + "px";
			else this.botElement.style.paddingRight = width + "px";
		}
	};
	var DataTree = class extends Module {
		static moduleName = "dataTree";
		constructor(table) {
			super(table);
			this.indent = 10;
			this.field = "";
			this.collapseEl = null;
			this.expandEl = null;
			this.branchEl = null;
			this.elementField = false;
			this.startOpen = function() {};
			this.registerTableOption("dataTree", false);
			this.registerTableOption("dataTreeFilter", true);
			this.registerTableOption("dataTreeSort", true);
			this.registerTableOption("dataTreeElementColumn", false);
			this.registerTableOption("dataTreeBranchElement", true);
			this.registerTableOption("dataTreeChildIndent", 9);
			this.registerTableOption("dataTreeChildField", "_children");
			this.registerTableOption("dataTreeCollapseElement", false);
			this.registerTableOption("dataTreeExpandElement", false);
			this.registerTableOption("dataTreeStartExpanded", false);
			this.registerTableOption("dataTreeChildColumnCalcs", false);
			this.registerTableOption("dataTreeSelectPropagate", false);
			this.registerComponentFunction("row", "treeCollapse", this.collapseRow.bind(this));
			this.registerComponentFunction("row", "treeExpand", this.expandRow.bind(this));
			this.registerComponentFunction("row", "treeToggle", this.toggleRow.bind(this));
			this.registerComponentFunction("row", "getTreeParent", this.getTreeParent.bind(this));
			this.registerComponentFunction("row", "getTreeChildren", this.getRowChildren.bind(this));
			this.registerComponentFunction("row", "addTreeChild", this.addTreeChildRow.bind(this));
			this.registerComponentFunction("row", "isTreeExpanded", this.isRowExpanded.bind(this));
		}
		initialize() {
			if (this.table.options.dataTree) {
				var dummyEl = null, options = this.table.options;
				this.field = options.dataTreeChildField;
				this.indent = options.dataTreeChildIndent;
				if (this.options("movableRows")) console.warn("The movableRows option is not available with dataTree enabled, moving of child rows could result in unpredictable behavior");
				if (options.dataTreeBranchElement) if (options.dataTreeBranchElement === true) {
					this.branchEl = document.createElement("div");
					this.branchEl.classList.add("tabulator-data-tree-branch");
				} else if (typeof options.dataTreeBranchElement === "string") {
					dummyEl = document.createElement("div");
					dummyEl.innerHTML = options.dataTreeBranchElement;
					this.branchEl = dummyEl.firstChild;
				} else this.branchEl = options.dataTreeBranchElement;
				else {
					this.branchEl = document.createElement("div");
					this.branchEl.classList.add("tabulator-data-tree-branch-empty");
				}
				if (options.dataTreeCollapseElement) if (typeof options.dataTreeCollapseElement === "string") {
					dummyEl = document.createElement("div");
					dummyEl.innerHTML = options.dataTreeCollapseElement;
					this.collapseEl = dummyEl.firstChild;
				} else this.collapseEl = options.dataTreeCollapseElement;
				else {
					this.collapseEl = document.createElement("div");
					this.collapseEl.classList.add("tabulator-data-tree-control");
					this.collapseEl.tabIndex = 0;
					this.collapseEl.innerHTML = "<div class='tabulator-data-tree-control-collapse'></div>";
				}
				if (options.dataTreeExpandElement) if (typeof options.dataTreeExpandElement === "string") {
					dummyEl = document.createElement("div");
					dummyEl.innerHTML = options.dataTreeExpandElement;
					this.expandEl = dummyEl.firstChild;
				} else this.expandEl = options.dataTreeExpandElement;
				else {
					this.expandEl = document.createElement("div");
					this.expandEl.classList.add("tabulator-data-tree-control");
					this.expandEl.tabIndex = 0;
					this.expandEl.innerHTML = "<div class='tabulator-data-tree-control-expand'></div>";
				}
				switch (typeof options.dataTreeStartExpanded) {
					case "boolean":
						this.startOpen = function(row, index) {
							return options.dataTreeStartExpanded;
						};
						break;
					case "function":
						this.startOpen = options.dataTreeStartExpanded;
						break;
					default:
						this.startOpen = function(row, index) {
							return options.dataTreeStartExpanded[index];
						};
						break;
				}
				this.subscribe("row-init", this.initializeRow.bind(this));
				this.subscribe("row-layout-after", this.layoutRow.bind(this));
				this.subscribe("row-deleting", this.rowDeleting.bind(this));
				this.subscribe("row-deleted", this.rowDelete.bind(this), 0);
				this.subscribe("row-data-changed", this.rowDataChanged.bind(this), 10);
				this.subscribe("cell-value-updated", this.cellValueChanged.bind(this));
				this.subscribe("edit-cancelled", this.cellValueChanged.bind(this));
				this.subscribe("column-moving-rows", this.columnMoving.bind(this));
				this.subscribe("table-built", this.initializeElementField.bind(this));
				this.subscribe("table-redrawing", this.tableRedrawing.bind(this));
				this.registerDisplayHandler(this.getRows.bind(this), 30);
			}
		}
		tableRedrawing(force) {
			var rows;
			if (force) {
				rows = this.table.rowManager.getRows();
				rows.forEach((row) => {
					this.reinitializeRowChildren(row);
				});
			}
		}
		initializeElementField() {
			var firstCol = this.table.columnManager.getFirstVisibleColumn();
			this.elementField = this.table.options.dataTreeElementColumn || (firstCol ? firstCol.field : false);
		}
		getRowChildren(row) {
			return this.getTreeChildren(row, true);
		}
		columnMoving() {
			var rows = [];
			this.table.rowManager.rows.forEach((row) => {
				rows = rows.concat(this.getTreeChildren(row, false, true));
			});
			return rows;
		}
		rowDataChanged(row, visible, updatedData) {
			if (this.redrawNeeded(updatedData)) {
				this.initializeRow(row);
				if (visible) {
					this.layoutRow(row);
					this.refreshData(true);
				}
			}
		}
		cellValueChanged(cell) {
			if (cell.column.getField() === this.elementField) this.layoutRow(cell.row);
		}
		initializeRow(row) {
			var childArray = row.getData()[this.field];
			var isArray = Array.isArray(childArray);
			var children = isArray || !isArray && typeof childArray === "object" && childArray !== null;
			if (!children && row.modules.dataTree && row.modules.dataTree.branchEl) row.modules.dataTree.branchEl.parentNode.removeChild(row.modules.dataTree.branchEl);
			if (!children && row.modules.dataTree && row.modules.dataTree.controlEl) row.modules.dataTree.controlEl.parentNode.removeChild(row.modules.dataTree.controlEl);
			row.modules.dataTree = {
				index: row.modules.dataTree ? row.modules.dataTree.index : 0,
				open: children ? row.modules.dataTree ? row.modules.dataTree.open : this.startOpen(row.getComponent(), 0) : false,
				controlEl: row.modules.dataTree && children ? row.modules.dataTree.controlEl : false,
				branchEl: row.modules.dataTree && children ? row.modules.dataTree.branchEl : false,
				parent: row.modules.dataTree ? row.modules.dataTree.parent : false,
				children
			};
		}
		reinitializeRowChildren(row) {
			this.getTreeChildren(row, false, true).forEach(function(child) {
				child.reinitialize(true);
			});
		}
		layoutRow(row) {
			var el = (this.elementField ? row.getCell(this.elementField) : row.getCells()[0]).getElement(), config = row.modules.dataTree;
			if (config.branchEl) {
				if (config.branchEl.parentNode) config.branchEl.parentNode.removeChild(config.branchEl);
				config.branchEl = false;
			}
			if (config.controlEl) {
				if (config.controlEl.parentNode) config.controlEl.parentNode.removeChild(config.controlEl);
				config.controlEl = false;
			}
			this.generateControlElement(row, el);
			row.getElement().classList.add("tabulator-tree-level-" + config.index);
			if (config.index) if (this.branchEl) {
				config.branchEl = this.branchEl.cloneNode(true);
				el.insertBefore(config.branchEl, el.firstChild);
				if (this.table.rtl) config.branchEl.style.marginRight = (config.branchEl.offsetWidth + config.branchEl.style.marginLeft) * (config.index - 1) + config.index * this.indent + "px";
				else config.branchEl.style.marginLeft = (config.branchEl.offsetWidth + config.branchEl.style.marginRight) * (config.index - 1) + config.index * this.indent + "px";
			} else if (this.table.rtl) el.style.paddingRight = parseInt(window.getComputedStyle(el, null).getPropertyValue("padding-right")) + config.index * this.indent + "px";
			else el.style.paddingLeft = parseInt(window.getComputedStyle(el, null).getPropertyValue("padding-left")) + config.index * this.indent + "px";
		}
		generateControlElement(row, el) {
			var config = row.modules.dataTree, oldControl = config.controlEl;
			el = el || row.getCells()[0].getElement();
			if (config.children !== false) {
				if (config.open) {
					config.controlEl = this.collapseEl.cloneNode(true);
					config.controlEl.addEventListener("click", (e) => {
						e.stopPropagation();
						this.collapseRow(row);
					});
				} else {
					config.controlEl = this.expandEl.cloneNode(true);
					config.controlEl.addEventListener("click", (e) => {
						e.stopPropagation();
						this.expandRow(row);
					});
				}
				config.controlEl.addEventListener("mousedown", (e) => {
					e.stopPropagation();
				});
				if (oldControl && oldControl.parentNode === el) oldControl.parentNode.replaceChild(config.controlEl, oldControl);
				else el.insertBefore(config.controlEl, el.firstChild);
			}
		}
		getRows(rows) {
			var output = [];
			rows.forEach((row, i) => {
				var config, children;
				output.push(row);
				if (row instanceof Row$1) {
					row.create();
					config = row.modules.dataTree;
					if (!config.index && config.children !== false) {
						children = this.getChildren(row, false, true);
						children.forEach((child) => {
							child.create();
							output.push(child);
						});
					}
				}
			});
			return output;
		}
		getChildren(row, allChildren, sortOnly) {
			var config = row.modules.dataTree, children = [], output = [];
			if (config.children !== false && (config.open || allChildren)) {
				if (!Array.isArray(config.children)) config.children = this.generateChildren(row);
				if (this.table.modExists("filter") && this.table.options.dataTreeFilter) children = this.table.modules.filter.filter(config.children);
				else children = config.children;
				if (this.table.modExists("sort") && this.table.options.dataTreeSort) this.table.modules.sort.sort(children, sortOnly);
				children.forEach((child) => {
					output.push(child);
					this.getChildren(child, false, true).forEach((sub) => {
						output.push(sub);
					});
				});
			}
			return output;
		}
		generateChildren(row) {
			var children = [];
			var childArray = row.getData()[this.field];
			if (!Array.isArray(childArray)) childArray = [childArray];
			childArray.forEach((childData) => {
				var childRow = new Row$1(childData || {}, this.table.rowManager);
				childRow.create();
				childRow.modules.dataTree.index = row.modules.dataTree.index + 1;
				childRow.modules.dataTree.parent = row;
				if (childRow.modules.dataTree.children) childRow.modules.dataTree.open = this.startOpen(childRow.getComponent(), childRow.modules.dataTree.index);
				children.push(childRow);
			});
			return children;
		}
		expandRow(row, silent) {
			var config = row.modules.dataTree;
			if (config.children !== false) {
				config.open = true;
				row.reinitialize();
				this.refreshData(true);
				this.dispatchExternal("dataTreeRowExpanded", row.getComponent(), row.modules.dataTree.index);
			}
		}
		collapseRow(row) {
			var config = row.modules.dataTree;
			if (config.children !== false) {
				config.open = false;
				row.reinitialize();
				this.refreshData(true);
				this.dispatchExternal("dataTreeRowCollapsed", row.getComponent(), row.modules.dataTree.index);
			}
		}
		toggleRow(row) {
			var config = row.modules.dataTree;
			if (config.children !== false) if (config.open) this.collapseRow(row);
			else this.expandRow(row);
		}
		isRowExpanded(row) {
			return row.modules.dataTree.open;
		}
		getTreeParent(row) {
			return row.modules.dataTree.parent ? row.modules.dataTree.parent.getComponent() : false;
		}
		getTreeParentRoot(row) {
			return row.modules.dataTree && row.modules.dataTree.parent ? this.getTreeParentRoot(row.modules.dataTree.parent) : row;
		}
		getFilteredTreeChildren(row) {
			var config = row.modules.dataTree, output = [], children;
			if (config.children) {
				if (!Array.isArray(config.children)) config.children = this.generateChildren(row);
				if (this.table.modExists("filter") && this.table.options.dataTreeFilter) children = this.table.modules.filter.filter(config.children);
				else children = config.children;
				children.forEach((childRow) => {
					if (childRow instanceof Row$1) output.push(childRow);
				});
			}
			return output;
		}
		rowDeleting(row) {
			var config = row.modules.dataTree;
			if (config && config.children && Array.isArray(config.children)) config.children.forEach((childRow) => {
				if (childRow instanceof Row$1) childRow.wipe();
			});
		}
		rowDelete(row) {
			var parent = row.modules.dataTree.parent, childIndex;
			if (parent) {
				childIndex = this.findChildIndex(row, parent);
				if (childIndex !== false) parent.data[this.field].splice(childIndex, 1);
				if (!parent.data[this.field].length) delete parent.data[this.field];
				this.initializeRow(parent);
				this.layoutRow(parent);
			}
			this.refreshData(true);
		}
		addTreeChildRow(row, data, top, index) {
			var childIndex = false;
			if (typeof data === "string") data = JSON.parse(data);
			if (!Array.isArray(row.data[this.field])) {
				row.data[this.field] = [];
				row.modules.dataTree.open = this.startOpen(row.getComponent(), row.modules.dataTree.index);
			}
			if (typeof index !== "undefined") {
				childIndex = this.findChildIndex(index, row);
				if (childIndex !== false) row.data[this.field].splice(top ? childIndex : childIndex + 1, 0, data);
			}
			if (childIndex === false) if (top) row.data[this.field].unshift(data);
			else row.data[this.field].push(data);
			this.initializeRow(row);
			this.layoutRow(row);
			this.refreshData(true);
		}
		findChildIndex(subject, parent) {
			var match = false;
			if (typeof subject == "object") {
				if (subject instanceof Row$1) match = subject.data;
				else if (subject instanceof RowComponent) match = subject._getSelf().data;
				else if (typeof HTMLElement !== "undefined" && subject instanceof HTMLElement) {
					if (parent.modules.dataTree) {
						match = parent.modules.dataTree.children.find((childRow) => {
							return childRow instanceof Row$1 ? childRow.element === subject : false;
						});
						if (match) match = match.data;
					}
				} else if (subject === null) match = false;
			} else if (typeof subject == "undefined") match = false;
			else match = parent.data[this.field].find((row) => {
				return row.data[this.table.options.index] == subject;
			});
			if (match) {
				if (Array.isArray(parent.data[this.field])) match = parent.data[this.field].indexOf(match);
				if (match == -1) match = false;
			}
			return match;
		}
		getTreeChildren(row, component, recurse) {
			var config = row.modules.dataTree, output = [];
			if (config && config.children) {
				if (!Array.isArray(config.children)) config.children = this.generateChildren(row);
				config.children.forEach((childRow) => {
					if (childRow instanceof Row$1) {
						output.push(component ? childRow.getComponent() : childRow);
						if (recurse) this.getTreeChildren(childRow, component, recurse).forEach((child) => {
							output.push(child);
						});
					}
				});
			}
			return output;
		}
		getChildField() {
			return this.field;
		}
		redrawNeeded(data) {
			return (this.field ? typeof data[this.field] !== "undefined" : false) || (this.elementField ? typeof data[this.elementField] !== "undefined" : false);
		}
	};
	function csv$1(list, options = {}, setFileContents) {
		var delimiter = options.delimiter ? options.delimiter : ",", fileContents = [], headers = [];
		list.forEach((row) => {
			var item = [];
			switch (row.type) {
				case "group":
					console.warn("Download Warning - CSV downloader cannot process row groups");
					break;
				case "calc":
					console.warn("Download Warning - CSV downloader cannot process column calculations");
					break;
				case "header":
					row.columns.forEach((col, i) => {
						if (col && col.depth === 1) headers[i] = typeof col.value == "undefined" || col.value === null ? "" : "\"" + String(col.value).split("\"").join("\"\"") + "\"";
					});
					break;
				case "row":
					row.columns.forEach((col) => {
						if (col) {
							switch (typeof col.value) {
								case "object":
									col.value = col.value !== null ? JSON.stringify(col.value) : "";
									break;
								case "undefined":
									col.value = "";
									break;
							}
							item.push("\"" + String(col.value).split("\"").join("\"\"") + "\"");
						}
					});
					fileContents.push(item.join(delimiter));
					break;
			}
		});
		if (headers.length) fileContents.unshift(headers.join(delimiter));
		fileContents = fileContents.join("\n");
		if (options.bom) fileContents = "" + fileContents;
		setFileContents(fileContents, "text/csv");
	}
	function json$2(list, options, setFileContents) {
		var fileContents = [];
		list.forEach((row) => {
			var item = {};
			switch (row.type) {
				case "header": break;
				case "group":
					console.warn("Download Warning - JSON downloader cannot process row groups");
					break;
				case "calc":
					console.warn("Download Warning - JSON downloader cannot process column calculations");
					break;
				case "row":
					row.columns.forEach((col) => {
						if (col) item[col.component.getTitleDownload() || col.component.getField()] = col.value;
					});
					fileContents.push(item);
					break;
			}
		});
		fileContents = JSON.stringify(fileContents, null, "	");
		setFileContents(fileContents, "application/json");
	}
	function pdf(list, options = {}, setFileContents) {
		var header = [], body = [], autoTableParams = {}, rowGroupStyles = options.rowGroupStyles || {
			fontStyle: "bold",
			fontSize: 12,
			cellPadding: 6,
			fillColor: 220
		}, rowCalcStyles = options.rowCalcStyles || {
			fontStyle: "bold",
			fontSize: 10,
			cellPadding: 4,
			fillColor: 232
		}, jsPDFParams = options.jsPDF || {}, title = options.title ? options.title : "", jspdfLib, doc;
		if (!jsPDFParams.orientation) jsPDFParams.orientation = options.orientation || "landscape";
		if (!jsPDFParams.unit) jsPDFParams.unit = "pt";
		list.forEach((row) => {
			switch (row.type) {
				case "header":
					header.push(parseRow(row));
					break;
				case "group":
					body.push(parseRow(row, rowGroupStyles));
					break;
				case "calc":
					body.push(parseRow(row, rowCalcStyles));
					break;
				case "row":
					body.push(parseRow(row));
					break;
			}
		});
		function parseRow(row, styles) {
			var rowData = [];
			row.columns.forEach((col) => {
				var cell;
				if (col) {
					switch (typeof col.value) {
						case "object":
							col.value = col.value !== null ? JSON.stringify(col.value) : "";
							break;
						case "undefined":
							col.value = "";
							break;
					}
					cell = {
						content: col.value,
						colSpan: col.width,
						rowSpan: col.height
					};
					if (styles) cell.styles = styles;
					rowData.push(cell);
				}
			});
			return rowData;
		}
		jspdfLib = this.dependencyRegistry.lookup("jspdf", "jsPDF");
		doc = new jspdfLib(jsPDFParams);
		if (options.autoTable) if (typeof options.autoTable === "function") autoTableParams = options.autoTable(doc) || {};
		else autoTableParams = options.autoTable;
		if (title) autoTableParams.didDrawPage = function(data) {
			doc.text(title, 40, 30);
		};
		autoTableParams.head = header;
		autoTableParams.body = body;
		doc.autoTable(autoTableParams);
		if (options.documentProcessing) options.documentProcessing(doc);
		setFileContents(doc.output("arraybuffer"), "application/pdf");
	}
	function xlsx$1(list, options, setFileContents) {
		var self = this, sheetName = options.sheetName || "Sheet1", XLSXLib = this.dependencyRegistry.lookup("XLSX"), workbook = XLSXLib.utils.book_new(), tableFeatures = new CoreFeature(this), compression = "compress" in options ? options.compress : true, writeOptions = options.writeOptions || {
			bookType: "xlsx",
			bookSST: true,
			compression
		}, output;
		writeOptions.type = "binary";
		workbook.SheetNames = [];
		workbook.Sheets = {};
		function generateSheet() {
			var rows = [], merges = [], worksheet = {}, range = {
				s: {
					c: 0,
					r: 0
				},
				e: {
					c: list[0] ? list[0].columns.reduce((a, b) => a + (b && b.width ? b.width : 1), 0) : 0,
					r: list.length
				}
			};
			list.forEach((row, i) => {
				var rowData = [];
				row.columns.forEach(function(col, j) {
					if (col) {
						rowData.push(!(col.value instanceof Date) && typeof col.value === "object" ? JSON.stringify(col.value) : col.value);
						if (col.width > 1 || col.height > -1) {
							if (col.height > 1 || col.width > 1) merges.push({
								s: {
									r: i,
									c: j
								},
								e: {
									r: i + col.height - 1,
									c: j + col.width - 1
								}
							});
						}
					} else rowData.push("");
				});
				rows.push(rowData);
			});
			XLSXLib.utils.sheet_add_aoa(worksheet, rows);
			worksheet["!ref"] = XLSXLib.utils.encode_range(range);
			if (merges.length) worksheet["!merges"] = merges;
			return worksheet;
		}
		if (options.sheetOnly) {
			setFileContents(generateSheet());
			return;
		}
		if (options.sheets) for (var sheet in options.sheets) if (options.sheets[sheet] === true) {
			workbook.SheetNames.push(sheet);
			workbook.Sheets[sheet] = generateSheet();
		} else {
			workbook.SheetNames.push(sheet);
			tableFeatures.commsSend(options.sheets[sheet], "download", "intercept", {
				type: "xlsx",
				options: { sheetOnly: true },
				active: self.active,
				intercept: function(data) {
					workbook.Sheets[sheet] = data;
				}
			});
		}
		else {
			workbook.SheetNames.push(sheetName);
			workbook.Sheets[sheetName] = generateSheet();
		}
		if (options.documentProcessing) workbook = options.documentProcessing(workbook);
		function s2ab(s) {
			var buf = new ArrayBuffer(s.length);
			var view = new Uint8Array(buf);
			for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 255;
			return buf;
		}
		output = XLSXLib.write(workbook, writeOptions);
		setFileContents(s2ab(output), "application/octet-stream");
	}
	function html$1(list, options, setFileContents) {
		if (this.modExists("export", true)) setFileContents(this.modules.export.generateHTMLTable(list), "text/html");
	}
	function jsonLines(list, options, setFileContents) {
		const fileContents = [];
		list.forEach((row) => {
			const item = {};
			switch (row.type) {
				case "header": break;
				case "group":
					console.warn("Download Warning - JSON downloader cannot process row groups");
					break;
				case "calc":
					console.warn("Download Warning - JSON downloader cannot process column calculations");
					break;
				case "row":
					row.columns.forEach((col) => {
						if (col) item[col.component.getTitleDownload() || col.component.getField()] = col.value;
					});
					fileContents.push(JSON.stringify(item));
					break;
			}
		});
		setFileContents(fileContents.join("\n"), "application/x-ndjson");
	}
	var defaultDownloaders = {
		csv: csv$1,
		json: json$2,
		jsonLines,
		pdf,
		xlsx: xlsx$1,
		html: html$1
	};
	var Download = class Download extends Module {
		static moduleName = "download";
		static downloaders = defaultDownloaders;
		constructor(table) {
			super(table);
			this.registerTableOption("downloadEncoder", function(data, mimeType) {
				return new Blob([data], { type: mimeType });
			});
			this.registerTableOption("downloadConfig", {});
			this.registerTableOption("downloadRowRange", "active");
			this.registerColumnOption("download");
			this.registerColumnOption("titleDownload");
		}
		initialize() {
			this.deprecatedOptionsCheck();
			this.registerTableFunction("download", this.download.bind(this));
			this.registerTableFunction("downloadToTab", this.downloadToTab.bind(this));
		}
		deprecatedOptionsCheck() {}
		downloadToTab(type, filename, options, active) {
			this.download(type, filename, options, active, true);
		}
		download(type, filename, options, range, interceptCallback) {
			var downloadFunc = false;
			function buildLink(data, mime) {
				if (interceptCallback) if (interceptCallback === true) this.triggerDownload(data, mime, type, filename, true);
				else interceptCallback(data);
				else this.triggerDownload(data, mime, type, filename);
			}
			if (typeof type == "function") downloadFunc = type;
			else if (Download.downloaders[type]) downloadFunc = Download.downloaders[type];
			else console.warn("Download Error - No such download type found: ", type);
			if (downloadFunc) {
				var list = this.generateExportList(range);
				downloadFunc.call(this.table, list, options || {}, buildLink.bind(this));
			}
		}
		generateExportList(range) {
			var list = this.table.modules.export.generateExportList(this.table.options.downloadConfig, false, range || this.table.options.downloadRowRange, "download");
			var groupHeader = this.table.options.groupHeaderDownload;
			if (groupHeader && !Array.isArray(groupHeader)) groupHeader = [groupHeader];
			list.forEach((row) => {
				var group;
				if (row.type === "group") {
					group = row.columns[0];
					if (groupHeader && groupHeader[row.indent]) group.value = groupHeader[row.indent](group.value, row.component._group.getRowCount(), row.component._group.getData(), row.component);
				}
			});
			return list;
		}
		triggerDownload(data, mime, type, filename, newTab) {
			var element = document.createElement("a"), blob = this.table.options.downloadEncoder(data, mime);
			if (blob) {
				if (newTab) window.open(window.URL.createObjectURL(blob));
				else {
					filename = filename || "Tabulator." + (typeof type === "function" ? "txt" : type);
					if (navigator.msSaveOrOpenBlob) navigator.msSaveOrOpenBlob(blob, filename);
					else {
						element.setAttribute("href", window.URL.createObjectURL(blob));
						element.setAttribute("download", filename);
						element.style.display = "none";
						document.body.appendChild(element);
						element.click();
						document.body.removeChild(element);
					}
				}
				this.dispatchExternal("downloadComplete");
			}
		}
		commsReceived(table, action, data) {
			switch (action) {
				case "intercept":
					this.download(data.type, "", data.options, data.active, data.intercept);
					break;
			}
		}
	};
	function maskInput(el, options) {
		var mask = options.mask, maskLetter = typeof options.maskLetterChar !== "undefined" ? options.maskLetterChar : "A", maskNumber = typeof options.maskNumberChar !== "undefined" ? options.maskNumberChar : "9", maskWildcard = typeof options.maskWildcardChar !== "undefined" ? options.maskWildcardChar : "*";
		function fillSymbols(index) {
			var symbol = mask[index];
			if (typeof symbol !== "undefined" && symbol !== maskWildcard && symbol !== maskLetter && symbol !== maskNumber) {
				el.value = el.value + "" + symbol;
				fillSymbols(index + 1);
			}
		}
		el.addEventListener("keydown", (e) => {
			var index = el.value.length, char = e.key;
			if (e.keyCode > 46 && !e.ctrlKey && !e.metaKey) if (index >= mask.length) {
				e.preventDefault();
				e.stopPropagation();
				return false;
			} else switch (mask[index]) {
				case maskLetter:
					if (char.toUpperCase() == char.toLowerCase()) {
						e.preventDefault();
						e.stopPropagation();
						return false;
					}
					break;
				case maskNumber:
					if (isNaN(char)) {
						e.preventDefault();
						e.stopPropagation();
						return false;
					}
					break;
				case maskWildcard: break;
				default: if (char !== mask[index]) {
					e.preventDefault();
					e.stopPropagation();
					return false;
				}
			}
		});
		el.addEventListener("keyup", (e) => {
			if (e.keyCode > 46) {
				if (options.maskAutoFill) fillSymbols(el.value.length);
			}
		});
		if (!el.placeholder) el.placeholder = mask;
		if (options.maskAutoFill) fillSymbols(el.value.length);
	}
	function input(cell, onRendered, success, cancel, editorParams) {
		var cellValue = cell.getValue(), input = document.createElement("input");
		input.setAttribute("type", editorParams.search ? "search" : "text");
		input.style.padding = "4px";
		input.style.width = "100%";
		input.style.boxSizing = "border-box";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		input.value = typeof cellValue !== "undefined" ? cellValue : "";
		onRendered(function() {
			if (cell.getType() === "cell") {
				input.focus({ preventScroll: true });
				input.style.height = "100%";
				if (editorParams.selectContents) input.select();
			}
		});
		function onChange(e) {
			if ((cellValue === null || typeof cellValue === "undefined") && input.value !== "" || input.value !== cellValue) {
				if (success(input.value)) cellValue = input.value;
			} else cancel();
		}
		input.addEventListener("change", onChange);
		input.addEventListener("blur", onChange);
		input.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 13:
					onChange();
					break;
				case 27:
					cancel();
					break;
				case 35:
				case 36:
					e.stopPropagation();
					break;
			}
		});
		if (editorParams.mask) maskInput(input, editorParams);
		return input;
	}
	function textarea$1(cell, onRendered, success, cancel, editorParams) {
		var cellValue = cell.getValue(), vertNav = editorParams.verticalNavigation || "hybrid", value = String(cellValue !== null && typeof cellValue !== "undefined" ? cellValue : ""), input = document.createElement("textarea"), scrollHeight = 0;
		input.style.display = "block";
		input.style.padding = "2px";
		input.style.height = "100%";
		input.style.width = "100%";
		input.style.boxSizing = "border-box";
		input.style.whiteSpace = "pre-wrap";
		input.style.resize = "none";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		input.value = value;
		onRendered(function() {
			if (cell.getType() === "cell") {
				input.focus({ preventScroll: true });
				input.style.height = "100%";
				input.scrollHeight;
				input.style.height = input.scrollHeight + "px";
				cell.getRow().normalizeHeight();
				if (editorParams.selectContents) input.select();
			}
		});
		function onChange(e) {
			if ((cellValue === null || typeof cellValue === "undefined") && input.value !== "" || input.value !== cellValue) {
				if (success(input.value)) cellValue = input.value;
				setTimeout(function() {
					cell.getRow().normalizeHeight();
				}, 300);
			} else cancel();
		}
		input.addEventListener("change", onChange);
		input.addEventListener("blur", onChange);
		input.addEventListener("keyup", function() {
			input.style.height = "";
			var heightNow = input.scrollHeight;
			input.style.height = heightNow + "px";
			if (heightNow != scrollHeight) {
				scrollHeight = heightNow;
				cell.getRow().normalizeHeight();
			}
		});
		input.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 13:
					if (e.shiftKey && editorParams.shiftEnterSubmit) onChange();
					break;
				case 27:
					cancel();
					break;
				case 38:
					if (vertNav == "editor" || vertNav == "hybrid" && input.selectionStart) {
						e.stopImmediatePropagation();
						e.stopPropagation();
					}
					break;
				case 40:
					if (vertNav == "editor" || vertNav == "hybrid" && input.selectionStart !== input.value.length) {
						e.stopImmediatePropagation();
						e.stopPropagation();
					}
					break;
				case 35:
				case 36:
					e.stopPropagation();
					break;
			}
		});
		if (editorParams.mask) maskInput(input, editorParams);
		return input;
	}
	function number$1(cell, onRendered, success, cancel, editorParams) {
		var cellValue = cell.getValue(), vertNav = editorParams.verticalNavigation || "editor", input = document.createElement("input");
		input.setAttribute("type", "number");
		if (typeof editorParams.max != "undefined") input.setAttribute("max", editorParams.max);
		if (typeof editorParams.min != "undefined") input.setAttribute("min", editorParams.min);
		if (typeof editorParams.step != "undefined") input.setAttribute("step", editorParams.step);
		input.style.padding = "4px";
		input.style.width = "100%";
		input.style.boxSizing = "border-box";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		input.value = cellValue;
		var blurFunc = function(e) {
			onChange();
		};
		onRendered(function() {
			if (cell.getType() === "cell") {
				input.removeEventListener("blur", blurFunc);
				input.focus({ preventScroll: true });
				input.style.height = "100%";
				input.addEventListener("blur", blurFunc);
				if (editorParams.selectContents) input.select();
			}
		});
		function onChange() {
			var value = input.value;
			if (!isNaN(value) && value !== "") value = Number(value);
			if (value !== cellValue) {
				if (success(value)) cellValue = value;
			} else cancel();
		}
		input.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 13:
					onChange();
					break;
				case 27:
					cancel();
					break;
				case 38:
				case 40:
					if (vertNav == "editor") {
						e.stopImmediatePropagation();
						e.stopPropagation();
					}
					break;
				case 35:
				case 36:
					e.stopPropagation();
					break;
			}
		});
		if (editorParams.mask) maskInput(input, editorParams);
		return input;
	}
	function range(cell, onRendered, success, cancel, editorParams) {
		var cellValue = cell.getValue(), input = document.createElement("input");
		input.setAttribute("type", "range");
		if (typeof editorParams.max != "undefined") input.setAttribute("max", editorParams.max);
		if (typeof editorParams.min != "undefined") input.setAttribute("min", editorParams.min);
		if (typeof editorParams.step != "undefined") input.setAttribute("step", editorParams.step);
		input.style.padding = "4px";
		input.style.width = "100%";
		input.style.boxSizing = "border-box";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		input.value = cellValue;
		onRendered(function() {
			if (cell.getType() === "cell") {
				input.focus({ preventScroll: true });
				input.style.height = "100%";
			}
		});
		function onChange() {
			var value = input.value;
			if (!isNaN(value) && value !== "") value = Number(value);
			if (value != cellValue) {
				if (success(value)) cellValue = value;
			} else cancel();
		}
		input.addEventListener("blur", function(e) {
			onChange();
		});
		input.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 13:
					onChange();
					break;
				case 27:
					cancel();
					break;
			}
		});
		return input;
	}
	function date$1(cell, onRendered, success, cancel, editorParams) {
		var inputFormat = editorParams.format, vertNav = editorParams.verticalNavigation || "editor", DT = inputFormat ? window.DateTime || luxon.DateTime : null;
		var cellValue = cell.getValue(), input = document.createElement("input");
		function convertDate(value) {
			var newDatetime;
			if (DT.isDateTime(value)) newDatetime = value;
			else if (inputFormat === "iso") newDatetime = DT.fromISO(String(value));
			else newDatetime = DT.fromFormat(String(value), inputFormat);
			return newDatetime.toFormat("yyyy-MM-dd");
		}
		input.type = "date";
		input.style.padding = "4px";
		input.style.width = "100%";
		input.style.boxSizing = "border-box";
		if (editorParams.max) input.setAttribute("max", inputFormat ? convertDate(editorParams.max) : editorParams.max);
		if (editorParams.min) input.setAttribute("min", inputFormat ? convertDate(editorParams.min) : editorParams.min);
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		cellValue = typeof cellValue !== "undefined" ? cellValue : "";
		if (inputFormat) if (DT) cellValue = convertDate(cellValue);
		else console.error("Editor Error - 'date' editor 'format' param is dependant on luxon.js");
		input.value = cellValue;
		onRendered(function() {
			if (cell.getType() === "cell") {
				input.focus({ preventScroll: true });
				input.style.height = "100%";
				if (editorParams.selectContents) input.select();
			}
		});
		function onChange() {
			var value = input.value, luxDate;
			if ((cellValue === null || typeof cellValue === "undefined") && value !== "" || value !== cellValue) {
				if (value && inputFormat) {
					luxDate = DT.fromFormat(String(value), "yyyy-MM-dd");
					switch (inputFormat) {
						case true:
							value = luxDate;
							break;
						case "iso":
							value = luxDate.toISO();
							break;
						default: value = luxDate.toFormat(inputFormat);
					}
				}
				if (success(value)) cellValue = input.value;
			} else cancel();
		}
		input.addEventListener("blur", function(e) {
			if (e.relatedTarget || e.rangeParent || e.explicitOriginalTarget !== input) onChange();
		});
		input.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 13:
					onChange();
					break;
				case 27:
					cancel();
					break;
				case 35:
				case 36:
					e.stopPropagation();
					break;
				case 38:
				case 40:
					if (vertNav == "editor") {
						e.stopImmediatePropagation();
						e.stopPropagation();
					}
					break;
			}
		});
		return input;
	}
	function time$1(cell, onRendered, success, cancel, editorParams) {
		var inputFormat = editorParams.format, vertNav = editorParams.verticalNavigation || "editor", DT = inputFormat ? window.DateTime || luxon.DateTime : null, newDatetime;
		var cellValue = cell.getValue(), input = document.createElement("input");
		input.type = "time";
		input.style.padding = "4px";
		input.style.width = "100%";
		input.style.boxSizing = "border-box";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		cellValue = typeof cellValue !== "undefined" ? cellValue : "";
		if (inputFormat) if (DT) {
			if (DT.isDateTime(cellValue)) newDatetime = cellValue;
			else if (inputFormat === "iso") newDatetime = DT.fromISO(String(cellValue));
			else newDatetime = DT.fromFormat(String(cellValue), inputFormat);
			cellValue = newDatetime.toFormat("HH:mm");
		} else console.error("Editor Error - 'date' editor 'format' param is dependant on luxon.js");
		input.value = cellValue;
		onRendered(function() {
			if (cell.getType() == "cell") {
				input.focus({ preventScroll: true });
				input.style.height = "100%";
				if (editorParams.selectContents) input.select();
			}
		});
		function onChange() {
			var value = input.value, luxTime;
			if ((cellValue === null || typeof cellValue === "undefined") && value !== "" || value !== cellValue) {
				if (value && inputFormat) {
					luxTime = DT.fromFormat(String(value), "hh:mm");
					switch (inputFormat) {
						case true:
							value = luxTime;
							break;
						case "iso":
							value = luxTime.toISO();
							break;
						default: value = luxTime.toFormat(inputFormat);
					}
				}
				if (success(value)) cellValue = input.value;
			} else cancel();
		}
		input.addEventListener("blur", function(e) {
			if (e.relatedTarget || e.rangeParent || e.explicitOriginalTarget !== input) onChange();
		});
		input.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 13:
					onChange();
					break;
				case 27:
					cancel();
					break;
				case 35:
				case 36:
					e.stopPropagation();
					break;
				case 38:
				case 40:
					if (vertNav == "editor") {
						e.stopImmediatePropagation();
						e.stopPropagation();
					}
					break;
			}
		});
		return input;
	}
	function datetime$2(cell, onRendered, success, cancel, editorParams) {
		var inputFormat = editorParams.format, vertNav = editorParams.verticalNavigation || "editor", DT = inputFormat ? this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime") : null, newDatetime;
		var cellValue = cell.getValue(), input = document.createElement("input");
		input.type = "datetime-local";
		input.style.padding = "4px";
		input.style.width = "100%";
		input.style.boxSizing = "border-box";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		cellValue = typeof cellValue !== "undefined" ? cellValue : "";
		if (inputFormat) if (DT) {
			if (DT.isDateTime(cellValue)) newDatetime = cellValue;
			else if (inputFormat === "iso") newDatetime = DT.fromISO(String(cellValue));
			else newDatetime = DT.fromFormat(String(cellValue), inputFormat);
			cellValue = newDatetime.toFormat("yyyy-MM-dd") + "T" + newDatetime.toFormat("HH:mm");
		} else console.error("Editor Error - 'date' editor 'format' param is dependant on luxon.js");
		input.value = cellValue;
		onRendered(function() {
			if (cell.getType() === "cell") {
				input.focus({ preventScroll: true });
				input.style.height = "100%";
				if (editorParams.selectContents) input.select();
			}
		});
		function onChange() {
			var value = input.value, luxDateTime;
			if ((cellValue === null || typeof cellValue === "undefined") && value !== "" || value !== cellValue) {
				if (value && inputFormat) {
					luxDateTime = DT.fromISO(String(value));
					switch (inputFormat) {
						case true:
							value = luxDateTime;
							break;
						case "iso":
							value = luxDateTime.toISO();
							break;
						default: value = luxDateTime.toFormat(inputFormat);
					}
				}
				if (success(value)) cellValue = input.value;
			} else cancel();
		}
		input.addEventListener("blur", function(e) {
			if (e.relatedTarget || e.rangeParent || e.explicitOriginalTarget !== input) onChange();
		});
		input.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 13:
					onChange();
					break;
				case 27:
					cancel();
					break;
				case 35:
				case 36:
					e.stopPropagation();
					break;
				case 38:
				case 40:
					if (vertNav == "editor") {
						e.stopImmediatePropagation();
						e.stopPropagation();
					}
					break;
			}
		});
		return input;
	}
	var Edit$1 = class Edit {
		constructor(editor, cell, onRendered, success, cancel, editorParams) {
			this.edit = editor;
			this.table = editor.table;
			this.cell = cell;
			this.params = this._initializeParams(editorParams);
			this.data = [];
			this.displayItems = [];
			this.currentItems = [];
			this.focusedItem = null;
			this.input = this._createInputElement();
			this.listEl = this._createListElement();
			this.initialValues = null;
			this.isFilter = cell.getType() === "header";
			this.filterTimeout = null;
			this.filtered = false;
			this.typing = false;
			this.values = [];
			this.popup = null;
			this.listIteration = 0;
			this.lastAction = "";
			this.filterTerm = "";
			this.blurable = true;
			this.actions = {
				success,
				cancel
			};
			this._deprecatedOptionsCheck();
			this._initializeValue();
			onRendered(this._onRendered.bind(this));
		}
		_deprecatedOptionsCheck() {}
		_initializeValue() {
			var initialValue = this.cell.getValue();
			if (typeof initialValue === "undefined" && typeof this.params.defaultValue !== "undefined") initialValue = this.params.defaultValue;
			this.initialValues = this.params.multiselect ? initialValue : [initialValue];
			if (this.isFilter) {
				this.input.value = this.initialValues ? this.initialValues.join(",") : "";
				this.headerFilterInitialListGen();
			}
		}
		_onRendered() {
			var cellEl = this.cell.getElement();
			function clickStop(e) {
				e.stopPropagation();
			}
			if (!this.isFilter) {
				this.input.style.height = "100%";
				this.input.focus({ preventScroll: true });
			}
			cellEl.addEventListener("click", clickStop);
			setTimeout(() => {
				cellEl.removeEventListener("click", clickStop);
			}, 1e3);
			this.input.addEventListener("mousedown", this._preventPopupBlur.bind(this));
		}
		_createListElement() {
			var listEl = document.createElement("div");
			listEl.classList.add("tabulator-edit-list");
			listEl.addEventListener("mousedown", this._preventBlur.bind(this));
			listEl.addEventListener("keydown", this._inputKeyDown.bind(this));
			return listEl;
		}
		_setListWidth() {
			var element = this.isFilter ? this.input : this.cell.getElement();
			this.listEl.style.minWidth = element.offsetWidth + "px";
			if (this.params.maxWidth) if (this.params.maxWidth === true) this.listEl.style.maxWidth = element.offsetWidth + "px";
			else if (typeof this.params.maxWidth === "number") this.listEl.style.maxWidth = this.params.maxWidth + "px";
			else this.listEl.style.maxWidth = this.params.maxWidth;
		}
		_createInputElement() {
			var attribs = this.params.elementAttributes;
			var input = document.createElement("input");
			input.setAttribute("type", this.params.clearable ? "search" : "text");
			input.style.padding = "4px";
			input.style.width = "100%";
			input.style.boxSizing = "border-box";
			if (!this.params.autocomplete) {
				input.style.cursor = "default";
				input.style.caretColor = "transparent";
			}
			if (attribs && typeof attribs == "object") for (let key in attribs) if (key.charAt(0) == "+") {
				key = key.slice(1);
				input.setAttribute(key, input.getAttribute(key) + attribs["+" + key]);
			} else input.setAttribute(key, attribs[key]);
			if (this.params.mask) maskInput(input, this.params);
			this._bindInputEvents(input);
			return input;
		}
		_initializeParams(params) {
			var valueKeys = [
				"values",
				"valuesURL",
				"valuesLookup"
			], valueCheck;
			params = Object.assign({}, params);
			params.verticalNavigation = params.verticalNavigation || "editor";
			params.placeholderLoading = typeof params.placeholderLoading === "undefined" ? "Searching ..." : params.placeholderLoading;
			params.placeholderEmpty = typeof params.placeholderEmpty === "undefined" ? "No Results Found" : params.placeholderEmpty;
			params.filterDelay = typeof params.filterDelay === "undefined" ? 300 : params.filterDelay;
			params.emptyValue = Object.keys(params).includes("emptyValue") ? params.emptyValue : "";
			valueCheck = Object.keys(params).filter((key) => valueKeys.includes(key)).length;
			if (!valueCheck) console.warn("list editor config error - either the values, valuesURL, or valuesLookup option must be set");
			else if (valueCheck > 1) console.warn("list editor config error - only one of the values, valuesURL, or valuesLookup options can be set on the same editor");
			if (params.autocomplete) {
				if (params.multiselect) {
					params.multiselect = false;
					console.warn("list editor config error - multiselect option is not available when autocomplete is enabled");
				}
			} else {
				if (params.freetext) {
					params.freetext = false;
					console.warn("list editor config error - freetext option is only available when autocomplete is enabled");
				}
				if (params.filterFunc) {
					params.filterFunc = false;
					console.warn("list editor config error - filterFunc option is only available when autocomplete is enabled");
				}
				if (params.filterRemote) {
					params.filterRemote = false;
					console.warn("list editor config error - filterRemote option is only available when autocomplete is enabled");
				}
				if (params.mask) {
					params.mask = false;
					console.warn("list editor config error - mask option is only available when autocomplete is enabled");
				}
				if (params.allowEmpty) {
					params.allowEmpty = false;
					console.warn("list editor config error - allowEmpty option is only available when autocomplete is enabled");
				}
				if (params.listOnEmpty) {
					params.listOnEmpty = false;
					console.warn("list editor config error - listOnEmpty option is only available when autocomplete is enabled");
				}
			}
			if (params.filterRemote && !(typeof params.valuesLookup === "function" || params.valuesURL)) {
				params.filterRemote = false;
				console.warn("list editor config error - filterRemote option should only be used when values list is populated from a remote source");
			}
			return params;
		}
		_bindInputEvents(input) {
			input.addEventListener("focus", this._inputFocus.bind(this));
			input.addEventListener("click", this._inputClick.bind(this));
			input.addEventListener("blur", this._inputBlur.bind(this));
			input.addEventListener("keydown", this._inputKeyDown.bind(this));
			input.addEventListener("search", this._inputSearch.bind(this));
			if (this.params.autocomplete) input.addEventListener("keyup", this._inputKeyUp.bind(this));
		}
		_inputFocus(e) {
			this.rebuildOptionsList();
		}
		_filter() {
			if (this.params.filterRemote) {
				clearTimeout(this.filterTimeout);
				this.filterTimeout = setTimeout(() => {
					this.rebuildOptionsList();
				}, this.params.filterDelay);
			} else this._filterList();
		}
		_inputClick(e) {
			e.stopPropagation();
		}
		_inputBlur(e) {
			if (this.blurable) if (this.popup) this.popup.hide();
			else this._resolveValue(true);
		}
		_inputSearch() {
			this._clearChoices();
		}
		_inputKeyDown(e) {
			switch (e.keyCode) {
				case 38:
					this._keyUp(e);
					break;
				case 40:
					this._keyDown(e);
					break;
				case 37:
				case 39:
					this._keySide(e);
					break;
				case 13:
					this._keyEnter();
					break;
				case 27:
					this._keyEsc();
					break;
				case 36:
				case 35:
					this._keyHomeEnd(e);
					break;
				case 9:
					this._keyTab(e);
					break;
				default: this._keySelectLetter(e);
			}
		}
		_inputKeyUp(e) {
			switch (e.keyCode) {
				case 38:
				case 37:
				case 39:
				case 40:
				case 13:
				case 27: break;
				default: this._keyAutoCompLetter(e);
			}
		}
		_preventPopupBlur() {
			if (this.popup) this.popup.blockHide();
			setTimeout(() => {
				if (this.popup) this.popup.restoreHide();
			}, 10);
		}
		_preventBlur() {
			this.blurable = false;
			setTimeout(() => {
				this.blurable = true;
			}, 10);
		}
		_keyTab(e) {
			if (this.params.autocomplete && this.lastAction === "typing") this._resolveValue(true);
			else if (this.focusedItem) this._chooseItem(this.focusedItem, true);
		}
		_keyUp(e) {
			var index = this.displayItems.indexOf(this.focusedItem);
			if (this.params.verticalNavigation == "editor" || this.params.verticalNavigation == "hybrid" && index) {
				e.stopImmediatePropagation();
				e.stopPropagation();
				e.preventDefault();
				if (index > 0) this._focusItem(this.displayItems[index - 1]);
			}
		}
		_keyDown(e) {
			var index = this.displayItems.indexOf(this.focusedItem);
			if (this.params.verticalNavigation == "editor" || this.params.verticalNavigation == "hybrid" && index < this.displayItems.length - 1) {
				e.stopImmediatePropagation();
				e.stopPropagation();
				e.preventDefault();
				if (index < this.displayItems.length - 1) if (index == -1) this._focusItem(this.displayItems[0]);
				else this._focusItem(this.displayItems[index + 1]);
			}
		}
		_keySide(e) {
			if (!this.params.autocomplete) {
				e.stopImmediatePropagation();
				e.stopPropagation();
				e.preventDefault();
			}
		}
		_keyEnter(e) {
			if (this.params.autocomplete && this.lastAction === "typing") this._resolveValue(true);
			else if (this.focusedItem) this._chooseItem(this.focusedItem);
		}
		_keyEsc(e) {
			this._cancel();
		}
		_keyHomeEnd(e) {
			if (this.params.autocomplete) e.stopImmediatePropagation();
		}
		_keySelectLetter(e) {
			if (!this.params.autocomplete) {
				e.preventDefault();
				if (e.keyCode >= 38 && e.keyCode <= 90) this._scrollToValue(e.keyCode);
			}
		}
		_keyAutoCompLetter(e) {
			this._filter();
			this.lastAction = "typing";
			this.typing = true;
		}
		_scrollToValue(char) {
			clearTimeout(this.filterTimeout);
			var character = String.fromCharCode(char).toLowerCase();
			this.filterTerm += character.toLowerCase();
			var match = this.displayItems.find((item) => {
				return typeof item.label !== "undefined" && item.label.toLowerCase().startsWith(this.filterTerm);
			});
			if (match) this._focusItem(match);
			this.filterTimeout = setTimeout(() => {
				this.filterTerm = "";
			}, 800);
		}
		_focusItem(item) {
			this.lastAction = "focus";
			if (this.focusedItem && this.focusedItem.element) this.focusedItem.element.classList.remove("focused");
			this.focusedItem = item;
			if (item && item.element) {
				item.element.classList.add("focused");
				item.element.scrollIntoView({
					behavior: "smooth",
					block: "nearest",
					inline: "start"
				});
			}
		}
		headerFilterInitialListGen() {
			this._generateOptions(true);
		}
		rebuildOptionsList() {
			this._generateOptions().then(this._sortOptions.bind(this)).then(this._buildList.bind(this)).then(this._showList.bind(this)).catch((e) => {
				if (!Number.isInteger(e)) console.error("List generation error", e);
			});
		}
		_filterList() {
			this._buildList(this._filterOptions());
			this._showList();
		}
		_generateOptions(silent) {
			var values = [];
			var iteration = ++this.listIteration;
			this.filtered = false;
			if (this.params.values) values = this.params.values;
			else if (this.params.valuesURL) values = this._ajaxRequest(this.params.valuesURL, this.input.value);
			else if (typeof this.params.valuesLookup === "function") values = this.params.valuesLookup(this.cell, this.input.value);
			else if (this.params.valuesLookup) values = this._uniqueColumnValues(this.params.valuesLookupField);
			if (values instanceof Promise) {
				if (!silent) this._addPlaceholder(this.params.placeholderLoading);
				return values.then().then((responseValues) => {
					if (this.listIteration === iteration) return this._parseList(responseValues);
					else return Promise.reject(iteration);
				});
			} else return Promise.resolve(this._parseList(values));
		}
		_addPlaceholder(contents) {
			var placeholder = document.createElement("div");
			if (typeof contents === "function") contents = contents(this.cell.getComponent(), this.listEl);
			if (contents) {
				this._clearList();
				if (contents instanceof HTMLElement) placeholder = contents;
				else {
					placeholder.classList.add("tabulator-edit-list-placeholder");
					placeholder.innerHTML = contents;
				}
				this.listEl.appendChild(placeholder);
				this._showList();
			}
		}
		_ajaxRequest(url, term) {
			var params = this.params.filterRemote ? { term } : {};
			url = urlBuilder(url, {}, params);
			return fetch(url).then((response) => {
				if (response.ok) return response.json().catch((error) => {
					console.warn("List Ajax Load Error - Invalid JSON returned", error);
					return Promise.reject(error);
				});
				else {
					console.error("List Ajax Load Error - Connection Error: " + response.status, response.statusText);
					return Promise.reject(response);
				}
			}).catch((error) => {
				console.error("List Ajax Load Error - Connection Error: ", error);
				return Promise.reject(error);
			});
		}
		_uniqueColumnValues(field) {
			var output = {}, data = this.table.getData(this.params.valuesLookup), column;
			if (field) column = this.table.columnManager.getColumnByField(field);
			else column = this.cell.getColumn()._getSelf();
			if (column) data.forEach((row) => {
				var val = column.getFieldValue(row);
				if (!this._emptyValueCheck(val)) if (this.params.multiselect && Array.isArray(val)) val.forEach((item) => {
					if (!this._emptyValueCheck(item)) output[item] = true;
				});
				else output[val] = true;
			});
			else {
				console.warn("unable to find matching column to create select lookup list:", field);
				output = [];
			}
			return Object.keys(output);
		}
		_emptyValueCheck(value) {
			return value === null || typeof value === "undefined" || value === "";
		}
		_parseList(inputValues) {
			var data = [];
			if (!Array.isArray(inputValues)) inputValues = Object.entries(inputValues).map(([key, value]) => {
				return {
					label: value,
					value: key
				};
			});
			inputValues.forEach((value) => {
				if (typeof value !== "object") value = {
					label: value,
					value
				};
				this._parseListItem(value, data, 0);
			});
			if (!this.currentItems.length && this.params.freetext) {
				this.input.value = this.initialValues;
				this.typing = true;
				this.lastAction = "typing";
			}
			this.data = data;
			return data;
		}
		_parseListItem(option, data, level) {
			var item = {};
			if (option.options) item = this._parseListGroup(option, level + 1);
			else {
				item = {
					label: option.label,
					value: option.value,
					itemParams: option.itemParams,
					elementAttributes: option.elementAttributes,
					element: false,
					selected: false,
					visible: true,
					level,
					original: option
				};
				if (this.initialValues && this.initialValues.indexOf(option.value) > -1) this._chooseItem(item, true);
			}
			data.push(item);
		}
		_parseListGroup(option, level) {
			var item = {
				label: option.label,
				group: true,
				itemParams: option.itemParams,
				elementAttributes: option.elementAttributes,
				element: false,
				visible: true,
				level,
				options: [],
				original: option
			};
			option.options.forEach((child) => {
				this._parseListItem(child, item.options, level);
			});
			return item;
		}
		_sortOptions(options) {
			var sorter;
			if (this.params.sort) {
				sorter = typeof this.params.sort === "function" ? this.params.sort : this._defaultSortFunction.bind(this);
				this._sortGroup(sorter, options);
			}
			return options;
		}
		_sortGroup(sorter, options) {
			options.sort((a, b) => {
				return sorter(a.label, b.label, a.value, b.value, a.original, b.original);
			});
			options.forEach((option) => {
				if (option.group) this._sortGroup(sorter, option.options);
			});
		}
		_defaultSortFunction(as, bs) {
			var a, b, a1, b1, i = 0, L, rx = /(\d+)|(\D+)/g, rd = /\d/;
			var emptyAlign = 0;
			if (this.params.sort === "desc") [as, bs] = [bs, as];
			if (!as && as !== 0) emptyAlign = !bs && bs !== 0 ? 0 : -1;
			else if (!bs && bs !== 0) emptyAlign = 1;
			else {
				if (isFinite(as) && isFinite(bs)) return as - bs;
				a = String(as).toLowerCase();
				b = String(bs).toLowerCase();
				if (a === b) return 0;
				if (!(rd.test(a) && rd.test(b))) return a > b ? 1 : -1;
				a = a.match(rx);
				b = b.match(rx);
				L = a.length > b.length ? b.length : a.length;
				while (i < L) {
					a1 = a[i];
					b1 = b[i++];
					if (a1 !== b1) if (isFinite(a1) && isFinite(b1)) {
						if (a1.charAt(0) === "0") a1 = "." + a1;
						if (b1.charAt(0) === "0") b1 = "." + b1;
						return a1 - b1;
					} else return a1 > b1 ? 1 : -1;
				}
				return a.length > b.length;
			}
			return emptyAlign;
		}
		_filterOptions() {
			var filterFunc = this.params.filterFunc || this._defaultFilterFunc, term = this.input.value;
			if (term) {
				this.filtered = true;
				this.data.forEach((item) => {
					this._filterItem(filterFunc, term, item);
				});
			} else this.filtered = false;
			return this.data;
		}
		_filterItem(func, term, item) {
			var matches = false;
			if (!item.group) item.visible = func(term, item.label, item.value, item.original);
			else {
				item.options.forEach((option) => {
					if (this._filterItem(func, term, option)) matches = true;
				});
				item.visible = matches;
			}
			return item.visible;
		}
		_defaultFilterFunc(term, label, value, item) {
			term = String(term).toLowerCase();
			if (label !== null && typeof label !== "undefined") {
				if (String(label).toLowerCase().indexOf(term) > -1 || String(value).toLowerCase().indexOf(term) > -1) return true;
			}
			return false;
		}
		_clearList() {
			while (this.listEl.firstChild) this.listEl.removeChild(this.listEl.firstChild);
			this.displayItems = [];
		}
		_buildList(data) {
			this._clearList();
			data.forEach((option) => {
				this._buildItem(option);
			});
			if (!this.displayItems.length) this._addPlaceholder(this.params.placeholderEmpty);
		}
		_buildItem(item) {
			var el = item.element, contents;
			if (!this.filtered || item.visible) {
				if (!el) {
					el = document.createElement("div");
					el.tabIndex = 0;
					contents = this.params.itemFormatter ? this.params.itemFormatter(item.label, item.value, item.original, el) : item.label;
					if (contents instanceof HTMLElement) el.appendChild(contents);
					else el.innerHTML = contents;
					if (item.group) el.classList.add("tabulator-edit-list-group");
					else el.classList.add("tabulator-edit-list-item");
					el.classList.add("tabulator-edit-list-group-level-" + item.level);
					if (item.elementAttributes && typeof item.elementAttributes == "object") for (let key in item.elementAttributes) if (key.charAt(0) == "+") {
						key = key.slice(1);
						el.setAttribute(key, this.input.getAttribute(key) + item.elementAttributes["+" + key]);
					} else el.setAttribute(key, item.elementAttributes[key]);
					if (item.group) el.addEventListener("click", this._groupClick.bind(this, item));
					else el.addEventListener("click", this._itemClick.bind(this, item));
					el.addEventListener("mousedown", this._preventBlur.bind(this));
					item.element = el;
				}
				this._styleItem(item);
				this.listEl.appendChild(el);
				if (item.group) item.options.forEach((option) => {
					this._buildItem(option);
				});
				else this.displayItems.push(item);
			}
		}
		_showList() {
			var startVis = this.popup && this.popup.isVisible();
			if (this.input.parentNode) {
				if (this.params.autocomplete && this.input.value === "" && !this.params.listOnEmpty) {
					if (this.popup) this.popup.hide(true);
					return;
				}
				this._setListWidth();
				if (!this.popup) this.popup = this.edit.popup(this.listEl);
				this.popup.show(this.cell.getElement(), "bottom");
				if (!startVis) setTimeout(() => {
					this.popup.hideOnBlur(this._resolveValue.bind(this, true));
				}, 10);
			}
		}
		_styleItem(item) {
			if (item && item.element) if (item.selected) item.element.classList.add("active");
			else item.element.classList.remove("active");
		}
		_itemClick(item, e) {
			e.stopPropagation();
			this._chooseItem(item);
		}
		_groupClick(item, e) {
			e.stopPropagation();
		}
		_cancel() {
			this.popup.hide(true);
			this.actions.cancel();
		}
		_clearChoices() {
			this.typing = true;
			this.currentItems.forEach((item) => {
				item.selected = false;
				this._styleItem(item);
			});
			this.currentItems = [];
			this.focusedItem = null;
		}
		_chooseItem(item, silent) {
			var index;
			this.typing = false;
			if (this.params.multiselect) {
				index = this.currentItems.indexOf(item);
				if (index > -1) {
					this.currentItems.splice(index, 1);
					item.selected = false;
				} else {
					this.currentItems.push(item);
					item.selected = true;
				}
				this.input.value = this.currentItems.map((item) => item.label).join(",");
				this._styleItem(item);
			} else {
				this.currentItems = [item];
				item.selected = true;
				this.input.value = item.label;
				this._styleItem(item);
				if (!silent) this._resolveValue();
			}
			this._focusItem(item);
		}
		_resolveValue(blur) {
			var output, initialValue;
			if (this.popup) this.popup.hide(true);
			if (this.params.multiselect) output = this.currentItems.map((item) => item.value);
			else if (blur && this.params.autocomplete && this.typing) if (this.params.freetext || this.params.allowEmpty && this.input.value === "") output = this.input.value;
			else {
				this.actions.cancel();
				return;
			}
			else if (this.currentItems[0]) output = this.currentItems[0].value;
			else {
				initialValue = Array.isArray(this.initialValues) ? this.initialValues[0] : this.initialValues;
				if (initialValue === null || typeof initialValue === "undefined" || initialValue === "") output = initialValue;
				else output = this.params.emptyValue;
			}
			if (output === "") output = this.params.emptyValue;
			this.actions.success(output);
			if (this.isFilter) {
				this.initialValues = output && !Array.isArray(output) ? [output] : output;
				this.currentItems = [];
			}
		}
	};
	function list(cell, onRendered, success, cancel, editorParams) {
		return new Edit$1(this, cell, onRendered, success, cancel, editorParams).input;
	}
	function star$1(cell, onRendered, success, cancel, editorParams) {
		var self = this, element = cell.getElement(), value = cell.getValue(), maxStars = element.getElementsByTagName("svg").length || 5, size = element.getElementsByTagName("svg")[0] ? element.getElementsByTagName("svg")[0].getAttribute("width") : 14, stars = [], starsHolder = document.createElement("div"), star = document.createElementNS("http://www.w3.org/2000/svg", "svg");
		function starChange(val) {
			stars.forEach(function(star, i) {
				if (i < val) {
					if (self.table.browser == "ie") star.setAttribute("class", "tabulator-star-active");
					else star.classList.replace("tabulator-star-inactive", "tabulator-star-active");
					star.innerHTML = "<polygon fill=\"#488CE9\" stroke=\"#014AAE\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>";
				} else {
					if (self.table.browser == "ie") star.setAttribute("class", "tabulator-star-inactive");
					else star.classList.replace("tabulator-star-active", "tabulator-star-inactive");
					star.innerHTML = "<polygon fill=\"#010155\" stroke=\"#686868\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>";
				}
			});
		}
		function buildStar(i) {
			var starHolder = document.createElement("span");
			var nextStar = star.cloneNode(true);
			stars.push(nextStar);
			starHolder.addEventListener("mouseenter", function(e) {
				e.stopPropagation();
				e.stopImmediatePropagation();
				starChange(i);
			});
			starHolder.addEventListener("mousemove", function(e) {
				e.stopPropagation();
				e.stopImmediatePropagation();
			});
			starHolder.addEventListener("click", function(e) {
				e.stopPropagation();
				e.stopImmediatePropagation();
				success(i);
				element.blur();
			});
			starHolder.appendChild(nextStar);
			starsHolder.appendChild(starHolder);
		}
		function changeValue(val) {
			value = val;
			starChange(val);
		}
		element.style.whiteSpace = "nowrap";
		element.style.overflow = "hidden";
		element.style.textOverflow = "ellipsis";
		starsHolder.style.verticalAlign = "middle";
		starsHolder.style.display = "inline-block";
		starsHolder.style.padding = "4px";
		star.setAttribute("width", size);
		star.setAttribute("height", size);
		star.setAttribute("viewBox", "0 0 512 512");
		star.setAttribute("xml:space", "preserve");
		star.style.padding = "0 1px";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			starsHolder.setAttribute(key, starsHolder.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else starsHolder.setAttribute(key, editorParams.elementAttributes[key]);
		for (var i = 1; i <= maxStars; i++) buildStar(i);
		value = Math.min(parseInt(value), maxStars);
		starChange(value);
		starsHolder.addEventListener("mousemove", function(e) {
			starChange(0);
		});
		starsHolder.addEventListener("click", function(e) {
			success(0);
		});
		element.addEventListener("blur", function(e) {
			cancel();
		});
		element.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 39:
					changeValue(value + 1);
					break;
				case 37:
					changeValue(value - 1);
					break;
				case 13:
					success(value);
					break;
				case 27:
					cancel();
					break;
			}
		});
		return starsHolder;
	}
	function progress$1(cell, onRendered, success, cancel, editorParams) {
		var element = cell.getElement(), max = typeof editorParams.max === "undefined" ? element.getElementsByTagName("div")[0] && element.getElementsByTagName("div")[0].getAttribute("max") || 100 : editorParams.max, min = typeof editorParams.min === "undefined" ? element.getElementsByTagName("div")[0] && element.getElementsByTagName("div")[0].getAttribute("min") || 0 : editorParams.min, percent = (max - min) / 100, value = cell.getValue() || 0, handle = document.createElement("div"), bar = document.createElement("div"), mouseDrag, mouseDragWidth;
		function updateValue() {
			var style = window.getComputedStyle(element, null);
			var calcVal = percent * Math.round(bar.offsetWidth / ((element.clientWidth - parseInt(style.getPropertyValue("padding-left")) - parseInt(style.getPropertyValue("padding-right"))) / 100)) + min;
			success(calcVal);
			element.setAttribute("aria-valuenow", calcVal);
			element.setAttribute("aria-label", value);
		}
		handle.style.position = "absolute";
		handle.style.right = "0";
		handle.style.top = "0";
		handle.style.bottom = "0";
		handle.style.width = "5px";
		handle.classList.add("tabulator-progress-handle");
		bar.style.display = "inline-block";
		bar.style.position = "relative";
		bar.style.height = "100%";
		bar.style.backgroundColor = "#488CE9";
		bar.style.maxWidth = "100%";
		bar.style.minWidth = "0%";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			bar.setAttribute(key, bar.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else bar.setAttribute(key, editorParams.elementAttributes[key]);
		element.style.padding = "4px 4px";
		value = Math.min(parseFloat(value), max);
		value = Math.max(parseFloat(value), min);
		value = Math.round((value - min) / percent);
		bar.style.width = value + "%";
		element.setAttribute("aria-valuemin", min);
		element.setAttribute("aria-valuemax", max);
		bar.appendChild(handle);
		handle.addEventListener("mousedown", function(e) {
			mouseDrag = e.screenX;
			mouseDragWidth = bar.offsetWidth;
		});
		handle.addEventListener("mouseover", function() {
			handle.style.cursor = "ew-resize";
		});
		element.addEventListener("mousemove", function(e) {
			if (mouseDrag) bar.style.width = mouseDragWidth + e.screenX - mouseDrag + "px";
		});
		element.addEventListener("mouseup", function(e) {
			if (mouseDrag) {
				e.stopPropagation();
				e.stopImmediatePropagation();
				mouseDrag = false;
				mouseDragWidth = false;
				updateValue();
			}
		});
		element.addEventListener("keydown", function(e) {
			switch (e.keyCode) {
				case 39:
					e.preventDefault();
					bar.style.width = bar.clientWidth + element.clientWidth / 100 + "px";
					break;
				case 37:
					e.preventDefault();
					bar.style.width = bar.clientWidth - element.clientWidth / 100 + "px";
					break;
				case 9:
				case 13:
					updateValue();
					break;
				case 27:
					cancel();
					break;
			}
		});
		element.addEventListener("blur", function() {
			cancel();
		});
		return bar;
	}
	function tickCross$1(cell, onRendered, success, cancel, editorParams) {
		var value = cell.getValue(), input = document.createElement("input"), tristate = editorParams.tristate, indetermValue = typeof editorParams.indeterminateValue === "undefined" ? null : editorParams.indeterminateValue, indetermState = false, trueValueSet = Object.keys(editorParams).includes("trueValue"), falseValueSet = Object.keys(editorParams).includes("falseValue");
		input.setAttribute("type", "checkbox");
		input.style.marginTop = "5px";
		input.style.boxSizing = "border-box";
		if (editorParams.elementAttributes && typeof editorParams.elementAttributes == "object") for (let key in editorParams.elementAttributes) if (key.charAt(0) == "+") {
			key = key.slice(1);
			input.setAttribute(key, input.getAttribute(key) + editorParams.elementAttributes["+" + key]);
		} else input.setAttribute(key, editorParams.elementAttributes[key]);
		input.value = value;
		if (tristate && (typeof value === "undefined" || value === indetermValue || value === "")) {
			indetermState = true;
			input.indeterminate = true;
		}
		if (this.table.browser != "firefox" && this.table.browser != "safari") onRendered(function() {
			if (cell.getType() === "cell") input.focus({ preventScroll: true });
		});
		input.checked = trueValueSet ? value === editorParams.trueValue : value === true || value === "true" || value === "True" || value === 1;
		function setValue(blur) {
			var checkedValue = input.checked;
			if (trueValueSet && checkedValue) checkedValue = editorParams.trueValue;
			else if (falseValueSet && !checkedValue) checkedValue = editorParams.falseValue;
			if (tristate) if (!blur) if (input.checked && !indetermState) {
				input.checked = false;
				input.indeterminate = true;
				indetermState = true;
				return indetermValue;
			} else {
				indetermState = false;
				return checkedValue;
			}
			else if (indetermState) return indetermValue;
			else return checkedValue;
			else return checkedValue;
		}
		input.addEventListener("change", function(e) {
			success(setValue());
		});
		input.addEventListener("blur", function(e) {
			success(setValue(true));
		});
		input.addEventListener("keydown", function(e) {
			if (e.keyCode == 13) success(setValue());
			if (e.keyCode == 27) cancel();
		});
		return input;
	}
	function adaptable$1(cell, onRendered, success, cancel, params) {
		var column = cell._getSelf().column, lookup, editorFunc, editorParams;
		function defaultLookup(cell) {
			var value = cell.getValue(), editor = "input";
			switch (typeof value) {
				case "number":
					editor = "number";
					break;
				case "boolean":
					editor = "tickCross";
					break;
				case "string":
					if (value.includes("\n")) editor = "textarea";
					break;
			}
			return editor;
		}
		lookup = params.editorLookup ? params.editorLookup(cell) : defaultLookup(cell);
		if (params.paramsLookup) editorParams = typeof params.paramsLookup === "function" ? params.paramsLookup(lookup, cell) : params.paramsLookup[lookup];
		editorFunc = this.table.modules.edit.lookupEditor(lookup, column);
		return editorFunc.call(this, cell, onRendered, success, cancel, editorParams || {});
	}
	var defaultEditors = {
		input,
		textarea: textarea$1,
		number: number$1,
		range,
		date: date$1,
		time: time$1,
		datetime: datetime$2,
		list,
		star: star$1,
		progress: progress$1,
		tickCross: tickCross$1,
		adaptable: adaptable$1
	};
	var Edit = class Edit extends Module {
		static moduleName = "edit";
		static editors = defaultEditors;
		constructor(table) {
			super(table);
			this.currentCell = false;
			this.mouseClick = false;
			this.recursionBlock = false;
			this.invalidEdit = false;
			this.editedCells = [];
			this.convertEmptyValues = false;
			this.editors = Edit.editors;
			this.registerTableOption("editTriggerEvent", "focus");
			this.registerTableOption("editorEmptyValue");
			this.registerTableOption("editorEmptyValueFunc", this.emptyValueCheck.bind(this));
			this.registerColumnOption("editable");
			this.registerColumnOption("editor");
			this.registerColumnOption("editorParams");
			this.registerColumnOption("editorEmptyValue");
			this.registerColumnOption("editorEmptyValueFunc");
			this.registerColumnOption("cellEditing");
			this.registerColumnOption("cellEdited");
			this.registerColumnOption("cellEditCancelled");
			this.registerTableFunction("getEditedCells", this.getEditedCells.bind(this));
			this.registerTableFunction("clearCellEdited", this.clearCellEdited.bind(this));
			this.registerTableFunction("navigatePrev", this.navigatePrev.bind(this));
			this.registerTableFunction("navigateNext", this.navigateNext.bind(this));
			this.registerTableFunction("navigateLeft", this.navigateLeft.bind(this));
			this.registerTableFunction("navigateRight", this.navigateRight.bind(this));
			this.registerTableFunction("navigateUp", this.navigateUp.bind(this));
			this.registerTableFunction("navigateDown", this.navigateDown.bind(this));
			this.registerComponentFunction("cell", "isEdited", this.cellIsEdited.bind(this));
			this.registerComponentFunction("cell", "clearEdited", this.clearEdited.bind(this));
			this.registerComponentFunction("cell", "edit", this.editCell.bind(this));
			this.registerComponentFunction("cell", "cancelEdit", this.cellCancelEdit.bind(this));
			this.registerComponentFunction("cell", "navigatePrev", this.navigatePrev.bind(this));
			this.registerComponentFunction("cell", "navigateNext", this.navigateNext.bind(this));
			this.registerComponentFunction("cell", "navigateLeft", this.navigateLeft.bind(this));
			this.registerComponentFunction("cell", "navigateRight", this.navigateRight.bind(this));
			this.registerComponentFunction("cell", "navigateUp", this.navigateUp.bind(this));
			this.registerComponentFunction("cell", "navigateDown", this.navigateDown.bind(this));
		}
		initialize() {
			this.subscribe("cell-init", this.bindEditor.bind(this));
			this.subscribe("cell-delete", this.clearEdited.bind(this));
			this.subscribe("cell-value-changed", this.updateCellClass.bind(this));
			this.subscribe("column-layout", this.initializeColumnCheck.bind(this));
			this.subscribe("column-delete", this.columnDeleteCheck.bind(this));
			this.subscribe("row-deleting", this.rowDeleteCheck.bind(this));
			this.subscribe("row-layout", this.rowEditableCheck.bind(this));
			this.subscribe("data-refreshing", this.cancelEdit.bind(this));
			this.subscribe("clipboard-paste", this.pasteBlocker.bind(this));
			this.subscribe("keybinding-nav-prev", this.navigatePrev.bind(this, void 0));
			this.subscribe("keybinding-nav-next", this.keybindingNavigateNext.bind(this));
			this.subscribe("keybinding-nav-up", this.navigateUp.bind(this, void 0));
			this.subscribe("keybinding-nav-down", this.navigateDown.bind(this, void 0));
			if (Object.keys(this.table.options).includes("editorEmptyValue")) this.convertEmptyValues = true;
		}
		pasteBlocker(e) {
			if (this.currentCell) return true;
		}
		keybindingNavigateNext(e) {
			var cell = this.currentCell, newRow = this.options("tabEndNewRow");
			if (cell) {
				if (!this.navigateNext(cell, e)) {
					if (newRow) {
						cell.getElement().firstChild.blur();
						if (!this.invalidEdit) {
							if (newRow === true) newRow = this.table.addRow({});
							else if (typeof newRow == "function") newRow = this.table.addRow(newRow(cell.row.getComponent()));
							else newRow = this.table.addRow(Object.assign({}, newRow));
							newRow.then(() => {
								setTimeout(() => {
									cell.getComponent().navigateNext();
								});
							});
						}
					}
				}
			}
		}
		cellIsEdited(cell) {
			return !!cell.modules.edit && cell.modules.edit.edited;
		}
		cellCancelEdit(cell) {
			if (cell === this.currentCell) this.table.modules.edit.cancelEdit();
			else console.warn("Cancel Editor Error - This cell is not currently being edited ");
		}
		updateCellClass(cell) {
			if (this.allowEdit(cell)) cell.getElement().classList.add("tabulator-editable");
			else cell.getElement().classList.remove("tabulator-editable");
		}
		clearCellEdited(cells) {
			if (!cells) cells = this.table.modules.edit.getEditedCells();
			if (!Array.isArray(cells)) cells = [cells];
			cells.forEach((cell) => {
				this.table.modules.edit.clearEdited(cell._getSelf());
			});
		}
		navigatePrev(cell = this.currentCell, e) {
			var nextCell, prevRow;
			if (cell) {
				if (e) e.preventDefault();
				nextCell = this.navigateLeft();
				if (nextCell) return true;
				else {
					prevRow = this.table.rowManager.prevDisplayRow(cell.row, true);
					if (prevRow) {
						nextCell = this.findPrevEditableCell(prevRow, prevRow.cells.length);
						if (nextCell) {
							nextCell.getComponent().edit();
							return true;
						}
					}
				}
			}
			return false;
		}
		navigateNext(cell = this.currentCell, e) {
			var nextCell, nextRow;
			if (cell) {
				if (e) e.preventDefault();
				nextCell = this.navigateRight();
				if (nextCell) return true;
				else {
					nextRow = this.table.rowManager.nextDisplayRow(cell.row, true);
					if (nextRow) {
						nextCell = this.findNextEditableCell(nextRow, -1);
						if (nextCell) {
							nextCell.getComponent().edit();
							return true;
						}
					}
				}
			}
			return false;
		}
		navigateLeft(cell = this.currentCell, e) {
			var index, nextCell;
			if (cell) {
				if (e) e.preventDefault();
				index = cell.getIndex();
				nextCell = this.findPrevEditableCell(cell.row, index);
				if (nextCell) {
					nextCell.getComponent().edit();
					return true;
				}
			}
			return false;
		}
		navigateRight(cell = this.currentCell, e) {
			var index, nextCell;
			if (cell) {
				if (e) e.preventDefault();
				index = cell.getIndex();
				nextCell = this.findNextEditableCell(cell.row, index);
				if (nextCell) {
					nextCell.getComponent().edit();
					return true;
				}
			}
			return false;
		}
		navigateUp(cell = this.currentCell, e) {
			var index, nextRow;
			if (cell) {
				if (e) e.preventDefault();
				index = cell.getIndex();
				nextRow = this.table.rowManager.prevDisplayRow(cell.row, true);
				if (nextRow) {
					nextRow.cells[index].getComponent().edit();
					return true;
				}
			}
			return false;
		}
		navigateDown(cell = this.currentCell, e) {
			var index, nextRow;
			if (cell) {
				if (e) e.preventDefault();
				index = cell.getIndex();
				nextRow = this.table.rowManager.nextDisplayRow(cell.row, true);
				if (nextRow) {
					nextRow.cells[index].getComponent().edit();
					return true;
				}
			}
			return false;
		}
		findNextEditableCell(row, index) {
			var nextCell = false;
			if (index < row.cells.length - 1) for (var i = index + 1; i < row.cells.length; i++) {
				let cell = row.cells[i];
				if (cell.column.modules.edit && Helpers.elVisible(cell.getElement())) {
					if (this.allowEdit(cell)) {
						nextCell = cell;
						break;
					}
				}
			}
			return nextCell;
		}
		findPrevEditableCell(row, index) {
			var prevCell = false;
			if (index > 0) for (var i = index - 1; i >= 0; i--) {
				let cell = row.cells[i];
				if (cell.column.modules.edit && Helpers.elVisible(cell.getElement())) {
					if (this.allowEdit(cell)) {
						prevCell = cell;
						break;
					}
				}
			}
			return prevCell;
		}
		initializeColumnCheck(column) {
			if (typeof column.definition.editor !== "undefined") this.initializeColumn(column);
		}
		columnDeleteCheck(column) {
			if (this.currentCell && this.currentCell.column === column) this.cancelEdit();
		}
		rowDeleteCheck(row) {
			if (this.currentCell && this.currentCell.row === row) this.cancelEdit();
		}
		rowEditableCheck(row) {
			row.getCells().forEach((cell) => {
				if (cell.column.modules.edit && typeof cell.column.modules.edit.check === "function") this.updateCellClass(cell);
			});
		}
		initializeColumn(column) {
			var convertEmpty = Object.keys(column.definition).includes("editorEmptyValue");
			var config = {
				editor: false,
				blocked: false,
				check: column.definition.editable,
				params: column.definition.editorParams || {},
				convertEmptyValues: convertEmpty,
				editorEmptyValue: column.definition.editorEmptyValue,
				editorEmptyValueFunc: column.definition.editorEmptyValueFunc
			};
			config.editor = this.lookupEditor(column.definition.editor, column);
			if (config.editor) column.modules.edit = config;
		}
		lookupEditor(editor, column) {
			var editorFunc;
			switch (typeof editor) {
				case "string":
					if (this.editors[editor]) editorFunc = this.editors[editor];
					else console.warn("Editor Error - No such editor found: ", editor);
					break;
				case "function":
					editorFunc = editor;
					break;
				case "boolean":
					if (editor === true) if (typeof column.definition.formatter !== "function") if (this.editors[column.definition.formatter]) editorFunc = this.editors[column.definition.formatter];
					else editorFunc = this.editors["input"];
					else console.warn("Editor Error - Cannot auto lookup editor for a custom formatter: ", column.definition.formatter);
					break;
			}
			return editorFunc;
		}
		getCurrentCell() {
			return this.currentCell ? this.currentCell.getComponent() : false;
		}
		clearEditor(cancel) {
			var cell = this.currentCell, cellEl;
			this.invalidEdit = false;
			if (cell) {
				this.currentCell = false;
				cellEl = cell.getElement();
				this.dispatch("edit-editor-clear", cell, cancel);
				cellEl.classList.remove("tabulator-editing");
				while (cellEl.firstChild) cellEl.removeChild(cellEl.firstChild);
				cell.row.getElement().classList.remove("tabulator-editing");
				cell.table.element.classList.remove("tabulator-editing");
			}
		}
		cancelEdit() {
			if (this.currentCell) {
				var cell = this.currentCell;
				var component = this.currentCell.getComponent();
				this.clearEditor(true);
				cell.setValueActual(cell.getValue());
				cell.cellRendered();
				if (cell.column.definition.editor == "textarea" || cell.column.definition.variableHeight) cell.row.normalizeHeight(true);
				if (cell.column.definition.cellEditCancelled) cell.column.definition.cellEditCancelled.call(this.table, component);
				this.dispatch("edit-cancelled", cell);
				this.dispatchExternal("cellEditCancelled", component);
			}
		}
		bindEditor(cell) {
			if (cell.column.modules.edit) {
				var self = this, element = cell.getElement(true);
				this.updateCellClass(cell);
				element.setAttribute("tabindex", 0);
				element.addEventListener("mousedown", function(e) {
					if (e.button === 2) e.preventDefault();
					else self.mouseClick = true;
				});
				if (this.options("editTriggerEvent") === "dblclick") element.addEventListener("dblclick", function(e) {
					if (!element.classList.contains("tabulator-editing")) {
						element.focus({ preventScroll: true });
						self.edit(cell, e, false);
					}
				});
				if (this.options("editTriggerEvent") === "focus" || this.options("editTriggerEvent") === "click") element.addEventListener("click", function(e) {
					if (!element.classList.contains("tabulator-editing")) {
						element.focus({ preventScroll: true });
						self.edit(cell, e, false);
					}
				});
				if (this.options("editTriggerEvent") === "focus") element.addEventListener("focus", function(e) {
					if (!self.recursionBlock) self.edit(cell, e, false);
				});
			}
		}
		focusCellNoEvent(cell, block) {
			this.recursionBlock = true;
			if (!(block && this.table.browser === "ie")) cell.getElement().focus({ preventScroll: true });
			this.recursionBlock = false;
		}
		editCell(cell, forceEdit) {
			this.focusCellNoEvent(cell);
			this.edit(cell, false, forceEdit);
		}
		focusScrollAdjust(cell) {
			if (this.table.rowManager.getRenderMode() == "virtual") {
				var topEdge = this.table.rowManager.element.scrollTop, bottomEdge = this.table.rowManager.element.clientHeight + this.table.rowManager.element.scrollTop, rowEl = cell.row.getElement();
				if (rowEl.offsetTop < topEdge) this.table.rowManager.element.scrollTop -= topEdge - rowEl.offsetTop;
				else if (rowEl.offsetTop + rowEl.offsetHeight > bottomEdge) this.table.rowManager.element.scrollTop += rowEl.offsetTop + rowEl.offsetHeight - bottomEdge;
				var leftEdge = this.table.rowManager.element.scrollLeft, rightEdge = this.table.rowManager.element.clientWidth + this.table.rowManager.element.scrollLeft, cellEl = cell.getElement();
				if (this.table.modExists("frozenColumns")) {
					leftEdge += parseInt(this.table.modules.frozenColumns.leftMargin || 0);
					rightEdge -= parseInt(this.table.modules.frozenColumns.rightMargin || 0);
				}
				if (this.table.options.renderHorizontal === "virtual") {
					leftEdge -= parseInt(this.table.columnManager.renderer.vDomPadLeft);
					rightEdge -= parseInt(this.table.columnManager.renderer.vDomPadLeft);
				}
				if (cellEl.offsetLeft < leftEdge) this.table.rowManager.element.scrollLeft -= leftEdge - cellEl.offsetLeft;
				else if (cellEl.offsetLeft + cellEl.offsetWidth > rightEdge) this.table.rowManager.element.scrollLeft += cellEl.offsetLeft + cellEl.offsetWidth - rightEdge;
			}
		}
		allowEdit(cell) {
			var check = cell.column.modules.edit ? true : false;
			if (cell.column.modules.edit) switch (typeof cell.column.modules.edit.check) {
				case "function":
					if (cell.row.initialized) check = cell.column.modules.edit.check(cell.getComponent());
					break;
				case "string":
					check = !!cell.row.data[cell.column.modules.edit.check];
					break;
				case "boolean":
					check = cell.column.modules.edit.check;
					break;
			}
			return check;
		}
		edit(cell, e, forceEdit) {
			var self = this, allowEdit = true, rendered = function() {}, element = cell.getElement(), editFinished = false, cellEditor, component, params;
			if (this.currentCell) {
				if (!this.invalidEdit && this.currentCell !== cell) this.cancelEdit();
				return;
			}
			function success(value) {
				if (self.currentCell === cell && !editFinished) {
					var valid = self.chain("edit-success", [cell, value], true, true);
					if (valid === true || self.table.options.validationMode === "highlight") {
						editFinished = true;
						self.clearEditor();
						if (!cell.modules.edit) cell.modules.edit = {};
						cell.modules.edit.edited = true;
						if (self.editedCells.indexOf(cell) == -1) self.editedCells.push(cell);
						value = self.transformEmptyValues(value, cell);
						cell.setValue(value, true);
						return valid === true;
					} else {
						editFinished = true;
						self.invalidEdit = true;
						self.focusCellNoEvent(cell, true);
						rendered();
						setTimeout(() => {
							editFinished = false;
						}, 10);
						return false;
					}
				}
			}
			function cancel() {
				if (self.currentCell === cell && !editFinished) self.cancelEdit();
			}
			function onRendered(callback) {
				rendered = callback;
			}
			if (!cell.column.modules.edit.blocked) {
				if (e) e.stopPropagation();
				allowEdit = this.allowEdit(cell);
				if (allowEdit || forceEdit) {
					self.cancelEdit();
					self.currentCell = cell;
					this.focusScrollAdjust(cell);
					component = cell.getComponent();
					if (this.mouseClick) {
						this.mouseClick = false;
						if (cell.column.definition.cellClick) cell.column.definition.cellClick.call(this.table, e, component);
					}
					if (cell.column.definition.cellEditing) cell.column.definition.cellEditing.call(this.table, component);
					this.dispatch("cell-editing", cell);
					this.dispatchExternal("cellEditing", component);
					params = typeof cell.column.modules.edit.params === "function" ? cell.column.modules.edit.params(component) : cell.column.modules.edit.params;
					cellEditor = cell.column.modules.edit.editor.call(self, component, onRendered, success, cancel, params);
					if (this.currentCell && cellEditor !== false) if (cellEditor instanceof Node) {
						element.classList.add("tabulator-editing");
						cell.row.getElement().classList.add("tabulator-editing");
						cell.table.element.classList.add("tabulator-editing");
						while (element.firstChild) element.removeChild(element.firstChild);
						element.appendChild(cellEditor);
						rendered();
						var children = element.children;
						for (var i = 0; i < children.length; i++) children[i].addEventListener("click", function(e) {
							e.stopPropagation();
						});
					} else {
						console.warn("Edit Error - Editor should return an instance of Node, the editor returned:", cellEditor);
						this.blur(element);
						return false;
					}
					else {
						this.blur(element);
						return false;
					}
					return true;
				} else {
					this.mouseClick = false;
					this.blur(element);
					return false;
				}
			} else {
				this.mouseClick = false;
				this.blur(element);
				return false;
			}
		}
		emptyValueCheck(value) {
			return value === "" || value === null || typeof value === "undefined";
		}
		transformEmptyValues(value, cell) {
			var mod = cell.column.modules.edit, convert = mod.convertEmptyValues || this.convertEmptyValues, checkFunc;
			if (convert) {
				checkFunc = mod.editorEmptyValueFunc || this.options("editorEmptyValueFunc");
				if (checkFunc && checkFunc(value)) value = mod.convertEmptyValues ? mod.editorEmptyValue : this.options("editorEmptyValue");
			}
			return value;
		}
		blur(element) {
			if (!this.confirm("edit-blur", [element])) element.blur();
		}
		getEditedCells() {
			var output = [];
			this.editedCells.forEach((cell) => {
				output.push(cell.getComponent());
			});
			return output;
		}
		clearEdited(cell) {
			var editIndex;
			if (cell.modules.edit && cell.modules.edit.edited) {
				cell.modules.edit.edited = false;
				this.dispatch("edit-edited-clear", cell);
			}
			editIndex = this.editedCells.indexOf(cell);
			if (editIndex > -1) this.editedCells.splice(editIndex, 1);
		}
	};
	var ExportRow = class {
		constructor(type, columns, component, indent) {
			this.type = type;
			this.columns = columns;
			this.component = component || false;
			this.indent = indent || 0;
		}
	};
	var ExportColumn = class {
		constructor(value, component, width, height, depth) {
			this.value = value;
			this.component = component || false;
			this.width = width;
			this.height = height;
			this.depth = depth;
		}
	};
	var columnLookups$1 = {};
	var rowLookups$1 = {
		visible: function() {
			return this.rowManager.getVisibleRows(false, true);
		},
		all: function() {
			return this.rowManager.rows;
		},
		selected: function() {
			return this.modules.selectRow.selectedRows;
		},
		active: function() {
			if (this.options.pagination) return this.rowManager.getDisplayRows(this.rowManager.displayRows.length - 2);
			else return this.rowManager.getDisplayRows();
		}
	};
	var Export = class Export extends Module {
		static moduleName = "export";
		static columnLookups = columnLookups$1;
		static rowLookups = rowLookups$1;
		constructor(table) {
			super(table);
			this.config = {};
			this.cloneTableStyle = true;
			this.colVisProp = "";
			this.colVisPropAttach = "";
			this.registerTableOption("htmlOutputConfig", false);
			this.registerColumnOption("htmlOutput");
			this.registerColumnOption("titleHtmlOutput");
		}
		initialize() {
			this.registerTableFunction("getHtml", this.getHtml.bind(this));
		}
		generateExportList(config, style, range, colVisProp) {
			var headers, body, columns, colLookup;
			this.cloneTableStyle = style;
			this.config = config || {};
			this.colVisProp = colVisProp;
			this.colVisPropAttach = this.colVisProp.charAt(0).toUpperCase() + this.colVisProp.slice(1);
			colLookup = Export.columnLookups[range];
			if (colLookup) {
				columns = colLookup.call(this.table);
				columns = columns.filter((col) => this.columnVisCheck(col));
			}
			headers = this.config.columnHeaders !== false ? this.headersToExportRows(this.generateColumnGroupHeaders(columns)) : [];
			if (columns) columns = columns.map((col) => col.getComponent());
			body = this.bodyToExportRows(this.rowLookup(range), columns);
			return headers.concat(body);
		}
		generateTable(config, style, range, colVisProp) {
			var list = this.generateExportList(config, style, range, colVisProp);
			return this.generateTableElement(list);
		}
		rowLookup(range) {
			var rows = [], rowLookup;
			if (typeof range == "function") range.call(this.table).forEach((row) => {
				row = this.table.rowManager.findRow(row);
				if (row) rows.push(row);
			});
			else {
				rowLookup = Export.rowLookups[range] || Export.rowLookups["active"];
				rows = rowLookup.call(this.table);
			}
			return Object.assign([], rows);
		}
		generateColumnGroupHeaders(columns) {
			var output = [];
			if (!columns) columns = this.config.columnGroups !== false ? this.table.columnManager.columns : this.table.columnManager.columnsByIndex;
			columns.forEach((column) => {
				var colData = this.processColumnGroup(column);
				if (colData) output.push(colData);
			});
			return output;
		}
		processColumnGroup(column) {
			var subGroups = column.columns, maxDepth = 0;
			var groupData = {
				title: column.definition["title" + this.colVisPropAttach] || column.definition.title,
				column,
				depth: 1
			};
			if (subGroups.length) {
				groupData.subGroups = [];
				groupData.width = 0;
				subGroups.forEach((subGroup) => {
					var subGroupData = this.processColumnGroup(subGroup);
					if (subGroupData) {
						groupData.width += subGroupData.width;
						groupData.subGroups.push(subGroupData);
						if (subGroupData.depth > maxDepth) maxDepth = subGroupData.depth;
					}
				});
				groupData.depth += maxDepth;
				if (!groupData.width) return false;
			} else if (this.columnVisCheck(column)) groupData.width = 1;
			else return false;
			return groupData;
		}
		columnVisCheck(column) {
			var visProp = column.definition[this.colVisProp];
			if (this.config.rowHeaders === false && column.isRowHeader) return false;
			if (typeof visProp === "function") visProp = visProp.call(this.table, column.getComponent());
			if (visProp === false || visProp === true) return visProp;
			return column.visible && column.field;
		}
		headersToExportRows(columns) {
			var headers = [], headerDepth = 0, exportRows = [];
			function parseColumnGroup(column, level) {
				var depth = headerDepth - level;
				if (typeof headers[level] === "undefined") headers[level] = [];
				column.height = column.subGroups ? 1 : depth - column.depth + 1;
				headers[level].push(column);
				if (column.height > 1) for (let i = 1; i < column.height; i++) {
					if (typeof headers[level + i] === "undefined") headers[level + i] = [];
					headers[level + i].push(false);
				}
				if (column.width > 1) for (let i = 1; i < column.width; i++) headers[level].push(false);
				if (column.subGroups) column.subGroups.forEach(function(subGroup) {
					parseColumnGroup(subGroup, level + 1);
				});
			}
			columns.forEach(function(column) {
				if (column.depth > headerDepth) headerDepth = column.depth;
			});
			columns.forEach(function(column) {
				parseColumnGroup(column, 0);
			});
			headers.forEach((header) => {
				var columns = [];
				header.forEach((col) => {
					if (col) {
						let title = typeof col.title === "undefined" ? "" : col.title;
						columns.push(new ExportColumn(title, col.column.getComponent(), col.width, col.height, col.depth));
					} else columns.push(null);
				});
				exportRows.push(new ExportRow("header", columns));
			});
			return exportRows;
		}
		bodyToExportRows(rows, columns = []) {
			var exportRows = [];
			if (columns.length === 0) this.table.columnManager.columnsByIndex.forEach((column) => {
				if (this.columnVisCheck(column)) columns.push(column.getComponent());
			});
			if (this.config.columnCalcs !== false && this.table.modExists("columnCalcs")) {
				if (this.table.modules.columnCalcs.topInitialized) rows.unshift(this.table.modules.columnCalcs.topRow);
				if (this.table.modules.columnCalcs.botInitialized) rows.push(this.table.modules.columnCalcs.botRow);
			}
			rows = rows.filter((row) => {
				switch (row.type) {
					case "group": return this.config.rowGroups !== false;
					case "calc": return this.config.columnCalcs !== false;
					case "row": return !(this.table.options.dataTree && this.config.dataTree === false && row.modules.dataTree.parent);
				}
				return true;
			});
			rows.forEach((row, i) => {
				var rowData = row.getData(this.colVisProp);
				var exportCols = [];
				var indent = 0;
				switch (row.type) {
					case "group":
						indent = row.level;
						exportCols.push(new ExportColumn(row.key, row.getComponent(), columns.length, 1));
						break;
					case "calc":
					case "row":
						columns.forEach((col) => {
							exportCols.push(new ExportColumn(col._column.getFieldValue(rowData), col, 1, 1));
						});
						if (this.table.options.dataTree && this.config.dataTree !== false) indent = row.modules.dataTree.index;
						break;
				}
				exportRows.push(new ExportRow(row.type, exportCols, row.getComponent(), indent));
			});
			return exportRows;
		}
		generateTableElement(list) {
			var table = document.createElement("table"), headerEl = document.createElement("thead"), bodyEl = document.createElement("tbody"), styles = this.lookupTableStyles(), rowFormatter = this.table.options["rowFormatter" + this.colVisPropAttach], setup = {};
			setup.rowFormatter = rowFormatter !== null ? rowFormatter : this.table.options.rowFormatter;
			if (this.table.options.dataTree && this.config.dataTree !== false && this.table.modExists("columnCalcs")) setup.treeElementField = this.table.modules.dataTree.elementField;
			setup.groupHeader = this.table.options["groupHeader" + this.colVisPropAttach];
			if (setup.groupHeader && !Array.isArray(setup.groupHeader)) setup.groupHeader = [setup.groupHeader];
			table.classList.add("tabulator-print-table");
			this.mapElementStyles(this.table.columnManager.getHeadersElement(), headerEl, [
				"border-top",
				"border-left",
				"border-right",
				"border-bottom",
				"background-color",
				"color",
				"font-weight",
				"font-family",
				"font-size"
			]);
			if (list.length > 1e3) console.warn("It may take a long time to render an HTML table with more than 1000 rows");
			list.forEach((row, i) => {
				let rowEl;
				switch (row.type) {
					case "header":
						headerEl.appendChild(this.generateHeaderElement(row, setup, styles));
						break;
					case "group":
						bodyEl.appendChild(this.generateGroupElement(row, setup, styles));
						break;
					case "calc":
						bodyEl.appendChild(this.generateCalcElement(row, setup, styles));
						break;
					case "row":
						rowEl = this.generateRowElement(row, setup, styles);
						this.mapElementStyles(i % 2 && styles.evenRow ? styles.evenRow : styles.oddRow, rowEl, [
							"border-top",
							"border-left",
							"border-right",
							"border-bottom",
							"color",
							"font-weight",
							"font-family",
							"font-size",
							"background-color"
						]);
						bodyEl.appendChild(rowEl);
						break;
				}
			});
			if (headerEl.innerHTML) table.appendChild(headerEl);
			table.appendChild(bodyEl);
			this.mapElementStyles(this.table.element, table, [
				"border-top",
				"border-left",
				"border-right",
				"border-bottom"
			]);
			return table;
		}
		lookupTableStyles() {
			var styles = {};
			if (this.cloneTableStyle && window.getComputedStyle) {
				styles.oddRow = this.table.element.querySelector(".tabulator-row-odd:not(.tabulator-group):not(.tabulator-calcs)");
				styles.evenRow = this.table.element.querySelector(".tabulator-row-even:not(.tabulator-group):not(.tabulator-calcs)");
				styles.calcRow = this.table.element.querySelector(".tabulator-row.tabulator-calcs");
				styles.firstRow = this.table.element.querySelector(".tabulator-row:not(.tabulator-group):not(.tabulator-calcs)");
				styles.firstGroup = this.table.element.getElementsByClassName("tabulator-group")[0];
				if (styles.firstRow) {
					styles.styleCells = styles.firstRow.getElementsByClassName("tabulator-cell");
					styles.styleRowHeader = styles.firstRow.getElementsByClassName("tabulator-row-header")[0];
					styles.firstCell = styles.styleCells[0];
					styles.lastCell = styles.styleCells[styles.styleCells.length - 1];
				}
			}
			return styles;
		}
		generateHeaderElement(row, setup, styles) {
			var rowEl = document.createElement("tr");
			row.columns.forEach((column) => {
				if (column) {
					var cellEl = document.createElement("th");
					var classNames = column.component._column.definition.cssClass ? column.component._column.definition.cssClass.split(" ") : [];
					cellEl.colSpan = column.width;
					cellEl.rowSpan = column.height;
					cellEl.innerHTML = column.value;
					if (this.cloneTableStyle) cellEl.style.boxSizing = "border-box";
					classNames.forEach(function(className) {
						cellEl.classList.add(className);
					});
					this.mapElementStyles(column.component.getElement(), cellEl, [
						"text-align",
						"border-left",
						"border-right",
						"background-color",
						"color",
						"font-weight",
						"font-family",
						"font-size"
					]);
					this.mapElementStyles(column.component._column.contentElement, cellEl, [
						"padding-top",
						"padding-left",
						"padding-right",
						"padding-bottom"
					]);
					if (column.component._column.visible) this.mapElementStyles(column.component.getElement(), cellEl, ["width"]);
					else if (column.component._column.definition.width) cellEl.style.width = column.component._column.definition.width + "px";
					if (column.component._column.parent && column.component._column.parent.isGroup) this.mapElementStyles(column.component._column.parent.groupElement, cellEl, ["border-top"]);
					else this.mapElementStyles(column.component.getElement(), cellEl, ["border-top"]);
					if (column.component._column.isGroup) this.mapElementStyles(column.component.getElement(), cellEl, ["border-bottom"]);
					else this.mapElementStyles(this.table.columnManager.getElement(), cellEl, ["border-bottom"]);
					rowEl.appendChild(cellEl);
				}
			});
			return rowEl;
		}
		generateGroupElement(row, setup, styles) {
			var rowEl = document.createElement("tr"), cellEl = document.createElement("td"), group = row.columns[0];
			rowEl.classList.add("tabulator-print-table-row");
			if (setup.groupHeader && setup.groupHeader[row.indent]) group.value = setup.groupHeader[row.indent](group.value, row.component._group.getRowCount(), row.component._group.getData(), row.component);
			else if (setup.groupHeader !== false) group.value = row.component._group.generator(group.value, row.component._group.getRowCount(), row.component._group.getData(), row.component);
			cellEl.colSpan = group.width;
			cellEl.innerHTML = group.value;
			rowEl.classList.add("tabulator-print-table-group");
			rowEl.classList.add("tabulator-group-level-" + row.indent);
			if (group.component.isVisible()) rowEl.classList.add("tabulator-group-visible");
			this.mapElementStyles(styles.firstGroup, rowEl, [
				"border-top",
				"border-left",
				"border-right",
				"border-bottom",
				"color",
				"font-weight",
				"font-family",
				"font-size",
				"background-color"
			]);
			this.mapElementStyles(styles.firstGroup, cellEl, [
				"padding-top",
				"padding-left",
				"padding-right",
				"padding-bottom"
			]);
			rowEl.appendChild(cellEl);
			return rowEl;
		}
		generateCalcElement(row, setup, styles) {
			var rowEl = this.generateRowElement(row, setup, styles);
			rowEl.classList.add("tabulator-print-table-calcs");
			this.mapElementStyles(styles.calcRow, rowEl, [
				"border-top",
				"border-left",
				"border-right",
				"border-bottom",
				"color",
				"font-weight",
				"font-family",
				"font-size",
				"background-color"
			]);
			return rowEl;
		}
		generateRowElement(row, setup, styles) {
			var rowEl = document.createElement("tr");
			rowEl.classList.add("tabulator-print-table-row");
			row.columns.forEach((col, i) => {
				if (col) {
					var cellEl = document.createElement("td"), column = col.component._column, table = this.table, index = table.columnManager.findColumnIndex(column), value = col.value, cellStyle, styleProps;
					var cellWrapper = {
						modules: {},
						getValue: function() {
							return value;
						},
						getField: function() {
							return column.definition.field;
						},
						getElement: function() {
							return cellEl;
						},
						getType: function() {
							return "cell";
						},
						getColumn: function() {
							return column.getComponent();
						},
						getData: function() {
							return row.component.getData();
						},
						getRow: function() {
							return row.component;
						},
						getTable: function() {
							return table;
						},
						getComponent: function() {
							return cellWrapper;
						},
						column
					};
					(column.definition.cssClass ? column.definition.cssClass.split(" ") : []).forEach(function(className) {
						cellEl.classList.add(className);
					});
					if (this.table.modExists("format") && this.config.formatCells !== false) value = this.table.modules.format.formatExportValue(cellWrapper, this.colVisProp);
					else switch (typeof value) {
						case "object":
							value = value !== null ? JSON.stringify(value) : "";
							break;
						case "undefined":
							value = "";
							break;
					}
					if (value instanceof Node) cellEl.appendChild(value);
					else cellEl.innerHTML = value;
					styleProps = [
						"padding-top",
						"padding-left",
						"padding-right",
						"padding-bottom",
						"border-top",
						"border-left",
						"border-right",
						"border-bottom",
						"color",
						"font-weight",
						"font-family",
						"font-size",
						"text-align"
					];
					if (column.isRowHeader) {
						cellStyle = styles.styleRowHeader;
						styleProps.push("background-color");
					} else cellStyle = styles.styleCells && styles.styleCells[index] ? styles.styleCells[index] : styles.firstCell;
					if (cellStyle) {
						this.mapElementStyles(cellStyle, cellEl, styleProps);
						if (column.definition.align) cellEl.style.textAlign = column.definition.align;
					}
					if (this.table.options.dataTree && this.config.dataTree !== false) {
						if (setup.treeElementField && setup.treeElementField == column.field || !setup.treeElementField && i == 0) {
							if (row.component._row.modules.dataTree.controlEl) cellEl.insertBefore(row.component._row.modules.dataTree.controlEl.cloneNode(true), cellEl.firstChild);
							if (row.component._row.modules.dataTree.branchEl) cellEl.insertBefore(row.component._row.modules.dataTree.branchEl.cloneNode(true), cellEl.firstChild);
						}
					}
					rowEl.appendChild(cellEl);
					if (cellWrapper.modules.format && cellWrapper.modules.format.renderedCallback) cellWrapper.modules.format.renderedCallback();
				}
			});
			if (setup.rowFormatter && row.type === "row" && this.config.formatCells !== false) {
				let formatComponent = Object.assign(row.component);
				formatComponent.getElement = function() {
					return rowEl;
				};
				setup.rowFormatter(row.component);
			}
			return rowEl;
		}
		generateHTMLTable(list) {
			var holder = document.createElement("div");
			holder.appendChild(this.generateTableElement(list));
			return holder.innerHTML;
		}
		getHtml(visible, style, config, colVisProp) {
			var list = this.generateExportList(config || this.table.options.htmlOutputConfig, style, visible, colVisProp || "htmlOutput");
			return this.generateHTMLTable(list);
		}
		mapElementStyles(from, to, props) {
			if (this.cloneTableStyle && from && to) {
				var lookup = {
					"background-color": "backgroundColor",
					"color": "fontColor",
					"width": "width",
					"font-weight": "fontWeight",
					"font-family": "fontFamily",
					"font-size": "fontSize",
					"text-align": "textAlign",
					"border-top": "borderTop",
					"border-left": "borderLeft",
					"border-right": "borderRight",
					"border-bottom": "borderBottom",
					"padding-top": "paddingTop",
					"padding-left": "paddingLeft",
					"padding-right": "paddingRight",
					"padding-bottom": "paddingBottom"
				};
				if (window.getComputedStyle) {
					var fromStyle = window.getComputedStyle(from);
					props.forEach(function(prop) {
						if (!to.style[lookup[prop]]) to.style[lookup[prop]] = fromStyle.getPropertyValue(prop);
					});
				}
			}
		}
	};
	var defaultFilters = {
		"=": function(filterVal, rowVal, rowData, filterParams) {
			return rowVal == filterVal ? true : false;
		},
		"<": function(filterVal, rowVal, rowData, filterParams) {
			return rowVal < filterVal ? true : false;
		},
		"<=": function(filterVal, rowVal, rowData, filterParams) {
			return rowVal <= filterVal ? true : false;
		},
		">": function(filterVal, rowVal, rowData, filterParams) {
			return rowVal > filterVal ? true : false;
		},
		">=": function(filterVal, rowVal, rowData, filterParams) {
			return rowVal >= filterVal ? true : false;
		},
		"!=": function(filterVal, rowVal, rowData, filterParams) {
			return rowVal != filterVal ? true : false;
		},
		"regex": function(filterVal, rowVal, rowData, filterParams) {
			if (typeof filterVal == "string") filterVal = new RegExp(filterVal);
			return filterVal.test(rowVal);
		},
		"like": function(filterVal, rowVal, rowData, filterParams) {
			if (filterVal === null || typeof filterVal === "undefined") return rowVal === filterVal ? true : false;
			else if (typeof rowVal !== "undefined" && rowVal !== null) return String(rowVal).toLowerCase().indexOf(filterVal.toLowerCase()) > -1;
			else return false;
		},
		"keywords": function(filterVal, rowVal, rowData, filterParams) {
			var keywords = filterVal.toLowerCase().split(typeof filterParams.separator === "undefined" ? " " : filterParams.separator), value = String(rowVal === null || typeof rowVal === "undefined" ? "" : rowVal).toLowerCase(), matches = [];
			keywords.forEach((keyword) => {
				if (value.includes(keyword)) matches.push(true);
			});
			return filterParams.matchAll ? matches.length === keywords.length : !!matches.length;
		},
		"starts": function(filterVal, rowVal, rowData, filterParams) {
			if (filterVal === null || typeof filterVal === "undefined") return rowVal === filterVal ? true : false;
			else if (typeof rowVal !== "undefined" && rowVal !== null) return String(rowVal).toLowerCase().startsWith(filterVal.toLowerCase());
			else return false;
		},
		"ends": function(filterVal, rowVal, rowData, filterParams) {
			if (filterVal === null || typeof filterVal === "undefined") return rowVal === filterVal ? true : false;
			else if (typeof rowVal !== "undefined" && rowVal !== null) return String(rowVal).toLowerCase().endsWith(filterVal.toLowerCase());
			else return false;
		},
		"in": function(filterVal, rowVal, rowData, filterParams) {
			if (Array.isArray(filterVal)) return filterVal.length ? filterVal.indexOf(rowVal) > -1 : true;
			else {
				console.warn("Filter Error - filter value is not an array:", filterVal);
				return false;
			}
		}
	};
	var Filter = class Filter extends Module {
		static moduleName = "filter";
		static filters = defaultFilters;
		constructor(table) {
			super(table);
			this.filterList = [];
			this.headerFilters = {};
			this.headerFilterColumns = [];
			this.prevHeaderFilterChangeCheck = "";
			this.prevHeaderFilterChangeCheck = "{}";
			this.changed = false;
			this.tableInitialized = false;
			this.registerTableOption("filterMode", "local");
			this.registerTableOption("initialFilter", false);
			this.registerTableOption("initialHeaderFilter", false);
			this.registerTableOption("headerFilterLiveFilterDelay", 300);
			this.registerTableOption("placeholderHeaderFilter", false);
			this.registerColumnOption("headerFilter");
			this.registerColumnOption("headerFilterPlaceholder");
			this.registerColumnOption("headerFilterParams");
			this.registerColumnOption("headerFilterEmptyCheck");
			this.registerColumnOption("headerFilterFunc");
			this.registerColumnOption("headerFilterFuncParams");
			this.registerColumnOption("headerFilterLiveFilter");
			this.registerTableFunction("searchRows", this.searchRows.bind(this));
			this.registerTableFunction("searchData", this.searchData.bind(this));
			this.registerTableFunction("setFilter", this.userSetFilter.bind(this));
			this.registerTableFunction("refreshFilter", this.userRefreshFilter.bind(this));
			this.registerTableFunction("addFilter", this.userAddFilter.bind(this));
			this.registerTableFunction("getFilters", this.getFilters.bind(this));
			this.registerTableFunction("setHeaderFilterFocus", this.userSetHeaderFilterFocus.bind(this));
			this.registerTableFunction("getHeaderFilterValue", this.userGetHeaderFilterValue.bind(this));
			this.registerTableFunction("setHeaderFilterValue", this.userSetHeaderFilterValue.bind(this));
			this.registerTableFunction("getHeaderFilters", this.getHeaderFilters.bind(this));
			this.registerTableFunction("removeFilter", this.userRemoveFilter.bind(this));
			this.registerTableFunction("clearFilter", this.userClearFilter.bind(this));
			this.registerTableFunction("clearHeaderFilter", this.userClearHeaderFilter.bind(this));
			this.registerComponentFunction("column", "headerFilterFocus", this.setHeaderFilterFocus.bind(this));
			this.registerComponentFunction("column", "reloadHeaderFilter", this.reloadHeaderFilter.bind(this));
			this.registerComponentFunction("column", "getHeaderFilterValue", this.getHeaderFilterValue.bind(this));
			this.registerComponentFunction("column", "setHeaderFilterValue", this.setHeaderFilterValue.bind(this));
		}
		initialize() {
			this.subscribe("column-init", this.initializeColumnHeaderFilter.bind(this));
			this.subscribe("column-width-fit-before", this.hideHeaderFilterElements.bind(this));
			this.subscribe("column-width-fit-after", this.showHeaderFilterElements.bind(this));
			this.subscribe("table-built", this.tableBuilt.bind(this));
			this.subscribe("placeholder", this.generatePlaceholder.bind(this));
			if (this.table.options.filterMode === "remote") this.subscribe("data-params", this.remoteFilterParams.bind(this));
			this.registerDataHandler(this.filter.bind(this), 10);
		}
		tableBuilt() {
			if (this.table.options.initialFilter) this.setFilter(this.table.options.initialFilter);
			if (this.table.options.initialHeaderFilter) this.table.options.initialHeaderFilter.forEach((item) => {
				var column = this.table.columnManager.findColumn(item.field);
				if (column) this.setHeaderFilterValue(column, item.value);
				else {
					console.warn("Column Filter Error - No matching column found:", item.field);
					return false;
				}
			});
			this.tableInitialized = true;
		}
		remoteFilterParams(data, config, silent, params) {
			params.filter = this.getFilters(true, true);
			return params;
		}
		generatePlaceholder(text) {
			if (this.table.options.placeholderHeaderFilter && Object.keys(this.headerFilters).length) return this.table.options.placeholderHeaderFilter;
		}
		userSetFilter(field, type, value, params) {
			this.setFilter(field, type, value, params);
			this.refreshFilter();
		}
		userRefreshFilter() {
			this.refreshFilter();
		}
		userAddFilter(field, type, value, params) {
			this.addFilter(field, type, value, params);
			this.refreshFilter();
		}
		userSetHeaderFilterFocus(field) {
			var column = this.table.columnManager.findColumn(field);
			if (column) this.setHeaderFilterFocus(column);
			else {
				console.warn("Column Filter Focus Error - No matching column found:", field);
				return false;
			}
		}
		userGetHeaderFilterValue(field) {
			var column = this.table.columnManager.findColumn(field);
			if (column) return this.getHeaderFilterValue(column);
			else console.warn("Column Filter Error - No matching column found:", field);
		}
		userSetHeaderFilterValue(field, value) {
			var column = this.table.columnManager.findColumn(field);
			if (column) this.setHeaderFilterValue(column, value);
			else {
				console.warn("Column Filter Error - No matching column found:", field);
				return false;
			}
		}
		userRemoveFilter(field, type, value) {
			this.removeFilter(field, type, value);
			this.refreshFilter();
		}
		userClearFilter(all) {
			this.clearFilter(all);
			this.refreshFilter();
		}
		userClearHeaderFilter() {
			this.clearHeaderFilter();
			this.refreshFilter();
		}
		searchRows(field, type, value) {
			return this.search("rows", field, type, value);
		}
		searchData(field, type, value) {
			return this.search("data", field, type, value);
		}
		initializeColumnHeaderFilter(column) {
			if (column.definition.headerFilter) this.initializeColumn(column);
		}
		initializeColumn(column, value) {
			var self = this, field = column.getField();
			function success(value) {
				var filterType = column.modules.filter.tagType == "input" && column.modules.filter.attrType == "text" || column.modules.filter.tagType == "textarea" ? "partial" : "match", type = "", filterChangeCheck = "", filterFunc;
				if (typeof column.modules.filter.prevSuccess === "undefined" || column.modules.filter.prevSuccess !== value) {
					column.modules.filter.prevSuccess = value;
					if (!column.modules.filter.emptyFunc(value)) {
						column.modules.filter.value = value;
						switch (typeof column.definition.headerFilterFunc) {
							case "string":
								if (Filter.filters[column.definition.headerFilterFunc]) {
									type = column.definition.headerFilterFunc;
									filterFunc = function(data) {
										var params = column.definition.headerFilterFuncParams || {};
										var fieldVal = column.getFieldValue(data);
										params = typeof params === "function" ? params(value, fieldVal, data) : params;
										return Filter.filters[column.definition.headerFilterFunc](value, fieldVal, data, params);
									};
								} else console.warn("Header Filter Error - Matching filter function not found: ", column.definition.headerFilterFunc);
								break;
							case "function":
								filterFunc = function(data) {
									var params = column.definition.headerFilterFuncParams || {};
									var fieldVal = column.getFieldValue(data);
									params = typeof params === "function" ? params(value, fieldVal, data) : params;
									return column.definition.headerFilterFunc(value, fieldVal, data, params);
								};
								type = filterFunc;
								break;
						}
						if (!filterFunc) switch (filterType) {
							case "partial":
								filterFunc = function(data) {
									var colVal = column.getFieldValue(data);
									if (typeof colVal !== "undefined" && colVal !== null) return String(colVal).toLowerCase().indexOf(String(value).toLowerCase()) > -1;
									else return false;
								};
								type = "like";
								break;
							default:
								filterFunc = function(data) {
									return column.getFieldValue(data) == value;
								};
								type = "=";
						}
						self.headerFilters[field] = {
							value,
							func: filterFunc,
							type
						};
					} else delete self.headerFilters[field];
					column.modules.filter.value = value;
					filterChangeCheck = JSON.stringify(self.headerFilters);
					if (self.prevHeaderFilterChangeCheck !== filterChangeCheck) {
						self.prevHeaderFilterChangeCheck = filterChangeCheck;
						self.trackChanges();
						self.refreshFilter();
					}
				}
				return true;
			}
			column.modules.filter = {
				success,
				attrType: false,
				tagType: false,
				emptyFunc: false
			};
			this.generateHeaderFilterElement(column);
		}
		generateHeaderFilterElement(column, initialValue, reinitialize) {
			var self = this, success = column.modules.filter.success, field = column.getField(), filterElement, editor, editorElement, cellWrapper, typingTimer, searchTrigger, params, onRenderedCallback;
			column.modules.filter.value = initialValue;
			function cancel() {}
			function onRendered(callback) {
				onRenderedCallback = callback;
			}
			if (column.modules.filter.headerElement && column.modules.filter.headerElement.parentNode) column.contentElement.removeChild(column.modules.filter.headerElement.parentNode);
			if (field) {
				column.modules.filter.emptyFunc = column.definition.headerFilterEmptyCheck || function(value) {
					return !value && value !== 0;
				};
				filterElement = document.createElement("div");
				filterElement.classList.add("tabulator-header-filter");
				switch (typeof column.definition.headerFilter) {
					case "string":
						if (self.table.modules.edit.editors[column.definition.headerFilter]) {
							editor = self.table.modules.edit.editors[column.definition.headerFilter];
							if ((column.definition.headerFilter === "tick" || column.definition.headerFilter === "tickCross") && !column.definition.headerFilterEmptyCheck) column.modules.filter.emptyFunc = function(value) {
								return value !== true && value !== false;
							};
						} else console.warn("Filter Error - Cannot build header filter, No such editor found: ", column.definition.editor);
						break;
					case "function":
						editor = column.definition.headerFilter;
						break;
					case "boolean":
						if (column.modules.edit && column.modules.edit.editor) editor = column.modules.edit.editor;
						else if (column.definition.formatter && self.table.modules.edit.editors[column.definition.formatter]) {
							editor = self.table.modules.edit.editors[column.definition.formatter];
							if ((column.definition.formatter === "tick" || column.definition.formatter === "tickCross") && !column.definition.headerFilterEmptyCheck) column.modules.filter.emptyFunc = function(value) {
								return value !== true && value !== false;
							};
						} else editor = self.table.modules.edit.editors["input"];
						break;
				}
				if (editor) {
					cellWrapper = {
						getValue: function() {
							return typeof initialValue !== "undefined" ? initialValue : "";
						},
						getField: function() {
							return column.definition.field;
						},
						getElement: function() {
							return filterElement;
						},
						getColumn: function() {
							return column.getComponent();
						},
						getTable: () => {
							return this.table;
						},
						getType: () => {
							return "header";
						},
						getRow: function() {
							return { normalizeHeight: function() {} };
						}
					};
					params = column.definition.headerFilterParams || {};
					params = typeof params === "function" ? params.call(self.table, cellWrapper) : params;
					editorElement = editor.call(this.table.modules.edit, cellWrapper, onRendered, success, cancel, params);
					if (!editorElement) {
						console.warn("Filter Error - Cannot add filter to " + field + " column, editor returned a value of false");
						return;
					}
					if (!(editorElement instanceof Node)) {
						console.warn("Filter Error - Cannot add filter to " + field + " column, editor should return an instance of Node, the editor returned:", editorElement);
						return;
					}
					self.langBind("headerFilters|columns|" + column.definition.field, function(value) {
						editorElement.setAttribute("placeholder", typeof value !== "undefined" && value ? value : column.definition.headerFilterPlaceholder || self.langText("headerFilters|default"));
					});
					editorElement.addEventListener("click", function(e) {
						e.stopPropagation();
						editorElement.focus();
					});
					editorElement.addEventListener("focus", (e) => {
						var left = this.table.columnManager.contentsElement.scrollLeft;
						if (left !== this.table.rowManager.element.scrollLeft) {
							this.table.rowManager.scrollHorizontal(left);
							this.table.columnManager.scrollHorizontal(left);
						}
					});
					typingTimer = false;
					searchTrigger = function(e) {
						if (typingTimer) clearTimeout(typingTimer);
						typingTimer = setTimeout(function() {
							success(editorElement.value);
						}, self.table.options.headerFilterLiveFilterDelay);
					};
					column.modules.filter.headerElement = editorElement;
					column.modules.filter.attrType = editorElement.hasAttribute("type") ? editorElement.getAttribute("type").toLowerCase() : "";
					column.modules.filter.tagType = editorElement.tagName.toLowerCase();
					if (column.definition.headerFilterLiveFilter !== false) {
						if (!(column.definition.headerFilter === "autocomplete" || column.definition.headerFilter === "tickCross" || (column.definition.editor === "autocomplete" || column.definition.editor === "tickCross") && column.definition.headerFilter === true)) {
							editorElement.addEventListener("keyup", searchTrigger);
							editorElement.addEventListener("search", searchTrigger);
							if (column.modules.filter.attrType == "number") editorElement.addEventListener("change", function(e) {
								success(editorElement.value);
							});
							if (column.modules.filter.attrType == "text" && this.table.browser !== "ie") editorElement.setAttribute("type", "search");
						}
						if (column.modules.filter.tagType == "input" || column.modules.filter.tagType == "select" || column.modules.filter.tagType == "textarea") editorElement.addEventListener("mousedown", function(e) {
							e.stopPropagation();
						});
					}
					filterElement.appendChild(editorElement);
					column.contentElement.appendChild(filterElement);
					if (!reinitialize) self.headerFilterColumns.push(column);
					if (onRenderedCallback) onRenderedCallback();
				}
			} else console.warn("Filter Error - Cannot add header filter, column has no field set:", column.definition.title);
		}
		hideHeaderFilterElements() {
			this.headerFilterColumns.forEach(function(column) {
				if (column.modules.filter && column.modules.filter.headerElement) column.modules.filter.headerElement.style.display = "none";
			});
		}
		showHeaderFilterElements() {
			this.headerFilterColumns.forEach(function(column) {
				if (column.modules.filter && column.modules.filter.headerElement) column.modules.filter.headerElement.style.display = "";
			});
		}
		setHeaderFilterFocus(column) {
			if (column.modules.filter && column.modules.filter.headerElement) column.modules.filter.headerElement.focus();
			else console.warn("Column Filter Focus Error - No header filter set on column:", column.getField());
		}
		getHeaderFilterValue(column) {
			if (column.modules.filter && column.modules.filter.headerElement) return column.modules.filter.value;
			else console.warn("Column Filter Error - No header filter set on column:", column.getField());
		}
		setHeaderFilterValue(column, value) {
			if (column) if (column.modules.filter && column.modules.filter.headerElement) {
				this.generateHeaderFilterElement(column, value, true);
				column.modules.filter.success(value);
			} else console.warn("Column Filter Error - No header filter set on column:", column.getField());
		}
		reloadHeaderFilter(column) {
			if (column) if (column.modules.filter && column.modules.filter.headerElement) this.generateHeaderFilterElement(column, column.modules.filter.value, true);
			else console.warn("Column Filter Error - No header filter set on column:", column.getField());
		}
		refreshFilter() {
			if (this.tableInitialized) if (this.table.options.filterMode === "remote") this.reloadData(null, false, false);
			else this.refreshData(true);
		}
		trackChanges() {
			this.changed = true;
			this.dispatch("filter-changed");
		}
		hasChanged() {
			var changed = this.changed;
			this.changed = false;
			return changed;
		}
		setFilter(field, type, value, params) {
			this.filterList = [];
			if (!Array.isArray(field)) field = [{
				field,
				type,
				value,
				params
			}];
			this.addFilter(field);
		}
		addFilter(field, type, value, params) {
			var changed = false;
			if (!Array.isArray(field)) field = [{
				field,
				type,
				value,
				params
			}];
			field.forEach((filter) => {
				filter = this.findFilter(filter);
				if (filter) {
					this.filterList.push(filter);
					changed = true;
				}
			});
			if (changed) this.trackChanges();
		}
		findFilter(filter) {
			var column;
			if (Array.isArray(filter)) return this.findSubFilters(filter);
			var filterFunc = false;
			if (typeof filter.field == "function") filterFunc = function(data) {
				return filter.field(data, filter.type || {});
			};
			else if (Filter.filters[filter.type]) {
				column = this.table.columnManager.getColumnByField(filter.field);
				if (column) filterFunc = function(data) {
					return Filter.filters[filter.type](filter.value, column.getFieldValue(data), data, filter.params || {});
				};
				else filterFunc = function(data) {
					return Filter.filters[filter.type](filter.value, data[filter.field], data, filter.params || {});
				};
			} else console.warn("Filter Error - No such filter type found, ignoring: ", filter.type);
			filter.func = filterFunc;
			return filter.func ? filter : false;
		}
		findSubFilters(filters) {
			var output = [];
			filters.forEach((filter) => {
				filter = this.findFilter(filter);
				if (filter) output.push(filter);
			});
			return output.length ? output : false;
		}
		getFilters(all, ajax) {
			var output = [];
			if (all) output = this.getHeaderFilters();
			if (ajax) output.forEach(function(item) {
				if (typeof item.type == "function") item.type = "function";
			});
			output = output.concat(this.filtersToArray(this.filterList, ajax));
			return output;
		}
		filtersToArray(filterList, ajax) {
			var output = [];
			filterList.forEach((filter) => {
				var item;
				if (Array.isArray(filter)) output.push(this.filtersToArray(filter, ajax));
				else {
					item = {
						field: filter.field,
						type: filter.type,
						value: filter.value
					};
					if (ajax) {
						if (typeof item.type == "function") item.type = "function";
					}
					output.push(item);
				}
			});
			return output;
		}
		getHeaderFilters() {
			var output = [];
			for (var key in this.headerFilters) output.push({
				field: key,
				type: this.headerFilters[key].type,
				value: this.headerFilters[key].value
			});
			return output;
		}
		removeFilter(field, type, value) {
			if (!Array.isArray(field)) field = [{
				field,
				type,
				value
			}];
			field.forEach((filter) => {
				var index = -1;
				if (typeof filter.field == "object") index = this.filterList.findIndex((element) => {
					return filter === element;
				});
				else index = this.filterList.findIndex((element) => {
					return filter.field === element.field && filter.type === element.type && filter.value === element.value;
				});
				if (index > -1) this.filterList.splice(index, 1);
				else console.warn("Filter Error - No matching filter type found, ignoring: ", filter.type);
			});
			this.trackChanges();
		}
		clearFilter(all) {
			this.filterList = [];
			if (all) this.clearHeaderFilter();
			this.trackChanges();
		}
		clearHeaderFilter() {
			this.headerFilters = {};
			this.prevHeaderFilterChangeCheck = "{}";
			this.headerFilterColumns.forEach((column) => {
				if (typeof column.modules.filter.value !== "undefined") delete column.modules.filter.value;
				column.modules.filter.prevSuccess = void 0;
				this.reloadHeaderFilter(column);
			});
			this.trackChanges();
		}
		search(searchType, field, type, value) {
			var activeRows = [], filterList = [];
			if (!Array.isArray(field)) field = [{
				field,
				type,
				value
			}];
			field.forEach((filter) => {
				filter = this.findFilter(filter);
				if (filter) filterList.push(filter);
			});
			this.table.rowManager.rows.forEach((row) => {
				var match = true;
				filterList.forEach((filter) => {
					if (!this.filterRecurse(filter, row.getData())) match = false;
				});
				if (match) activeRows.push(searchType === "data" ? row.getData("data") : row.getComponent());
			});
			return activeRows;
		}
		filter(rowList, filters) {
			var activeRows = [], activeRowComponents = [];
			if (this.subscribedExternal("dataFiltering")) this.dispatchExternal("dataFiltering", this.getFilters(true));
			if (this.table.options.filterMode !== "remote" && (this.filterList.length || Object.keys(this.headerFilters).length)) rowList.forEach((row) => {
				if (this.filterRow(row)) activeRows.push(row);
			});
			else activeRows = rowList.slice(0);
			if (this.subscribedExternal("dataFiltered")) {
				activeRows.forEach((row) => {
					activeRowComponents.push(row.getComponent());
				});
				this.dispatchExternal("dataFiltered", this.getFilters(true), activeRowComponents);
			}
			return activeRows;
		}
		filterRow(row, filters) {
			var match = true, data = row.getData();
			this.filterList.forEach((filter) => {
				if (!this.filterRecurse(filter, data)) match = false;
			});
			for (var field in this.headerFilters) if (!this.headerFilters[field].func(data)) match = false;
			return match;
		}
		filterRecurse(filter, data) {
			var match = false;
			if (Array.isArray(filter)) filter.forEach((subFilter) => {
				if (this.filterRecurse(subFilter, data)) match = true;
			});
			else match = filter.func(data);
			return match;
		}
	};
	function plaintext(cell, formatterParams, onRendered) {
		return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
	}
	function html(cell, formatterParams, onRendered) {
		return cell.getValue();
	}
	function textarea(cell, formatterParams, onRendered) {
		cell.getElement().style.whiteSpace = "pre-wrap";
		return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
	}
	function money(cell, formatterParams, onRendered) {
		var floatVal = parseFloat(cell.getValue()), sign = "", number, integer, decimal, rgx, value;
		var decimalSym = formatterParams.decimal || ".";
		var thousandSym = formatterParams.thousand || ",";
		var negativeSign = formatterParams.negativeSign || "-";
		var symbol = formatterParams.symbol || "";
		var after = !!formatterParams.symbolAfter;
		var precision = typeof formatterParams.precision !== "undefined" ? formatterParams.precision : 2;
		if (isNaN(floatVal)) return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
		if (floatVal < 0) {
			floatVal = Math.abs(floatVal);
			sign = negativeSign;
		}
		number = precision !== false ? floatVal.toFixed(precision) : floatVal;
		number = String(number).split(".");
		integer = number[0];
		decimal = number.length > 1 ? decimalSym + number[1] : "";
		if (formatterParams.thousand !== false) {
			rgx = /(\d+)(\d{3})/;
			while (rgx.test(integer)) integer = integer.replace(rgx, "$1" + thousandSym + "$2");
		}
		value = integer + decimal;
		if (sign === true) {
			value = "(" + value + ")";
			return after ? value + symbol : symbol + value;
		} else return after ? sign + value + symbol : sign + symbol + value;
	}
	function link(cell, formatterParams, onRendered) {
		var value = cell.getValue(), urlPrefix = formatterParams.urlPrefix || "", download = formatterParams.download, label = value, el = document.createElement("a"), data;
		function labelTraverse(path, data) {
			var value = data[path.shift()];
			if (path.length && typeof value === "object") return labelTraverse(path, value);
			return value;
		}
		if (formatterParams.labelField) {
			data = cell.getData();
			label = labelTraverse(formatterParams.labelField.split(this.table.options.nestedFieldSeparator), data);
		}
		if (formatterParams.label) switch (typeof formatterParams.label) {
			case "string":
				label = formatterParams.label;
				break;
			case "function":
				label = formatterParams.label(cell);
				break;
		}
		if (label) {
			if (formatterParams.urlField) {
				data = cell.getData();
				value = Helpers.retrieveNestedData(this.table.options.nestedFieldSeparator, formatterParams.urlField, data);
			}
			if (formatterParams.url) switch (typeof formatterParams.url) {
				case "string":
					value = formatterParams.url;
					break;
				case "function":
					value = formatterParams.url(cell);
					break;
			}
			el.setAttribute("href", urlPrefix + value);
			if (formatterParams.target) el.setAttribute("target", formatterParams.target);
			if (formatterParams.download) {
				if (typeof download == "function") download = download(cell);
				else download = download === true ? "" : download;
				el.setAttribute("download", download);
			}
			el.innerHTML = this.emptyToSpace(this.sanitizeHTML(label));
			return el;
		} else return "&nbsp;";
	}
	function image(cell, formatterParams, onRendered) {
		var el = document.createElement("img"), src = cell.getValue();
		if (formatterParams.urlPrefix) src = formatterParams.urlPrefix + cell.getValue();
		if (formatterParams.urlSuffix) src = src + formatterParams.urlSuffix;
		el.setAttribute("src", src);
		switch (typeof formatterParams.height) {
			case "number":
				el.style.height = formatterParams.height + "px";
				break;
			case "string":
				el.style.height = formatterParams.height;
				break;
		}
		switch (typeof formatterParams.width) {
			case "number":
				el.style.width = formatterParams.width + "px";
				break;
			case "string":
				el.style.width = formatterParams.width;
				break;
		}
		el.addEventListener("load", function() {
			cell.getRow().normalizeHeight();
		});
		return el;
	}
	function tickCross(cell, formatterParams, onRendered) {
		var value = cell.getValue(), element = cell.getElement(), empty = formatterParams.allowEmpty, truthy = formatterParams.allowTruthy, trueValueSet = Object.keys(formatterParams).includes("trueValue"), tick = typeof formatterParams.tickElement !== "undefined" ? formatterParams.tickElement : "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#2DC214\" clip-rule=\"evenodd\" d=\"M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34  c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351  l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07  l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z\" fill-rule=\"evenodd\"/></svg>", cross = typeof formatterParams.crossElement !== "undefined" ? formatterParams.crossElement : "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\"  viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#CE1515\" d=\"M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272  c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0  l-6.276,6.267c-0.313,0.313-0.828,0.313-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269  c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73  L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z\"/></svg>";
		if (trueValueSet && value === formatterParams.trueValue || !trueValueSet && (truthy && value || value === true || value === "true" || value === "True" || value === 1 || value === "1")) {
			element.setAttribute("aria-checked", true);
			return tick || "";
		} else if (empty && (value === "null" || value === "" || value === null || typeof value === "undefined")) {
			element.setAttribute("aria-checked", "mixed");
			return "";
		} else {
			element.setAttribute("aria-checked", false);
			return cross || "";
		}
	}
	function datetime$1(cell, formatterParams, onRendered) {
		var DT = this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime");
		var inputFormat = formatterParams.inputFormat || "yyyy-MM-dd HH:mm:ss";
		var outputFormat = formatterParams.outputFormat || "dd/MM/yyyy HH:mm:ss";
		var invalid = typeof formatterParams.invalidPlaceholder !== "undefined" ? formatterParams.invalidPlaceholder : "";
		var value = cell.getValue();
		if (typeof DT != "undefined") {
			var newDatetime;
			if (DT.isDateTime(value)) newDatetime = value;
			else if (inputFormat === "iso") newDatetime = DT.fromISO(String(value));
			else newDatetime = DT.fromFormat(String(value), inputFormat);
			if (newDatetime.isValid) {
				if (formatterParams.timezone) newDatetime = newDatetime.setZone(formatterParams.timezone);
				return newDatetime.toFormat(outputFormat);
			} else if (invalid === true || !value) return value;
			else if (typeof invalid === "function") return invalid(value);
			else return invalid;
		} else console.error("Format Error - 'datetime' formatter is dependant on luxon.js");
	}
	function datetimediff(cell, formatterParams, onRendered) {
		var DT = this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime");
		var inputFormat = formatterParams.inputFormat || "yyyy-MM-dd HH:mm:ss";
		var invalid = typeof formatterParams.invalidPlaceholder !== "undefined" ? formatterParams.invalidPlaceholder : "";
		var suffix = typeof formatterParams.suffix !== "undefined" ? formatterParams.suffix : false;
		var unit = typeof formatterParams.unit !== "undefined" ? formatterParams.unit : "days";
		var humanize = typeof formatterParams.humanize !== "undefined" ? formatterParams.humanize : false;
		var date = typeof formatterParams.date !== "undefined" ? formatterParams.date : DT.now();
		var value = cell.getValue();
		if (typeof DT != "undefined") {
			var newDatetime;
			if (DT.isDateTime(value)) newDatetime = value;
			else if (inputFormat === "iso") newDatetime = DT.fromISO(String(value));
			else newDatetime = DT.fromFormat(String(value), inputFormat);
			if (newDatetime.isValid) if (humanize) return newDatetime.diff(date, unit).toHuman() + (suffix ? " " + suffix : "");
			else return parseInt(newDatetime.diff(date, unit)[unit]) + (suffix ? " " + suffix : "");
			else if (invalid === true) return value;
			else if (typeof invalid === "function") return invalid(value);
			else return invalid;
		} else console.error("Format Error - 'datetimediff' formatter is dependant on luxon.js");
	}
	function lookup(cell, formatterParams, onRendered) {
		var value = cell.getValue();
		if (typeof formatterParams[value] === "undefined") {
			console.warn("Missing display value for " + value);
			return value;
		}
		return formatterParams[value];
	}
	function star(cell, formatterParams, onRendered) {
		var value = cell.getValue(), element = cell.getElement(), maxStars = formatterParams && formatterParams.stars ? formatterParams.stars : 5, stars = document.createElement("span"), star = document.createElementNS("http://www.w3.org/2000/svg", "svg"), starActive = "<polygon fill=\"#FFEA00\" stroke=\"#C1AB60\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>", starInactive = "<polygon fill=\"#D2D2D2\" stroke=\"#686868\" stroke-width=\"37.6152\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" points=\"259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 \"/>";
		stars.style.verticalAlign = "middle";
		star.setAttribute("width", "14");
		star.setAttribute("height", "14");
		star.setAttribute("viewBox", "0 0 512 512");
		star.setAttribute("xml:space", "preserve");
		star.style.padding = "0 1px";
		value = value && !isNaN(value) ? parseInt(value) : 0;
		value = Math.max(0, Math.min(value, maxStars));
		for (var i = 1; i <= maxStars; i++) {
			var nextStar = star.cloneNode(true);
			nextStar.innerHTML = i <= value ? starActive : starInactive;
			stars.appendChild(nextStar);
		}
		element.style.whiteSpace = "nowrap";
		element.style.overflow = "hidden";
		element.style.textOverflow = "ellipsis";
		element.setAttribute("aria-label", value);
		return stars;
	}
	function traffic(cell, formatterParams, onRendered) {
		var value = this.sanitizeHTML(cell.getValue()) || 0, el = document.createElement("span"), max = formatterParams && formatterParams.max ? formatterParams.max : 100, min = formatterParams && formatterParams.min ? formatterParams.min : 0, colors = formatterParams && typeof formatterParams.color !== "undefined" ? formatterParams.color : [
			"red",
			"orange",
			"green"
		], color = "#666666", percent, percentValue;
		if (isNaN(value) || typeof cell.getValue() === "undefined") return;
		el.classList.add("tabulator-traffic-light");
		percentValue = parseFloat(value) <= max ? parseFloat(value) : max;
		percentValue = parseFloat(percentValue) >= min ? parseFloat(percentValue) : min;
		percent = (max - min) / 100;
		percentValue = Math.round((percentValue - min) / percent);
		switch (typeof colors) {
			case "string":
				color = colors;
				break;
			case "function":
				color = colors(value);
				break;
			case "object": if (Array.isArray(colors)) {
				var unit = 100 / colors.length;
				var index = Math.floor(percentValue / unit);
				index = Math.min(index, colors.length - 1);
				index = Math.max(index, 0);
				color = colors[index];
				break;
			}
		}
		el.style.backgroundColor = color;
		return el;
	}
	function progress(cell, formatterParams = {}, onRendered) {
		var value = this.sanitizeHTML(cell.getValue()) || 0, element = cell.getElement(), max = formatterParams.max ? formatterParams.max : 100, min = formatterParams.min ? formatterParams.min : 0, legendAlign = formatterParams.legendAlign ? formatterParams.legendAlign : "center", percent, percentValue = parseFloat(value) <= max ? parseFloat(value) : max, color, legend, legendColor;
		percentValue = parseFloat(percentValue) >= min ? parseFloat(percentValue) : min;
		percent = (max - min) / 100;
		percentValue = Math.round((percentValue - min) / percent);
		switch (typeof formatterParams.color) {
			case "string":
				color = formatterParams.color;
				break;
			case "function":
				color = formatterParams.color(value);
				break;
			case "object": if (Array.isArray(formatterParams.color)) {
				let unit = 100 / formatterParams.color.length;
				let index = Math.floor(percentValue / unit);
				index = Math.min(index, formatterParams.color.length - 1);
				index = Math.max(index, 0);
				color = formatterParams.color[index];
				break;
			}
			default: color = "#2DC214";
		}
		switch (typeof formatterParams.legend) {
			case "string":
				legend = formatterParams.legend;
				break;
			case "function":
				legend = formatterParams.legend(value);
				break;
			case "boolean":
				legend = value;
				break;
			default: legend = false;
		}
		switch (typeof formatterParams.legendColor) {
			case "string":
				legendColor = formatterParams.legendColor;
				break;
			case "function":
				legendColor = formatterParams.legendColor(value);
				break;
			case "object":
				if (Array.isArray(formatterParams.legendColor)) {
					let unit = 100 / formatterParams.legendColor.length;
					let index = Math.floor(percentValue / unit);
					index = Math.min(index, formatterParams.legendColor.length - 1);
					index = Math.max(index, 0);
					legendColor = formatterParams.legendColor[index];
				}
				break;
			default: legendColor = "#000";
		}
		element.style.minWidth = "30px";
		element.style.position = "relative";
		element.setAttribute("aria-label", percentValue);
		var barEl = document.createElement("div");
		barEl.style.display = "inline-block";
		barEl.style.width = percentValue + "%";
		barEl.style.backgroundColor = color;
		barEl.style.height = "100%";
		barEl.setAttribute("data-max", max);
		barEl.setAttribute("data-min", min);
		var barContainer = document.createElement("div");
		barContainer.style.position = "relative";
		barContainer.style.width = "100%";
		barContainer.style.height = "100%";
		if (legend) {
			var legendEl = document.createElement("div");
			legendEl.style.position = "absolute";
			legendEl.style.top = 0;
			legendEl.style.left = 0;
			legendEl.style.textAlign = legendAlign;
			legendEl.style.width = "100%";
			legendEl.style.color = legendColor;
			legendEl.innerHTML = legend;
		}
		onRendered(function() {
			if (!(cell instanceof CellComponent)) {
				var holderEl = document.createElement("div");
				holderEl.style.position = "absolute";
				holderEl.style.top = "4px";
				holderEl.style.bottom = "4px";
				holderEl.style.left = "4px";
				holderEl.style.right = "4px";
				element.appendChild(holderEl);
				element = holderEl;
			}
			element.appendChild(barContainer);
			barContainer.appendChild(barEl);
			if (legend) barContainer.appendChild(legendEl);
		});
		return "";
	}
	function color(cell, formatterParams, onRendered) {
		cell.getElement().style.backgroundColor = this.sanitizeHTML(cell.getValue());
		return "";
	}
	function buttonTick(cell, formatterParams, onRendered) {
		return "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#2DC214\" clip-rule=\"evenodd\" d=\"M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34  c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351  l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07  l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z\" fill-rule=\"evenodd\"/></svg>";
	}
	function buttonCross(cell, formatterParams, onRendered) {
		return "<svg enable-background=\"new 0 0 24 24\" height=\"14\" width=\"14\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" ><path fill=\"#CE1515\" d=\"M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272  c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0  l-6.276,6.267c-0.313,0.313-0.828,0.313-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269  c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73  L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z\"/></svg>";
	}
	function toggle(cell, formatterParams, onRendered) {
		var value = cell.getValue(), size = formatterParams.size || 15, sizePx = size + "px", containEl, switchEl, onValue = formatterParams.hasOwnProperty("onValue") ? formatterParams.onValue : true, offValue = formatterParams.hasOwnProperty("offValue") ? formatterParams.offValue : false, state = formatterParams.onTruthy ? value : value === onValue;
		containEl = document.createElement("div");
		containEl.classList.add("tabulator-toggle");
		if (state) {
			containEl.classList.add("tabulator-toggle-on");
			containEl.style.flexDirection = "row-reverse";
			if (formatterParams.onColor) containEl.style.background = formatterParams.onColor;
		} else if (formatterParams.offColor) containEl.style.background = formatterParams.offColor;
		containEl.style.width = 2.5 * size + "px";
		containEl.style.borderRadius = sizePx;
		if (formatterParams.clickable) containEl.addEventListener("click", (e) => {
			cell.setValue(state ? offValue : onValue);
		});
		switchEl = document.createElement("div");
		switchEl.classList.add("tabulator-toggle-switch");
		switchEl.style.height = sizePx;
		switchEl.style.width = sizePx;
		switchEl.style.borderRadius = sizePx;
		containEl.appendChild(switchEl);
		return containEl;
	}
	function rownum(cell, formatterParams, onRendered) {
		var content = document.createElement("span");
		var row = cell.getRow();
		var table = cell.getTable();
		row.watchPosition((position) => {
			if (formatterParams.relativeToPage) position += table.modules.page.getPageSize() * (table.modules.page.getPage() - 1);
			content.innerText = position;
		});
		return content;
	}
	function handle(cell, formatterParams, onRendered) {
		cell.getElement().classList.add("tabulator-row-handle");
		return "<div class='tabulator-row-handle-box'><div class='tabulator-row-handle-bar'></div><div class='tabulator-row-handle-bar'></div><div class='tabulator-row-handle-bar'></div></div>";
	}
	function adaptable(cell, params, onRendered) {
		var lookup, formatterFunc, formatterParams;
		function defaultLookup(cell) {
			var value = cell.getValue(), formatter = "plaintext";
			switch (typeof value) {
				case "boolean":
					formatter = "tickCross";
					break;
				case "string":
					if (value.includes("\n")) formatter = "textarea";
					break;
			}
			return formatter;
		}
		lookup = params.formatterLookup ? params.formatterLookup(cell) : defaultLookup(cell);
		if (params.paramsLookup) formatterParams = typeof params.paramsLookup === "function" ? params.paramsLookup(lookup, cell) : params.paramsLookup[lookup];
		formatterFunc = this.table.modules.format.lookupFormatter(lookup);
		return formatterFunc.call(this, cell, formatterParams || {}, onRendered);
	}
	function array$2(cell, formatterParams, onRendered) {
		var delimiter = formatterParams.delimiter || ",", value = cell.getValue(), table = this.table, valueMap;
		if (formatterParams.valueMap) if (typeof formatterParams.valueMap === "string") valueMap = function(value) {
			return value.map((item) => {
				return Helpers.retrieveNestedData(table.options.nestedFieldSeparator, formatterParams.valueMap, item);
			});
		};
		else valueMap = formatterParams.valueMap;
		if (Array.isArray(value)) {
			if (valueMap) value = valueMap(value);
			return value.join(delimiter);
		} else return value;
	}
	function json$1(cell, formatterParams, onRendered) {
		var indent = formatterParams.indent || "	", multiline = typeof formatterParams.multiline === "undefined" ? true : formatterParams.multiline, replacer = formatterParams.replacer || null, value = cell.getValue();
		if (multiline) cell.getElement().style.whiteSpace = "pre-wrap";
		return JSON.stringify(value, replacer, indent);
	}
	var defaultFormatters = {
		plaintext,
		html,
		textarea,
		money,
		link,
		image,
		tickCross,
		datetime: datetime$1,
		datetimediff,
		lookup,
		star,
		traffic,
		progress,
		color,
		buttonTick,
		buttonCross,
		toggle,
		rownum,
		handle,
		adaptable,
		array: array$2,
		json: json$1
	};
	var Format = class Format extends Module {
		static moduleName = "format";
		static formatters = defaultFormatters;
		constructor(table) {
			super(table);
			this.registerColumnOption("formatter");
			this.registerColumnOption("formatterParams");
			this.registerColumnOption("formatterPrint");
			this.registerColumnOption("formatterPrintParams");
			this.registerColumnOption("formatterClipboard");
			this.registerColumnOption("formatterClipboardParams");
			this.registerColumnOption("formatterHtmlOutput");
			this.registerColumnOption("formatterHtmlOutputParams");
			this.registerColumnOption("titleFormatter");
			this.registerColumnOption("titleFormatterParams");
		}
		initialize() {
			this.subscribe("cell-format", this.formatValue.bind(this));
			this.subscribe("cell-rendered", this.cellRendered.bind(this));
			this.subscribe("column-layout", this.initializeColumn.bind(this));
			this.subscribe("column-format", this.formatHeader.bind(this));
		}
		initializeColumn(column) {
			column.modules.format = this.lookupTypeFormatter(column, "");
			if (typeof column.definition.formatterPrint !== "undefined") column.modules.format.print = this.lookupTypeFormatter(column, "Print");
			if (typeof column.definition.formatterClipboard !== "undefined") column.modules.format.clipboard = this.lookupTypeFormatter(column, "Clipboard");
			if (typeof column.definition.formatterHtmlOutput !== "undefined") column.modules.format.htmlOutput = this.lookupTypeFormatter(column, "HtmlOutput");
		}
		lookupTypeFormatter(column, type) {
			var config = { params: column.definition["formatter" + type + "Params"] || {} }, formatter = column.definition["formatter" + type];
			config.formatter = this.lookupFormatter(formatter);
			return config;
		}
		lookupFormatter(formatter) {
			var formatterFunc;
			switch (typeof formatter) {
				case "string":
					if (Format.formatters[formatter]) formatterFunc = Format.formatters[formatter];
					else {
						console.warn("Formatter Error - No such formatter found: ", formatter);
						formatterFunc = Format.formatters.plaintext;
					}
					break;
				case "function":
					formatterFunc = formatter;
					break;
				default:
					formatterFunc = Format.formatters.plaintext;
					break;
			}
			return formatterFunc;
		}
		cellRendered(cell) {
			if (cell.modules.format && cell.modules.format.renderedCallback && !cell.modules.format.rendered) {
				cell.modules.format.renderedCallback();
				cell.modules.format.rendered = true;
			}
		}
		formatHeader(column, title, el) {
			var formatter, params, onRendered, mockCell;
			if (column.definition.titleFormatter) {
				formatter = this.lookupFormatter(column.definition.titleFormatter);
				onRendered = (callback) => {
					column.titleFormatterRendered = callback;
				};
				mockCell = {
					getValue: function() {
						return title;
					},
					getElement: function() {
						return el;
					},
					getType: function() {
						return "header";
					},
					getColumn: function() {
						return column.getComponent();
					},
					getTable: () => {
						return this.table;
					}
				};
				params = column.definition.titleFormatterParams || {};
				params = typeof params === "function" ? params() : params;
				return formatter.call(this, mockCell, params, onRendered);
			} else return title;
		}
		formatValue(cell) {
			var component = cell.getComponent(), params = typeof cell.column.modules.format.params === "function" ? cell.column.modules.format.params(component) : cell.column.modules.format.params;
			function onRendered(callback) {
				if (!cell.modules.format) cell.modules.format = {};
				cell.modules.format.renderedCallback = callback;
				cell.modules.format.rendered = false;
			}
			return cell.column.modules.format.formatter.call(this, component, params, onRendered);
		}
		formatExportValue(cell, type) {
			var formatter = cell.column.modules.format[type], params;
			if (formatter) {
				params = typeof formatter.params === "function" ? formatter.params(cell.getComponent()) : formatter.params;
				function onRendered(callback) {
					if (!cell.modules.format) cell.modules.format = {};
					cell.modules.format.renderedCallback = callback;
					cell.modules.format.rendered = false;
				}
				return formatter.formatter.call(this, cell.getComponent(), params, onRendered);
			} else return this.formatValue(cell);
		}
		sanitizeHTML(value) {
			if (value) {
				var entityMap = {
					"&": "&amp;",
					"<": "&lt;",
					">": "&gt;",
					"\"": "&quot;",
					"'": "&#39;",
					"/": "&#x2F;",
					"`": "&#x60;",
					"=": "&#x3D;"
				};
				return String(value).replace(/[&<>"'`=/]/g, function(s) {
					return entityMap[s];
				});
			} else return value;
		}
		emptyToSpace(value) {
			return value === null || typeof value === "undefined" || value === "" ? "&nbsp;" : value;
		}
	};
	var FrozenColumns = class extends Module {
		static moduleName = "frozenColumns";
		constructor(table) {
			super(table);
			this.leftColumns = [];
			this.rightColumns = [];
			this.initializationMode = "left";
			this.active = false;
			this.blocked = true;
			this.registerColumnOption("frozen");
		}
		reset() {
			this.initializationMode = "left";
			this.leftColumns = [];
			this.rightColumns = [];
			this.active = false;
		}
		initialize() {
			this.subscribe("cell-layout", this.layoutCell.bind(this));
			this.subscribe("column-init", this.initializeColumn.bind(this));
			this.subscribe("column-width", this.layout.bind(this));
			this.subscribe("row-layout-after", this.layoutRow.bind(this));
			this.subscribe("table-layout", this.layout.bind(this));
			this.subscribe("columns-loading", this.reset.bind(this));
			this.subscribe("column-add", this.reinitializeColumns.bind(this));
			this.subscribe("column-deleted", this.reinitializeColumns.bind(this));
			this.subscribe("column-hide", this.reinitializeColumns.bind(this));
			this.subscribe("column-show", this.reinitializeColumns.bind(this));
			this.subscribe("columns-loaded", this.reinitializeColumns.bind(this));
			this.subscribe("table-redraw", this.layout.bind(this));
			this.subscribe("layout-refreshing", this.blockLayout.bind(this));
			this.subscribe("layout-refreshed", this.unblockLayout.bind(this));
			this.subscribe("scrollbar-vertical", this.adjustForScrollbar.bind(this));
		}
		blockLayout() {
			this.blocked = true;
		}
		unblockLayout() {
			this.blocked = false;
		}
		layoutCell(cell) {
			this.layoutElement(cell.element, cell.column);
		}
		reinitializeColumns() {
			this.reset();
			this.table.columnManager.columnsByIndex.forEach((column) => {
				this.initializeColumn(column);
			});
			this.layout();
		}
		initializeColumn(column) {
			var config = {
				margin: 0,
				edge: false
			};
			if (!column.isGroup) if (this.frozenCheck(column)) {
				config.position = this.initializationMode;
				if (this.initializationMode == "left") this.leftColumns.push(column);
				else this.rightColumns.unshift(column);
				this.active = true;
				column.modules.frozen = config;
			} else this.initializationMode = "right";
		}
		frozenCheck(column) {
			if (column.parent.isGroup && column.definition.frozen) console.warn("Frozen Column Error - Parent column group must be frozen, not individual columns or sub column groups");
			if (column.parent.isGroup) return this.frozenCheck(column.parent);
			else return column.definition.frozen;
		}
		layoutCalcRows() {
			if (this.table.modExists("columnCalcs")) {
				if (this.table.modules.columnCalcs.topInitialized && this.table.modules.columnCalcs.topRow) this.layoutRow(this.table.modules.columnCalcs.topRow);
				if (this.table.modules.columnCalcs.botInitialized && this.table.modules.columnCalcs.botRow) this.layoutRow(this.table.modules.columnCalcs.botRow);
				if (this.table.modExists("groupRows")) this.layoutGroupCalcs(this.table.modules.groupRows.getGroups());
			}
		}
		layoutGroupCalcs(groups) {
			groups.forEach((group) => {
				if (group.calcs.top) this.layoutRow(group.calcs.top);
				if (group.calcs.bottom) this.layoutRow(group.calcs.bottom);
				if (group.groupList && group.groupList.length) this.layoutGroupCalcs(group.groupList);
			});
		}
		layoutColumnPosition(allCells) {
			var leftParents = [];
			var leftMargin = 0;
			var rightMargin = 0;
			this.leftColumns.forEach((column, i) => {
				column.modules.frozen.marginValue = leftMargin;
				column.modules.frozen.margin = column.modules.frozen.marginValue + "px";
				if (column.visible) leftMargin += column.getWidth();
				if (i == this.leftColumns.length - 1) column.modules.frozen.edge = true;
				else column.modules.frozen.edge = false;
				if (column.parent.isGroup) {
					var parentEl = this.getColGroupParentElement(column);
					if (!leftParents.includes(parentEl)) {
						this.layoutElement(parentEl, column);
						leftParents.push(parentEl);
					}
					parentEl.classList.toggle("tabulator-frozen-left", column.modules.frozen.edge && column.modules.frozen.position === "left");
					parentEl.classList.toggle("tabulator-frozen-right", column.modules.frozen.edge && column.modules.frozen.position === "right");
				} else this.layoutElement(column.getElement(), column);
				if (allCells) column.cells.forEach((cell) => {
					this.layoutElement(cell.getElement(true), column);
				});
			});
			this.rightColumns.forEach((column, i) => {
				column.modules.frozen.marginValue = rightMargin;
				column.modules.frozen.margin = column.modules.frozen.marginValue + "px";
				if (column.visible) rightMargin += column.getWidth();
				if (i == this.rightColumns.length - 1) column.modules.frozen.edge = true;
				else column.modules.frozen.edge = false;
				if (column.parent.isGroup) this.layoutElement(this.getColGroupParentElement(column), column);
				else this.layoutElement(column.getElement(), column);
				if (allCells) column.cells.forEach((cell) => {
					this.layoutElement(cell.getElement(true), column);
				});
			});
		}
		getColGroupParentElement(column) {
			return column.parent.isGroup ? this.getColGroupParentElement(column.parent) : column.getElement();
		}
		layout() {
			if (this.active && !this.blocked) {
				this.layoutColumnPosition();
				this.reinitializeRows();
				this.layoutCalcRows();
			}
		}
		reinitializeRows() {
			var visibleRows = this.table.rowManager.getVisibleRows(true);
			this.table.rowManager.getRows().filter((row) => !visibleRows.includes(row)).forEach((row) => {
				row.deinitialize();
			});
			visibleRows.forEach((row) => {
				if (row.type === "row") this.layoutRow(row);
			});
		}
		layoutRow(row) {
			if (this.table.options.layout === "fitDataFill" && this.rightColumns.length) this.table.rowManager.getTableElement().style.minWidth = "calc(100% - " + this.rightMargin + ")";
			this.leftColumns.forEach((column) => {
				var cell = row.getCell(column);
				if (cell) this.layoutElement(cell.getElement(true), column);
			});
			this.rightColumns.forEach((column) => {
				var cell = row.getCell(column);
				if (cell) this.layoutElement(cell.getElement(true), column);
			});
		}
		layoutElement(element, column) {
			var position;
			if (column.modules.frozen && element) {
				element.style.position = "sticky";
				if (this.table.rtl) position = column.modules.frozen.position === "left" ? "right" : "left";
				else position = column.modules.frozen.position;
				element.style[position] = column.modules.frozen.margin;
				element.classList.add("tabulator-frozen");
				element.classList.toggle("tabulator-frozen-left", column.modules.frozen.edge && column.modules.frozen.position === "left");
				element.classList.toggle("tabulator-frozen-right", column.modules.frozen.edge && column.modules.frozen.position === "right");
			}
		}
		adjustForScrollbar(width) {
			if (this.rightColumns.length) this.table.columnManager.getContentsElement().style.width = "calc(100% - " + width + "px)";
		}
		getFrozenColumns() {
			return this.leftColumns.concat(this.rightColumns);
		}
		_calcSpace(columns, index) {
			var width = 0;
			for (let i = 0; i < index; i++) if (columns[i].visible) width += columns[i].getWidth();
			return width;
		}
	};
	var FrozenRows = class extends Module {
		static moduleName = "frozenRows";
		constructor(table) {
			super(table);
			this.topElement = document.createElement("div");
			this.rows = [];
			this.registerComponentFunction("row", "freeze", this.freezeRow.bind(this));
			this.registerComponentFunction("row", "unfreeze", this.unfreezeRow.bind(this));
			this.registerComponentFunction("row", "isFrozen", this.isRowFrozen.bind(this));
			this.registerTableOption("frozenRowsField", "id");
			this.registerTableOption("frozenRows", false);
		}
		initialize() {
			var fragment = document.createDocumentFragment();
			this.rows = [];
			this.topElement.classList.add("tabulator-frozen-rows-holder");
			fragment.appendChild(document.createElement("br"));
			fragment.appendChild(this.topElement);
			this.table.columnManager.getContentsElement().insertBefore(fragment, this.table.columnManager.headersElement.nextSibling);
			this.subscribe("row-deleting", this.detachRow.bind(this));
			this.subscribe("rows-visible", this.visibleRows.bind(this));
			this.registerDisplayHandler(this.getRows.bind(this), 10);
			if (this.table.options.frozenRows) {
				this.subscribe("data-processed", this.initializeRows.bind(this));
				this.subscribe("row-added", this.initializeRow.bind(this));
				this.subscribe("table-redrawing", this.resizeHolderWidth.bind(this));
				this.subscribe("column-resized", this.resizeHolderWidth.bind(this));
				this.subscribe("column-show", this.resizeHolderWidth.bind(this));
				this.subscribe("column-hide", this.resizeHolderWidth.bind(this));
			}
			this.resizeHolderWidth();
		}
		resizeHolderWidth() {
			this.topElement.style.minWidth = this.table.columnManager.headersElement.offsetWidth + "px";
		}
		initializeRows() {
			this.table.rowManager.getRows().forEach((row) => {
				this.initializeRow(row);
			});
		}
		initializeRow(row) {
			var frozenRows = this.table.options.frozenRows, rowType = typeof frozenRows;
			if (rowType === "number") {
				if (row.getPosition() && row.getPosition() + this.rows.length <= frozenRows) this.freezeRow(row);
			} else if (rowType === "function") {
				if (frozenRows.call(this.table, row.getComponent())) this.freezeRow(row);
			} else if (Array.isArray(frozenRows)) {
				if (frozenRows.includes(row.data[this.options("frozenRowsField")])) this.freezeRow(row);
			}
		}
		isRowFrozen(row) {
			return this.rows.indexOf(row) > -1;
		}
		isFrozen() {
			return !!this.rows.length;
		}
		visibleRows(viewable, rows) {
			this.rows.forEach((row) => {
				rows.push(row);
			});
			return rows;
		}
		getRows(rows) {
			var output = rows.slice(0);
			this.rows.forEach(function(row) {
				var index = output.indexOf(row);
				if (index > -1) output.splice(index, 1);
			});
			return output;
		}
		freezeRow(row) {
			if (!row.modules.frozen) {
				row.modules.frozen = true;
				this.topElement.appendChild(row.getElement());
				row.initialize();
				row.normalizeHeight();
				this.rows.push(row);
				this.refreshData(false, "display");
				this.table.rowManager.adjustTableSize();
				this.styleRows();
			} else console.warn("Freeze Error - Row is already frozen");
		}
		unfreezeRow(row) {
			if (row.modules.frozen) {
				row.modules.frozen = false;
				this.detachRow(row);
				this.table.rowManager.adjustTableSize();
				this.refreshData(false, "display");
				if (this.rows.length) this.styleRows();
			} else console.warn("Freeze Error - Row is already unfrozen");
		}
		detachRow(row) {
			var index = this.rows.indexOf(row);
			if (index > -1) {
				var rowEl = row.getElement();
				if (rowEl.parentNode) rowEl.parentNode.removeChild(rowEl);
				this.rows.splice(index, 1);
			}
		}
		styleRows(row) {
			this.rows.forEach((row, i) => {
				this.table.rowManager.styleRow(row, i);
			});
		}
	};
	var GroupComponent = class {
		constructor(group) {
			this._group = group;
			this.type = "GroupComponent";
			return new Proxy(this, { get: function(target, name, receiver) {
				if (typeof target[name] !== "undefined") return target[name];
				else return target._group.groupManager.table.componentFunctionBinder.handle("group", target._group, name);
			} });
		}
		getKey() {
			return this._group.key;
		}
		getField() {
			return this._group.field;
		}
		getElement() {
			return this._group.element;
		}
		getRows() {
			return this._group.getRows(true);
		}
		getSubGroups() {
			return this._group.getSubGroups(true);
		}
		getParentGroup() {
			return this._group.parent ? this._group.parent.getComponent() : false;
		}
		isVisible() {
			return this._group.visible;
		}
		show() {
			this._group.show();
		}
		hide() {
			this._group.hide();
		}
		toggle() {
			this._group.toggleVisibility();
		}
		scrollTo(position, ifVisible) {
			return this._group.groupManager.table.rowManager.scrollToRow(this._group, position, ifVisible);
		}
		_getSelf() {
			return this._group;
		}
		getTable() {
			return this._group.groupManager.table;
		}
	};
	var Group = class Group {
		constructor(groupManager, parent, level, key, field, generator, oldGroup) {
			this.groupManager = groupManager;
			this.parent = parent;
			this.key = key;
			this.level = level;
			this.field = field;
			this.hasSubGroups = level < groupManager.groupIDLookups.length - 1;
			this.addRow = this.hasSubGroups ? this._addRowToGroup : this._addRow;
			this.type = "group";
			this.old = oldGroup;
			this.rows = [];
			this.groups = [];
			this.groupList = [];
			this.generator = generator;
			this.element = false;
			this.elementContents = false;
			this.height = 0;
			this.outerHeight = 0;
			this.initialized = false;
			this.calcs = {};
			this.initialized = false;
			this.modules = {};
			this.arrowElement = false;
			this.visible = oldGroup ? oldGroup.visible : typeof groupManager.startOpen[level] !== "undefined" ? groupManager.startOpen[level] : groupManager.startOpen[0];
			this.component = null;
			this.createElements();
			this.addBindings();
			this.createValueGroups();
		}
		wipe(elementsOnly) {
			if (!elementsOnly) if (this.groupList.length) this.groupList.forEach(function(group) {
				group.wipe();
			});
			else this.rows.forEach((row) => {
				if (row.modules) delete row.modules.group;
			});
			this.element = false;
			this.arrowElement = false;
			this.elementContents = false;
		}
		createElements() {
			var arrow = document.createElement("div");
			arrow.classList.add("tabulator-arrow");
			this.element = document.createElement("div");
			this.element.classList.add("tabulator-row");
			this.element.classList.add("tabulator-group");
			this.element.classList.add("tabulator-group-level-" + this.level);
			this.element.setAttribute("role", "rowgroup");
			this.arrowElement = document.createElement("div");
			this.arrowElement.classList.add("tabulator-group-toggle");
			this.arrowElement.appendChild(arrow);
			if (this.groupManager.table.options.movableRows !== false && this.groupManager.table.modExists("moveRow")) this.groupManager.table.modules.moveRow.initializeGroupHeader(this);
		}
		createValueGroups() {
			var level = this.level + 1;
			if (this.groupManager.allowedValues && this.groupManager.allowedValues[level]) this.groupManager.allowedValues[level].forEach((value) => {
				this._createGroup(value, level);
			});
		}
		addBindings() {
			var toggleElement;
			if (this.groupManager.table.options.groupToggleElement) {
				toggleElement = this.groupManager.table.options.groupToggleElement == "arrow" ? this.arrowElement : this.element;
				toggleElement.addEventListener("click", (e) => {
					if (this.groupManager.table.options.groupToggleElement === "arrow") {
						e.stopPropagation();
						e.stopImmediatePropagation();
					}
					setTimeout(() => {
						this.toggleVisibility();
					});
				});
			}
		}
		_createGroup(groupID, level) {
			var groupKey = level + "_" + groupID;
			var group = new Group(this.groupManager, this, level, groupID, this.groupManager.groupIDLookups[level].field, this.groupManager.headerGenerator[level] || this.groupManager.headerGenerator[0], this.old ? this.old.groups[groupKey] : false);
			this.groups[groupKey] = group;
			this.groupList.push(group);
		}
		_addRowToGroup(row) {
			var level = this.level + 1;
			if (this.hasSubGroups) {
				var groupID = this.groupManager.groupIDLookups[level].func(row.getData()), groupKey = level + "_" + groupID;
				if (this.groupManager.allowedValues && this.groupManager.allowedValues[level]) {
					if (this.groups[groupKey]) this.groups[groupKey].addRow(row);
				} else {
					if (!this.groups[groupKey]) this._createGroup(groupID, level);
					this.groups[groupKey].addRow(row);
				}
			}
		}
		_addRow(row) {
			this.rows.push(row);
			row.modules.group = this;
		}
		insertRow(row, to, after) {
			var data = this.conformRowData({});
			row.updateData(data);
			var toIndex = this.rows.indexOf(to);
			if (toIndex > -1) if (after) this.rows.splice(toIndex + 1, 0, row);
			else this.rows.splice(toIndex, 0, row);
			else if (after) this.rows.push(row);
			else this.rows.unshift(row);
			row.modules.group = this;
			if (this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.options.columnCalcs != "table") this.groupManager.table.modules.columnCalcs.recalcGroup(this);
			this.groupManager.updateGroupRows(true);
		}
		scrollHeader(left) {
			if (this.arrowElement) {
				this.arrowElement.style.marginLeft = left;
				this.groupList.forEach(function(child) {
					child.scrollHeader(left);
				});
			}
		}
		getRowIndex(row) {}
		conformRowData(data) {
			if (this.field) data[this.field] = this.key;
			else console.warn("Data Conforming Error - Cannot conform row data to match new group as groupBy is a function");
			if (this.parent) data = this.parent.conformRowData(data);
			return data;
		}
		removeRow(row) {
			var index = this.rows.indexOf(row);
			var el = row.getElement();
			if (index > -1) this.rows.splice(index, 1);
			if (!this.groupManager.table.options.groupValues && !this.rows.length) {
				if (this.parent) this.parent.removeGroup(this);
				else this.groupManager.removeGroup(this);
				this.groupManager.updateGroupRows(true);
			} else {
				if (el.parentNode) el.parentNode.removeChild(el);
				if (!this.groupManager.blockRedraw) {
					this.generateGroupHeaderContents();
					if (this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.options.columnCalcs != "table") this.groupManager.table.modules.columnCalcs.recalcGroup(this);
				}
			}
		}
		removeGroup(group) {
			var groupKey = group.level + "_" + group.key, index;
			if (this.groups[groupKey]) {
				delete this.groups[groupKey];
				index = this.groupList.indexOf(group);
				if (index > -1) this.groupList.splice(index, 1);
				if (!this.groupList.length) if (this.parent) this.parent.removeGroup(this);
				else this.groupManager.removeGroup(this);
			}
		}
		getHeadersAndRows() {
			var output = [];
			output.push(this);
			this._visSet();
			if (this.calcs.top) {
				this.calcs.top.detachElement();
				this.calcs.top.deleteCells();
			}
			if (this.calcs.bottom) {
				this.calcs.bottom.detachElement();
				this.calcs.bottom.deleteCells();
			}
			if (this.visible) if (this.groupList.length) this.groupList.forEach(function(group) {
				output = output.concat(group.getHeadersAndRows());
			});
			else {
				if (this.groupManager.table.options.columnCalcs != "table" && this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.modules.columnCalcs.hasTopCalcs()) {
					this.calcs.top = this.groupManager.table.modules.columnCalcs.generateTopRow(this.rows);
					output.push(this.calcs.top);
				}
				output = output.concat(this.rows);
				if (this.groupManager.table.options.columnCalcs != "table" && this.groupManager.table.modExists("columnCalcs") && this.groupManager.table.modules.columnCalcs.hasBottomCalcs()) {
					this.calcs.bottom = this.groupManager.table.modules.columnCalcs.generateBottomRow(this.rows);
					output.push(this.calcs.bottom);
				}
			}
			else if (!this.groupList.length && this.groupManager.table.options.columnCalcs != "table") {
				if (this.groupManager.table.modExists("columnCalcs")) {
					if (this.groupManager.table.modules.columnCalcs.hasTopCalcs()) {
						if (this.groupManager.table.options.groupClosedShowCalcs) {
							this.calcs.top = this.groupManager.table.modules.columnCalcs.generateTopRow(this.rows);
							output.push(this.calcs.top);
						}
					}
					if (this.groupManager.table.modules.columnCalcs.hasBottomCalcs()) {
						if (this.groupManager.table.options.groupClosedShowCalcs) {
							this.calcs.bottom = this.groupManager.table.modules.columnCalcs.generateBottomRow(this.rows);
							output.push(this.calcs.bottom);
						}
					}
				}
			}
			return output;
		}
		getData(visible, transform) {
			var output = [];
			this._visSet();
			if (!visible || visible && this.visible) this.rows.forEach((row) => {
				output.push(row.getData(transform || "data"));
			});
			return output;
		}
		getRowCount() {
			var count = 0;
			if (this.groupList.length) this.groupList.forEach((group) => {
				count += group.getRowCount();
			});
			else count = this.rows.length;
			return count;
		}
		toggleVisibility() {
			if (this.visible) this.hide();
			else this.show();
		}
		hide() {
			this.visible = false;
			if (this.groupManager.table.rowManager.getRenderMode() == "basic" && !this.groupManager.table.options.pagination) {
				this.element.classList.remove("tabulator-group-visible");
				if (this.groupList.length) this.groupList.forEach((group) => {
					group.getHeadersAndRows().forEach((row) => {
						row.detachElement();
					});
				});
				else this.rows.forEach((row) => {
					var rowEl = row.getElement();
					rowEl.parentNode.removeChild(rowEl);
				});
				this.groupManager.updateGroupRows(true);
			} else this.groupManager.updateGroupRows(true);
			this.groupManager.table.externalEvents.dispatch("groupVisibilityChanged", this.getComponent(), false);
		}
		show() {
			this.visible = true;
			if (this.groupManager.table.rowManager.getRenderMode() == "basic" && !this.groupManager.table.options.pagination) {
				this.element.classList.add("tabulator-group-visible");
				var prev = this.generateElement();
				if (this.groupList.length) this.groupList.forEach((group) => {
					group.getHeadersAndRows().forEach((row) => {
						var rowEl = row.getElement();
						prev.parentNode.insertBefore(rowEl, prev.nextSibling);
						row.initialize();
						prev = rowEl;
					});
				});
				else this.rows.forEach((row) => {
					var rowEl = row.getElement();
					prev.parentNode.insertBefore(rowEl, prev.nextSibling);
					row.initialize();
					prev = rowEl;
				});
				this.groupManager.updateGroupRows(true);
			} else this.groupManager.updateGroupRows(true);
			this.groupManager.table.externalEvents.dispatch("groupVisibilityChanged", this.getComponent(), true);
		}
		_visSet() {
			var data = [];
			if (typeof this.visible == "function") {
				this.rows.forEach(function(row) {
					data.push(row.getData());
				});
				this.visible = this.visible(this.key, this.getRowCount(), data, this.getComponent());
			}
		}
		getRowGroup(row) {
			var match = false;
			if (this.groupList.length) this.groupList.forEach(function(group) {
				var result = group.getRowGroup(row);
				if (result) match = result;
			});
			else if (this.rows.find(function(item) {
				return item === row;
			})) match = this;
			return match;
		}
		getSubGroups(component) {
			var output = [];
			this.groupList.forEach(function(child) {
				output.push(component ? child.getComponent() : child);
			});
			return output;
		}
		getRows(component, includeChildren) {
			var output = [];
			if (includeChildren && this.groupList.length) this.groupList.forEach((group) => {
				output = output.concat(group.getRows(component, includeChildren));
			});
			else this.rows.forEach(function(row) {
				output.push(component ? row.getComponent() : row);
			});
			return output;
		}
		generateGroupHeaderContents() {
			var data = [];
			this.getRows(false, true).forEach(function(row) {
				data.push(row.getData());
			});
			this.elementContents = this.generator(this.key, this.getRowCount(), data, this.getComponent());
			while (this.element.firstChild) this.element.removeChild(this.element.firstChild);
			if (typeof this.elementContents === "string") this.element.innerHTML = this.elementContents;
			else this.element.appendChild(this.elementContents);
			this.element.insertBefore(this.arrowElement, this.element.firstChild);
		}
		getPath(path = []) {
			path.unshift(this.key);
			if (this.parent) this.parent.getPath(path);
			return path;
		}
		getElement() {
			return this.elementContents ? this.element : this.generateElement();
		}
		generateElement() {
			this.addBindings = false;
			this._visSet();
			if (this.visible) this.element.classList.add("tabulator-group-visible");
			else this.element.classList.remove("tabulator-group-visible");
			for (var i = 0; i < this.element.childNodes.length; ++i) this.element.childNodes[i].parentNode.removeChild(this.element.childNodes[i]);
			this.generateGroupHeaderContents();
			return this.element;
		}
		detachElement() {
			if (this.element && this.element.parentNode) this.element.parentNode.removeChild(this.element);
		}
		normalizeHeight() {
			this.setHeight(this.element.clientHeight);
		}
		initialize(force) {
			if (!this.initialized || force) {
				this.normalizeHeight();
				this.initialized = true;
			}
		}
		reinitialize() {
			this.initialized = false;
			this.height = 0;
			if (Helpers.elVisible(this.element)) this.initialize(true);
		}
		setHeight(height) {
			if (this.height != height) {
				this.height = height;
				this.outerHeight = this.element.offsetHeight;
			}
		}
		getHeight() {
			return this.outerHeight;
		}
		getGroup() {
			return this;
		}
		reinitializeHeight() {}
		calcHeight() {}
		setCellHeight() {}
		clearCellHeight() {}
		deinitializeHeight() {}
		rendered() {}
		getComponent() {
			if (!this.component) this.component = new GroupComponent(this);
			return this.component;
		}
	};
	var GroupRows = class extends Module {
		static moduleName = "groupRows";
		constructor(table) {
			super(table);
			this.groupIDLookups = false;
			this.startOpen = [function() {
				return false;
			}];
			this.headerGenerator = [function() {
				return "";
			}];
			this.groupList = [];
			this.allowedValues = false;
			this.groups = {};
			this.displayHandler = this.getRows.bind(this);
			this.blockRedraw = false;
			this.registerTableOption("groupBy", false);
			this.registerTableOption("groupStartOpen", true);
			this.registerTableOption("groupValues", false);
			this.registerTableOption("groupUpdateOnCellEdit", false);
			this.registerTableOption("groupHeader", false);
			this.registerTableOption("groupHeaderPrint", null);
			this.registerTableOption("groupHeaderClipboard", null);
			this.registerTableOption("groupHeaderHtmlOutput", null);
			this.registerTableOption("groupHeaderDownload", null);
			this.registerTableOption("groupToggleElement", "arrow");
			this.registerTableOption("groupClosedShowCalcs", false);
			this.registerTableFunction("setGroupBy", this.setGroupBy.bind(this));
			this.registerTableFunction("setGroupValues", this.setGroupValues.bind(this));
			this.registerTableFunction("setGroupStartOpen", this.setGroupStartOpen.bind(this));
			this.registerTableFunction("setGroupHeader", this.setGroupHeader.bind(this));
			this.registerTableFunction("getGroups", this.userGetGroups.bind(this));
			this.registerTableFunction("getGroupedData", this.userGetGroupedData.bind(this));
			this.registerComponentFunction("row", "getGroup", this.rowGetGroup.bind(this));
		}
		initialize() {
			this.subscribe("table-destroy", this._blockRedrawing.bind(this));
			this.subscribe("rows-wipe", this._blockRedrawing.bind(this));
			this.subscribe("rows-wiped", this._restore_redrawing.bind(this));
			if (this.table.options.groupBy) {
				if (this.table.options.groupUpdateOnCellEdit) {
					this.subscribe("cell-value-updated", this.cellUpdated.bind(this));
					this.subscribe("row-data-changed", this.reassignRowToGroup.bind(this), 0);
				}
				this.subscribe("table-built", this.configureGroupSetup.bind(this));
				this.subscribe("row-deleting", this.rowDeleting.bind(this));
				this.subscribe("row-deleted", this.rowsUpdated.bind(this));
				this.subscribe("scroll-horizontal", this.scrollHeaders.bind(this));
				this.subscribe("rows-wipe", this.wipe.bind(this));
				this.subscribe("rows-added", this.rowsUpdated.bind(this));
				this.subscribe("row-moving", this.rowMoving.bind(this));
				this.subscribe("row-adding-index", this.rowAddingIndex.bind(this));
				this.subscribe("rows-sample", this.rowSample.bind(this));
				this.subscribe("render-virtual-fill", this.virtualRenderFill.bind(this));
				this.registerDisplayHandler(this.displayHandler, 20);
				this.initialized = true;
			}
		}
		_blockRedrawing() {
			this.blockRedraw = true;
		}
		_restore_redrawing() {
			this.blockRedraw = false;
		}
		configureGroupSetup() {
			if (this.table.options.groupBy) {
				var groupBy = this.table.options.groupBy, startOpen = this.table.options.groupStartOpen, groupHeader = this.table.options.groupHeader;
				this.allowedValues = this.table.options.groupValues;
				if (Array.isArray(groupBy) && Array.isArray(groupHeader) && groupBy.length > groupHeader.length) console.warn("Error creating group headers, groupHeader array is shorter than groupBy array");
				this.headerGenerator = [function() {
					return "";
				}];
				this.startOpen = [function() {
					return false;
				}];
				this.langBind("groups|item", (langValue, lang) => {
					this.headerGenerator[0] = (value, count, data) => {
						return (typeof value === "undefined" ? "" : value) + "<span>(" + count + " " + (count === 1 ? langValue : lang.groups.items) + ")</span>";
					};
				});
				this.groupIDLookups = [];
				if (groupBy) {
					if (this.table.modExists("columnCalcs") && this.table.options.columnCalcs != "table" && this.table.options.columnCalcs != "both") this.table.modules.columnCalcs.removeCalcs();
				} else if (this.table.modExists("columnCalcs") && this.table.options.columnCalcs != "group") this.table.columnManager.getRealColumns().forEach((col) => {
					if (col.definition.topCalc) this.table.modules.columnCalcs.initializeTopRow();
					if (col.definition.bottomCalc) this.table.modules.columnCalcs.initializeBottomRow();
				});
				if (!Array.isArray(groupBy)) groupBy = [groupBy];
				groupBy.forEach((group, i) => {
					var lookupFunc, column;
					if (typeof group == "function") lookupFunc = group;
					else {
						column = this.table.columnManager.getColumnByField(group);
						if (column) lookupFunc = function(data) {
							return column.getFieldValue(data);
						};
						else lookupFunc = function(data) {
							return data[group];
						};
					}
					this.groupIDLookups.push({
						field: typeof group === "function" ? false : group,
						func: lookupFunc,
						values: this.allowedValues ? this.allowedValues[i] : false
					});
				});
				if (startOpen) {
					if (!Array.isArray(startOpen)) startOpen = [startOpen];
					startOpen.forEach((level) => {});
					this.startOpen = startOpen;
				}
				if (groupHeader) this.headerGenerator = Array.isArray(groupHeader) ? groupHeader : [groupHeader];
			} else {
				this.groupList = [];
				this.groups = {};
			}
		}
		rowSample(rows, prevValue) {
			if (this.table.options.groupBy) {
				var group = this.getGroups(false)[0];
				prevValue.push(group.getRows(false)[0]);
			}
			return prevValue;
		}
		virtualRenderFill() {
			var el = this.table.rowManager.tableElement;
			var rows = this.table.rowManager.getVisibleRows();
			if (this.table.options.groupBy) {
				rows = rows.filter((row) => {
					return row.type !== "group";
				});
				el.style.minWidth = !rows.length ? this.table.columnManager.getWidth() + "px" : "";
			} else return rows;
		}
		rowAddingIndex(row, index, top) {
			if (this.table.options.groupBy) {
				this.assignRowToGroup(row);
				var groupRows = row.modules.group.rows;
				if (groupRows.length > 1) if (!index || index && groupRows.indexOf(index) == -1) {
					if (top) {
						if (groupRows[0] !== row) {
							index = groupRows[0];
							this.table.rowManager.moveRowInArray(row.modules.group.rows, row, index, !top);
						}
					} else if (groupRows[groupRows.length - 1] !== row) {
						index = groupRows[groupRows.length - 1];
						this.table.rowManager.moveRowInArray(row.modules.group.rows, row, index, !top);
					}
				} else this.table.rowManager.moveRowInArray(row.modules.group.rows, row, index, !top);
				return index;
			}
		}
		trackChanges() {
			this.dispatch("group-changed");
		}
		setGroupBy(groups) {
			this.table.options.groupBy = groups;
			if (!this.initialized) this.initialize();
			this.configureGroupSetup();
			if (!groups && this.table.modExists("columnCalcs") && this.table.options.columnCalcs === true) this.table.modules.columnCalcs.reinitializeCalcs();
			this.refreshData();
			this.trackChanges();
		}
		setGroupValues(groupValues) {
			this.table.options.groupValues = groupValues;
			this.configureGroupSetup();
			this.refreshData();
			this.trackChanges();
		}
		setGroupStartOpen(values) {
			this.table.options.groupStartOpen = values;
			this.configureGroupSetup();
			if (this.table.options.groupBy) {
				this.refreshData();
				this.trackChanges();
			} else console.warn("Grouping Update - cant refresh view, no groups have been set");
		}
		setGroupHeader(values) {
			this.table.options.groupHeader = values;
			this.configureGroupSetup();
			if (this.table.options.groupBy) {
				this.refreshData();
				this.trackChanges();
			} else console.warn("Grouping Update - cant refresh view, no groups have been set");
		}
		userGetGroups(values) {
			return this.getGroups(true);
		}
		userGetGroupedData() {
			return this.table.options.groupBy ? this.getGroupedData() : this.getData();
		}
		rowGetGroup(row) {
			return row.modules.group ? row.modules.group.getComponent() : false;
		}
		rowMoving(from, to, after) {
			if (this.table.options.groupBy) {
				if (!after && to instanceof Group) to = this.table.rowManager.prevDisplayRow(from) || to;
				var toGroup = to instanceof Group ? to : to.modules.group;
				var fromGroup = from instanceof Group ? from : from.modules.group;
				if (toGroup === fromGroup) this.table.rowManager.moveRowInArray(toGroup.rows, from, to, after);
				else {
					if (fromGroup) fromGroup.removeRow(from);
					toGroup.insertRow(from, to, after);
				}
			}
		}
		rowDeleting(row) {
			if (this.table.options.groupBy && row.modules.group) row.modules.group.removeRow(row);
		}
		rowsUpdated(row) {
			if (this.table.options.groupBy) this.updateGroupRows(true);
		}
		cellUpdated(cell) {
			if (this.table.options.groupBy) this.reassignRowToGroup(cell.row);
		}
		getRows(rows) {
			if (this.table.options.groupBy && this.groupIDLookups.length) {
				this.dispatchExternal("dataGrouping");
				this.generateGroups(rows);
				if (this.subscribedExternal("dataGrouped")) this.dispatchExternal("dataGrouped", this.getGroups(true));
				return this.updateGroupRows();
			} else return rows.slice(0);
		}
		getGroups(component) {
			var groupComponents = [];
			this.groupList.forEach(function(group) {
				groupComponents.push(component ? group.getComponent() : group);
			});
			return groupComponents;
		}
		getChildGroups(group) {
			var groupComponents = [];
			if (!group) group = this;
			group.groupList.forEach((child) => {
				if (child.groupList.length) groupComponents = groupComponents.concat(this.getChildGroups(child));
				else groupComponents.push(child);
			});
			return groupComponents;
		}
		wipe() {
			if (this.table.options.groupBy) {
				this.groupList.forEach(function(group) {
					group.wipe();
				});
				this.groupList = [];
				this.groups = {};
			}
		}
		pullGroupListData(groupList) {
			var groupListData = [];
			groupList.forEach((group) => {
				var groupHeader = {};
				groupHeader.level = 0;
				groupHeader.rowCount = 0;
				groupHeader.headerContent = "";
				var childData = [];
				if (group.hasSubGroups) {
					childData = this.pullGroupListData(group.groupList);
					groupHeader.level = group.level;
					groupHeader.rowCount = childData.length - group.groupList.length;
					groupHeader.headerContent = group.generator(group.key, groupHeader.rowCount, group.rows, group);
					groupListData.push(groupHeader);
					groupListData = groupListData.concat(childData);
				} else {
					groupHeader.level = group.level;
					groupHeader.headerContent = group.generator(group.key, group.rows.length, group.rows, group);
					groupHeader.rowCount = group.getRows().length;
					groupListData.push(groupHeader);
					group.getRows().forEach((row) => {
						groupListData.push(row.getData("data"));
					});
				}
			});
			return groupListData;
		}
		getGroupedData() {
			return this.pullGroupListData(this.groupList);
		}
		getRowGroup(row) {
			var match = false;
			if (this.options("dataTree")) row = this.table.modules.dataTree.getTreeParentRoot(row);
			this.groupList.forEach((group) => {
				var result = group.getRowGroup(row);
				if (result) match = result;
			});
			return match;
		}
		countGroups() {
			return this.groupList.length;
		}
		generateGroups(rows) {
			var oldGroups = this.groups;
			this.groups = {};
			this.groupList = [];
			if (this.allowedValues && this.allowedValues[0]) {
				this.allowedValues[0].forEach((value) => {
					this.createGroup(value, 0, oldGroups);
				});
				rows.forEach((row) => {
					this.assignRowToExistingGroup(row, oldGroups);
				});
			} else rows.forEach((row) => {
				this.assignRowToGroup(row, oldGroups);
			});
			Object.values(oldGroups).forEach((group) => {
				group.wipe(true);
			});
		}
		createGroup(groupID, level, oldGroups) {
			var groupKey = level + "_" + groupID, group;
			oldGroups = oldGroups || [];
			group = new Group(this, false, level, groupID, this.groupIDLookups[0].field, this.headerGenerator[0], oldGroups[groupKey]);
			this.groups[groupKey] = group;
			this.groupList.push(group);
		}
		assignRowToExistingGroup(row, oldGroups) {
			var groupKey = "0_" + this.groupIDLookups[0].func(row.getData());
			if (this.groups[groupKey]) this.groups[groupKey].addRow(row);
		}
		assignRowToGroup(row, oldGroups) {
			var groupID = this.groupIDLookups[0].func(row.getData()), newGroupNeeded = !this.groups["0_" + groupID];
			if (newGroupNeeded) this.createGroup(groupID, 0, oldGroups);
			this.groups["0_" + groupID].addRow(row);
			return !newGroupNeeded;
		}
		reassignRowToGroup(row) {
			if (row.type === "row") {
				var oldRowGroup = row.modules.group, oldGroupPath = oldRowGroup.getPath(), newGroupPath = this.getExpectedPath(row);
				if (!(oldGroupPath.length == newGroupPath.length && oldGroupPath.every((element, index) => {
					return element === newGroupPath[index];
				}))) {
					oldRowGroup.removeRow(row);
					this.assignRowToGroup(row, this.groups);
					this.refreshData(true);
				}
			}
		}
		getExpectedPath(row) {
			var groupPath = [], rowData = row.getData();
			this.groupIDLookups.forEach((groupId) => {
				groupPath.push(groupId.func(rowData));
			});
			return groupPath;
		}
		updateGroupRows(force) {
			var output = [];
			if (!this.blockRedraw) {
				this.groupList.forEach((group) => {
					output = output.concat(group.getHeadersAndRows());
				});
				if (force) this.refreshData(true);
			}
			return output;
		}
		scrollHeaders(left) {
			if (this.table.options.groupBy) {
				if (this.table.options.renderHorizontal === "virtual") left -= this.table.columnManager.renderer.vDomPadLeft;
				left = left + "px";
				this.groupList.forEach((group) => {
					group.scrollHeader(left);
				});
			}
		}
		removeGroup(group) {
			var groupKey = group.level + "_" + group.key, index;
			if (this.groups[groupKey]) {
				delete this.groups[groupKey];
				index = this.groupList.indexOf(group);
				if (index > -1) this.groupList.splice(index, 1);
			}
		}
		checkBasicModeGroupHeaderWidth() {
			var element = this.table.rowManager.tableElement, onlyGroupHeaders = true;
			this.table.rowManager.getDisplayRows().forEach((row, index) => {
				this.table.rowManager.styleRow(row, index);
				element.appendChild(row.getElement());
				row.initialize(true);
				if (row.type !== "group") onlyGroupHeaders = false;
			});
			if (onlyGroupHeaders) element.style.minWidth = this.table.columnManager.getWidth() + "px";
			else element.style.minWidth = "";
		}
	};
	var defaultUndoers = {
		cellEdit: function(action) {
			action.component.setValueProcessData(action.data.oldValue);
			action.component.cellRendered();
		},
		rowAdd: function(action) {
			action.component.deleteActual();
			this.table.rowManager.checkPlaceholder();
		},
		rowDelete: function(action) {
			var newRow = this.table.rowManager.addRowActual(action.data.data, action.data.pos, action.data.index);
			if (this.table.options.groupBy && this.table.modExists("groupRows")) this.table.modules.groupRows.updateGroupRows(true);
			this._rebindRow(action.component, newRow);
			this.table.rowManager.checkPlaceholder();
		},
		rowMove: function(action) {
			var after = action.data.posFrom - action.data.posTo > 0;
			this.table.rowManager.moveRowActual(action.component, this.table.rowManager.getRowFromPosition(action.data.posFrom), after);
			this.table.rowManager.regenerateRowPositions();
			this.table.rowManager.reRenderInPosition();
		}
	};
	var defaultRedoers = {
		cellEdit: function(action) {
			action.component.setValueProcessData(action.data.newValue);
			action.component.cellRendered();
		},
		rowAdd: function(action) {
			var newRow = this.table.rowManager.addRowActual(action.data.data, action.data.pos, action.data.index);
			if (this.table.options.groupBy && this.table.modExists("groupRows")) this.table.modules.groupRows.updateGroupRows(true);
			this._rebindRow(action.component, newRow);
			this.table.rowManager.checkPlaceholder();
		},
		rowDelete: function(action) {
			action.component.deleteActual();
			this.table.rowManager.checkPlaceholder();
		},
		rowMove: function(action) {
			this.table.rowManager.moveRowActual(action.component, this.table.rowManager.getRowFromPosition(action.data.posTo), action.data.after);
			this.table.rowManager.regenerateRowPositions();
			this.table.rowManager.reRenderInPosition();
		}
	};
	var extensions$3 = { keybindings: {
		bindings: {
			undo: ["ctrl + 90", "meta + 90"],
			redo: ["ctrl + 89", "meta + 89"]
		},
		actions: {
			undo: function(e) {
				var cell = false;
				if (this.table.options.history && this.table.modExists("history") && this.table.modExists("edit")) {
					cell = this.table.modules.edit.currentCell;
					if (!cell) {
						e.preventDefault();
						this.table.modules.history.undo();
					}
				}
			},
			redo: function(e) {
				var cell = false;
				if (this.table.options.history && this.table.modExists("history") && this.table.modExists("edit")) {
					cell = this.table.modules.edit.currentCell;
					if (!cell) {
						e.preventDefault();
						this.table.modules.history.redo();
					}
				}
			}
		}
	} };
	var History = class History extends Module {
		static moduleName = "history";
		static moduleExtensions = extensions$3;
		static undoers = defaultUndoers;
		static redoers = defaultRedoers;
		constructor(table) {
			super(table);
			this.history = [];
			this.index = -1;
			this.registerTableOption("history", false);
		}
		initialize() {
			if (this.table.options.history) {
				this.subscribe("cell-value-updated", this.cellUpdated.bind(this));
				this.subscribe("cell-delete", this.clearComponentHistory.bind(this));
				this.subscribe("row-delete", this.rowDeleted.bind(this));
				this.subscribe("rows-wipe", this.clear.bind(this));
				this.subscribe("row-added", this.rowAdded.bind(this));
				this.subscribe("row-move", this.rowMoved.bind(this));
			}
			this.registerTableFunction("undo", this.undo.bind(this));
			this.registerTableFunction("redo", this.redo.bind(this));
			this.registerTableFunction("getHistoryUndoSize", this.getHistoryUndoSize.bind(this));
			this.registerTableFunction("getHistoryRedoSize", this.getHistoryRedoSize.bind(this));
			this.registerTableFunction("clearHistory", this.clear.bind(this));
		}
		rowMoved(from, to, after) {
			this.action("rowMove", from, {
				posFrom: from.getPosition(),
				posTo: to.getPosition(),
				to,
				after
			});
		}
		rowAdded(row, data, pos, index) {
			this.action("rowAdd", row, {
				data,
				pos,
				index
			});
		}
		rowDeleted(row) {
			var index, rows;
			if (this.table.options.groupBy) {
				rows = row.getComponent().getGroup()._getSelf().rows;
				index = rows.indexOf(row);
				if (index) index = rows[index - 1];
			} else {
				index = row.table.rowManager.getRowIndex(row);
				if (index) index = row.table.rowManager.rows[index - 1];
			}
			this.action("rowDelete", row, {
				data: row.getData(),
				pos: !index,
				index
			});
		}
		cellUpdated(cell) {
			this.action("cellEdit", cell, {
				oldValue: cell.oldValue,
				newValue: cell.value
			});
		}
		clear() {
			this.history = [];
			this.index = -1;
		}
		action(type, component, data) {
			this.history = this.history.slice(0, this.index + 1);
			this.history.push({
				type,
				component,
				data
			});
			this.index++;
		}
		getHistoryUndoSize() {
			return this.index + 1;
		}
		getHistoryRedoSize() {
			return this.history.length - (this.index + 1);
		}
		clearComponentHistory(component) {
			var index = this.history.findIndex(function(item) {
				return item.component === component;
			});
			if (index > -1) {
				this.history.splice(index, 1);
				if (index <= this.index) this.index--;
				this.clearComponentHistory(component);
			}
		}
		undo() {
			if (this.index > -1) {
				let action = this.history[this.index];
				History.undoers[action.type].call(this, action);
				this.index--;
				this.dispatchExternal("historyUndo", action.type, action.component.getComponent(), action.data);
				return true;
			} else {
				console.warn(this.options("history") ? "History Undo Error - No more history to undo" : "History module not enabled");
				return false;
			}
		}
		redo() {
			if (this.history.length - 1 > this.index) {
				this.index++;
				let action = this.history[this.index];
				History.redoers[action.type].call(this, action);
				this.dispatchExternal("historyRedo", action.type, action.component.getComponent(), action.data);
				return true;
			} else {
				console.warn(this.options("history") ? "History Redo Error - No more history to redo" : "History module not enabled");
				return false;
			}
		}
		_rebindRow(oldRow, newRow) {
			this.history.forEach(function(action) {
				if (action.component instanceof Row$1) {
					if (action.component === oldRow) action.component = newRow;
				} else if (action.component instanceof Cell) {
					if (action.component.row === oldRow) {
						var field = action.component.column.getField();
						if (field) action.component = newRow.getCell(field);
					}
				}
			});
		}
	};
	var HtmlTableImport = class extends Module {
		static moduleName = "htmlTableImport";
		constructor(table) {
			super(table);
			this.fieldIndex = [];
			this.hasIndex = false;
		}
		initialize() {
			this.tableElementCheck();
		}
		tableElementCheck() {
			if (this.table.originalElement && this.table.originalElement.tagName === "TABLE") if (this.table.originalElement.childNodes.length) this.parseTable();
			else console.warn("Unable to parse data from empty table tag, Tabulator should be initialized on a div tag unless importing data from a table element.");
		}
		parseTable() {
			var element = this.table.originalElement, options = this.table.options, headers = element.getElementsByTagName("th"), rows = element.getElementsByTagName("tbody")[0], data = [];
			this.hasIndex = false;
			this.dispatchExternal("htmlImporting");
			rows = rows ? rows.getElementsByTagName("tr") : [];
			this._extractOptions(element, options);
			if (headers.length) this._extractHeaders(headers, rows);
			else this._generateBlankHeaders(headers, rows);
			for (var index = 0; index < rows.length; index++) {
				var cells = rows[index].getElementsByTagName("td"), item = {};
				if (!this.hasIndex) item[options.index] = index;
				for (var i = 0; i < cells.length; i++) {
					var cell = cells[i];
					if (typeof this.fieldIndex[i] !== "undefined") item[this.fieldIndex[i]] = cell.innerHTML;
				}
				data.push(item);
			}
			options.data = data;
			this.dispatchExternal("htmlImported");
		}
		_extractOptions(element, options, defaultOptions) {
			var attributes = element.attributes;
			var optionsArr = defaultOptions ? Object.keys(defaultOptions) : Object.keys(options);
			var optionsList = {};
			optionsArr.forEach((item) => {
				optionsList[item.toLowerCase()] = item;
			});
			for (var index in attributes) {
				var attrib = attributes[index];
				var name;
				if (attrib && typeof attrib == "object" && attrib.name && attrib.name.indexOf("tabulator-") === 0) {
					name = attrib.name.replace("tabulator-", "");
					if (typeof optionsList[name] !== "undefined") options[optionsList[name]] = this._attribValue(attrib.value);
				}
			}
		}
		_attribValue(value) {
			if (value === "true") return true;
			if (value === "false") return false;
			return value;
		}
		_findCol(title) {
			return this.table.options.columns.find((column) => {
				return column.title === title;
			}) || false;
		}
		_extractHeaders(headers, rows) {
			for (var index = 0; index < headers.length; index++) {
				var header = headers[index], exists = false, col = this._findCol(header.textContent), width;
				if (col) exists = true;
				else col = { title: header.textContent.trim() };
				if (!col.field) col.field = header.textContent.trim().toLowerCase().replaceAll(" ", "_");
				width = header.getAttribute("width");
				if (width && !col.width) col.width = width;
				this._extractOptions(header, col, this.table.columnManager.optionsList.registeredDefaults);
				this.fieldIndex[index] = col.field;
				if (col.field == this.table.options.index) this.hasIndex = true;
				if (!exists) this.table.options.columns.push(col);
			}
		}
		_generateBlankHeaders(headers, rows) {
			for (var index = 0; index < headers.length; index++) {
				var header = headers[index], col = {
					title: "",
					field: "col" + index
				};
				this.fieldIndex[index] = col.field;
				var width = header.getAttribute("width");
				if (width) col.width = width;
				this.table.options.columns.push(col);
			}
		}
	};
	function csv(input) {
		var data = [], row = 0, col = 0, inQuote = false;
		for (let index = 0; index < input.length; index++) {
			let char = input[index], nextChar = input[index + 1];
			if (!data[row]) data[row] = [];
			if (!data[row][col]) data[row][col] = "";
			if (char == "\"" && inQuote && nextChar == "\"") {
				data[row][col] += char;
				index++;
				continue;
			}
			if (char == "\"") {
				inQuote = !inQuote;
				continue;
			}
			if (char == "," && !inQuote) {
				col++;
				continue;
			}
			if (char == "\r" && nextChar == "\n" && !inQuote) {
				col = 0;
				row++;
				index++;
				continue;
			}
			if ((char == "\r" || char == "\n") && !inQuote) {
				col = 0;
				row++;
				continue;
			}
			data[row][col] += char;
		}
		return data;
	}
	function json(input) {
		try {
			return JSON.parse(input);
		} catch (e) {
			console.warn("JSON Import Error - File contents is invalid JSON", e);
			return Promise.reject();
		}
	}
	function array$1(input) {
		return input;
	}
	function xlsx(input) {
		var XLSXLib = this.dependencyRegistry.lookup("XLSX"), workbook2 = XLSXLib.read(input), sheet = workbook2.Sheets[workbook2.SheetNames[0]];
		return XLSXLib.utils.sheet_to_json(sheet, { header: 1 });
	}
	var defaultImporters = {
		csv,
		json,
		array: array$1,
		xlsx
	};
	var Import = class Import extends Module {
		static moduleName = "import";
		static importers = defaultImporters;
		constructor(table) {
			super(table);
			this.registerTableOption("importFormat");
			this.registerTableOption("importReader", "text");
			this.registerTableOption("importHeaderTransform");
			this.registerTableOption("importValueTransform");
			this.registerTableOption("importDataValidator");
			this.registerTableOption("importFileValidator");
		}
		initialize() {
			this.registerTableFunction("import", this.importFromFile.bind(this));
			if (this.table.options.importFormat) {
				this.subscribe("data-loading", this.loadDataCheck.bind(this), 10);
				this.subscribe("data-load", this.loadData.bind(this), 10);
			}
		}
		loadDataCheck(data) {
			return this.table.options.importFormat && (typeof data === "string" || Array.isArray(data) && data.length && Array.isArray(data));
		}
		loadData(data, params, config, silent, previousData) {
			return this.importData(this.lookupImporter(), data).then(this.structureData.bind(this)).catch((err) => {
				console.error("Import Error:", err || "Unable to import data");
				return Promise.reject(err);
			});
		}
		lookupImporter(importFormat) {
			var importer;
			if (!importFormat) importFormat = this.table.options.importFormat;
			if (typeof importFormat === "string") importer = Import.importers[importFormat];
			else importer = importFormat;
			if (!importer) console.error("Import Error - Importer not found:", importFormat);
			return importer;
		}
		importFromFile(importFormat, extension, importReader) {
			var importer = this.lookupImporter(importFormat);
			if (importer) return this.pickFile(extension, importReader).then(this.importData.bind(this, importer)).then(this.structureData.bind(this)).then(this.mutateData.bind(this)).then(this.validateData.bind(this)).then(this.setData.bind(this)).catch((err) => {
				this.dispatch("import-error", err);
				this.dispatchExternal("importError", err);
				console.error("Import Error:", err || "Unable to import file");
				this.table.dataLoader.alertError();
				setTimeout(() => {
					this.table.dataLoader.clearAlert();
				}, 3e3);
				return Promise.reject(err);
			});
		}
		pickFile(extensions, importReader) {
			return new Promise((resolve, reject) => {
				var input = document.createElement("input");
				input.type = "file";
				input.accept = extensions;
				input.addEventListener("change", (e) => {
					var file = input.files[0], reader = new FileReader(), valid = this.validateFile(file);
					if (valid === true) {
						this.dispatch("import-importing", input.files);
						this.dispatchExternal("importImporting", input.files);
						switch (importReader || this.table.options.importReader) {
							case "buffer":
								reader.readAsArrayBuffer(file);
								break;
							case "binary":
								reader.readAsBinaryString(file);
								break;
							case "url":
								reader.readAsDataURL(file);
								break;
							default: reader.readAsText(file);
						}
						reader.onload = (e) => {
							resolve(reader.result);
						};
						reader.onerror = (e) => {
							console.warn("File Load Error - Unable to read file");
							reject(e);
						};
					} else reject(valid);
				});
				this.dispatch("import-choose");
				this.dispatchExternal("importChoose");
				input.click();
			});
		}
		importData(importer, fileContents) {
			var data;
			this.table.dataLoader.alertLoader();
			return new Promise((resolve, reject) => {
				setTimeout(() => {
					data = importer.call(this.table, fileContents);
					if (data instanceof Promise) resolve(data);
					else data ? resolve(data) : reject();
				}, 10);
			});
		}
		structureData(parsedData) {
			var data = [];
			if (Array.isArray(parsedData) && parsedData.length && Array.isArray(parsedData[0])) {
				if (this.table.options.autoColumns) data = this.structureArrayToObject(parsedData);
				else data = this.structureArrayToColumns(parsedData);
				return data;
			} else return parsedData;
		}
		mutateData(data) {
			var output = [];
			if (Array.isArray(data)) data.forEach((row) => {
				output.push(this.table.modules.mutator.transformRow(row, "import"));
			});
			else output = data;
			return output;
		}
		transformHeader(headers) {
			var output = [];
			if (this.table.options.importHeaderTransform) headers.forEach((item) => {
				output.push(this.table.options.importHeaderTransform.call(this.table, item, headers));
			});
			else return headers;
			return output;
		}
		transformData(row) {
			var output = [];
			if (this.table.options.importValueTransform) row.forEach((item) => {
				output.push(this.table.options.importValueTransform.call(this.table, item, row));
			});
			else return row;
			return output;
		}
		structureArrayToObject(parsedData) {
			var columns = this.transformHeader(parsedData.shift());
			return parsedData.map((values) => {
				var row = {};
				values = this.transformData(values);
				columns.forEach((key, i) => {
					row[key] = values[i];
				});
				return row;
			});
		}
		structureArrayToColumns(parsedData) {
			var data = [], firstRow = this.transformHeader(parsedData[0]), columns = this.table.getColumns();
			if (columns[0] && firstRow[0]) {
				if (columns[0].getDefinition().title === firstRow[0]) parsedData.shift();
			}
			parsedData.forEach((rowData) => {
				var row = {};
				rowData = this.transformData(rowData);
				rowData.forEach((value, index) => {
					var column = columns[index];
					if (column) row[column.getField()] = value;
				});
				data.push(row);
			});
			return data;
		}
		validateFile(file) {
			if (this.table.options.importFileValidator) return this.table.options.importFileValidator.call(this.table, file);
			return true;
		}
		validateData(data) {
			var result;
			if (this.table.options.importDataValidator) {
				result = this.table.options.importDataValidator.call(this.table, data);
				if (result === true) return data;
				else return Promise.reject(result);
			}
			return data;
		}
		setData(data) {
			this.dispatch("import-imported", data);
			this.dispatchExternal("importImported", data);
			this.table.dataLoader.clearAlert();
			return this.table.setData(data);
		}
	};
	var Interaction = class extends Module {
		static moduleName = "interaction";
		constructor(table) {
			super(table);
			this.eventMap = {
				rowClick: "row-click",
				rowDblClick: "row-dblclick",
				rowContext: "row-contextmenu",
				rowMouseEnter: "row-mouseenter",
				rowMouseLeave: "row-mouseleave",
				rowMouseOver: "row-mouseover",
				rowMouseOut: "row-mouseout",
				rowMouseMove: "row-mousemove",
				rowMouseDown: "row-mousedown",
				rowMouseUp: "row-mouseup",
				rowTap: "row",
				rowDblTap: "row",
				rowTapHold: "row",
				cellClick: "cell-click",
				cellDblClick: "cell-dblclick",
				cellContext: "cell-contextmenu",
				cellMouseEnter: "cell-mouseenter",
				cellMouseLeave: "cell-mouseleave",
				cellMouseOver: "cell-mouseover",
				cellMouseOut: "cell-mouseout",
				cellMouseMove: "cell-mousemove",
				cellMouseDown: "cell-mousedown",
				cellMouseUp: "cell-mouseup",
				cellTap: "cell",
				cellDblTap: "cell",
				cellTapHold: "cell",
				headerClick: "column-click",
				headerDblClick: "column-dblclick",
				headerContext: "column-contextmenu",
				headerMouseEnter: "column-mouseenter",
				headerMouseLeave: "column-mouseleave",
				headerMouseOver: "column-mouseover",
				headerMouseOut: "column-mouseout",
				headerMouseMove: "column-mousemove",
				headerMouseDown: "column-mousedown",
				headerMouseUp: "column-mouseup",
				headerTap: "column",
				headerDblTap: "column",
				headerTapHold: "column",
				groupClick: "group-click",
				groupDblClick: "group-dblclick",
				groupContext: "group-contextmenu",
				groupMouseEnter: "group-mouseenter",
				groupMouseLeave: "group-mouseleave",
				groupMouseOver: "group-mouseover",
				groupMouseOut: "group-mouseout",
				groupMouseMove: "group-mousemove",
				groupMouseDown: "group-mousedown",
				groupMouseUp: "group-mouseup",
				groupTap: "group",
				groupDblTap: "group",
				groupTapHold: "group"
			};
			this.subscribers = {};
			this.touchSubscribers = {};
			this.columnSubscribers = {};
			this.touchWatchers = {
				row: {
					tap: null,
					tapDbl: null,
					tapHold: null
				},
				cell: {
					tap: null,
					tapDbl: null,
					tapHold: null
				},
				column: {
					tap: null,
					tapDbl: null,
					tapHold: null
				},
				group: {
					tap: null,
					tapDbl: null,
					tapHold: null
				}
			};
			this.registerColumnOption("headerClick");
			this.registerColumnOption("headerDblClick");
			this.registerColumnOption("headerContext");
			this.registerColumnOption("headerMouseEnter");
			this.registerColumnOption("headerMouseLeave");
			this.registerColumnOption("headerMouseOver");
			this.registerColumnOption("headerMouseOut");
			this.registerColumnOption("headerMouseMove");
			this.registerColumnOption("headerMouseDown");
			this.registerColumnOption("headerMouseUp");
			this.registerColumnOption("headerTap");
			this.registerColumnOption("headerDblTap");
			this.registerColumnOption("headerTapHold");
			this.registerColumnOption("cellClick");
			this.registerColumnOption("cellDblClick");
			this.registerColumnOption("cellContext");
			this.registerColumnOption("cellMouseEnter");
			this.registerColumnOption("cellMouseLeave");
			this.registerColumnOption("cellMouseOver");
			this.registerColumnOption("cellMouseOut");
			this.registerColumnOption("cellMouseMove");
			this.registerColumnOption("cellMouseDown");
			this.registerColumnOption("cellMouseUp");
			this.registerColumnOption("cellTap");
			this.registerColumnOption("cellDblTap");
			this.registerColumnOption("cellTapHold");
		}
		initialize() {
			this.initializeExternalEvents();
			this.subscribe("column-init", this.initializeColumn.bind(this));
			this.subscribe("cell-dblclick", this.cellContentsSelectionFixer.bind(this));
			this.subscribe("scroll-horizontal", this.clearTouchWatchers.bind(this));
			this.subscribe("scroll-vertical", this.clearTouchWatchers.bind(this));
		}
		clearTouchWatchers() {
			Object.values(this.touchWatchers).forEach((type) => {
				for (let key in type) type[key] = null;
			});
		}
		cellContentsSelectionFixer(e, cell) {
			var range;
			if (this.table.modExists("edit")) {
				if (this.table.modules.edit.currentCell === cell) return;
			}
			e.preventDefault();
			try {
				if (document.selection) {
					range = document.body.createTextRange();
					range.moveToElementText(cell.getElement());
					range.select();
				} else if (window.getSelection) {
					range = document.createRange();
					range.selectNode(cell.getElement());
					window.getSelection().removeAllRanges();
					window.getSelection().addRange(range);
				}
			} catch (e) {}
		}
		initializeExternalEvents() {
			for (let key in this.eventMap) this.subscriptionChangeExternal(key, this.subscriptionChanged.bind(this, key));
		}
		subscriptionChanged(key, added) {
			if (added) {
				if (!this.subscribers[key]) if (this.eventMap[key].includes("-")) {
					this.subscribers[key] = this.handle.bind(this, key);
					this.subscribe(this.eventMap[key], this.subscribers[key]);
				} else this.subscribeTouchEvents(key);
			} else if (this.eventMap[key].includes("-")) {
				if (this.subscribers[key] && !this.columnSubscribers[key] && !this.subscribedExternal(key)) {
					this.unsubscribe(this.eventMap[key], this.subscribers[key]);
					delete this.subscribers[key];
				}
			} else this.unsubscribeTouchEvents(key);
		}
		subscribeTouchEvents(key) {
			var type = this.eventMap[key];
			if (!this.touchSubscribers[type + "-touchstart"]) {
				this.touchSubscribers[type + "-touchstart"] = this.handleTouch.bind(this, type, "start");
				this.touchSubscribers[type + "-touchend"] = this.handleTouch.bind(this, type, "end");
				this.subscribe(type + "-touchstart", this.touchSubscribers[type + "-touchstart"]);
				this.subscribe(type + "-touchend", this.touchSubscribers[type + "-touchend"]);
			}
			this.subscribers[key] = true;
		}
		unsubscribeTouchEvents(key) {
			var noTouch = true, type = this.eventMap[key];
			if (this.subscribers[key] && !this.subscribedExternal(key)) {
				delete this.subscribers[key];
				for (let i in this.eventMap) if (this.eventMap[i] === type) {
					if (this.subscribers[i]) noTouch = false;
				}
				if (noTouch) {
					this.unsubscribe(type + "-touchstart", this.touchSubscribers[type + "-touchstart"]);
					this.unsubscribe(type + "-touchend", this.touchSubscribers[type + "-touchend"]);
					delete this.touchSubscribers[type + "-touchstart"];
					delete this.touchSubscribers[type + "-touchend"];
				}
			}
		}
		initializeColumn(column) {
			var def = column.definition;
			for (let key in this.eventMap) if (def[key]) {
				this.subscriptionChanged(key, true);
				if (!this.columnSubscribers[key]) this.columnSubscribers[key] = [];
				this.columnSubscribers[key].push(column);
			}
		}
		handle(action, e, component) {
			this.dispatchEvent(action, e, component);
		}
		handleTouch(type, action, e, component) {
			var watchers = this.touchWatchers[type];
			if (type === "column") type = "header";
			switch (action) {
				case "start":
					watchers.tap = true;
					clearTimeout(watchers.tapHold);
					watchers.tapHold = setTimeout(() => {
						clearTimeout(watchers.tapHold);
						watchers.tapHold = null;
						watchers.tap = null;
						clearTimeout(watchers.tapDbl);
						watchers.tapDbl = null;
						this.dispatchEvent(type + "TapHold", e, component);
					}, 1e3);
					break;
				case "end":
					if (watchers.tap) {
						watchers.tap = null;
						this.dispatchEvent(type + "Tap", e, component);
					}
					if (watchers.tapDbl) {
						clearTimeout(watchers.tapDbl);
						watchers.tapDbl = null;
						this.dispatchEvent(type + "DblTap", e, component);
					} else watchers.tapDbl = setTimeout(() => {
						clearTimeout(watchers.tapDbl);
						watchers.tapDbl = null;
					}, 300);
					clearTimeout(watchers.tapHold);
					watchers.tapHold = null;
					break;
			}
		}
		dispatchEvent(action, e, component) {
			var componentObj = component.getComponent(), callback;
			if (this.columnSubscribers[action]) {
				if (component instanceof Cell) callback = component.column.definition[action];
				else if (component instanceof Column) callback = component.definition[action];
				if (callback) callback(e, componentObj);
			}
			this.dispatchExternal(action, e, componentObj);
		}
	};
	var defaultBindings = {
		navPrev: "shift + 9",
		navNext: 9,
		navUp: 38,
		navDown: 40,
		navLeft: 37,
		navRight: 39,
		scrollPageUp: 33,
		scrollPageDown: 34,
		scrollToStart: 36,
		scrollToEnd: 35
	};
	var defaultActions = {
		keyBlock: function(e) {
			e.stopPropagation();
			e.preventDefault();
		},
		scrollPageUp: function(e) {
			var rowManager = this.table.rowManager, newPos = rowManager.scrollTop - rowManager.element.clientHeight;
			e.preventDefault();
			if (rowManager.displayRowsCount) if (newPos >= 0) rowManager.element.scrollTop = newPos;
			else rowManager.scrollToRow(rowManager.getDisplayRows()[0]);
			this.table.element.focus();
		},
		scrollPageDown: function(e) {
			var rowManager = this.table.rowManager, newPos = rowManager.scrollTop + rowManager.element.clientHeight, scrollMax = rowManager.element.scrollHeight;
			e.preventDefault();
			if (rowManager.displayRowsCount) if (newPos <= scrollMax) rowManager.element.scrollTop = newPos;
			else rowManager.scrollToRow(rowManager.getDisplayRows()[rowManager.displayRowsCount - 1]);
			this.table.element.focus();
		},
		scrollToStart: function(e) {
			var rowManager = this.table.rowManager;
			e.preventDefault();
			if (rowManager.displayRowsCount) rowManager.scrollToRow(rowManager.getDisplayRows()[0]);
			this.table.element.focus();
		},
		scrollToEnd: function(e) {
			var rowManager = this.table.rowManager;
			e.preventDefault();
			if (rowManager.displayRowsCount) rowManager.scrollToRow(rowManager.getDisplayRows()[rowManager.displayRowsCount - 1]);
			this.table.element.focus();
		},
		navPrev: function(e) {
			this.dispatch("keybinding-nav-prev", e);
		},
		navNext: function(e) {
			this.dispatch("keybinding-nav-next", e);
		},
		navLeft: function(e) {
			this.dispatch("keybinding-nav-left", e);
		},
		navRight: function(e) {
			this.dispatch("keybinding-nav-right", e);
		},
		navUp: function(e) {
			this.dispatch("keybinding-nav-up", e);
		},
		navDown: function(e) {
			this.dispatch("keybinding-nav-down", e);
		}
	};
	var Keybindings = class Keybindings extends Module {
		static moduleName = "keybindings";
		static bindings = defaultBindings;
		static actions = defaultActions;
		constructor(table) {
			super(table);
			this.watchKeys = null;
			this.pressedKeys = null;
			this.keyupBinding = false;
			this.keydownBinding = false;
			this.registerTableOption("keybindings", {});
			this.registerTableOption("tabEndNewRow", false);
		}
		initialize() {
			var bindings = this.table.options.keybindings, mergedBindings = {};
			this.watchKeys = {};
			this.pressedKeys = [];
			if (bindings !== false) {
				Object.assign(mergedBindings, Keybindings.bindings);
				Object.assign(mergedBindings, bindings);
				this.mapBindings(mergedBindings);
				this.bindEvents();
			}
			this.subscribe("table-destroy", this.clearBindings.bind(this));
		}
		mapBindings(bindings) {
			for (let key in bindings) if (Keybindings.actions[key]) {
				if (bindings[key]) {
					if (typeof bindings[key] !== "object") bindings[key] = [bindings[key]];
					bindings[key].forEach((binding) => {
						(Array.isArray(binding) ? binding : [binding]).forEach((item) => {
							this.mapBinding(key, item);
						});
					});
				}
			} else console.warn("Key Binding Error - no such action:", key);
		}
		mapBinding(action, symbolsList) {
			var binding = {
				action: Keybindings.actions[action],
				keys: [],
				ctrl: false,
				shift: false,
				meta: false
			};
			symbolsList.toString().toLowerCase().split(" ").join("").split("+").forEach((symbol) => {
				switch (symbol) {
					case "ctrl":
						binding.ctrl = true;
						break;
					case "shift":
						binding.shift = true;
						break;
					case "meta":
						binding.meta = true;
						break;
					default:
						symbol = isNaN(symbol) ? symbol.toUpperCase().charCodeAt(0) : parseInt(symbol);
						binding.keys.push(symbol);
						if (!this.watchKeys[symbol]) this.watchKeys[symbol] = [];
						this.watchKeys[symbol].push(binding);
				}
			});
		}
		bindEvents() {
			var self = this;
			this.keyupBinding = function(e) {
				var code = e.keyCode;
				var bindings = self.watchKeys[code];
				if (bindings) {
					self.pressedKeys.push(code);
					bindings.forEach(function(binding) {
						self.checkBinding(e, binding);
					});
				}
			};
			this.keydownBinding = function(e) {
				var code = e.keyCode;
				if (self.watchKeys[code]) {
					var index = self.pressedKeys.indexOf(code);
					if (index > -1) self.pressedKeys.splice(index, 1);
				}
			};
			this.table.element.addEventListener("keydown", this.keyupBinding);
			this.table.element.addEventListener("keyup", this.keydownBinding);
		}
		clearBindings() {
			if (this.keyupBinding) this.table.element.removeEventListener("keydown", this.keyupBinding);
			if (this.keydownBinding) this.table.element.removeEventListener("keyup", this.keydownBinding);
		}
		checkBinding(e, binding) {
			var match = true;
			if (e.ctrlKey == binding.ctrl && e.shiftKey == binding.shift && e.metaKey == binding.meta) {
				binding.keys.forEach((key) => {
					if (this.pressedKeys.indexOf(key) == -1) match = false;
				});
				if (match) binding.action.call(this, e);
				return true;
			}
			return false;
		}
	};
	var Menu = class extends Module {
		static moduleName = "menu";
		constructor(table) {
			super(table);
			this.menuContainer = null;
			this.nestedMenuBlock = false;
			this.currentComponent = null;
			this.rootPopup = null;
			this.columnSubscribers = {};
			this.registerTableOption("rowContextMenu", false);
			this.registerTableOption("rowClickMenu", false);
			this.registerTableOption("rowDblClickMenu", false);
			this.registerTableOption("groupContextMenu", false);
			this.registerTableOption("groupClickMenu", false);
			this.registerTableOption("groupDblClickMenu", false);
			this.registerColumnOption("headerContextMenu");
			this.registerColumnOption("headerClickMenu");
			this.registerColumnOption("headerDblClickMenu");
			this.registerColumnOption("headerMenu");
			this.registerColumnOption("headerMenuIcon");
			this.registerColumnOption("contextMenu");
			this.registerColumnOption("clickMenu");
			this.registerColumnOption("dblClickMenu");
		}
		initialize() {
			this.deprecatedOptionsCheck();
			this.initializeRowWatchers();
			this.initializeGroupWatchers();
			this.subscribe("column-init", this.initializeColumn.bind(this));
		}
		deprecatedOptionsCheck() {}
		initializeRowWatchers() {
			if (this.table.options.rowContextMenu) {
				this.subscribe("row-contextmenu", this.loadMenuEvent.bind(this, this.table.options.rowContextMenu));
				this.table.on("rowTapHold", this.loadMenuEvent.bind(this, this.table.options.rowContextMenu));
			}
			if (this.table.options.rowClickMenu) this.subscribe("row-click", this.loadMenuEvent.bind(this, this.table.options.rowClickMenu));
			if (this.table.options.rowDblClickMenu) this.subscribe("row-dblclick", this.loadMenuEvent.bind(this, this.table.options.rowDblClickMenu));
		}
		initializeGroupWatchers() {
			if (this.table.options.groupContextMenu) {
				this.subscribe("group-contextmenu", this.loadMenuEvent.bind(this, this.table.options.groupContextMenu));
				this.table.on("groupTapHold", this.loadMenuEvent.bind(this, this.table.options.groupContextMenu));
			}
			if (this.table.options.groupClickMenu) this.subscribe("group-click", this.loadMenuEvent.bind(this, this.table.options.groupClickMenu));
			if (this.table.options.groupDblClickMenu) this.subscribe("group-dblclick", this.loadMenuEvent.bind(this, this.table.options.groupDblClickMenu));
		}
		initializeColumn(column) {
			var def = column.definition;
			if (def.headerContextMenu && !this.columnSubscribers.headerContextMenu) {
				this.columnSubscribers.headerContextMenu = this.loadMenuTableColumnEvent.bind(this, "headerContextMenu");
				this.subscribe("column-contextmenu", this.columnSubscribers.headerContextMenu);
				this.table.on("headerTapHold", this.loadMenuTableColumnEvent.bind(this, "headerContextMenu"));
			}
			if (def.headerClickMenu && !this.columnSubscribers.headerClickMenu) {
				this.columnSubscribers.headerClickMenu = this.loadMenuTableColumnEvent.bind(this, "headerClickMenu");
				this.subscribe("column-click", this.columnSubscribers.headerClickMenu);
			}
			if (def.headerDblClickMenu && !this.columnSubscribers.headerDblClickMenu) {
				this.columnSubscribers.headerDblClickMenu = this.loadMenuTableColumnEvent.bind(this, "headerDblClickMenu");
				this.subscribe("column-dblclick", this.columnSubscribers.headerDblClickMenu);
			}
			if (def.headerMenu) this.initializeColumnHeaderMenu(column);
			if (def.contextMenu && !this.columnSubscribers.contextMenu) {
				this.columnSubscribers.contextMenu = this.loadMenuTableCellEvent.bind(this, "contextMenu");
				this.subscribe("cell-contextmenu", this.columnSubscribers.contextMenu);
				this.table.on("cellTapHold", this.loadMenuTableCellEvent.bind(this, "contextMenu"));
			}
			if (def.clickMenu && !this.columnSubscribers.clickMenu) {
				this.columnSubscribers.clickMenu = this.loadMenuTableCellEvent.bind(this, "clickMenu");
				this.subscribe("cell-click", this.columnSubscribers.clickMenu);
			}
			if (def.dblClickMenu && !this.columnSubscribers.dblClickMenu) {
				this.columnSubscribers.dblClickMenu = this.loadMenuTableCellEvent.bind(this, "dblClickMenu");
				this.subscribe("cell-dblclick", this.columnSubscribers.dblClickMenu);
			}
		}
		initializeColumnHeaderMenu(column) {
			var icon = column.definition.headerMenuIcon, headerMenuEl = document.createElement("span");
			headerMenuEl.classList.add("tabulator-header-popup-button");
			if (icon) {
				if (typeof icon === "function") icon = icon(column.getComponent());
				if (icon instanceof HTMLElement) headerMenuEl.appendChild(icon);
				else headerMenuEl.innerHTML = icon;
			} else headerMenuEl.innerHTML = "&vellip;";
			headerMenuEl.addEventListener("click", (e) => {
				e.stopPropagation();
				e.preventDefault();
				this.loadMenuEvent(column.definition.headerMenu, e, column);
			});
			column.titleElement.insertBefore(headerMenuEl, column.titleElement.firstChild);
		}
		loadMenuTableCellEvent(option, e, cell) {
			if (cell._cell) cell = cell._cell;
			if (cell.column.definition[option]) this.loadMenuEvent(cell.column.definition[option], e, cell);
		}
		loadMenuTableColumnEvent(option, e, column) {
			if (column._column) column = column._column;
			if (column.definition[option]) this.loadMenuEvent(column.definition[option], e, column);
		}
		loadMenuEvent(menu, e, component) {
			if (component._group) component = component._group;
			else if (component._row) component = component._row;
			menu = typeof menu == "function" ? menu.call(this.table, e, component.getComponent()) : menu;
			this.loadMenu(e, component, menu);
		}
		loadMenu(e, component, menu, parentEl, parentPopup) {
			var touch = !(e instanceof MouseEvent), menuEl = document.createElement("div"), popup;
			menuEl.classList.add("tabulator-menu");
			if (!touch) e.preventDefault();
			if (!menu || !menu.length) return;
			if (!parentEl) {
				if (this.nestedMenuBlock) {
					if (this.rootPopup) return;
				} else this.nestedMenuBlock = setTimeout(() => {
					this.nestedMenuBlock = false;
				}, 100);
				if (this.rootPopup) this.rootPopup.hide();
				this.rootPopup = popup = this.popup(menuEl);
			} else popup = parentPopup.child(menuEl);
			menu.forEach((item) => {
				var itemEl = document.createElement("div"), label = item.label, disabled = item.disabled;
				if (item.separator) itemEl.classList.add("tabulator-menu-separator");
				else {
					itemEl.classList.add("tabulator-menu-item");
					if (typeof label == "function") label = label.call(this.table, component.getComponent());
					if (label instanceof Node) itemEl.appendChild(label);
					else itemEl.innerHTML = label;
					if (typeof disabled == "function") disabled = disabled.call(this.table, component.getComponent());
					if (disabled) {
						itemEl.classList.add("tabulator-menu-item-disabled");
						itemEl.addEventListener("click", (e) => {
							e.stopPropagation();
						});
					} else if (item.menu && item.menu.length) itemEl.addEventListener("click", (e) => {
						e.stopPropagation();
						this.loadMenu(e, component, item.menu, itemEl, popup);
					});
					else if (item.action) itemEl.addEventListener("click", (e) => {
						item.action(e, component.getComponent());
					});
					if (item.menu && item.menu.length) itemEl.classList.add("tabulator-menu-item-submenu");
				}
				menuEl.appendChild(itemEl);
			});
			menuEl.addEventListener("click", (e) => {
				if (this.rootPopup) this.rootPopup.hide();
			});
			popup.show(parentEl || e);
			if (popup === this.rootPopup) {
				this.rootPopup.hideOnBlur(() => {
					this.rootPopup = null;
					if (this.currentComponent) {
						this.dispatch("menu-closed", menu, popup);
						this.dispatchExternal("menuClosed", this.currentComponent.getComponent());
						this.currentComponent = null;
					}
				});
				this.currentComponent = component;
				this.dispatch("menu-opened", menu, popup);
				this.dispatchExternal("menuOpened", component.getComponent());
			}
		}
	};
	var MoveColumns = class extends Module {
		static moduleName = "moveColumn";
		constructor(table) {
			super(table);
			this.placeholderElement = this.createPlaceholderElement();
			this.hoverElement = false;
			this.checkTimeout = false;
			this.checkPeriod = 250;
			this.moving = false;
			this.toCol = false;
			this.toColAfter = false;
			this.startX = 0;
			this.autoScrollMargin = 40;
			this.autoScrollStep = 5;
			this.autoScrollTimeout = false;
			this.touchMove = false;
			this.moveHover = this.moveHover.bind(this);
			this.endMove = this.endMove.bind(this);
			this.registerTableOption("movableColumns", false);
		}
		createPlaceholderElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-col");
			el.classList.add("tabulator-col-placeholder");
			return el;
		}
		initialize() {
			if (this.table.options.movableColumns) {
				this.subscribe("column-init", this.initializeColumn.bind(this));
				this.subscribe("alert-show", this.abortMove.bind(this));
			}
		}
		abortMove() {
			clearTimeout(this.checkTimeout);
		}
		initializeColumn(column) {
			var self = this, config = {}, colEl;
			if (!column.modules.frozen && !column.isGroup && !column.isRowHeader) {
				colEl = column.getElement();
				config.mousemove = function(e) {
					if (column.parent === self.moving.parent) {
						if ((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left + self.table.columnManager.contentsElement.scrollLeft > column.getWidth() / 2) {
							if (self.toCol !== column || !self.toColAfter) {
								colEl.parentNode.insertBefore(self.placeholderElement, colEl.nextSibling);
								self.moveColumn(column, true);
							}
						} else if (self.toCol !== column || self.toColAfter) {
							colEl.parentNode.insertBefore(self.placeholderElement, colEl);
							self.moveColumn(column, false);
						}
					}
				}.bind(self);
				colEl.addEventListener("mousedown", function(e) {
					self.touchMove = false;
					if (e.which === 1) self.checkTimeout = setTimeout(function() {
						self.startMove(e, column);
					}, self.checkPeriod);
				});
				colEl.addEventListener("mouseup", function(e) {
					if (e.which === 1) {
						if (self.checkTimeout) clearTimeout(self.checkTimeout);
					}
				});
				self.bindTouchEvents(column);
			}
			column.modules.moveColumn = config;
		}
		bindTouchEvents(column) {
			var colEl = column.getElement(), startXMove = false, nextCol, prevCol, nextColWidth, prevColWidth, nextColWidthLast, prevColWidthLast;
			colEl.addEventListener("touchstart", (e) => {
				this.checkTimeout = setTimeout(() => {
					this.touchMove = true;
					nextCol = column.nextColumn();
					nextColWidth = nextCol ? nextCol.getWidth() / 2 : 0;
					prevCol = column.prevColumn();
					prevColWidth = prevCol ? prevCol.getWidth() / 2 : 0;
					nextColWidthLast = 0;
					prevColWidthLast = 0;
					startXMove = false;
					this.startMove(e, column);
				}, this.checkPeriod);
			}, { passive: true });
			colEl.addEventListener("touchmove", (e) => {
				var diff, moveToCol;
				if (this.moving) {
					this.moveHover(e);
					if (!startXMove) startXMove = e.touches[0].pageX;
					diff = e.touches[0].pageX - startXMove;
					if (diff > 0) {
						if (nextCol && diff - nextColWidthLast > nextColWidth) {
							moveToCol = nextCol;
							if (moveToCol !== column) {
								startXMove = e.touches[0].pageX;
								moveToCol.getElement().parentNode.insertBefore(this.placeholderElement, moveToCol.getElement().nextSibling);
								this.moveColumn(moveToCol, true);
							}
						}
					} else if (prevCol && -diff - prevColWidthLast > prevColWidth) {
						moveToCol = prevCol;
						if (moveToCol !== column) {
							startXMove = e.touches[0].pageX;
							moveToCol.getElement().parentNode.insertBefore(this.placeholderElement, moveToCol.getElement());
							this.moveColumn(moveToCol, false);
						}
					}
					if (moveToCol) {
						nextCol = moveToCol.nextColumn();
						nextColWidthLast = nextColWidth;
						nextColWidth = nextCol ? nextCol.getWidth() / 2 : 0;
						prevCol = moveToCol.prevColumn();
						prevColWidthLast = prevColWidth;
						prevColWidth = prevCol ? prevCol.getWidth() / 2 : 0;
					}
				}
			}, { passive: true });
			colEl.addEventListener("touchend", (e) => {
				if (this.checkTimeout) clearTimeout(this.checkTimeout);
				if (this.moving) this.endMove(e);
			});
		}
		startMove(e, column) {
			var element = column.getElement(), headerElement = this.table.columnManager.getContentsElement(), headersElement = this.table.columnManager.getHeadersElement();
			if (this.table.modules.selectRange && this.table.modules.selectRange.columnSelection) {
				if (this.table.modules.selectRange.mousedown && this.table.modules.selectRange.selecting === "column") return;
			}
			this.moving = column;
			this.startX = (this.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(element).left;
			this.table.element.classList.add("tabulator-block-select");
			this.placeholderElement.style.width = column.getWidth() + "px";
			this.placeholderElement.style.height = column.getHeight() + "px";
			element.parentNode.insertBefore(this.placeholderElement, element);
			element.parentNode.removeChild(element);
			this.hoverElement = element.cloneNode(true);
			this.hoverElement.classList.add("tabulator-moving");
			headerElement.appendChild(this.hoverElement);
			this.hoverElement.style.left = "0";
			this.hoverElement.style.bottom = headerElement.clientHeight - headersElement.offsetHeight + "px";
			if (!this.touchMove) {
				this._bindMouseMove();
				document.body.addEventListener("mousemove", this.moveHover);
				document.body.addEventListener("mouseup", this.endMove);
			}
			this.moveHover(e);
			this.dispatch("column-moving", e, this.moving);
		}
		_bindMouseMove() {
			this.table.columnManager.columnsByIndex.forEach(function(column) {
				if (column.modules.moveColumn.mousemove) column.getElement().addEventListener("mousemove", column.modules.moveColumn.mousemove);
			});
		}
		_unbindMouseMove() {
			this.table.columnManager.columnsByIndex.forEach(function(column) {
				if (column.modules.moveColumn.mousemove) column.getElement().removeEventListener("mousemove", column.modules.moveColumn.mousemove);
			});
		}
		moveColumn(column, after) {
			var movingCells = this.moving.getCells();
			this.toCol = column;
			this.toColAfter = after;
			if (after) column.getCells().forEach(function(cell, i) {
				var cellEl = cell.getElement(true);
				if (cellEl.parentNode && movingCells[i]) cellEl.parentNode.insertBefore(movingCells[i].getElement(), cellEl.nextSibling);
			});
			else column.getCells().forEach(function(cell, i) {
				var cellEl = cell.getElement(true);
				if (cellEl.parentNode && movingCells[i]) cellEl.parentNode.insertBefore(movingCells[i].getElement(), cellEl);
			});
		}
		endMove(e) {
			if (e.which === 1 || this.touchMove) {
				this._unbindMouseMove();
				this.placeholderElement.parentNode.insertBefore(this.moving.getElement(), this.placeholderElement.nextSibling);
				this.placeholderElement.parentNode.removeChild(this.placeholderElement);
				this.hoverElement.parentNode.removeChild(this.hoverElement);
				this.table.element.classList.remove("tabulator-block-select");
				if (this.toCol) this.table.columnManager.moveColumnActual(this.moving, this.toCol, this.toColAfter);
				this.moving = false;
				this.toCol = false;
				this.toColAfter = false;
				if (!this.touchMove) {
					document.body.removeEventListener("mousemove", this.moveHover);
					document.body.removeEventListener("mouseup", this.endMove);
				}
			}
		}
		moveHover(e) {
			var columnHolder = this.table.columnManager.getContentsElement(), scrollLeft = columnHolder.scrollLeft, xPos = (this.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(columnHolder).left + scrollLeft, scrollPos;
			this.hoverElement.style.left = xPos - this.startX + "px";
			if (xPos - scrollLeft < this.autoScrollMargin) {
				if (!this.autoScrollTimeout) this.autoScrollTimeout = setTimeout(() => {
					scrollPos = Math.max(0, scrollLeft - 5);
					this.table.rowManager.getElement().scrollLeft = scrollPos;
					this.autoScrollTimeout = false;
				}, 1);
			}
			if (scrollLeft + columnHolder.clientWidth - xPos < this.autoScrollMargin) {
				if (!this.autoScrollTimeout) this.autoScrollTimeout = setTimeout(() => {
					scrollPos = Math.min(columnHolder.clientWidth, scrollLeft + 5);
					this.table.rowManager.getElement().scrollLeft = scrollPos;
					this.autoScrollTimeout = false;
				}, 1);
			}
		}
	};
	var defaultSenders = { delete: function(fromRow, toRow, toTable) {
		fromRow.delete();
	} };
	var defaultReceivers = {
		insert: function(fromRow, toRow, fromTable) {
			this.table.addRow(fromRow.getData(), void 0, toRow);
			return true;
		},
		add: function(fromRow, toRow, fromTable) {
			this.table.addRow(fromRow.getData());
			return true;
		},
		update: function(fromRow, toRow, fromTable) {
			if (toRow) {
				toRow.update(fromRow.getData());
				return true;
			}
			return false;
		},
		replace: function(fromRow, toRow, fromTable) {
			if (toRow) {
				this.table.addRow(fromRow.getData(), void 0, toRow);
				toRow.delete();
				return true;
			}
			return false;
		}
	};
	var MoveRows = class MoveRows extends Module {
		static moduleName = "moveRow";
		static senders = defaultSenders;
		static receivers = defaultReceivers;
		constructor(table) {
			super(table);
			this.placeholderElement = this.createPlaceholderElement();
			this.hoverElement = false;
			this.checkTimeout = false;
			this.checkPeriod = 150;
			this.moving = false;
			this.toRow = false;
			this.toRowAfter = false;
			this.hasHandle = false;
			this.startY = 0;
			this.startX = 0;
			this.moveHover = this.moveHover.bind(this);
			this.endMove = this.endMove.bind(this);
			this.tableRowDropEvent = false;
			this.touchMove = false;
			this.connection = false;
			this.connectionSelectorsTables = false;
			this.connectionSelectorsElements = false;
			this.connectionElements = [];
			this.connections = [];
			this.connectedTable = false;
			this.connectedRow = false;
			this.registerTableOption("movableRows", false);
			this.registerTableOption("movableRowsConnectedTables", false);
			this.registerTableOption("movableRowsConnectedElements", false);
			this.registerTableOption("movableRowsSender", false);
			this.registerTableOption("movableRowsReceiver", "insert");
			this.registerColumnOption("rowHandle");
		}
		createPlaceholderElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-row");
			el.classList.add("tabulator-row-placeholder");
			return el;
		}
		initialize() {
			if (this.table.options.movableRows) {
				this.connectionSelectorsTables = this.table.options.movableRowsConnectedTables;
				this.connectionSelectorsElements = this.table.options.movableRowsConnectedElements;
				this.connection = this.connectionSelectorsTables || this.connectionSelectorsElements;
				this.subscribe("cell-init", this.initializeCell.bind(this));
				this.subscribe("column-init", this.initializeColumn.bind(this));
				this.subscribe("row-init", this.initializeRow.bind(this));
			}
		}
		initializeGroupHeader(group) {
			var self = this, config = {};
			config.mouseup = function(e) {
				self.tableRowDrop(e, group);
			}.bind(self);
			config.mousemove = function(e) {
				var rowEl;
				if (e.pageY - Helpers.elOffset(group.element).top + self.table.rowManager.element.scrollTop > group.getHeight() / 2) {
					if (self.toRow !== group || !self.toRowAfter) {
						rowEl = group.getElement();
						rowEl.parentNode.insertBefore(self.placeholderElement, rowEl.nextSibling);
						self.moveRow(group, true);
					}
				} else if (self.toRow !== group || self.toRowAfter) {
					rowEl = group.getElement();
					if (rowEl.previousSibling) {
						rowEl.parentNode.insertBefore(self.placeholderElement, rowEl);
						self.moveRow(group, false);
					}
				}
			}.bind(self);
			group.modules.moveRow = config;
		}
		initializeRow(row) {
			var self = this, config = {}, rowEl;
			config.mouseup = function(e) {
				self.tableRowDrop(e, row);
			}.bind(self);
			config.mousemove = function(e) {
				var rowEl = row.getElement();
				if (e.pageY - Helpers.elOffset(rowEl).top + self.table.rowManager.element.scrollTop > row.getHeight() / 2) {
					if (self.toRow !== row || !self.toRowAfter) {
						rowEl.parentNode.insertBefore(self.placeholderElement, rowEl.nextSibling);
						self.moveRow(row, true);
					}
				} else if (self.toRow !== row || self.toRowAfter) {
					rowEl.parentNode.insertBefore(self.placeholderElement, rowEl);
					self.moveRow(row, false);
				}
			}.bind(self);
			if (!this.hasHandle) {
				rowEl = row.getElement();
				rowEl.addEventListener("mousedown", function(e) {
					if (e.which === 1) self.checkTimeout = setTimeout(function() {
						self.startMove(e, row);
					}, self.checkPeriod);
				});
				rowEl.addEventListener("mouseup", function(e) {
					if (e.which === 1) {
						if (self.checkTimeout) clearTimeout(self.checkTimeout);
					}
				});
				this.bindTouchEvents(row, row.getElement());
			}
			row.modules.moveRow = config;
		}
		initializeColumn(column) {
			if (column.definition.rowHandle && this.table.options.movableRows !== false) this.hasHandle = true;
		}
		initializeCell(cell) {
			if (cell.column.definition.rowHandle && this.table.options.movableRows !== false) {
				var self = this, cellEl = cell.getElement(true);
				cellEl.addEventListener("mousedown", function(e) {
					if (e.which === 1) self.checkTimeout = setTimeout(function() {
						self.startMove(e, cell.row);
					}, self.checkPeriod);
				});
				cellEl.addEventListener("mouseup", function(e) {
					if (e.which === 1) {
						if (self.checkTimeout) clearTimeout(self.checkTimeout);
					}
				});
				this.bindTouchEvents(cell.row, cellEl);
			}
		}
		bindTouchEvents(row, element) {
			var startYMove = false, nextRow, prevRow, nextRowHeight, prevRowHeight, nextRowHeightLast, prevRowHeightLast;
			element.addEventListener("touchstart", (e) => {
				this.checkTimeout = setTimeout(() => {
					this.touchMove = true;
					nextRow = row.nextRow();
					nextRowHeight = nextRow ? nextRow.getHeight() / 2 : 0;
					prevRow = row.prevRow();
					prevRowHeight = prevRow ? prevRow.getHeight() / 2 : 0;
					nextRowHeightLast = 0;
					prevRowHeightLast = 0;
					startYMove = false;
					this.startMove(e, row);
				}, this.checkPeriod);
			}, { passive: true });
			this.moving, this.toRow, this.toRowAfter;
			element.addEventListener("touchmove", (e) => {
				var diff, moveToRow;
				if (this.moving) {
					e.preventDefault();
					this.moveHover(e);
					if (!startYMove) startYMove = e.touches[0].pageY;
					diff = e.touches[0].pageY - startYMove;
					if (diff > 0) {
						if (nextRow && diff - nextRowHeightLast > nextRowHeight) {
							moveToRow = nextRow;
							if (moveToRow !== row) {
								startYMove = e.touches[0].pageY;
								moveToRow.getElement().parentNode.insertBefore(this.placeholderElement, moveToRow.getElement().nextSibling);
								this.moveRow(moveToRow, true);
							}
						}
					} else if (prevRow && -diff - prevRowHeightLast > prevRowHeight) {
						moveToRow = prevRow;
						if (moveToRow !== row) {
							startYMove = e.touches[0].pageY;
							moveToRow.getElement().parentNode.insertBefore(this.placeholderElement, moveToRow.getElement());
							this.moveRow(moveToRow, false);
						}
					}
					if (moveToRow) {
						nextRow = moveToRow.nextRow();
						nextRowHeightLast = nextRowHeight;
						nextRowHeight = nextRow ? nextRow.getHeight() / 2 : 0;
						prevRow = moveToRow.prevRow();
						prevRowHeightLast = prevRowHeight;
						prevRowHeight = prevRow ? prevRow.getHeight() / 2 : 0;
					}
				}
			});
			element.addEventListener("touchend", (e) => {
				if (this.checkTimeout) clearTimeout(this.checkTimeout);
				if (this.moving) {
					this.endMove(e);
					this.touchMove = false;
				}
			});
		}
		_bindMouseMove() {
			this.table.rowManager.getDisplayRows().forEach((row) => {
				if ((row.type === "row" || row.type === "group") && row.modules.moveRow && row.modules.moveRow.mousemove) row.getElement().addEventListener("mousemove", row.modules.moveRow.mousemove);
			});
		}
		_unbindMouseMove() {
			this.table.rowManager.getDisplayRows().forEach((row) => {
				if ((row.type === "row" || row.type === "group") && row.modules.moveRow && row.modules.moveRow.mousemove) row.getElement().removeEventListener("mousemove", row.modules.moveRow.mousemove);
			});
		}
		startMove(e, row) {
			var element = row.getElement();
			this.setStartPosition(e, row);
			this.moving = row;
			this.table.element.classList.add("tabulator-block-select");
			this.placeholderElement.style.width = row.getWidth() + "px";
			this.placeholderElement.style.height = row.getHeight() + "px";
			if (!this.connection) {
				element.parentNode.insertBefore(this.placeholderElement, element);
				element.parentNode.removeChild(element);
			} else {
				this.table.element.classList.add("tabulator-movingrow-sending");
				this.connectToTables(row);
			}
			this.hoverElement = element.cloneNode(true);
			this.hoverElement.classList.add("tabulator-moving");
			if (this.connection) {
				document.body.appendChild(this.hoverElement);
				this.hoverElement.style.left = "0";
				this.hoverElement.style.top = "0";
				this.hoverElement.style.width = this.table.element.clientWidth + "px";
				this.hoverElement.style.whiteSpace = "nowrap";
				this.hoverElement.style.overflow = "hidden";
				this.hoverElement.style.pointerEvents = "none";
			} else {
				this.table.rowManager.getTableElement().appendChild(this.hoverElement);
				this.hoverElement.style.left = "0";
				this.hoverElement.style.top = "0";
				this._bindMouseMove();
			}
			document.body.addEventListener("mousemove", this.moveHover);
			document.body.addEventListener("mouseup", this.endMove);
			this.dispatchExternal("rowMoving", row.getComponent());
			this.moveHover(e);
		}
		setStartPosition(e, row) {
			var pageX = this.touchMove ? e.touches[0].pageX : e.pageX, pageY = this.touchMove ? e.touches[0].pageY : e.pageY, element = row.getElement(), position;
			if (this.connection) {
				position = element.getBoundingClientRect();
				this.startX = position.left - pageX + window.pageXOffset;
				this.startY = position.top - pageY + window.pageYOffset;
			} else this.startY = pageY - element.getBoundingClientRect().top;
		}
		endMove(e) {
			if (!e || e.which === 1 || this.touchMove) {
				this._unbindMouseMove();
				if (!this.connection) {
					this.placeholderElement.parentNode.insertBefore(this.moving.getElement(), this.placeholderElement.nextSibling);
					this.placeholderElement.parentNode.removeChild(this.placeholderElement);
				}
				this.hoverElement.parentNode.removeChild(this.hoverElement);
				this.table.element.classList.remove("tabulator-block-select");
				if (this.toRow) this.table.rowManager.moveRow(this.moving, this.toRow, this.toRowAfter);
				else this.dispatchExternal("rowMoveCancelled", this.moving.getComponent());
				this.moving = false;
				this.toRow = false;
				this.toRowAfter = false;
				document.body.removeEventListener("mousemove", this.moveHover);
				document.body.removeEventListener("mouseup", this.endMove);
				if (this.connection) {
					this.table.element.classList.remove("tabulator-movingrow-sending");
					this.disconnectFromTables();
				}
			}
		}
		moveRow(row, after) {
			this.toRow = row;
			this.toRowAfter = after;
		}
		moveHover(e) {
			if (this.connection) this.moveHoverConnections.call(this, e);
			else this.moveHoverTable.call(this, e);
		}
		moveHoverTable(e) {
			var rowHolder = this.table.rowManager.getElement(), scrollTop = rowHolder.scrollTop, yPos = (this.touchMove ? e.touches[0].pageY : e.pageY) - rowHolder.getBoundingClientRect().top + scrollTop;
			this.hoverElement.style.top = Math.min(yPos - this.startY, this.table.rowManager.element.scrollHeight - this.hoverElement.offsetHeight) + "px";
		}
		moveHoverConnections(e) {
			this.hoverElement.style.left = this.startX + (this.touchMove ? e.touches[0].pageX : e.pageX) + "px";
			this.hoverElement.style.top = this.startY + (this.touchMove ? e.touches[0].pageY : e.pageY) + "px";
		}
		elementRowDrop(e, element, row) {
			this.dispatchExternal("movableRowsElementDrop", e, element, row ? row.getComponent() : false);
		}
		connectToTables(row) {
			var connectionTables;
			if (this.connectionSelectorsTables) {
				connectionTables = this.commsConnections(this.connectionSelectorsTables);
				this.dispatchExternal("movableRowsSendingStart", connectionTables);
				this.commsSend(this.connectionSelectorsTables, "moveRow", "connect", { row });
			}
			if (this.connectionSelectorsElements) {
				this.connectionElements = [];
				if (!Array.isArray(this.connectionSelectorsElements)) this.connectionSelectorsElements = [this.connectionSelectorsElements];
				this.connectionSelectorsElements.forEach((query) => {
					if (typeof query === "string") this.connectionElements = this.connectionElements.concat(Array.prototype.slice.call(document.querySelectorAll(query)));
					else this.connectionElements.push(query);
				});
				this.connectionElements.forEach((element) => {
					var dropEvent = (e) => {
						this.elementRowDrop(e, element, this.moving);
					};
					element.addEventListener("mouseup", dropEvent);
					element.tabulatorElementDropEvent = dropEvent;
					element.classList.add("tabulator-movingrow-receiving");
				});
			}
		}
		disconnectFromTables() {
			var connectionTables;
			if (this.connectionSelectorsTables) {
				connectionTables = this.commsConnections(this.connectionSelectorsTables);
				this.dispatchExternal("movableRowsSendingStop", connectionTables);
				this.commsSend(this.connectionSelectorsTables, "moveRow", "disconnect");
			}
			this.connectionElements.forEach((element) => {
				element.classList.remove("tabulator-movingrow-receiving");
				element.removeEventListener("mouseup", element.tabulatorElementDropEvent);
				delete element.tabulatorElementDropEvent;
			});
		}
		connect(table, row) {
			if (!this.connectedTable) {
				this.connectedTable = table;
				this.connectedRow = row;
				this.table.element.classList.add("tabulator-movingrow-receiving");
				this.table.rowManager.getDisplayRows().forEach((row) => {
					if (row.type === "row" && row.modules.moveRow && row.modules.moveRow.mouseup) row.getElement().addEventListener("mouseup", row.modules.moveRow.mouseup);
				});
				this.tableRowDropEvent = this.tableRowDrop.bind(this);
				this.table.element.addEventListener("mouseup", this.tableRowDropEvent);
				this.dispatchExternal("movableRowsReceivingStart", row, table);
				return true;
			} else {
				console.warn("Move Row Error - Table cannot accept connection, already connected to table:", this.connectedTable);
				return false;
			}
		}
		disconnect(table) {
			if (table === this.connectedTable) {
				this.connectedTable = false;
				this.connectedRow = false;
				this.table.element.classList.remove("tabulator-movingrow-receiving");
				this.table.rowManager.getDisplayRows().forEach((row) => {
					if (row.type === "row" && row.modules.moveRow && row.modules.moveRow.mouseup) row.getElement().removeEventListener("mouseup", row.modules.moveRow.mouseup);
				});
				this.table.element.removeEventListener("mouseup", this.tableRowDropEvent);
				this.dispatchExternal("movableRowsReceivingStop", table);
			} else console.warn("Move Row Error - trying to disconnect from non connected table");
		}
		dropComplete(table, row, success) {
			var sender = false;
			if (success) {
				switch (typeof this.table.options.movableRowsSender) {
					case "string":
						sender = MoveRows.senders[this.table.options.movableRowsSender];
						break;
					case "function":
						sender = this.table.options.movableRowsSender;
						break;
				}
				if (sender) sender.call(this, this.moving ? this.moving.getComponent() : void 0, row ? row.getComponent() : void 0, table);
				else if (this.table.options.movableRowsSender) console.warn("Mover Row Error - no matching sender found:", this.table.options.movableRowsSender);
				this.dispatchExternal("movableRowsSent", this.moving.getComponent(), row ? row.getComponent() : void 0, table);
			} else this.dispatchExternal("movableRowsSentFailed", this.moving.getComponent(), row ? row.getComponent() : void 0, table);
			this.endMove();
		}
		tableRowDrop(e, row) {
			var receiver = false, success = false;
			e.stopImmediatePropagation();
			switch (typeof this.table.options.movableRowsReceiver) {
				case "string":
					receiver = MoveRows.receivers[this.table.options.movableRowsReceiver];
					break;
				case "function":
					receiver = this.table.options.movableRowsReceiver;
					break;
			}
			if (receiver) success = receiver.call(this, this.connectedRow.getComponent(), row ? row.getComponent() : void 0, this.connectedTable);
			else console.warn("Mover Row Error - no matching receiver found:", this.table.options.movableRowsReceiver);
			if (success) this.dispatchExternal("movableRowsReceived", this.connectedRow.getComponent(), row ? row.getComponent() : void 0, this.connectedTable);
			else this.dispatchExternal("movableRowsReceivedFailed", this.connectedRow.getComponent(), row ? row.getComponent() : void 0, this.connectedTable);
			this.commsSend(this.connectedTable, "moveRow", "dropcomplete", {
				row,
				success
			});
		}
		commsReceived(table, action, data) {
			switch (action) {
				case "connect": return this.connect(table, data.row);
				case "disconnect": return this.disconnect(table);
				case "dropcomplete": return this.dropComplete(table, data.row, data.success);
			}
		}
	};
	var defaultMutators = {};
	var Mutator = class Mutator extends Module {
		static moduleName = "mutator";
		static mutators = defaultMutators;
		constructor(table) {
			super(table);
			this.allowedTypes = [
				"",
				"data",
				"edit",
				"clipboard",
				"import"
			];
			this.enabled = true;
			this.registerColumnOption("mutator");
			this.registerColumnOption("mutatorParams");
			this.registerColumnOption("mutatorData");
			this.registerColumnOption("mutatorDataParams");
			this.registerColumnOption("mutatorEdit");
			this.registerColumnOption("mutatorEditParams");
			this.registerColumnOption("mutatorClipboard");
			this.registerColumnOption("mutatorClipboardParams");
			this.registerColumnOption("mutatorImport");
			this.registerColumnOption("mutatorImportParams");
			this.registerColumnOption("mutateLink");
		}
		initialize() {
			this.subscribe("cell-value-changing", this.transformCell.bind(this));
			this.subscribe("cell-value-changed", this.mutateLink.bind(this));
			this.subscribe("column-layout", this.initializeColumn.bind(this));
			this.subscribe("row-data-init-before", this.rowDataChanged.bind(this));
			this.subscribe("row-data-changing", this.rowDataChanged.bind(this));
		}
		rowDataChanged(row, tempData, updatedData) {
			return this.transformRow(tempData, "data", updatedData);
		}
		initializeColumn(column) {
			var match = false, config = {};
			this.allowedTypes.forEach((type) => {
				var key = "mutator" + (type.charAt(0).toUpperCase() + type.slice(1)), mutator;
				if (column.definition[key]) {
					mutator = this.lookupMutator(column.definition[key]);
					if (mutator) {
						match = true;
						config[key] = {
							mutator,
							params: column.definition[key + "Params"] || {}
						};
					}
				}
			});
			if (match) column.modules.mutate = config;
		}
		lookupMutator(value) {
			var mutator = false;
			switch (typeof value) {
				case "string":
					if (Mutator.mutators[value]) mutator = Mutator.mutators[value];
					else console.warn("Mutator Error - No such mutator found, ignoring: ", value);
					break;
				case "function":
					mutator = value;
					break;
			}
			return mutator;
		}
		transformRow(data, type, updatedData) {
			var key = "mutator" + (type.charAt(0).toUpperCase() + type.slice(1)), value;
			if (this.enabled) this.table.columnManager.traverse((column) => {
				var mutator, params, component;
				if (column.modules.mutate) {
					mutator = column.modules.mutate[key] || column.modules.mutate.mutator || false;
					if (mutator) {
						value = column.getFieldValue(typeof updatedData !== "undefined" ? updatedData : data);
						if (type == "data" && !updatedData || typeof value !== "undefined") {
							component = column.getComponent();
							params = typeof mutator.params === "function" ? mutator.params(value, data, type, component) : mutator.params;
							column.setFieldValue(data, mutator.mutator(value, data, type, params, component));
						}
					}
				}
			});
			return data;
		}
		transformCell(cell, value) {
			if (cell.column.modules.mutate) {
				var mutator = cell.column.modules.mutate.mutatorEdit || cell.column.modules.mutate.mutator || false, tempData = {};
				if (mutator) {
					tempData = Object.assign(tempData, cell.row.getData());
					cell.column.setFieldValue(tempData, value);
					return mutator.mutator(value, tempData, "edit", mutator.params, cell.getComponent());
				}
			}
			return value;
		}
		mutateLink(cell) {
			var links = cell.column.definition.mutateLink;
			if (links) {
				if (!Array.isArray(links)) links = [links];
				links.forEach((link) => {
					var linkCell = cell.row.getCell(link);
					if (linkCell) linkCell.setValue(linkCell.getValue(), true, true);
				});
			}
		}
		enable() {
			this.enabled = true;
		}
		disable() {
			this.enabled = false;
		}
	};
	function rows(pageSize, currentRow, currentPage, totalRows, totalPages) {
		var el = document.createElement("span"), showingEl = document.createElement("span"), valueEl = document.createElement("span"), ofEl = document.createElement("span"), totalEl = document.createElement("span"), rowsEl = document.createElement("span");
		this.table.modules.localize.langBind("pagination|counter|showing", (value) => {
			showingEl.innerHTML = value;
		});
		this.table.modules.localize.langBind("pagination|counter|of", (value) => {
			ofEl.innerHTML = value;
		});
		this.table.modules.localize.langBind("pagination|counter|rows", (value) => {
			rowsEl.innerHTML = value;
		});
		if (totalRows) {
			valueEl.innerHTML = " " + currentRow + "-" + Math.min(currentRow + pageSize - 1, totalRows) + " ";
			totalEl.innerHTML = " " + totalRows + " ";
			el.appendChild(showingEl);
			el.appendChild(valueEl);
			el.appendChild(ofEl);
			el.appendChild(totalEl);
			el.appendChild(rowsEl);
		} else {
			valueEl.innerHTML = " 0 ";
			el.appendChild(showingEl);
			el.appendChild(valueEl);
			el.appendChild(rowsEl);
		}
		return el;
	}
	function pages(pageSize, currentRow, currentPage, totalRows, totalPages) {
		var el = document.createElement("span"), showingEl = document.createElement("span"), valueEl = document.createElement("span"), ofEl = document.createElement("span"), totalEl = document.createElement("span"), rowsEl = document.createElement("span");
		this.table.modules.localize.langBind("pagination|counter|showing", (value) => {
			showingEl.innerHTML = value;
		});
		valueEl.innerHTML = " " + currentPage + " ";
		this.table.modules.localize.langBind("pagination|counter|of", (value) => {
			ofEl.innerHTML = value;
		});
		totalEl.innerHTML = " " + totalPages + " ";
		this.table.modules.localize.langBind("pagination|counter|pages", (value) => {
			rowsEl.innerHTML = value;
		});
		el.appendChild(showingEl);
		el.appendChild(valueEl);
		el.appendChild(ofEl);
		el.appendChild(totalEl);
		el.appendChild(rowsEl);
		return el;
	}
	var defaultPageCounters = {
		rows,
		pages
	};
	var Page = class Page extends Module {
		static moduleName = "page";
		static pageCounters = defaultPageCounters;
		constructor(table) {
			super(table);
			this.mode = "local";
			this.progressiveLoad = false;
			this.element = null;
			this.pageCounterElement = null;
			this.pageCounter = null;
			this.size = 0;
			this.page = 1;
			this.count = 5;
			this.max = 1;
			this.remoteRowCountEstimate = null;
			this.initialLoad = true;
			this.dataChanging = false;
			this.pageSizes = [];
			this.registerTableOption("pagination", false);
			this.registerTableOption("paginationMode", "local");
			this.registerTableOption("paginationSize", false);
			this.registerTableOption("paginationInitialPage", 1);
			this.registerTableOption("paginationCounter", false);
			this.registerTableOption("paginationCounterElement", false);
			this.registerTableOption("paginationButtonCount", 5);
			this.registerTableOption("paginationSizeSelector", false);
			this.registerTableOption("paginationElement", false);
			this.registerTableOption("paginationAddRow", "page");
			this.registerTableOption("paginationOutOfRange", false);
			this.registerTableOption("progressiveLoad", false);
			this.registerTableOption("progressiveLoadDelay", 0);
			this.registerTableOption("progressiveLoadScrollMargin", 0);
			this.registerTableFunction("setMaxPage", this.setMaxPage.bind(this));
			this.registerTableFunction("setPage", this.setPage.bind(this));
			this.registerTableFunction("setPageToRow", this.userSetPageToRow.bind(this));
			this.registerTableFunction("setPageSize", this.userSetPageSize.bind(this));
			this.registerTableFunction("getPageSize", this.getPageSize.bind(this));
			this.registerTableFunction("previousPage", this.previousPage.bind(this));
			this.registerTableFunction("nextPage", this.nextPage.bind(this));
			this.registerTableFunction("getPage", this.getPage.bind(this));
			this.registerTableFunction("getPageMax", this.getPageMax.bind(this));
			this.registerComponentFunction("row", "pageTo", this.setPageToRow.bind(this));
		}
		initialize() {
			if (this.table.options.pagination) {
				this.subscribe("row-deleted", this.rowsUpdated.bind(this));
				this.subscribe("row-added", this.rowsUpdated.bind(this));
				this.subscribe("data-processed", this.initialLoadComplete.bind(this));
				this.subscribe("table-built", this.calculatePageSizes.bind(this));
				this.subscribe("footer-redraw", this.footerRedraw.bind(this));
				if (this.table.options.paginationAddRow == "page") this.subscribe("row-adding-position", this.rowAddingPosition.bind(this));
				if (this.table.options.paginationMode === "remote") {
					this.subscribe("data-params", this.remotePageParams.bind(this));
					this.subscribe("data-loaded", this._parseRemoteData.bind(this));
				}
				if (this.table.options.progressiveLoad) console.error("Progressive Load Error - Pagination and progressive load cannot be used at the same time");
				this.registerDisplayHandler(this.restOnRenderBefore.bind(this), 40);
				this.registerDisplayHandler(this.getRows.bind(this), 50);
				this.createElements();
				this.initializePageCounter();
				this.initializePaginator();
			} else if (this.table.options.progressiveLoad) {
				this.subscribe("data-params", this.remotePageParams.bind(this));
				this.subscribe("data-loaded", this._parseRemoteData.bind(this));
				this.subscribe("table-built", this.calculatePageSizes.bind(this));
				this.subscribe("data-processed", this.initialLoadComplete.bind(this));
				this.initializeProgressive(this.table.options.progressiveLoad);
				if (this.table.options.progressiveLoad === "scroll") this.subscribe("scroll-vertical", this.scrollVertical.bind(this));
			}
		}
		rowAddingPosition(row, top) {
			var rowManager = this.table.rowManager, displayRows = rowManager.getDisplayRows(), index;
			if (top) {
				if (displayRows.length) index = displayRows[0];
				else if (rowManager.activeRows.length) {
					index = rowManager.activeRows[rowManager.activeRows.length - 1];
					top = false;
				}
			} else if (displayRows.length) {
				index = displayRows[displayRows.length - 1];
				top = displayRows.length < this.size ? false : true;
			}
			return {
				index,
				top
			};
		}
		calculatePageSizes() {
			var testElRow, testElCell;
			if (this.table.options.paginationSize) this.size = this.table.options.paginationSize;
			else {
				testElRow = document.createElement("div");
				testElRow.classList.add("tabulator-row");
				testElRow.style.visibility = "hidden";
				testElCell = document.createElement("div");
				testElCell.classList.add("tabulator-cell");
				testElCell.innerHTML = "Page Row Test";
				testElRow.appendChild(testElCell);
				this.table.rowManager.getTableElement().appendChild(testElRow);
				this.size = Math.floor(this.table.rowManager.getElement().clientHeight / testElRow.offsetHeight);
				this.table.rowManager.getTableElement().removeChild(testElRow);
			}
			this.dispatchExternal("pageSizeChanged", this.size);
			this.generatePageSizeSelectList();
		}
		initialLoadComplete() {
			this.initialLoad = false;
		}
		remotePageParams(data, config, silent, params) {
			if (!this.initialLoad) {
				if (this.progressiveLoad && !silent || !this.progressiveLoad && !this.dataChanging) this.reset(true);
			}
			params.page = this.page;
			if (this.size) params.size = this.size;
			return params;
		}
		userSetPageToRow(row) {
			if (this.table.options.pagination) {
				row = this.table.rowManager.findRow(row);
				if (row) return this.setPageToRow(row);
			}
			return Promise.reject();
		}
		userSetPageSize(size) {
			if (this.table.options.pagination) {
				this.setPageSize(size);
				return this.setPage(1);
			} else return false;
		}
		scrollVertical(top, dir) {
			var element, diff, margin;
			if (!dir && !this.table.dataLoader.loading) {
				element = this.table.rowManager.getElement();
				diff = element.scrollHeight - element.clientHeight - top;
				margin = this.table.options.progressiveLoadScrollMargin || element.clientHeight * 2;
				if (diff < margin) this.nextPage().catch(() => {});
			}
		}
		restOnRenderBefore(rows, renderInPosition) {
			if (!renderInPosition) {
				if (this.mode === "local") this.reset();
			}
			return rows;
		}
		rowsUpdated() {
			this.refreshData(true, "all");
		}
		createElements() {
			var button;
			this.element = document.createElement("span");
			this.element.classList.add("tabulator-paginator");
			this.pagesElement = document.createElement("span");
			this.pagesElement.classList.add("tabulator-pages");
			button = document.createElement("button");
			button.classList.add("tabulator-page");
			button.setAttribute("type", "button");
			button.setAttribute("role", "button");
			button.setAttribute("aria-label", "");
			button.setAttribute("title", "");
			this.firstBut = button.cloneNode(true);
			this.firstBut.setAttribute("data-page", "first");
			this.prevBut = button.cloneNode(true);
			this.prevBut.setAttribute("data-page", "prev");
			this.nextBut = button.cloneNode(true);
			this.nextBut.setAttribute("data-page", "next");
			this.lastBut = button.cloneNode(true);
			this.lastBut.setAttribute("data-page", "last");
			if (this.table.options.paginationSizeSelector) {
				this.pageSizeSelect = document.createElement("select");
				this.pageSizeSelect.classList.add("tabulator-page-size");
			}
		}
		generatePageSizeSelectList() {
			var pageSizes = [];
			if (this.pageSizeSelect) {
				if (Array.isArray(this.table.options.paginationSizeSelector)) {
					pageSizes = this.table.options.paginationSizeSelector;
					this.pageSizes = pageSizes;
					if (this.pageSizes.indexOf(this.size) == -1) pageSizes.unshift(this.size);
				} else if (this.pageSizes.indexOf(this.size) == -1) {
					pageSizes = [];
					for (let i = 1; i < 5; i++) pageSizes.push(this.size * i);
					this.pageSizes = pageSizes;
				} else pageSizes = this.pageSizes;
				while (this.pageSizeSelect.firstChild) this.pageSizeSelect.removeChild(this.pageSizeSelect.firstChild);
				pageSizes.forEach((item) => {
					var itemEl = document.createElement("option");
					itemEl.value = item;
					if (item === true) this.langBind("pagination|all", function(value) {
						itemEl.innerHTML = value;
					});
					else itemEl.innerHTML = item;
					this.pageSizeSelect.appendChild(itemEl);
				});
				this.pageSizeSelect.value = this.size;
			}
		}
		initializePageCounter() {
			var counter = this.table.options.paginationCounter, pageCounter = null;
			if (counter) {
				if (typeof counter === "function") pageCounter = counter;
				else pageCounter = Page.pageCounters[counter];
				if (pageCounter) {
					this.pageCounter = pageCounter;
					this.pageCounterElement = document.createElement("span");
					this.pageCounterElement.classList.add("tabulator-page-counter");
				} else console.warn("Pagination Error - No such page counter found: ", counter);
			}
		}
		initializePaginator(hidden) {
			var pageSelectLabel, paginationCounterHolder;
			if (!hidden) {
				this.langBind("pagination|first", (value) => {
					this.firstBut.innerHTML = value;
				});
				this.langBind("pagination|first_title", (value) => {
					this.firstBut.setAttribute("aria-label", value);
					this.firstBut.setAttribute("title", value);
				});
				this.langBind("pagination|prev", (value) => {
					this.prevBut.innerHTML = value;
				});
				this.langBind("pagination|prev_title", (value) => {
					this.prevBut.setAttribute("aria-label", value);
					this.prevBut.setAttribute("title", value);
				});
				this.langBind("pagination|next", (value) => {
					this.nextBut.innerHTML = value;
				});
				this.langBind("pagination|next_title", (value) => {
					this.nextBut.setAttribute("aria-label", value);
					this.nextBut.setAttribute("title", value);
				});
				this.langBind("pagination|last", (value) => {
					this.lastBut.innerHTML = value;
				});
				this.langBind("pagination|last_title", (value) => {
					this.lastBut.setAttribute("aria-label", value);
					this.lastBut.setAttribute("title", value);
				});
				this.firstBut.addEventListener("click", () => {
					this.setPage(1);
				});
				this.prevBut.addEventListener("click", () => {
					this.previousPage();
				});
				this.nextBut.addEventListener("click", () => {
					this.nextPage();
				});
				this.lastBut.addEventListener("click", () => {
					this.setPage(this.max);
				});
				if (this.table.options.paginationElement) this.element = this.table.options.paginationElement;
				if (this.pageSizeSelect) {
					pageSelectLabel = document.createElement("label");
					this.langBind("pagination|page_size", (value) => {
						this.pageSizeSelect.setAttribute("aria-label", value);
						this.pageSizeSelect.setAttribute("title", value);
						pageSelectLabel.innerHTML = value;
					});
					this.element.appendChild(pageSelectLabel);
					this.element.appendChild(this.pageSizeSelect);
					this.pageSizeSelect.addEventListener("change", (e) => {
						this.setPageSize(this.pageSizeSelect.value == "true" ? true : this.pageSizeSelect.value);
						this.setPage(1);
					});
				}
				this.element.appendChild(this.firstBut);
				this.element.appendChild(this.prevBut);
				this.element.appendChild(this.pagesElement);
				this.element.appendChild(this.nextBut);
				this.element.appendChild(this.lastBut);
				if (!this.table.options.paginationElement) {
					if (this.table.options.paginationCounter) if (this.table.options.paginationCounterElement) {
						if (this.table.options.paginationCounterElement instanceof HTMLElement) this.table.options.paginationCounterElement.appendChild(this.pageCounterElement);
						else if (typeof this.table.options.paginationCounterElement === "string") {
							paginationCounterHolder = document.querySelector(this.table.options.paginationCounterElement);
							if (paginationCounterHolder) paginationCounterHolder.appendChild(this.pageCounterElement);
							else console.warn("Pagination Error - Unable to find element matching paginationCounterElement selector:", this.table.options.paginationCounterElement);
						}
					} else this.footerAppend(this.pageCounterElement);
					this.footerAppend(this.element);
				}
				this.page = this.table.options.paginationInitialPage;
				this.count = this.table.options.paginationButtonCount;
			}
			this.mode = this.table.options.paginationMode;
		}
		initializeProgressive(mode) {
			this.initializePaginator(true);
			this.mode = "progressive_" + mode;
			this.progressiveLoad = true;
		}
		trackChanges() {
			this.dispatch("page-changed");
		}
		setMaxRows(rowCount) {
			if (!rowCount) this.max = 1;
			else this.max = this.size === true ? 1 : Math.ceil(rowCount / this.size);
			if (this.page > this.max) this.page = this.max;
		}
		reset(force) {
			if (!this.initialLoad) {
				if (this.mode == "local" || force) {
					this.page = 1;
					this.trackChanges();
				}
			}
		}
		setMaxPage(max) {
			max = parseInt(max);
			this.max = max || 1;
			if (this.page > this.max) {
				this.page = this.max;
				this.trigger();
			}
		}
		setPage(page) {
			switch (page) {
				case "first": return this.setPage(1);
				case "prev": return this.previousPage();
				case "next": return this.nextPage();
				case "last": return this.setPage(this.max);
			}
			page = parseInt(page);
			if (page > 0 && page <= this.max || this.mode !== "local") {
				this.page = page;
				this.trackChanges();
				return this.trigger();
			} else {
				console.warn("Pagination Error - Requested page is out of range of 1 - " + this.max + ":", page);
				return Promise.reject();
			}
		}
		setPageToRow(row) {
			var index = this.displayRows(-1).indexOf(row);
			if (index > -1) {
				var page = this.size === true ? 1 : Math.ceil((index + 1) / this.size);
				return this.setPage(page);
			} else {
				console.warn("Pagination Error - Requested row is not visible");
				return Promise.reject();
			}
		}
		setPageSize(size) {
			if (size !== true) size = parseInt(size);
			if (size > 0) {
				this.size = size;
				this.dispatchExternal("pageSizeChanged", size);
			}
			if (this.pageSizeSelect) this.generatePageSizeSelectList();
			this.trackChanges();
		}
		_setPageCounter(totalRows, size, currentRow) {
			var content;
			if (this.pageCounter) {
				if (this.mode === "remote") {
					size = this.size;
					currentRow = (this.page - 1) * this.size + 1;
					totalRows = this.remoteRowCountEstimate;
				}
				content = this.pageCounter.call(this, size, currentRow, this.page, totalRows, this.max);
				switch (typeof content) {
					case "object":
						if (content instanceof Node) {
							while (this.pageCounterElement.firstChild) this.pageCounterElement.removeChild(this.pageCounterElement.firstChild);
							this.pageCounterElement.appendChild(content);
						} else {
							this.pageCounterElement.innerHTML = "";
							if (content != null) console.warn("Page Counter Error - Page Counter has returned a type of object, the only valid page counter object return is an instance of Node, the page counter returned:", content);
						}
						break;
					case "undefined":
						this.pageCounterElement.innerHTML = "";
						break;
					default: this.pageCounterElement.innerHTML = content;
				}
			}
		}
		_setPageButtons() {
			let leftSize = Math.floor((this.count - 1) / 2);
			let rightSize = Math.ceil((this.count - 1) / 2);
			let min = this.max - this.page + leftSize + 1 < this.count ? this.max - this.count + 1 : Math.max(this.page - leftSize, 1);
			let max = this.page <= rightSize ? Math.min(this.count, this.max) : Math.min(this.page + rightSize, this.max);
			while (this.pagesElement.firstChild) this.pagesElement.removeChild(this.pagesElement.firstChild);
			if (this.page == 1) {
				this.firstBut.disabled = true;
				this.prevBut.disabled = true;
			} else {
				this.firstBut.disabled = false;
				this.prevBut.disabled = false;
			}
			if (this.page == this.max) {
				this.lastBut.disabled = true;
				this.nextBut.disabled = true;
			} else {
				this.lastBut.disabled = false;
				this.nextBut.disabled = false;
			}
			for (let i = min; i <= max; i++) if (i > 0 && i <= this.max) this.pagesElement.appendChild(this._generatePageButton(i));
			this.footerRedraw();
		}
		_generatePageButton(page) {
			var button = document.createElement("button");
			button.classList.add("tabulator-page");
			if (page == this.page) button.classList.add("active");
			button.setAttribute("type", "button");
			button.setAttribute("role", "button");
			this.langBind("pagination|page_title", (value) => {
				button.setAttribute("aria-label", value + " " + page);
				button.setAttribute("title", value + " " + page);
			});
			button.setAttribute("data-page", page);
			button.textContent = page;
			button.addEventListener("click", (e) => {
				this.setPage(page);
			});
			return button;
		}
		previousPage() {
			if (this.page > 1) {
				this.page--;
				this.trackChanges();
				return this.trigger();
			} else {
				console.warn("Pagination Error - Previous page would be less than page 1:", 0);
				return Promise.reject();
			}
		}
		nextPage() {
			if (this.page < this.max) {
				this.page++;
				this.trackChanges();
				return this.trigger();
			} else {
				if (!this.progressiveLoad) console.warn("Pagination Error - Next page would be greater than maximum page of " + this.max + ":", this.max + 1);
				return Promise.reject();
			}
		}
		getPage() {
			return this.page;
		}
		getPageMax() {
			return this.max;
		}
		getPageSize(size) {
			return this.size;
		}
		getMode() {
			return this.mode;
		}
		getRows(data) {
			var actualRowPageSize = 0, output, start, end, actualStartRow;
			var actualRows = data.filter((row) => {
				return row.type === "row";
			});
			if (this.mode == "local") {
				output = [];
				this.setMaxRows(data.length);
				if (this.size === true) {
					start = 0;
					end = data.length;
				} else {
					start = this.size * (this.page - 1);
					end = start + parseInt(this.size);
				}
				this._setPageButtons();
				for (let i = start; i < end; i++) {
					let row = data[i];
					if (row) {
						output.push(row);
						if (row.type === "row") {
							if (!actualStartRow) actualStartRow = row;
							actualRowPageSize++;
						}
					}
				}
				this._setPageCounter(actualRows.length, actualRowPageSize, actualStartRow ? actualRows.indexOf(actualStartRow) + 1 : 0);
				return output;
			} else {
				this._setPageButtons();
				this._setPageCounter(actualRows.length);
				return data.slice(0);
			}
		}
		trigger() {
			var left;
			switch (this.mode) {
				case "local":
					left = this.table.rowManager.scrollLeft;
					this.refreshData();
					this.table.rowManager.scrollHorizontal(left);
					this.dispatchExternal("pageLoaded", this.getPage());
					return Promise.resolve();
				case "remote":
					this.dataChanging = true;
					return this.reloadData(null).finally(() => {
						this.dataChanging = false;
					});
				case "progressive_load":
				case "progressive_scroll": return this.reloadData(null, true);
				default:
					console.warn("Pagination Error - no such pagination mode:", this.mode);
					return Promise.reject();
			}
		}
		_parseRemoteData(data) {
			var margin, paginationOutOfRange;
			if (typeof data.last_page === "undefined") console.warn("Remote Pagination Error - Server response missing '" + (this.options("dataReceiveParams").last_page || "last_page") + "' property");
			if (data.data) {
				this.max = parseInt(data.last_page) || 1;
				this.remoteRowCountEstimate = typeof data.last_row !== "undefined" ? data.last_row : data.last_page * this.size - (this.page == data.last_page ? this.size - data.data.length : 0);
				if (this.progressiveLoad) {
					switch (this.mode) {
						case "progressive_load":
							if (this.page == 1) this.table.rowManager.setData(data.data, false, this.page == 1);
							else this.table.rowManager.addRows(data.data);
							if (this.page < this.max) setTimeout(() => {
								this.nextPage();
							}, this.table.options.progressiveLoadDelay);
							break;
						case "progressive_scroll":
							data = this.page === 1 ? data.data : this.table.rowManager.getData().concat(data.data);
							this.table.rowManager.setData(data, this.page !== 1, this.page == 1);
							margin = this.table.options.progressiveLoadScrollMargin || this.table.rowManager.element.clientHeight * 2;
							if (this.table.rowManager.element.scrollHeight <= this.table.rowManager.element.clientHeight + margin) {
								if (this.page < this.max) setTimeout(() => {
									this.nextPage();
								});
							}
							break;
					}
					return false;
				} else {
					if (this.page > this.max) {
						console.warn("Remote Pagination Error - Server returned last page value lower than the current page");
						paginationOutOfRange = this.options("paginationOutOfRange");
						if (paginationOutOfRange) return this.setPage(typeof paginationOutOfRange === "function" ? paginationOutOfRange.call(this, this.page, this.max) : paginationOutOfRange);
					}
					this.dispatchExternal("pageLoaded", this.getPage());
				}
			} else console.warn("Remote Pagination Error - Server response missing '" + (this.options("dataReceiveParams").data || "data") + "' property");
			return data.data;
		}
		footerRedraw() {
			var footer = this.table.footerManager.containerElement;
			if (Math.ceil(footer.clientWidth) - footer.scrollWidth < 0) this.pagesElement.style.display = "none";
			else {
				this.pagesElement.style.display = "";
				if (Math.ceil(footer.clientWidth) - footer.scrollWidth < 0) this.pagesElement.style.display = "none";
			}
		}
	};
	var defaultReaders = {
		local: function(id, type) {
			var data = localStorage.getItem(id + "-" + type);
			return data ? JSON.parse(data) : false;
		},
		cookie: function(id, type) {
			var cookie = document.cookie, key = id + "-" + type, cookiePos = cookie.indexOf(key + "="), end, data;
			if (cookiePos > -1) {
				cookie = cookie.slice(cookiePos);
				end = cookie.indexOf(";");
				if (end > -1) cookie = cookie.slice(0, end);
				data = cookie.replace(key + "=", "");
			}
			return data ? JSON.parse(data) : false;
		}
	};
	var defaultWriters = {
		local: function(id, type, data) {
			localStorage.setItem(id + "-" + type, JSON.stringify(data));
		},
		cookie: function(id, type, data) {
			var expireDate = new Date();
			expireDate.setDate(expireDate.getDate() + 1e4);
			document.cookie = id + "-" + type + "=" + JSON.stringify(data) + "; expires=" + expireDate.toUTCString();
		}
	};
	var Persistence = class Persistence extends Module {
		static moduleName = "persistence";
		static moduleInitOrder = -10;
		static readers = defaultReaders;
		static writers = defaultWriters;
		constructor(table) {
			super(table);
			this.mode = "";
			this.id = "";
			this.defWatcherBlock = false;
			this.config = {};
			this.readFunc = false;
			this.writeFunc = false;
			this.registerTableOption("persistence", false);
			this.registerTableOption("persistenceID", "");
			this.registerTableOption("persistenceMode", true);
			this.registerTableOption("persistenceReaderFunc", false);
			this.registerTableOption("persistenceWriterFunc", false);
		}
		localStorageTest() {
			var testKey = "_tabulator_test";
			try {
				window.localStorage.setItem(testKey, testKey);
				window.localStorage.removeItem(testKey);
				return true;
			} catch (e) {
				return false;
			}
		}
		initialize() {
			if (this.table.options.persistence) {
				var mode = this.table.options.persistenceMode, id = this.table.options.persistenceID, retrievedData;
				this.mode = mode !== true ? mode : this.localStorageTest() ? "local" : "cookie";
				if (this.table.options.persistenceReaderFunc) if (typeof this.table.options.persistenceReaderFunc === "function") this.readFunc = this.table.options.persistenceReaderFunc;
				else if (Persistence.readers[this.table.options.persistenceReaderFunc]) this.readFunc = Persistence.readers[this.table.options.persistenceReaderFunc];
				else console.warn("Persistence Read Error - invalid reader set", this.table.options.persistenceReaderFunc);
				else if (Persistence.readers[this.mode]) this.readFunc = Persistence.readers[this.mode];
				else console.warn("Persistence Read Error - invalid reader set", this.mode);
				if (this.table.options.persistenceWriterFunc) if (typeof this.table.options.persistenceWriterFunc === "function") this.writeFunc = this.table.options.persistenceWriterFunc;
				else if (Persistence.writers[this.table.options.persistenceWriterFunc]) this.writeFunc = Persistence.writers[this.table.options.persistenceWriterFunc];
				else console.warn("Persistence Write Error - invalid reader set", this.table.options.persistenceWriterFunc);
				else if (Persistence.writers[this.mode]) this.writeFunc = Persistence.writers[this.mode];
				else console.warn("Persistence Write Error - invalid writer set", this.mode);
				this.id = "tabulator-" + (id || this.table.element.getAttribute("id") || "");
				this.config = {
					sort: this.table.options.persistence === true || this.table.options.persistence.sort,
					filter: this.table.options.persistence === true || this.table.options.persistence.filter,
					headerFilter: this.table.options.persistence === true || this.table.options.persistence.headerFilter,
					group: this.table.options.persistence === true || this.table.options.persistence.group,
					page: this.table.options.persistence === true || this.table.options.persistence.page,
					columns: this.table.options.persistence === true ? [
						"title",
						"width",
						"visible"
					] : this.table.options.persistence.columns
				};
				if (this.config.page) {
					retrievedData = this.retrieveData("page");
					if (retrievedData) {
						if (typeof retrievedData.paginationSize !== "undefined" && (this.config.page === true || this.config.page.size)) this.table.options.paginationSize = retrievedData.paginationSize;
						if (typeof retrievedData.paginationInitialPage !== "undefined" && (this.config.page === true || this.config.page.page)) this.table.options.paginationInitialPage = retrievedData.paginationInitialPage;
					}
				}
				if (this.config.group) {
					retrievedData = this.retrieveData("group");
					if (retrievedData) {
						if (typeof retrievedData.groupBy !== "undefined" && (this.config.group === true || this.config.group.groupBy)) this.table.options.groupBy = retrievedData.groupBy;
						if (typeof retrievedData.groupStartOpen !== "undefined" && (this.config.group === true || this.config.group.groupStartOpen)) this.table.options.groupStartOpen = retrievedData.groupStartOpen;
						if (typeof retrievedData.groupHeader !== "undefined" && (this.config.group === true || this.config.group.groupHeader)) this.table.options.groupHeader = retrievedData.groupHeader;
					}
				}
				if (this.config.columns) {
					this.table.options.columns = this.load("columns", this.table.options.columns);
					this.subscribe("column-init", this.initializeColumn.bind(this));
					this.subscribe("column-show", this.save.bind(this, "columns"));
					this.subscribe("column-hide", this.save.bind(this, "columns"));
					this.subscribe("column-moved", this.save.bind(this, "columns"));
				}
				this.subscribe("table-built", this.tableBuilt.bind(this), 0);
				this.subscribe("table-redraw", this.tableRedraw.bind(this));
				this.subscribe("filter-changed", this.eventSave.bind(this, "filter"));
				this.subscribe("filter-changed", this.eventSave.bind(this, "headerFilter"));
				this.subscribe("sort-changed", this.eventSave.bind(this, "sort"));
				this.subscribe("group-changed", this.eventSave.bind(this, "group"));
				this.subscribe("page-changed", this.eventSave.bind(this, "page"));
				this.subscribe("column-resized", this.eventSave.bind(this, "columns"));
				this.subscribe("column-width", this.eventSave.bind(this, "columns"));
				this.subscribe("layout-refreshed", this.eventSave.bind(this, "columns"));
			}
			this.registerTableFunction("getColumnLayout", this.getColumnLayout.bind(this));
			this.registerTableFunction("setColumnLayout", this.setColumnLayout.bind(this));
		}
		eventSave(type) {
			if (this.config[type]) this.save(type);
		}
		tableBuilt() {
			var sorters, filters, headerFilters;
			if (this.config.sort) {
				sorters = this.load("sort");
				if (!sorters === false) this.table.options.initialSort = sorters;
			}
			if (this.config.filter) {
				filters = this.load("filter");
				if (!filters === false) this.table.options.initialFilter = filters;
			}
			if (this.config.headerFilter) {
				headerFilters = this.load("headerFilter");
				if (!headerFilters === false) this.table.options.initialHeaderFilter = headerFilters;
			}
		}
		tableRedraw(force) {
			if (force && this.config.columns) this.save("columns");
		}
		getColumnLayout() {
			return this.parseColumns(this.table.columnManager.getColumns());
		}
		setColumnLayout(layout) {
			this.table.columnManager.setColumns(this.mergeDefinition(this.table.options.columns, layout, true));
			return true;
		}
		initializeColumn(column) {
			var def, keys;
			if (this.config.columns) {
				this.defWatcherBlock = true;
				def = column.getDefinition();
				keys = this.config.columns === true ? Object.keys(def) : this.config.columns;
				keys.forEach((key) => {
					var props = Object.getOwnPropertyDescriptor(def, key);
					var value = def[key];
					if (props) Object.defineProperty(def, key, {
						set: (newValue) => {
							value = newValue;
							if (!this.defWatcherBlock) this.save("columns");
							if (props.set) props.set(newValue);
						},
						get: () => {
							if (props.get) props.get();
							return value;
						}
					});
				});
				this.defWatcherBlock = false;
			}
		}
		load(type, current) {
			var data = this.retrieveData(type);
			if (current) data = data ? this.mergeDefinition(current, data) : current;
			return data;
		}
		retrieveData(type) {
			return this.readFunc ? this.readFunc(this.id, type) : false;
		}
		mergeDefinition(oldCols, newCols, mergeAllNew) {
			var output = [];
			newCols = newCols || [];
			newCols.forEach((column, to) => {
				var from = this._findColumn(oldCols, column), keys;
				if (from) {
					if (mergeAllNew) keys = Object.keys(column);
					else if (this.config.columns === true || this.config.columns == void 0) {
						keys = Object.keys(from);
						keys.push("width");
					} else keys = this.config.columns;
					keys.forEach((key) => {
						if (key !== "columns" && typeof column[key] !== "undefined") from[key] = column[key];
					});
					if (from.columns) from.columns = this.mergeDefinition(from.columns, column.columns);
					output.push(from);
				}
			});
			oldCols.forEach((column, i) => {
				if (!this._findColumn(newCols, column)) if (output.length > i) output.splice(i, 0, column);
				else output.push(column);
			});
			return output;
		}
		_findColumn(columns, subject) {
			var type = subject.columns ? "group" : subject.field ? "field" : "object";
			return columns.find(function(col) {
				switch (type) {
					case "group": return col.title === subject.title && col.columns.length === subject.columns.length;
					case "field": return col.field === subject.field;
					case "object": return col === subject;
				}
			});
		}
		save(type) {
			var data = {};
			switch (type) {
				case "columns":
					data = this.parseColumns(this.table.columnManager.getColumns());
					break;
				case "filter":
					data = this.table.modules.filter.getFilters();
					break;
				case "headerFilter":
					data = this.table.modules.filter.getHeaderFilters();
					break;
				case "sort":
					data = this.validateSorters(this.table.modules.sort.getSort());
					break;
				case "group":
					data = this.getGroupConfig();
					break;
				case "page":
					data = this.getPageConfig();
					break;
			}
			if (this.writeFunc) this.writeFunc(this.id, type, data);
		}
		validateSorters(data) {
			data.forEach(function(item) {
				item.column = item.field;
				delete item.field;
			});
			return data;
		}
		getGroupConfig() {
			var data = {};
			if (this.config.group) {
				if (this.config.group === true || this.config.group.groupBy) data.groupBy = this.table.options.groupBy;
				if (this.config.group === true || this.config.group.groupStartOpen) data.groupStartOpen = this.table.options.groupStartOpen;
				if (this.config.group === true || this.config.group.groupHeader) data.groupHeader = this.table.options.groupHeader;
			}
			return data;
		}
		getPageConfig() {
			var data = {};
			if (this.config.page) {
				if (this.config.page === true || this.config.page.size) data.paginationSize = this.table.modules.page.getPageSize();
				if (this.config.page === true || this.config.page.page) data.paginationInitialPage = this.table.modules.page.getPage();
			}
			return data;
		}
		parseColumns(columns) {
			var definitions = [], excludedKeys = [
				"headerContextMenu",
				"headerMenu",
				"contextMenu",
				"clickMenu"
			];
			columns.forEach((column) => {
				var defStore = {}, colDef = column.getDefinition(), keys;
				if (column.isGroup) {
					defStore.title = colDef.title;
					defStore.columns = this.parseColumns(column.getColumns());
				} else {
					defStore.field = column.getField();
					if (this.config.columns === true || this.config.columns == void 0) {
						keys = Object.keys(colDef);
						keys.push("width");
						keys.push("visible");
					} else keys = this.config.columns;
					keys.forEach((key) => {
						switch (key) {
							case "width":
								defStore.width = column.getWidth();
								break;
							case "visible":
								defStore.visible = column.visible;
								break;
							default: if (typeof colDef[key] !== "function" && excludedKeys.indexOf(key) === -1) defStore[key] = colDef[key];
						}
					});
				}
				definitions.push(defStore);
			});
			return definitions;
		}
	};
	var Popup = class extends Module {
		static moduleName = "popup";
		constructor(table) {
			super(table);
			this.columnSubscribers = {};
			this.registerTableOption("rowContextPopup", false);
			this.registerTableOption("rowClickPopup", false);
			this.registerTableOption("rowDblClickPopup", false);
			this.registerTableOption("groupContextPopup", false);
			this.registerTableOption("groupClickPopup", false);
			this.registerTableOption("groupDblClickPopup", false);
			this.registerColumnOption("headerContextPopup");
			this.registerColumnOption("headerClickPopup");
			this.registerColumnOption("headerDblClickPopup");
			this.registerColumnOption("headerPopup");
			this.registerColumnOption("headerPopupIcon");
			this.registerColumnOption("contextPopup");
			this.registerColumnOption("clickPopup");
			this.registerColumnOption("dblClickPopup");
			this.registerComponentFunction("cell", "popup", this._componentPopupCall.bind(this));
			this.registerComponentFunction("column", "popup", this._componentPopupCall.bind(this));
			this.registerComponentFunction("row", "popup", this._componentPopupCall.bind(this));
			this.registerComponentFunction("group", "popup", this._componentPopupCall.bind(this));
		}
		initialize() {
			this.initializeRowWatchers();
			this.initializeGroupWatchers();
			this.subscribe("column-init", this.initializeColumn.bind(this));
		}
		_componentPopupCall(component, contents, position) {
			this.loadPopupEvent(contents, null, component, position);
		}
		initializeRowWatchers() {
			if (this.table.options.rowContextPopup) {
				this.subscribe("row-contextmenu", this.loadPopupEvent.bind(this, this.table.options.rowContextPopup));
				this.table.on("rowTapHold", this.loadPopupEvent.bind(this, this.table.options.rowContextPopup));
			}
			if (this.table.options.rowClickPopup) this.subscribe("row-click", this.loadPopupEvent.bind(this, this.table.options.rowClickPopup));
			if (this.table.options.rowDblClickPopup) this.subscribe("row-dblclick", this.loadPopupEvent.bind(this, this.table.options.rowDblClickPopup));
		}
		initializeGroupWatchers() {
			if (this.table.options.groupContextPopup) {
				this.subscribe("group-contextmenu", this.loadPopupEvent.bind(this, this.table.options.groupContextPopup));
				this.table.on("groupTapHold", this.loadPopupEvent.bind(this, this.table.options.groupContextPopup));
			}
			if (this.table.options.groupClickPopup) this.subscribe("group-click", this.loadPopupEvent.bind(this, this.table.options.groupClickPopup));
			if (this.table.options.groupDblClickPopup) this.subscribe("group-dblclick", this.loadPopupEvent.bind(this, this.table.options.groupDblClickPopup));
		}
		initializeColumn(column) {
			var def = column.definition;
			if (def.headerContextPopup && !this.columnSubscribers.headerContextPopup) {
				this.columnSubscribers.headerContextPopup = this.loadPopupTableColumnEvent.bind(this, "headerContextPopup");
				this.subscribe("column-contextmenu", this.columnSubscribers.headerContextPopup);
				this.table.on("headerTapHold", this.loadPopupTableColumnEvent.bind(this, "headerContextPopup"));
			}
			if (def.headerClickPopup && !this.columnSubscribers.headerClickPopup) {
				this.columnSubscribers.headerClickPopup = this.loadPopupTableColumnEvent.bind(this, "headerClickPopup");
				this.subscribe("column-click", this.columnSubscribers.headerClickPopup);
			}
			if (def.headerDblClickPopup && !this.columnSubscribers.headerDblClickPopup) {
				this.columnSubscribers.headerDblClickPopup = this.loadPopupTableColumnEvent.bind(this, "headerDblClickPopup");
				this.subscribe("column-dblclick", this.columnSubscribers.headerDblClickPopup);
			}
			if (def.headerPopup) this.initializeColumnHeaderPopup(column);
			if (def.contextPopup && !this.columnSubscribers.contextPopup) {
				this.columnSubscribers.contextPopup = this.loadPopupTableCellEvent.bind(this, "contextPopup");
				this.subscribe("cell-contextmenu", this.columnSubscribers.contextPopup);
				this.table.on("cellTapHold", this.loadPopupTableCellEvent.bind(this, "contextPopup"));
			}
			if (def.clickPopup && !this.columnSubscribers.clickPopup) {
				this.columnSubscribers.clickPopup = this.loadPopupTableCellEvent.bind(this, "clickPopup");
				this.subscribe("cell-click", this.columnSubscribers.clickPopup);
			}
			if (def.dblClickPopup && !this.columnSubscribers.dblClickPopup) {
				this.columnSubscribers.dblClickPopup = this.loadPopupTableCellEvent.bind(this, "dblClickPopup");
				this.subscribe("cell-click", this.columnSubscribers.dblClickPopup);
			}
		}
		initializeColumnHeaderPopup(column) {
			var icon = column.definition.headerPopupIcon, headerPopupEl = document.createElement("span");
			headerPopupEl.classList.add("tabulator-header-popup-button");
			if (icon) {
				if (typeof icon === "function") icon = icon(column.getComponent());
				if (icon instanceof HTMLElement) headerPopupEl.appendChild(icon);
				else headerPopupEl.innerHTML = icon;
			} else headerPopupEl.innerHTML = "&vellip;";
			headerPopupEl.addEventListener("click", (e) => {
				e.stopPropagation();
				e.preventDefault();
				this.loadPopupEvent(column.definition.headerPopup, e, column);
			});
			column.titleElement.insertBefore(headerPopupEl, column.titleElement.firstChild);
		}
		loadPopupTableCellEvent(option, e, cell) {
			if (cell._cell) cell = cell._cell;
			if (cell.column.definition[option]) this.loadPopupEvent(cell.column.definition[option], e, cell);
		}
		loadPopupTableColumnEvent(option, e, column) {
			if (column._column) column = column._column;
			if (column.definition[option]) this.loadPopupEvent(column.definition[option], e, column);
		}
		loadPopupEvent(contents, e, component, position) {
			var renderedCallback;
			function onRendered(callback) {
				renderedCallback = callback;
			}
			if (component._group) component = component._group;
			else if (component._row) component = component._row;
			contents = typeof contents == "function" ? contents.call(this.table, e, component.getComponent(), onRendered) : contents;
			this.loadPopup(e, component, contents, renderedCallback, position);
		}
		loadPopup(e, component, contents, renderedCallback, position) {
			var touch = !(e instanceof MouseEvent), contentsEl, popup;
			if (contents instanceof HTMLElement) contentsEl = contents;
			else {
				contentsEl = document.createElement("div");
				contentsEl.innerHTML = contents;
			}
			contentsEl.classList.add("tabulator-popup");
			contentsEl.addEventListener("click", (e) => {
				e.stopPropagation();
			});
			if (!touch) e.preventDefault();
			popup = this.popup(contentsEl);
			if (typeof renderedCallback === "function") popup.renderCallback(renderedCallback);
			if (e) popup.show(e);
			else popup.show(component.getElement(), position || "center");
			popup.hideOnBlur(() => {
				this.dispatchExternal("popupClosed", component.getComponent());
			});
			this.dispatchExternal("popupOpened", component.getComponent());
		}
	};
	var Print = class extends Module {
		static moduleName = "print";
		constructor(table) {
			super(table);
			this.element = false;
			this.manualBlock = false;
			this.beforeprintEventHandler = null;
			this.afterprintEventHandler = null;
			this.registerTableOption("printAsHtml", false);
			this.registerTableOption("printFormatter", false);
			this.registerTableOption("printHeader", false);
			this.registerTableOption("printFooter", false);
			this.registerTableOption("printStyled", true);
			this.registerTableOption("printRowRange", "visible");
			this.registerTableOption("printConfig", {});
			this.registerColumnOption("print");
			this.registerColumnOption("titlePrint");
		}
		initialize() {
			if (this.table.options.printAsHtml) {
				this.beforeprintEventHandler = this.replaceTable.bind(this);
				this.afterprintEventHandler = this.cleanup.bind(this);
				window.addEventListener("beforeprint", this.beforeprintEventHandler);
				window.addEventListener("afterprint", this.afterprintEventHandler);
				this.subscribe("table-destroy", this.destroy.bind(this));
			}
			this.registerTableFunction("print", this.printFullscreen.bind(this));
		}
		destroy() {
			if (this.table.options.printAsHtml) {
				window.removeEventListener("beforeprint", this.beforeprintEventHandler);
				window.removeEventListener("afterprint", this.afterprintEventHandler);
			}
		}
		replaceTable() {
			if (!this.manualBlock) {
				this.element = document.createElement("div");
				this.element.classList.add("tabulator-print-table");
				this.element.appendChild(this.table.modules.export.generateTable(this.table.options.printConfig, this.table.options.printStyled, this.table.options.printRowRange, "print"));
				this.table.element.style.display = "none";
				this.table.element.parentNode.insertBefore(this.element, this.table.element);
			}
		}
		cleanup() {
			document.body.classList.remove("tabulator-print-fullscreen-hide");
			if (this.element && this.element.parentNode) {
				this.element.parentNode.removeChild(this.element);
				this.table.element.style.display = "";
			}
		}
		printFullscreen(visible, style, config) {
			var scrollX = window.scrollX, scrollY = window.scrollY, headerEl = document.createElement("div"), footerEl = document.createElement("div"), tableEl = this.table.modules.export.generateTable(typeof config != "undefined" ? config : this.table.options.printConfig, typeof style != "undefined" ? style : this.table.options.printStyled, visible || this.table.options.printRowRange, "print"), headerContent, footerContent;
			this.manualBlock = true;
			this.element = document.createElement("div");
			this.element.classList.add("tabulator-print-fullscreen");
			if (this.table.options.printHeader) {
				headerEl.classList.add("tabulator-print-header");
				headerContent = typeof this.table.options.printHeader == "function" ? this.table.options.printHeader.call(this.table) : this.table.options.printHeader;
				if (typeof headerContent == "string") headerEl.innerHTML = headerContent;
				else headerEl.appendChild(headerContent);
				this.element.appendChild(headerEl);
			}
			this.element.appendChild(tableEl);
			if (this.table.options.printFooter) {
				footerEl.classList.add("tabulator-print-footer");
				footerContent = typeof this.table.options.printFooter == "function" ? this.table.options.printFooter.call(this.table) : this.table.options.printFooter;
				if (typeof footerContent == "string") footerEl.innerHTML = footerContent;
				else footerEl.appendChild(footerContent);
				this.element.appendChild(footerEl);
			}
			document.body.classList.add("tabulator-print-fullscreen-hide");
			document.body.appendChild(this.element);
			if (this.table.options.printFormatter) this.table.options.printFormatter(this.element, tableEl);
			window.print();
			this.cleanup();
			window.scrollTo(scrollX, scrollY);
			this.manualBlock = false;
		}
	};
	var ReactiveData = class extends Module {
		static moduleName = "reactiveData";
		constructor(table) {
			super(table);
			this.data = false;
			this.blocked = false;
			this.origFuncs = {};
			this.currentVersion = 0;
			this.registerTableOption("reactiveData", false);
		}
		initialize() {
			if (this.table.options.reactiveData) {
				this.subscribe("cell-value-save-before", this.block.bind(this, "cellsave"));
				this.subscribe("cell-value-save-after", this.unblock.bind(this, "cellsave"));
				this.subscribe("row-data-save-before", this.block.bind(this, "rowsave"));
				this.subscribe("row-data-save-after", this.unblock.bind(this, "rowsave"));
				this.subscribe("row-data-init-after", this.watchRow.bind(this));
				this.subscribe("data-processing", this.watchData.bind(this));
				this.subscribe("table-destroy", this.unwatchData.bind(this));
			}
		}
		watchData(data) {
			var self = this, version;
			this.currentVersion++;
			version = this.currentVersion;
			this.unwatchData();
			this.data = data;
			this.origFuncs.push = data.push;
			Object.defineProperty(this.data, "push", {
				enumerable: false,
				configurable: true,
				value: function() {
					var args = Array.from(arguments), result;
					if (!self.blocked && version === self.currentVersion) {
						self.block("data-push");
						args.forEach((arg) => {
							self.table.rowManager.addRowActual(arg, false);
						});
						result = self.origFuncs.push.apply(data, arguments);
						self.unblock("data-push");
					}
					return result;
				}
			});
			this.origFuncs.unshift = data.unshift;
			Object.defineProperty(this.data, "unshift", {
				enumerable: false,
				configurable: true,
				value: function() {
					var args = Array.from(arguments), result;
					if (!self.blocked && version === self.currentVersion) {
						self.block("data-unshift");
						args.forEach((arg) => {
							self.table.rowManager.addRowActual(arg, true);
						});
						result = self.origFuncs.unshift.apply(data, arguments);
						self.unblock("data-unshift");
					}
					return result;
				}
			});
			this.origFuncs.shift = data.shift;
			Object.defineProperty(this.data, "shift", {
				enumerable: false,
				configurable: true,
				value: function() {
					var row, result;
					if (!self.blocked && version === self.currentVersion) {
						self.block("data-shift");
						if (self.data.length) {
							row = self.table.rowManager.getRowFromDataObject(self.data[0]);
							if (row) row.deleteActual();
						}
						result = self.origFuncs.shift.call(data);
						self.unblock("data-shift");
					}
					return result;
				}
			});
			this.origFuncs.pop = data.pop;
			Object.defineProperty(this.data, "pop", {
				enumerable: false,
				configurable: true,
				value: function() {
					var row, result;
					if (!self.blocked && version === self.currentVersion) {
						self.block("data-pop");
						if (self.data.length) {
							row = self.table.rowManager.getRowFromDataObject(self.data[self.data.length - 1]);
							if (row) row.deleteActual();
						}
						result = self.origFuncs.pop.call(data);
						self.unblock("data-pop");
					}
					return result;
				}
			});
			this.origFuncs.splice = data.splice;
			Object.defineProperty(this.data, "splice", {
				enumerable: false,
				configurable: true,
				value: function() {
					var args = Array.from(arguments), start = args[0] < 0 ? data.length + args[0] : args[0], end = args[1], newRows = args[2] ? args.slice(2) : false, startRow, result;
					if (!self.blocked && version === self.currentVersion) {
						self.block("data-splice");
						if (newRows) {
							startRow = data[start] ? self.table.rowManager.getRowFromDataObject(data[start]) : false;
							if (startRow) newRows.forEach((rowData) => {
								self.table.rowManager.addRowActual(rowData, true, startRow, true);
							});
							else {
								newRows = newRows.slice().reverse();
								newRows.forEach((rowData) => {
									self.table.rowManager.addRowActual(rowData, true, false, true);
								});
							}
						}
						if (end !== 0) {
							var oldRows = data.slice(start, typeof args[1] === "undefined" ? args[1] : start + end);
							oldRows.forEach((rowData, i) => {
								var row = self.table.rowManager.getRowFromDataObject(rowData);
								if (row) row.deleteActual(i !== oldRows.length - 1);
							});
						}
						if (newRows || end !== 0) self.table.rowManager.reRenderInPosition();
						result = self.origFuncs.splice.apply(data, arguments);
						self.unblock("data-splice");
					}
					return result;
				}
			});
		}
		unwatchData() {
			if (this.data !== false) for (var key in this.origFuncs) Object.defineProperty(this.data, key, {
				enumerable: true,
				configurable: true,
				writable: true,
				value: this.origFuncs.key
			});
		}
		watchRow(row) {
			var data = row.getData();
			for (var key in data) this.watchKey(row, data, key);
			if (this.table.options.dataTree) this.watchTreeChildren(row);
		}
		watchTreeChildren(row) {
			var self = this, childField = row.getData()[this.table.options.dataTreeChildField], origFuncs = {};
			if (childField) {
				origFuncs.push = childField.push;
				Object.defineProperty(childField, "push", {
					enumerable: false,
					configurable: true,
					value: () => {
						if (!self.blocked) {
							self.block("tree-push");
							var result = origFuncs.push.apply(childField, arguments);
							this.rebuildTree(row);
							self.unblock("tree-push");
						}
						return result;
					}
				});
				origFuncs.unshift = childField.unshift;
				Object.defineProperty(childField, "unshift", {
					enumerable: false,
					configurable: true,
					value: () => {
						if (!self.blocked) {
							self.block("tree-unshift");
							var result = origFuncs.unshift.apply(childField, arguments);
							this.rebuildTree(row);
							self.unblock("tree-unshift");
						}
						return result;
					}
				});
				origFuncs.shift = childField.shift;
				Object.defineProperty(childField, "shift", {
					enumerable: false,
					configurable: true,
					value: () => {
						if (!self.blocked) {
							self.block("tree-shift");
							var result = origFuncs.shift.call(childField);
							this.rebuildTree(row);
							self.unblock("tree-shift");
						}
						return result;
					}
				});
				origFuncs.pop = childField.pop;
				Object.defineProperty(childField, "pop", {
					enumerable: false,
					configurable: true,
					value: () => {
						if (!self.blocked) {
							self.block("tree-pop");
							var result = origFuncs.pop.call(childField);
							this.rebuildTree(row);
							self.unblock("tree-pop");
						}
						return result;
					}
				});
				origFuncs.splice = childField.splice;
				Object.defineProperty(childField, "splice", {
					enumerable: false,
					configurable: true,
					value: () => {
						if (!self.blocked) {
							self.block("tree-splice");
							var result = origFuncs.splice.apply(childField, arguments);
							this.rebuildTree(row);
							self.unblock("tree-splice");
						}
						return result;
					}
				});
			}
		}
		rebuildTree(row) {
			this.table.modules.dataTree.initializeRow(row);
			this.table.modules.dataTree.layoutRow(row);
			this.table.rowManager.refreshActiveData("tree", false, true);
		}
		watchKey(row, data, key) {
			var self = this, props = Object.getOwnPropertyDescriptor(data, key), value = data[key], version = this.currentVersion;
			Object.defineProperty(data, key, {
				set: (newValue) => {
					value = newValue;
					if (!self.blocked && version === self.currentVersion) {
						self.block("key");
						var update = {};
						update[key] = newValue;
						row.updateData(update);
						self.unblock("key");
					}
					if (props.set) props.set(newValue);
				},
				get: () => {
					if (props.get) props.get();
					return value;
				}
			});
		}
		unwatchRow(row) {
			var data = row.getData();
			for (var key in data) Object.defineProperty(data, key, { value: data[key] });
		}
		block(key) {
			if (!this.blocked) this.blocked = key;
		}
		unblock(key) {
			if (this.blocked === key) this.blocked = false;
		}
	};
	var ResizeColumns = class extends Module {
		static moduleName = "resizeColumns";
		constructor(table) {
			super(table);
			this.startColumn = false;
			this.startX = false;
			this.startWidth = false;
			this.latestX = false;
			this.handle = null;
			this.initialNextColumn = null;
			this.nextColumn = null;
			this.initialized = false;
			this.registerColumnOption("resizable", true);
			this.registerTableOption("resizableColumnFit", false);
			this.registerTableOption("resizableColumnGuide", false);
		}
		initialize() {
			this.subscribe("column-rendered", this.layoutColumnHeader.bind(this));
		}
		initializeEventWatchers() {
			if (!this.initialized) {
				this.subscribe("cell-rendered", this.layoutCellHandles.bind(this));
				this.subscribe("cell-delete", this.deInitializeComponent.bind(this));
				this.subscribe("cell-height", this.resizeHandle.bind(this));
				this.subscribe("column-moved", this.columnLayoutUpdated.bind(this));
				this.subscribe("column-hide", this.deInitializeColumn.bind(this));
				this.subscribe("column-show", this.columnLayoutUpdated.bind(this));
				this.subscribe("column-width", this.columnWidthUpdated.bind(this));
				this.subscribe("column-delete", this.deInitializeComponent.bind(this));
				this.subscribe("column-height", this.resizeHandle.bind(this));
				this.initialized = true;
			}
		}
		layoutCellHandles(cell) {
			if (cell.row.type === "row") {
				this.deInitializeComponent(cell);
				this.initializeColumn("cell", cell, cell.column, cell.element);
			}
		}
		layoutColumnHeader(column) {
			if (column.definition.resizable) {
				this.initializeEventWatchers();
				this.deInitializeComponent(column);
				this.initializeColumn("header", column, column, column.element);
			}
		}
		columnLayoutUpdated(column) {
			var prev = column.prevColumn();
			this.reinitializeColumn(column);
			if (prev) this.reinitializeColumn(prev);
		}
		columnWidthUpdated(column) {
			if (column.modules.frozen) {
				if (this.table.modules.frozenColumns.leftColumns.includes(column)) this.table.modules.frozenColumns.leftColumns.forEach((col) => {
					this.reinitializeColumn(col);
				});
				else if (this.table.modules.frozenColumns.rightColumns.includes(column)) this.table.modules.frozenColumns.rightColumns.forEach((col) => {
					this.reinitializeColumn(col);
				});
			}
		}
		frozenColumnOffset(column) {
			var offset = false;
			if (column.modules.frozen) {
				offset = column.modules.frozen.marginValue;
				if (column.modules.frozen.position === "left") offset += column.getWidth() - 3;
				else if (offset) offset -= 3;
			}
			return offset !== false ? offset + "px" : false;
		}
		reinitializeColumn(column) {
			var frozenOffset = this.frozenColumnOffset(column);
			column.cells.forEach((cell) => {
				if (cell.modules.resize && cell.modules.resize.handleEl) {
					if (frozenOffset) {
						cell.modules.resize.handleEl.style[column.modules.frozen.position] = frozenOffset;
						cell.modules.resize.handleEl.style["z-index"] = 11;
					}
					cell.element.after(cell.modules.resize.handleEl);
				}
			});
			if (column.modules.resize && column.modules.resize.handleEl) {
				if (frozenOffset) column.modules.resize.handleEl.style[column.modules.frozen.position] = frozenOffset;
				column.element.after(column.modules.resize.handleEl);
			}
		}
		initializeColumn(type, component, column, element) {
			var self = this, variableHeight = false, mode = column.definition.resizable, config = {}, nearestColumn = column.getLastColumn();
			if (type === "header") {
				variableHeight = column.definition.formatter == "textarea" || column.definition.variableHeight;
				config = { variableHeight };
			}
			if ((mode === true || mode == type) && this._checkResizability(nearestColumn)) {
				var handle = document.createElement("span");
				handle.className = "tabulator-col-resize-handle";
				handle.addEventListener("click", function(e) {
					e.stopPropagation();
				});
				var handleDown = function(e) {
					self.startColumn = column;
					self.initialNextColumn = self.nextColumn = nearestColumn.nextColumn();
					self._mouseDown(e, nearestColumn, handle);
				};
				handle.addEventListener("mousedown", handleDown);
				handle.addEventListener("touchstart", handleDown, { passive: true });
				handle.addEventListener("dblclick", (e) => {
					var oldWidth = nearestColumn.getWidth();
					e.stopPropagation();
					nearestColumn.reinitializeWidth(true);
					if (oldWidth !== nearestColumn.getWidth()) {
						self.dispatch("column-resized", nearestColumn);
						self.dispatchExternal("columnResized", nearestColumn.getComponent());
					}
				});
				if (column.modules.frozen) {
					handle.style.position = "sticky";
					handle.style[column.modules.frozen.position] = this.frozenColumnOffset(column);
				}
				config.handleEl = handle;
				if (element.parentNode && column.visible) element.after(handle);
			}
			component.modules.resize = config;
		}
		deInitializeColumn(column) {
			this.deInitializeComponent(column);
			column.cells.forEach((cell) => {
				this.deInitializeComponent(cell);
			});
		}
		deInitializeComponent(component) {
			var handleEl;
			if (component.modules.resize) {
				handleEl = component.modules.resize.handleEl;
				if (handleEl && handleEl.parentElement) handleEl.parentElement.removeChild(handleEl);
			}
		}
		resizeHandle(component, height) {
			if (component.modules.resize && component.modules.resize.handleEl) component.modules.resize.handleEl.style.height = height;
		}
		resize(e, column) {
			var x = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX, startDiff = x - this.startX, moveDiff = x - this.latestX, blockedBefore, blockedAfter;
			this.latestX = x;
			if (this.table.rtl) {
				startDiff = -startDiff;
				moveDiff = -moveDiff;
			}
			blockedBefore = column.width == column.minWidth || column.width == column.maxWidth;
			column.setWidth(this.startWidth + startDiff);
			blockedAfter = column.width == column.minWidth || column.width == column.maxWidth;
			if (moveDiff < 0) this.nextColumn = this.initialNextColumn;
			if (this.table.options.resizableColumnFit && this.nextColumn && !(blockedBefore && blockedAfter)) {
				let colWidth = this.nextColumn.getWidth();
				if (moveDiff > 0) {
					if (colWidth <= this.nextColumn.minWidth) this.nextColumn = this.nextColumn.nextColumn();
				}
				if (this.nextColumn) this.nextColumn.setWidth(this.nextColumn.getWidth() - moveDiff);
			}
			this.table.columnManager.rerenderColumns(true);
			if (!this.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight) column.checkCellHeights();
		}
		calcGuidePosition(e, column, handle) {
			var mouseX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX, handleX = handle.getBoundingClientRect().x - this.table.element.getBoundingClientRect().x, tableX = this.table.element.getBoundingClientRect().x, columnX = column.element.getBoundingClientRect().left - tableX, mouseDiff = mouseX - this.startX, pos = Math.max(handleX + mouseDiff, columnX + column.minWidth);
			if (column.maxWidth) pos = Math.min(pos, columnX + column.maxWidth);
			return pos;
		}
		_checkResizability(column) {
			return column.definition.resizable;
		}
		_mouseDown(e, column, handle) {
			var self = this, guideEl;
			this.dispatchExternal("columnResizing", column.getComponent());
			if (self.table.options.resizableColumnGuide) {
				guideEl = document.createElement("span");
				guideEl.classList.add("tabulator-col-resize-guide");
				self.table.element.appendChild(guideEl);
				setTimeout(() => {
					guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px";
				});
			}
			self.table.element.classList.add("tabulator-block-select");
			function mouseMove(e) {
				if (self.table.options.resizableColumnGuide) guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px";
				else self.resize(e, column);
			}
			function mouseUp(e) {
				if (self.table.options.resizableColumnGuide) {
					self.resize(e, column);
					guideEl.remove();
				}
				if (self.startColumn.modules.edit) self.startColumn.modules.edit.blocked = false;
				if (self.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight) column.checkCellHeights();
				document.body.removeEventListener("mouseup", mouseUp);
				document.body.removeEventListener("mousemove", mouseMove);
				handle.removeEventListener("touchmove", mouseMove);
				handle.removeEventListener("touchend", mouseUp);
				self.table.element.classList.remove("tabulator-block-select");
				if (self.startWidth !== column.getWidth()) {
					self.table.columnManager.verticalAlignHeaders();
					self.dispatch("column-resized", column);
					self.dispatchExternal("columnResized", column.getComponent());
				}
			}
			e.stopPropagation();
			if (self.startColumn.modules.edit) self.startColumn.modules.edit.blocked = true;
			self.startX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX;
			self.latestX = self.startX;
			self.startWidth = column.getWidth();
			document.body.addEventListener("mousemove", mouseMove);
			document.body.addEventListener("mouseup", mouseUp);
			handle.addEventListener("touchmove", mouseMove, { passive: true });
			handle.addEventListener("touchend", mouseUp);
		}
	};
	var ResizeRows = class extends Module {
		static moduleName = "resizeRows";
		constructor(table) {
			super(table);
			this.startColumn = false;
			this.startY = false;
			this.startHeight = false;
			this.handle = null;
			this.prevHandle = null;
			this.registerTableOption("resizableRows", false);
			this.registerTableOption("resizableRowGuide", false);
		}
		initialize() {
			if (this.table.options.resizableRows) this.subscribe("row-layout-after", this.initializeRow.bind(this));
		}
		initializeRow(row) {
			var self = this, rowEl = row.getElement();
			var handle = document.createElement("div");
			handle.className = "tabulator-row-resize-handle";
			var prevHandle = document.createElement("div");
			prevHandle.className = "tabulator-row-resize-handle prev";
			handle.addEventListener("click", function(e) {
				e.stopPropagation();
			});
			var handleDown = function(e) {
				self.startRow = row;
				self._mouseDown(e, row, handle);
			};
			handle.addEventListener("mousedown", handleDown);
			handle.addEventListener("touchstart", handleDown, { passive: true });
			prevHandle.addEventListener("click", function(e) {
				e.stopPropagation();
			});
			var prevHandleDown = function(e) {
				var prevRow = self.table.rowManager.prevDisplayRow(row);
				if (prevRow) {
					self.startRow = prevRow;
					self._mouseDown(e, prevRow, prevHandle);
				}
			};
			prevHandle.addEventListener("mousedown", prevHandleDown);
			prevHandle.addEventListener("touchstart", prevHandleDown, { passive: true });
			rowEl.appendChild(handle);
			rowEl.appendChild(prevHandle);
		}
		resize(e, row) {
			row.setHeight(this.startHeight + ((typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY) - this.startY));
		}
		calcGuidePosition(e, row, handle) {
			var mouseY = typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY, handleY = handle.getBoundingClientRect().y - this.table.element.getBoundingClientRect().y, tableY = this.table.element.getBoundingClientRect().y, rowY = row.element.getBoundingClientRect().top - tableY, mouseDiff = mouseY - this.startY;
			return Math.max(handleY + mouseDiff, rowY);
		}
		_mouseDown(e, row, handle) {
			var self = this, guideEl;
			self.dispatchExternal("rowResizing", row.getComponent());
			if (self.table.options.resizableRowGuide) {
				guideEl = document.createElement("span");
				guideEl.classList.add("tabulator-row-resize-guide");
				self.table.element.appendChild(guideEl);
				setTimeout(() => {
					guideEl.style.top = self.calcGuidePosition(e, row, handle) + "px";
				});
			}
			self.table.element.classList.add("tabulator-block-select");
			function mouseMove(e) {
				if (self.table.options.resizableRowGuide) guideEl.style.top = self.calcGuidePosition(e, row, handle) + "px";
				else self.resize(e, row);
			}
			function mouseUp(e) {
				if (self.table.options.resizableRowGuide) {
					self.resize(e, row);
					guideEl.remove();
				}
				document.body.removeEventListener("mouseup", mouseMove);
				document.body.removeEventListener("mousemove", mouseMove);
				handle.removeEventListener("touchmove", mouseMove);
				handle.removeEventListener("touchend", mouseUp);
				self.table.element.classList.remove("tabulator-block-select");
				self.dispatchExternal("rowResized", row.getComponent());
			}
			e.stopPropagation();
			self.startY = typeof e.screenY === "undefined" ? e.touches[0].screenY : e.screenY;
			self.startHeight = row.getHeight();
			document.body.addEventListener("mousemove", mouseMove);
			document.body.addEventListener("mouseup", mouseUp);
			handle.addEventListener("touchmove", mouseMove, { passive: true });
			handle.addEventListener("touchend", mouseUp);
		}
	};
	var ResizeTable = class extends Module {
		static moduleName = "resizeTable";
		constructor(table) {
			super(table);
			this.binding = false;
			this.visibilityObserver = false;
			this.resizeObserver = false;
			this.containerObserver = false;
			this.tableHeight = 0;
			this.tableWidth = 0;
			this.containerHeight = 0;
			this.containerWidth = 0;
			this.autoResize = false;
			this.visible = false;
			this.initialized = false;
			this.initialRedraw = false;
			this.registerTableOption("autoResize", true);
		}
		initialize() {
			if (this.table.options.autoResize) {
				var table = this.table, tableStyle;
				this.tableHeight = table.element.clientHeight;
				this.tableWidth = table.element.clientWidth;
				if (table.element.parentNode) {
					this.containerHeight = table.element.parentNode.clientHeight;
					this.containerWidth = table.element.parentNode.clientWidth;
				}
				if (typeof IntersectionObserver !== "undefined" && typeof ResizeObserver !== "undefined" && table.rowManager.getRenderMode() === "virtual") {
					this.initializeVisibilityObserver();
					this.autoResize = true;
					this.resizeObserver = new ResizeObserver((entry) => {
						if (!table.browserMobile || table.browserMobile && (!table.modules.edit || table.modules.edit && !table.modules.edit.currentCell)) {
							var nodeHeight = Math.floor(entry[0].contentRect.height);
							var nodeWidth = Math.floor(entry[0].contentRect.width);
							if (this.tableHeight != nodeHeight || this.tableWidth != nodeWidth) {
								this.tableHeight = nodeHeight;
								this.tableWidth = nodeWidth;
								if (table.element.parentNode) {
									this.containerHeight = table.element.parentNode.clientHeight;
									this.containerWidth = table.element.parentNode.clientWidth;
								}
								this.redrawTable();
							}
						}
					});
					this.resizeObserver.observe(table.element);
					tableStyle = window.getComputedStyle(table.element);
					if (this.table.element.parentNode && !this.table.rowManager.fixedHeight && (tableStyle.getPropertyValue("max-height") || tableStyle.getPropertyValue("min-height"))) {
						this.containerObserver = new ResizeObserver((entry) => {
							if (!table.browserMobile || table.browserMobile && (!table.modules.edit || table.modules.edit && !table.modules.edit.currentCell)) {
								var nodeHeight = Math.floor(entry[0].contentRect.height);
								var nodeWidth = Math.floor(entry[0].contentRect.width);
								if (this.containerHeight != nodeHeight || this.containerWidth != nodeWidth) {
									this.containerHeight = nodeHeight;
									this.containerWidth = nodeWidth;
									this.tableHeight = table.element.clientHeight;
									this.tableWidth = table.element.clientWidth;
								}
								this.redrawTable();
							}
						});
						this.containerObserver.observe(this.table.element.parentNode);
					}
					this.subscribe("table-resize", this.tableResized.bind(this));
				} else {
					this.binding = function() {
						if (!table.browserMobile || table.browserMobile && (!table.modules.edit || table.modules.edit && !table.modules.edit.currentCell)) {
							table.columnManager.rerenderColumns(true);
							table.redraw();
						}
					};
					window.addEventListener("resize", this.binding);
				}
				this.subscribe("table-destroy", this.clearBindings.bind(this));
			}
		}
		initializeVisibilityObserver() {
			this.visibilityObserver = new IntersectionObserver((entries) => {
				this.visible = entries[0].isIntersecting;
				if (!this.initialized) {
					this.initialized = true;
					this.initialRedraw = !this.visible;
				} else if (this.visible) {
					this.redrawTable(this.initialRedraw);
					this.initialRedraw = false;
				}
			});
			this.visibilityObserver.observe(this.table.element);
		}
		redrawTable(force) {
			if (this.initialized && this.visible) {
				this.table.columnManager.rerenderColumns(true);
				this.table.redraw(force);
			}
		}
		tableResized() {
			this.table.rowManager.redraw();
		}
		clearBindings() {
			if (this.binding) window.removeEventListener("resize", this.binding);
			if (this.resizeObserver) this.resizeObserver.unobserve(this.table.element);
			if (this.visibilityObserver) this.visibilityObserver.unobserve(this.table.element);
			if (this.containerObserver) this.containerObserver.unobserve(this.table.element.parentNode);
		}
	};
	function responsiveCollapse(cell, formatterParams, onRendered) {
		var el = document.createElement("div"), config = cell.getRow()._row.modules.responsiveLayout;
		el.classList.add("tabulator-responsive-collapse-toggle");
		el.innerHTML = `<svg class='tabulator-responsive-collapse-toggle-open' viewbox="0 0 24 24">
  <line x1="7" y1="12" x2="17" y2="12" fill="none" stroke-width="3" stroke-linecap="round" />
  <line y1="7" x1="12" y2="17" x2="12" fill="none" stroke-width="3" stroke-linecap="round" />
</svg>

<svg class='tabulator-responsive-collapse-toggle-close' viewbox="0 0 24 24">
  <line x1="7" y1="12" x2="17" y2="12"  fill="none" stroke-width="3" stroke-linecap="round" />
</svg>`;
		cell.getElement().classList.add("tabulator-row-handle");
		function toggleList(isOpen) {
			var collapseEl = config.element;
			config.open = isOpen;
			if (collapseEl) if (config.open) {
				el.classList.add("open");
				collapseEl.style.display = "";
			} else {
				el.classList.remove("open");
				collapseEl.style.display = "none";
			}
		}
		el.addEventListener("click", function(e) {
			e.stopImmediatePropagation();
			toggleList(!config.open);
			cell.getTable().rowManager.adjustTableSize();
		});
		toggleList(config.open);
		return el;
	}
	var extensions$2 = { format: { formatters: { responsiveCollapse } } };
	var ResponsiveLayout = class extends Module {
		static moduleName = "responsiveLayout";
		static moduleExtensions = extensions$2;
		constructor(table) {
			super(table);
			this.columns = [];
			this.hiddenColumns = [];
			this.mode = "";
			this.index = 0;
			this.collapseFormatter = [];
			this.collapseStartOpen = true;
			this.collapseHandleColumn = false;
			this.registerTableOption("responsiveLayout", false);
			this.registerTableOption("responsiveLayoutCollapseStartOpen", true);
			this.registerTableOption("responsiveLayoutCollapseUseFormatters", true);
			this.registerTableOption("responsiveLayoutCollapseFormatter", false);
			this.registerColumnOption("responsive");
		}
		initialize() {
			if (this.table.options.responsiveLayout) {
				this.subscribe("column-layout", this.initializeColumn.bind(this));
				this.subscribe("column-show", this.updateColumnVisibility.bind(this));
				this.subscribe("column-hide", this.updateColumnVisibility.bind(this));
				this.subscribe("columns-loaded", this.initializeResponsivity.bind(this));
				this.subscribe("column-moved", this.initializeResponsivity.bind(this));
				this.subscribe("column-add", this.initializeResponsivity.bind(this));
				this.subscribe("column-delete", this.initializeResponsivity.bind(this));
				this.subscribe("table-redrawing", this.tableRedraw.bind(this));
				if (this.table.options.responsiveLayout === "collapse") {
					this.subscribe("row-data-changed", this.generateCollapsedRowContent.bind(this));
					this.subscribe("row-init", this.initializeRow.bind(this));
					this.subscribe("row-layout", this.layoutRow.bind(this));
				}
			}
		}
		tableRedraw(force) {
			if (["fitColumns", "fitDataStretch"].indexOf(this.layoutMode()) === -1) {
				if (!force) this.update();
			}
		}
		initializeResponsivity() {
			var columns = [];
			this.mode = this.table.options.responsiveLayout;
			this.collapseFormatter = this.table.options.responsiveLayoutCollapseFormatter || this.formatCollapsedData;
			this.collapseStartOpen = this.table.options.responsiveLayoutCollapseStartOpen;
			this.hiddenColumns = [];
			if (this.collapseFormatter) this.collapseFormatter = this.collapseFormatter.bind(this.table);
			this.table.columnManager.columnsByIndex.forEach((column, i) => {
				if (column.modules.responsive) {
					if (column.modules.responsive.order && column.modules.responsive.visible) {
						column.modules.responsive.index = i;
						columns.push(column);
						if (!column.visible && this.mode === "collapse") this.hiddenColumns.push(column);
					}
				}
			});
			columns = columns.reverse();
			columns = columns.sort((a, b) => {
				return b.modules.responsive.order - a.modules.responsive.order || b.modules.responsive.index - a.modules.responsive.index;
			});
			this.columns = columns;
			if (this.mode === "collapse") this.generateCollapsedContent();
			for (let col of this.table.columnManager.columnsByIndex) if (col.definition.formatter == "responsiveCollapse") {
				this.collapseHandleColumn = col;
				break;
			}
			if (this.collapseHandleColumn) if (this.hiddenColumns.length) this.collapseHandleColumn.show();
			else this.collapseHandleColumn.hide();
		}
		initializeColumn(column) {
			var def = column.getDefinition();
			column.modules.responsive = {
				order: typeof def.responsive === "undefined" ? 1 : def.responsive,
				visible: def.visible === false ? false : true
			};
		}
		initializeRow(row) {
			var el;
			if (row.type !== "calc") {
				el = document.createElement("div");
				el.classList.add("tabulator-responsive-collapse");
				row.modules.responsiveLayout = {
					element: el,
					open: this.collapseStartOpen
				};
				if (!this.collapseStartOpen) el.style.display = "none";
			}
		}
		layoutRow(row) {
			var rowEl = row.getElement();
			if (row.modules.responsiveLayout) {
				rowEl.appendChild(row.modules.responsiveLayout.element);
				this.generateCollapsedRowContent(row);
			}
		}
		updateColumnVisibility(column, responsiveToggle) {
			if (!responsiveToggle && column.modules.responsive) {
				column.modules.responsive.visible = column.visible;
				this.initializeResponsivity();
			}
		}
		hideColumn(column) {
			var colCount = this.hiddenColumns.length;
			column.hide(false, true);
			if (this.mode === "collapse") {
				this.hiddenColumns.unshift(column);
				this.generateCollapsedContent();
				if (this.collapseHandleColumn && !colCount) this.collapseHandleColumn.show();
			}
		}
		showColumn(column) {
			var index;
			column.show(false, true);
			column.setWidth(column.getWidth());
			if (this.mode === "collapse") {
				index = this.hiddenColumns.indexOf(column);
				if (index > -1) this.hiddenColumns.splice(index, 1);
				this.generateCollapsedContent();
				if (this.collapseHandleColumn && !this.hiddenColumns.length) this.collapseHandleColumn.hide();
			}
		}
		update() {
			var working = true;
			while (working) {
				let width = this.table.modules.layout.getMode() == "fitColumns" ? this.table.columnManager.getFlexBaseWidth() : this.table.columnManager.getWidth();
				let diff = (this.table.options.headerVisible ? this.table.columnManager.element.clientWidth : this.table.element.clientWidth) - width;
				if (diff < 0) {
					let column = this.columns[this.index];
					if (column) {
						this.hideColumn(column);
						this.index++;
					} else working = false;
				} else {
					let column = this.columns[this.index - 1];
					if (column) if (diff > 0) if (diff >= column.getWidth()) {
						this.showColumn(column);
						this.index--;
					} else working = false;
					else working = false;
					else working = false;
				}
				if (!this.table.rowManager.activeRowsCount) this.table.rowManager.renderEmptyScroll();
			}
		}
		generateCollapsedContent() {
			this.table.rowManager.getDisplayRows().forEach((row) => {
				this.generateCollapsedRowContent(row);
			});
		}
		generateCollapsedRowContent(row) {
			var el, contents;
			if (row.modules.responsiveLayout) {
				el = row.modules.responsiveLayout.element;
				while (el.firstChild) el.removeChild(el.firstChild);
				contents = this.collapseFormatter(this.generateCollapsedRowData(row));
				if (contents) el.appendChild(contents);
				row.calcHeight(true);
			}
		}
		generateCollapsedRowData(row) {
			var data = row.getData(), output = [], mockCellComponent;
			this.hiddenColumns.forEach((column) => {
				var value = column.getFieldValue(data);
				if (column.definition.title && column.field) if (column.modules.format && this.table.options.responsiveLayoutCollapseUseFormatters) {
					mockCellComponent = {
						value: false,
						data: {},
						getValue: function() {
							return value;
						},
						getData: function() {
							return data;
						},
						getType: function() {
							return "cell";
						},
						getElement: function() {
							return document.createElement("div");
						},
						getRow: function() {
							return row.getComponent();
						},
						getColumn: function() {
							return column.getComponent();
						},
						getTable: () => {
							return this.table;
						}
					};
					function onRendered(callback) {
						callback();
					}
					output.push({
						field: column.field,
						title: column.definition.title,
						value: column.modules.format.formatter.call(this.table.modules.format, mockCellComponent, column.modules.format.params, onRendered)
					});
				} else output.push({
					field: column.field,
					title: column.definition.title,
					value
				});
			});
			return output;
		}
		formatCollapsedData(data) {
			var list = document.createElement("table");
			data.forEach((item) => {
				var row = document.createElement("tr");
				var titleData = document.createElement("td");
				var valueData = document.createElement("td");
				var node_content;
				var titleHighlight = document.createElement("strong");
				titleData.appendChild(titleHighlight);
				this.modules.localize.bind("columns|" + item.field, function(text) {
					titleHighlight.innerHTML = text || item.title;
				});
				if (item.value instanceof Node) {
					node_content = document.createElement("div");
					node_content.appendChild(item.value);
					valueData.appendChild(node_content);
				} else valueData.innerHTML = item.value;
				row.appendChild(titleData);
				row.appendChild(valueData);
				list.appendChild(row);
			});
			return Object.keys(data).length ? list : "";
		}
	};
	function rowSelection(cell, formatterParams, onRendered) {
		var checkbox = document.createElement("input");
		var blocked = false;
		checkbox.type = "checkbox";
		checkbox.setAttribute("aria-label", "Select Row");
		if (this.table.modExists("selectRow", true)) {
			checkbox.addEventListener("click", (e) => {
				e.stopPropagation();
			});
			if (typeof cell.getRow == "function") {
				var row = cell.getRow();
				if (row instanceof RowComponent) {
					checkbox.addEventListener("change", (e) => {
						if (this.table.options.selectableRowsRangeMode === "click") if (!blocked) row.toggleSelect();
						else blocked = false;
						else row.toggleSelect();
					});
					if (this.table.options.selectableRowsRangeMode === "click") checkbox.addEventListener("click", (e) => {
						blocked = true;
						this.table.modules.selectRow.handleComplexRowClick(row._row, e);
					});
					checkbox.checked = row.isSelected && row.isSelected();
					this.table.modules.selectRow.registerRowSelectCheckbox(row, checkbox);
				} else checkbox = "";
			} else {
				checkbox.addEventListener("change", (e) => {
					if (this.table.modules.selectRow.selectedRows.length) this.table.deselectRow();
					else this.table.selectRow(formatterParams.rowRange);
				});
				this.table.modules.selectRow.registerHeaderSelectCheckbox(checkbox);
			}
		}
		return checkbox;
	}
	var extensions$1 = { format: { formatters: { rowSelection } } };
	var SelectRow = class extends Module {
		static moduleName = "selectRow";
		static moduleExtensions = extensions$1;
		constructor(table) {
			super(table);
			this.selecting = false;
			this.lastClickedRow = false;
			this.selectPrev = [];
			this.selectedRows = [];
			this.headerCheckboxElement = null;
			this.registerTableOption("selectableRows", "highlight");
			this.registerTableOption("selectableRowsRangeMode", "drag");
			this.registerTableOption("selectableRowsRollingSelection", true);
			this.registerTableOption("selectableRowsPersistence", true);
			this.registerTableOption("selectableRowsCheck", function(data, row) {
				return true;
			});
			this.registerTableFunction("selectRow", this.selectRows.bind(this));
			this.registerTableFunction("deselectRow", this.deselectRows.bind(this));
			this.registerTableFunction("toggleSelectRow", this.toggleRow.bind(this));
			this.registerTableFunction("getSelectedRows", this.getSelectedRows.bind(this));
			this.registerTableFunction("getSelectedData", this.getSelectedData.bind(this));
			this.registerComponentFunction("row", "select", this.selectRows.bind(this));
			this.registerComponentFunction("row", "deselect", this.deselectRows.bind(this));
			this.registerComponentFunction("row", "toggleSelect", this.toggleRow.bind(this));
			this.registerComponentFunction("row", "isSelected", this.isRowSelected.bind(this));
		}
		initialize() {
			this.deprecatedOptionsCheck();
			if (this.table.options.selectableRows === "highlight" && this.table.options.selectableRange) this.table.options.selectableRows = false;
			if (this.table.options.selectableRows !== false) {
				this.subscribe("row-init", this.initializeRow.bind(this));
				this.subscribe("row-deleting", this.rowDeleted.bind(this));
				this.subscribe("rows-wipe", this.clearSelectionData.bind(this));
				this.subscribe("rows-retrieve", this.rowRetrieve.bind(this));
				if (this.table.options.selectableRows && !this.table.options.selectableRowsPersistence) this.subscribe("data-refreshing", this.deselectRows.bind(this));
			}
		}
		deprecatedOptionsCheck() {}
		rowRetrieve(type, prevValue) {
			return type === "selected" ? this.selectedRows : prevValue;
		}
		rowDeleted(row) {
			this._deselectRow(row, true);
		}
		clearSelectionData(silent) {
			var prevSelected = this.selectedRows.length;
			this.selecting = false;
			this.lastClickedRow = false;
			this.selectPrev = [];
			this.selectedRows = [];
			if (prevSelected && silent !== true) this._rowSelectionChanged();
		}
		initializeRow(row) {
			var self = this, selectable = self.checkRowSelectability(row), element = row.getElement();
			var endSelect = function() {
				setTimeout(function() {
					self.selecting = false;
				}, 50);
				document.body.removeEventListener("mouseup", endSelect);
			};
			row.modules.select = { selected: false };
			element.classList.toggle("tabulator-selectable", selectable);
			element.classList.toggle("tabulator-unselectable", !selectable);
			if (self.checkRowSelectability(row)) {
				if (self.table.options.selectableRows && self.table.options.selectableRows != "highlight") if (self.table.options.selectableRowsRangeMode === "click") element.addEventListener("click", this.handleComplexRowClick.bind(this, row));
				else {
					element.addEventListener("click", function(e) {
						if (!self.table.modExists("edit") || !self.table.modules.edit.getCurrentCell()) self.table._clearSelection();
						if (!self.selecting) self.toggleRow(row);
					});
					element.addEventListener("mousedown", function(e) {
						if (e.shiftKey) {
							self.table._clearSelection();
							self.selecting = true;
							self.selectPrev = [];
							document.body.addEventListener("mouseup", endSelect);
							document.body.addEventListener("keyup", endSelect);
							self.toggleRow(row);
							return false;
						}
					});
					element.addEventListener("mouseenter", function(e) {
						if (self.selecting) {
							self.table._clearSelection();
							self.toggleRow(row);
							if (self.selectPrev[1] == row) self.toggleRow(self.selectPrev[0]);
						}
					});
					element.addEventListener("mouseout", function(e) {
						if (self.selecting) {
							self.table._clearSelection();
							self.selectPrev.unshift(row);
						}
					});
				}
			}
		}
		handleComplexRowClick(row, e) {
			if (e.shiftKey) {
				this.table._clearSelection();
				this.lastClickedRow = this.lastClickedRow || row;
				var lastClickedRowIdx = this.table.rowManager.getDisplayRowIndex(this.lastClickedRow);
				var rowIdx = this.table.rowManager.getDisplayRowIndex(row);
				var fromRowIdx = lastClickedRowIdx <= rowIdx ? lastClickedRowIdx : rowIdx;
				var toRowIdx = lastClickedRowIdx >= rowIdx ? lastClickedRowIdx : rowIdx;
				var toggledRows = this.table.rowManager.getDisplayRows().slice(0).splice(fromRowIdx, toRowIdx - fromRowIdx + 1);
				if (e.ctrlKey || e.metaKey) {
					toggledRows.forEach((toggledRow) => {
						if (toggledRow !== this.lastClickedRow) if (this.table.options.selectableRows !== true && !this.isRowSelected(row)) {
							if (this.selectedRows.length < this.table.options.selectableRows) this.toggleRow(toggledRow);
						} else this.toggleRow(toggledRow);
					});
					this.lastClickedRow = row;
				} else {
					this.deselectRows(void 0, true);
					if (this.table.options.selectableRows !== true) {
						if (toggledRows.length > this.table.options.selectableRows) toggledRows = toggledRows.slice(0, this.table.options.selectableRows);
					}
					this.selectRows(toggledRows);
				}
				this.table._clearSelection();
			} else if (e.ctrlKey || e.metaKey) {
				this.toggleRow(row);
				this.lastClickedRow = row;
			} else {
				this.deselectRows(void 0, true);
				this.selectRows(row);
				this.lastClickedRow = row;
			}
		}
		checkRowSelectability(row) {
			if (row && row.type === "row") return this.table.options.selectableRowsCheck.call(this.table, row.getComponent());
			return false;
		}
		toggleRow(row) {
			if (this.checkRowSelectability(row)) if (row.modules.select && row.modules.select.selected) this._deselectRow(row);
			else this._selectRow(row);
		}
		selectRows(rows) {
			var changes = [], rowMatch, change;
			switch (typeof rows) {
				case "undefined":
					rowMatch = this.table.rowManager.rows;
					break;
				case "number":
					rowMatch = this.table.rowManager.findRow(rows);
					break;
				case "string":
					rowMatch = this.table.rowManager.findRow(rows);
					if (!rowMatch) rowMatch = this.table.rowManager.getRows(rows);
					break;
				default:
					rowMatch = rows;
					break;
			}
			if (Array.isArray(rowMatch)) {
				if (rowMatch.length) {
					rowMatch.forEach((row) => {
						change = this._selectRow(row, true, true);
						if (change) changes.push(change);
					});
					this._rowSelectionChanged(false, changes);
				}
			} else if (rowMatch) this._selectRow(rowMatch, false, true);
		}
		_selectRow(rowInfo, silent, force) {
			if (!isNaN(this.table.options.selectableRows) && this.table.options.selectableRows !== true && !force) {
				if (this.selectedRows.length >= this.table.options.selectableRows) if (this.table.options.selectableRowsRollingSelection) this._deselectRow(this.selectedRows[0]);
				else return false;
			}
			var row = this.table.rowManager.findRow(rowInfo);
			if (row) {
				if (this.selectedRows.indexOf(row) == -1) {
					row.getElement().classList.add("tabulator-selected");
					if (!row.modules.select) row.modules.select = {};
					row.modules.select.selected = true;
					if (row.modules.select.checkboxEl) row.modules.select.checkboxEl.checked = true;
					this.selectedRows.push(row);
					if (this.table.options.dataTreeSelectPropagate) this.childRowSelection(row, true);
					this.dispatchExternal("rowSelected", row.getComponent());
					this._rowSelectionChanged(silent, row);
					return row;
				}
			} else if (!silent) console.warn("Selection Error - No such row found, ignoring selection:" + rowInfo);
		}
		isRowSelected(row) {
			return this.selectedRows.indexOf(row) !== -1;
		}
		deselectRows(rows, silent) {
			var changes = [], rowMatch, change;
			switch (typeof rows) {
				case "undefined":
					rowMatch = Object.assign([], this.selectedRows);
					break;
				case "number":
					rowMatch = this.table.rowManager.findRow(rows);
					break;
				case "string":
					rowMatch = this.table.rowManager.findRow(rows);
					if (!rowMatch) rowMatch = this.table.rowManager.getRows(rows);
					break;
				default:
					rowMatch = rows;
					break;
			}
			if (Array.isArray(rowMatch)) {
				if (rowMatch.length) {
					rowMatch.forEach((row) => {
						change = this._deselectRow(row, true, true);
						if (change) changes.push(change);
					});
					this._rowSelectionChanged(silent, [], changes);
				}
			} else if (rowMatch) this._deselectRow(rowMatch, silent, true);
		}
		_deselectRow(rowInfo, silent) {
			var self = this, row = self.table.rowManager.findRow(rowInfo), index, element;
			if (row) {
				index = self.selectedRows.findIndex(function(selectedRow) {
					return selectedRow == row;
				});
				if (index > -1) {
					element = row.getElement();
					if (element) element.classList.remove("tabulator-selected");
					if (!row.modules.select) row.modules.select = {};
					row.modules.select.selected = false;
					if (row.modules.select.checkboxEl) row.modules.select.checkboxEl.checked = false;
					self.selectedRows.splice(index, 1);
					if (this.table.options.dataTreeSelectPropagate) this.childRowSelection(row, false);
					this.dispatchExternal("rowDeselected", row.getComponent());
					self._rowSelectionChanged(silent, void 0, row);
					return row;
				}
			} else if (!silent) console.warn("Deselection Error - No such row found, ignoring selection:" + rowInfo);
		}
		getSelectedData() {
			var data = [];
			this.selectedRows.forEach(function(row) {
				data.push(row.getData());
			});
			return data;
		}
		getSelectedRows() {
			var rows = [];
			this.selectedRows.forEach(function(row) {
				rows.push(row.getComponent());
			});
			return rows;
		}
		_rowSelectionChanged(silent, selected = [], deselected = []) {
			if (this.headerCheckboxElement) if (this.selectedRows.length === 0) {
				this.headerCheckboxElement.checked = false;
				this.headerCheckboxElement.indeterminate = false;
			} else if (this.table.rowManager.rows.length === this.selectedRows.length) {
				this.headerCheckboxElement.checked = true;
				this.headerCheckboxElement.indeterminate = false;
			} else {
				this.headerCheckboxElement.indeterminate = true;
				this.headerCheckboxElement.checked = false;
			}
			if (!silent) {
				if (!Array.isArray(selected)) selected = [selected];
				selected = selected.map((row) => row.getComponent());
				if (!Array.isArray(deselected)) deselected = [deselected];
				deselected = deselected.map((row) => row.getComponent());
				this.dispatchExternal("rowSelectionChanged", this.getSelectedData(), this.getSelectedRows(), selected, deselected);
			}
		}
		registerRowSelectCheckbox(row, element) {
			if (!row._row.modules.select) row._row.modules.select = {};
			row._row.modules.select.checkboxEl = element;
		}
		registerHeaderSelectCheckbox(element) {
			this.headerCheckboxElement = element;
		}
		childRowSelection(row, select) {
			var children = this.table.modules.dataTree.getChildren(row, true, true);
			if (select) for (let child of children) this._selectRow(child, true);
			else for (let child of children) this._deselectRow(child, true);
		}
	};
	var RangeComponent = class {
		constructor(range) {
			this._range = range;
			return new Proxy(this, { get: function(target, name, receiver) {
				if (typeof target[name] !== "undefined") return target[name];
				else return target._range.table.componentFunctionBinder.handle("range", target._range, name);
			} });
		}
		getElement() {
			return this._range.element;
		}
		getData() {
			return this._range.getData();
		}
		getCells() {
			return this._range.getCells(true, true);
		}
		getStructuredCells() {
			return this._range.getStructuredCells();
		}
		getRows() {
			return this._range.getRows().map((row) => row.getComponent());
		}
		getColumns() {
			return this._range.getColumns().map((column) => column.getComponent());
		}
		getBounds() {
			return this._range.getBounds();
		}
		getTopEdge() {
			return this._range.top;
		}
		getBottomEdge() {
			return this._range.bottom;
		}
		getLeftEdge() {
			return this._range.left;
		}
		getRightEdge() {
			return this._range.right;
		}
		setBounds(start, end) {
			if (this._range.destroyedGuard("setBounds")) this._range.setBounds(start ? start._cell : start, end ? end._cell : end);
		}
		setStartBound(start) {
			if (this._range.destroyedGuard("setStartBound")) {
				this._range.setEndBound(start ? start._cell : start);
				this._range.rangeManager.layoutElement();
			}
		}
		setEndBound(end) {
			if (this._range.destroyedGuard("setEndBound")) {
				this._range.setEndBound(end ? end._cell : end);
				this._range.rangeManager.layoutElement();
			}
		}
		clearValues() {
			if (this._range.destroyedGuard("clearValues")) this._range.clearValues();
		}
		remove() {
			if (this._range.destroyedGuard("remove")) this._range.destroy(true);
		}
	};
	var Range = class extends CoreFeature {
		constructor(table, rangeManager, start, end) {
			super(table);
			this.rangeManager = rangeManager;
			this.element = null;
			this.initialized = false;
			this.initializing = {
				start: false,
				end: false
			};
			this.destroyed = false;
			this.top = 0;
			this.bottom = 0;
			this.left = 0;
			this.right = 0;
			this.table = table;
			this.start = {
				row: 0,
				col: 0
			};
			this.end = {
				row: 0,
				col: 0
			};
			if (this.rangeManager.rowHeader) {
				this.left = 1;
				this.right = 1;
				this.start.col = 1;
				this.end.col = 1;
			}
			this.initElement();
			setTimeout(() => {
				this.initBounds(start, end);
			});
		}
		initElement() {
			this.element = document.createElement("div");
			this.element.classList.add("tabulator-range");
		}
		initBounds(start, end) {
			this._updateMinMax();
			if (start) this.setBounds(start, end || start);
		}
		setStart(row, col) {
			if (this.start.row !== row || this.start.col !== col) {
				this.start.row = row;
				this.start.col = col;
				this.initializing.start = true;
				this._updateMinMax();
			}
		}
		setEnd(row, col) {
			if (this.end.row !== row || this.end.col !== col) {
				this.end.row = row;
				this.end.col = col;
				this.initializing.end = true;
				this._updateMinMax();
			}
		}
		setBounds(start, end, visibleRows) {
			if (start) this.setStartBound(start);
			this.setEndBound(end || start);
			this.rangeManager.layoutElement(visibleRows);
		}
		setStartBound(element) {
			var row, col;
			if (element.type === "column") {
				if (this.rangeManager.columnSelection) this.setStart(0, element.getPosition() - 1);
			} else {
				row = element.row.position - 1;
				col = element.column.getPosition() - 1;
				if (element.column === this.rangeManager.rowHeader) this.setStart(row, 1);
				else this.setStart(row, col);
			}
		}
		setEndBound(element) {
			var rowsCount = this._getTableRows().length, row, col, isRowHeader;
			if (element.type === "column") {
				if (this.rangeManager.columnSelection) {
					if (this.rangeManager.selecting === "column") this.setEnd(rowsCount - 1, element.getPosition() - 1);
					else if (this.rangeManager.selecting === "cell") this.setEnd(0, element.getPosition() - 1);
				}
			} else {
				row = element.row.position - 1;
				col = element.column.getPosition() - 1;
				isRowHeader = element.column === this.rangeManager.rowHeader;
				if (this.rangeManager.selecting === "row") this.setEnd(row, this._getTableColumns().length - 1);
				else if (this.rangeManager.selecting !== "row" && isRowHeader) this.setEnd(row, 0);
				else if (this.rangeManager.selecting === "column") this.setEnd(rowsCount - 1, col);
				else this.setEnd(row, col);
			}
		}
		_updateMinMax() {
			this.top = Math.min(this.start.row, this.end.row);
			this.bottom = Math.max(this.start.row, this.end.row);
			this.left = Math.min(this.start.col, this.end.col);
			this.right = Math.max(this.start.col, this.end.col);
			if (this.initialized) this.dispatchExternal("rangeChanged", this.getComponent());
			else if (this.initializing.start && this.initializing.end) {
				this.initialized = true;
				this.dispatchExternal("rangeAdded", this.getComponent());
			}
		}
		_getTableColumns() {
			return this.table.columnManager.getVisibleColumnsByIndex();
		}
		_getTableRows() {
			return this.table.rowManager.getDisplayRows().filter((row) => row.type === "row");
		}
		layout() {
			var _vDomTop = this.table.rowManager.renderer.vDomTop, _vDomBottom = this.table.rowManager.renderer.vDomBottom, _vDomLeft = this.table.columnManager.renderer.leftCol, _vDomRight = this.table.columnManager.renderer.rightCol, top, bottom, left, right, topLeftCell, bottomRightCell, topLeftCellEl, bottomRightCellEl, topLeftRowEl, bottomRightRowEl;
			if (this.table.options.renderHorizontal === "virtual" && this.rangeManager.rowHeader) _vDomRight += 1;
			if (_vDomTop == null) _vDomTop = 0;
			if (_vDomBottom == null) _vDomBottom = Infinity;
			if (_vDomLeft == null) _vDomLeft = 0;
			if (_vDomRight == null) _vDomRight = Infinity;
			if (this.overlaps(_vDomLeft, _vDomTop, _vDomRight, _vDomBottom)) {
				top = Math.max(this.top, _vDomTop);
				bottom = Math.min(this.bottom, _vDomBottom);
				left = Math.max(this.left, _vDomLeft);
				right = Math.min(this.right, _vDomRight);
				topLeftCell = this.rangeManager.getCell(top, left);
				bottomRightCell = this.rangeManager.getCell(bottom, right);
				topLeftCellEl = topLeftCell.getElement();
				bottomRightCellEl = bottomRightCell.getElement();
				topLeftRowEl = topLeftCell.row.getElement();
				bottomRightRowEl = bottomRightCell.row.getElement();
				this.element.classList.add("tabulator-range-active");
				if (this.table.rtl) {
					this.element.style.right = topLeftRowEl.offsetWidth - topLeftCellEl.offsetLeft - topLeftCellEl.offsetWidth + "px";
					this.element.style.width = topLeftCellEl.offsetLeft + topLeftCellEl.offsetWidth - bottomRightCellEl.offsetLeft + "px";
				} else {
					this.element.style.left = topLeftRowEl.offsetLeft + topLeftCellEl.offsetLeft + "px";
					this.element.style.width = bottomRightCellEl.offsetLeft + bottomRightCellEl.offsetWidth - topLeftCellEl.offsetLeft + "px";
				}
				this.element.style.top = topLeftRowEl.offsetTop + "px";
				this.element.style.height = bottomRightRowEl.offsetTop + bottomRightRowEl.offsetHeight - topLeftRowEl.offsetTop + "px";
			}
		}
		atTopLeft(cell) {
			return cell.row.position - 1 === this.top && cell.column.getPosition() - 1 === this.left;
		}
		atBottomRight(cell) {
			return cell.row.position - 1 === this.bottom && cell.column.getPosition() - 1 === this.right;
		}
		occupies(cell) {
			return this.occupiesRow(cell.row) && this.occupiesColumn(cell.column);
		}
		occupiesRow(row) {
			return this.top <= row.position - 1 && row.position - 1 <= this.bottom;
		}
		occupiesColumn(col) {
			return this.left <= col.getPosition() - 1 && col.getPosition() - 1 <= this.right;
		}
		overlaps(left, top, right, bottom) {
			if (this.left > right || left > this.right || this.top > bottom || top > this.bottom) return false;
			return true;
		}
		getData() {
			var data = [], rows = this.getRows(), columns = this.getColumns();
			rows.forEach((row) => {
				var rowData = row.getData(), result = {};
				columns.forEach((column) => {
					result[column.field] = rowData[column.field];
				});
				data.push(result);
			});
			return data;
		}
		getCells(structured, component) {
			var cells = [], rows = this.getRows(), columns = this.getColumns();
			if (structured) cells = rows.map((row) => {
				var arr = [];
				row.getCells().forEach((cell) => {
					if (columns.includes(cell.column)) arr.push(component ? cell.getComponent() : cell);
				});
				return arr;
			});
			else rows.forEach((row) => {
				row.getCells().forEach((cell) => {
					if (columns.includes(cell.column)) cells.push(component ? cell.getComponent() : cell);
				});
			});
			return cells;
		}
		getStructuredCells() {
			return this.getCells(true, true);
		}
		getRows() {
			return this._getTableRows().slice(this.top, this.bottom + 1);
		}
		getColumns() {
			return this._getTableColumns().slice(this.left, this.right + 1);
		}
		clearValues() {
			var cells = this.getCells();
			var clearValue = this.table.options.selectableRangeClearCellsValue;
			this.table.blockRedraw();
			cells.forEach((cell) => {
				cell.setValue(clearValue);
			});
			this.table.restoreRedraw();
		}
		getBounds(component) {
			var cells = this.getCells(false, component), output = {
				start: null,
				end: null
			};
			if (cells.length) {
				output.start = cells[0];
				output.end = cells[cells.length - 1];
			} else console.warn("No bounds defined on range");
			return output;
		}
		getComponent() {
			if (!this.component) this.component = new RangeComponent(this);
			return this.component;
		}
		destroy(notify) {
			this.destroyed = true;
			this.element.remove();
			if (notify) this.rangeManager.rangeRemoved(this);
			if (this.initialized) this.dispatchExternal("rangeRemoved", this.getComponent());
		}
		destroyedGuard(func) {
			if (this.destroyed) console.warn("You cannot call the " + func + " function on a destroyed range");
			return !this.destroyed;
		}
	};
	var extensions = {
		keybindings: {
			bindings: {
				rangeJumpUp: ["ctrl + 38", "meta + 38"],
				rangeJumpDown: ["ctrl + 40", "meta + 40"],
				rangeJumpLeft: ["ctrl + 37", "meta + 37"],
				rangeJumpRight: ["ctrl + 39", "meta + 39"],
				rangeExpandUp: "shift + 38",
				rangeExpandDown: "shift + 40",
				rangeExpandLeft: "shift + 37",
				rangeExpandRight: "shift + 39",
				rangeExpandJumpUp: ["ctrl + shift + 38", "meta + shift + 38"],
				rangeExpandJumpDown: ["ctrl + shift + 40", "meta + shift + 40"],
				rangeExpandJumpLeft: ["ctrl + shift + 37", "meta + shift + 37"],
				rangeExpandJumpRight: ["ctrl + shift + 39", "meta + shift + 39"]
			},
			actions: {
				rangeJumpLeft: function(e) {
					this.dispatch("keybinding-nav-range", e, "left", true, false);
				},
				rangeJumpRight: function(e) {
					this.dispatch("keybinding-nav-range", e, "right", true, false);
				},
				rangeJumpUp: function(e) {
					this.dispatch("keybinding-nav-range", e, "up", true, false);
				},
				rangeJumpDown: function(e) {
					this.dispatch("keybinding-nav-range", e, "down", true, false);
				},
				rangeExpandLeft: function(e) {
					this.dispatch("keybinding-nav-range", e, "left", false, true);
				},
				rangeExpandRight: function(e) {
					this.dispatch("keybinding-nav-range", e, "right", false, true);
				},
				rangeExpandUp: function(e) {
					this.dispatch("keybinding-nav-range", e, "up", false, true);
				},
				rangeExpandDown: function(e) {
					this.dispatch("keybinding-nav-range", e, "down", false, true);
				},
				rangeExpandJumpLeft: function(e) {
					this.dispatch("keybinding-nav-range", e, "left", true, true);
				},
				rangeExpandJumpRight: function(e) {
					this.dispatch("keybinding-nav-range", e, "right", true, true);
				},
				rangeExpandJumpUp: function(e) {
					this.dispatch("keybinding-nav-range", e, "up", true, true);
				},
				rangeExpandJumpDown: function(e) {
					this.dispatch("keybinding-nav-range", e, "down", true, true);
				}
			}
		},
		clipboard: {
			pasteActions: { range: function(data) {
				var rows = [], range = this.table.modules.selectRange.activeRange, singleCell = false, bounds, startCell, startRow, rowWidth, dataLength = data.length;
				if (range) {
					bounds = range.getBounds();
					startCell = bounds.start;
					if (bounds.start === bounds.end) singleCell = true;
					if (startCell) {
						rows = this.table.rowManager.activeRows.slice();
						startRow = rows.indexOf(startCell.row);
						if (singleCell) rowWidth = data.length;
						else rowWidth = rows.indexOf(bounds.end.row) - startRow + 1;
						if (startRow > -1) {
							this.table.blockRedraw();
							rows = rows.slice(startRow, startRow + rowWidth);
							rows.forEach((row, i) => {
								row.updateData(data[i % dataLength]);
							});
							this.table.restoreRedraw();
						}
					}
				}
				return rows;
			} },
			pasteParsers: { range: function(clipboard) {
				var data = [], rows = [], range = this.table.modules.selectRange.activeRange, singleCell = false, bounds, startCell, colWidth, columnMap, startCol;
				if (range) {
					bounds = range.getBounds();
					startCell = bounds.start;
					if (bounds.start === bounds.end) singleCell = true;
					if (startCell) {
						clipboard = clipboard.split("\n");
						clipboard.forEach(function(row) {
							data.push(row.split("	"));
						});
						if (data.length) {
							columnMap = this.table.columnManager.getVisibleColumnsByIndex();
							startCol = columnMap.indexOf(startCell.column);
							if (startCol > -1) {
								if (singleCell) colWidth = data[0].length;
								else colWidth = columnMap.indexOf(bounds.end.column) - startCol + 1;
								columnMap = columnMap.slice(startCol, startCol + colWidth);
								data.forEach((item) => {
									var row = {};
									var itemLength = item.length;
									columnMap.forEach(function(col, i) {
										row[col.field] = item[i % itemLength];
									});
									rows.push(row);
								});
								return rows;
							}
						}
					}
				}
				return false;
			} }
		},
		export: {
			columnLookups: { range: function() {
				var columns = this.modules.selectRange.selectedColumns();
				if (this.columnManager.rowHeader) columns.unshift(this.columnManager.rowHeader);
				return columns;
			} },
			rowLookups: { range: function() {
				return this.modules.selectRange.selectedRows();
			} }
		}
	};
	var SelectRange = class extends Module {
		static moduleName = "selectRange";
		static moduleInitOrder = 1;
		static moduleExtensions = extensions;
		constructor(table) {
			super(table);
			this.selecting = "cell";
			this.mousedown = false;
			this.ranges = [];
			this.overlay = null;
			this.rowHeader = null;
			this.layoutChangeTimeout = null;
			this.columnSelection = false;
			this.rowSelection = false;
			this.maxRanges = 0;
			this.activeRange = false;
			this.blockKeydown = false;
			this.keyDownEvent = this._handleKeyDown.bind(this);
			this.mouseUpEvent = this._handleMouseUp.bind(this);
			this.registerTableOption("selectableRange", false);
			this.registerTableOption("selectableRangeColumns", false);
			this.registerTableOption("selectableRangeRows", false);
			this.registerTableOption("selectableRangeClearCells", false);
			this.registerTableOption("selectableRangeClearCellsValue", void 0);
			this.registerTableOption("selectableRangeAutoFocus", true);
			this.registerTableFunction("getRangesData", this.getRangesData.bind(this));
			this.registerTableFunction("getRanges", this.getRanges.bind(this));
			this.registerTableFunction("addRange", this.addRangeFromComponent.bind(this));
			this.registerComponentFunction("cell", "getRanges", this.cellGetRanges.bind(this));
			this.registerComponentFunction("row", "getRanges", this.rowGetRanges.bind(this));
			this.registerComponentFunction("column", "getRanges", this.colGetRanges.bind(this));
		}
		initialize() {
			if (this.options("selectableRange")) {
				if (!this.options("selectableRows")) {
					this.maxRanges = this.options("selectableRange");
					this.initializeTable();
					this.initializeWatchers();
				} else console.warn("SelectRange functionality cannot be used in conjunction with row selection");
				if (this.options("columns").findIndex((column) => column.frozen) > 0) console.warn("Having frozen column in arbitrary position with selectRange option may result in unpredictable behavior.");
				if (this.options("columns").filter((column) => column.frozen) > 1) console.warn("Having multiple frozen columns with selectRange option may result in unpredictable behavior.");
			}
		}
		initializeTable() {
			this.overlay = document.createElement("div");
			this.overlay.classList.add("tabulator-range-overlay");
			this.rangeContainer = document.createElement("div");
			this.rangeContainer.classList.add("tabulator-range-container");
			this.activeRangeCellElement = document.createElement("div");
			this.activeRangeCellElement.classList.add("tabulator-range-cell-active");
			this.overlay.appendChild(this.rangeContainer);
			this.overlay.appendChild(this.activeRangeCellElement);
			this.table.rowManager.element.addEventListener("keydown", this.keyDownEvent);
			this.resetRanges();
			this.table.rowManager.element.appendChild(this.overlay);
			this.table.columnManager.element.setAttribute("tabindex", 0);
			this.table.element.classList.add("tabulator-ranges");
		}
		initializeWatchers() {
			this.columnSelection = this.options("selectableRangeColumns");
			this.rowSelection = this.options("selectableRangeRows");
			this.subscribe("column-init", this.initializeColumn.bind(this));
			this.subscribe("column-mousedown", this.handleColumnMouseDown.bind(this));
			this.subscribe("column-mousemove", this.handleColumnMouseMove.bind(this));
			this.subscribe("column-resized", this.handleColumnResized.bind(this));
			this.subscribe("column-moving", this.handleColumnMoving.bind(this));
			this.subscribe("column-moved", this.handleColumnMoved.bind(this));
			this.subscribe("column-width", this.layoutChange.bind(this));
			this.subscribe("column-height", this.layoutChange.bind(this));
			this.subscribe("column-resized", this.layoutChange.bind(this));
			this.subscribe("columns-loaded", this.updateHeaderColumn.bind(this));
			this.subscribe("cell-height", this.layoutChange.bind(this));
			this.subscribe("cell-rendered", this.renderCell.bind(this));
			this.subscribe("cell-mousedown", this.handleCellMouseDown.bind(this));
			this.subscribe("cell-mousemove", this.handleCellMouseMove.bind(this));
			this.subscribe("cell-click", this.handleCellClick.bind(this));
			this.subscribe("cell-editing", this.handleEditingCell.bind(this));
			this.subscribe("page-changed", this.redraw.bind(this));
			this.subscribe("scroll-vertical", this.layoutChange.bind(this));
			this.subscribe("scroll-horizontal", this.layoutChange.bind(this));
			this.subscribe("data-destroy", this.tableDestroyed.bind(this));
			this.subscribe("data-processed", this.resetRanges.bind(this));
			this.subscribe("table-layout", this.layoutElement.bind(this));
			this.subscribe("table-redraw", this.redraw.bind(this));
			this.subscribe("table-destroy", this.tableDestroyed.bind(this));
			this.subscribe("edit-editor-clear", this.finishEditingCell.bind(this));
			this.subscribe("edit-blur", this.restoreFocus.bind(this));
			this.subscribe("keybinding-nav-prev", this.keyNavigate.bind(this, "left"));
			this.subscribe("keybinding-nav-next", this.keyNavigate.bind(this, "right"));
			this.subscribe("keybinding-nav-left", this.keyNavigate.bind(this, "left"));
			this.subscribe("keybinding-nav-right", this.keyNavigate.bind(this, "right"));
			this.subscribe("keybinding-nav-up", this.keyNavigate.bind(this, "up"));
			this.subscribe("keybinding-nav-down", this.keyNavigate.bind(this, "down"));
			this.subscribe("keybinding-nav-range", this.keyNavigateRange.bind(this));
		}
		initializeColumn(column) {
			if (this.columnSelection && column.definition.headerSort && this.options("headerSortClickElement") !== "icon") console.warn("Using column headerSort with selectableRangeColumns option may result in unpredictable behavior. Consider using headerSortClickElement: 'icon'.");
			if (column.modules.edit);
		}
		updateHeaderColumn() {
			var frozenCols;
			if (this.rowSelection) {
				this.rowHeader = this.table.columnManager.getVisibleColumnsByIndex()[0];
				if (this.rowHeader) {
					this.rowHeader.definition.cssClass = this.rowHeader.definition.cssClass + " tabulator-range-row-header";
					if (this.rowHeader.definition.headerSort) console.warn("Using column headerSort with selectableRangeRows option may result in unpredictable behavior");
					if (this.rowHeader.definition.editor) console.warn("Using column editor with selectableRangeRows option may result in unpredictable behavior");
				}
			}
			if (this.table.modules.frozenColumns && this.table.modules.frozenColumns.active) {
				frozenCols = this.table.modules.frozenColumns.getFrozenColumns();
				if (frozenCols.length > 1 || frozenCols.length === 1 && frozenCols[0] !== this.rowHeader) console.warn("Using frozen columns that are not the range header in combination with the selectRange option may result in unpredictable behavior");
			}
		}
		getRanges() {
			return this.ranges.map((range) => range.getComponent());
		}
		getRangesData() {
			return this.ranges.map((range) => range.getData());
		}
		addRangeFromComponent(start, end) {
			start = start ? start._cell : null;
			end = end ? end._cell : null;
			return this.addRange(start, end);
		}
		cellGetRanges(cell) {
			var ranges = [];
			if (cell.column === this.rowHeader) ranges = this.ranges.filter((range) => range.occupiesRow(cell.row));
			else ranges = this.ranges.filter((range) => range.occupies(cell));
			return ranges.map((range) => range.getComponent());
		}
		rowGetRanges(row) {
			return this.ranges.filter((range) => range.occupiesRow(row)).map((range) => range.getComponent());
		}
		colGetRanges(col) {
			return this.ranges.filter((range) => range.occupiesColumn(col)).map((range) => range.getComponent());
		}
		_handleMouseUp(e) {
			this.mousedown = false;
			document.removeEventListener("mouseup", this.mouseUpEvent);
		}
		_handleKeyDown(e) {
			if (!this.blockKeydown && (!this.table.modules.edit || this.table.modules.edit && !this.table.modules.edit.currentCell)) {
				if (e.key === "Enter") {
					if (this.table.modules.edit && this.table.modules.edit.currentCell) return;
					this.table.modules.edit.editCell(this.getActiveCell());
					e.preventDefault();
				}
				if ((e.key === "Backspace" || e.key === "Delete") && this.options("selectableRangeClearCells")) {
					if (this.activeRange) this.activeRange.clearValues();
				}
			}
		}
		initializeFocus(cell) {
			var range;
			this.restoreFocus();
			try {
				if (document.selection) {
					range = document.body.createTextRange();
					range.moveToElementText(cell.getElement());
					range.select();
				} else if (window.getSelection) {
					range = document.createRange();
					range.selectNode(cell.getElement());
					window.getSelection().removeAllRanges();
					window.getSelection().addRange(range);
				}
			} catch (e) {}
		}
		restoreFocus(element) {
			this.table.rowManager.element.focus();
			return true;
		}
		handleColumnResized(column) {
			var selected;
			if (this.selecting !== "column" && this.selecting !== "all") return;
			selected = this.ranges.some((range) => range.occupiesColumn(column));
			if (!selected) return;
			this.ranges.forEach((range) => {
				range.getColumns(true).forEach((selectedColumn) => {
					if (selectedColumn !== column) selectedColumn.setWidth(column.width);
				});
			});
		}
		handleColumnMoving(_event, column) {
			this.resetRanges().setBounds(column);
			this.overlay.style.visibility = "hidden";
		}
		handleColumnMoved(from, _to, _after) {
			this.activeRange.setBounds(from);
			this.layoutElement();
		}
		handleColumnMouseDown(event, column) {
			if (event.button === 2 && (this.selecting === "column" || this.selecting === "all") && this.activeRange.occupiesColumn(column)) return;
			if (this.table.options.movableColumns && this.selecting === "column" && this.activeRange.occupiesColumn(column)) return;
			this.mousedown = true;
			document.addEventListener("mouseup", this.mouseUpEvent);
			this.newSelection(event, column);
		}
		handleColumnMouseMove(e, column) {
			if (column === this.rowHeader || !this.mousedown || this.selecting === "all") return;
			this.activeRange.setBounds(false, column, true);
		}
		renderCell(cell) {
			var el = cell.getElement(), rangeIdx = this.ranges.findIndex((range) => range.occupies(cell));
			el.classList.toggle("tabulator-range-selected", rangeIdx !== -1);
			el.classList.toggle("tabulator-range-only-cell-selected", this.ranges.length === 1 && this.ranges[0].atTopLeft(cell) && this.ranges[0].atBottomRight(cell));
			el.dataset.range = rangeIdx;
		}
		handleCellMouseDown(event, cell) {
			if (event.button === 2 && (this.activeRange.occupies(cell) || (this.selecting === "row" || this.selecting === "all") && this.activeRange.occupiesRow(cell.row))) return;
			this.mousedown = true;
			document.addEventListener("mouseup", this.mouseUpEvent);
			this.newSelection(event, cell);
		}
		handleCellMouseMove(e, cell) {
			if (!this.mousedown || this.selecting === "all") return;
			this.activeRange.setBounds(false, cell, true);
		}
		handleCellClick(e, cell) {
			this.initializeFocus(cell);
		}
		handleEditingCell(cell) {
			if (this.activeRange) this.activeRange.setBounds(cell);
		}
		finishEditingCell() {
			this.blockKeydown = true;
			this.table.rowManager.element.focus();
			setTimeout(() => {
				this.blockKeydown = false;
			}, 10);
		}
		keyNavigate(dir, e) {
			if (this.navigate(false, false, dir));
			e.preventDefault();
		}
		keyNavigateRange(e, dir, jump, expand) {
			if (this.navigate(jump, expand, dir));
			e.preventDefault();
		}
		navigate(jump, expand, dir) {
			var moved = false, range, rangeEdge, prevRect, nextRow, nextCol, row, column, rowRect, rowManagerRect, columnRect, columnManagerRect;
			if (this.table.modules.edit && this.table.modules.edit.currentCell) return false;
			if (this.ranges.length > 1) this.ranges = this.ranges.filter((range) => {
				if (range === this.activeRange) {
					range.setEnd(range.start.row, range.start.col);
					return true;
				}
				range.destroy();
				return false;
			});
			range = this.activeRange;
			prevRect = {
				top: range.top,
				bottom: range.bottom,
				left: range.left,
				right: range.right
			};
			rangeEdge = expand ? range.end : range.start;
			nextRow = rangeEdge.row;
			nextCol = rangeEdge.col;
			if (jump) switch (dir) {
				case "left":
					nextCol = this.findJumpCellLeft(range.start.row, rangeEdge.col);
					break;
				case "right":
					nextCol = this.findJumpCellRight(range.start.row, rangeEdge.col);
					break;
				case "up":
					nextRow = this.findJumpCellUp(rangeEdge.row, range.start.col);
					break;
				case "down":
					nextRow = this.findJumpCellDown(rangeEdge.row, range.start.col);
					break;
			}
			else {
				if (expand) {
					if (this.selecting === "row" && (dir === "left" || dir === "right") || this.selecting === "column" && (dir === "up" || dir === "down")) return;
				}
				switch (dir) {
					case "left":
						nextCol = Math.max(nextCol - 1, 0);
						break;
					case "right":
						nextCol = Math.min(nextCol + 1, this.getTableColumns().length - 1);
						break;
					case "up":
						nextRow = Math.max(nextRow - 1, 0);
						break;
					case "down":
						nextRow = Math.min(nextRow + 1, this.getTableRows().length - 1);
						break;
				}
			}
			if (this.rowHeader && nextCol === 0) nextCol = 1;
			if (!expand) range.setStart(nextRow, nextCol);
			range.setEnd(nextRow, nextCol);
			if (!expand) this.selecting = "cell";
			moved = prevRect.top !== range.top || prevRect.bottom !== range.bottom || prevRect.left !== range.left || prevRect.right !== range.right;
			if (moved) {
				row = this.getRowByRangePos(range.end.row);
				column = this.getColumnByRangePos(range.end.col);
				rowRect = row.getElement().getBoundingClientRect();
				columnRect = column.getElement().getBoundingClientRect();
				rowManagerRect = this.table.rowManager.getElement().getBoundingClientRect();
				columnManagerRect = this.table.columnManager.getElement().getBoundingClientRect();
				if (!(rowRect.top >= rowManagerRect.top && rowRect.bottom <= rowManagerRect.bottom)) if (row.getElement().parentNode && column.getElement().parentNode) this.autoScroll(range, row.getElement(), column.getElement());
				else row.getComponent().scrollTo(void 0, false);
				if (!(columnRect.left >= columnManagerRect.left + this.getRowHeaderWidth() && columnRect.right <= columnManagerRect.right)) if (row.getElement().parentNode && column.getElement().parentNode) this.autoScroll(range, row.getElement(), column.getElement());
				else column.getComponent().scrollTo(void 0, false);
				this.layoutElement();
				return true;
			}
		}
		rangeRemoved(removed) {
			this.ranges = this.ranges.filter((range) => range !== removed);
			if (this.activeRange === removed) if (this.ranges.length) this.activeRange = this.ranges[this.ranges.length - 1];
			else this.addRange();
			this.layoutElement();
		}
		findJumpRow(column, rows, reverse, emptyStart, emptySide) {
			if (reverse) rows = rows.reverse();
			return this.findJumpItem(emptyStart, emptySide, rows, function(row) {
				return row.getData()[column.getField()];
			});
		}
		findJumpCol(row, columns, reverse, emptyStart, emptySide) {
			if (reverse) columns = columns.reverse();
			return this.findJumpItem(emptyStart, emptySide, columns, function(column) {
				return row.getData()[column.getField()];
			});
		}
		findJumpItem(emptyStart, emptySide, items, valueResolver) {
			var nextItem;
			for (let currentItem of items) {
				let currentValue = valueResolver(currentItem);
				if (emptyStart) {
					nextItem = currentItem;
					if (currentValue) break;
				} else if (emptySide) {
					nextItem = currentItem;
					if (currentValue) break;
				} else if (currentValue) nextItem = currentItem;
				else break;
			}
			return nextItem;
		}
		findJumpCellLeft(rowPos, colPos) {
			var row = this.getRowByRangePos(rowPos), columns = this.getTableColumns(), isStartingCellEmpty = this.isEmpty(row.getData()[columns[colPos].getField()]), isLeftOfStartingCellEmpty = columns[colPos - 1] ? this.isEmpty(row.getData()[columns[colPos - 1].getField()]) : false, targetCols = this.rowHeader ? columns.slice(1, colPos) : columns.slice(0, colPos), jumpCol = this.findJumpCol(row, targetCols, true, isStartingCellEmpty, isLeftOfStartingCellEmpty);
			if (jumpCol) return jumpCol.getPosition() - 1;
			return colPos;
		}
		findJumpCellRight(rowPos, colPos) {
			var row = this.getRowByRangePos(rowPos), columns = this.getTableColumns(), isStartingCellEmpty = this.isEmpty(row.getData()[columns[colPos].getField()]), isRightOfStartingCellEmpty = columns[colPos + 1] ? this.isEmpty(row.getData()[columns[colPos + 1].getField()]) : false, jumpCol = this.findJumpCol(row, columns.slice(colPos + 1, columns.length), false, isStartingCellEmpty, isRightOfStartingCellEmpty);
			if (jumpCol) return jumpCol.getPosition() - 1;
			return colPos;
		}
		findJumpCellUp(rowPos, colPos) {
			var column = this.getColumnByRangePos(colPos), rows = this.getTableRows(), isStartingCellEmpty = this.isEmpty(rows[rowPos].getData()[column.getField()]), isTopOfStartingCellEmpty = rows[rowPos - 1] ? this.isEmpty(rows[rowPos - 1].getData()[column.getField()]) : false, jumpRow = this.findJumpRow(column, rows.slice(0, rowPos), true, isStartingCellEmpty, isTopOfStartingCellEmpty);
			if (jumpRow) return jumpRow.position - 1;
			return rowPos;
		}
		findJumpCellDown(rowPos, colPos) {
			var column = this.getColumnByRangePos(colPos), rows = this.getTableRows(), isStartingCellEmpty = this.isEmpty(rows[rowPos].getData()[column.getField()]), isBottomOfStartingCellEmpty = rows[rowPos + 1] ? this.isEmpty(rows[rowPos + 1].getData()[column.getField()]) : false, jumpRow = this.findJumpRow(column, rows.slice(rowPos + 1, rows.length), false, isStartingCellEmpty, isBottomOfStartingCellEmpty);
			if (jumpRow) return jumpRow.position - 1;
			return rowPos;
		}
		newSelection(event, element) {
			var range;
			if (element.type === "column") {
				if (!this.columnSelection) return;
				if (element === this.rowHeader) {
					range = this.resetRanges();
					this.selecting = "all";
					var topLeftCell, bottomRightCell = this.getCell(-1, -1);
					if (this.rowHeader) topLeftCell = this.getCell(0, 1);
					else topLeftCell = this.getCell(0, 0);
					range.setBounds(topLeftCell, bottomRightCell);
					return;
				} else this.selecting = "column";
			} else if (element.column === this.rowHeader) this.selecting = "row";
			else this.selecting = "cell";
			if (event.shiftKey) this.activeRange.setBounds(false, element);
			else if (event.ctrlKey) this.addRange().setBounds(element);
			else this.resetRanges().setBounds(element);
		}
		autoScroll(range, row, column) {
			var tableHolder = this.table.rowManager.element, rect, view, withinHorizontalView, withinVerticalView;
			if (typeof row === "undefined") row = this.getRowByRangePos(range.end.row).getElement();
			if (typeof column === "undefined") column = this.getColumnByRangePos(range.end.col).getElement();
			rect = {
				left: column.offsetLeft,
				right: column.offsetLeft + column.offsetWidth,
				top: row.offsetTop,
				bottom: row.offsetTop + row.offsetHeight
			};
			view = {
				left: tableHolder.scrollLeft + this.getRowHeaderWidth(),
				right: Math.ceil(tableHolder.scrollLeft + tableHolder.clientWidth),
				top: tableHolder.scrollTop,
				bottom: tableHolder.scrollTop + tableHolder.offsetHeight - this.table.rowManager.scrollbarWidth
			};
			withinHorizontalView = view.left < rect.left && rect.left < view.right && view.left < rect.right && rect.right < view.right;
			withinVerticalView = view.top < rect.top && rect.top < view.bottom && view.top < rect.bottom && rect.bottom < view.bottom;
			if (!withinHorizontalView) {
				if (rect.left < view.left) tableHolder.scrollLeft = rect.left - this.getRowHeaderWidth();
				else if (rect.right > view.right) tableHolder.scrollLeft = Math.min(rect.right - tableHolder.clientWidth, rect.left - this.getRowHeaderWidth());
			}
			if (!withinVerticalView) {
				if (rect.top < view.top) tableHolder.scrollTop = rect.top;
				else if (rect.bottom > view.bottom) tableHolder.scrollTop = rect.bottom - tableHolder.clientHeight;
			}
		}
		layoutChange() {
			this.overlay.style.visibility = "hidden";
			clearTimeout(this.layoutChangeTimeout);
			this.layoutChangeTimeout = setTimeout(this.layoutRanges.bind(this), 200);
		}
		redraw(force) {
			if (force) {
				this.selecting = "cell";
				this.resetRanges();
				this.layoutElement();
			}
		}
		layoutElement(visibleRows) {
			var rows;
			if (visibleRows) rows = this.table.rowManager.getVisibleRows(true);
			else rows = this.table.rowManager.getRows();
			rows.forEach((row) => {
				if (row.type === "row") {
					this.layoutRow(row);
					row.cells.forEach((cell) => this.renderCell(cell));
				}
			});
			this.getTableColumns().forEach((column) => {
				this.layoutColumn(column);
			});
			this.layoutRanges();
		}
		layoutRow(row) {
			var el = row.getElement(), selected = false, occupied = this.ranges.some((range) => range.occupiesRow(row));
			if (this.selecting === "row") selected = occupied;
			else if (this.selecting === "all") selected = true;
			el.classList.toggle("tabulator-range-selected", selected);
			el.classList.toggle("tabulator-range-highlight", occupied);
		}
		layoutColumn(column) {
			var el = column.getElement(), selected = false, occupied = this.ranges.some((range) => range.occupiesColumn(column));
			if (this.selecting === "column") selected = occupied;
			else if (this.selecting === "all") selected = true;
			el.classList.toggle("tabulator-range-selected", selected);
			el.classList.toggle("tabulator-range-highlight", occupied);
		}
		layoutRanges() {
			var activeCell, activeCellEl, activeRowEl;
			if (!this.table.initialized) return;
			activeCell = this.getActiveCell();
			if (!activeCell) return;
			activeCellEl = activeCell.getElement();
			activeRowEl = activeCell.row.getElement();
			if (this.table.rtl) this.activeRangeCellElement.style.right = activeRowEl.offsetWidth - activeCellEl.offsetLeft - activeCellEl.offsetWidth + "px";
			else this.activeRangeCellElement.style.left = activeRowEl.offsetLeft + activeCellEl.offsetLeft + "px";
			this.activeRangeCellElement.style.top = activeRowEl.offsetTop + "px";
			this.activeRangeCellElement.style.width = activeCellEl.offsetWidth + "px";
			this.activeRangeCellElement.style.height = activeRowEl.offsetHeight + "px";
			this.ranges.forEach((range) => range.layout());
			this.overlay.style.visibility = "visible";
		}
		getCell(rowIdx, colIdx) {
			var row;
			if (colIdx < 0) {
				colIdx = this.getTableColumns().length + colIdx;
				if (colIdx < 0) return null;
			}
			if (rowIdx < 0) rowIdx = this.getTableRows().length + rowIdx;
			row = this.table.rowManager.getRowFromPosition(rowIdx + 1);
			return row ? row.getCells(false, true).filter((cell) => cell.column.visible)[colIdx] : null;
		}
		getActiveCell() {
			return this.getCell(this.activeRange.start.row, this.activeRange.start.col);
		}
		getRowByRangePos(pos) {
			return this.getTableRows()[pos];
		}
		getColumnByRangePos(pos) {
			return this.getTableColumns()[pos];
		}
		getTableRows() {
			return this.table.rowManager.getDisplayRows().filter((row) => row.type === "row");
		}
		getTableColumns() {
			return this.table.columnManager.getVisibleColumnsByIndex();
		}
		addRange(start, end) {
			var range;
			if (this.maxRanges !== true && this.ranges.length >= this.maxRanges) this.ranges.shift().destroy();
			range = new Range(this.table, this, start, end);
			this.activeRange = range;
			this.ranges.push(range);
			this.rangeContainer.appendChild(range.element);
			return range;
		}
		resetRanges() {
			var range, cell, visibleCells;
			this.ranges.forEach((range) => range.destroy());
			this.ranges = [];
			range = this.addRange();
			if (this.table.rowManager.activeRows.length) {
				visibleCells = this.table.rowManager.activeRows[0].cells.filter((cell) => cell.column.visible);
				cell = visibleCells[this.rowHeader ? 1 : 0];
				if (cell) {
					range.setBounds(cell);
					if (this.options("selectableRangeAutoFocus")) this.initializeFocus(cell);
				}
			}
			return range;
		}
		tableDestroyed() {
			document.removeEventListener("mouseup", this.mouseUpEvent);
			this.table.rowManager.element.removeEventListener("keydown", this.keyDownEvent);
		}
		selectedRows(component) {
			return component ? this.activeRange.getRows().map((row) => row.getComponent()) : this.activeRange.getRows();
		}
		selectedColumns(component) {
			return component ? this.activeRange.getColumns().map((col) => col.getComponent()) : this.activeRange.getColumns();
		}
		getRowHeaderWidth() {
			if (!this.rowHeader) return 0;
			return this.rowHeader.getElement().offsetWidth;
		}
		isEmpty(value) {
			return value === null || value === void 0 || value === "";
		}
	};
	function number(a, b, aRow, bRow, column, dir, params) {
		var alignEmptyValues = params.alignEmptyValues;
		var decimal = params.decimalSeparator;
		var thousand = params.thousandSeparator;
		var emptyAlign = 0;
		a = String(a);
		b = String(b);
		if (thousand) {
			a = a.split(thousand).join("");
			b = b.split(thousand).join("");
		}
		if (decimal) {
			a = a.split(decimal).join(".");
			b = b.split(decimal).join(".");
		}
		a = parseFloat(a);
		b = parseFloat(b);
		if (isNaN(a)) emptyAlign = isNaN(b) ? 0 : -1;
		else if (isNaN(b)) emptyAlign = 1;
		else return a - b;
		if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
		return emptyAlign;
	}
	function string(a, b, aRow, bRow, column, dir, params) {
		var alignEmptyValues = params.alignEmptyValues;
		var emptyAlign = 0;
		var locale;
		if (!a) emptyAlign = !b ? 0 : -1;
		else if (!b) emptyAlign = 1;
		else {
			switch (typeof params.locale) {
				case "boolean":
					if (params.locale) locale = this.langLocale();
					break;
				case "string":
					locale = params.locale;
					break;
			}
			return String(a).toLowerCase().localeCompare(String(b).toLowerCase(), locale);
		}
		if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
		return emptyAlign;
	}
	function datetime(a, b, aRow, bRow, column, dir, params) {
		var DT = this.table.dependencyRegistry.lookup(["luxon", "DateTime"], "DateTime");
		var format = params.format || "dd/MM/yyyy HH:mm:ss", alignEmptyValues = params.alignEmptyValues, emptyAlign = 0;
		if (typeof DT != "undefined") {
			if (!DT.isDateTime(a)) if (format === "iso") a = DT.fromISO(String(a));
			else a = DT.fromFormat(String(a), format);
			if (!DT.isDateTime(b)) if (format === "iso") b = DT.fromISO(String(b));
			else b = DT.fromFormat(String(b), format);
			if (!a.isValid) emptyAlign = !b.isValid ? 0 : -1;
			else if (!b.isValid) emptyAlign = 1;
			else return a - b;
			if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
			return emptyAlign;
		} else console.error("Sort Error - 'datetime' sorter is dependant on luxon.js");
	}
	function date(a, b, aRow, bRow, column, dir, params) {
		if (!params.format) params.format = "dd/MM/yyyy";
		return datetime.call(this, a, b, aRow, bRow, column, dir, params);
	}
	function time$2(a, b, aRow, bRow, column, dir, params) {
		if (!params.format) params.format = "HH:mm";
		return datetime.call(this, a, b, aRow, bRow, column, dir, params);
	}
	function boolean(a, b, aRow, bRow, column, dir, params) {
		return (a === true || a === "true" || a === "True" || a === 1 ? 1 : 0) - (b === true || b === "true" || b === "True" || b === 1 ? 1 : 0);
	}
	function array(a, b, aRow, bRow, column, dir, params) {
		var type = params.type || "length", alignEmptyValues = params.alignEmptyValues, emptyAlign = 0, table = this.table, valueMap;
		if (params.valueMap) if (typeof params.valueMap === "string") valueMap = function(value) {
			return value.map((item) => {
				return Helpers.retrieveNestedData(table.options.nestedFieldSeparator, params.valueMap, item);
			});
		};
		else valueMap = params.valueMap;
		function calc(value) {
			var result;
			if (valueMap) value = valueMap(value);
			switch (type) {
				case "length":
					result = value.length;
					break;
				case "sum":
					result = value.reduce(function(c, d) {
						return c + d;
					});
					break;
				case "max":
					result = Math.max.apply(null, value);
					break;
				case "min":
					result = Math.min.apply(null, value);
					break;
				case "avg":
					result = value.reduce(function(c, d) {
						return c + d;
					}) / value.length;
					break;
				case "string":
					result = value.join("");
					break;
			}
			return result;
		}
		if (!Array.isArray(a)) emptyAlign = !Array.isArray(b) ? 0 : -1;
		else if (!Array.isArray(b)) emptyAlign = 1;
		else if (type === "string") return String(calc(a)).toLowerCase().localeCompare(String(calc(b)).toLowerCase());
		else return calc(b) - calc(a);
		if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
		return emptyAlign;
	}
	function exists(a, b, aRow, bRow, column, dir, params) {
		return (typeof a == "undefined" ? 0 : 1) - (typeof b == "undefined" ? 0 : 1);
	}
	function alphanum(as, bs, aRow, bRow, column, dir, params) {
		var a, b, a1, b1, i = 0, L, rx = /(\d+)|(\D+)/g, rd = /\d/;
		var alignEmptyValues = params.alignEmptyValues;
		var emptyAlign = 0;
		if (!as && as !== 0) emptyAlign = !bs && bs !== 0 ? 0 : -1;
		else if (!bs && bs !== 0) emptyAlign = 1;
		else {
			if (isFinite(as) && isFinite(bs)) return as - bs;
			a = String(as).toLowerCase();
			b = String(bs).toLowerCase();
			if (a === b) return 0;
			if (!(rd.test(a) && rd.test(b))) return a > b ? 1 : -1;
			a = a.match(rx);
			b = b.match(rx);
			L = a.length > b.length ? b.length : a.length;
			while (i < L) {
				a1 = a[i];
				b1 = b[i++];
				if (a1 !== b1) if (isFinite(a1) && isFinite(b1)) {
					if (a1.charAt(0) === "0") a1 = "." + a1;
					if (b1.charAt(0) === "0") b1 = "." + b1;
					return a1 - b1;
				} else return a1 > b1 ? 1 : -1;
			}
			return a.length > b.length;
		}
		if (alignEmptyValues === "top" && dir === "desc" || alignEmptyValues === "bottom" && dir === "asc") emptyAlign *= -1;
		return emptyAlign;
	}
	var defaultSorters = {
		number,
		string,
		date,
		time: time$2,
		datetime,
		boolean,
		array,
		exists,
		alphanum
	};
	var Sort = class Sort extends Module {
		static moduleName = "sort";
		static sorters = defaultSorters;
		constructor(table) {
			super(table);
			this.sortList = [];
			this.changed = false;
			this.registerTableOption("sortMode", "local");
			this.registerTableOption("initialSort", false);
			this.registerTableOption("columnHeaderSortMulti", true);
			this.registerTableOption("sortOrderReverse", false);
			this.registerTableOption("headerSortElement", "<div class='tabulator-arrow'></div>");
			this.registerTableOption("headerSortClickElement", "header");
			this.registerColumnOption("sorter");
			this.registerColumnOption("sorterParams");
			this.registerColumnOption("headerSort", true);
			this.registerColumnOption("headerSortStartingDir");
			this.registerColumnOption("headerSortTristate");
		}
		initialize() {
			this.subscribe("column-layout", this.initializeColumn.bind(this));
			this.subscribe("table-built", this.tableBuilt.bind(this));
			this.registerDataHandler(this.sort.bind(this), 20);
			this.registerTableFunction("setSort", this.userSetSort.bind(this));
			this.registerTableFunction("getSorters", this.getSort.bind(this));
			this.registerTableFunction("clearSort", this.clearSort.bind(this));
			if (this.table.options.sortMode === "remote") this.subscribe("data-params", this.remoteSortParams.bind(this));
		}
		tableBuilt() {
			if (this.table.options.initialSort) this.setSort(this.table.options.initialSort);
		}
		remoteSortParams(data, config, silent, params) {
			var sorters = this.getSort();
			sorters.forEach((item) => {
				delete item.column;
			});
			params.sort = sorters;
			return params;
		}
		userSetSort(sortList, dir) {
			this.setSort(sortList, dir);
			this.refreshSort();
		}
		clearSort() {
			this.clear();
			this.refreshSort();
		}
		initializeColumn(column) {
			var sorter = false, colEl, arrowEl;
			switch (typeof column.definition.sorter) {
				case "string":
					if (Sort.sorters[column.definition.sorter]) sorter = Sort.sorters[column.definition.sorter];
					else console.warn("Sort Error - No such sorter found: ", column.definition.sorter);
					break;
				case "function":
					sorter = column.definition.sorter;
					break;
			}
			column.modules.sort = {
				sorter,
				dir: "none",
				params: column.definition.sorterParams || {},
				startingDir: column.definition.headerSortStartingDir || "asc",
				tristate: column.definition.headerSortTristate
			};
			if (column.definition.headerSort !== false) {
				colEl = column.getElement();
				colEl.classList.add("tabulator-sortable");
				arrowEl = document.createElement("div");
				arrowEl.classList.add("tabulator-col-sorter");
				switch (this.table.options.headerSortClickElement) {
					case "icon":
						arrowEl.classList.add("tabulator-col-sorter-element");
						break;
					case "header":
						colEl.classList.add("tabulator-col-sorter-element");
						break;
					default:
						colEl.classList.add("tabulator-col-sorter-element");
						break;
				}
				switch (this.table.options.headerSortElement) {
					case "function": break;
					case "object":
						arrowEl.appendChild(this.table.options.headerSortElement);
						break;
					default: arrowEl.innerHTML = this.table.options.headerSortElement;
				}
				column.titleHolderElement.appendChild(arrowEl);
				column.modules.sort.element = arrowEl;
				this.setColumnHeaderSortIcon(column, "none");
				if (this.table.options.headerSortClickElement === "icon") arrowEl.addEventListener("mousedown", (e) => {
					e.stopPropagation();
				});
				(this.table.options.headerSortClickElement === "icon" ? arrowEl : colEl).addEventListener("click", (e) => {
					var dir = "", sorters = [], match = false;
					if (column.modules.sort) {
						if (column.modules.sort.tristate) if (column.modules.sort.dir == "none") dir = column.modules.sort.startingDir;
						else if (column.modules.sort.dir == column.modules.sort.startingDir) dir = column.modules.sort.dir == "asc" ? "desc" : "asc";
						else dir = "none";
						else switch (column.modules.sort.dir) {
							case "asc":
								dir = "desc";
								break;
							case "desc":
								dir = "asc";
								break;
							default: dir = column.modules.sort.startingDir;
						}
						if (this.table.options.columnHeaderSortMulti && (e.shiftKey || e.ctrlKey)) {
							sorters = this.getSort();
							match = sorters.findIndex((sorter) => {
								return sorter.field === column.getField();
							});
							if (match > -1) {
								sorters[match].dir = dir;
								match = sorters.splice(match, 1)[0];
								if (dir != "none") sorters.push(match);
							} else if (dir != "none") sorters.push({
								column,
								dir
							});
							this.setSort(sorters);
						} else if (dir == "none") this.clear();
						else this.setSort(column, dir);
						this.refreshSort();
					}
				});
			}
		}
		refreshSort() {
			if (this.table.options.sortMode === "remote") this.reloadData(null, false, false);
			else this.refreshData(true);
		}
		hasChanged() {
			var changed = this.changed;
			this.changed = false;
			return changed;
		}
		getSort() {
			var self = this, sorters = [];
			self.sortList.forEach(function(item) {
				if (item.column) sorters.push({
					column: item.column.getComponent(),
					field: item.column.getField(),
					dir: item.dir
				});
			});
			return sorters;
		}
		setSort(sortList, dir) {
			var self = this, newSortList = [];
			if (!Array.isArray(sortList)) sortList = [{
				column: sortList,
				dir
			}];
			sortList.forEach(function(item) {
				var column = self.table.columnManager.findColumn(item.column);
				if (column) {
					item.column = column;
					newSortList.push(item);
					self.changed = true;
				} else console.warn("Sort Warning - Sort field does not exist and is being ignored: ", item.column);
			});
			self.sortList = newSortList;
			this.dispatch("sort-changed");
		}
		clear() {
			this.setSort([]);
		}
		findSorter(column) {
			var row = this.table.rowManager.activeRows[0], sorter = "string", field, value;
			if (row) {
				row = row.getData();
				field = column.getField();
				if (field) {
					value = column.getFieldValue(row);
					switch (typeof value) {
						case "undefined":
							sorter = "string";
							break;
						case "boolean":
							sorter = "boolean";
							break;
						default:
							if (!isNaN(value) && value !== "") sorter = "number";
							else if (value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)) sorter = "alphanum";
							break;
					}
				}
			}
			return Sort.sorters[sorter];
		}
		sort(data, sortOnly) {
			var self = this, sortList = this.table.options.sortOrderReverse ? self.sortList.slice().reverse() : self.sortList, sortListActual = [], rowComponents = [];
			if (this.subscribedExternal("dataSorting")) this.dispatchExternal("dataSorting", self.getSort());
			if (!sortOnly) self.clearColumnHeaders();
			if (this.table.options.sortMode !== "remote") {
				sortList.forEach(function(item, i) {
					var sortObj;
					if (item.column) {
						sortObj = item.column.modules.sort;
						if (sortObj) {
							if (!sortObj.sorter) sortObj.sorter = self.findSorter(item.column);
							item.params = typeof sortObj.params === "function" ? sortObj.params(item.column.getComponent(), item.dir) : sortObj.params;
							sortListActual.push(item);
						}
						if (!sortOnly) self.setColumnHeader(item.column, item.dir);
					}
				});
				if (sortListActual.length) self._sortItems(data, sortListActual);
			} else if (!sortOnly) sortList.forEach(function(item, i) {
				self.setColumnHeader(item.column, item.dir);
			});
			if (this.subscribedExternal("dataSorted")) {
				data.forEach((row) => {
					rowComponents.push(row.getComponent());
				});
				this.dispatchExternal("dataSorted", self.getSort(), rowComponents);
			}
			return data;
		}
		clearColumnHeaders() {
			this.table.columnManager.getRealColumns().forEach((column) => {
				if (column.modules.sort) {
					column.modules.sort.dir = "none";
					column.getElement().setAttribute("aria-sort", "none");
					this.setColumnHeaderSortIcon(column, "none");
				}
			});
		}
		setColumnHeader(column, dir) {
			column.modules.sort.dir = dir;
			column.getElement().setAttribute("aria-sort", dir === "asc" ? "ascending" : "descending");
			this.setColumnHeaderSortIcon(column, dir);
		}
		setColumnHeaderSortIcon(column, dir) {
			var sortEl = column.modules.sort.element, arrowEl;
			if (column.definition.headerSort && typeof this.table.options.headerSortElement === "function") {
				while (sortEl.firstChild) sortEl.removeChild(sortEl.firstChild);
				arrowEl = this.table.options.headerSortElement.call(this.table, column.getComponent(), dir);
				if (typeof arrowEl === "object") sortEl.appendChild(arrowEl);
				else sortEl.innerHTML = arrowEl;
			}
		}
		_sortItems(data, sortList) {
			var sorterCount = sortList.length - 1;
			data.sort((a, b) => {
				var result;
				for (var i = sorterCount; i >= 0; i--) {
					let sortItem = sortList[i];
					result = this._sortRow(a, b, sortItem.column, sortItem.dir, sortItem.params);
					if (result !== 0) break;
				}
				return result;
			});
		}
		_sortRow(a, b, column, dir, params) {
			var el1Comp, el2Comp;
			var el1 = dir == "asc" ? a : b;
			var el2 = dir == "asc" ? b : a;
			a = column.getFieldValue(el1.getData());
			b = column.getFieldValue(el2.getData());
			a = typeof a !== "undefined" ? a : "";
			b = typeof b !== "undefined" ? b : "";
			el1Comp = el1.getComponent();
			el2Comp = el2.getComponent();
			return column.modules.sort.sorter.call(this, a, b, el1Comp, el2Comp, column.getComponent(), dir, params);
		}
	};
	var GridCalculator = class {
		constructor(columns, rows) {
			this.columnCount = columns;
			this.rowCount = rows;
			this.columnString = [];
			this.columns = [];
			this.rows = [];
		}
		genColumns(data) {
			var colCount = Math.max(this.columnCount, Math.max(...data.map((item) => item.length)));
			this.columnString = [];
			this.columns = [];
			for (let i = 1; i <= colCount; i++) {
				this.incrementChar(this.columnString.length - 1);
				this.columns.push(this.columnString.join(""));
			}
			return this.columns;
		}
		genRows(data) {
			var rowCount = Math.max(this.rowCount, data.length);
			this.rows = [];
			for (let i = 1; i <= rowCount; i++) this.rows.push(i);
			return this.rows;
		}
		incrementChar(i) {
			let char = this.columnString[i];
			if (char) if (char !== "Z") this.columnString[i] = String.fromCharCode(this.columnString[i].charCodeAt(0) + 1);
			else {
				this.columnString[i] = "A";
				if (i) this.incrementChar(i - 1);
				else this.columnString.push("A");
			}
			else this.columnString.push("A");
		}
		setRowCount(count) {
			this.rowCount = count;
		}
		setColumnCount(count) {
			this.columnCount = count;
		}
	};
	var SheetComponent = class {
		constructor(sheet) {
			this._sheet = sheet;
			return new Proxy(this, { get: function(target, name, receiver) {
				if (typeof target[name] !== "undefined") return target[name];
				else return target._sheet.table.componentFunctionBinder.handle("sheet", target._sheet, name);
			} });
		}
		getTitle() {
			return this._sheet.title;
		}
		getKey() {
			return this._sheet.key;
		}
		getDefinition() {
			return this._sheet.getDefinition();
		}
		getData() {
			return this._sheet.getData();
		}
		setData(data) {
			return this._sheet.setData(data);
		}
		clear() {
			return this._sheet.clear();
		}
		remove() {
			return this._sheet.remove();
		}
		active() {
			return this._sheet.active();
		}
		setTitle(title) {
			return this._sheet.setTitle(title);
		}
		setRows(rows) {
			return this._sheet.setRows(rows);
		}
		setColumns(columns) {
			return this._sheet.setColumns(columns);
		}
	};
	var Sheet = class extends CoreFeature {
		constructor(spreadsheetManager, definition) {
			super(spreadsheetManager.table);
			this.spreadsheetManager = spreadsheetManager;
			this.definition = definition;
			this.title = this.definition.title || "";
			this.key = this.definition.key || this.definition.title;
			this.rowCount = this.definition.rows;
			this.columnCount = this.definition.columns;
			this.data = this.definition.data || [];
			this.element = null;
			this.isActive = false;
			this.grid = new GridCalculator(this.columnCount, this.rowCount);
			this.defaultColumnDefinition = {
				width: 100,
				headerHozAlign: "center",
				headerSort: false
			};
			this.columnDefinition = Object.assign(this.defaultColumnDefinition, this.options("spreadsheetColumnDefinition"));
			this.columnDefs = [];
			this.rowDefs = [];
			this.columnFields = [];
			this.columns = [];
			this.rows = [];
			this.scrollTop = null;
			this.scrollLeft = null;
			this.initialize();
			this.dispatchExternal("sheetAdded", this.getComponent());
		}
		initialize() {
			this.initializeElement();
			this.initializeColumns();
			this.initializeRows();
		}
		reinitialize() {
			this.initializeColumns();
			this.initializeRows();
		}
		initializeElement() {
			this.element = document.createElement("div");
			this.element.classList.add("tabulator-spreadsheet-tab");
			this.element.innerText = this.title;
			this.element.addEventListener("click", () => {
				this.spreadsheetManager.loadSheet(this);
			});
		}
		initializeColumns() {
			this.grid.setColumnCount(this.columnCount);
			this.columnFields = this.grid.genColumns(this.data);
			this.columnDefs = [];
			this.columnFields.forEach((ref) => {
				var def = Object.assign({}, this.columnDefinition);
				def.field = ref;
				def.title = ref;
				this.columnDefs.push(def);
			});
		}
		initializeRows() {
			var refs;
			this.grid.setRowCount(this.rowCount);
			refs = this.grid.genRows(this.data);
			this.rowDefs = [];
			refs.forEach((ref, i) => {
				var def = { "_id": ref };
				var data = this.data[i];
				if (data) data.forEach((val, j) => {
					var field = this.columnFields[j];
					if (field) def[field] = val;
				});
				this.rowDefs.push(def);
			});
		}
		unload() {
			this.isActive = false;
			this.scrollTop = this.table.rowManager.scrollTop;
			this.scrollLeft = this.table.rowManager.scrollLeft;
			this.data = this.getData(true);
			this.element.classList.remove("tabulator-spreadsheet-tab-active");
		}
		load() {
			var wasInactive = !this.isActive;
			this.isActive = true;
			this.table.blockRedraw();
			this.table.setData([]);
			this.table.setColumns(this.columnDefs);
			this.table.setData(this.rowDefs);
			this.table.restoreRedraw();
			if (wasInactive && this.scrollTop !== null) {
				this.table.rowManager.element.scrollLeft = this.scrollLeft;
				this.table.rowManager.element.scrollTop = this.scrollTop;
			}
			this.element.classList.add("tabulator-spreadsheet-tab-active");
			this.dispatchExternal("sheetLoaded", this.getComponent());
		}
		getComponent() {
			return new SheetComponent(this);
		}
		getDefinition() {
			return {
				title: this.title,
				key: this.key,
				rows: this.rowCount,
				columns: this.columnCount,
				data: this.getData()
			};
		}
		getData(full) {
			var output = [], rowWidths, outputWidth, outputHeight;
			this.rowDefs.forEach((rowData) => {
				var row = [];
				this.columnFields.forEach((field) => {
					row.push(rowData[field]);
				});
				output.push(row);
			});
			if (!full && !this.options("spreadsheetOutputFull")) {
				rowWidths = output.map((row) => row.findLastIndex((val) => typeof val !== "undefined") + 1);
				outputWidth = Math.max(...rowWidths);
				outputHeight = rowWidths.findLastIndex((width) => width > 0) + 1;
				output = output.slice(0, outputHeight);
				output = output.map((row) => row.slice(0, outputWidth));
			}
			return output;
		}
		setData(data) {
			this.data = data;
			this.reinitialize();
			this.dispatchExternal("sheetUpdated", this.getComponent());
			if (this.isActive) this.load();
		}
		clear() {
			this.setData([]);
		}
		setTitle(title) {
			this.title = title;
			this.element.innerText = title;
			this.dispatchExternal("sheetUpdated", this.getComponent());
		}
		setRows(rows) {
			this.rowCount = rows;
			this.initializeRows();
			this.dispatchExternal("sheetUpdated", this.getComponent());
			if (this.isActive) this.load();
		}
		setColumns(columns) {
			this.columnCount = columns;
			this.reinitialize();
			this.dispatchExternal("sheetUpdated", this.getComponent());
			if (this.isActive) this.load();
		}
		remove() {
			this.spreadsheetManager.removeSheet(this);
		}
		destroy() {
			if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
			this.dispatchExternal("sheetRemoved", this.getComponent());
		}
		active() {
			this.spreadsheetManager.loadSheet(this);
		}
	};
	var Spreadsheet = class extends Module {
		static moduleName = "spreadsheet";
		constructor(table) {
			super(table);
			this.sheets = [];
			this.element = null;
			this.registerTableOption("spreadsheet", false);
			this.registerTableOption("spreadsheetRows", 50);
			this.registerTableOption("spreadsheetColumns", 50);
			this.registerTableOption("spreadsheetColumnDefinition", {});
			this.registerTableOption("spreadsheetOutputFull", false);
			this.registerTableOption("spreadsheetData", false);
			this.registerTableOption("spreadsheetSheets", false);
			this.registerTableOption("spreadsheetSheetTabs", false);
			this.registerTableOption("spreadsheetSheetTabsElement", false);
			this.registerTableFunction("setSheets", this.setSheets.bind(this));
			this.registerTableFunction("addSheet", this.addSheet.bind(this));
			this.registerTableFunction("getSheets", this.getSheets.bind(this));
			this.registerTableFunction("getSheetDefinitions", this.getSheetDefinitions.bind(this));
			this.registerTableFunction("setSheetData", this.setSheetData.bind(this));
			this.registerTableFunction("getSheet", this.getSheet.bind(this));
			this.registerTableFunction("getSheetData", this.getSheetData.bind(this));
			this.registerTableFunction("clearSheet", this.clearSheet.bind(this));
			this.registerTableFunction("removeSheet", this.removeSheetFunc.bind(this));
			this.registerTableFunction("activeSheet", this.activeSheetFunc.bind(this));
		}
		initialize() {
			if (this.options("spreadsheet")) {
				this.subscribe("table-initialized", this.tableInitialized.bind(this));
				this.subscribe("data-loaded", this.loadRemoteData.bind(this));
				this.table.options.index = "_id";
				if (this.options("spreadsheetData") && this.options("spreadsheetSheets")) {
					console.warn("You cannot use spreadsheetData and spreadsheetSheets at the same time, ignoring spreadsheetData");
					this.table.options.spreadsheetData = false;
				}
				this.compatibilityCheck();
				if (this.options("spreadsheetSheetTabs")) this.initializeTabset();
			}
		}
		compatibilityCheck() {
			if (this.options("data")) console.warn("Do not use the data option when working with spreadsheets, use either spreadsheetData or spreadsheetSheets to pass data into the table");
			if (this.options("pagination")) console.warn("The spreadsheet module is not compatible with the pagination module");
			if (this.options("groupBy")) console.warn("The spreadsheet module is not compatible with the row grouping module");
			if (this.options("responsiveCollapse")) console.warn("The spreadsheet module is not compatible with the responsive collapse module");
		}
		initializeTabset() {
			this.element = document.createElement("div");
			this.element.classList.add("tabulator-spreadsheet-tabs");
			var altContainer = this.options("spreadsheetSheetTabsElement");
			if (altContainer && !(altContainer instanceof HTMLElement)) {
				altContainer = document.querySelector(altContainer);
				if (!altContainer) console.warn("Unable to find element matching spreadsheetSheetTabsElement selector:", this.options("spreadsheetSheetTabsElement"));
			}
			if (altContainer) altContainer.appendChild(this.element);
			else this.footerAppend(this.element);
		}
		tableInitialized() {
			if (this.sheets.length) this.loadSheet(this.sheets[0]);
			else if (this.options("spreadsheetSheets")) this.loadSheets(this.options("spreadsheetSheets"));
			else if (this.options("spreadsheetData")) this.loadData(this.options("spreadsheetData"));
		}
		loadRemoteData(data, data1, data2) {
			console.log("data", data, data1, data2);
			if (Array.isArray(data)) {
				this.table.dataLoader.clearAlert();
				this.dispatchExternal("dataLoaded", data);
				if (!data.length || Array.isArray(data[0])) this.loadData(data);
				else this.loadSheets(data);
			} else console.error("Spreadsheet Loading Error - Unable to process remote data due to invalid data type \nExpecting: array \nReceived: ", typeof data, "\nData:     ", data);
			return false;
		}
		loadData(data) {
			var def = { data };
			this.loadSheet(this.newSheet(def));
		}
		destroySheets() {
			this.sheets.forEach((sheet) => {
				sheet.destroy();
			});
			this.sheets = [];
			this.activeSheet = null;
		}
		loadSheets(sheets) {
			if (!Array.isArray(sheets)) sheets = [];
			this.destroySheets();
			sheets.forEach((def) => {
				this.newSheet(def);
			});
			this.loadSheet(this.sheets[0]);
		}
		loadSheet(sheet) {
			if (this.activeSheet !== sheet) {
				if (this.activeSheet) this.activeSheet.unload();
				this.activeSheet = sheet;
				sheet.load();
			}
		}
		newSheet(definition = {}) {
			var sheet;
			if (!definition.rows) definition.rows = this.options("spreadsheetRows");
			if (!definition.columns) definition.columns = this.options("spreadsheetColumns");
			sheet = new Sheet(this, definition);
			this.sheets.push(sheet);
			if (this.element) this.element.appendChild(sheet.element);
			return sheet;
		}
		removeSheet(sheet) {
			var index = this.sheets.indexOf(sheet), prevSheet;
			if (this.sheets.length > 1) {
				if (index > -1) {
					this.sheets.splice(index, 1);
					sheet.destroy();
					if (this.activeSheet === sheet) {
						prevSheet = this.sheets[index - 1] || this.sheets[0];
						if (prevSheet) this.loadSheet(prevSheet);
						else this.activeSheet = null;
					}
				}
			} else console.warn("Unable to remove sheet, at least one sheet must be active");
		}
		lookupSheet(key) {
			if (!key) return this.activeSheet;
			else if (key instanceof Sheet) return key;
			else if (key instanceof SheetComponent) return key._sheet;
			else return this.sheets.find((sheet) => sheet.key === key) || false;
		}
		setSheets(sheets) {
			this.loadSheets(sheets);
			return this.getSheets();
		}
		addSheet(sheet) {
			return this.newSheet(sheet).getComponent();
		}
		getSheetDefinitions() {
			return this.sheets.map((sheet) => sheet.getDefinition());
		}
		getSheets() {
			return this.sheets.map((sheet) => sheet.getComponent());
		}
		getSheet(key) {
			var sheet = this.lookupSheet(key);
			return sheet ? sheet.getComponent() : false;
		}
		setSheetData(key, data) {
			if (key && !data) {
				data = key;
				key = false;
			}
			var sheet = this.lookupSheet(key);
			return sheet ? sheet.setData(data) : false;
		}
		getSheetData(key) {
			var sheet = this.lookupSheet(key);
			return sheet ? sheet.getData() : false;
		}
		clearSheet(key) {
			var sheet = this.lookupSheet(key);
			return sheet ? sheet.clear() : false;
		}
		removeSheetFunc(key) {
			var sheet = this.lookupSheet(key);
			if (sheet) this.removeSheet(sheet);
		}
		activeSheetFunc(key) {
			var sheet = this.lookupSheet(key);
			return sheet ? this.loadSheet(sheet) : false;
		}
	};
	var Tooltip = class extends Module {
		static moduleName = "tooltip";
		constructor(table) {
			super(table);
			this.tooltipSubscriber = null, this.headerSubscriber = null, this.timeout = null;
			this.popupInstance = null;
			this.registerTableOption("tooltipDelay", 300);
			this.registerColumnOption("tooltip");
			this.registerColumnOption("headerTooltip");
		}
		initialize() {
			this.deprecatedOptionsCheck();
			this.subscribe("column-init", this.initializeColumn.bind(this));
		}
		deprecatedOptionsCheck() {}
		initializeColumn(column) {
			if (column.definition.headerTooltip && !this.headerSubscriber) {
				this.headerSubscriber = true;
				this.subscribe("column-mousemove", this.mousemoveCheck.bind(this, "headerTooltip"));
				this.subscribe("column-mouseout", this.mouseoutCheck.bind(this, "headerTooltip"));
			}
			if (column.definition.tooltip && !this.tooltipSubscriber) {
				this.tooltipSubscriber = true;
				this.subscribe("cell-mousemove", this.mousemoveCheck.bind(this, "tooltip"));
				this.subscribe("cell-mouseout", this.mouseoutCheck.bind(this, "tooltip"));
			}
		}
		mousemoveCheck(action, e, component) {
			var tooltip = action === "tooltip" ? component.column.definition.tooltip : component.definition.headerTooltip;
			if (tooltip) {
				this.clearPopup();
				this.timeout = setTimeout(this.loadTooltip.bind(this, e, component, tooltip), this.table.options.tooltipDelay);
			}
		}
		mouseoutCheck(action, e, component) {
			if (!this.popupInstance) this.clearPopup();
		}
		clearPopup(action, e, component) {
			clearTimeout(this.timeout);
			this.timeout = null;
			if (this.popupInstance) this.popupInstance.hide();
		}
		loadTooltip(e, component, tooltip) {
			var contentsEl, renderedCallback, coords;
			function onRendered(callback) {
				renderedCallback = callback;
			}
			if (typeof tooltip === "function") tooltip = tooltip(e, component.getComponent(), onRendered);
			if (tooltip instanceof HTMLElement) contentsEl = tooltip;
			else {
				contentsEl = document.createElement("div");
				if (tooltip === true) if (component instanceof Cell) tooltip = component.value;
				else if (component.definition.field) this.langBind("columns|" + component.definition.field, (value) => {
					contentsEl.innerHTML = tooltip = value || component.definition.title;
				});
				else tooltip = component.definition.title;
				contentsEl.innerHTML = tooltip;
			}
			if (tooltip || tooltip === 0 || tooltip === false) {
				contentsEl.classList.add("tabulator-tooltip");
				contentsEl.addEventListener("mousemove", (e) => e.preventDefault());
				this.popupInstance = this.popup(contentsEl);
				if (typeof renderedCallback === "function") this.popupInstance.renderCallback(renderedCallback);
				coords = this.popupInstance.containerEventCoords(e);
				this.popupInstance.show(coords.x + 15, coords.y + 15).hideOnBlur(() => {
					this.dispatchExternal("TooltipClosed", component.getComponent());
					this.popupInstance = null;
				});
				this.dispatchExternal("TooltipOpened", component.getComponent());
			}
		}
	};
	var defaultValidators = {
		integer: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			value = Number(value);
			return !isNaN(value) && isFinite(value) && Math.floor(value) === value;
		},
		float: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			value = Number(value);
			return !isNaN(value) && isFinite(value) && value % 1 !== 0;
		},
		numeric: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return !isNaN(value);
		},
		string: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return isNaN(value);
		},
		alphanumeric: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return new RegExp(/^[a-z0-9]+$/i).test(value);
		},
		max: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return parseFloat(value) <= parameters;
		},
		min: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return parseFloat(value) >= parameters;
		},
		starts: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return String(value).toLowerCase().startsWith(String(parameters).toLowerCase());
		},
		ends: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return String(value).toLowerCase().endsWith(String(parameters).toLowerCase());
		},
		minLength: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return String(value).length >= parameters;
		},
		maxLength: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return String(value).length <= parameters;
		},
		in: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			if (typeof parameters == "string") parameters = parameters.split("|");
			return parameters.indexOf(value) > -1;
		},
		regex: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			return new RegExp(parameters).test(value);
		},
		unique: function(cell, value, parameters) {
			if (value === "" || value === null || typeof value === "undefined") return true;
			var unique = true;
			var cellData = cell.getData();
			var column = cell.getColumn()._getSelf();
			this.table.rowManager.rows.forEach(function(row) {
				var data = row.getData();
				if (data !== cellData) {
					if (value == column.getFieldValue(data)) unique = false;
				}
			});
			return unique;
		},
		required: function(cell, value, parameters) {
			return value !== "" && value !== null && typeof value !== "undefined";
		}
	};
	var allModules = Object.freeze({
		__proto__: null,
		AccessorModule: Accessor,
		AjaxModule: Ajax,
		ClipboardModule: Clipboard,
		ColumnCalcsModule: ColumnCalcs,
		DataTreeModule: DataTree,
		DownloadModule: Download,
		EditModule: Edit,
		ExportModule: Export,
		FilterModule: Filter,
		FormatModule: Format,
		FrozenColumnsModule: FrozenColumns,
		FrozenRowsModule: FrozenRows,
		GroupRowsModule: GroupRows,
		HistoryModule: History,
		HtmlTableImportModule: HtmlTableImport,
		ImportModule: Import,
		InteractionModule: Interaction,
		KeybindingsModule: Keybindings,
		MenuModule: Menu,
		MoveColumnsModule: MoveColumns,
		MoveRowsModule: MoveRows,
		MutatorModule: Mutator,
		PageModule: Page,
		PersistenceModule: Persistence,
		PopupModule: Popup,
		PrintModule: Print,
		ReactiveDataModule: ReactiveData,
		ResizeColumnsModule: ResizeColumns,
		ResizeRowsModule: ResizeRows,
		ResizeTableModule: ResizeTable,
		ResponsiveLayoutModule: ResponsiveLayout,
		SelectRangeModule: SelectRange,
		SelectRowModule: SelectRow,
		SortModule: Sort,
		SpreadsheetModule: Spreadsheet,
		TooltipModule: Tooltip,
		ValidateModule: class Validate extends Module {
			static moduleName = "validate";
			static validators = defaultValidators;
			constructor(table) {
				super(table);
				this.invalidCells = [];
				this.registerTableOption("validationMode", "blocking");
				this.registerColumnOption("validator");
				this.registerTableFunction("getInvalidCells", this.getInvalidCells.bind(this));
				this.registerTableFunction("clearCellValidation", this.userClearCellValidation.bind(this));
				this.registerTableFunction("validate", this.userValidate.bind(this));
				this.registerComponentFunction("cell", "isValid", this.cellIsValid.bind(this));
				this.registerComponentFunction("cell", "clearValidation", this.clearValidation.bind(this));
				this.registerComponentFunction("cell", "validate", this.cellValidate.bind(this));
				this.registerComponentFunction("column", "validate", this.columnValidate.bind(this));
				this.registerComponentFunction("row", "validate", this.rowValidate.bind(this));
			}
			initialize() {
				this.subscribe("cell-delete", this.clearValidation.bind(this));
				this.subscribe("column-layout", this.initializeColumnCheck.bind(this));
				this.subscribe("edit-success", this.editValidate.bind(this));
				this.subscribe("edit-editor-clear", this.editorClear.bind(this));
				this.subscribe("edit-edited-clear", this.editedClear.bind(this));
			}
			editValidate(cell, value, previousValue) {
				var valid = this.table.options.validationMode !== "manual" ? this.validate(cell.column.modules.validate, cell, value) : true;
				if (valid !== true) setTimeout(() => {
					cell.getElement().classList.add("tabulator-validation-fail");
					this.dispatchExternal("validationFailed", cell.getComponent(), value, valid);
				});
				return valid;
			}
			editorClear(cell, cancelled) {
				if (cancelled) {
					if (cell.column.modules.validate) this.cellValidate(cell);
				}
				cell.getElement().classList.remove("tabulator-validation-fail");
			}
			editedClear(cell) {
				if (cell.modules.validate) cell.modules.validate.invalid = false;
			}
			cellIsValid(cell) {
				return cell.modules.validate ? cell.modules.validate.invalid || true : true;
			}
			cellValidate(cell) {
				return this.validate(cell.column.modules.validate, cell, cell.getValue());
			}
			columnValidate(column) {
				var invalid = [];
				column.cells.forEach((cell) => {
					if (this.cellValidate(cell) !== true) invalid.push(cell.getComponent());
				});
				return invalid.length ? invalid : true;
			}
			rowValidate(row) {
				var invalid = [];
				row.cells.forEach((cell) => {
					if (this.cellValidate(cell) !== true) invalid.push(cell.getComponent());
				});
				return invalid.length ? invalid : true;
			}
			userClearCellValidation(cells) {
				if (!cells) cells = this.getInvalidCells();
				if (!Array.isArray(cells)) cells = [cells];
				cells.forEach((cell) => {
					this.clearValidation(cell._getSelf());
				});
			}
			userValidate(cells) {
				var output = [];
				this.table.rowManager.rows.forEach((row) => {
					row = row.getComponent();
					var valid = row.validate();
					if (valid !== true) output = output.concat(valid);
				});
				return output.length ? output : true;
			}
			initializeColumnCheck(column) {
				if (typeof column.definition.validator !== "undefined") this.initializeColumn(column);
			}
			initializeColumn(column) {
				var self = this, config = [], validator;
				if (column.definition.validator) {
					if (Array.isArray(column.definition.validator)) column.definition.validator.forEach((item) => {
						validator = self._extractValidator(item);
						if (validator) config.push(validator);
					});
					else {
						validator = this._extractValidator(column.definition.validator);
						if (validator) config.push(validator);
					}
					column.modules.validate = config.length ? config : false;
				}
			}
			_extractValidator(value) {
				var type, params, pos;
				switch (typeof value) {
					case "string":
						pos = value.indexOf(":");
						if (pos > -1) {
							type = value.substring(0, pos);
							params = value.substring(pos + 1);
						} else type = value;
						return this._buildValidator(type, params);
					case "function": return this._buildValidator(value);
					case "object": return this._buildValidator(value.type, value.parameters);
				}
			}
			_buildValidator(type, params) {
				var func = typeof type == "function" ? type : Validate.validators[type];
				if (!func) {
					console.warn("Validator Setup Error - No matching validator found:", type);
					return false;
				} else return {
					type: typeof type == "function" ? "function" : type,
					func,
					params
				};
			}
			validate(validators, cell, value) {
				var self = this, failedValidators = [], invalidIndex = this.invalidCells.indexOf(cell);
				if (validators) validators.forEach((item) => {
					if (!item.func.call(self, cell.getComponent(), value, item.params)) failedValidators.push({
						type: item.type,
						parameters: item.params
					});
				});
				if (!cell.modules.validate) cell.modules.validate = {};
				if (!failedValidators.length) {
					cell.modules.validate.invalid = false;
					cell.getElement().classList.remove("tabulator-validation-fail");
					if (invalidIndex > -1) this.invalidCells.splice(invalidIndex, 1);
				} else {
					cell.modules.validate.invalid = failedValidators;
					if (this.table.options.validationMode !== "manual") cell.getElement().classList.add("tabulator-validation-fail");
					if (invalidIndex == -1) this.invalidCells.push(cell);
				}
				return failedValidators.length ? failedValidators : true;
			}
			getInvalidCells() {
				var output = [];
				this.invalidCells.forEach((cell) => {
					output.push(cell.getComponent());
				});
				return output;
			}
			clearValidation(cell) {
				var invalidIndex;
				if (cell.modules.validate && cell.modules.validate.invalid) {
					cell.getElement().classList.remove("tabulator-validation-fail");
					cell.modules.validate.invalid = false;
					invalidIndex = this.invalidCells.indexOf(cell);
					if (invalidIndex > -1) this.invalidCells.splice(invalidIndex, 1);
				}
			}
		}
	});
	var defaultOptions = {
		debugEventsExternal: false,
		debugEventsInternal: false,
		debugInvalidOptions: true,
		debugInvalidComponentFuncs: true,
		debugInitialization: true,
		debugDeprecation: true,
		height: false,
		minHeight: false,
		maxHeight: false,
		columnHeaderVertAlign: "top",
		popupContainer: false,
		columns: [],
		columnDefaults: {},
		rowHeader: false,
		data: false,
		autoColumns: false,
		autoColumnsDefinitions: false,
		nestedFieldSeparator: ".",
		footerElement: false,
		index: "id",
		textDirection: "auto",
		addRowPos: "bottom",
		headerVisible: true,
		renderVertical: "virtual",
		renderHorizontal: "basic",
		renderVerticalBuffer: 0,
		scrollToRowPosition: "top",
		scrollToRowIfVisible: true,
		scrollToColumnPosition: "left",
		scrollToColumnIfVisible: true,
		rowFormatter: false,
		rowFormatterPrint: null,
		rowFormatterClipboard: null,
		rowFormatterHtmlOutput: null,
		rowHeight: null,
		placeholder: false,
		dataLoader: true,
		dataLoaderLoading: false,
		dataLoaderError: false,
		dataLoaderErrorTimeout: 3e3,
		dataSendParams: {},
		dataReceiveParams: {},
		dependencies: {}
	};
	var OptionsList = class {
		constructor(table, msgType, defaults = {}) {
			this.table = table;
			this.msgType = msgType;
			this.registeredDefaults = Object.assign({}, defaults);
		}
		register(option, value) {
			this.registeredDefaults[option] = value;
		}
		generate(defaultOptions, userOptions = {}) {
			var output = Object.assign({}, this.registeredDefaults), warn = this.table.options.debugInvalidOptions || userOptions.debugInvalidOptions === true;
			Object.assign(output, defaultOptions);
			for (let key in userOptions) if (!output.hasOwnProperty(key)) {
				if (warn) console.warn("Invalid " + this.msgType + " option:", key);
				output[key] = userOptions.key;
			}
			for (let key in output) if (key in userOptions) output[key] = userOptions[key];
			else if (Array.isArray(output[key])) output[key] = Object.assign([], output[key]);
			else if (typeof output[key] === "object" && output[key] !== null) output[key] = Object.assign({}, output[key]);
			else if (typeof output[key] === "undefined") delete output[key];
			return output;
		}
	};
	var Renderer = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.elementVertical = table.rowManager.element;
			this.elementHorizontal = table.columnManager.element;
			this.tableElement = table.rowManager.tableElement;
			this.verticalFillMode = "fit";
		}
		initialize() {}
		clearRows() {}
		clearColumns() {}
		reinitializeColumnWidths(columns) {}
		renderRows() {}
		renderColumns() {}
		rerenderRows(callback) {
			if (callback) callback();
		}
		rerenderColumns(update, blockRedraw) {}
		renderRowCells(row) {}
		rerenderRowCells(row, force) {}
		scrollColumns(left, dir) {}
		scrollRows(top, dir) {}
		resize() {}
		scrollToRow(row) {}
		scrollToRowNearestTop(row) {}
		visibleRows(includingBuffer) {
			return [];
		}
		rows() {
			return this.table.rowManager.getDisplayRows();
		}
		styleRow(row, index) {
			var rowEl = row.getElement();
			if (index % 2) {
				rowEl.classList.add("tabulator-row-even");
				rowEl.classList.remove("tabulator-row-odd");
			} else {
				rowEl.classList.add("tabulator-row-odd");
				rowEl.classList.remove("tabulator-row-even");
			}
		}
		clear() {
			this.clearRows();
			this.clearColumns();
		}
		render() {
			this.renderRows();
			this.renderColumns();
		}
		rerender(callback) {
			this.rerenderRows();
			this.rerenderColumns();
		}
		scrollToRowPosition(row, position, ifVisible) {
			var rowIndex = this.rows().indexOf(row), rowEl = row.getElement(), offset = 0;
			return new Promise((resolve, reject) => {
				if (rowIndex > -1) {
					if (typeof ifVisible === "undefined") ifVisible = this.table.options.scrollToRowIfVisible;
					if (!ifVisible) {
						if (Helpers.elVisible(rowEl)) {
							offset = Helpers.elOffset(rowEl).top - Helpers.elOffset(this.elementVertical).top;
							if (offset > 0 && offset < this.elementVertical.clientHeight - rowEl.offsetHeight) {
								resolve();
								return false;
							}
						}
					}
					if (typeof position === "undefined") position = this.table.options.scrollToRowPosition;
					if (position === "nearest") position = this.scrollToRowNearestTop(row) ? "top" : "bottom";
					this.scrollToRow(row);
					switch (position) {
						case "middle":
						case "center":
							if (this.elementVertical.scrollHeight - this.elementVertical.scrollTop == this.elementVertical.clientHeight) this.elementVertical.scrollTop = this.elementVertical.scrollTop + (rowEl.offsetTop - this.elementVertical.scrollTop) - (this.elementVertical.scrollHeight - rowEl.offsetTop) / 2;
							else this.elementVertical.scrollTop = this.elementVertical.scrollTop - this.elementVertical.clientHeight / 2;
							break;
						case "bottom":
							if (this.elementVertical.scrollHeight - this.elementVertical.scrollTop == this.elementVertical.clientHeight) this.elementVertical.scrollTop = this.elementVertical.scrollTop - (this.elementVertical.scrollHeight - rowEl.offsetTop) + rowEl.offsetHeight;
							else this.elementVertical.scrollTop = this.elementVertical.scrollTop - this.elementVertical.clientHeight + rowEl.offsetHeight;
							break;
						case "top":
							this.elementVertical.scrollTop = rowEl.offsetTop;
							break;
					}
					resolve();
				} else {
					console.warn("Scroll Error - Row not visible");
					reject("Scroll Error - Row not visible");
				}
			});
		}
	};
	var BasicHorizontal = class extends Renderer {
		constructor(table) {
			super(table);
		}
		renderRowCells(row, inFragment) {
			const rowFrag = document.createDocumentFragment();
			row.cells.forEach((cell) => {
				rowFrag.appendChild(cell.getElement());
			});
			row.element.appendChild(rowFrag);
			if (!inFragment) row.cells.forEach((cell) => {
				cell.cellRendered();
			});
		}
		reinitializeColumnWidths(columns) {
			columns.forEach(function(column) {
				column.reinitializeWidth();
			});
		}
	};
	var VirtualDomHorizontal = class extends Renderer {
		constructor(table) {
			super(table);
			this.leftCol = 0;
			this.rightCol = 0;
			this.scrollLeft = 0;
			this.vDomScrollPosLeft = 0;
			this.vDomScrollPosRight = 0;
			this.vDomPadLeft = 0;
			this.vDomPadRight = 0;
			this.fitDataColAvg = 0;
			this.windowBuffer = 200;
			this.visibleRows = null;
			this.initialized = false;
			this.isFitData = false;
			this.columns = [];
		}
		initialize() {
			this.compatibilityCheck();
			this.layoutCheck();
			this.vertScrollListen();
		}
		compatibilityCheck() {
			if (this.options("layout") == "fitDataTable") console.warn("Horizontal Virtual DOM is not compatible with fitDataTable layout mode");
			if (this.options("responsiveLayout")) console.warn("Horizontal Virtual DOM is not compatible with responsive columns");
			if (this.options("rtl")) console.warn("Horizontal Virtual DOM is not currently compatible with RTL text direction");
		}
		layoutCheck() {
			this.isFitData = this.options("layout").startsWith("fitData");
		}
		vertScrollListen() {
			this.subscribe("scroll-vertical", this.clearVisRowCache.bind(this));
			this.subscribe("data-refreshed", this.clearVisRowCache.bind(this));
		}
		clearVisRowCache() {
			this.visibleRows = null;
		}
		renderColumns(row, force) {
			this.dataChange();
		}
		scrollColumns(left, dir) {
			if (this.scrollLeft != left) {
				this.scrollLeft = left;
				this.scroll(left - (this.vDomScrollPosLeft + this.windowBuffer));
			}
		}
		calcWindowBuffer() {
			var buffer = this.elementVertical.clientWidth;
			this.table.columnManager.columnsByIndex.forEach((column) => {
				if (column.visible) {
					var width = column.getWidth();
					if (width > buffer) buffer = width;
				}
			});
			this.windowBuffer = buffer * 2;
		}
		rerenderColumns(update, blockRedraw) {
			var old = {
				cols: this.columns,
				leftCol: this.leftCol,
				rightCol: this.rightCol
			}, colPos = 0;
			if (update && !this.initialized) return;
			this.clear();
			this.calcWindowBuffer();
			this.scrollLeft = this.elementVertical.scrollLeft;
			this.vDomScrollPosLeft = this.scrollLeft - this.windowBuffer;
			this.vDomScrollPosRight = this.scrollLeft + this.elementVertical.clientWidth + this.windowBuffer;
			this.table.columnManager.columnsByIndex.forEach((column) => {
				var config = {}, width;
				if (column.visible) {
					if (!column.modules.frozen) {
						width = column.getWidth();
						config.leftPos = colPos;
						config.rightPos = colPos + width;
						config.width = width;
						if (this.isFitData) config.fitDataCheck = column.modules.vdomHoz ? column.modules.vdomHoz.fitDataCheck : true;
						if (colPos + width > this.vDomScrollPosLeft && colPos < this.vDomScrollPosRight) {
							if (this.leftCol == -1) {
								this.leftCol = this.columns.length;
								this.vDomPadLeft = colPos;
							}
							this.rightCol = this.columns.length;
						} else if (this.leftCol !== -1) this.vDomPadRight += width;
						this.columns.push(column);
						column.modules.vdomHoz = config;
						colPos += width;
					}
				}
			});
			this.tableElement.style.paddingLeft = this.vDomPadLeft + "px";
			this.tableElement.style.paddingRight = this.vDomPadRight + "px";
			this.initialized = true;
			if (!blockRedraw) {
				if (!update || this.reinitChanged(old)) this.reinitializeRows();
			}
			this.elementVertical.scrollLeft = this.scrollLeft;
		}
		renderRowCells(row) {
			if (this.initialized) this.initializeRow(row);
			else {
				const rowFrag = document.createDocumentFragment();
				row.cells.forEach((cell) => {
					rowFrag.appendChild(cell.getElement());
				});
				row.element.appendChild(rowFrag);
				row.cells.forEach((cell) => {
					cell.cellRendered();
				});
			}
		}
		rerenderRowCells(row, force) {
			this.reinitializeRow(row, force);
		}
		reinitializeColumnWidths(columns) {
			for (let i = this.leftCol; i <= this.rightCol; i++) {
				let col = this.columns[i];
				if (col) col.reinitializeWidth();
			}
		}
		deinitialize() {
			this.initialized = false;
		}
		clear() {
			this.columns = [];
			this.leftCol = -1;
			this.rightCol = 0;
			this.vDomScrollPosLeft = 0;
			this.vDomScrollPosRight = 0;
			this.vDomPadLeft = 0;
			this.vDomPadRight = 0;
		}
		dataChange() {
			var change = false, row, rowEl;
			if (this.isFitData) {
				this.table.columnManager.columnsByIndex.forEach((column) => {
					if (!column.definition.width && column.visible) change = true;
				});
				if (change && this.table.rowManager.getDisplayRows().length) {
					this.vDomScrollPosRight = this.scrollLeft + this.elementVertical.clientWidth + this.windowBuffer;
					row = this.chain("rows-sample", [1], [], () => {
						return this.table.rowManager.getDisplayRows();
					})[0];
					if (row) {
						rowEl = row.getElement();
						row.generateCells();
						this.tableElement.appendChild(rowEl);
						for (let colEnd = 0; colEnd < row.cells.length; colEnd++) {
							let cell = row.cells[colEnd];
							rowEl.appendChild(cell.getElement());
							cell.column.reinitializeWidth();
						}
						rowEl.parentNode.removeChild(rowEl);
						this.rerenderColumns(false, true);
					}
				}
			} else if (this.options("layout") === "fitColumns") {
				this.layoutRefresh();
				this.rerenderColumns(false, true);
			}
		}
		reinitChanged(old) {
			var match = true;
			if (old.cols.length !== this.columns.length || old.leftCol !== this.leftCol || old.rightCol !== this.rightCol) return true;
			old.cols.forEach((col, i) => {
				if (col !== this.columns[i]) match = false;
			});
			return !match;
		}
		reinitializeRows() {
			var visibleRows = this.getVisibleRows(), otherRows = this.table.rowManager.getRows().filter((row) => !visibleRows.includes(row));
			visibleRows.forEach((row) => {
				this.reinitializeRow(row, true);
			});
			otherRows.forEach((row) => {
				row.deinitialize();
			});
		}
		getVisibleRows() {
			if (!this.visibleRows) this.visibleRows = this.table.rowManager.getVisibleRows();
			return this.visibleRows;
		}
		scroll(diff) {
			this.vDomScrollPosLeft += diff;
			this.vDomScrollPosRight += diff;
			if (Math.abs(diff) > this.windowBuffer / 2) this.rerenderColumns();
			else if (diff > 0) {
				this.addColRight();
				this.removeColLeft();
			} else {
				this.addColLeft();
				this.removeColRight();
			}
		}
		colPositionAdjust(start, end, diff) {
			for (let i = start; i < end; i++) {
				let column = this.columns[i];
				column.modules.vdomHoz.leftPos += diff;
				column.modules.vdomHoz.rightPos += diff;
			}
		}
		addColRight() {
			var changes = false, working = true;
			while (working) {
				let column = this.columns[this.rightCol + 1];
				if (column) if (column.modules.vdomHoz.leftPos <= this.vDomScrollPosRight) {
					changes = true;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") {
							var cell = row.getCell(column);
							row.getElement().insertBefore(cell.getElement(), row.getCell(this.columns[this.rightCol]).getElement().nextSibling);
							cell.cellRendered();
						}
					});
					this.fitDataColActualWidthCheck(column);
					this.rightCol++;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") row.modules.vdomHoz.rightCol = this.rightCol;
					});
					if (this.rightCol >= this.columns.length - 1) this.vDomPadRight = 0;
					else this.vDomPadRight -= column.getWidth();
				} else working = false;
				else working = false;
			}
			if (changes) this.tableElement.style.paddingRight = this.vDomPadRight + "px";
		}
		addColLeft() {
			var changes = false, working = true;
			while (working) {
				let column = this.columns[this.leftCol - 1];
				if (column) if (column.modules.vdomHoz.rightPos >= this.vDomScrollPosLeft) {
					changes = true;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") {
							var cell = row.getCell(column);
							row.getElement().insertBefore(cell.getElement(), row.getCell(this.columns[this.leftCol]).getElement());
							cell.cellRendered();
						}
					});
					this.leftCol--;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") row.modules.vdomHoz.leftCol = this.leftCol;
					});
					if (this.leftCol <= 0) this.vDomPadLeft = 0;
					else this.vDomPadLeft -= column.getWidth();
					let diff = this.fitDataColActualWidthCheck(column);
					if (diff) {
						this.scrollLeft = this.elementVertical.scrollLeft = this.elementVertical.scrollLeft + diff;
						this.vDomPadRight -= diff;
					}
				} else working = false;
				else working = false;
			}
			if (changes) this.tableElement.style.paddingLeft = this.vDomPadLeft + "px";
		}
		removeColRight() {
			var changes = false, working = true;
			while (working) {
				let column = this.columns[this.rightCol];
				if (column) if (column.modules.vdomHoz.leftPos > this.vDomScrollPosRight) {
					changes = true;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") {
							var cell = row.getCell(column);
							try {
								row.getElement().removeChild(cell.getElement());
							} catch (ex) {
								console.warn("Could not removeColRight", ex.message);
							}
						}
					});
					this.vDomPadRight += column.getWidth();
					this.rightCol--;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") row.modules.vdomHoz.rightCol = this.rightCol;
					});
				} else working = false;
				else working = false;
			}
			if (changes) this.tableElement.style.paddingRight = this.vDomPadRight + "px";
		}
		removeColLeft() {
			var changes = false, working = true;
			while (working) {
				let column = this.columns[this.leftCol];
				if (column) if (column.modules.vdomHoz.rightPos < this.vDomScrollPosLeft) {
					changes = true;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") {
							var cell = row.getCell(column);
							try {
								row.getElement().removeChild(cell.getElement());
							} catch (ex) {
								console.warn("Could not removeColLeft", ex.message);
							}
						}
					});
					this.vDomPadLeft += column.getWidth();
					this.leftCol++;
					this.getVisibleRows().forEach((row) => {
						if (row.type !== "group") row.modules.vdomHoz.leftCol = this.leftCol;
					});
				} else working = false;
				else working = false;
			}
			if (changes) this.tableElement.style.paddingLeft = this.vDomPadLeft + "px";
		}
		fitDataColActualWidthCheck(column) {
			var newWidth, widthDiff;
			if (column.modules.vdomHoz.fitDataCheck) {
				column.reinitializeWidth();
				newWidth = column.getWidth();
				widthDiff = newWidth - column.modules.vdomHoz.width;
				if (widthDiff) {
					column.modules.vdomHoz.rightPos += widthDiff;
					column.modules.vdomHoz.width = newWidth;
					this.colPositionAdjust(this.columns.indexOf(column) + 1, this.columns.length, widthDiff);
				}
				column.modules.vdomHoz.fitDataCheck = false;
			}
			return widthDiff;
		}
		initializeRow(row) {
			if (row.type !== "group") {
				row.modules.vdomHoz = {
					leftCol: this.leftCol,
					rightCol: this.rightCol
				};
				if (this.table.modules.frozenColumns) this.table.modules.frozenColumns.leftColumns.forEach((column) => {
					this.appendCell(row, column);
				});
				for (let i = this.leftCol; i <= this.rightCol; i++) this.appendCell(row, this.columns[i]);
				if (this.table.modules.frozenColumns) this.table.modules.frozenColumns.rightColumns.forEach((column) => {
					this.appendCell(row, column);
				});
			}
		}
		appendCell(row, column) {
			if (column && column.visible) {
				let cell = row.getCell(column);
				row.getElement().appendChild(cell.getElement());
				cell.cellRendered();
			}
		}
		reinitializeRow(row, force) {
			if (row.type !== "group") {
				if (force || !row.modules.vdomHoz || row.modules.vdomHoz.leftCol !== this.leftCol || row.modules.vdomHoz.rightCol !== this.rightCol) {
					var rowEl = row.getElement();
					while (rowEl.firstChild) rowEl.removeChild(rowEl.firstChild);
					this.initializeRow(row);
				}
			}
		}
	};
	var ColumnManager = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.blockHozScrollEvent = false;
			this.headersElement = null;
			this.contentsElement = null;
			this.rowHeader = null;
			this.element = null;
			this.columns = [];
			this.columnsByIndex = [];
			this.columnsByField = {};
			this.scrollLeft = 0;
			this.optionsList = new OptionsList(this.table, "column definition", defaultColumnOptions);
			this.redrawBlock = false;
			this.redrawBlockUpdate = null;
			this.renderer = null;
		}
		initialize() {
			this.initializeRenderer();
			this.headersElement = this.createHeadersElement();
			this.contentsElement = this.createHeaderContentsElement();
			this.element = this.createHeaderElement();
			this.contentsElement.insertBefore(this.headersElement, this.contentsElement.firstChild);
			this.element.insertBefore(this.contentsElement, this.element.firstChild);
			this.initializeScrollWheelWatcher();
			this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
			this.subscribe("scrollbar-vertical", this.padVerticalScrollbar.bind(this));
		}
		padVerticalScrollbar(width) {
			if (this.table.rtl) this.headersElement.style.marginLeft = width + "px";
			else this.headersElement.style.marginRight = width + "px";
		}
		initializeRenderer() {
			var renderClass;
			var renderers = {
				"virtual": VirtualDomHorizontal,
				"basic": BasicHorizontal
			};
			if (typeof this.table.options.renderHorizontal === "string") renderClass = renderers[this.table.options.renderHorizontal];
			else renderClass = this.table.options.renderHorizontal;
			if (renderClass) {
				this.renderer = new renderClass(this.table, this.element, this.tableElement);
				this.renderer.initialize();
			} else console.error("Unable to find matching renderer:", this.table.options.renderHorizontal);
		}
		createHeadersElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-headers");
			el.setAttribute("role", "row");
			return el;
		}
		createHeaderContentsElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-header-contents");
			el.setAttribute("role", "rowgroup");
			return el;
		}
		createHeaderElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-header");
			el.setAttribute("role", "rowgroup");
			if (!this.table.options.headerVisible) el.classList.add("tabulator-header-hidden");
			return el;
		}
		getElement() {
			return this.element;
		}
		getContentsElement() {
			return this.contentsElement;
		}
		getHeadersElement() {
			return this.headersElement;
		}
		scrollHorizontal(left) {
			this.contentsElement.scrollLeft = left;
			this.scrollLeft = left;
			this.renderer.scrollColumns(left);
		}
		initializeScrollWheelWatcher() {
			this.contentsElement.addEventListener("wheel", (e) => {
				var left;
				if (e.deltaX) {
					left = this.contentsElement.scrollLeft + e.deltaX;
					this.table.rowManager.scrollHorizontal(left);
					this.table.columnManager.scrollHorizontal(left);
				}
			});
		}
		generateColumnsFromRowData(data) {
			var cols = [], collProgress = {}, rowSample = this.table.options.autoColumns === "full" ? data : [data[0]], definitions = this.table.options.autoColumnsDefinitions;
			if (data && data.length) {
				rowSample.forEach((row) => {
					Object.keys(row).forEach((key, index) => {
						let value = row[key], col;
						if (!collProgress[key]) {
							col = {
								field: key,
								title: key,
								sorter: this.calculateSorterFromValue(value)
							};
							cols.splice(index, 0, col);
							collProgress[key] = typeof value === "undefined" ? col : true;
						} else if (collProgress[key] !== true) {
							if (typeof value !== "undefined") {
								collProgress[key].sorter = this.calculateSorterFromValue(value);
								collProgress[key] = true;
							}
						}
					});
				});
				if (definitions) switch (typeof definitions) {
					case "function":
						this.table.options.columns = definitions.call(this.table, cols);
						break;
					case "object":
						if (Array.isArray(definitions)) cols.forEach((col) => {
							var match = definitions.find((def) => {
								return def.field === col.field;
							});
							if (match) Object.assign(col, match);
						});
						else cols.forEach((col) => {
							if (definitions[col.field]) Object.assign(col, definitions[col.field]);
						});
						this.table.options.columns = cols;
						break;
				}
				else this.table.options.columns = cols;
				this.setColumns(this.table.options.columns);
			}
		}
		calculateSorterFromValue(value) {
			var sorter;
			switch (typeof value) {
				case "undefined":
					sorter = "string";
					break;
				case "boolean":
					sorter = "boolean";
					break;
				case "number":
					sorter = "number";
					break;
				case "object":
					if (Array.isArray(value)) sorter = "array";
					else sorter = "string";
					break;
				default:
					if (!isNaN(value) && value !== "") sorter = "number";
					else if (value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)) sorter = "alphanum";
					else sorter = "string";
					break;
			}
			return sorter;
		}
		setColumns(cols, row) {
			while (this.headersElement.firstChild) this.headersElement.removeChild(this.headersElement.firstChild);
			this.columns = [];
			this.columnsByIndex = [];
			this.columnsByField = {};
			this.dispatch("columns-loading");
			this.dispatchExternal("columnsLoading");
			if (this.table.options.rowHeader) {
				this.rowHeader = new Column(this.table.options.rowHeader === true ? {} : this.table.options.rowHeader, this, true);
				this.columns.push(this.rowHeader);
				this.headersElement.appendChild(this.rowHeader.getElement());
				this.rowHeader.columnRendered();
			}
			cols.forEach((def, i) => {
				this._addColumn(def);
			});
			this._reIndexColumns();
			this.dispatch("columns-loaded");
			if (this.subscribedExternal("columnsLoaded")) this.dispatchExternal("columnsLoaded", this.getComponents());
			this.rerenderColumns(false, true);
			this.redraw(true);
		}
		_addColumn(definition, before, nextToColumn) {
			var column = new Column(definition, this), colEl = column.getElement(), index = nextToColumn ? this.findColumnIndex(nextToColumn) : nextToColumn;
			if (before && this.rowHeader && (!nextToColumn || nextToColumn === this.rowHeader)) {
				before = false;
				nextToColumn = this.rowHeader;
				index = 0;
			}
			if (nextToColumn && index > -1) {
				var topColumn = nextToColumn.getTopColumn();
				var parentIndex = this.columns.indexOf(topColumn);
				var nextEl = topColumn.getElement();
				if (before) {
					this.columns.splice(parentIndex, 0, column);
					nextEl.parentNode.insertBefore(colEl, nextEl);
				} else {
					this.columns.splice(parentIndex + 1, 0, column);
					nextEl.parentNode.insertBefore(colEl, nextEl.nextSibling);
				}
			} else if (before) {
				this.columns.unshift(column);
				this.headersElement.insertBefore(column.getElement(), this.headersElement.firstChild);
			} else {
				this.columns.push(column);
				this.headersElement.appendChild(column.getElement());
			}
			column.columnRendered();
			return column;
		}
		registerColumnField(col) {
			if (col.definition.field) this.columnsByField[col.definition.field] = col;
		}
		registerColumnPosition(col) {
			this.columnsByIndex.push(col);
		}
		_reIndexColumns() {
			this.columnsByIndex = [];
			this.columns.forEach(function(column) {
				column.reRegisterPosition();
			});
		}
		verticalAlignHeaders() {
			var minHeight = 0;
			if (!this.redrawBlock) {
				this.headersElement.style.height = "";
				this.columns.forEach((column) => {
					column.clearVerticalAlign();
				});
				this.columns.forEach((column) => {
					var height = column.getHeight();
					if (height > minHeight) minHeight = height;
				});
				this.headersElement.style.height = minHeight + "px";
				this.columns.forEach((column) => {
					column.verticalAlign(this.table.options.columnHeaderVertAlign, minHeight);
				});
				this.table.rowManager.adjustTableSize();
			}
		}
		findColumn(subject) {
			var columns;
			if (typeof subject == "object") {
				if (subject instanceof Column) return subject;
				else if (subject instanceof ColumnComponent) return subject._getSelf() || false;
				else if (typeof HTMLElement !== "undefined" && subject instanceof HTMLElement) {
					columns = [];
					this.columns.forEach((column) => {
						columns.push(column);
						columns = columns.concat(column.getColumns(true));
					});
					return columns.find((column) => {
						return column.element === subject;
					}) || false;
				}
			} else return this.columnsByField[subject] || false;
			return false;
		}
		getColumnByField(field) {
			return this.columnsByField[field];
		}
		getColumnsByFieldRoot(root) {
			var matches = [];
			Object.keys(this.columnsByField).forEach((field) => {
				if ((this.table.options.nestedFieldSeparator ? field.split(this.table.options.nestedFieldSeparator)[0] : field) === root) matches.push(this.columnsByField[field]);
			});
			return matches;
		}
		getColumnByIndex(index) {
			return this.columnsByIndex[index];
		}
		getFirstVisibleColumn() {
			var index = this.columnsByIndex.findIndex((col) => {
				return col.visible;
			});
			return index > -1 ? this.columnsByIndex[index] : false;
		}
		getVisibleColumnsByIndex() {
			return this.columnsByIndex.filter((col) => col.visible);
		}
		getColumns() {
			return this.columns;
		}
		findColumnIndex(column) {
			return this.columnsByIndex.findIndex((col) => {
				return column === col;
			});
		}
		getRealColumns() {
			return this.columnsByIndex;
		}
		traverse(callback) {
			this.columnsByIndex.forEach((column, i) => {
				callback(column, i);
			});
		}
		getDefinitions(active) {
			var output = [];
			this.columnsByIndex.forEach((column) => {
				if (!active || active && column.visible) output.push(column.getDefinition());
			});
			return output;
		}
		getDefinitionTree() {
			var output = [];
			this.columns.forEach((column) => {
				output.push(column.getDefinition(true));
			});
			return output;
		}
		getComponents(structured) {
			var output = [];
			(structured ? this.columns : this.columnsByIndex).forEach((column) => {
				output.push(column.getComponent());
			});
			return output;
		}
		getWidth() {
			var width = 0;
			this.columnsByIndex.forEach((column) => {
				if (column.visible) width += column.getWidth();
			});
			return width;
		}
		moveColumn(from, to, after) {
			to.element.parentNode.insertBefore(from.element, to.element);
			if (after) to.element.parentNode.insertBefore(to.element, from.element);
			this.moveColumnActual(from, to, after);
			this.verticalAlignHeaders();
			this.table.rowManager.reinitialize();
		}
		moveColumnActual(from, to, after) {
			if (from.parent.isGroup) this._moveColumnInArray(from.parent.columns, from, to, after);
			else this._moveColumnInArray(this.columns, from, to, after);
			this._moveColumnInArray(this.columnsByIndex, from, to, after, true);
			this.rerenderColumns(true);
			this.dispatch("column-moved", from, to, after);
			if (this.subscribedExternal("columnMoved")) this.dispatchExternal("columnMoved", from.getComponent(), this.table.columnManager.getComponents());
		}
		_moveColumnInArray(columns, from, to, after, updateRows) {
			var fromIndex = columns.indexOf(from), toIndex, rows = [];
			if (fromIndex > -1) {
				columns.splice(fromIndex, 1);
				toIndex = columns.indexOf(to);
				if (toIndex > -1) {
					if (after) toIndex = toIndex + 1;
				} else toIndex = fromIndex;
				columns.splice(toIndex, 0, from);
				if (updateRows) {
					rows = this.chain("column-moving-rows", [
						from,
						to,
						after
					], null, []) || [];
					rows = rows.concat(this.table.rowManager.rows);
					rows.forEach(function(row) {
						if (row.cells.length) {
							var cell = row.cells.splice(fromIndex, 1)[0];
							row.cells.splice(toIndex, 0, cell);
						}
					});
				}
			}
		}
		scrollToColumn(column, position, ifVisible) {
			var left = 0, offset = column.getLeftOffset(), adjust = 0, colEl = column.getElement();
			return new Promise((resolve, reject) => {
				if (typeof position === "undefined") position = this.table.options.scrollToColumnPosition;
				if (typeof ifVisible === "undefined") ifVisible = this.table.options.scrollToColumnIfVisible;
				if (column.visible) {
					switch (position) {
						case "middle":
						case "center":
							adjust = -this.element.clientWidth / 2;
							break;
						case "right":
							adjust = colEl.clientWidth - this.headersElement.clientWidth;
							break;
					}
					if (!ifVisible) {
						if (offset > 0 && offset + colEl.offsetWidth < this.element.clientWidth) return false;
					}
					left = offset + adjust;
					left = Math.max(Math.min(left, this.table.rowManager.element.scrollWidth - this.table.rowManager.element.clientWidth), 0);
					this.table.rowManager.scrollHorizontal(left);
					this.scrollHorizontal(left);
					resolve();
				} else {
					console.warn("Scroll Error - Column not visible");
					reject("Scroll Error - Column not visible");
				}
			});
		}
		generateCells(row) {
			var cells = [];
			this.columnsByIndex.forEach((column) => {
				cells.push(column.generateCell(row));
			});
			return cells;
		}
		getFlexBaseWidth() {
			var totalWidth = this.table.element.clientWidth, fixedWidth = 0;
			if (this.table.rowManager.element.scrollHeight > this.table.rowManager.element.clientHeight) totalWidth -= this.table.rowManager.element.offsetWidth - this.table.rowManager.element.clientWidth;
			this.columnsByIndex.forEach(function(column) {
				var width, minWidth, colWidth;
				if (column.visible) {
					width = column.definition.width || 0;
					minWidth = parseInt(column.minWidth);
					if (typeof width == "string") if (width.indexOf("%") > -1) colWidth = totalWidth / 100 * parseInt(width);
					else colWidth = parseInt(width);
					else colWidth = width;
					fixedWidth += colWidth > minWidth ? colWidth : minWidth;
				}
			});
			return fixedWidth;
		}
		addColumn(definition, before, nextToColumn) {
			return new Promise((resolve, reject) => {
				var column = this._addColumn(definition, before, nextToColumn);
				this._reIndexColumns();
				this.dispatch("column-add", definition, before, nextToColumn);
				if (this.layoutMode() != "fitColumns") column.reinitializeWidth();
				this.redraw(true);
				this.table.rowManager.reinitialize();
				this.rerenderColumns();
				resolve(column);
			});
		}
		deregisterColumn(column) {
			var field = column.getField(), index;
			if (field) delete this.columnsByField[field];
			index = this.columnsByIndex.indexOf(column);
			if (index > -1) this.columnsByIndex.splice(index, 1);
			index = this.columns.indexOf(column);
			if (index > -1) this.columns.splice(index, 1);
			this.verticalAlignHeaders();
			this.redraw();
		}
		rerenderColumns(update, silent) {
			if (!this.redrawBlock) this.renderer.rerenderColumns(update, silent);
			else if (update === false || update === true && this.redrawBlockUpdate === null) this.redrawBlockUpdate = update;
		}
		blockRedraw() {
			this.redrawBlock = true;
			this.redrawBlockUpdate = null;
		}
		restoreRedraw() {
			this.redrawBlock = false;
			this.verticalAlignHeaders();
			this.renderer.rerenderColumns(this.redrawBlockUpdate);
		}
		redraw(force) {
			if (Helpers.elVisible(this.element)) this.verticalAlignHeaders();
			if (force) {
				this.table.rowManager.resetScroll();
				this.table.rowManager.reinitialize();
			}
			if (!this.confirm("table-redrawing", force)) this.layoutRefresh(force);
			this.dispatch("table-redraw", force);
			this.table.footerManager.redraw();
		}
	};
	var BasicVertical = class extends Renderer {
		constructor(table) {
			super(table);
			this.verticalFillMode = "fill";
			this.scrollTop = 0;
			this.scrollLeft = 0;
			this.scrollTop = 0;
			this.scrollLeft = 0;
		}
		clearRows() {
			var element = this.tableElement;
			while (element.firstChild) element.removeChild(element.firstChild);
			element.scrollTop = 0;
			element.scrollLeft = 0;
			element.style.minWidth = "";
			element.style.minHeight = "";
			element.style.display = "";
			element.style.visibility = "";
		}
		renderRows() {
			var element = this.tableElement, onlyGroupHeaders = true, tableFrag = document.createDocumentFragment(), rows = this.rows();
			rows.forEach((row, index) => {
				this.styleRow(row, index);
				row.initialize(false, true);
				if (row.type !== "group") onlyGroupHeaders = false;
				tableFrag.appendChild(row.getElement());
			});
			element.appendChild(tableFrag);
			rows.forEach((row) => {
				row.rendered();
				if (!row.heightInitialized) row.calcHeight(true);
			});
			rows.forEach((row) => {
				if (!row.heightInitialized) row.setCellHeight();
			});
			if (onlyGroupHeaders) element.style.minWidth = this.table.columnManager.getWidth() + "px";
			else element.style.minWidth = "";
		}
		rerenderRows(callback) {
			this.clearRows();
			if (callback) callback();
			this.renderRows();
			if (!this.rows().length) this.table.rowManager.tableEmpty();
		}
		scrollToRowNearestTop(row) {
			var rowTop = Helpers.elOffset(row.getElement()).top;
			return !(Math.abs(this.elementVertical.scrollTop - rowTop) > Math.abs(this.elementVertical.scrollTop + this.elementVertical.clientHeight - rowTop));
		}
		scrollToRow(row) {
			var rowEl = row.getElement();
			this.elementVertical.scrollTop = Helpers.elOffset(rowEl).top - Helpers.elOffset(this.elementVertical).top + this.elementVertical.scrollTop;
		}
		visibleRows(includingBuffer) {
			return this.rows();
		}
	};
	var VirtualDomVertical = class extends Renderer {
		constructor(table) {
			super(table);
			this.verticalFillMode = "fill";
			this.scrollTop = 0;
			this.scrollLeft = 0;
			this.vDomRowHeight = 20;
			this.vDomTop = 0;
			this.vDomBottom = 0;
			this.vDomScrollPosTop = 0;
			this.vDomScrollPosBottom = 0;
			this.vDomTopPad = 0;
			this.vDomBottomPad = 0;
			this.vDomMaxRenderChain = 90;
			this.vDomWindowBuffer = 0;
			this.vDomWindowMinTotalRows = 20;
			this.vDomWindowMinMarginRows = 5;
			this.vDomTopNewRows = [];
			this.vDomBottomNewRows = [];
		}
		clearRows() {
			var element = this.tableElement;
			while (element.firstChild) element.removeChild(element.firstChild);
			element.style.paddingTop = "";
			element.style.paddingBottom = "";
			element.style.minHeight = "";
			element.style.display = "";
			element.style.visibility = "";
			this.elementVertical.scrollTop = 0;
			this.elementVertical.scrollLeft = 0;
			this.scrollTop = 0;
			this.scrollLeft = 0;
			this.vDomTop = 0;
			this.vDomBottom = 0;
			this.vDomTopPad = 0;
			this.vDomBottomPad = 0;
			this.vDomScrollPosTop = 0;
			this.vDomScrollPosBottom = 0;
		}
		renderRows() {
			this._virtualRenderFill();
		}
		rerenderRows(callback) {
			var scrollTop = this.elementVertical.scrollTop;
			var topRow = false;
			var topOffset = false;
			var left = this.table.rowManager.scrollLeft;
			var rows = this.rows();
			for (var i = this.vDomTop; i <= this.vDomBottom; i++) if (rows[i]) {
				var diff = scrollTop - rows[i].getElement().offsetTop;
				if (topOffset === false || Math.abs(diff) < topOffset) {
					topOffset = diff;
					topRow = i;
				} else break;
			}
			rows.forEach((row) => {
				row.deinitializeHeight();
			});
			if (callback) callback();
			if (this.rows().length) this._virtualRenderFill(topRow === false ? this.rows.length - 1 : topRow, true, topOffset || 0);
			else {
				this.clear();
				this.table.rowManager.tableEmpty();
			}
			this.scrollColumns(left);
		}
		scrollColumns(left) {
			this.table.rowManager.scrollHorizontal(left);
		}
		scrollRows(top, dir) {
			var topDiff = top - this.vDomScrollPosTop;
			var bottomDiff = top - this.vDomScrollPosBottom;
			var margin = this.vDomWindowBuffer * 2;
			var rows = this.rows();
			this.scrollTop = top;
			if (-topDiff > margin || bottomDiff > margin) {
				var left = this.table.rowManager.scrollLeft;
				this._virtualRenderFill(Math.floor(this.elementVertical.scrollTop / this.elementVertical.scrollHeight * rows.length));
				this.scrollColumns(left);
			} else if (dir) {
				if (topDiff < 0) this._addTopRow(rows, -topDiff);
				if (bottomDiff < 0) if (this.vDomScrollHeight - this.scrollTop > this.vDomWindowBuffer) this._removeBottomRow(rows, -bottomDiff);
				else this.vDomScrollPosBottom = this.scrollTop;
			} else {
				if (bottomDiff >= 0) this._addBottomRow(rows, bottomDiff);
				if (topDiff >= 0) if (this.scrollTop > this.vDomWindowBuffer) this._removeTopRow(rows, topDiff);
				else this.vDomScrollPosTop = this.scrollTop;
			}
		}
		resize() {
			this.vDomWindowBuffer = this.table.options.renderVerticalBuffer || this.elementVertical.clientHeight;
		}
		scrollToRowNearestTop(row) {
			var rowIndex = this.rows().indexOf(row);
			return !(Math.abs(this.vDomTop - rowIndex) > Math.abs(this.vDomBottom - rowIndex));
		}
		scrollToRow(row) {
			var index = this.rows().indexOf(row);
			if (index > -1) this._virtualRenderFill(index, true);
		}
		visibleRows(includingBuffer) {
			var topEdge = this.elementVertical.scrollTop, bottomEdge = this.elementVertical.clientHeight + topEdge, topFound = false, topRow = 0, bottomRow = 0, rows = this.rows();
			if (includingBuffer) {
				topRow = this.vDomTop;
				bottomRow = this.vDomBottom;
			} else for (var i = this.vDomTop; i <= this.vDomBottom; i++) if (rows[i]) if (!topFound) if (topEdge - rows[i].getElement().offsetTop >= 0) topRow = i;
			else {
				topFound = true;
				if (bottomEdge - rows[i].getElement().offsetTop >= 0) bottomRow = i;
				else break;
			}
			else if (bottomEdge - rows[i].getElement().offsetTop >= 0) bottomRow = i;
			else break;
			return rows.slice(topRow, bottomRow + 1);
		}
		_virtualRenderFill(position, forceMove, offset) {
			var element = this.tableElement, holder = this.elementVertical, topPad = 0, rowsHeight = 0, rowHeight = 0, heightOccupied = 0, topPadHeight = 0, i = 0, rows = this.rows(), rowsCount = rows.length, index = 0, row, rowFragment, renderedRows = [], totalRowsRendered = 0, rowsToRender = 0, fixedHeight = this.table.rowManager.fixedHeight, containerHeight = this.elementVertical.clientHeight, avgRowHeight = this.table.options.rowHeight, resized = true;
			position = position || 0;
			offset = offset || 0;
			if (!position) this.clear();
			else {
				while (element.firstChild) element.removeChild(element.firstChild);
				heightOccupied = (rowsCount - position + 1) * this.vDomRowHeight;
				if (heightOccupied < containerHeight) {
					position -= Math.ceil((containerHeight - heightOccupied) / this.vDomRowHeight);
					if (position < 0) position = 0;
				}
				topPad = Math.min(Math.max(Math.floor(this.vDomWindowBuffer / this.vDomRowHeight), this.vDomWindowMinMarginRows), position);
				position -= topPad;
			}
			if (rowsCount && Helpers.elVisible(this.elementVertical)) {
				this.vDomTop = position;
				this.vDomBottom = position - 1;
				if (fixedHeight || this.table.options.maxHeight) {
					if (avgRowHeight) rowsToRender = containerHeight / avgRowHeight + this.vDomWindowBuffer / avgRowHeight;
					rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil(rowsToRender));
				} else rowsToRender = rowsCount;
				while ((rowsToRender == rowsCount || rowsHeight <= containerHeight + this.vDomWindowBuffer || totalRowsRendered < this.vDomWindowMinTotalRows) && this.vDomBottom < rowsCount - 1) {
					renderedRows = [];
					rowFragment = document.createDocumentFragment();
					i = 0;
					while (i < rowsToRender && this.vDomBottom < rowsCount - 1) {
						index = this.vDomBottom + 1, row = rows[index];
						this.styleRow(row, index);
						row.initialize(false, true);
						if (!row.heightInitialized && !this.table.options.rowHeight) row.clearCellHeight();
						rowFragment.appendChild(row.getElement());
						renderedRows.push(row);
						this.vDomBottom++;
						i++;
					}
					if (!renderedRows.length) break;
					element.appendChild(rowFragment);
					renderedRows.forEach((row) => {
						row.rendered();
						if (!row.heightInitialized) row.calcHeight(true);
					});
					renderedRows.forEach((row) => {
						if (!row.heightInitialized) row.setCellHeight();
					});
					renderedRows.forEach((row) => {
						rowHeight = row.getHeight();
						if (totalRowsRendered < topPad) topPadHeight += rowHeight;
						else rowsHeight += rowHeight;
						if (rowHeight > this.vDomWindowBuffer) this.vDomWindowBuffer = rowHeight * 2;
						totalRowsRendered++;
					});
					resized = this.table.rowManager.adjustTableSize();
					containerHeight = this.elementVertical.clientHeight;
					if (resized && (fixedHeight || this.table.options.maxHeight)) {
						avgRowHeight = rowsHeight / totalRowsRendered;
						rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil(containerHeight / avgRowHeight + this.vDomWindowBuffer / avgRowHeight));
					}
				}
				if (!position) {
					this.vDomTopPad = 0;
					this.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / totalRowsRendered);
					this.vDomBottomPad = this.vDomRowHeight * (rowsCount - this.vDomBottom - 1);
					this.vDomScrollHeight = topPadHeight + rowsHeight + this.vDomBottomPad - containerHeight;
				} else {
					this.vDomTopPad = !forceMove ? this.scrollTop - topPadHeight : this.vDomRowHeight * this.vDomTop + offset;
					this.vDomBottomPad = this.vDomBottom == rowsCount - 1 ? 0 : Math.max(this.vDomScrollHeight - this.vDomTopPad - rowsHeight - topPadHeight, 0);
				}
				element.style.paddingTop = this.vDomTopPad + "px";
				element.style.paddingBottom = this.vDomBottomPad + "px";
				if (forceMove) this.scrollTop = this.vDomTopPad + topPadHeight + offset - (this.elementVertical.scrollWidth > this.elementVertical.clientWidth ? this.elementVertical.offsetHeight - containerHeight : 0);
				this.scrollTop = Math.min(this.scrollTop, this.elementVertical.scrollHeight - containerHeight);
				if (this.elementVertical.scrollWidth > this.elementVertical.clientWidth && forceMove) this.scrollTop += this.elementVertical.offsetHeight - containerHeight;
				this.vDomScrollPosTop = this.scrollTop;
				this.vDomScrollPosBottom = this.scrollTop;
				holder.scrollTop = this.scrollTop;
				this.dispatch("render-virtual-fill");
			}
		}
		_addTopRow(rows, fillableSpace) {
			var table = this.tableElement, addedRows = [], paddingAdjust = 0, index = this.vDomTop - 1, i = 0, working = true;
			while (working) if (this.vDomTop) {
				let row = rows[index], rowHeight, initialized;
				if (row && i < this.vDomMaxRenderChain) {
					rowHeight = row.getHeight() || this.vDomRowHeight;
					initialized = row.initialized;
					if (fillableSpace >= rowHeight) {
						this.styleRow(row, index);
						table.insertBefore(row.getElement(), table.firstChild);
						if (!row.initialized || !row.heightInitialized) addedRows.push(row);
						row.initialize();
						if (!initialized) {
							rowHeight = row.getElement().offsetHeight;
							if (rowHeight > this.vDomWindowBuffer) this.vDomWindowBuffer = rowHeight * 2;
						}
						fillableSpace -= rowHeight;
						paddingAdjust += rowHeight;
						this.vDomTop--;
						index--;
						i++;
					} else working = false;
				} else working = false;
			} else working = false;
			for (let row of addedRows) row.clearCellHeight();
			this._quickNormalizeRowHeight(addedRows);
			if (paddingAdjust) {
				this.vDomTopPad -= paddingAdjust;
				if (this.vDomTopPad < 0) this.vDomTopPad = index * this.vDomRowHeight;
				if (index < 1) this.vDomTopPad = 0;
				table.style.paddingTop = this.vDomTopPad + "px";
				this.vDomScrollPosTop -= paddingAdjust;
			}
		}
		_removeTopRow(rows, fillableSpace) {
			var removableRows = [], paddingAdjust = 0, i = 0, working = true;
			while (working) {
				let row = rows[this.vDomTop], rowHeight;
				if (row && i < this.vDomMaxRenderChain) {
					rowHeight = row.getHeight() || this.vDomRowHeight;
					if (fillableSpace >= rowHeight) {
						this.vDomTop++;
						fillableSpace -= rowHeight;
						paddingAdjust += rowHeight;
						removableRows.push(row);
						i++;
					} else working = false;
				} else working = false;
			}
			for (let row of removableRows) {
				let rowEl = row.getElement();
				if (rowEl.parentNode) rowEl.parentNode.removeChild(rowEl);
			}
			if (paddingAdjust) {
				this.vDomTopPad += paddingAdjust;
				this.tableElement.style.paddingTop = this.vDomTopPad + "px";
				this.vDomScrollPosTop += this.vDomTop ? paddingAdjust : paddingAdjust + this.vDomWindowBuffer;
			}
		}
		_addBottomRow(rows, fillableSpace) {
			var table = this.tableElement, addedRows = [], paddingAdjust = 0, index = this.vDomBottom + 1, i = 0, working = true;
			while (working) {
				let row = rows[index], rowHeight, initialized;
				if (row && i < this.vDomMaxRenderChain) {
					rowHeight = row.getHeight() || this.vDomRowHeight;
					initialized = row.initialized;
					if (fillableSpace >= rowHeight) {
						this.styleRow(row, index);
						table.appendChild(row.getElement());
						if (!row.initialized || !row.heightInitialized) addedRows.push(row);
						row.initialize();
						if (!initialized) {
							rowHeight = row.getElement().offsetHeight;
							if (rowHeight > this.vDomWindowBuffer) this.vDomWindowBuffer = rowHeight * 2;
						}
						fillableSpace -= rowHeight;
						paddingAdjust += rowHeight;
						this.vDomBottom++;
						index++;
						i++;
					} else working = false;
				} else working = false;
			}
			for (let row of addedRows) row.clearCellHeight();
			this._quickNormalizeRowHeight(addedRows);
			if (paddingAdjust) {
				this.vDomBottomPad -= paddingAdjust;
				if (this.vDomBottomPad < 0 || index == rows.length - 1) this.vDomBottomPad = 0;
				table.style.paddingBottom = this.vDomBottomPad + "px";
				this.vDomScrollPosBottom += paddingAdjust;
			}
		}
		_removeBottomRow(rows, fillableSpace) {
			var removableRows = [], paddingAdjust = 0, i = 0, working = true;
			while (working) {
				let row = rows[this.vDomBottom], rowHeight;
				if (row && i < this.vDomMaxRenderChain) {
					rowHeight = row.getHeight() || this.vDomRowHeight;
					if (fillableSpace >= rowHeight) {
						this.vDomBottom--;
						fillableSpace -= rowHeight;
						paddingAdjust += rowHeight;
						removableRows.push(row);
						i++;
					} else working = false;
				} else working = false;
			}
			for (let row of removableRows) {
				let rowEl = row.getElement();
				if (rowEl.parentNode) rowEl.parentNode.removeChild(rowEl);
			}
			if (paddingAdjust) {
				this.vDomBottomPad += paddingAdjust;
				if (this.vDomBottomPad < 0) this.vDomBottomPad = 0;
				this.tableElement.style.paddingBottom = this.vDomBottomPad + "px";
				this.vDomScrollPosBottom -= paddingAdjust;
			}
		}
		_quickNormalizeRowHeight(rows) {
			for (let row of rows) row.calcHeight();
			for (let row of rows) row.setCellHeight();
		}
	};
	var RowManager = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.element = this.createHolderElement();
			this.tableElement = this.createTableElement();
			this.heightFixer = this.createTableElement();
			this.placeholder = null;
			this.placeholderContents = null;
			this.firstRender = false;
			this.renderMode = "virtual";
			this.fixedHeight = false;
			this.rows = [];
			this.activeRowsPipeline = [];
			this.activeRows = [];
			this.activeRowsCount = 0;
			this.displayRows = [];
			this.displayRowsCount = 0;
			this.scrollTop = 0;
			this.scrollLeft = 0;
			this.redrawBlock = false;
			this.redrawBlockRestoreConfig = false;
			this.redrawBlockRenderInPosition = false;
			this.dataPipeline = [];
			this.displayPipeline = [];
			this.scrollbarWidth = 0;
			this.renderer = null;
		}
		createHolderElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-tableholder");
			el.setAttribute("tabindex", 0);
			return el;
		}
		createTableElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-table");
			el.setAttribute("role", "rowgroup");
			return el;
		}
		initializePlaceholder() {
			var placeholder = this.table.options.placeholder;
			if (typeof placeholder === "function") placeholder = placeholder.call(this.table);
			placeholder = this.chain("placeholder", [placeholder], placeholder, placeholder) || placeholder;
			if (placeholder) {
				let el = document.createElement("div");
				el.classList.add("tabulator-placeholder");
				if (typeof placeholder == "string") {
					let contents = document.createElement("div");
					contents.classList.add("tabulator-placeholder-contents");
					contents.innerHTML = placeholder;
					el.appendChild(contents);
					this.placeholderContents = contents;
				} else if (typeof HTMLElement !== "undefined" && placeholder instanceof HTMLElement) {
					el.appendChild(placeholder);
					this.placeholderContents = placeholder;
				} else {
					console.warn("Invalid placeholder provided, must be string or HTML Element", placeholder);
					this.el = null;
				}
				this.placeholder = el;
			}
		}
		getElement() {
			return this.element;
		}
		getTableElement() {
			return this.tableElement;
		}
		initialize() {
			this.initializePlaceholder();
			this.initializeRenderer();
			this.element.appendChild(this.tableElement);
			this.firstRender = true;
			this.element.addEventListener("scroll", () => {
				var left = this.element.scrollLeft, leftDir = this.scrollLeft > left, top = this.element.scrollTop, topDir = this.scrollTop > top;
				if (this.scrollLeft != left) {
					this.scrollLeft = left;
					this.dispatch("scroll-horizontal", left, leftDir);
					this.dispatchExternal("scrollHorizontal", left, leftDir);
					this._positionPlaceholder();
				}
				if (this.scrollTop != top) {
					this.scrollTop = top;
					this.renderer.scrollRows(top, topDir);
					this.dispatch("scroll-vertical", top, topDir);
					this.dispatchExternal("scrollVertical", top, topDir);
				}
			});
		}
		findRow(subject) {
			if (typeof subject == "object") {
				if (subject instanceof Row$1) return subject;
				else if (subject instanceof RowComponent) return subject._getSelf() || false;
				else if (typeof HTMLElement !== "undefined" && subject instanceof HTMLElement) return this.rows.find((row) => {
					return row.getElement() === subject;
				}) || false;
				else if (subject === null) return false;
			} else if (typeof subject == "undefined") return false;
			else return this.rows.find((row) => {
				return row.data[this.table.options.index] == subject;
			}) || false;
			return false;
		}
		getRowFromDataObject(data) {
			return this.rows.find((row) => {
				return row.data === data;
			}) || false;
		}
		getRowFromPosition(position) {
			return this.getDisplayRows().find((row) => {
				return row.type === "row" && row.getPosition() === position && row.isDisplayed();
			});
		}
		scrollToRow(row, position, ifVisible) {
			return this.renderer.scrollToRowPosition(row, position, ifVisible);
		}
		setData(data, renderInPosition, columnsChanged) {
			return new Promise((resolve, reject) => {
				if (renderInPosition && this.getDisplayRows().length) if (this.table.options.pagination) this._setDataActual(data, true);
				else this.reRenderInPosition(() => {
					this._setDataActual(data);
				});
				else {
					if (this.table.options.autoColumns && columnsChanged && this.table.initialized) this.table.columnManager.generateColumnsFromRowData(data);
					this.resetScroll();
					this._setDataActual(data);
				}
				resolve();
			});
		}
		_setDataActual(data, renderInPosition) {
			this.dispatchExternal("dataProcessing", data);
			this._wipeElements();
			if (Array.isArray(data)) {
				this.dispatch("data-processing", data);
				data.forEach((def, i) => {
					if (def && typeof def === "object") {
						var row = new Row$1(def, this);
						this.rows.push(row);
					} else console.warn("Data Loading Warning - Invalid row data detected and ignored, expecting object but received:", def);
				});
				this.refreshActiveData(false, false, renderInPosition);
				this.dispatch("data-processed", data);
				this.dispatchExternal("dataProcessed", data);
			} else console.error("Data Loading Error - Unable to process data due to invalid data type \nExpecting: array \nReceived: ", typeof data, "\nData:     ", data);
		}
		_wipeElements() {
			this.dispatch("rows-wipe");
			this.destroy();
			this.adjustTableSize();
			this.dispatch("rows-wiped");
		}
		destroy() {
			this.rows.forEach((row) => {
				row.wipe();
			});
			this.rows = [];
			this.activeRows = [];
			this.activeRowsPipeline = [];
			this.activeRowsCount = 0;
			this.displayRows = [];
			this.displayRowsCount = 0;
		}
		deleteRow(row, blockRedraw) {
			var allIndex = this.rows.indexOf(row), activeIndex = this.activeRows.indexOf(row);
			if (activeIndex > -1) this.activeRows.splice(activeIndex, 1);
			if (allIndex > -1) this.rows.splice(allIndex, 1);
			this.setActiveRows(this.activeRows);
			this.displayRowIterator((rows) => {
				var displayIndex = rows.indexOf(row);
				if (displayIndex > -1) rows.splice(displayIndex, 1);
			});
			if (!blockRedraw) this.reRenderInPosition();
			this.regenerateRowPositions();
			this.dispatchExternal("rowDeleted", row.getComponent());
			if (!this.displayRowsCount) this.tableEmpty();
			if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.getData());
		}
		addRow(data, pos, index, blockRedraw) {
			return this.addRowActual(data, pos, index, blockRedraw);
		}
		addRows(data, pos, index, refreshDisplayOnly) {
			var rows = [];
			return new Promise((resolve, reject) => {
				pos = this.findAddRowPos(pos);
				if (!Array.isArray(data)) data = [data];
				if (typeof index == "undefined" && pos || typeof index !== "undefined" && !pos) data.reverse();
				data.forEach((item, i) => {
					var row = this.addRow(item, pos, index, true);
					rows.push(row);
					this.dispatch("row-added", row, item, pos, index);
				});
				this.refreshActiveData(refreshDisplayOnly ? "displayPipeline" : false, false, true);
				this.regenerateRowPositions();
				if (this.displayRowsCount) this._clearPlaceholder();
				resolve(rows);
			});
		}
		findAddRowPos(pos) {
			if (typeof pos === "undefined") pos = this.table.options.addRowPos;
			if (pos === "pos") pos = true;
			if (pos === "bottom") pos = false;
			return pos;
		}
		addRowActual(data, pos, index, blockRedraw) {
			var row = data instanceof Row$1 ? data : new Row$1(data || {}, this), top = this.findAddRowPos(pos), allIndex = -1, activeIndex, chainResult;
			if (!index) {
				chainResult = this.chain("row-adding-position", [row, top], null, {
					index,
					top
				});
				index = chainResult.index;
				top = chainResult.top;
			}
			if (typeof index !== "undefined") index = this.findRow(index);
			index = this.chain("row-adding-index", [
				row,
				index,
				top
			], null, index);
			if (index) allIndex = this.rows.indexOf(index);
			if (index && allIndex > -1) {
				activeIndex = this.activeRows.indexOf(index);
				this.displayRowIterator(function(rows) {
					var displayIndex = rows.indexOf(index);
					if (displayIndex > -1) rows.splice(top ? displayIndex : displayIndex + 1, 0, row);
				});
				if (activeIndex > -1) this.activeRows.splice(top ? activeIndex : activeIndex + 1, 0, row);
				this.rows.splice(top ? allIndex : allIndex + 1, 0, row);
			} else if (top) {
				this.displayRowIterator(function(rows) {
					rows.unshift(row);
				});
				this.activeRows.unshift(row);
				this.rows.unshift(row);
			} else {
				this.displayRowIterator(function(rows) {
					rows.push(row);
				});
				this.activeRows.push(row);
				this.rows.push(row);
			}
			this.setActiveRows(this.activeRows);
			this.dispatchExternal("rowAdded", row.getComponent());
			if (this.subscribedExternal("dataChanged")) this.dispatchExternal("dataChanged", this.table.rowManager.getData());
			if (!blockRedraw) this.reRenderInPosition();
			return row;
		}
		moveRow(from, to, after) {
			this.dispatch("row-move", from, to, after);
			this.moveRowActual(from, to, after);
			this.regenerateRowPositions();
			this.dispatch("row-moved", from, to, after);
			this.dispatchExternal("rowMoved", from.getComponent());
		}
		moveRowActual(from, to, after) {
			this.moveRowInArray(this.rows, from, to, after);
			this.moveRowInArray(this.activeRows, from, to, after);
			this.displayRowIterator((rows) => {
				this.moveRowInArray(rows, from, to, after);
			});
			this.dispatch("row-moving", from, to, after);
		}
		moveRowInArray(rows, from, to, after) {
			var fromIndex, toIndex, start, end;
			if (from !== to) {
				fromIndex = rows.indexOf(from);
				if (fromIndex > -1) {
					rows.splice(fromIndex, 1);
					toIndex = rows.indexOf(to);
					if (toIndex > -1) if (after) rows.splice(toIndex + 1, 0, from);
					else rows.splice(toIndex, 0, from);
					else rows.splice(fromIndex, 0, from);
				}
				if (rows === this.getDisplayRows()) {
					start = fromIndex < toIndex ? fromIndex : toIndex;
					end = toIndex > fromIndex ? toIndex : fromIndex + 1;
					for (let i = start; i <= end; i++) if (rows[i]) this.styleRow(rows[i], i);
				}
			}
		}
		clearData() {
			this.setData([]);
		}
		getRowIndex(row) {
			return this.findRowIndex(row, this.rows);
		}
		getDisplayRowIndex(row) {
			var index = this.getDisplayRows().indexOf(row);
			return index > -1 ? index : false;
		}
		nextDisplayRow(row, rowOnly) {
			var index = this.getDisplayRowIndex(row), nextRow = false;
			if (index !== false && index < this.displayRowsCount - 1) nextRow = this.getDisplayRows()[index + 1];
			if (nextRow && (!(nextRow instanceof Row$1) || nextRow.type != "row")) return this.nextDisplayRow(nextRow, rowOnly);
			return nextRow;
		}
		prevDisplayRow(row, rowOnly) {
			var index = this.getDisplayRowIndex(row), prevRow = false;
			if (index) prevRow = this.getDisplayRows()[index - 1];
			if (rowOnly && prevRow && (!(prevRow instanceof Row$1) || prevRow.type != "row")) return this.prevDisplayRow(prevRow, rowOnly);
			return prevRow;
		}
		findRowIndex(row, list) {
			var rowIndex;
			row = this.findRow(row);
			if (row) {
				rowIndex = list.indexOf(row);
				if (rowIndex > -1) return rowIndex;
			}
			return false;
		}
		getData(active, transform) {
			var output = [];
			this.getRows(active).forEach(function(row) {
				if (row.type == "row") output.push(row.getData(transform || "data"));
			});
			return output;
		}
		getComponents(active) {
			var output = [];
			this.getRows(active).forEach(function(row) {
				output.push(row.getComponent());
			});
			return output;
		}
		getDataCount(active) {
			return this.getRows(active).length;
		}
		scrollHorizontal(left) {
			this.scrollLeft = left;
			this.element.scrollLeft = left;
			this.dispatch("scroll-horizontal", left);
		}
		registerDataPipelineHandler(handler, priority) {
			if (typeof priority !== "undefined") {
				this.dataPipeline.push({
					handler,
					priority
				});
				this.dataPipeline.sort((a, b) => {
					return a.priority - b.priority;
				});
			} else console.error("Data pipeline handlers must have a priority in order to be registered");
		}
		registerDisplayPipelineHandler(handler, priority) {
			if (typeof priority !== "undefined") {
				this.displayPipeline.push({
					handler,
					priority
				});
				this.displayPipeline.sort((a, b) => {
					return a.priority - b.priority;
				});
			} else console.error("Display pipeline handlers must have a priority in order to be registered");
		}
		refreshActiveData(handler, skipStage, renderInPosition) {
			var table = this.table, stage = "", index = 0, cascadeOrder = [
				"all",
				"dataPipeline",
				"display",
				"displayPipeline",
				"end"
			];
			if (!this.table.destroyed) {
				if (typeof handler === "function") {
					index = this.dataPipeline.findIndex((item) => {
						return item.handler === handler;
					});
					if (index > -1) {
						stage = "dataPipeline";
						if (skipStage) if (index == this.dataPipeline.length - 1) stage = "display";
						else index++;
					} else {
						index = this.displayPipeline.findIndex((item) => {
							return item.handler === handler;
						});
						if (index > -1) {
							stage = "displayPipeline";
							if (skipStage) if (index == this.displayPipeline.length - 1) stage = "end";
							else index++;
						} else {
							console.error("Unable to refresh data, invalid handler provided", handler);
							return;
						}
					}
				} else {
					stage = handler || "all";
					index = 0;
				}
				if (this.redrawBlock) {
					if (!this.redrawBlockRestoreConfig || this.redrawBlockRestoreConfig && (this.redrawBlockRestoreConfig.stage === stage && index < this.redrawBlockRestoreConfig.index || cascadeOrder.indexOf(stage) < cascadeOrder.indexOf(this.redrawBlockRestoreConfig.stage))) this.redrawBlockRestoreConfig = {
						handler,
						skipStage,
						renderInPosition,
						stage,
						index
					};
					return;
				} else {
					if (Helpers.elVisible(this.element)) if (renderInPosition) this.reRenderInPosition(this.refreshPipelines.bind(this, handler, stage, index, renderInPosition));
					else {
						this.refreshPipelines(handler, stage, index, renderInPosition);
						if (!handler) this.table.columnManager.renderer.renderColumns();
						this.renderTable();
						if (table.options.layoutColumnsOnNewData) this.table.columnManager.redraw(true);
					}
					else this.refreshPipelines(handler, stage, index, renderInPosition);
					this.dispatch("data-refreshed");
				}
			}
		}
		refreshPipelines(handler, stage, index, renderInPosition) {
			this.dispatch("data-refreshing");
			if (!handler || !this.activeRowsPipeline[0]) this.activeRowsPipeline[0] = this.rows.slice(0);
			switch (stage) {
				case "all":
				case "dataPipeline":
					for (let i = index; i < this.dataPipeline.length; i++) {
						let result = this.dataPipeline[i].handler(this.activeRowsPipeline[i].slice(0));
						this.activeRowsPipeline[i + 1] = result || this.activeRowsPipeline[i].slice(0);
					}
					this.setActiveRows(this.activeRowsPipeline[this.dataPipeline.length]);
				case "display":
					index = 0;
					this.resetDisplayRows();
				case "displayPipeline": for (let i = index; i < this.displayPipeline.length; i++) {
					let result = this.displayPipeline[i].handler((i ? this.getDisplayRows(i - 1) : this.activeRows).slice(0), renderInPosition);
					this.setDisplayRows(result || this.getDisplayRows(i - 1).slice(0), i);
				}
				case "end": this.regenerateRowPositions();
			}
			if (this.getDisplayRows().length) this._clearPlaceholder();
		}
		regenerateRowPositions() {
			var rows = this.getDisplayRows();
			var index = 1;
			rows.forEach((row) => {
				if (row.type === "row") {
					row.setPosition(index);
					index++;
				}
			});
		}
		setActiveRows(activeRows) {
			this.activeRows = this.activeRows = Object.assign([], activeRows);
			this.activeRowsCount = this.activeRows.length;
		}
		resetDisplayRows() {
			this.displayRows = [];
			this.displayRows.push(this.activeRows.slice(0));
			this.displayRowsCount = this.displayRows[0].length;
		}
		setDisplayRows(displayRows, index) {
			this.displayRows[index] = displayRows;
			if (index == this.displayRows.length - 1) this.displayRowsCount = this.displayRows[this.displayRows.length - 1].length;
		}
		getDisplayRows(index) {
			if (typeof index == "undefined") return this.displayRows.length ? this.displayRows[this.displayRows.length - 1] : [];
			else return this.displayRows[index] || [];
		}
		getVisibleRows(chain, viewable) {
			var rows = Object.assign([], this.renderer.visibleRows(!viewable));
			if (chain) rows = this.chain("rows-visible", [viewable], rows, rows);
			return rows;
		}
		displayRowIterator(callback) {
			this.activeRowsPipeline.forEach(callback);
			this.displayRows.forEach(callback);
			this.displayRowsCount = this.displayRows[this.displayRows.length - 1].length;
		}
		getRows(type) {
			var rows = [];
			switch (type) {
				case "active":
					rows = this.activeRows;
					break;
				case "display":
					rows = this.table.rowManager.getDisplayRows();
					break;
				case "visible":
					rows = this.getVisibleRows(false, true);
					break;
				default: rows = this.chain("rows-retrieve", type, null, this.rows) || this.rows;
			}
			return rows;
		}
		reRenderInPosition(callback) {
			if (this.redrawBlock) if (callback) callback();
			else this.redrawBlockRenderInPosition = true;
			else {
				this.dispatchExternal("renderStarted");
				this.renderer.rerenderRows(callback);
				if (!this.fixedHeight) this.adjustTableSize();
				this.scrollBarCheck();
				this.dispatchExternal("renderComplete");
			}
		}
		scrollBarCheck() {
			var scrollbarWidth = 0;
			if (this.element.scrollHeight > this.element.clientHeight) scrollbarWidth = this.element.offsetWidth - this.element.clientWidth;
			if (scrollbarWidth !== this.scrollbarWidth) {
				this.scrollbarWidth = scrollbarWidth;
				this.dispatch("scrollbar-vertical", scrollbarWidth);
			}
		}
		initializeRenderer() {
			var renderClass;
			var renderers = {
				"virtual": VirtualDomVertical,
				"basic": BasicVertical
			};
			if (typeof this.table.options.renderVertical === "string") renderClass = renderers[this.table.options.renderVertical];
			else renderClass = this.table.options.renderVertical;
			if (renderClass) {
				this.renderMode = this.table.options.renderVertical;
				this.renderer = new renderClass(this.table, this.element, this.tableElement);
				this.renderer.initialize();
				if ((this.table.element.clientHeight || this.table.options.height) && !(this.table.options.minHeight && this.table.options.maxHeight)) this.fixedHeight = true;
				else this.fixedHeight = false;
			} else console.error("Unable to find matching renderer:", this.table.options.renderVertical);
		}
		getRenderMode() {
			return this.renderMode;
		}
		renderTable() {
			this.dispatchExternal("renderStarted");
			this.element.scrollTop = 0;
			this._clearTable();
			if (this.displayRowsCount) {
				this.renderer.renderRows();
				if (this.firstRender) {
					this.firstRender = false;
					if (!this.fixedHeight) this.adjustTableSize();
					this.layoutRefresh(true);
				}
			} else this.renderEmptyScroll();
			if (!this.fixedHeight) this.adjustTableSize();
			this.dispatch("table-layout");
			if (!this.displayRowsCount) this._showPlaceholder();
			this.scrollBarCheck();
			this.dispatchExternal("renderComplete");
		}
		renderEmptyScroll() {
			if (this.placeholder) this.tableElement.style.display = "none";
			else this.tableElement.style.minWidth = this.table.columnManager.getWidth() + "px";
		}
		_clearTable() {
			this._clearPlaceholder();
			this.scrollTop = 0;
			this.scrollLeft = 0;
			this.renderer.clearRows();
		}
		tableEmpty() {
			this.renderEmptyScroll();
			this._showPlaceholder();
		}
		checkPlaceholder() {
			if (this.displayRowsCount) this._clearPlaceholder();
			else this.tableEmpty();
		}
		_showPlaceholder() {
			if (this.placeholder) {
				if (this.placeholder && this.placeholder.parentNode) this.placeholder.parentNode.removeChild(this.placeholder);
				this.initializePlaceholder();
				this.placeholder.setAttribute("tabulator-render-mode", this.renderMode);
				this.getElement().appendChild(this.placeholder);
				this._positionPlaceholder();
				this.adjustTableSize();
			}
		}
		_clearPlaceholder() {
			if (this.placeholder && this.placeholder.parentNode) this.placeholder.parentNode.removeChild(this.placeholder);
			this.tableElement.style.minWidth = "";
			this.tableElement.style.display = "";
		}
		_positionPlaceholder() {
			if (this.placeholder && this.placeholder.parentNode) {
				this.placeholder.style.width = this.table.columnManager.getWidth() + "px";
				this.placeholderContents.style.width = this.table.rowManager.element.clientWidth + "px";
				this.placeholderContents.style.marginLeft = this.scrollLeft + "px";
			}
		}
		styleRow(row, index) {
			var rowEl = row.getElement();
			if (index % 2) {
				rowEl.classList.add("tabulator-row-even");
				rowEl.classList.remove("tabulator-row-odd");
			} else {
				rowEl.classList.add("tabulator-row-odd");
				rowEl.classList.remove("tabulator-row-even");
			}
		}
		normalizeHeight(force) {
			this.activeRows.forEach(function(row) {
				row.normalizeHeight(force);
			});
		}
		adjustTableSize() {
			let initialHeight = this.element.clientHeight, minHeight;
			let resized = false;
			if (this.renderer.verticalFillMode === "fill") {
				let otherHeight = Math.floor(this.table.columnManager.getElement().getBoundingClientRect().height + (this.table.footerManager && this.table.footerManager.active && !this.table.footerManager.external ? this.table.footerManager.getElement().getBoundingClientRect().height : 0));
				if (this.fixedHeight) {
					minHeight = isNaN(this.table.options.minHeight) ? this.table.options.minHeight : this.table.options.minHeight + "px";
					const height = "calc(100% - " + otherHeight + "px)";
					this.element.style.minHeight = minHeight || "calc(100% - " + otherHeight + "px)";
					this.element.style.height = height;
					this.element.style.maxHeight = height;
				} else {
					this.element.style.height = "";
					this.element.style.height = this.table.element.clientHeight - otherHeight + "px";
					this.element.scrollTop = this.scrollTop;
				}
				this.renderer.resize();
				if (!this.fixedHeight && initialHeight != this.element.clientHeight) {
					resized = true;
					if (this.subscribed("table-resize")) this.dispatch("table-resize");
					else this.redraw();
				}
				this.scrollBarCheck();
			}
			this._positionPlaceholder();
			return resized;
		}
		reinitialize() {
			this.rows.forEach(function(row) {
				row.reinitialize(true);
			});
		}
		blockRedraw() {
			this.redrawBlock = true;
			this.redrawBlockRestoreConfig = false;
		}
		restoreRedraw() {
			this.redrawBlock = false;
			if (this.redrawBlockRestoreConfig) {
				this.refreshActiveData(this.redrawBlockRestoreConfig.handler, this.redrawBlockRestoreConfig.skipStage, this.redrawBlockRestoreConfig.renderInPosition);
				this.redrawBlockRestoreConfig = false;
			} else if (this.redrawBlockRenderInPosition) this.reRenderInPosition();
			this.redrawBlockRenderInPosition = false;
		}
		redraw(force) {
			this.adjustTableSize();
			this.table.tableWidth = this.table.element.clientWidth;
			if (!force) {
				this.reRenderInPosition();
				this.scrollHorizontal(this.scrollLeft);
			} else this.renderTable();
		}
		resetScroll() {
			this.element.scrollLeft = 0;
			this.element.scrollTop = 0;
			if (this.table.browser === "ie") {
				var event = document.createEvent("Event");
				event.initEvent("scroll", false, true);
				this.element.dispatchEvent(event);
			} else this.element.dispatchEvent(new Event("scroll"));
		}
	};
	var FooterManager = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.active = false;
			this.element = this.createElement();
			this.containerElement = this.createContainerElement();
			this.external = false;
		}
		initialize() {
			this.initializeElement();
		}
		createElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-footer");
			return el;
		}
		createContainerElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-footer-contents");
			this.element.appendChild(el);
			return el;
		}
		initializeElement() {
			if (this.table.options.footerElement) switch (typeof this.table.options.footerElement) {
				case "string":
					if (this.table.options.footerElement[0] === "<") this.containerElement.innerHTML = this.table.options.footerElement;
					else {
						this.external = true;
						this.containerElement = document.querySelector(this.table.options.footerElement);
					}
					break;
				default:
					this.element = this.table.options.footerElement;
					break;
			}
		}
		getElement() {
			return this.element;
		}
		append(element) {
			this.activate();
			this.containerElement.appendChild(element);
			this.table.rowManager.adjustTableSize();
		}
		prepend(element) {
			this.activate();
			this.element.insertBefore(element, this.element.firstChild);
			this.table.rowManager.adjustTableSize();
		}
		remove(element) {
			element.parentNode.removeChild(element);
			this.deactivate();
		}
		deactivate(force) {
			if (!this.element.firstChild || force) {
				if (!this.external) this.element.parentNode.removeChild(this.element);
				this.active = false;
			}
		}
		activate() {
			if (!this.active) {
				this.active = true;
				if (!this.external) {
					this.table.element.appendChild(this.getElement());
					this.table.element.style.display = "";
				}
			}
		}
		redraw() {
			this.dispatch("footer-redraw");
		}
	};
	var InteractionManager = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.el = null;
			this.abortClasses = ["tabulator-headers", "tabulator-table"];
			this.previousTargets = {};
			this.listeners = [
				"click",
				"dblclick",
				"contextmenu",
				"mouseenter",
				"mouseleave",
				"mouseover",
				"mouseout",
				"mousemove",
				"mouseup",
				"mousedown",
				"touchstart",
				"touchend"
			];
			this.componentMap = {
				"tabulator-cell": "cell",
				"tabulator-row": "row",
				"tabulator-group": "group",
				"tabulator-col": "column"
			};
			this.pseudoTrackers = {
				"row": {
					subscriber: null,
					target: null
				},
				"cell": {
					subscriber: null,
					target: null
				},
				"group": {
					subscriber: null,
					target: null
				},
				"column": {
					subscriber: null,
					target: null
				}
			};
			this.pseudoTracking = false;
		}
		initialize() {
			this.el = this.table.element;
			this.buildListenerMap();
			this.bindSubscriptionWatchers();
		}
		buildListenerMap() {
			var listenerMap = {};
			this.listeners.forEach((listener) => {
				listenerMap[listener] = {
					handler: null,
					components: []
				};
			});
			this.listeners = listenerMap;
		}
		bindPseudoEvents() {
			Object.keys(this.pseudoTrackers).forEach((key) => {
				this.pseudoTrackers[key].subscriber = this.pseudoMouseEnter.bind(this, key);
				this.subscribe(key + "-mouseover", this.pseudoTrackers[key].subscriber);
			});
			this.pseudoTracking = true;
		}
		pseudoMouseEnter(key, e, target) {
			if (this.pseudoTrackers[key].target !== target) {
				if (this.pseudoTrackers[key].target) this.dispatch(key + "-mouseleave", e, this.pseudoTrackers[key].target);
				this.pseudoMouseLeave(key, e);
				this.pseudoTrackers[key].target = target;
				this.dispatch(key + "-mouseenter", e, target);
			}
		}
		pseudoMouseLeave(key, e) {
			var leaveList = Object.keys(this.pseudoTrackers), linkedKeys = {
				"row": ["cell"],
				"cell": ["row"]
			};
			leaveList = leaveList.filter((item) => {
				var links = linkedKeys[key];
				return item !== key && (!links || links && !links.includes(item));
			});
			leaveList.forEach((key) => {
				var target = this.pseudoTrackers[key].target;
				if (this.pseudoTrackers[key].target) {
					this.dispatch(key + "-mouseleave", e, target);
					this.pseudoTrackers[key].target = null;
				}
			});
		}
		bindSubscriptionWatchers() {
			var listeners = Object.keys(this.listeners), components = Object.values(this.componentMap);
			for (let comp of components) for (let listener of listeners) {
				let key = comp + "-" + listener;
				this.subscriptionChange(key, this.subscriptionChanged.bind(this, comp, listener));
			}
			this.subscribe("table-destroy", this.clearWatchers.bind(this));
		}
		subscriptionChanged(component, key, added) {
			var listener = this.listeners[key].components, index = listener.indexOf(component), changed = false;
			if (added) {
				if (index === -1) {
					listener.push(component);
					changed = true;
				}
			} else if (!this.subscribed(component + "-" + key)) {
				if (index > -1) {
					listener.splice(index, 1);
					changed = true;
				}
			}
			if ((key === "mouseenter" || key === "mouseleave") && !this.pseudoTracking) this.bindPseudoEvents();
			if (changed) this.updateEventListeners();
		}
		updateEventListeners() {
			for (let key in this.listeners) {
				let listener = this.listeners[key];
				if (listener.components.length) {
					if (!listener.handler) {
						listener.handler = this.track.bind(this, key);
						this.el.addEventListener(key, listener.handler);
					}
				} else if (listener.handler) {
					this.el.removeEventListener(key, listener.handler);
					listener.handler = null;
				}
			}
		}
		track(type, e) {
			var path = e.composedPath && e.composedPath() || e.path;
			var targets = this.findTargets(path);
			targets = this.bindComponents(type, targets);
			this.triggerEvents(type, e, targets);
			if (this.pseudoTracking && (type == "mouseover" || type == "mouseleave") && !Object.keys(targets).length) this.pseudoMouseLeave("none", e);
		}
		findTargets(path) {
			var targets = {};
			let componentMap = Object.keys(this.componentMap);
			for (let el of path) {
				let classList = el.classList ? [...el.classList] : [];
				if (classList.filter((item) => {
					return this.abortClasses.includes(item);
				}).length) break;
				let elTargets = classList.filter((item) => {
					return componentMap.includes(item);
				});
				for (let target of elTargets) if (!targets[this.componentMap[target]]) targets[this.componentMap[target]] = el;
			}
			if (targets.group && targets.group === targets.row) delete targets.row;
			return targets;
		}
		bindComponents(type, targets) {
			var keys = Object.keys(targets).reverse(), listener = this.listeners[type], matches = {}, output = {}, targetMatches = {};
			for (let key of keys) {
				let component, target = targets[key], previousTarget = this.previousTargets[key];
				if (previousTarget && previousTarget.target === target) component = previousTarget.component;
				else switch (key) {
					case "row":
					case "group":
						if (listener.components.includes("row") || listener.components.includes("cell") || listener.components.includes("group")) {
							component = this.table.rowManager.getVisibleRows(true).find((row) => {
								return row.getElement() === target;
							});
							if (targets["row"] && targets["row"].parentNode && targets["row"].parentNode.closest(".tabulator-row")) targets[key] = false;
						}
						break;
					case "column":
						if (listener.components.includes("column")) component = this.table.columnManager.findColumn(target);
						break;
					case "cell":
						if (listener.components.includes("cell")) {
							if (matches["row"] instanceof Row$1) component = matches["row"].findCell(target);
							else if (targets["row"]) console.warn("Event Target Lookup Error - The row this cell is attached to cannot be found, has the table been reinitialized without being destroyed first?");
						}
						break;
				}
				if (component) {
					matches[key] = component;
					targetMatches[key] = {
						target,
						component
					};
				}
			}
			this.previousTargets = targetMatches;
			Object.keys(targets).forEach((key) => {
				output[key] = matches[key];
			});
			return output;
		}
		triggerEvents(type, e, targets) {
			var listener = this.listeners[type];
			for (let key in targets) if (targets[key] && listener.components.includes(key)) this.dispatch(key + "-" + type, e, targets[key]);
		}
		clearWatchers() {
			for (let key in this.listeners) {
				let listener = this.listeners[key];
				if (listener.handler) {
					this.el.removeEventListener(key, listener.handler);
					listener.handler = null;
				}
			}
		}
	};
	var ComponentFunctionBinder = class {
		constructor(table) {
			this.table = table;
			this.bindings = {};
		}
		bind(type, funcName, handler) {
			if (!this.bindings[type]) this.bindings[type] = {};
			if (this.bindings[type][funcName]) console.warn("Unable to bind component handler, a matching function name is already bound", type, funcName, handler);
			else this.bindings[type][funcName] = handler;
		}
		handle(type, component, name) {
			if (this.bindings[type] && this.bindings[type][name] && typeof this.bindings[type][name].bind === "function") return this.bindings[type][name].bind(null, component);
			else if (name !== "then" && typeof name === "string" && !name.startsWith("_")) {
				if (this.table.options.debugInvalidComponentFuncs) console.error("The " + type + " component does not have a " + name + " function, have you checked that you have the correct Tabulator module installed?");
			}
		}
	};
	var DataLoader = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.requestOrder = 0;
			this.loading = false;
		}
		initialize() {}
		load(data, params, config, replace, silent, columnsChanged) {
			var requestNo = ++this.requestOrder;
			if (this.table.destroyed) return Promise.resolve();
			this.dispatchExternal("dataLoading", data);
			if (data && (data.indexOf("{") == 0 || data.indexOf("[") == 0)) data = JSON.parse(data);
			if (this.confirm("data-loading", [
				data,
				params,
				config,
				silent
			])) {
				this.loading = true;
				if (!silent) this.alertLoader();
				params = this.chain("data-params", [
					data,
					config,
					silent
				], params || {}, params || {});
				params = this.mapParams(params, this.table.options.dataSendParams);
				return this.chain("data-load", [
					data,
					params,
					config,
					silent
				], false, Promise.resolve([])).then((response) => {
					if (!this.table.destroyed) {
						if (!Array.isArray(response) && typeof response == "object") response = this.mapParams(response, this.objectInvert(this.table.options.dataReceiveParams));
						var rowData = this.chain("data-loaded", [response], null, response);
						if (requestNo == this.requestOrder) {
							this.clearAlert();
							if (rowData !== false) {
								this.dispatchExternal("dataLoaded", rowData);
								this.table.rowManager.setData(rowData, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
							}
						} else console.warn("Data Load Response Blocked - An active data load request was blocked by an attempt to change table data while the request was being made");
					} else console.warn("Data Load Response Blocked - Table has been destroyed");
				}).catch((error) => {
					console.error("Data Load Error: ", error);
					this.dispatchExternal("dataLoadError", error);
					if (!silent) this.alertError();
					setTimeout(() => {
						this.clearAlert();
					}, this.table.options.dataLoaderErrorTimeout);
				}).finally(() => {
					this.loading = false;
				});
			} else {
				this.dispatchExternal("dataLoaded", data);
				if (!data) data = [];
				this.table.rowManager.setData(data, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
				return Promise.resolve();
			}
		}
		mapParams(params, map) {
			var output = {};
			for (let key in params) output[map.hasOwnProperty(key) ? map[key] : key] = params[key];
			return output;
		}
		objectInvert(obj) {
			var output = {};
			for (let key in obj) output[obj[key]] = key;
			return output;
		}
		blockActiveLoad() {
			this.requestOrder++;
		}
		alertLoader() {
			if (typeof this.table.options.dataLoader === "function" ? this.table.options.dataLoader() : this.table.options.dataLoader) this.table.alertManager.alert(this.table.options.dataLoaderLoading || this.langText("data|loading"));
		}
		alertError() {
			this.table.alertManager.alert(this.table.options.dataLoaderError || this.langText("data|error"), "error");
		}
		clearAlert() {
			this.table.alertManager.clear();
		}
	};
	var ExternalEventBus = class {
		constructor(table, optionsList, debug) {
			this.table = table;
			this.events = {};
			this.optionsList = optionsList || {};
			this.subscriptionNotifiers = {};
			this.dispatch = debug ? this._debugDispatch.bind(this) : this._dispatch.bind(this);
			this.debug = debug;
		}
		subscriptionChange(key, callback) {
			if (!this.subscriptionNotifiers[key]) this.subscriptionNotifiers[key] = [];
			this.subscriptionNotifiers[key].push(callback);
			if (this.subscribed(key)) this._notifySubscriptionChange(key, true);
		}
		subscribe(key, callback) {
			if (!this.events[key]) this.events[key] = [];
			this.events[key].push(callback);
			this._notifySubscriptionChange(key, true);
		}
		unsubscribe(key, callback) {
			var index;
			if (this.events[key]) if (callback) {
				index = this.events[key].findIndex((item) => {
					return item === callback;
				});
				if (index > -1) this.events[key].splice(index, 1);
				else {
					console.warn("Cannot remove event, no matching event found:", key, callback);
					return;
				}
			} else delete this.events[key];
			else {
				console.warn("Cannot remove event, no events set on:", key);
				return;
			}
			this._notifySubscriptionChange(key, false);
		}
		subscribed(key) {
			return this.events[key] && this.events[key].length;
		}
		_notifySubscriptionChange(key, subscribed) {
			var notifiers = this.subscriptionNotifiers[key];
			if (notifiers) notifiers.forEach((callback) => {
				callback(subscribed);
			});
		}
		_dispatch() {
			var args = Array.from(arguments), key = args.shift(), result;
			if (this.events[key]) this.events[key].forEach((callback, i) => {
				let callResult = callback.apply(this.table, args);
				if (!i) result = callResult;
			});
			return result;
		}
		_debugDispatch() {
			var args = Array.from(arguments), key = args[0];
			args[0] = "ExternalEvent:" + args[0];
			if (this.debug === true || this.debug.includes(key)) console.log(...args);
			return this._dispatch(...arguments);
		}
	};
	var InternalEventBus = class {
		constructor(debug) {
			this.events = {};
			this.subscriptionNotifiers = {};
			this.dispatch = debug ? this._debugDispatch.bind(this) : this._dispatch.bind(this);
			this.chain = debug ? this._debugChain.bind(this) : this._chain.bind(this);
			this.confirm = debug ? this._debugConfirm.bind(this) : this._confirm.bind(this);
			this.debug = debug;
		}
		subscriptionChange(key, callback) {
			if (!this.subscriptionNotifiers[key]) this.subscriptionNotifiers[key] = [];
			this.subscriptionNotifiers[key].push(callback);
			if (this.subscribed(key)) this._notifySubscriptionChange(key, true);
		}
		subscribe(key, callback, priority = 1e4) {
			if (!this.events[key]) this.events[key] = [];
			this.events[key].push({
				callback,
				priority
			});
			this.events[key].sort((a, b) => {
				return a.priority - b.priority;
			});
			this._notifySubscriptionChange(key, true);
		}
		unsubscribe(key, callback) {
			var index;
			if (this.events[key]) {
				if (callback) {
					index = this.events[key].findIndex((item) => {
						return item.callback === callback;
					});
					if (index > -1) this.events[key].splice(index, 1);
					else {
						console.warn("Cannot remove event, no matching event found:", key, callback);
						return;
					}
				}
			} else {
				console.warn("Cannot remove event, no events set on:", key);
				return;
			}
			this._notifySubscriptionChange(key, false);
		}
		subscribed(key) {
			return this.events[key] && this.events[key].length;
		}
		_chain(key, args, initialValue, fallback) {
			var value = initialValue;
			if (!Array.isArray(args)) args = [args];
			if (this.subscribed(key)) {
				this.events[key].forEach((subscriber, i) => {
					value = subscriber.callback.apply(this, args.concat([value]));
				});
				return value;
			} else return typeof fallback === "function" ? fallback() : fallback;
		}
		_confirm(key, args) {
			var confirmed = false;
			if (!Array.isArray(args)) args = [args];
			if (this.subscribed(key)) this.events[key].forEach((subscriber, i) => {
				if (subscriber.callback.apply(this, args)) confirmed = true;
			});
			return confirmed;
		}
		_notifySubscriptionChange(key, subscribed) {
			var notifiers = this.subscriptionNotifiers[key];
			if (notifiers) notifiers.forEach((callback) => {
				callback(subscribed);
			});
		}
		_dispatch() {
			var args = Array.from(arguments), key = args.shift();
			if (this.events[key]) this.events[key].forEach((subscriber) => {
				subscriber.callback.apply(this, args);
			});
		}
		_debugDispatch() {
			var args = Array.from(arguments), key = args[0];
			args[0] = "InternalEvent:" + key;
			if (this.debug === true || this.debug.includes(key)) console.log(...args);
			return this._dispatch(...arguments);
		}
		_debugChain() {
			var args = Array.from(arguments), key = args[0];
			args[0] = "InternalEvent:" + key;
			if (this.debug === true || this.debug.includes(key)) console.log(...args);
			return this._chain(...arguments);
		}
		_debugConfirm() {
			var args = Array.from(arguments), key = args[0];
			args[0] = "InternalEvent:" + key;
			if (this.debug === true || this.debug.includes(key)) console.log(...args);
			return this._confirm(...arguments);
		}
	};
	var DeprecationAdvisor = class extends CoreFeature {
		constructor(table) {
			super(table);
		}
		_warnUser() {
			if (this.options("debugDeprecation")) console.warn(...arguments);
		}
		check(oldOption, newOption, convert) {
			var msg = "";
			if (typeof this.options(oldOption) !== "undefined") {
				msg = "Deprecated Setup Option - Use of the %c" + oldOption + "%c option is now deprecated";
				if (newOption) {
					msg = msg + ", Please use the %c" + newOption + "%c option instead";
					this._warnUser(msg, "font-weight: bold;", "font-weight: normal;", "font-weight: bold;", "font-weight: normal;");
					if (convert) this.table.options[newOption] = this.table.options[oldOption];
				} else this._warnUser(msg, "font-weight: bold;", "font-weight: normal;");
				return false;
			} else return true;
		}
		checkMsg(oldOption, msg) {
			if (typeof this.options(oldOption) !== "undefined") {
				this._warnUser("%cDeprecated Setup Option - Use of the %c" + oldOption + " %c option is now deprecated, " + msg, "font-weight: normal;", "font-weight: bold;", "font-weight: normal;");
				return false;
			} else return true;
		}
		msg(msg) {
			this._warnUser(msg);
		}
	};
	var DependencyRegistry = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.deps = {};
			this.props = {};
		}
		initialize() {
			this.deps = Object.assign({}, this.options("dependencies"));
		}
		lookup(key, prop, silent) {
			if (Array.isArray(key)) {
				for (const item of key) {
					var match = this.lookup(item, prop, true);
					if (match) break;
				}
				if (match) return match;
				else this.error(key);
			} else if (prop) return this.lookupProp(key, prop, silent);
			else return this.lookupKey(key, silent);
		}
		lookupProp(key, prop, silent) {
			var dependency;
			if (this.props[key] && this.props[key][prop]) return this.props[key][prop];
			else {
				dependency = this.lookupKey(key, silent);
				if (dependency) {
					if (!this.props[key]) this.props[key] = {};
					this.props[key][prop] = dependency[prop] || dependency;
					return this.props[key][prop];
				}
			}
		}
		lookupKey(key, silent) {
			var dependency;
			if (this.deps[key]) dependency = this.deps[key];
			else if (window[key]) {
				this.deps[key] = window[key];
				dependency = this.deps[key];
			} else if (!silent) this.error(key);
			return dependency;
		}
		error(key) {
			console.error("Unable to find dependency", key, "Please check documentation and ensure you have imported the required library into your project");
		}
	};
	function fitData(columns, forced) {
		if (forced) this.table.columnManager.renderer.reinitializeColumnWidths(columns);
		if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
	}
	function fitDataGeneral(columns, forced) {
		columns.forEach(function(column) {
			column.reinitializeWidth();
		});
		if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
	}
	function fitDataStretch(columns, forced) {
		var colsWidth = 0, tableWidth = this.table.rowManager.element.clientWidth, gap = 0, lastCol = false;
		columns.forEach((column, i) => {
			if (!column.widthFixed) column.reinitializeWidth();
			if (this.table.options.responsiveLayout ? column.modules.responsive.visible : column.visible) lastCol = column;
			if (column.visible) colsWidth += column.getWidth();
		});
		if (lastCol) {
			gap = tableWidth - colsWidth + lastCol.getWidth();
			if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) {
				lastCol.setWidth(0);
				this.table.modules.responsiveLayout.update();
			}
			if (gap > 0) lastCol.setWidth(gap);
			else lastCol.reinitializeWidth();
		} else if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
	}
	function fitColumns(columns, forced) {
		var totalWidth = this.table.rowManager.element.getBoundingClientRect().width;
		var fixedWidth = 0;
		var flexWidth = 0;
		var flexGrowUnits = 0;
		var flexColWidth = 0;
		var flexColumns = [];
		var fixedShrinkColumns = [];
		var flexShrinkUnits = 0;
		var overflowWidth = 0;
		var gapFill = 0;
		function calcWidth(width) {
			var colWidth;
			if (typeof width == "string") if (width.indexOf("%") > -1) colWidth = totalWidth / 100 * parseInt(width);
			else colWidth = parseInt(width);
			else colWidth = width;
			return colWidth;
		}
		function scaleColumns(columns, freeSpace, colWidth, shrinkCols) {
			var oversizeCols = [], oversizeSpace = 0, remainingSpace = 0, nextColWidth = 0, remainingFlexGrowUnits = flexGrowUnits, gap = 0, changeUnits = 0, undersizeCols = [];
			function calcGrow(col) {
				return colWidth * (col.column.definition.widthGrow || 1);
			}
			function calcShrink(col) {
				return calcWidth(col.width) - colWidth * (col.column.definition.widthShrink || 0);
			}
			columns.forEach(function(col, i) {
				var width = shrinkCols ? calcShrink(col) : calcGrow(col);
				if (col.column.minWidth >= width) oversizeCols.push(col);
				else if (col.column.maxWidth && col.column.maxWidth < width) {
					col.width = col.column.maxWidth;
					freeSpace -= col.column.maxWidth;
					remainingFlexGrowUnits -= shrinkCols ? col.column.definition.widthShrink || 1 : col.column.definition.widthGrow || 1;
					if (remainingFlexGrowUnits) colWidth = Math.floor(freeSpace / remainingFlexGrowUnits);
				} else {
					undersizeCols.push(col);
					changeUnits += shrinkCols ? col.column.definition.widthShrink || 1 : col.column.definition.widthGrow || 1;
				}
			});
			if (oversizeCols.length) {
				oversizeCols.forEach(function(col) {
					oversizeSpace += shrinkCols ? col.width - col.column.minWidth : col.column.minWidth;
					col.width = col.column.minWidth;
				});
				remainingSpace = freeSpace - oversizeSpace;
				nextColWidth = changeUnits ? Math.floor(remainingSpace / changeUnits) : remainingSpace;
				gap = scaleColumns(undersizeCols, remainingSpace, nextColWidth, shrinkCols);
			} else {
				gap = changeUnits ? freeSpace - Math.floor(freeSpace / changeUnits) * changeUnits : freeSpace;
				undersizeCols.forEach(function(column) {
					column.width = shrinkCols ? calcShrink(column) : calcGrow(column);
				});
			}
			return gap;
		}
		if (this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)) this.table.modules.responsiveLayout.update();
		if (this.table.rowManager.element.scrollHeight > this.table.rowManager.element.clientHeight) totalWidth -= this.table.rowManager.element.offsetWidth - this.table.rowManager.element.clientWidth;
		columns.forEach(function(column) {
			var width, minWidth, colWidth;
			if (column.visible) {
				width = column.definition.width;
				minWidth = parseInt(column.minWidth);
				if (width) {
					colWidth = calcWidth(width);
					fixedWidth += colWidth > minWidth ? colWidth : minWidth;
					if (column.definition.widthShrink) {
						fixedShrinkColumns.push({
							column,
							width: colWidth > minWidth ? colWidth : minWidth
						});
						flexShrinkUnits += column.definition.widthShrink;
					}
				} else {
					flexColumns.push({
						column,
						width: 0
					});
					flexGrowUnits += column.definition.widthGrow || 1;
				}
			}
		});
		flexWidth = totalWidth - fixedWidth;
		flexColWidth = Math.floor(flexWidth / flexGrowUnits);
		gapFill = scaleColumns(flexColumns, flexWidth, flexColWidth, false);
		if (flexColumns.length && gapFill > 0) flexColumns[flexColumns.length - 1].width += gapFill;
		flexColumns.forEach(function(col) {
			flexWidth -= col.width;
		});
		overflowWidth = Math.abs(gapFill) + flexWidth;
		if (overflowWidth > 0 && flexShrinkUnits) gapFill = scaleColumns(fixedShrinkColumns, overflowWidth, Math.floor(overflowWidth / flexShrinkUnits), true);
		if (gapFill && fixedShrinkColumns.length) fixedShrinkColumns[fixedShrinkColumns.length - 1].width -= gapFill;
		flexColumns.forEach(function(col) {
			col.column.setWidth(col.width);
		});
		fixedShrinkColumns.forEach(function(col) {
			col.column.setWidth(col.width);
		});
	}
	var defaultModes = {
		fitData,
		fitDataFill: fitDataGeneral,
		fitDataTable: fitDataGeneral,
		fitDataStretch,
		fitColumns
	};
	var Layout = class Layout extends Module {
		static moduleName = "layout";
		static modes = defaultModes;
		constructor(table) {
			super(table, "layout");
			this.mode = null;
			this.registerTableOption("layout", "fitData");
			this.registerTableOption("layoutColumnsOnNewData", false);
			this.registerColumnOption("widthGrow");
			this.registerColumnOption("widthShrink");
		}
		initialize() {
			var layout = this.table.options.layout;
			if (Layout.modes[layout]) this.mode = layout;
			else {
				console.warn("Layout Error - invalid mode set, defaulting to 'fitData' : " + layout);
				this.mode = "fitData";
			}
			this.table.element.setAttribute("tabulator-layout", this.mode);
			this.subscribe("column-init", this.initializeColumn.bind(this));
		}
		initializeColumn(column) {
			if (column.definition.widthGrow) column.definition.widthGrow = Number(column.definition.widthGrow);
			if (column.definition.widthShrink) column.definition.widthShrink = Number(column.definition.widthShrink);
		}
		getMode() {
			return this.mode;
		}
		layout(dataChanged) {
			var variableHeight = this.table.columnManager.columnsByIndex.find((column) => column.definition.variableHeight || column.definition.formatter === "textarea");
			this.dispatch("layout-refreshing");
			Layout.modes[this.mode].call(this, this.table.columnManager.columnsByIndex, dataChanged);
			if (variableHeight) this.table.rowManager.normalizeHeight(true);
			this.dispatch("layout-refreshed");
		}
	};
	var defaultLangs = { "default": {
		"groups": {
			"item": "item",
			"items": "items"
		},
		"columns": {},
		"data": {
			"loading": "Loading",
			"error": "Error"
		},
		"pagination": {
			"page_size": "Page Size",
			"page_title": "Show Page",
			"first": "First",
			"first_title": "First Page",
			"last": "Last",
			"last_title": "Last Page",
			"prev": "Prev",
			"prev_title": "Prev Page",
			"next": "Next",
			"next_title": "Next Page",
			"all": "All",
			"counter": {
				"showing": "Showing",
				"of": "of",
				"rows": "rows",
				"pages": "pages"
			}
		},
		"headerFilters": {
			"default": "filter column...",
			"columns": {}
		}
	} };
	var Localize = class Localize extends Module {
		static moduleName = "localize";
		static langs = defaultLangs;
		constructor(table) {
			super(table);
			this.locale = "default";
			this.lang = false;
			this.bindings = {};
			this.langList = {};
			this.registerTableOption("locale", false);
			this.registerTableOption("langs", {});
		}
		initialize() {
			this.langList = Helpers.deepClone(Localize.langs);
			if (this.table.options.columnDefaults.headerFilterPlaceholder !== false) this.setHeaderFilterPlaceholder(this.table.options.columnDefaults.headerFilterPlaceholder);
			for (let locale in this.table.options.langs) this.installLang(locale, this.table.options.langs[locale]);
			this.setLocale(this.table.options.locale);
			this.registerTableFunction("setLocale", this.setLocale.bind(this));
			this.registerTableFunction("getLocale", this.getLocale.bind(this));
			this.registerTableFunction("getLang", this.getLang.bind(this));
		}
		setHeaderFilterPlaceholder(placeholder) {
			this.langList.default.headerFilters.default = placeholder;
		}
		installLang(locale, lang) {
			if (this.langList[locale]) this._setLangProp(this.langList[locale], lang);
			else this.langList[locale] = lang;
		}
		_setLangProp(lang, values) {
			for (let key in values) if (lang[key] && typeof lang[key] == "object") this._setLangProp(lang[key], values[key]);
			else lang[key] = values[key];
		}
		setLocale(desiredLocale) {
			desiredLocale = desiredLocale || "default";
			function traverseLang(trans, path) {
				for (var prop in trans) if (typeof trans[prop] == "object") {
					if (!path[prop]) path[prop] = {};
					traverseLang(trans[prop], path[prop]);
				} else path[prop] = trans[prop];
			}
			if (desiredLocale === true && navigator.language) desiredLocale = navigator.language.toLowerCase();
			if (desiredLocale) {
				if (!this.langList[desiredLocale]) {
					let prefix = desiredLocale.split("-")[0];
					if (this.langList[prefix]) {
						console.warn("Localization Error - Exact matching locale not found, using closest match: ", desiredLocale, prefix);
						desiredLocale = prefix;
					} else {
						console.warn("Localization Error - Matching locale not found, using default: ", desiredLocale);
						desiredLocale = "default";
					}
				}
			}
			this.locale = desiredLocale;
			this.lang = Helpers.deepClone(this.langList.default || {});
			if (desiredLocale != "default") traverseLang(this.langList[desiredLocale], this.lang);
			this.dispatchExternal("localized", this.locale, this.lang);
			this._executeBindings();
		}
		getLocale(locale) {
			return this.locale;
		}
		getLang(locale) {
			return locale ? this.langList[locale] : this.lang;
		}
		getText(path, value) {
			var pathArray = (value ? path + "|" + value : path).split("|");
			return this._getLangElement(pathArray, this.locale) || "";
		}
		_getLangElement(path, locale) {
			var root = this.lang;
			path.forEach(function(level) {
				var rootPath;
				if (root) {
					rootPath = root[level];
					if (typeof rootPath != "undefined") root = rootPath;
					else root = false;
				}
			});
			return root;
		}
		bind(path, callback) {
			if (!this.bindings[path]) this.bindings[path] = [];
			this.bindings[path].push(callback);
			callback(this.getText(path), this.lang);
		}
		_executeBindings() {
			for (let path in this.bindings) this.bindings[path].forEach((binding) => {
				binding(this.getText(path), this.lang);
			});
		}
	};
	var Comms = class extends Module {
		static moduleName = "comms";
		constructor(table) {
			super(table);
		}
		initialize() {
			this.registerTableFunction("tableComms", this.receive.bind(this));
		}
		getConnections(selectors) {
			var connections = [];
			this.table.constructor.registry.lookupTable(selectors).forEach((con) => {
				if (this.table !== con) connections.push(con);
			});
			return connections;
		}
		send(selectors, module, action, data) {
			var connections = this.getConnections(selectors);
			connections.forEach((connection) => {
				connection.tableComms(this.table.element, module, action, data);
			});
			if (!connections.length && selectors) console.warn("Table Connection Error - No tables matching selector found", selectors);
		}
		receive(table, module, action, data) {
			if (this.table.modExists(module)) return this.table.modules[module].commsReceived(table, action, data);
			else console.warn("Inter-table Comms Error - no such module:", module);
		}
	};
	var coreModules = Object.freeze({
		__proto__: null,
		CommsModule: Comms,
		LayoutModule: Layout,
		LocalizeModule: Localize
	});
	var TableRegistry = class TableRegistry {
		static registry = {
			tables: [],
			register(table) {
				TableRegistry.registry.tables.push(table);
			},
			deregister(table) {
				var index = TableRegistry.registry.tables.indexOf(table);
				if (index > -1) TableRegistry.registry.tables.splice(index, 1);
			},
			lookupTable(query, silent) {
				var results = [], matches, match;
				if (typeof query === "string") {
					matches = document.querySelectorAll(query);
					if (matches.length) for (var i = 0; i < matches.length; i++) {
						match = TableRegistry.registry.matchElement(matches[i]);
						if (match) results.push(match);
					}
				} else if (typeof HTMLElement !== "undefined" && query instanceof HTMLElement || query instanceof TableRegistry) {
					match = TableRegistry.registry.matchElement(query);
					if (match) results.push(match);
				} else if (Array.isArray(query)) query.forEach(function(item) {
					results = results.concat(TableRegistry.registry.lookupTable(item));
				});
				else if (!silent) console.warn("Table Connection Error - Invalid Selector", query);
				return results;
			},
			matchElement(element) {
				return TableRegistry.registry.tables.find(function(table) {
					return element instanceof TableRegistry ? table === element : table.element === element;
				});
			}
		};
		static findTable(query) {
			var results = TableRegistry.registry.lookupTable(query, true);
			return Array.isArray(results) && !results.length ? false : results;
		}
	};
	var ModuleBinder = class ModuleBinder extends TableRegistry {
		static moduleBindings = {};
		static moduleExtensions = {};
		static modulesRegistered = false;
		static defaultModules = false;
		constructor() {
			super();
		}
		static initializeModuleBinder(defaultModules) {
			if (!ModuleBinder.modulesRegistered) {
				ModuleBinder.modulesRegistered = true;
				ModuleBinder._registerModules(coreModules, true);
				if (defaultModules) ModuleBinder._registerModules(defaultModules);
			}
		}
		static _extendModule(name, property, values) {
			if (ModuleBinder.moduleBindings[name]) {
				var source = ModuleBinder.moduleBindings[name][property];
				if (source) if (typeof values == "object") for (let key in values) source[key] = values[key];
				else console.warn("Module Error - Invalid value type, it must be an object");
				else console.warn("Module Error - property does not exist:", property);
			} else console.warn("Module Error - module does not exist:", name);
		}
		static _registerModules(modules, core) {
			var mods = Object.values(modules);
			if (core) mods.forEach((mod) => {
				mod.prototype.moduleCore = true;
			});
			ModuleBinder._registerModule(mods);
		}
		static _registerModule(modules) {
			if (!Array.isArray(modules)) modules = [modules];
			modules.forEach((mod) => {
				ModuleBinder._registerModuleBinding(mod);
				ModuleBinder._registerModuleExtensions(mod);
			});
		}
		static _registerModuleBinding(mod) {
			if (mod.moduleName) ModuleBinder.moduleBindings[mod.moduleName] = mod;
			else console.error("Unable to bind module, no moduleName defined", mod.moduleName);
		}
		static _registerModuleExtensions(mod) {
			var extensions = mod.moduleExtensions;
			if (mod.moduleExtensions) for (let modKey in extensions) {
				let ext = extensions[modKey];
				if (ModuleBinder.moduleBindings[modKey]) for (let propKey in ext) ModuleBinder._extendModule(modKey, propKey, ext[propKey]);
				else {
					if (!ModuleBinder.moduleExtensions[modKey]) ModuleBinder.moduleExtensions[modKey] = {};
					for (let propKey in ext) {
						if (!ModuleBinder.moduleExtensions[modKey][propKey]) ModuleBinder.moduleExtensions[modKey][propKey] = {};
						Object.assign(ModuleBinder.moduleExtensions[modKey][propKey], ext[propKey]);
					}
				}
			}
			ModuleBinder._extendModuleFromQueue(mod);
		}
		static _extendModuleFromQueue(mod) {
			var extensions = ModuleBinder.moduleExtensions[mod.moduleName];
			if (extensions) for (let propKey in extensions) ModuleBinder._extendModule(mod.moduleName, propKey, extensions[propKey]);
		}
		_bindModules() {
			var orderedStartMods = [], orderedEndMods = [], unOrderedMods = [];
			this.modules = {};
			for (var name in ModuleBinder.moduleBindings) {
				let mod = ModuleBinder.moduleBindings[name];
				let module = new mod(this);
				this.modules[name] = module;
				if (mod.prototype.moduleCore) this.modulesCore.push(module);
				else if (mod.moduleInitOrder) if (mod.moduleInitOrder < 0) orderedStartMods.push(module);
				else orderedEndMods.push(module);
				else unOrderedMods.push(module);
			}
			orderedStartMods.sort((a, b) => a.moduleInitOrder > b.moduleInitOrder ? 1 : -1);
			orderedEndMods.sort((a, b) => a.moduleInitOrder > b.moduleInitOrder ? 1 : -1);
			this.modulesRegular = orderedStartMods.concat(unOrderedMods.concat(orderedEndMods));
		}
	};
	var Alert = class extends CoreFeature {
		constructor(table) {
			super(table);
			this.element = this._createAlertElement();
			this.msgElement = this._createMsgElement();
			this.type = null;
			this.element.appendChild(this.msgElement);
		}
		_createAlertElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-alert");
			return el;
		}
		_createMsgElement() {
			var el = document.createElement("div");
			el.classList.add("tabulator-alert-msg");
			el.setAttribute("role", "alert");
			return el;
		}
		_typeClass() {
			return "tabulator-alert-state-" + this.type;
		}
		alert(content, type = "msg") {
			if (content) {
				this.clear();
				this.dispatch("alert-show", type);
				this.type = type;
				while (this.msgElement.firstChild) this.msgElement.removeChild(this.msgElement.firstChild);
				this.msgElement.classList.add(this._typeClass());
				if (typeof content === "function") content = content();
				if (content instanceof HTMLElement) this.msgElement.appendChild(content);
				else this.msgElement.innerHTML = content;
				this.table.element.appendChild(this.element);
			}
		}
		clear() {
			this.dispatch("alert-hide", this.type);
			if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
			this.msgElement.classList.remove(this._typeClass());
		}
	};
	var Tabulator$1$1 = class Tabulator$1 extends ModuleBinder {
		static defaultOptions = defaultOptions;
		static extendModule() {
			Tabulator$1.initializeModuleBinder();
			Tabulator$1._extendModule(...arguments);
		}
		static registerModule() {
			Tabulator$1.initializeModuleBinder();
			Tabulator$1._registerModule(...arguments);
		}
		constructor(element, options, modules) {
			super();
			Tabulator$1.initializeModuleBinder(modules);
			this.options = {};
			this.columnManager = null;
			this.rowManager = null;
			this.footerManager = null;
			this.alertManager = null;
			this.vdomHoz = null;
			this.externalEvents = null;
			this.eventBus = null;
			this.interactionMonitor = false;
			this.browser = "";
			this.browserSlow = false;
			this.browserMobile = false;
			this.rtl = false;
			this.originalElement = null;
			this.componentFunctionBinder = new ComponentFunctionBinder(this);
			this.dataLoader = false;
			this.modules = {};
			this.modulesCore = [];
			this.modulesRegular = [];
			this.deprecationAdvisor = new DeprecationAdvisor(this);
			this.optionsList = new OptionsList(this, "table constructor");
			this.dependencyRegistry = new DependencyRegistry(this);
			this.initialized = false;
			this.destroyed = false;
			if (this.initializeElement(element)) {
				this.initializeCoreSystems(options);
				setTimeout(() => {
					this._create();
				});
			}
			this.constructor.registry.register(this);
		}
		initializeElement(element) {
			if (typeof HTMLElement !== "undefined" && element instanceof HTMLElement) {
				this.element = element;
				return true;
			} else if (typeof element === "string") {
				this.element = document.querySelector(element);
				if (this.element) return true;
				else {
					console.error("Tabulator Creation Error - no element found matching selector: ", element);
					return false;
				}
			} else {
				console.error("Tabulator Creation Error - Invalid element provided:", element);
				return false;
			}
		}
		initializeCoreSystems(options) {
			this.columnManager = new ColumnManager(this);
			this.rowManager = new RowManager(this);
			this.footerManager = new FooterManager(this);
			this.dataLoader = new DataLoader(this);
			this.alertManager = new Alert(this);
			this._bindModules();
			this.options = this.optionsList.generate(Tabulator$1.defaultOptions, options);
			this._clearObjectPointers();
			this._mapDeprecatedFunctionality();
			this.externalEvents = new ExternalEventBus(this, this.options, this.options.debugEventsExternal);
			this.eventBus = new InternalEventBus(this.options.debugEventsInternal);
			this.interactionMonitor = new InteractionManager(this);
			this.dataLoader.initialize();
			this.footerManager.initialize();
			this.dependencyRegistry.initialize();
		}
		_mapDeprecatedFunctionality() {}
		_clearSelection() {
			this.element.classList.add("tabulator-block-select");
			if (window.getSelection) {
				if (window.getSelection().empty) window.getSelection().empty();
				else if (window.getSelection().removeAllRanges) window.getSelection().removeAllRanges();
			} else if (document.selection) document.selection.empty();
			this.element.classList.remove("tabulator-block-select");
		}
		_create() {
			this.externalEvents.dispatch("tableBuilding");
			this.eventBus.dispatch("table-building");
			this._rtlCheck();
			this._buildElement();
			this._initializeTable();
			this.initialized = true;
			this._loadInitialData().finally(() => {
				this.eventBus.dispatch("table-initialized");
				this.externalEvents.dispatch("tableBuilt");
			});
		}
		_rtlCheck() {
			var style = window.getComputedStyle(this.element);
			switch (this.options.textDirection) {
				case "auto": if (style.direction !== "rtl") break;
				case "rtl":
					this.element.classList.add("tabulator-rtl");
					this.rtl = true;
					break;
				case "ltr": this.element.classList.add("tabulator-ltr");
				default: this.rtl = false;
			}
		}
		_clearObjectPointers() {
			this.options.columns = this.options.columns.slice(0);
			if (Array.isArray(this.options.data) && !this.options.reactiveData) this.options.data = this.options.data.slice(0);
		}
		_buildElement() {
			var element = this.element, options = this.options, newElement;
			if (element.tagName === "TABLE") {
				this.originalElement = this.element;
				newElement = document.createElement("div");
				var attributes = element.attributes;
				for (var i in attributes) if (typeof attributes[i] == "object") newElement.setAttribute(attributes[i].name, attributes[i].value);
				element.parentNode.replaceChild(newElement, element);
				this.element = element = newElement;
			}
			element.classList.add("tabulator");
			element.setAttribute("role", "grid");
			while (element.firstChild) element.removeChild(element.firstChild);
			if (options.height) {
				options.height = isNaN(options.height) ? options.height : options.height + "px";
				element.style.height = options.height;
			}
			if (options.minHeight !== false) {
				options.minHeight = isNaN(options.minHeight) ? options.minHeight : options.minHeight + "px";
				element.style.minHeight = options.minHeight;
			}
			if (options.maxHeight !== false) {
				options.maxHeight = isNaN(options.maxHeight) ? options.maxHeight : options.maxHeight + "px";
				element.style.maxHeight = options.maxHeight;
			}
		}
		_initializeTable() {
			var element = this.element, options = this.options;
			this.interactionMonitor.initialize();
			this.columnManager.initialize();
			this.rowManager.initialize();
			this._detectBrowser();
			this.modulesCore.forEach((mod) => {
				mod.initialize();
			});
			element.appendChild(this.columnManager.getElement());
			element.appendChild(this.rowManager.getElement());
			if (options.footerElement) this.footerManager.activate();
			if (options.autoColumns && options.data) this.columnManager.generateColumnsFromRowData(this.options.data);
			this.modulesRegular.forEach((mod) => {
				mod.initialize();
			});
			this.columnManager.setColumns(options.columns);
			this.eventBus.dispatch("table-built");
		}
		_loadInitialData() {
			return this.dataLoader.load(this.options.data).finally(() => {
				this.columnManager.verticalAlignHeaders();
			});
		}
		destroy() {
			var element = this.element;
			this.destroyed = true;
			this.constructor.registry.deregister(this);
			this.eventBus.dispatch("table-destroy");
			this.rowManager.destroy();
			while (element.firstChild) element.removeChild(element.firstChild);
			element.classList.remove("tabulator");
			this.externalEvents.dispatch("tableDestroyed");
		}
		_detectBrowser() {
			var ua = navigator.userAgent || navigator.vendor || window.opera;
			if (ua.indexOf("Trident") > -1) {
				this.browser = "ie";
				this.browserSlow = true;
			} else if (ua.indexOf("Edge") > -1) {
				this.browser = "edge";
				this.browserSlow = true;
			} else if (ua.indexOf("Firefox") > -1) {
				this.browser = "firefox";
				this.browserSlow = false;
			} else if (ua.indexOf("Mac OS") > -1) {
				this.browser = "safari";
				this.browserSlow = false;
			} else {
				this.browser = "other";
				this.browserSlow = false;
			}
			this.browserMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(ua.slice(0, 4));
		}
		initGuard(func, msg) {
			var stack, line;
			if (this.options.debugInitialization && !this.initialized) {
				if (!func) {
					stack = new Error().stack.split("\n");
					line = stack[0] == "Error" ? stack[2] : stack[1];
					if (line[0] == " ") func = line.trim().split(" ")[1].split(".")[1];
					else func = line.trim().split("@")[0];
				}
				console.warn("Table Not Initialized - Calling the " + func + " function before the table is initialized may result in inconsistent behavior, Please wait for the `tableBuilt` event before calling this function." + (msg ? " " + msg : ""));
			}
			return this.initialized;
		}
		blockRedraw() {
			this.initGuard();
			this.eventBus.dispatch("redraw-blocking");
			this.rowManager.blockRedraw();
			this.columnManager.blockRedraw();
			this.eventBus.dispatch("redraw-blocked");
		}
		restoreRedraw() {
			this.initGuard();
			this.eventBus.dispatch("redraw-restoring");
			this.rowManager.restoreRedraw();
			this.columnManager.restoreRedraw();
			this.eventBus.dispatch("redraw-restored");
		}
		setData(data, params, config) {
			this.initGuard(false, "To set initial data please use the 'data' property in the table constructor.");
			return this.dataLoader.load(data, params, config, false);
		}
		clearData() {
			this.initGuard();
			this.dataLoader.blockActiveLoad();
			this.rowManager.clearData();
		}
		getData(active) {
			return this.rowManager.getData(active);
		}
		getDataCount(active) {
			return this.rowManager.getDataCount(active);
		}
		replaceData(data, params, config) {
			this.initGuard();
			return this.dataLoader.load(data, params, config, true, true);
		}
		updateData(data) {
			var responses = 0;
			this.initGuard();
			return new Promise((resolve, reject) => {
				this.dataLoader.blockActiveLoad();
				if (typeof data === "string") data = JSON.parse(data);
				if (data && data.length > 0) data.forEach((item) => {
					var row = this.rowManager.findRow(item[this.options.index]);
					if (row) {
						responses++;
						row.updateData(item).then(() => {
							responses--;
							if (!responses) resolve();
						}).catch((e) => {
							reject("Update Error - Unable to update row", item, e);
						});
					} else reject("Update Error - Unable to find row", item);
				});
				else {
					console.warn("Update Error - No data provided");
					reject("Update Error - No data provided");
				}
			});
		}
		addData(data, pos, index) {
			this.initGuard();
			return new Promise((resolve, reject) => {
				this.dataLoader.blockActiveLoad();
				if (typeof data === "string") data = JSON.parse(data);
				if (data) this.rowManager.addRows(data, pos, index).then((rows) => {
					var output = [];
					rows.forEach(function(row) {
						output.push(row.getComponent());
					});
					resolve(output);
				});
				else {
					console.warn("Update Error - No data provided");
					reject("Update Error - No data provided");
				}
			});
		}
		updateOrAddData(data) {
			var rows = [], responses = 0;
			this.initGuard();
			return new Promise((resolve, reject) => {
				this.dataLoader.blockActiveLoad();
				if (typeof data === "string") data = JSON.parse(data);
				if (data && data.length > 0) data.forEach((item) => {
					var row = this.rowManager.findRow(item[this.options.index]);
					responses++;
					if (row) row.updateData(item).then(() => {
						responses--;
						rows.push(row.getComponent());
						if (!responses) resolve(rows);
					});
					else this.rowManager.addRows(item).then((newRows) => {
						responses--;
						rows.push(newRows[0].getComponent());
						if (!responses) resolve(rows);
					});
				});
				else {
					console.warn("Update Error - No data provided");
					reject("Update Error - No data provided");
				}
			});
		}
		getRow(index) {
			var row = this.rowManager.findRow(index);
			if (row) return row.getComponent();
			else {
				console.warn("Find Error - No matching row found:", index);
				return false;
			}
		}
		getRowFromPosition(position) {
			var row = this.rowManager.getRowFromPosition(position);
			if (row) return row.getComponent();
			else {
				console.warn("Find Error - No matching row found:", position);
				return false;
			}
		}
		deleteRow(index) {
			var foundRows = [];
			this.initGuard();
			if (!Array.isArray(index)) index = [index];
			for (let item of index) {
				let row = this.rowManager.findRow(item, true);
				if (row) foundRows.push(row);
				else {
					console.error("Delete Error - No matching row found:", item);
					return Promise.reject("Delete Error - No matching row found");
				}
			}
			foundRows.sort((a, b) => {
				return this.rowManager.rows.indexOf(a) > this.rowManager.rows.indexOf(b) ? 1 : -1;
			});
			foundRows.forEach((row) => {
				row.delete();
			});
			this.rowManager.reRenderInPosition();
			return Promise.resolve();
		}
		addRow(data, pos, index) {
			this.initGuard();
			if (typeof data === "string") data = JSON.parse(data);
			return this.rowManager.addRows(data, pos, index, true).then((rows) => {
				return rows[0].getComponent();
			});
		}
		updateOrAddRow(index, data) {
			var row = this.rowManager.findRow(index);
			this.initGuard();
			if (typeof data === "string") data = JSON.parse(data);
			if (row) return row.updateData(data).then(() => {
				return row.getComponent();
			});
			else return this.rowManager.addRows(data).then((rows) => {
				return rows[0].getComponent();
			});
		}
		updateRow(index, data) {
			var row = this.rowManager.findRow(index);
			this.initGuard();
			if (typeof data === "string") data = JSON.parse(data);
			if (row) return row.updateData(data).then(() => {
				return Promise.resolve(row.getComponent());
			});
			else {
				console.warn("Update Error - No matching row found:", index);
				return Promise.reject("Update Error - No matching row found");
			}
		}
		scrollToRow(index, position, ifVisible) {
			var row = this.rowManager.findRow(index);
			if (row) return this.rowManager.scrollToRow(row, position, ifVisible);
			else {
				console.warn("Scroll Error - No matching row found:", index);
				return Promise.reject("Scroll Error - No matching row found");
			}
		}
		moveRow(from, to, after) {
			var fromRow = this.rowManager.findRow(from);
			this.initGuard();
			if (fromRow) fromRow.moveToRow(to, after);
			else console.warn("Move Error - No matching row found:", from);
		}
		getRows(active) {
			return this.rowManager.getComponents(active);
		}
		getRowPosition(index) {
			var row = this.rowManager.findRow(index);
			if (row) return row.getPosition();
			else {
				console.warn("Position Error - No matching row found:", index);
				return false;
			}
		}
		setColumns(definition) {
			this.initGuard(false, "To set initial columns please use the 'columns' property in the table constructor");
			this.columnManager.setColumns(definition);
		}
		getColumns(structured) {
			return this.columnManager.getComponents(structured);
		}
		getColumn(field) {
			var column = this.columnManager.findColumn(field);
			if (column) return column.getComponent();
			else {
				console.warn("Find Error - No matching column found:", field);
				return false;
			}
		}
		getColumnDefinitions() {
			return this.columnManager.getDefinitionTree();
		}
		showColumn(field) {
			var column = this.columnManager.findColumn(field);
			this.initGuard();
			if (column) column.show();
			else {
				console.warn("Column Show Error - No matching column found:", field);
				return false;
			}
		}
		hideColumn(field) {
			var column = this.columnManager.findColumn(field);
			this.initGuard();
			if (column) column.hide();
			else {
				console.warn("Column Hide Error - No matching column found:", field);
				return false;
			}
		}
		toggleColumn(field) {
			var column = this.columnManager.findColumn(field);
			this.initGuard();
			if (column) if (column.visible) column.hide();
			else column.show();
			else {
				console.warn("Column Visibility Toggle Error - No matching column found:", field);
				return false;
			}
		}
		addColumn(definition, before, field) {
			var column = this.columnManager.findColumn(field);
			this.initGuard();
			return this.columnManager.addColumn(definition, before, column).then((column) => {
				return column.getComponent();
			});
		}
		deleteColumn(field) {
			var column = this.columnManager.findColumn(field);
			this.initGuard();
			if (column) return column.delete();
			else {
				console.warn("Column Delete Error - No matching column found:", field);
				return Promise.reject();
			}
		}
		updateColumnDefinition(field, definition) {
			var column = this.columnManager.findColumn(field);
			this.initGuard();
			if (column) return column.updateDefinition(definition);
			else {
				console.warn("Column Update Error - No matching column found:", field);
				return Promise.reject();
			}
		}
		moveColumn(from, to, after) {
			var fromColumn = this.columnManager.findColumn(from), toColumn = this.columnManager.findColumn(to);
			this.initGuard();
			if (fromColumn) if (toColumn) this.columnManager.moveColumn(fromColumn, toColumn, after);
			else console.warn("Move Error - No matching column found:", toColumn);
			else console.warn("Move Error - No matching column found:", from);
		}
		scrollToColumn(field, position, ifVisible) {
			return new Promise((resolve, reject) => {
				var column = this.columnManager.findColumn(field);
				if (column) return this.columnManager.scrollToColumn(column, position, ifVisible);
				else {
					console.warn("Scroll Error - No matching column found:", field);
					return Promise.reject("Scroll Error - No matching column found");
				}
			});
		}
		redraw(force) {
			this.initGuard();
			this.columnManager.redraw(force);
			this.rowManager.redraw(force);
		}
		setHeight(height) {
			this.options.height = isNaN(height) ? height : height + "px";
			this.element.style.height = this.options.height;
			this.rowManager.initializeRenderer();
			this.rowManager.redraw(true);
		}
		on(key, callback) {
			this.externalEvents.subscribe(key, callback);
		}
		off(key, callback) {
			this.externalEvents.unsubscribe(key, callback);
		}
		dispatchEvent() {
			Array.from(arguments).shift();
			this.externalEvents.dispatch(...arguments);
		}
		alert(contents, type) {
			this.initGuard();
			this.alertManager.alert(contents, type);
		}
		clearAlert() {
			this.initGuard();
			this.alertManager.clear();
		}
		modExists(plugin, required) {
			if (this.modules[plugin]) return true;
			else {
				if (required) console.error("Tabulator Module Not Installed: " + plugin);
				return false;
			}
		}
		module(key) {
			var mod = this.modules[key];
			if (!mod) console.error("Tabulator module not installed: " + key);
			return mod;
		}
	};
	var TabulatorFull = class extends Tabulator$1$1 {
		static extendModule() {
			Tabulator$1$1.initializeModuleBinder(allModules);
			Tabulator$1$1._extendModule(...arguments);
		}
		static registerModule() {
			Tabulator$1$1.initializeModuleBinder(allModules);
			Tabulator$1$1._registerModule(...arguments);
		}
		constructor(element, options, modules) {
			super(element, options, allModules);
		}
	};
	var TabulatorFull$1 = TabulatorFull;
	var require_toastify = __commonJSMin(((exports, module) => {
		(function(root, factory) {
			if (typeof module === "object" && module.exports) module.exports = factory();
			else root.Toastify = factory();
		})(exports, function(global) {
			var Toastify = function(options) {
				return new Toastify.lib.init(options);
			}, version = "1.12.0";
			Toastify.defaults = {
				oldestFirst: true,
				text: "Toastify is awesome!",
				node: void 0,
				duration: 3e3,
				selector: void 0,
				callback: function() {},
				destination: void 0,
				newWindow: false,
				close: false,
				gravity: "toastify-top",
				positionLeft: false,
				position: "",
				backgroundColor: "",
				avatar: "",
				className: "",
				stopOnFocus: true,
				onClick: function() {},
				offset: {
					x: 0,
					y: 0
				},
				escapeMarkup: true,
				ariaLive: "polite",
				style: { background: "" }
			};
			Toastify.lib = Toastify.prototype = {
				toastify: version,
				constructor: Toastify,
				init: function(options) {
					if (!options) options = {};
					this.options = {};
					this.toastElement = null;
					this.options.text = options.text || Toastify.defaults.text;
					this.options.node = options.node || Toastify.defaults.node;
					this.options.duration = options.duration === 0 ? 0 : options.duration || Toastify.defaults.duration;
					this.options.selector = options.selector || Toastify.defaults.selector;
					this.options.callback = options.callback || Toastify.defaults.callback;
					this.options.destination = options.destination || Toastify.defaults.destination;
					this.options.newWindow = options.newWindow || Toastify.defaults.newWindow;
					this.options.close = options.close || Toastify.defaults.close;
					this.options.gravity = options.gravity === "bottom" ? "toastify-bottom" : Toastify.defaults.gravity;
					this.options.positionLeft = options.positionLeft || Toastify.defaults.positionLeft;
					this.options.position = options.position || Toastify.defaults.position;
					this.options.backgroundColor = options.backgroundColor || Toastify.defaults.backgroundColor;
					this.options.avatar = options.avatar || Toastify.defaults.avatar;
					this.options.className = options.className || Toastify.defaults.className;
					this.options.stopOnFocus = options.stopOnFocus === void 0 ? Toastify.defaults.stopOnFocus : options.stopOnFocus;
					this.options.onClick = options.onClick || Toastify.defaults.onClick;
					this.options.offset = options.offset || Toastify.defaults.offset;
					this.options.escapeMarkup = options.escapeMarkup !== void 0 ? options.escapeMarkup : Toastify.defaults.escapeMarkup;
					this.options.ariaLive = options.ariaLive || Toastify.defaults.ariaLive;
					this.options.style = options.style || Toastify.defaults.style;
					if (options.backgroundColor) this.options.style.background = options.backgroundColor;
					return this;
				},
				buildToast: function() {
					if (!this.options) throw "Toastify is not initialized";
					var divElement = document.createElement("div");
					divElement.className = "toastify on " + this.options.className;
					if (!!this.options.position) divElement.className += " toastify-" + this.options.position;
					else if (this.options.positionLeft === true) {
						divElement.className += " toastify-left";
						console.warn("Property `positionLeft` will be depreciated in further versions. Please use `position` instead.");
					} else divElement.className += " toastify-right";
					divElement.className += " " + this.options.gravity;
					if (this.options.backgroundColor) console.warn("DEPRECATION NOTICE: \"backgroundColor\" is being deprecated. Please use the \"style.background\" property.");
					for (var property in this.options.style) divElement.style[property] = this.options.style[property];
					if (this.options.ariaLive) divElement.setAttribute("aria-live", this.options.ariaLive);
					if (this.options.node && this.options.node.nodeType === Node.ELEMENT_NODE) divElement.appendChild(this.options.node);
					else {
						if (this.options.escapeMarkup) divElement.innerText = this.options.text;
						else divElement.innerHTML = this.options.text;
						if (this.options.avatar !== "") {
							var avatarElement = document.createElement("img");
							avatarElement.src = this.options.avatar;
							avatarElement.className = "toastify-avatar";
							if (this.options.position == "left" || this.options.positionLeft === true) divElement.appendChild(avatarElement);
							else divElement.insertAdjacentElement("afterbegin", avatarElement);
						}
					}
					if (this.options.close === true) {
						var closeElement = document.createElement("button");
						closeElement.type = "button";
						closeElement.setAttribute("aria-label", "Close");
						closeElement.className = "toast-close";
						closeElement.innerHTML = "&#10006;";
						closeElement.addEventListener("click", function(event) {
							event.stopPropagation();
							this.removeElement(this.toastElement);
							window.clearTimeout(this.toastElement.timeOutValue);
						}.bind(this));
						var width = window.innerWidth > 0 ? window.innerWidth : screen.width;
						if ((this.options.position == "left" || this.options.positionLeft === true) && width > 360) divElement.insertAdjacentElement("afterbegin", closeElement);
						else divElement.appendChild(closeElement);
					}
					if (this.options.stopOnFocus && this.options.duration > 0) {
						var self = this;
						divElement.addEventListener("mouseover", function(event) {
							window.clearTimeout(divElement.timeOutValue);
						});
						divElement.addEventListener("mouseleave", function() {
							divElement.timeOutValue = window.setTimeout(function() {
								self.removeElement(divElement);
							}, self.options.duration);
						});
					}
					if (typeof this.options.destination !== "undefined") divElement.addEventListener("click", function(event) {
						event.stopPropagation();
						if (this.options.newWindow === true) window.open(this.options.destination, "_blank");
						else window.location = this.options.destination;
					}.bind(this));
					if (typeof this.options.onClick === "function" && typeof this.options.destination === "undefined") divElement.addEventListener("click", function(event) {
						event.stopPropagation();
						this.options.onClick();
					}.bind(this));
					if (typeof this.options.offset === "object") {
						var x = getAxisOffsetAValue("x", this.options);
						var y = getAxisOffsetAValue("y", this.options);
						var xOffset = this.options.position == "left" ? x : "-" + x;
						var yOffset = this.options.gravity == "toastify-top" ? y : "-" + y;
						divElement.style.transform = "translate(" + xOffset + "," + yOffset + ")";
					}
					return divElement;
				},
				showToast: function() {
					this.toastElement = this.buildToast();
					var rootElement;
					if (typeof this.options.selector === "string") rootElement = document.getElementById(this.options.selector);
					else if (this.options.selector instanceof HTMLElement || typeof ShadowRoot !== "undefined" && this.options.selector instanceof ShadowRoot) rootElement = this.options.selector;
					else rootElement = document.body;
					if (!rootElement) throw "Root element is not defined";
					var elementToInsert = Toastify.defaults.oldestFirst ? rootElement.firstChild : rootElement.lastChild;
					rootElement.insertBefore(this.toastElement, elementToInsert);
					Toastify.reposition();
					if (this.options.duration > 0) this.toastElement.timeOutValue = window.setTimeout(function() {
						this.removeElement(this.toastElement);
					}.bind(this), this.options.duration);
					return this;
				},
				hideToast: function() {
					if (this.toastElement.timeOutValue) clearTimeout(this.toastElement.timeOutValue);
					this.removeElement(this.toastElement);
				},
				removeElement: function(toastElement) {
					toastElement.className = toastElement.className.replace(" on", "");
					window.setTimeout(function() {
						if (this.options.node && this.options.node.parentNode) this.options.node.parentNode.removeChild(this.options.node);
						if (toastElement.parentNode) toastElement.parentNode.removeChild(toastElement);
						this.options.callback.call(toastElement);
						Toastify.reposition();
					}.bind(this), 400);
				}
			};
			Toastify.reposition = function() {
				var topLeftOffsetSize = {
					top: 15,
					bottom: 15
				};
				var topRightOffsetSize = {
					top: 15,
					bottom: 15
				};
				var offsetSize = {
					top: 15,
					bottom: 15
				};
				var allToasts = document.getElementsByClassName("toastify");
				var classUsed;
				for (var i = 0; i < allToasts.length; i++) {
					if (containsClass(allToasts[i], "toastify-top") === true) classUsed = "toastify-top";
					else classUsed = "toastify-bottom";
					var height = allToasts[i].offsetHeight;
					classUsed = classUsed.substr(9, classUsed.length - 1);
					var offset = 15;
					if ((window.innerWidth > 0 ? window.innerWidth : screen.width) <= 360) {
						allToasts[i].style[classUsed] = offsetSize[classUsed] + "px";
						offsetSize[classUsed] += height + offset;
					} else if (containsClass(allToasts[i], "toastify-left") === true) {
						allToasts[i].style[classUsed] = topLeftOffsetSize[classUsed] + "px";
						topLeftOffsetSize[classUsed] += height + offset;
					} else {
						allToasts[i].style[classUsed] = topRightOffsetSize[classUsed] + "px";
						topRightOffsetSize[classUsed] += height + offset;
					}
				}
				return this;
			};
			function getAxisOffsetAValue(axis, options) {
				if (options.offset[axis]) if (isNaN(options.offset[axis])) return options.offset[axis];
				else return options.offset[axis] + "px";
				return "0px";
			}
			function containsClass(elem, yourClass) {
				if (!elem || typeof yourClass !== "string") return false;
				else if (elem.className && elem.className.trim().split(/\s+/gi).indexOf(yourClass) > -1) return true;
				else return false;
			}
			Toastify.lib.init.prototype = Toastify.lib;
			return Toastify;
		});
	}));
	var require_localforage = __commonJSMin(((exports, module) => {
		(function(f) {
			if (typeof exports === "object" && typeof module !== "undefined") module.exports = f();
			else if (typeof define === "function" && define.amd) define([], f);
			else {
				var g;
				if (typeof window !== "undefined") g = window;
				else if (typeof global !== "undefined") g = global;
				else if (typeof self !== "undefined") g = self;
				else g = this;
				g.localforage = f();
			}
		})(function() {
			return (function e(t, n, r) {
				function s(o, u) {
					if (!n[o]) {
						if (!t[o]) {
							var a = typeof __require == "function" && __require;
							if (!u && a) return a(o, !0);
							if (i) return i(o, !0);
							var f = new Error("Cannot find module '" + o + "'");
							throw f.code = "MODULE_NOT_FOUND", f;
						}
						var l = n[o] = { exports: {} };
						t[o][0].call(l.exports, function(e) {
							var n = t[o][1][e];
							return s(n ? n : e);
						}, l, l.exports, e, t, n, r);
					}
					return n[o].exports;
				}
				var i = typeof __require == "function" && __require;
				for (var o = 0; o < r.length; o++) s(r[o]);
				return s;
			})({
				1: [function(_dereq_, module$1, exports$1) {
					(function(global) {
						"use strict";
						var Mutation = global.MutationObserver || global.WebKitMutationObserver;
						var scheduleDrain;
						if (Mutation) {
							var called = 0;
							var observer = new Mutation(nextTick);
							var element = global.document.createTextNode("");
							observer.observe(element, { characterData: true });
							scheduleDrain = function() {
								element.data = called = ++called % 2;
							};
						} else if (!global.setImmediate && typeof global.MessageChannel !== "undefined") {
							var channel = new global.MessageChannel();
							channel.port1.onmessage = nextTick;
							scheduleDrain = function() {
								channel.port2.postMessage(0);
							};
						} else if ("document" in global && "onreadystatechange" in global.document.createElement("script")) scheduleDrain = function() {
							var scriptEl = global.document.createElement("script");
							scriptEl.onreadystatechange = function() {
								nextTick();
								scriptEl.onreadystatechange = null;
								scriptEl.parentNode.removeChild(scriptEl);
								scriptEl = null;
							};
							global.document.documentElement.appendChild(scriptEl);
						};
						else scheduleDrain = function() {
							setTimeout(nextTick, 0);
						};
						var draining;
						var queue = [];
						function nextTick() {
							draining = true;
							var i, oldQueue;
							var len = queue.length;
							while (len) {
								oldQueue = queue;
								queue = [];
								i = -1;
								while (++i < len) oldQueue[i]();
								len = queue.length;
							}
							draining = false;
						}
						module$1.exports = immediate;
						function immediate(task) {
							if (queue.push(task) === 1 && !draining) scheduleDrain();
						}
					}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
				}, {}],
				2: [function(_dereq_, module$2, exports$2) {
					"use strict";
					var immediate = _dereq_(1);
					function INTERNAL() {}
					var handlers = {};
					var REJECTED = ["REJECTED"];
					var FULFILLED = ["FULFILLED"];
					var PENDING = ["PENDING"];
					module$2.exports = Promise;
					function Promise(resolver) {
						if (typeof resolver !== "function") throw new TypeError("resolver must be a function");
						this.state = PENDING;
						this.queue = [];
						this.outcome = void 0;
						if (resolver !== INTERNAL) safelyResolveThenable(this, resolver);
					}
					Promise.prototype["catch"] = function(onRejected) {
						return this.then(null, onRejected);
					};
					Promise.prototype.then = function(onFulfilled, onRejected) {
						if (typeof onFulfilled !== "function" && this.state === FULFILLED || typeof onRejected !== "function" && this.state === REJECTED) return this;
						var promise = new this.constructor(INTERNAL);
						if (this.state !== PENDING) unwrap(promise, this.state === FULFILLED ? onFulfilled : onRejected, this.outcome);
						else this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
						return promise;
					};
					function QueueItem(promise, onFulfilled, onRejected) {
						this.promise = promise;
						if (typeof onFulfilled === "function") {
							this.onFulfilled = onFulfilled;
							this.callFulfilled = this.otherCallFulfilled;
						}
						if (typeof onRejected === "function") {
							this.onRejected = onRejected;
							this.callRejected = this.otherCallRejected;
						}
					}
					QueueItem.prototype.callFulfilled = function(value) {
						handlers.resolve(this.promise, value);
					};
					QueueItem.prototype.otherCallFulfilled = function(value) {
						unwrap(this.promise, this.onFulfilled, value);
					};
					QueueItem.prototype.callRejected = function(value) {
						handlers.reject(this.promise, value);
					};
					QueueItem.prototype.otherCallRejected = function(value) {
						unwrap(this.promise, this.onRejected, value);
					};
					function unwrap(promise, func, value) {
						immediate(function() {
							var returnValue;
							try {
								returnValue = func(value);
							} catch (e) {
								return handlers.reject(promise, e);
							}
							if (returnValue === promise) handlers.reject(promise, new TypeError("Cannot resolve promise with itself"));
							else handlers.resolve(promise, returnValue);
						});
					}
					handlers.resolve = function(self, value) {
						var result = tryCatch(getThen, value);
						if (result.status === "error") return handlers.reject(self, result.value);
						var thenable = result.value;
						if (thenable) safelyResolveThenable(self, thenable);
						else {
							self.state = FULFILLED;
							self.outcome = value;
							var i = -1;
							var len = self.queue.length;
							while (++i < len) self.queue[i].callFulfilled(value);
						}
						return self;
					};
					handlers.reject = function(self, error) {
						self.state = REJECTED;
						self.outcome = error;
						var i = -1;
						var len = self.queue.length;
						while (++i < len) self.queue[i].callRejected(error);
						return self;
					};
					function getThen(obj) {
						var then = obj && obj.then;
						if (obj && (typeof obj === "object" || typeof obj === "function") && typeof then === "function") return function appyThen() {
							then.apply(obj, arguments);
						};
					}
					function safelyResolveThenable(self, thenable) {
						var called = false;
						function onError(value) {
							if (called) return;
							called = true;
							handlers.reject(self, value);
						}
						function onSuccess(value) {
							if (called) return;
							called = true;
							handlers.resolve(self, value);
						}
						function tryToUnwrap() {
							thenable(onSuccess, onError);
						}
						var result = tryCatch(tryToUnwrap);
						if (result.status === "error") onError(result.value);
					}
					function tryCatch(func, value) {
						var out = {};
						try {
							out.value = func(value);
							out.status = "success";
						} catch (e) {
							out.status = "error";
							out.value = e;
						}
						return out;
					}
					Promise.resolve = resolve;
					function resolve(value) {
						if (value instanceof this) return value;
						return handlers.resolve(new this(INTERNAL), value);
					}
					Promise.reject = reject;
					function reject(reason) {
						var promise = new this(INTERNAL);
						return handlers.reject(promise, reason);
					}
					Promise.all = all;
					function all(iterable) {
						var self = this;
						if (Object.prototype.toString.call(iterable) !== "[object Array]") return this.reject(new TypeError("must be an array"));
						var len = iterable.length;
						var called = false;
						if (!len) return this.resolve([]);
						var values = new Array(len);
						var resolved = 0;
						var i = -1;
						var promise = new this(INTERNAL);
						while (++i < len) allResolver(iterable[i], i);
						return promise;
						function allResolver(value, i) {
							self.resolve(value).then(resolveFromAll, function(error) {
								if (!called) {
									called = true;
									handlers.reject(promise, error);
								}
							});
							function resolveFromAll(outValue) {
								values[i] = outValue;
								if (++resolved === len && !called) {
									called = true;
									handlers.resolve(promise, values);
								}
							}
						}
					}
					Promise.race = race;
					function race(iterable) {
						var self = this;
						if (Object.prototype.toString.call(iterable) !== "[object Array]") return this.reject(new TypeError("must be an array"));
						var len = iterable.length;
						var called = false;
						if (!len) return this.resolve([]);
						var i = -1;
						var promise = new this(INTERNAL);
						while (++i < len) resolver(iterable[i]);
						return promise;
						function resolver(value) {
							self.resolve(value).then(function(response) {
								if (!called) {
									called = true;
									handlers.resolve(promise, response);
								}
							}, function(error) {
								if (!called) {
									called = true;
									handlers.reject(promise, error);
								}
							});
						}
					}
				}, { "1": 1 }],
				3: [function(_dereq_, module$3, exports$3) {
					(function(global) {
						"use strict";
						if (typeof global.Promise !== "function") global.Promise = _dereq_(2);
					}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
				}, { "2": 2 }],
				4: [function(_dereq_, module$4, exports$4) {
					"use strict";
					var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) {
						return typeof obj;
					} : function(obj) {
						return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
					};
					function _classCallCheck(instance, Constructor) {
						if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
					}
					function getIDB() {
						try {
							if (typeof indexedDB !== "undefined") return indexedDB;
							if (typeof webkitIndexedDB !== "undefined") return webkitIndexedDB;
							if (typeof mozIndexedDB !== "undefined") return mozIndexedDB;
							if (typeof OIndexedDB !== "undefined") return OIndexedDB;
							if (typeof msIndexedDB !== "undefined") return msIndexedDB;
						} catch (e) {
							return;
						}
					}
					var idb = getIDB();
					function isIndexedDBValid() {
						try {
							if (!idb || !idb.open) return false;
							var isSafari = typeof openDatabase !== "undefined" && /(Safari|iPhone|iPad|iPod)/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) && !/BlackBerry/.test(navigator.platform);
							var hasFetch = typeof fetch === "function" && fetch.toString().indexOf("[native code") !== -1;
							return (!isSafari || hasFetch) && typeof indexedDB !== "undefined" && typeof IDBKeyRange !== "undefined";
						} catch (e) {
							return false;
						}
					}
					function createBlob(parts, properties) {
						parts = parts || [];
						properties = properties || {};
						try {
							return new Blob(parts, properties);
						} catch (e) {
							if (e.name !== "TypeError") throw e;
							var builder = new (typeof BlobBuilder !== "undefined" ? BlobBuilder : typeof MSBlobBuilder !== "undefined" ? MSBlobBuilder : typeof MozBlobBuilder !== "undefined" ? MozBlobBuilder : WebKitBlobBuilder)();
							for (var i = 0; i < parts.length; i += 1) builder.append(parts[i]);
							return builder.getBlob(properties.type);
						}
					}
					if (typeof Promise === "undefined") _dereq_(3);
					var Promise$1 = Promise;
					function executeCallback(promise, callback) {
						if (callback) promise.then(function(result) {
							callback(null, result);
						}, function(error) {
							callback(error);
						});
					}
					function executeTwoCallbacks(promise, callback, errorCallback) {
						if (typeof callback === "function") promise.then(callback);
						if (typeof errorCallback === "function") promise["catch"](errorCallback);
					}
					function normalizeKey(key) {
						if (typeof key !== "string") {
							console.warn(key + " used as a key, but it is not a string.");
							key = String(key);
						}
						return key;
					}
					function getCallback() {
						if (arguments.length && typeof arguments[arguments.length - 1] === "function") return arguments[arguments.length - 1];
					}
					var DETECT_BLOB_SUPPORT_STORE = "local-forage-detect-blob-support";
					var supportsBlobs = void 0;
					var dbContexts = {};
					var toString = Object.prototype.toString;
					var READ_ONLY = "readonly";
					var READ_WRITE = "readwrite";
					function _binStringToArrayBuffer(bin) {
						var length = bin.length;
						var buf = new ArrayBuffer(length);
						var arr = new Uint8Array(buf);
						for (var i = 0; i < length; i++) arr[i] = bin.charCodeAt(i);
						return buf;
					}
					function _checkBlobSupportWithoutCaching(idb) {
						return new Promise$1(function(resolve) {
							var txn = idb.transaction(DETECT_BLOB_SUPPORT_STORE, READ_WRITE);
							var blob = createBlob([""]);
							txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, "key");
							txn.onabort = function(e) {
								e.preventDefault();
								e.stopPropagation();
								resolve(false);
							};
							txn.oncomplete = function() {
								var matchedChrome = navigator.userAgent.match(/Chrome\/(\d+)/);
								resolve(navigator.userAgent.match(/Edge\//) || !matchedChrome || parseInt(matchedChrome[1], 10) >= 43);
							};
						})["catch"](function() {
							return false;
						});
					}
					function _checkBlobSupport(idb) {
						if (typeof supportsBlobs === "boolean") return Promise$1.resolve(supportsBlobs);
						return _checkBlobSupportWithoutCaching(idb).then(function(value) {
							supportsBlobs = value;
							return supportsBlobs;
						});
					}
					function _deferReadiness(dbInfo) {
						var dbContext = dbContexts[dbInfo.name];
						var deferredOperation = {};
						deferredOperation.promise = new Promise$1(function(resolve, reject) {
							deferredOperation.resolve = resolve;
							deferredOperation.reject = reject;
						});
						dbContext.deferredOperations.push(deferredOperation);
						if (!dbContext.dbReady) dbContext.dbReady = deferredOperation.promise;
						else dbContext.dbReady = dbContext.dbReady.then(function() {
							return deferredOperation.promise;
						});
					}
					function _advanceReadiness(dbInfo) {
						var deferredOperation = dbContexts[dbInfo.name].deferredOperations.pop();
						if (deferredOperation) {
							deferredOperation.resolve();
							return deferredOperation.promise;
						}
					}
					function _rejectReadiness(dbInfo, err) {
						var deferredOperation = dbContexts[dbInfo.name].deferredOperations.pop();
						if (deferredOperation) {
							deferredOperation.reject(err);
							return deferredOperation.promise;
						}
					}
					function _getConnection(dbInfo, upgradeNeeded) {
						return new Promise$1(function(resolve, reject) {
							dbContexts[dbInfo.name] = dbContexts[dbInfo.name] || createDbContext();
							if (dbInfo.db) if (upgradeNeeded) {
								_deferReadiness(dbInfo);
								dbInfo.db.close();
							} else return resolve(dbInfo.db);
							var dbArgs = [dbInfo.name];
							if (upgradeNeeded) dbArgs.push(dbInfo.version);
							var openreq = idb.open.apply(idb, dbArgs);
							if (upgradeNeeded) openreq.onupgradeneeded = function(e) {
								var db = openreq.result;
								try {
									db.createObjectStore(dbInfo.storeName);
									if (e.oldVersion <= 1) db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);
								} catch (ex) {
									if (ex.name === "ConstraintError") console.warn("The database \"" + dbInfo.name + "\" has been upgraded from version " + e.oldVersion + " to version " + e.newVersion + ", but the storage \"" + dbInfo.storeName + "\" already exists.");
									else throw ex;
								}
							};
							openreq.onerror = function(e) {
								e.preventDefault();
								reject(openreq.error);
							};
							openreq.onsuccess = function() {
								var db = openreq.result;
								db.onversionchange = function(e) {
									e.target.close();
								};
								resolve(db);
								_advanceReadiness(dbInfo);
							};
						});
					}
					function _getOriginalConnection(dbInfo) {
						return _getConnection(dbInfo, false);
					}
					function _getUpgradedConnection(dbInfo) {
						return _getConnection(dbInfo, true);
					}
					function _isUpgradeNeeded(dbInfo, defaultVersion) {
						if (!dbInfo.db) return true;
						var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);
						var isDowngrade = dbInfo.version < dbInfo.db.version;
						var isUpgrade = dbInfo.version > dbInfo.db.version;
						if (isDowngrade) {
							if (dbInfo.version !== defaultVersion) console.warn("The database \"" + dbInfo.name + "\" can't be downgraded from version " + dbInfo.db.version + " to version " + dbInfo.version + ".");
							dbInfo.version = dbInfo.db.version;
						}
						if (isUpgrade || isNewStore) {
							if (isNewStore) {
								var incVersion = dbInfo.db.version + 1;
								if (incVersion > dbInfo.version) dbInfo.version = incVersion;
							}
							return true;
						}
						return false;
					}
					function _encodeBlob(blob) {
						return new Promise$1(function(resolve, reject) {
							var reader = new FileReader();
							reader.onerror = reject;
							reader.onloadend = function(e) {
								resolve({
									__local_forage_encoded_blob: true,
									data: btoa(e.target.result || ""),
									type: blob.type
								});
							};
							reader.readAsBinaryString(blob);
						});
					}
					function _decodeBlob(encodedBlob) {
						return createBlob([_binStringToArrayBuffer(atob(encodedBlob.data))], { type: encodedBlob.type });
					}
					function _isEncodedBlob(value) {
						return value && value.__local_forage_encoded_blob;
					}
					function _fullyReady(callback) {
						var self = this;
						var promise = self._initReady().then(function() {
							var dbContext = dbContexts[self._dbInfo.name];
							if (dbContext && dbContext.dbReady) return dbContext.dbReady;
						});
						executeTwoCallbacks(promise, callback, callback);
						return promise;
					}
					function _tryReconnect(dbInfo) {
						_deferReadiness(dbInfo);
						var dbContext = dbContexts[dbInfo.name];
						var forages = dbContext.forages;
						for (var i = 0; i < forages.length; i++) {
							var forage = forages[i];
							if (forage._dbInfo.db) {
								forage._dbInfo.db.close();
								forage._dbInfo.db = null;
							}
						}
						dbInfo.db = null;
						return _getOriginalConnection(dbInfo).then(function(db) {
							dbInfo.db = db;
							if (_isUpgradeNeeded(dbInfo)) return _getUpgradedConnection(dbInfo);
							return db;
						}).then(function(db) {
							dbInfo.db = dbContext.db = db;
							for (var i = 0; i < forages.length; i++) forages[i]._dbInfo.db = db;
						})["catch"](function(err) {
							_rejectReadiness(dbInfo, err);
							throw err;
						});
					}
					function createTransaction(dbInfo, mode, callback, retries) {
						if (retries === void 0) retries = 1;
						try {
							callback(null, dbInfo.db.transaction(dbInfo.storeName, mode));
						} catch (err) {
							if (retries > 0 && (!dbInfo.db || err.name === "InvalidStateError" || err.name === "NotFoundError")) return Promise$1.resolve().then(function() {
								if (!dbInfo.db || err.name === "NotFoundError" && !dbInfo.db.objectStoreNames.contains(dbInfo.storeName) && dbInfo.version <= dbInfo.db.version) {
									if (dbInfo.db) dbInfo.version = dbInfo.db.version + 1;
									return _getUpgradedConnection(dbInfo);
								}
							}).then(function() {
								return _tryReconnect(dbInfo).then(function() {
									createTransaction(dbInfo, mode, callback, retries - 1);
								});
							})["catch"](callback);
							callback(err);
						}
					}
					function createDbContext() {
						return {
							forages: [],
							db: null,
							dbReady: null,
							deferredOperations: []
						};
					}
					function _initStorage(options) {
						var self = this;
						var dbInfo = { db: null };
						if (options) for (var i in options) dbInfo[i] = options[i];
						var dbContext = dbContexts[dbInfo.name];
						if (!dbContext) {
							dbContext = createDbContext();
							dbContexts[dbInfo.name] = dbContext;
						}
						dbContext.forages.push(self);
						if (!self._initReady) {
							self._initReady = self.ready;
							self.ready = _fullyReady;
						}
						var initPromises = [];
						function ignoreErrors() {
							return Promise$1.resolve();
						}
						for (var j = 0; j < dbContext.forages.length; j++) {
							var forage = dbContext.forages[j];
							if (forage !== self) initPromises.push(forage._initReady()["catch"](ignoreErrors));
						}
						var forages = dbContext.forages.slice(0);
						return Promise$1.all(initPromises).then(function() {
							dbInfo.db = dbContext.db;
							return _getOriginalConnection(dbInfo);
						}).then(function(db) {
							dbInfo.db = db;
							if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) return _getUpgradedConnection(dbInfo);
							return db;
						}).then(function(db) {
							dbInfo.db = dbContext.db = db;
							self._dbInfo = dbInfo;
							for (var k = 0; k < forages.length; k++) {
								var forage = forages[k];
								if (forage !== self) {
									forage._dbInfo.db = dbInfo.db;
									forage._dbInfo.version = dbInfo.version;
								}
							}
						});
					}
					function getItem(key, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
									if (err) return reject(err);
									try {
										var req = transaction.objectStore(self._dbInfo.storeName).get(key);
										req.onsuccess = function() {
											var value = req.result;
											if (value === void 0) value = null;
											if (_isEncodedBlob(value)) value = _decodeBlob(value);
											resolve(value);
										};
										req.onerror = function() {
											reject(req.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function iterate(iterator, callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
									if (err) return reject(err);
									try {
										var req = transaction.objectStore(self._dbInfo.storeName).openCursor();
										var iterationNumber = 1;
										req.onsuccess = function() {
											var cursor = req.result;
											if (cursor) {
												var value = cursor.value;
												if (_isEncodedBlob(value)) value = _decodeBlob(value);
												var result = iterator(value, cursor.key, iterationNumber++);
												if (result !== void 0) resolve(result);
												else cursor["continue"]();
											} else resolve();
										};
										req.onerror = function() {
											reject(req.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function setItem(key, value, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = new Promise$1(function(resolve, reject) {
							var dbInfo;
							self.ready().then(function() {
								dbInfo = self._dbInfo;
								if (toString.call(value) === "[object Blob]") return _checkBlobSupport(dbInfo.db).then(function(blobSupport) {
									if (blobSupport) return value;
									return _encodeBlob(value);
								});
								return value;
							}).then(function(value) {
								createTransaction(self._dbInfo, READ_WRITE, function(err, transaction) {
									if (err) return reject(err);
									try {
										var store = transaction.objectStore(self._dbInfo.storeName);
										if (value === null) value = void 0;
										var req = store.put(value, key);
										transaction.oncomplete = function() {
											if (value === void 0) value = null;
											resolve(value);
										};
										transaction.onabort = transaction.onerror = function() {
											reject(req.error ? req.error : req.transaction.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function removeItem(key, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								createTransaction(self._dbInfo, READ_WRITE, function(err, transaction) {
									if (err) return reject(err);
									try {
										var req = transaction.objectStore(self._dbInfo.storeName)["delete"](key);
										transaction.oncomplete = function() {
											resolve();
										};
										transaction.onerror = function() {
											reject(req.error);
										};
										transaction.onabort = function() {
											reject(req.error ? req.error : req.transaction.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function clear(callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								createTransaction(self._dbInfo, READ_WRITE, function(err, transaction) {
									if (err) return reject(err);
									try {
										var req = transaction.objectStore(self._dbInfo.storeName).clear();
										transaction.oncomplete = function() {
											resolve();
										};
										transaction.onabort = transaction.onerror = function() {
											reject(req.error ? req.error : req.transaction.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function length(callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
									if (err) return reject(err);
									try {
										var req = transaction.objectStore(self._dbInfo.storeName).count();
										req.onsuccess = function() {
											resolve(req.result);
										};
										req.onerror = function() {
											reject(req.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function key(n, callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							if (n < 0) {
								resolve(null);
								return;
							}
							self.ready().then(function() {
								createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
									if (err) return reject(err);
									try {
										var store = transaction.objectStore(self._dbInfo.storeName);
										var advanced = false;
										var req = store.openKeyCursor();
										req.onsuccess = function() {
											var cursor = req.result;
											if (!cursor) {
												resolve(null);
												return;
											}
											if (n === 0) resolve(cursor.key);
											else if (!advanced) {
												advanced = true;
												cursor.advance(n);
											} else resolve(cursor.key);
										};
										req.onerror = function() {
											reject(req.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function keys(callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								createTransaction(self._dbInfo, READ_ONLY, function(err, transaction) {
									if (err) return reject(err);
									try {
										var req = transaction.objectStore(self._dbInfo.storeName).openKeyCursor();
										var keys = [];
										req.onsuccess = function() {
											var cursor = req.result;
											if (!cursor) {
												resolve(keys);
												return;
											}
											keys.push(cursor.key);
											cursor["continue"]();
										};
										req.onerror = function() {
											reject(req.error);
										};
									} catch (e) {
										reject(e);
									}
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function dropInstance(options, callback) {
						callback = getCallback.apply(this, arguments);
						var currentConfig = this.config();
						options = typeof options !== "function" && options || {};
						if (!options.name) {
							options.name = options.name || currentConfig.name;
							options.storeName = options.storeName || currentConfig.storeName;
						}
						var self = this;
						var promise;
						if (!options.name) promise = Promise$1.reject("Invalid arguments");
						else {
							var dbPromise = options.name === currentConfig.name && self._dbInfo.db ? Promise$1.resolve(self._dbInfo.db) : _getOriginalConnection(options).then(function(db) {
								var dbContext = dbContexts[options.name];
								var forages = dbContext.forages;
								dbContext.db = db;
								for (var i = 0; i < forages.length; i++) forages[i]._dbInfo.db = db;
								return db;
							});
							if (!options.storeName) promise = dbPromise.then(function(db) {
								_deferReadiness(options);
								var dbContext = dbContexts[options.name];
								var forages = dbContext.forages;
								db.close();
								for (var i = 0; i < forages.length; i++) {
									var forage = forages[i];
									forage._dbInfo.db = null;
								}
								return new Promise$1(function(resolve, reject) {
									var req = idb.deleteDatabase(options.name);
									req.onerror = function() {
										var db = req.result;
										if (db) db.close();
										reject(req.error);
									};
									req.onblocked = function() {
										console.warn("dropInstance blocked for database \"" + options.name + "\" until all open connections are closed");
									};
									req.onsuccess = function() {
										var db = req.result;
										if (db) db.close();
										resolve(db);
									};
								}).then(function(db) {
									dbContext.db = db;
									for (var i = 0; i < forages.length; i++) {
										var _forage = forages[i];
										_advanceReadiness(_forage._dbInfo);
									}
								})["catch"](function(err) {
									(_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function() {});
									throw err;
								});
							});
							else promise = dbPromise.then(function(db) {
								if (!db.objectStoreNames.contains(options.storeName)) return;
								var newVersion = db.version + 1;
								_deferReadiness(options);
								var dbContext = dbContexts[options.name];
								var forages = dbContext.forages;
								db.close();
								for (var i = 0; i < forages.length; i++) {
									var forage = forages[i];
									forage._dbInfo.db = null;
									forage._dbInfo.version = newVersion;
								}
								return new Promise$1(function(resolve, reject) {
									var req = idb.open(options.name, newVersion);
									req.onerror = function(err) {
										req.result.close();
										reject(err);
									};
									req.onupgradeneeded = function() {
										req.result.deleteObjectStore(options.storeName);
									};
									req.onsuccess = function() {
										var db = req.result;
										db.close();
										resolve(db);
									};
								}).then(function(db) {
									dbContext.db = db;
									for (var j = 0; j < forages.length; j++) {
										var _forage2 = forages[j];
										_forage2._dbInfo.db = db;
										_advanceReadiness(_forage2._dbInfo);
									}
								})["catch"](function(err) {
									(_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function() {});
									throw err;
								});
							});
						}
						executeCallback(promise, callback);
						return promise;
					}
					var asyncStorage = {
						_driver: "asyncStorage",
						_initStorage,
						_support: isIndexedDBValid(),
						iterate,
						getItem,
						setItem,
						removeItem,
						clear,
						length,
						key,
						keys,
						dropInstance
					};
					function isWebSQLValid() {
						return typeof openDatabase === "function";
					}
					var BASE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
					var BLOB_TYPE_PREFIX = "~~local_forage_type~";
					var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
					var SERIALIZED_MARKER = "__lfsc__:";
					var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
					var TYPE_ARRAYBUFFER = "arbf";
					var TYPE_BLOB = "blob";
					var TYPE_INT8ARRAY = "si08";
					var TYPE_UINT8ARRAY = "ui08";
					var TYPE_UINT8CLAMPEDARRAY = "uic8";
					var TYPE_INT16ARRAY = "si16";
					var TYPE_INT32ARRAY = "si32";
					var TYPE_UINT16ARRAY = "ur16";
					var TYPE_UINT32ARRAY = "ui32";
					var TYPE_FLOAT32ARRAY = "fl32";
					var TYPE_FLOAT64ARRAY = "fl64";
					var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;
					var toString$1 = Object.prototype.toString;
					function stringToBuffer(serializedString) {
						var bufferLength = serializedString.length * .75;
						var len = serializedString.length;
						var i;
						var p = 0;
						var encoded1, encoded2, encoded3, encoded4;
						if (serializedString[serializedString.length - 1] === "=") {
							bufferLength--;
							if (serializedString[serializedString.length - 2] === "=") bufferLength--;
						}
						var buffer = new ArrayBuffer(bufferLength);
						var bytes = new Uint8Array(buffer);
						for (i = 0; i < len; i += 4) {
							encoded1 = BASE_CHARS.indexOf(serializedString[i]);
							encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);
							encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);
							encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);
							bytes[p++] = encoded1 << 2 | encoded2 >> 4;
							bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;
							bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;
						}
						return buffer;
					}
					function bufferToString(buffer) {
						var bytes = new Uint8Array(buffer);
						var base64String = "";
						var i;
						for (i = 0; i < bytes.length; i += 3) {
							base64String += BASE_CHARS[bytes[i] >> 2];
							base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];
							base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];
							base64String += BASE_CHARS[bytes[i + 2] & 63];
						}
						if (bytes.length % 3 === 2) base64String = base64String.substring(0, base64String.length - 1) + "=";
						else if (bytes.length % 3 === 1) base64String = base64String.substring(0, base64String.length - 2) + "==";
						return base64String;
					}
					function serialize(value, callback) {
						var valueType = "";
						if (value) valueType = toString$1.call(value);
						if (value && (valueType === "[object ArrayBuffer]" || value.buffer && toString$1.call(value.buffer) === "[object ArrayBuffer]")) {
							var buffer;
							var marker = SERIALIZED_MARKER;
							if (value instanceof ArrayBuffer) {
								buffer = value;
								marker += TYPE_ARRAYBUFFER;
							} else {
								buffer = value.buffer;
								if (valueType === "[object Int8Array]") marker += TYPE_INT8ARRAY;
								else if (valueType === "[object Uint8Array]") marker += TYPE_UINT8ARRAY;
								else if (valueType === "[object Uint8ClampedArray]") marker += TYPE_UINT8CLAMPEDARRAY;
								else if (valueType === "[object Int16Array]") marker += TYPE_INT16ARRAY;
								else if (valueType === "[object Uint16Array]") marker += TYPE_UINT16ARRAY;
								else if (valueType === "[object Int32Array]") marker += TYPE_INT32ARRAY;
								else if (valueType === "[object Uint32Array]") marker += TYPE_UINT32ARRAY;
								else if (valueType === "[object Float32Array]") marker += TYPE_FLOAT32ARRAY;
								else if (valueType === "[object Float64Array]") marker += TYPE_FLOAT64ARRAY;
								else callback(new Error("Failed to get type for BinaryArray"));
							}
							callback(marker + bufferToString(buffer));
						} else if (valueType === "[object Blob]") {
							var fileReader = new FileReader();
							fileReader.onload = function() {
								var str = BLOB_TYPE_PREFIX + value.type + "~" + bufferToString(this.result);
								callback(SERIALIZED_MARKER + TYPE_BLOB + str);
							};
							fileReader.readAsArrayBuffer(value);
						} else try {
							callback(JSON.stringify(value));
						} catch (e) {
							console.error("Couldn't convert value into a JSON string: ", value);
							callback(null, e);
						}
					}
					function deserialize(value) {
						if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) return JSON.parse(value);
						var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
						var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
						var blobType;
						if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
							var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
							blobType = matcher[1];
							serializedString = serializedString.substring(matcher[0].length);
						}
						var buffer = stringToBuffer(serializedString);
						switch (type) {
							case TYPE_ARRAYBUFFER: return buffer;
							case TYPE_BLOB: return createBlob([buffer], { type: blobType });
							case TYPE_INT8ARRAY: return new Int8Array(buffer);
							case TYPE_UINT8ARRAY: return new Uint8Array(buffer);
							case TYPE_UINT8CLAMPEDARRAY: return new Uint8ClampedArray(buffer);
							case TYPE_INT16ARRAY: return new Int16Array(buffer);
							case TYPE_UINT16ARRAY: return new Uint16Array(buffer);
							case TYPE_INT32ARRAY: return new Int32Array(buffer);
							case TYPE_UINT32ARRAY: return new Uint32Array(buffer);
							case TYPE_FLOAT32ARRAY: return new Float32Array(buffer);
							case TYPE_FLOAT64ARRAY: return new Float64Array(buffer);
							default: throw new Error("Unkown type: " + type);
						}
					}
					var localforageSerializer = {
						serialize,
						deserialize,
						stringToBuffer,
						bufferToString
					};
					function createDbTable(t, dbInfo, callback, errorCallback) {
						t.executeSql("CREATE TABLE IF NOT EXISTS " + dbInfo.storeName + " (id INTEGER PRIMARY KEY, key unique, value)", [], callback, errorCallback);
					}
					function _initStorage$1(options) {
						var self = this;
						var dbInfo = { db: null };
						if (options) for (var i in options) dbInfo[i] = typeof options[i] !== "string" ? options[i].toString() : options[i];
						var dbInfoPromise = new Promise$1(function(resolve, reject) {
							try {
								dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size);
							} catch (e) {
								return reject(e);
							}
							dbInfo.db.transaction(function(t) {
								createDbTable(t, dbInfo, function() {
									self._dbInfo = dbInfo;
									resolve();
								}, function(t, error) {
									reject(error);
								});
							}, reject);
						});
						dbInfo.serializer = localforageSerializer;
						return dbInfoPromise;
					}
					function tryExecuteSql(t, dbInfo, sqlStatement, args, callback, errorCallback) {
						t.executeSql(sqlStatement, args, callback, function(t, error) {
							if (error.code === error.SYNTAX_ERR) t.executeSql("SELECT name FROM sqlite_master WHERE type='table' AND name = ?", [dbInfo.storeName], function(t, results) {
								if (!results.rows.length) createDbTable(t, dbInfo, function() {
									t.executeSql(sqlStatement, args, callback, errorCallback);
								}, errorCallback);
								else errorCallback(t, error);
							}, errorCallback);
							else errorCallback(t, error);
						}, errorCallback);
					}
					function getItem$1(key, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								var dbInfo = self._dbInfo;
								dbInfo.db.transaction(function(t) {
									tryExecuteSql(t, dbInfo, "SELECT * FROM " + dbInfo.storeName + " WHERE key = ? LIMIT 1", [key], function(t, results) {
										var result = results.rows.length ? results.rows.item(0).value : null;
										if (result) result = dbInfo.serializer.deserialize(result);
										resolve(result);
									}, function(t, error) {
										reject(error);
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function iterate$1(iterator, callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								var dbInfo = self._dbInfo;
								dbInfo.db.transaction(function(t) {
									tryExecuteSql(t, dbInfo, "SELECT * FROM " + dbInfo.storeName, [], function(t, results) {
										var rows = results.rows;
										var length = rows.length;
										for (var i = 0; i < length; i++) {
											var item = rows.item(i);
											var result = item.value;
											if (result) result = dbInfo.serializer.deserialize(result);
											result = iterator(result, item.key, i + 1);
											if (result !== void 0) {
												resolve(result);
												return;
											}
										}
										resolve();
									}, function(t, error) {
										reject(error);
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function _setItem(key, value, callback, retriesLeft) {
						var self = this;
						key = normalizeKey(key);
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								if (value === void 0) value = null;
								var originalValue = value;
								var dbInfo = self._dbInfo;
								dbInfo.serializer.serialize(value, function(value, error) {
									if (error) reject(error);
									else dbInfo.db.transaction(function(t) {
										tryExecuteSql(t, dbInfo, "INSERT OR REPLACE INTO " + dbInfo.storeName + " (key, value) VALUES (?, ?)", [key, value], function() {
											resolve(originalValue);
										}, function(t, error) {
											reject(error);
										});
									}, function(sqlError) {
										if (sqlError.code === sqlError.QUOTA_ERR) {
											if (retriesLeft > 0) {
												resolve(_setItem.apply(self, [
													key,
													originalValue,
													callback,
													retriesLeft - 1
												]));
												return;
											}
											reject(sqlError);
										}
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function setItem$1(key, value, callback) {
						return _setItem.apply(this, [
							key,
							value,
							callback,
							1
						]);
					}
					function removeItem$1(key, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								var dbInfo = self._dbInfo;
								dbInfo.db.transaction(function(t) {
									tryExecuteSql(t, dbInfo, "DELETE FROM " + dbInfo.storeName + " WHERE key = ?", [key], function() {
										resolve();
									}, function(t, error) {
										reject(error);
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function clear$1(callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								var dbInfo = self._dbInfo;
								dbInfo.db.transaction(function(t) {
									tryExecuteSql(t, dbInfo, "DELETE FROM " + dbInfo.storeName, [], function() {
										resolve();
									}, function(t, error) {
										reject(error);
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function length$1(callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								var dbInfo = self._dbInfo;
								dbInfo.db.transaction(function(t) {
									tryExecuteSql(t, dbInfo, "SELECT COUNT(key) as c FROM " + dbInfo.storeName, [], function(t, results) {
										var result = results.rows.item(0).c;
										resolve(result);
									}, function(t, error) {
										reject(error);
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function key$1(n, callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								var dbInfo = self._dbInfo;
								dbInfo.db.transaction(function(t) {
									tryExecuteSql(t, dbInfo, "SELECT key FROM " + dbInfo.storeName + " WHERE id = ? LIMIT 1", [n + 1], function(t, results) {
										resolve(results.rows.length ? results.rows.item(0).key : null);
									}, function(t, error) {
										reject(error);
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function keys$1(callback) {
						var self = this;
						var promise = new Promise$1(function(resolve, reject) {
							self.ready().then(function() {
								var dbInfo = self._dbInfo;
								dbInfo.db.transaction(function(t) {
									tryExecuteSql(t, dbInfo, "SELECT key FROM " + dbInfo.storeName, [], function(t, results) {
										var keys = [];
										for (var i = 0; i < results.rows.length; i++) keys.push(results.rows.item(i).key);
										resolve(keys);
									}, function(t, error) {
										reject(error);
									});
								});
							})["catch"](reject);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function getAllStoreNames(db) {
						return new Promise$1(function(resolve, reject) {
							db.transaction(function(t) {
								t.executeSql("SELECT name FROM sqlite_master WHERE type='table' AND name <> '__WebKitDatabaseInfoTable__'", [], function(t, results) {
									var storeNames = [];
									for (var i = 0; i < results.rows.length; i++) storeNames.push(results.rows.item(i).name);
									resolve({
										db,
										storeNames
									});
								}, function(t, error) {
									reject(error);
								});
							}, function(sqlError) {
								reject(sqlError);
							});
						});
					}
					function dropInstance$1(options, callback) {
						callback = getCallback.apply(this, arguments);
						var currentConfig = this.config();
						options = typeof options !== "function" && options || {};
						if (!options.name) {
							options.name = options.name || currentConfig.name;
							options.storeName = options.storeName || currentConfig.storeName;
						}
						var self = this;
						var promise;
						if (!options.name) promise = Promise$1.reject("Invalid arguments");
						else promise = new Promise$1(function(resolve) {
							var db;
							if (options.name === currentConfig.name) db = self._dbInfo.db;
							else db = openDatabase(options.name, "", "", 0);
							if (!options.storeName) resolve(getAllStoreNames(db));
							else resolve({
								db,
								storeNames: [options.storeName]
							});
						}).then(function(operationInfo) {
							return new Promise$1(function(resolve, reject) {
								operationInfo.db.transaction(function(t) {
									function dropTable(storeName) {
										return new Promise$1(function(resolve, reject) {
											t.executeSql("DROP TABLE IF EXISTS " + storeName, [], function() {
												resolve();
											}, function(t, error) {
												reject(error);
											});
										});
									}
									var operations = [];
									for (var i = 0, len = operationInfo.storeNames.length; i < len; i++) operations.push(dropTable(operationInfo.storeNames[i]));
									Promise$1.all(operations).then(function() {
										resolve();
									})["catch"](function(e) {
										reject(e);
									});
								}, function(sqlError) {
									reject(sqlError);
								});
							});
						});
						executeCallback(promise, callback);
						return promise;
					}
					var webSQLStorage = {
						_driver: "webSQLStorage",
						_initStorage: _initStorage$1,
						_support: isWebSQLValid(),
						iterate: iterate$1,
						getItem: getItem$1,
						setItem: setItem$1,
						removeItem: removeItem$1,
						clear: clear$1,
						length: length$1,
						key: key$1,
						keys: keys$1,
						dropInstance: dropInstance$1
					};
					function isLocalStorageValid() {
						try {
							return typeof localStorage !== "undefined" && "setItem" in localStorage && !!localStorage.setItem;
						} catch (e) {
							return false;
						}
					}
					function _getKeyPrefix(options, defaultConfig) {
						var keyPrefix = options.name + "/";
						if (options.storeName !== defaultConfig.storeName) keyPrefix += options.storeName + "/";
						return keyPrefix;
					}
					function checkIfLocalStorageThrows() {
						var localStorageTestKey = "_localforage_support_test";
						try {
							localStorage.setItem(localStorageTestKey, true);
							localStorage.removeItem(localStorageTestKey);
							return false;
						} catch (e) {
							return true;
						}
					}
					function _isLocalStorageUsable() {
						return !checkIfLocalStorageThrows() || localStorage.length > 0;
					}
					function _initStorage$2(options) {
						var self = this;
						var dbInfo = {};
						if (options) for (var i in options) dbInfo[i] = options[i];
						dbInfo.keyPrefix = _getKeyPrefix(options, self._defaultConfig);
						if (!_isLocalStorageUsable()) return Promise$1.reject();
						self._dbInfo = dbInfo;
						dbInfo.serializer = localforageSerializer;
						return Promise$1.resolve();
					}
					function clear$2(callback) {
						var self = this;
						var promise = self.ready().then(function() {
							var keyPrefix = self._dbInfo.keyPrefix;
							for (var i = localStorage.length - 1; i >= 0; i--) {
								var key = localStorage.key(i);
								if (key.indexOf(keyPrefix) === 0) localStorage.removeItem(key);
							}
						});
						executeCallback(promise, callback);
						return promise;
					}
					function getItem$2(key, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = self.ready().then(function() {
							var dbInfo = self._dbInfo;
							var result = localStorage.getItem(dbInfo.keyPrefix + key);
							if (result) result = dbInfo.serializer.deserialize(result);
							return result;
						});
						executeCallback(promise, callback);
						return promise;
					}
					function iterate$2(iterator, callback) {
						var self = this;
						var promise = self.ready().then(function() {
							var dbInfo = self._dbInfo;
							var keyPrefix = dbInfo.keyPrefix;
							var keyPrefixLength = keyPrefix.length;
							var length = localStorage.length;
							var iterationNumber = 1;
							for (var i = 0; i < length; i++) {
								var key = localStorage.key(i);
								if (key.indexOf(keyPrefix) !== 0) continue;
								var value = localStorage.getItem(key);
								if (value) value = dbInfo.serializer.deserialize(value);
								value = iterator(value, key.substring(keyPrefixLength), iterationNumber++);
								if (value !== void 0) return value;
							}
						});
						executeCallback(promise, callback);
						return promise;
					}
					function key$2(n, callback) {
						var self = this;
						var promise = self.ready().then(function() {
							var dbInfo = self._dbInfo;
							var result;
							try {
								result = localStorage.key(n);
							} catch (error) {
								result = null;
							}
							if (result) result = result.substring(dbInfo.keyPrefix.length);
							return result;
						});
						executeCallback(promise, callback);
						return promise;
					}
					function keys$2(callback) {
						var self = this;
						var promise = self.ready().then(function() {
							var dbInfo = self._dbInfo;
							var length = localStorage.length;
							var keys = [];
							for (var i = 0; i < length; i++) {
								var itemKey = localStorage.key(i);
								if (itemKey.indexOf(dbInfo.keyPrefix) === 0) keys.push(itemKey.substring(dbInfo.keyPrefix.length));
							}
							return keys;
						});
						executeCallback(promise, callback);
						return promise;
					}
					function length$2(callback) {
						var promise = this.keys().then(function(keys) {
							return keys.length;
						});
						executeCallback(promise, callback);
						return promise;
					}
					function removeItem$2(key, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = self.ready().then(function() {
							var dbInfo = self._dbInfo;
							localStorage.removeItem(dbInfo.keyPrefix + key);
						});
						executeCallback(promise, callback);
						return promise;
					}
					function setItem$2(key, value, callback) {
						var self = this;
						key = normalizeKey(key);
						var promise = self.ready().then(function() {
							if (value === void 0) value = null;
							var originalValue = value;
							return new Promise$1(function(resolve, reject) {
								var dbInfo = self._dbInfo;
								dbInfo.serializer.serialize(value, function(value, error) {
									if (error) reject(error);
									else try {
										localStorage.setItem(dbInfo.keyPrefix + key, value);
										resolve(originalValue);
									} catch (e) {
										if (e.name === "QuotaExceededError" || e.name === "NS_ERROR_DOM_QUOTA_REACHED") reject(e);
										reject(e);
									}
								});
							});
						});
						executeCallback(promise, callback);
						return promise;
					}
					function dropInstance$2(options, callback) {
						callback = getCallback.apply(this, arguments);
						options = typeof options !== "function" && options || {};
						if (!options.name) {
							var currentConfig = this.config();
							options.name = options.name || currentConfig.name;
							options.storeName = options.storeName || currentConfig.storeName;
						}
						var self = this;
						var promise;
						if (!options.name) promise = Promise$1.reject("Invalid arguments");
						else promise = new Promise$1(function(resolve) {
							if (!options.storeName) resolve(options.name + "/");
							else resolve(_getKeyPrefix(options, self._defaultConfig));
						}).then(function(keyPrefix) {
							for (var i = localStorage.length - 1; i >= 0; i--) {
								var key = localStorage.key(i);
								if (key.indexOf(keyPrefix) === 0) localStorage.removeItem(key);
							}
						});
						executeCallback(promise, callback);
						return promise;
					}
					var localStorageWrapper = {
						_driver: "localStorageWrapper",
						_initStorage: _initStorage$2,
						_support: isLocalStorageValid(),
						iterate: iterate$2,
						getItem: getItem$2,
						setItem: setItem$2,
						removeItem: removeItem$2,
						clear: clear$2,
						length: length$2,
						key: key$2,
						keys: keys$2,
						dropInstance: dropInstance$2
					};
					var sameValue = function sameValue(x, y) {
						return x === y || typeof x === "number" && typeof y === "number" && isNaN(x) && isNaN(y);
					};
					var includes = function includes(array, searchElement) {
						var len = array.length;
						var i = 0;
						while (i < len) {
							if (sameValue(array[i], searchElement)) return true;
							i++;
						}
						return false;
					};
					var isArray = Array.isArray || function(arg) {
						return Object.prototype.toString.call(arg) === "[object Array]";
					};
					var DefinedDrivers = {};
					var DriverSupport = {};
					var DefaultDrivers = {
						INDEXEDDB: asyncStorage,
						WEBSQL: webSQLStorage,
						LOCALSTORAGE: localStorageWrapper
					};
					var DefaultDriverOrder = [
						DefaultDrivers.INDEXEDDB._driver,
						DefaultDrivers.WEBSQL._driver,
						DefaultDrivers.LOCALSTORAGE._driver
					];
					var OptionalDriverMethods = ["dropInstance"];
					var LibraryMethods = [
						"clear",
						"getItem",
						"iterate",
						"key",
						"keys",
						"length",
						"removeItem",
						"setItem"
					].concat(OptionalDriverMethods);
					var DefaultConfig = {
						description: "",
						driver: DefaultDriverOrder.slice(),
						name: "localforage",
						size: 4980736,
						storeName: "keyvaluepairs",
						version: 1
					};
					function callWhenReady(localForageInstance, libraryMethod) {
						localForageInstance[libraryMethod] = function() {
							var _args = arguments;
							return localForageInstance.ready().then(function() {
								return localForageInstance[libraryMethod].apply(localForageInstance, _args);
							});
						};
					}
					function extend() {
						for (var i = 1; i < arguments.length; i++) {
							var arg = arguments[i];
							if (arg) {
								for (var _key in arg) if (arg.hasOwnProperty(_key)) if (isArray(arg[_key])) arguments[0][_key] = arg[_key].slice();
								else arguments[0][_key] = arg[_key];
							}
						}
						return arguments[0];
					}
					module$4.exports = new (function() {
						function LocalForage(options) {
							_classCallCheck(this, LocalForage);
							for (var driverTypeKey in DefaultDrivers) if (DefaultDrivers.hasOwnProperty(driverTypeKey)) {
								var driver = DefaultDrivers[driverTypeKey];
								var driverName = driver._driver;
								this[driverTypeKey] = driverName;
								if (!DefinedDrivers[driverName]) this.defineDriver(driver);
							}
							this._defaultConfig = extend({}, DefaultConfig);
							this._config = extend({}, this._defaultConfig, options);
							this._driverSet = null;
							this._initDriver = null;
							this._ready = false;
							this._dbInfo = null;
							this._wrapLibraryMethodsWithReady();
							this.setDriver(this._config.driver)["catch"](function() {});
						}
						LocalForage.prototype.config = function config(options) {
							if ((typeof options === "undefined" ? "undefined" : _typeof(options)) === "object") {
								if (this._ready) return new Error("Can't call config() after localforage has been used.");
								for (var i in options) {
									if (i === "storeName") options[i] = options[i].replace(/\W/g, "_");
									if (i === "version" && typeof options[i] !== "number") return new Error("Database version must be a number.");
									this._config[i] = options[i];
								}
								if ("driver" in options && options.driver) return this.setDriver(this._config.driver);
								return true;
							} else if (typeof options === "string") return this._config[options];
							else return this._config;
						};
						LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) {
							var promise = new Promise$1(function(resolve, reject) {
								try {
									var driverName = driverObject._driver;
									var complianceError = new Error("Custom driver not compliant; see https://mozilla.github.io/localForage/#definedriver");
									if (!driverObject._driver) {
										reject(complianceError);
										return;
									}
									var driverMethods = LibraryMethods.concat("_initStorage");
									for (var i = 0, len = driverMethods.length; i < len; i++) {
										var driverMethodName = driverMethods[i];
										if ((!includes(OptionalDriverMethods, driverMethodName) || driverObject[driverMethodName]) && typeof driverObject[driverMethodName] !== "function") {
											reject(complianceError);
											return;
										}
									}
									(function configureMissingMethods() {
										var methodNotImplementedFactory = function methodNotImplementedFactory(methodName) {
											return function() {
												var error = new Error("Method " + methodName + " is not implemented by the current driver");
												var promise = Promise$1.reject(error);
												executeCallback(promise, arguments[arguments.length - 1]);
												return promise;
											};
										};
										for (var _i = 0, _len = OptionalDriverMethods.length; _i < _len; _i++) {
											var optionalDriverMethod = OptionalDriverMethods[_i];
											if (!driverObject[optionalDriverMethod]) driverObject[optionalDriverMethod] = methodNotImplementedFactory(optionalDriverMethod);
										}
									})();
									var setDriverSupport = function setDriverSupport(support) {
										if (DefinedDrivers[driverName]) console.info("Redefining LocalForage driver: " + driverName);
										DefinedDrivers[driverName] = driverObject;
										DriverSupport[driverName] = support;
										resolve();
									};
									if ("_support" in driverObject) if (driverObject._support && typeof driverObject._support === "function") driverObject._support().then(setDriverSupport, reject);
									else setDriverSupport(!!driverObject._support);
									else setDriverSupport(true);
								} catch (e) {
									reject(e);
								}
							});
							executeTwoCallbacks(promise, callback, errorCallback);
							return promise;
						};
						LocalForage.prototype.driver = function driver() {
							return this._driver || null;
						};
						LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) {
							var getDriverPromise = DefinedDrivers[driverName] ? Promise$1.resolve(DefinedDrivers[driverName]) : Promise$1.reject(new Error("Driver not found."));
							executeTwoCallbacks(getDriverPromise, callback, errorCallback);
							return getDriverPromise;
						};
						LocalForage.prototype.getSerializer = function getSerializer(callback) {
							var serializerPromise = Promise$1.resolve(localforageSerializer);
							executeTwoCallbacks(serializerPromise, callback);
							return serializerPromise;
						};
						LocalForage.prototype.ready = function ready(callback) {
							var self = this;
							var promise = self._driverSet.then(function() {
								if (self._ready === null) self._ready = self._initDriver();
								return self._ready;
							});
							executeTwoCallbacks(promise, callback, callback);
							return promise;
						};
						LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) {
							var self = this;
							if (!isArray(drivers)) drivers = [drivers];
							var supportedDrivers = this._getSupportedDrivers(drivers);
							function setDriverToConfig() {
								self._config.driver = self.driver();
							}
							function extendSelfWithDriver(driver) {
								self._extend(driver);
								setDriverToConfig();
								self._ready = self._initStorage(self._config);
								return self._ready;
							}
							function initDriver(supportedDrivers) {
								return function() {
									var currentDriverIndex = 0;
									function driverPromiseLoop() {
										while (currentDriverIndex < supportedDrivers.length) {
											var driverName = supportedDrivers[currentDriverIndex];
											currentDriverIndex++;
											self._dbInfo = null;
											self._ready = null;
											return self.getDriver(driverName).then(extendSelfWithDriver)["catch"](driverPromiseLoop);
										}
										setDriverToConfig();
										var error = new Error("No available storage method found.");
										self._driverSet = Promise$1.reject(error);
										return self._driverSet;
									}
									return driverPromiseLoop();
								};
							}
							var oldDriverSetDone = this._driverSet !== null ? this._driverSet["catch"](function() {
								return Promise$1.resolve();
							}) : Promise$1.resolve();
							this._driverSet = oldDriverSetDone.then(function() {
								var driverName = supportedDrivers[0];
								self._dbInfo = null;
								self._ready = null;
								return self.getDriver(driverName).then(function(driver) {
									self._driver = driver._driver;
									setDriverToConfig();
									self._wrapLibraryMethodsWithReady();
									self._initDriver = initDriver(supportedDrivers);
								});
							})["catch"](function() {
								setDriverToConfig();
								var error = new Error("No available storage method found.");
								self._driverSet = Promise$1.reject(error);
								return self._driverSet;
							});
							executeTwoCallbacks(this._driverSet, callback, errorCallback);
							return this._driverSet;
						};
						LocalForage.prototype.supports = function supports(driverName) {
							return !!DriverSupport[driverName];
						};
						LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) {
							extend(this, libraryMethodsAndProperties);
						};
						LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) {
							var supportedDrivers = [];
							for (var i = 0, len = drivers.length; i < len; i++) {
								var driverName = drivers[i];
								if (this.supports(driverName)) supportedDrivers.push(driverName);
							}
							return supportedDrivers;
						};
						LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() {
							for (var i = 0, len = LibraryMethods.length; i < len; i++) callWhenReady(this, LibraryMethods[i]);
						};
						LocalForage.prototype.createInstance = function createInstance(options) {
							return new LocalForage(options);
						};
						return LocalForage;
					}())();
				}, { "3": 3 }]
			}, {}, [4])(4);
		});
	}));
	var require_viewer = __commonJSMin(((exports, module) => {
		(function(global, factory) {
			typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, global.Viewer = factory());
		})(exports, (function() {
			"use strict";
			function ownKeys(object, enumerableOnly) {
				var keys = Object.keys(object);
				if (Object.getOwnPropertySymbols) {
					var symbols = Object.getOwnPropertySymbols(object);
					enumerableOnly && (symbols = symbols.filter(function(sym) {
						return Object.getOwnPropertyDescriptor(object, sym).enumerable;
					})), keys.push.apply(keys, symbols);
				}
				return keys;
			}
			function _objectSpread2(target) {
				for (var i = 1; i < arguments.length; i++) {
					var source = null != arguments[i] ? arguments[i] : {};
					i % 2 ? ownKeys(Object(source), !0).forEach(function(key) {
						_defineProperty(target, key, source[key]);
					}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function(key) {
						Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
					});
				}
				return target;
			}
			function _typeof(obj) {
				"@babel/helpers - typeof";
				return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
					return typeof obj;
				} : function(obj) {
					return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
				}, _typeof(obj);
			}
			function _classCallCheck(instance, Constructor) {
				if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
			}
			function _defineProperties(target, props) {
				for (var i = 0; i < props.length; i++) {
					var descriptor = props[i];
					descriptor.enumerable = descriptor.enumerable || false;
					descriptor.configurable = true;
					if ("value" in descriptor) descriptor.writable = true;
					Object.defineProperty(target, descriptor.key, descriptor);
				}
			}
			function _createClass(Constructor, protoProps, staticProps) {
				if (protoProps) _defineProperties(Constructor.prototype, protoProps);
				if (staticProps) _defineProperties(Constructor, staticProps);
				Object.defineProperty(Constructor, "prototype", { writable: false });
				return Constructor;
			}
			function _defineProperty(obj, key, value) {
				if (key in obj) Object.defineProperty(obj, key, {
					value,
					enumerable: true,
					configurable: true,
					writable: true
				});
				else obj[key] = value;
				return obj;
			}
			var DEFAULTS = {
				backdrop: true,
				button: true,
				navbar: true,
				title: true,
				toolbar: true,
				className: "",
				container: "body",
				filter: null,
				fullscreen: true,
				inheritedAttributes: [
					"crossOrigin",
					"decoding",
					"isMap",
					"loading",
					"referrerPolicy",
					"sizes",
					"srcset",
					"useMap"
				],
				initialCoverage: .9,
				initialViewIndex: 0,
				inline: false,
				interval: 5e3,
				keyboard: true,
				focus: true,
				loading: true,
				loop: true,
				minWidth: 200,
				minHeight: 100,
				movable: true,
				rotatable: true,
				scalable: true,
				zoomable: true,
				zoomOnTouch: true,
				zoomOnWheel: true,
				slideOnTouch: true,
				toggleOnDblclick: true,
				tooltip: true,
				transition: true,
				zIndex: 2015,
				zIndexInline: 0,
				zoomRatio: .1,
				minZoomRatio: .01,
				maxZoomRatio: 100,
				url: "src",
				ready: null,
				show: null,
				shown: null,
				hide: null,
				hidden: null,
				view: null,
				viewed: null,
				move: null,
				moved: null,
				rotate: null,
				rotated: null,
				scale: null,
				scaled: null,
				zoom: null,
				zoomed: null,
				play: null,
				stop: null
			};
			var TEMPLATE = "<div class=\"viewer-container\" tabindex=\"-1\" touch-action=\"none\"><div class=\"viewer-canvas\"></div><div class=\"viewer-footer\"><div class=\"viewer-title\"></div><div class=\"viewer-toolbar\"></div><div class=\"viewer-navbar\"><ul class=\"viewer-list\" role=\"navigation\"></ul></div></div><div class=\"viewer-tooltip\" role=\"alert\" aria-hidden=\"true\"></div><div class=\"viewer-button\" data-viewer-action=\"mix\" role=\"button\"></div><div class=\"viewer-player\"></div></div>";
			var IS_BROWSER = typeof window !== "undefined" && typeof window.document !== "undefined";
			var WINDOW = IS_BROWSER ? window : {};
			var IS_TOUCH_DEVICE = IS_BROWSER && WINDOW.document.documentElement ? "ontouchstart" in WINDOW.document.documentElement : false;
			var HAS_POINTER_EVENT = IS_BROWSER ? "PointerEvent" in WINDOW : false;
			var NAMESPACE = "viewer";
			var ACTION_MOVE = "move";
			var ACTION_SWITCH = "switch";
			var ACTION_ZOOM = "zoom";
			var CLASS_ACTIVE = "".concat(NAMESPACE, "-active");
			var CLASS_CLOSE = "".concat(NAMESPACE, "-close");
			var CLASS_FADE = "".concat(NAMESPACE, "-fade");
			var CLASS_FIXED = "".concat(NAMESPACE, "-fixed");
			var CLASS_FULLSCREEN = "".concat(NAMESPACE, "-fullscreen");
			var CLASS_FULLSCREEN_EXIT = "".concat(NAMESPACE, "-fullscreen-exit");
			var CLASS_HIDE = "".concat(NAMESPACE, "-hide");
			var CLASS_HIDE_MD_DOWN = "".concat(NAMESPACE, "-hide-md-down");
			var CLASS_HIDE_SM_DOWN = "".concat(NAMESPACE, "-hide-sm-down");
			var CLASS_HIDE_XS_DOWN = "".concat(NAMESPACE, "-hide-xs-down");
			var CLASS_IN = "".concat(NAMESPACE, "-in");
			var CLASS_INVISIBLE = "".concat(NAMESPACE, "-invisible");
			var CLASS_LOADING = "".concat(NAMESPACE, "-loading");
			var CLASS_MOVE = "".concat(NAMESPACE, "-move");
			var CLASS_OPEN = "".concat(NAMESPACE, "-open");
			var CLASS_SHOW = "".concat(NAMESPACE, "-show");
			var CLASS_TRANSITION = "".concat(NAMESPACE, "-transition");
			var EVENT_CLICK = "click";
			var EVENT_DBLCLICK = "dblclick";
			var EVENT_DRAG_START = "dragstart";
			var EVENT_FOCUSIN = "focusin";
			var EVENT_KEY_DOWN = "keydown";
			var EVENT_LOAD = "load";
			var EVENT_ERROR = "error";
			var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? "touchend touchcancel" : "mouseup";
			var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? "touchmove" : "mousemove";
			var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? "pointerdown" : IS_TOUCH_DEVICE ? "touchstart" : "mousedown";
			var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? "pointermove" : EVENT_TOUCH_MOVE;
			var EVENT_POINTER_UP = HAS_POINTER_EVENT ? "pointerup pointercancel" : EVENT_TOUCH_END;
			var EVENT_RESIZE = "resize";
			var EVENT_TRANSITION_END = "transitionend";
			var EVENT_WHEEL = "wheel";
			var EVENT_READY = "ready";
			var EVENT_SHOW = "show";
			var EVENT_SHOWN = "shown";
			var EVENT_HIDE = "hide";
			var EVENT_HIDDEN = "hidden";
			var EVENT_VIEW = "view";
			var EVENT_VIEWED = "viewed";
			var EVENT_MOVE = "move";
			var EVENT_MOVED = "moved";
			var EVENT_ROTATE = "rotate";
			var EVENT_ROTATED = "rotated";
			var EVENT_SCALE = "scale";
			var EVENT_SCALED = "scaled";
			var EVENT_ZOOM = "zoom";
			var EVENT_ZOOMED = "zoomed";
			var EVENT_PLAY = "play";
			var EVENT_STOP = "stop";
			var DATA_ACTION = "".concat(NAMESPACE, "Action");
			var REGEXP_SPACES = /\s\s*/;
			var BUTTONS = [
				"zoom-in",
				"zoom-out",
				"one-to-one",
				"reset",
				"prev",
				"play",
				"next",
				"rotate-left",
				"rotate-right",
				"flip-horizontal",
				"flip-vertical"
			];
			function isString(value) {
				return typeof value === "string";
			}
			var isNaN = Number.isNaN || WINDOW.isNaN;
			function isNumber(value) {
				return typeof value === "number" && !isNaN(value);
			}
			function isUndefined(value) {
				return typeof value === "undefined";
			}
			function isObject(value) {
				return _typeof(value) === "object" && value !== null;
			}
			var hasOwnProperty = Object.prototype.hasOwnProperty;
			function isPlainObject(value) {
				if (!isObject(value)) return false;
				try {
					var _constructor = value.constructor;
					var prototype = _constructor.prototype;
					return _constructor && prototype && hasOwnProperty.call(prototype, "isPrototypeOf");
				} catch (error) {
					return false;
				}
			}
			function isFunction(value) {
				return typeof value === "function";
			}
			function forEach(data, callback) {
				if (data && isFunction(callback)) {
					if (Array.isArray(data) || isNumber(data.length)) {
						var length = data.length;
						var i;
						for (i = 0; i < length; i += 1) if (callback.call(data, data[i], i, data) === false) break;
					} else if (isObject(data)) Object.keys(data).forEach(function(key) {
						callback.call(data, data[key], key, data);
					});
				}
				return data;
			}
			var assign = Object.assign || function assign(obj) {
				for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) args[_key - 1] = arguments[_key];
				if (isObject(obj) && args.length > 0) args.forEach(function(arg) {
					if (isObject(arg)) Object.keys(arg).forEach(function(key) {
						obj[key] = arg[key];
					});
				});
				return obj;
			};
			var REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/;
			function setStyle(element, styles) {
				var style = element.style;
				forEach(styles, function(value, property) {
					if (REGEXP_SUFFIX.test(property) && isNumber(value)) value += "px";
					style[property] = value;
				});
			}
			function escapeHTMLEntities(value) {
				return isString(value) ? value.replace(/&(?!amp;|quot;|#39;|lt;|gt;)/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;") : value;
			}
			function hasClass(element, value) {
				if (!element || !value) return false;
				return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;
			}
			function addClass(element, value) {
				if (!element || !value) return;
				if (isNumber(element.length)) {
					forEach(element, function(elem) {
						addClass(elem, value);
					});
					return;
				}
				if (element.classList) {
					element.classList.add(value);
					return;
				}
				var className = element.className.trim();
				if (!className) element.className = value;
				else if (className.indexOf(value) < 0) element.className = "".concat(className, " ").concat(value);
			}
			function removeClass(element, value) {
				if (!element || !value) return;
				if (isNumber(element.length)) {
					forEach(element, function(elem) {
						removeClass(elem, value);
					});
					return;
				}
				if (element.classList) {
					element.classList.remove(value);
					return;
				}
				if (element.className.indexOf(value) >= 0) element.className = element.className.replace(value, "");
			}
			function toggleClass(element, value, added) {
				if (!value) return;
				if (isNumber(element.length)) {
					forEach(element, function(elem) {
						toggleClass(elem, value, added);
					});
					return;
				}
				if (added) addClass(element, value);
				else removeClass(element, value);
			}
			var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
			function hyphenate(value) {
				return value.replace(REGEXP_HYPHENATE, "$1-$2").toLowerCase();
			}
			function getData(element, name) {
				if (isObject(element[name])) return element[name];
				if (element.dataset) return element.dataset[name];
				return element.getAttribute("data-".concat(hyphenate(name)));
			}
			function setData(element, name, data) {
				if (isObject(data)) element[name] = data;
				else if (element.dataset) element.dataset[name] = data;
				else element.setAttribute("data-".concat(hyphenate(name)), data);
			}
			var onceSupported = function() {
				var supported = false;
				if (IS_BROWSER) {
					var once = false;
					var listener = function listener() {};
					var options = Object.defineProperty({}, "once", {
						get: function get() {
							supported = true;
							return once;
						},
						set: function set(value) {
							once = value;
						}
					});
					WINDOW.addEventListener("test", listener, options);
					WINDOW.removeEventListener("test", listener, options);
				}
				return supported;
			}();
			function removeListener(element, type, listener) {
				var options = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {};
				var handler = listener;
				type.trim().split(REGEXP_SPACES).forEach(function(event) {
					if (!onceSupported) {
						var listeners = element.listeners;
						if (listeners && listeners[event] && listeners[event][listener]) {
							handler = listeners[event][listener];
							delete listeners[event][listener];
							if (Object.keys(listeners[event]).length === 0) delete listeners[event];
							if (Object.keys(listeners).length === 0) delete element.listeners;
						}
					}
					element.removeEventListener(event, handler, options);
				});
			}
			function addListener(element, type, listener) {
				var options = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {};
				var _handler = listener;
				type.trim().split(REGEXP_SPACES).forEach(function(event) {
					if (options.once && !onceSupported) {
						var _element$listeners = element.listeners, listeners = _element$listeners === void 0 ? {} : _element$listeners;
						_handler = function handler() {
							delete listeners[event][listener];
							element.removeEventListener(event, _handler, options);
							for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) args[_key2] = arguments[_key2];
							listener.apply(element, args);
						};
						if (!listeners[event]) listeners[event] = {};
						if (listeners[event][listener]) element.removeEventListener(event, listeners[event][listener], options);
						listeners[event][listener] = _handler;
						element.listeners = listeners;
					}
					element.addEventListener(event, _handler, options);
				});
			}
			function dispatchEvent(element, type, data, options) {
				var event;
				if (isFunction(Event) && isFunction(CustomEvent)) event = new CustomEvent(type, _objectSpread2({
					bubbles: true,
					cancelable: true,
					detail: data
				}, options));
				else {
					event = document.createEvent("CustomEvent");
					event.initCustomEvent(type, true, true, data);
				}
				return element.dispatchEvent(event);
			}
			function getOffset(element) {
				var box = element.getBoundingClientRect();
				return {
					left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
					top: box.top + (window.pageYOffset - document.documentElement.clientTop)
				};
			}
			function getTransforms(_ref) {
				var rotate = _ref.rotate, scaleX = _ref.scaleX, scaleY = _ref.scaleY, translateX = _ref.translateX, translateY = _ref.translateY;
				var values = [];
				if (isNumber(translateX) && translateX !== 0) values.push("translateX(".concat(translateX, "px)"));
				if (isNumber(translateY) && translateY !== 0) values.push("translateY(".concat(translateY, "px)"));
				if (isNumber(rotate) && rotate !== 0) values.push("rotate(".concat(rotate, "deg)"));
				if (isNumber(scaleX) && scaleX !== 1) values.push("scaleX(".concat(scaleX, ")"));
				if (isNumber(scaleY) && scaleY !== 1) values.push("scaleY(".concat(scaleY, ")"));
				var transform = values.length ? values.join(" ") : "none";
				return {
					WebkitTransform: transform,
					msTransform: transform,
					transform
				};
			}
			function getImageNameFromURL(url) {
				return isString(url) ? decodeURIComponent(url.replace(/^.*\//, "").replace(/[?&#].*$/, "")) : "";
			}
			var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent);
			function getImageNaturalSizes(image, options, callback) {
				var newImage = document.createElement("img");
				if (image.naturalWidth && !IS_SAFARI) {
					callback(image.naturalWidth, image.naturalHeight);
					return newImage;
				}
				var body = document.body || document.documentElement;
				newImage.onload = function() {
					callback(newImage.width, newImage.height);
					if (!IS_SAFARI) body.removeChild(newImage);
				};
				forEach(options.inheritedAttributes, function(name) {
					var value = image.getAttribute(name);
					if (value !== null) newImage.setAttribute(name, value);
				});
				newImage.src = image.src;
				if (!IS_SAFARI) {
					newImage.style.cssText = "left:0;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;opacity:0;position:absolute;top:0;z-index:-1;";
					body.appendChild(newImage);
				}
				return newImage;
			}
			function getResponsiveClass(type) {
				switch (type) {
					case 2: return CLASS_HIDE_XS_DOWN;
					case 3: return CLASS_HIDE_SM_DOWN;
					case 4: return CLASS_HIDE_MD_DOWN;
					default: return "";
				}
			}
			function getMaxZoomRatio(pointers) {
				var pointers2 = _objectSpread2({}, pointers);
				var ratios = [];
				forEach(pointers, function(pointer, pointerId) {
					delete pointers2[pointerId];
					forEach(pointers2, function(pointer2) {
						var x1 = Math.abs(pointer.startX - pointer2.startX);
						var y1 = Math.abs(pointer.startY - pointer2.startY);
						var x2 = Math.abs(pointer.endX - pointer2.endX);
						var y2 = Math.abs(pointer.endY - pointer2.endY);
						var z1 = Math.sqrt(x1 * x1 + y1 * y1);
						var ratio = (Math.sqrt(x2 * x2 + y2 * y2) - z1) / z1;
						ratios.push(ratio);
					});
				});
				ratios.sort(function(a, b) {
					return Math.abs(a) < Math.abs(b);
				});
				return ratios[0];
			}
			function getPointer(_ref2, endOnly) {
				var pageX = _ref2.pageX, pageY = _ref2.pageY;
				var end = {
					endX: pageX,
					endY: pageY
				};
				return endOnly ? end : _objectSpread2({
					timeStamp: Date.now(),
					startX: pageX,
					startY: pageY
				}, end);
			}
			function getPointersCenter(pointers) {
				var pageX = 0;
				var pageY = 0;
				var count = 0;
				forEach(pointers, function(_ref3) {
					var startX = _ref3.startX, startY = _ref3.startY;
					pageX += startX;
					pageY += startY;
					count += 1;
				});
				pageX /= count;
				pageY /= count;
				return {
					pageX,
					pageY
				};
			}
			var render = {
				render: function render() {
					this.initContainer();
					this.initViewer();
					this.initList();
					this.renderViewer();
				},
				initBody: function initBody() {
					var ownerDocument = this.element.ownerDocument;
					var body = ownerDocument.body || ownerDocument.documentElement;
					this.body = body;
					this.scrollbarWidth = window.innerWidth - ownerDocument.documentElement.clientWidth;
					this.initialBodyPaddingRight = body.style.paddingRight;
					this.initialBodyComputedPaddingRight = window.getComputedStyle(body).paddingRight;
				},
				initContainer: function initContainer() {
					this.containerData = {
						width: window.innerWidth,
						height: window.innerHeight
					};
				},
				initViewer: function initViewer() {
					var options = this.options, parent = this.parent;
					var viewerData;
					if (options.inline) {
						viewerData = {
							width: Math.max(parent.offsetWidth, options.minWidth),
							height: Math.max(parent.offsetHeight, options.minHeight)
						};
						this.parentData = viewerData;
					}
					if (this.fulled || !viewerData) viewerData = this.containerData;
					this.viewerData = assign({}, viewerData);
				},
				renderViewer: function renderViewer() {
					if (this.options.inline && !this.fulled) setStyle(this.viewer, this.viewerData);
				},
				initList: function initList() {
					var _this = this;
					var element = this.element, options = this.options, list = this.list;
					var items = [];
					list.innerHTML = "";
					forEach(this.images, function(image, index) {
						var src = image.src;
						var alt = image.alt || getImageNameFromURL(src);
						var url = _this.getImageURL(image);
						if (src || url) {
							var item = document.createElement("li");
							var img = document.createElement("img");
							forEach(options.inheritedAttributes, function(name) {
								var value = image.getAttribute(name);
								if (value !== null) img.setAttribute(name, value);
							});
							if (options.navbar) img.src = src || url;
							img.alt = alt;
							img.setAttribute("data-original-url", url || src);
							item.setAttribute("data-index", index);
							item.setAttribute("data-viewer-action", "view");
							item.setAttribute("role", "button");
							if (options.keyboard) item.setAttribute("tabindex", 0);
							item.appendChild(img);
							list.appendChild(item);
							items.push(item);
						}
					});
					this.items = items;
					forEach(items, function(item) {
						var image = item.firstElementChild;
						var onLoad;
						var onError;
						setData(image, "filled", true);
						if (options.loading) addClass(item, CLASS_LOADING);
						addListener(image, EVENT_LOAD, onLoad = function onLoad(event) {
							removeListener(image, EVENT_ERROR, onError);
							if (options.loading) removeClass(item, CLASS_LOADING);
							_this.loadImage(event);
						}, { once: true });
						addListener(image, EVENT_ERROR, onError = function onError() {
							removeListener(image, EVENT_LOAD, onLoad);
							if (options.loading) removeClass(item, CLASS_LOADING);
						}, { once: true });
					});
					if (options.transition) addListener(element, EVENT_VIEWED, function() {
						addClass(list, CLASS_TRANSITION);
					}, { once: true });
				},
				renderList: function renderList() {
					var index = this.index;
					var item = this.items[index];
					if (!item) return;
					var next = item.nextElementSibling;
					var gutter = parseInt(window.getComputedStyle(next || item).marginLeft, 10);
					var offsetWidth = item.offsetWidth;
					var outerWidth = offsetWidth + gutter;
					setStyle(this.list, assign({ width: outerWidth * this.length - gutter }, getTransforms({ translateX: (this.viewerData.width - offsetWidth) / 2 - outerWidth * index })));
				},
				resetList: function resetList() {
					var list = this.list;
					list.innerHTML = "";
					removeClass(list, CLASS_TRANSITION);
					setStyle(list, getTransforms({ translateX: 0 }));
				},
				initImage: function initImage(done) {
					var _this2 = this;
					var options = this.options, image = this.image, viewerData = this.viewerData;
					var footerHeight = this.footer.offsetHeight;
					var viewerWidth = viewerData.width;
					var viewerHeight = Math.max(viewerData.height - footerHeight, footerHeight);
					var oldImageData = this.imageData || {};
					var sizingImage;
					this.imageInitializing = { abort: function abort() {
						sizingImage.onload = null;
					} };
					sizingImage = getImageNaturalSizes(image, options, function(naturalWidth, naturalHeight) {
						var aspectRatio = naturalWidth / naturalHeight;
						var initialCoverage = Math.max(0, Math.min(1, options.initialCoverage));
						var width = viewerWidth;
						var height = viewerHeight;
						_this2.imageInitializing = false;
						if (viewerHeight * aspectRatio > viewerWidth) height = viewerWidth / aspectRatio;
						else width = viewerHeight * aspectRatio;
						initialCoverage = isNumber(initialCoverage) ? initialCoverage : .9;
						width = Math.min(width * initialCoverage, naturalWidth);
						height = Math.min(height * initialCoverage, naturalHeight);
						var left = (viewerWidth - width) / 2;
						var top = (viewerHeight - height) / 2;
						var imageData = {
							left,
							top,
							x: left,
							y: top,
							width,
							height,
							oldRatio: 1,
							ratio: width / naturalWidth,
							aspectRatio,
							naturalWidth,
							naturalHeight
						};
						var initialImageData = assign({}, imageData);
						if (options.rotatable) {
							imageData.rotate = oldImageData.rotate || 0;
							initialImageData.rotate = 0;
						}
						if (options.scalable) {
							imageData.scaleX = oldImageData.scaleX || 1;
							imageData.scaleY = oldImageData.scaleY || 1;
							initialImageData.scaleX = 1;
							initialImageData.scaleY = 1;
						}
						_this2.imageData = imageData;
						_this2.initialImageData = initialImageData;
						if (done) done();
					});
				},
				renderImage: function renderImage(done) {
					var _this3 = this;
					var image = this.image, imageData = this.imageData;
					setStyle(image, assign({
						width: imageData.width,
						height: imageData.height,
						marginLeft: imageData.x,
						marginTop: imageData.y
					}, getTransforms(imageData)));
					if (done) if ((this.viewing || this.moving || this.rotating || this.scaling || this.zooming) && this.options.transition && hasClass(image, CLASS_TRANSITION)) {
						var onTransitionEnd = function onTransitionEnd() {
							_this3.imageRendering = false;
							done();
						};
						this.imageRendering = { abort: function abort() {
							removeListener(image, EVENT_TRANSITION_END, onTransitionEnd);
						} };
						addListener(image, EVENT_TRANSITION_END, onTransitionEnd, { once: true });
					} else done();
				},
				resetImage: function resetImage() {
					if (this.viewing || this.viewed) {
						var image = this.image;
						if (this.viewing) this.viewing.abort();
						image.parentNode.removeChild(image);
						this.image = null;
					}
				}
			};
			var events = {
				bind: function bind() {
					var options = this.options, viewer = this.viewer, canvas = this.canvas;
					var document = this.element.ownerDocument;
					addListener(viewer, EVENT_CLICK, this.onClick = this.click.bind(this));
					addListener(viewer, EVENT_DRAG_START, this.onDragStart = this.dragstart.bind(this));
					addListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this));
					addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this));
					addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
					addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
					addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this));
					if (options.zoomable && options.zoomOnWheel) addListener(viewer, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {
						passive: false,
						capture: true
					});
					if (options.toggleOnDblclick) addListener(canvas, EVENT_DBLCLICK, this.onDblclick = this.dblclick.bind(this));
				},
				unbind: function unbind() {
					var options = this.options, viewer = this.viewer, canvas = this.canvas;
					var document = this.element.ownerDocument;
					removeListener(viewer, EVENT_CLICK, this.onClick);
					removeListener(viewer, EVENT_DRAG_START, this.onDragStart);
					removeListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown);
					removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove);
					removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
					removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
					removeListener(window, EVENT_RESIZE, this.onResize);
					if (options.zoomable && options.zoomOnWheel) removeListener(viewer, EVENT_WHEEL, this.onWheel, {
						passive: false,
						capture: true
					});
					if (options.toggleOnDblclick) removeListener(canvas, EVENT_DBLCLICK, this.onDblclick);
				}
			};
			var handlers = {
				click: function click(event) {
					var options = this.options, imageData = this.imageData;
					var target = event.target;
					var action = getData(target, DATA_ACTION);
					if (!action && target.localName === "img" && target.parentElement.localName === "li") {
						target = target.parentElement;
						action = getData(target, DATA_ACTION);
					}
					if (IS_TOUCH_DEVICE && event.isTrusted && target === this.canvas) clearTimeout(this.clickCanvasTimeout);
					switch (action) {
						case "mix":
							if (this.played) this.stop();
							else if (options.inline) if (this.fulled) this.exit();
							else this.full();
							else this.hide();
							break;
						case "hide":
							this.hide();
							break;
						case "view":
							this.view(getData(target, "index"));
							break;
						case "zoom-in":
							this.zoom(.1, true);
							break;
						case "zoom-out":
							this.zoom(-.1, true);
							break;
						case "one-to-one":
							this.toggle();
							break;
						case "reset":
							this.reset();
							break;
						case "prev":
							this.prev(options.loop);
							break;
						case "play":
							this.play(options.fullscreen);
							break;
						case "next":
							this.next(options.loop);
							break;
						case "rotate-left":
							this.rotate(-90);
							break;
						case "rotate-right":
							this.rotate(90);
							break;
						case "flip-horizontal":
							this.scaleX(-imageData.scaleX || -1);
							break;
						case "flip-vertical":
							this.scaleY(-imageData.scaleY || -1);
							break;
						default: if (this.played) this.stop();
					}
				},
				dblclick: function dblclick(event) {
					event.preventDefault();
					if (this.viewed && event.target === this.image) {
						if (IS_TOUCH_DEVICE && event.isTrusted) clearTimeout(this.doubleClickImageTimeout);
						this.toggle(event.isTrusted ? event : event.detail && event.detail.originalEvent);
					}
				},
				load: function load() {
					var _this = this;
					if (this.timeout) {
						clearTimeout(this.timeout);
						this.timeout = false;
					}
					var element = this.element, options = this.options, image = this.image, index = this.index, viewerData = this.viewerData;
					removeClass(image, CLASS_INVISIBLE);
					if (options.loading) removeClass(this.canvas, CLASS_LOADING);
					image.style.cssText = "height:0;" + "margin-left:".concat(viewerData.width / 2, "px;") + "margin-top:".concat(viewerData.height / 2, "px;") + "max-width:none!important;position:relative;width:0;";
					this.initImage(function() {
						toggleClass(image, CLASS_MOVE, options.movable);
						toggleClass(image, CLASS_TRANSITION, options.transition);
						_this.renderImage(function() {
							_this.viewed = true;
							_this.viewing = false;
							if (isFunction(options.viewed)) addListener(element, EVENT_VIEWED, options.viewed, { once: true });
							dispatchEvent(element, EVENT_VIEWED, {
								originalImage: _this.images[index],
								index,
								image
							}, { cancelable: false });
						});
					});
				},
				loadImage: function loadImage(event) {
					var image = event.target;
					var parent = image.parentNode;
					var parentWidth = parent.offsetWidth || 30;
					var parentHeight = parent.offsetHeight || 50;
					var filled = !!getData(image, "filled");
					getImageNaturalSizes(image, this.options, function(naturalWidth, naturalHeight) {
						var aspectRatio = naturalWidth / naturalHeight;
						var width = parentWidth;
						var height = parentHeight;
						if (parentHeight * aspectRatio > parentWidth) if (filled) width = parentHeight * aspectRatio;
						else height = parentWidth / aspectRatio;
						else if (filled) height = parentWidth / aspectRatio;
						else width = parentHeight * aspectRatio;
						setStyle(image, assign({
							width,
							height
						}, getTransforms({
							translateX: (parentWidth - width) / 2,
							translateY: (parentHeight - height) / 2
						})));
					});
				},
				keydown: function keydown(event) {
					var options = this.options;
					if (!options.keyboard) return;
					var keyCode = event.keyCode || event.which || event.charCode;
					switch (keyCode) {
						case 13:
							if (this.viewer.contains(event.target)) this.click(event);
							break;
					}
					if (!this.fulled) return;
					switch (keyCode) {
						case 27:
							if (this.played) this.stop();
							else if (options.inline) {
								if (this.fulled) this.exit();
							} else this.hide();
							break;
						case 32:
							if (this.played) this.stop();
							break;
						case 37:
							if (this.played && this.playing) this.playing.prev();
							else this.prev(options.loop);
							break;
						case 38:
							event.preventDefault();
							this.zoom(options.zoomRatio, true);
							break;
						case 39:
							if (this.played && this.playing) this.playing.next();
							else this.next(options.loop);
							break;
						case 40:
							event.preventDefault();
							this.zoom(-options.zoomRatio, true);
							break;
						case 48:
						case 49:
							if (event.ctrlKey) {
								event.preventDefault();
								this.toggle();
							}
							break;
					}
				},
				dragstart: function dragstart(event) {
					if (event.target.localName === "img") event.preventDefault();
				},
				pointerdown: function pointerdown(event) {
					var options = this.options, pointers = this.pointers;
					var buttons = event.buttons, button = event.button;
					if (!this.viewed || this.showing || this.viewing || this.hiding || (event.type === "mousedown" || event.type === "pointerdown" && event.pointerType === "mouse") && (isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 || event.ctrlKey)) return;
					event.preventDefault();
					if (event.changedTouches) forEach(event.changedTouches, function(touch) {
						pointers[touch.identifier] = getPointer(touch);
					});
					else pointers[event.pointerId || 0] = getPointer(event);
					var action = options.movable ? ACTION_MOVE : false;
					if (options.zoomOnTouch && options.zoomable && Object.keys(pointers).length > 1) action = ACTION_ZOOM;
					else if (options.slideOnTouch && (event.pointerType === "touch" || event.type === "touchstart") && this.isSwitchable()) action = ACTION_SWITCH;
					if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) removeClass(this.image, CLASS_TRANSITION);
					this.action = action;
				},
				pointermove: function pointermove(event) {
					var pointers = this.pointers, action = this.action;
					if (!this.viewed || !action) return;
					event.preventDefault();
					if (event.changedTouches) forEach(event.changedTouches, function(touch) {
						assign(pointers[touch.identifier] || {}, getPointer(touch, true));
					});
					else assign(pointers[event.pointerId || 0] || {}, getPointer(event, true));
					this.change(event);
				},
				pointerup: function pointerup(event) {
					var _this2 = this;
					var options = this.options, action = this.action, pointers = this.pointers;
					var pointer;
					if (event.changedTouches) forEach(event.changedTouches, function(touch) {
						pointer = pointers[touch.identifier];
						delete pointers[touch.identifier];
					});
					else {
						pointer = pointers[event.pointerId || 0];
						delete pointers[event.pointerId || 0];
					}
					if (!action) return;
					event.preventDefault();
					if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) addClass(this.image, CLASS_TRANSITION);
					this.action = false;
					if (IS_TOUCH_DEVICE && action !== ACTION_ZOOM && pointer && Date.now() - pointer.timeStamp < 500) {
						clearTimeout(this.clickCanvasTimeout);
						clearTimeout(this.doubleClickImageTimeout);
						if (options.toggleOnDblclick && this.viewed && event.target === this.image) if (this.imageClicked) {
							this.imageClicked = false;
							this.doubleClickImageTimeout = setTimeout(function() {
								dispatchEvent(_this2.image, EVENT_DBLCLICK, { originalEvent: event });
							}, 50);
						} else {
							this.imageClicked = true;
							this.doubleClickImageTimeout = setTimeout(function() {
								_this2.imageClicked = false;
							}, 500);
						}
						else {
							this.imageClicked = false;
							if (options.backdrop && options.backdrop !== "static" && event.target === this.canvas) this.clickCanvasTimeout = setTimeout(function() {
								dispatchEvent(_this2.canvas, EVENT_CLICK, { originalEvent: event });
							}, 50);
						}
					}
				},
				resize: function resize() {
					var _this3 = this;
					if (!this.isShown || this.hiding) return;
					if (this.fulled) {
						this.close();
						this.initBody();
						this.open();
					}
					this.initContainer();
					this.initViewer();
					this.renderViewer();
					this.renderList();
					if (this.viewed) this.initImage(function() {
						_this3.renderImage();
					});
					if (this.played) {
						if (this.options.fullscreen && this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
							this.stop();
							return;
						}
						forEach(this.player.getElementsByTagName("img"), function(image) {
							addListener(image, EVENT_LOAD, _this3.loadImage.bind(_this3), { once: true });
							dispatchEvent(image, EVENT_LOAD);
						});
					}
				},
				wheel: function wheel(event) {
					var _this4 = this;
					if (!this.viewed) return;
					event.preventDefault();
					if (this.wheeling) return;
					this.wheeling = true;
					setTimeout(function() {
						_this4.wheeling = false;
					}, 50);
					var ratio = Number(this.options.zoomRatio) || .1;
					var delta = 1;
					if (event.deltaY) delta = event.deltaY > 0 ? 1 : -1;
					else if (event.wheelDelta) delta = -event.wheelDelta / 120;
					else if (event.detail) delta = event.detail > 0 ? 1 : -1;
					this.zoom(-delta * ratio, true, null, event);
				}
			};
			var methods = {
				show: function show() {
					var immediate = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
					var element = this.element, options = this.options;
					if (options.inline || this.showing || this.isShown || this.showing) return this;
					if (!this.ready) {
						this.build();
						if (this.ready) this.show(immediate);
						return this;
					}
					if (isFunction(options.show)) addListener(element, EVENT_SHOW, options.show, { once: true });
					if (dispatchEvent(element, EVENT_SHOW) === false || !this.ready) return this;
					if (this.hiding) this.transitioning.abort();
					this.showing = true;
					this.open();
					var viewer = this.viewer;
					removeClass(viewer, CLASS_HIDE);
					viewer.setAttribute("role", "dialog");
					viewer.setAttribute("aria-labelledby", this.title.id);
					viewer.setAttribute("aria-modal", true);
					viewer.removeAttribute("aria-hidden");
					if (options.transition && !immediate) {
						var shown = this.shown.bind(this);
						this.transitioning = { abort: function abort() {
							removeListener(viewer, EVENT_TRANSITION_END, shown);
							removeClass(viewer, CLASS_IN);
						} };
						addClass(viewer, CLASS_TRANSITION);
						viewer.initialOffsetWidth = viewer.offsetWidth;
						addListener(viewer, EVENT_TRANSITION_END, shown, { once: true });
						addClass(viewer, CLASS_IN);
					} else {
						addClass(viewer, CLASS_IN);
						this.shown();
					}
					return this;
				},
				hide: function hide() {
					var _this = this;
					var immediate = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
					var element = this.element, options = this.options;
					if (options.inline || this.hiding || !(this.isShown || this.showing)) return this;
					if (isFunction(options.hide)) addListener(element, EVENT_HIDE, options.hide, { once: true });
					if (dispatchEvent(element, EVENT_HIDE) === false) return this;
					if (this.showing) this.transitioning.abort();
					this.hiding = true;
					if (this.played) this.stop();
					else if (this.viewing) this.viewing.abort();
					var viewer = this.viewer, image = this.image;
					var hideImmediately = function hideImmediately() {
						removeClass(viewer, CLASS_IN);
						_this.hidden();
					};
					if (options.transition && !immediate) {
						var onViewerTransitionEnd = function onViewerTransitionEnd(event) {
							if (event && event.target === viewer) {
								removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
								_this.hidden();
							}
						};
						var onImageTransitionEnd = function onImageTransitionEnd() {
							if (hasClass(viewer, CLASS_TRANSITION)) {
								addListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
								removeClass(viewer, CLASS_IN);
							} else hideImmediately();
						};
						this.transitioning = { abort: function abort() {
							if (_this.viewed && hasClass(image, CLASS_TRANSITION)) removeListener(image, EVENT_TRANSITION_END, onImageTransitionEnd);
							else if (hasClass(viewer, CLASS_TRANSITION)) removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
						} };
						if (this.viewed && hasClass(image, CLASS_TRANSITION)) {
							addListener(image, EVENT_TRANSITION_END, onImageTransitionEnd, { once: true });
							this.zoomTo(0, false, null, null, true);
						} else onImageTransitionEnd();
					} else hideImmediately();
					return this;
				},
				view: function view() {
					var _this2 = this;
					var index = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.options.initialViewIndex;
					index = Number(index) || 0;
					if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) return this;
					if (!this.isShown) {
						this.index = index;
						return this.show();
					}
					if (this.viewing) this.viewing.abort();
					var element = this.element, options = this.options, title = this.title, canvas = this.canvas;
					var item = this.items[index];
					var img = item.querySelector("img");
					var url = getData(img, "originalUrl");
					var alt = img.getAttribute("alt");
					var image = document.createElement("img");
					forEach(options.inheritedAttributes, function(name) {
						var value = img.getAttribute(name);
						if (value !== null) image.setAttribute(name, value);
					});
					image.src = url;
					image.alt = alt;
					if (isFunction(options.view)) addListener(element, EVENT_VIEW, options.view, { once: true });
					if (dispatchEvent(element, EVENT_VIEW, {
						originalImage: this.images[index],
						index,
						image
					}) === false || !this.isShown || this.hiding || this.played) return this;
					var activeItem = this.items[this.index];
					if (activeItem) {
						removeClass(activeItem, CLASS_ACTIVE);
						activeItem.removeAttribute("aria-selected");
					}
					addClass(item, CLASS_ACTIVE);
					item.setAttribute("aria-selected", true);
					if (options.focus) item.focus();
					this.image = image;
					this.viewed = false;
					this.index = index;
					this.imageData = {};
					addClass(image, CLASS_INVISIBLE);
					if (options.loading) addClass(canvas, CLASS_LOADING);
					canvas.innerHTML = "";
					canvas.appendChild(image);
					this.renderList();
					title.innerHTML = "";
					var onViewed = function onViewed() {
						var imageData = _this2.imageData;
						var render = Array.isArray(options.title) ? options.title[1] : options.title;
						title.innerHTML = escapeHTMLEntities(isFunction(render) ? render.call(_this2, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " × ").concat(imageData.naturalHeight, ")"));
					};
					var onLoad;
					var onError;
					addListener(element, EVENT_VIEWED, onViewed, { once: true });
					this.viewing = { abort: function abort() {
						removeListener(element, EVENT_VIEWED, onViewed);
						if (image.complete) {
							if (_this2.imageRendering) _this2.imageRendering.abort();
							else if (_this2.imageInitializing) _this2.imageInitializing.abort();
						} else {
							image.src = "";
							removeListener(image, EVENT_LOAD, onLoad);
							if (_this2.timeout) clearTimeout(_this2.timeout);
						}
					} };
					if (image.complete) this.load();
					else {
						addListener(image, EVENT_LOAD, onLoad = function onLoad() {
							removeListener(image, EVENT_ERROR, onError);
							_this2.load();
						}, { once: true });
						addListener(image, EVENT_ERROR, onError = function onError() {
							removeListener(image, EVENT_LOAD, onLoad);
							if (_this2.timeout) {
								clearTimeout(_this2.timeout);
								_this2.timeout = false;
							}
							removeClass(image, CLASS_INVISIBLE);
							if (options.loading) removeClass(_this2.canvas, CLASS_LOADING);
						}, { once: true });
						if (this.timeout) clearTimeout(this.timeout);
						this.timeout = setTimeout(function() {
							removeClass(image, CLASS_INVISIBLE);
							_this2.timeout = false;
						}, 1e3);
					}
					return this;
				},
				prev: function prev() {
					var loop = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
					var index = this.index - 1;
					if (index < 0) index = loop ? this.length - 1 : 0;
					this.view(index);
					return this;
				},
				next: function next() {
					var loop = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
					var maxIndex = this.length - 1;
					var index = this.index + 1;
					if (index > maxIndex) index = loop ? 0 : maxIndex;
					this.view(index);
					return this;
				},
				move: function move(x) {
					var y = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : x;
					var imageData = this.imageData;
					this.moveTo(isUndefined(x) ? x : imageData.x + Number(x), isUndefined(y) ? y : imageData.y + Number(y));
					return this;
				},
				moveTo: function moveTo(x) {
					var _this3 = this;
					var y = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : x;
					var _originalEvent = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
					var element = this.element, options = this.options, imageData = this.imageData;
					x = Number(x);
					y = Number(y);
					if (this.viewed && !this.played && options.movable) {
						var oldX = imageData.x;
						var oldY = imageData.y;
						var changed = false;
						if (isNumber(x)) changed = true;
						else x = oldX;
						if (isNumber(y)) changed = true;
						else y = oldY;
						if (changed) {
							if (isFunction(options.move)) addListener(element, EVENT_MOVE, options.move, { once: true });
							if (dispatchEvent(element, EVENT_MOVE, {
								x,
								y,
								oldX,
								oldY,
								originalEvent: _originalEvent
							}) === false) return this;
							imageData.x = x;
							imageData.y = y;
							imageData.left = x;
							imageData.top = y;
							this.moving = true;
							this.renderImage(function() {
								_this3.moving = false;
								if (isFunction(options.moved)) addListener(element, EVENT_MOVED, options.moved, { once: true });
								dispatchEvent(element, EVENT_MOVED, {
									x,
									y,
									oldX,
									oldY,
									originalEvent: _originalEvent
								}, { cancelable: false });
							});
						}
					}
					return this;
				},
				rotate: function rotate(degree) {
					this.rotateTo((this.imageData.rotate || 0) + Number(degree));
					return this;
				},
				rotateTo: function rotateTo(degree) {
					var _this4 = this;
					var element = this.element, options = this.options, imageData = this.imageData;
					degree = Number(degree);
					if (isNumber(degree) && this.viewed && !this.played && options.rotatable) {
						var oldDegree = imageData.rotate;
						if (isFunction(options.rotate)) addListener(element, EVENT_ROTATE, options.rotate, { once: true });
						if (dispatchEvent(element, EVENT_ROTATE, {
							degree,
							oldDegree
						}) === false) return this;
						imageData.rotate = degree;
						this.rotating = true;
						this.renderImage(function() {
							_this4.rotating = false;
							if (isFunction(options.rotated)) addListener(element, EVENT_ROTATED, options.rotated, { once: true });
							dispatchEvent(element, EVENT_ROTATED, {
								degree,
								oldDegree
							}, { cancelable: false });
						});
					}
					return this;
				},
				scaleX: function scaleX(_scaleX) {
					this.scale(_scaleX, this.imageData.scaleY);
					return this;
				},
				scaleY: function scaleY(_scaleY) {
					this.scale(this.imageData.scaleX, _scaleY);
					return this;
				},
				scale: function scale(scaleX) {
					var _this5 = this;
					var scaleY = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : scaleX;
					var element = this.element, options = this.options, imageData = this.imageData;
					scaleX = Number(scaleX);
					scaleY = Number(scaleY);
					if (this.viewed && !this.played && options.scalable) {
						var oldScaleX = imageData.scaleX;
						var oldScaleY = imageData.scaleY;
						var changed = false;
						if (isNumber(scaleX)) changed = true;
						else scaleX = oldScaleX;
						if (isNumber(scaleY)) changed = true;
						else scaleY = oldScaleY;
						if (changed) {
							if (isFunction(options.scale)) addListener(element, EVENT_SCALE, options.scale, { once: true });
							if (dispatchEvent(element, EVENT_SCALE, {
								scaleX,
								scaleY,
								oldScaleX,
								oldScaleY
							}) === false) return this;
							imageData.scaleX = scaleX;
							imageData.scaleY = scaleY;
							this.scaling = true;
							this.renderImage(function() {
								_this5.scaling = false;
								if (isFunction(options.scaled)) addListener(element, EVENT_SCALED, options.scaled, { once: true });
								dispatchEvent(element, EVENT_SCALED, {
									scaleX,
									scaleY,
									oldScaleX,
									oldScaleY
								}, { cancelable: false });
							});
						}
					}
					return this;
				},
				zoom: function zoom(ratio) {
					var showTooltip = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
					var pivot = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
					var _originalEvent = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
					var imageData = this.imageData;
					ratio = Number(ratio);
					if (ratio < 0) ratio = 1 / (1 - ratio);
					else ratio = 1 + ratio;
					this.zoomTo(imageData.width * ratio / imageData.naturalWidth, showTooltip, pivot, _originalEvent);
					return this;
				},
				zoomTo: function zoomTo(ratio) {
					var _this6 = this;
					var showTooltip = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
					var pivot = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
					var _originalEvent = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
					var _zoomable = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : false;
					var element = this.element, options = this.options, pointers = this.pointers, imageData = this.imageData;
					var x = imageData.x, y = imageData.y, width = imageData.width, height = imageData.height, naturalWidth = imageData.naturalWidth, naturalHeight = imageData.naturalHeight;
					ratio = Math.max(0, ratio);
					if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) {
						if (!_zoomable) {
							var minZoomRatio = Math.max(.01, options.minZoomRatio);
							var maxZoomRatio = Math.min(100, options.maxZoomRatio);
							ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio);
						}
						if (_originalEvent) switch (_originalEvent.type) {
							case "wheel":
								if (options.zoomRatio >= .055 && ratio > .95 && ratio < 1.05) ratio = 1;
								break;
							case "pointermove":
							case "touchmove":
							case "mousemove":
								if (ratio > .99 && ratio < 1.01) ratio = 1;
								break;
						}
						var newWidth = naturalWidth * ratio;
						var newHeight = naturalHeight * ratio;
						var offsetWidth = newWidth - width;
						var offsetHeight = newHeight - height;
						var oldRatio = imageData.ratio;
						if (isFunction(options.zoom)) addListener(element, EVENT_ZOOM, options.zoom, { once: true });
						if (dispatchEvent(element, EVENT_ZOOM, {
							ratio,
							oldRatio,
							originalEvent: _originalEvent
						}) === false) return this;
						this.zooming = true;
						if (_originalEvent) {
							var offset = getOffset(this.viewer);
							var center = pointers && Object.keys(pointers).length > 0 ? getPointersCenter(pointers) : {
								pageX: _originalEvent.pageX,
								pageY: _originalEvent.pageY
							};
							imageData.x -= offsetWidth * ((center.pageX - offset.left - x) / width);
							imageData.y -= offsetHeight * ((center.pageY - offset.top - y) / height);
						} else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) {
							imageData.x -= offsetWidth * ((pivot.x - x) / width);
							imageData.y -= offsetHeight * ((pivot.y - y) / height);
						} else {
							imageData.x -= offsetWidth / 2;
							imageData.y -= offsetHeight / 2;
						}
						imageData.left = imageData.x;
						imageData.top = imageData.y;
						imageData.width = newWidth;
						imageData.height = newHeight;
						imageData.oldRatio = oldRatio;
						imageData.ratio = ratio;
						this.renderImage(function() {
							_this6.zooming = false;
							if (isFunction(options.zoomed)) addListener(element, EVENT_ZOOMED, options.zoomed, { once: true });
							dispatchEvent(element, EVENT_ZOOMED, {
								ratio,
								oldRatio,
								originalEvent: _originalEvent
							}, { cancelable: false });
						});
						if (showTooltip) this.tooltip();
					}
					return this;
				},
				play: function play() {
					var _this7 = this;
					var fullscreen = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
					if (!this.isShown || this.played) return this;
					var element = this.element, options = this.options;
					if (isFunction(options.play)) addListener(element, EVENT_PLAY, options.play, { once: true });
					if (dispatchEvent(element, EVENT_PLAY) === false) return this;
					var player = this.player;
					var onLoad = this.loadImage.bind(this);
					var list = [];
					var total = 0;
					var index = 0;
					this.played = true;
					this.onLoadWhenPlay = onLoad;
					if (fullscreen) this.requestFullscreen(fullscreen);
					addClass(player, CLASS_SHOW);
					forEach(this.items, function(item, i) {
						var img = item.querySelector("img");
						var image = document.createElement("img");
						image.src = getData(img, "originalUrl");
						image.alt = img.getAttribute("alt");
						image.referrerPolicy = img.referrerPolicy;
						total += 1;
						addClass(image, CLASS_FADE);
						toggleClass(image, CLASS_TRANSITION, options.transition);
						if (hasClass(item, CLASS_ACTIVE)) {
							addClass(image, CLASS_IN);
							index = i;
						}
						list.push(image);
						addListener(image, EVENT_LOAD, onLoad, { once: true });
						player.appendChild(image);
					});
					if (isNumber(options.interval) && options.interval > 0) {
						var prev = function prev() {
							clearTimeout(_this7.playing.timeout);
							removeClass(list[index], CLASS_IN);
							index -= 1;
							index = index >= 0 ? index : total - 1;
							addClass(list[index], CLASS_IN);
							_this7.playing.timeout = setTimeout(prev, options.interval);
						};
						var next = function next() {
							clearTimeout(_this7.playing.timeout);
							removeClass(list[index], CLASS_IN);
							index += 1;
							index = index < total ? index : 0;
							addClass(list[index], CLASS_IN);
							_this7.playing.timeout = setTimeout(next, options.interval);
						};
						if (total > 1) this.playing = {
							prev,
							next,
							timeout: setTimeout(next, options.interval)
						};
					}
					return this;
				},
				stop: function stop() {
					var _this8 = this;
					if (!this.played) return this;
					var element = this.element, options = this.options;
					if (isFunction(options.stop)) addListener(element, EVENT_STOP, options.stop, { once: true });
					if (dispatchEvent(element, EVENT_STOP) === false) return this;
					var player = this.player;
					clearTimeout(this.playing.timeout);
					this.playing = false;
					this.played = false;
					forEach(player.getElementsByTagName("img"), function(image) {
						removeListener(image, EVENT_LOAD, _this8.onLoadWhenPlay);
					});
					removeClass(player, CLASS_SHOW);
					player.innerHTML = "";
					this.exitFullscreen();
					return this;
				},
				full: function full() {
					var _this9 = this;
					var options = this.options, viewer = this.viewer, image = this.image, list = this.list;
					if (!this.isShown || this.played || this.fulled || !options.inline) return this;
					this.fulled = true;
					this.open();
					addClass(this.button, CLASS_FULLSCREEN_EXIT);
					if (options.transition) {
						removeClass(list, CLASS_TRANSITION);
						if (this.viewed) removeClass(image, CLASS_TRANSITION);
					}
					addClass(viewer, CLASS_FIXED);
					viewer.setAttribute("role", "dialog");
					viewer.setAttribute("aria-labelledby", this.title.id);
					viewer.setAttribute("aria-modal", true);
					viewer.removeAttribute("style");
					setStyle(viewer, { zIndex: options.zIndex });
					if (options.focus) this.enforceFocus();
					this.initContainer();
					this.viewerData = assign({}, this.containerData);
					this.renderList();
					if (this.viewed) this.initImage(function() {
						_this9.renderImage(function() {
							if (options.transition) setTimeout(function() {
								addClass(image, CLASS_TRANSITION);
								addClass(list, CLASS_TRANSITION);
							}, 0);
						});
					});
					return this;
				},
				exit: function exit() {
					var _this10 = this;
					var options = this.options, viewer = this.viewer, image = this.image, list = this.list;
					if (!this.isShown || this.played || !this.fulled || !options.inline) return this;
					this.fulled = false;
					this.close();
					removeClass(this.button, CLASS_FULLSCREEN_EXIT);
					if (options.transition) {
						removeClass(list, CLASS_TRANSITION);
						if (this.viewed) removeClass(image, CLASS_TRANSITION);
					}
					if (options.focus) this.clearEnforceFocus();
					viewer.removeAttribute("role");
					viewer.removeAttribute("aria-labelledby");
					viewer.removeAttribute("aria-modal");
					removeClass(viewer, CLASS_FIXED);
					setStyle(viewer, { zIndex: options.zIndexInline });
					this.viewerData = assign({}, this.parentData);
					this.renderViewer();
					this.renderList();
					if (this.viewed) this.initImage(function() {
						_this10.renderImage(function() {
							if (options.transition) setTimeout(function() {
								addClass(image, CLASS_TRANSITION);
								addClass(list, CLASS_TRANSITION);
							}, 0);
						});
					});
					return this;
				},
				tooltip: function tooltip() {
					var _this11 = this;
					var options = this.options, tooltipBox = this.tooltipBox, imageData = this.imageData;
					if (!this.viewed || this.played || !options.tooltip) return this;
					tooltipBox.textContent = "".concat(Math.round(imageData.ratio * 100), "%");
					if (!this.tooltipping) if (options.transition) {
						if (this.fading) dispatchEvent(tooltipBox, EVENT_TRANSITION_END);
						addClass(tooltipBox, CLASS_SHOW);
						addClass(tooltipBox, CLASS_FADE);
						addClass(tooltipBox, CLASS_TRANSITION);
						tooltipBox.removeAttribute("aria-hidden");
						tooltipBox.initialOffsetWidth = tooltipBox.offsetWidth;
						addClass(tooltipBox, CLASS_IN);
					} else {
						addClass(tooltipBox, CLASS_SHOW);
						tooltipBox.removeAttribute("aria-hidden");
					}
					else clearTimeout(this.tooltipping);
					this.tooltipping = setTimeout(function() {
						if (options.transition) {
							addListener(tooltipBox, EVENT_TRANSITION_END, function() {
								removeClass(tooltipBox, CLASS_SHOW);
								removeClass(tooltipBox, CLASS_FADE);
								removeClass(tooltipBox, CLASS_TRANSITION);
								tooltipBox.setAttribute("aria-hidden", true);
								_this11.fading = false;
							}, { once: true });
							removeClass(tooltipBox, CLASS_IN);
							_this11.fading = true;
						} else {
							removeClass(tooltipBox, CLASS_SHOW);
							tooltipBox.setAttribute("aria-hidden", true);
						}
						_this11.tooltipping = false;
					}, 1e3);
					return this;
				},
				toggle: function toggle() {
					var _originalEvent = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : null;
					if (this.imageData.ratio === 1) this.zoomTo(this.imageData.oldRatio, true, null, _originalEvent);
					else this.zoomTo(1, true, null, _originalEvent);
					return this;
				},
				reset: function reset() {
					if (this.viewed && !this.played) {
						this.imageData = assign({}, this.initialImageData);
						this.renderImage();
					}
					return this;
				},
				update: function update() {
					var _this12 = this;
					var element = this.element, options = this.options, isImg = this.isImg;
					if (isImg && !element.parentNode) return this.destroy();
					var images = [];
					forEach(isImg ? [element] : element.querySelectorAll("img"), function(image) {
						if (isFunction(options.filter)) {
							if (options.filter.call(_this12, image)) images.push(image);
						} else if (_this12.getImageURL(image)) images.push(image);
					});
					if (!images.length) return this;
					this.images = images;
					this.length = images.length;
					if (this.ready) {
						var changedIndexes = [];
						forEach(this.items, function(item, i) {
							var img = item.querySelector("img");
							var image = images[i];
							if (image && img) {
								if (image.src !== img.src || image.alt !== img.alt) changedIndexes.push(i);
							} else changedIndexes.push(i);
						});
						setStyle(this.list, { width: "auto" });
						this.initList();
						if (this.isShown) if (this.length) {
							if (this.viewed) {
								var changedIndex = changedIndexes.indexOf(this.index);
								if (changedIndex >= 0) {
									this.viewed = false;
									this.view(Math.max(Math.min(this.index - changedIndex, this.length - 1), 0));
								} else {
									var activeItem = this.items[this.index];
									addClass(activeItem, CLASS_ACTIVE);
									activeItem.setAttribute("aria-selected", true);
								}
							}
						} else {
							this.image = null;
							this.viewed = false;
							this.index = 0;
							this.imageData = {};
							this.canvas.innerHTML = "";
							this.title.innerHTML = "";
						}
					} else this.build();
					return this;
				},
				destroy: function destroy() {
					var element = this.element, options = this.options;
					if (!element[NAMESPACE]) return this;
					this.destroyed = true;
					if (this.ready) {
						if (this.played) this.stop();
						if (options.inline) {
							if (this.fulled) this.exit();
							this.unbind();
						} else if (this.isShown) {
							if (this.viewing) {
								if (this.imageRendering) this.imageRendering.abort();
								else if (this.imageInitializing) this.imageInitializing.abort();
							}
							if (this.hiding) this.transitioning.abort();
							this.hidden();
						} else if (this.showing) {
							this.transitioning.abort();
							this.hidden();
						}
						this.ready = false;
						this.viewer.parentNode.removeChild(this.viewer);
					} else if (options.inline) {
						if (this.delaying) this.delaying.abort();
						else if (this.initializing) this.initializing.abort();
					}
					if (!options.inline) removeListener(element, EVENT_CLICK, this.onStart);
					element[NAMESPACE] = void 0;
					return this;
				}
			};
			var others = {
				getImageURL: function getImageURL(image) {
					var url = this.options.url;
					if (isString(url)) url = image.getAttribute(url);
					else if (isFunction(url)) url = url.call(this, image);
					else url = "";
					return url;
				},
				enforceFocus: function enforceFocus() {
					var _this = this;
					this.clearEnforceFocus();
					addListener(document, EVENT_FOCUSIN, this.onFocusin = function(event) {
						var viewer = _this.viewer;
						var target = event.target;
						if (target === document || target === viewer || viewer.contains(target)) return;
						while (target) {
							if (target.getAttribute("tabindex") !== null || target.getAttribute("aria-modal") === "true") return;
							target = target.parentElement;
						}
						viewer.focus();
					});
				},
				clearEnforceFocus: function clearEnforceFocus() {
					if (this.onFocusin) {
						removeListener(document, EVENT_FOCUSIN, this.onFocusin);
						this.onFocusin = null;
					}
				},
				open: function open() {
					var body = this.body;
					addClass(body, CLASS_OPEN);
					if (this.scrollbarWidth > 0) body.style.paddingRight = "".concat(this.scrollbarWidth + (parseFloat(this.initialBodyComputedPaddingRight) || 0), "px");
				},
				close: function close() {
					var body = this.body;
					removeClass(body, CLASS_OPEN);
					if (this.scrollbarWidth > 0) body.style.paddingRight = this.initialBodyPaddingRight;
				},
				shown: function shown() {
					var element = this.element, options = this.options, viewer = this.viewer;
					this.fulled = true;
					this.isShown = true;
					this.render();
					this.bind();
					this.showing = false;
					if (options.focus) {
						viewer.focus();
						this.enforceFocus();
					}
					if (isFunction(options.shown)) addListener(element, EVENT_SHOWN, options.shown, { once: true });
					if (dispatchEvent(element, EVENT_SHOWN) === false) return;
					if (this.ready && this.isShown && !this.hiding) this.view(this.index);
				},
				hidden: function hidden() {
					var element = this.element, options = this.options, viewer = this.viewer;
					if (options.fucus) this.clearEnforceFocus();
					this.fulled = false;
					this.viewed = false;
					this.isShown = false;
					this.close();
					this.unbind();
					addClass(viewer, CLASS_HIDE);
					viewer.removeAttribute("role");
					viewer.removeAttribute("aria-labelledby");
					viewer.removeAttribute("aria-modal");
					viewer.setAttribute("aria-hidden", true);
					this.resetList();
					this.resetImage();
					this.hiding = false;
					if (!this.destroyed) {
						if (isFunction(options.hidden)) addListener(element, EVENT_HIDDEN, options.hidden, { once: true });
						dispatchEvent(element, EVENT_HIDDEN, null, { cancelable: false });
					}
				},
				requestFullscreen: function requestFullscreen(options) {
					var document = this.element.ownerDocument;
					if (this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
						var documentElement = document.documentElement;
						if (documentElement.requestFullscreen) if (isPlainObject(options)) documentElement.requestFullscreen(options);
						else documentElement.requestFullscreen();
						else if (documentElement.webkitRequestFullscreen) documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
						else if (documentElement.mozRequestFullScreen) documentElement.mozRequestFullScreen();
						else if (documentElement.msRequestFullscreen) documentElement.msRequestFullscreen();
					}
				},
				exitFullscreen: function exitFullscreen() {
					var document = this.element.ownerDocument;
					if (this.fulled && (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
						if (document.exitFullscreen) document.exitFullscreen();
						else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
						else if (document.mozCancelFullScreen) document.mozCancelFullScreen();
						else if (document.msExitFullscreen) document.msExitFullscreen();
					}
				},
				change: function change(event) {
					var options = this.options, pointers = this.pointers;
					var pointer = pointers[Object.keys(pointers)[0]];
					if (!pointer) return;
					var offsetX = pointer.endX - pointer.startX;
					var offsetY = pointer.endY - pointer.startY;
					switch (this.action) {
						case ACTION_MOVE:
							this.move(offsetX, offsetY, event);
							break;
						case ACTION_ZOOM:
							this.zoom(getMaxZoomRatio(pointers), false, null, event);
							break;
						case ACTION_SWITCH:
							this.action = "switched";
							var absoluteOffsetX = Math.abs(offsetX);
							if (absoluteOffsetX > 1 && absoluteOffsetX > Math.abs(offsetY)) {
								this.pointers = {};
								if (offsetX > 1) this.prev(options.loop);
								else if (offsetX < -1) this.next(options.loop);
							}
							break;
					}
					forEach(pointers, function(p) {
						p.startX = p.endX;
						p.startY = p.endY;
					});
				},
				isSwitchable: function isSwitchable() {
					var imageData = this.imageData, viewerData = this.viewerData;
					return this.length > 1 && imageData.x >= 0 && imageData.y >= 0 && imageData.width <= viewerData.width && imageData.height <= viewerData.height;
				}
			};
			var AnotherViewer = WINDOW.Viewer;
			var getUniqueID = function(id) {
				return function() {
					id += 1;
					return id;
				};
			}(-1);
			var Viewer = function() {
				function Viewer(element) {
					var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
					_classCallCheck(this, Viewer);
					if (!element || element.nodeType !== 1) throw new Error("The first argument is required and must be an element.");
					this.element = element;
					this.options = assign({}, DEFAULTS, isPlainObject(options) && options);
					this.action = false;
					this.fading = false;
					this.fulled = false;
					this.hiding = false;
					this.imageClicked = false;
					this.imageData = {};
					this.index = this.options.initialViewIndex;
					this.isImg = false;
					this.isShown = false;
					this.length = 0;
					this.moving = false;
					this.played = false;
					this.playing = false;
					this.pointers = {};
					this.ready = false;
					this.rotating = false;
					this.scaling = false;
					this.showing = false;
					this.timeout = false;
					this.tooltipping = false;
					this.viewed = false;
					this.viewing = false;
					this.wheeling = false;
					this.zooming = false;
					this.id = getUniqueID();
					this.init();
				}
				_createClass(Viewer, [{
					key: "init",
					value: function init() {
						var _this = this;
						var element = this.element, options = this.options;
						if (element[NAMESPACE]) return;
						element[NAMESPACE] = this;
						if (options.focus && !options.keyboard) options.focus = false;
						var isImg = element.localName === "img";
						var images = [];
						forEach(isImg ? [element] : element.querySelectorAll("img"), function(image) {
							if (isFunction(options.filter)) {
								if (options.filter.call(_this, image)) images.push(image);
							} else if (_this.getImageURL(image)) images.push(image);
						});
						this.isImg = isImg;
						this.length = images.length;
						this.images = images;
						this.initBody();
						if (isUndefined(document.createElement(NAMESPACE).style.transition)) options.transition = false;
						if (options.inline) {
							var count = 0;
							var progress = function progress() {
								count += 1;
								if (count === _this.length) {
									var timeout;
									_this.initializing = false;
									_this.delaying = { abort: function abort() {
										clearTimeout(timeout);
									} };
									timeout = setTimeout(function() {
										_this.delaying = false;
										_this.build();
									}, 0);
								}
							};
							this.initializing = { abort: function abort() {
								forEach(images, function(image) {
									if (!image.complete) {
										removeListener(image, EVENT_LOAD, progress);
										removeListener(image, EVENT_ERROR, progress);
									}
								});
							} };
							forEach(images, function(image) {
								if (image.complete) progress();
								else {
									var onLoad;
									var onError;
									addListener(image, EVENT_LOAD, onLoad = function onLoad() {
										removeListener(image, EVENT_ERROR, onError);
										progress();
									}, { once: true });
									addListener(image, EVENT_ERROR, onError = function onError() {
										removeListener(image, EVENT_LOAD, onLoad);
										progress();
									}, { once: true });
								}
							});
						} else addListener(element, EVENT_CLICK, this.onStart = function(_ref) {
							var target = _ref.target;
							if (target.localName === "img" && (!isFunction(options.filter) || options.filter.call(_this, target))) _this.view(_this.images.indexOf(target));
						});
					}
				}, {
					key: "build",
					value: function build() {
						if (this.ready) return;
						var element = this.element, options = this.options;
						var parent = element.parentNode;
						var template = document.createElement("div");
						template.innerHTML = TEMPLATE;
						var viewer = template.querySelector(".".concat(NAMESPACE, "-container"));
						var title = viewer.querySelector(".".concat(NAMESPACE, "-title"));
						var toolbar = viewer.querySelector(".".concat(NAMESPACE, "-toolbar"));
						var navbar = viewer.querySelector(".".concat(NAMESPACE, "-navbar"));
						var button = viewer.querySelector(".".concat(NAMESPACE, "-button"));
						var canvas = viewer.querySelector(".".concat(NAMESPACE, "-canvas"));
						this.parent = parent;
						this.viewer = viewer;
						this.title = title;
						this.toolbar = toolbar;
						this.navbar = navbar;
						this.button = button;
						this.canvas = canvas;
						this.footer = viewer.querySelector(".".concat(NAMESPACE, "-footer"));
						this.tooltipBox = viewer.querySelector(".".concat(NAMESPACE, "-tooltip"));
						this.player = viewer.querySelector(".".concat(NAMESPACE, "-player"));
						this.list = viewer.querySelector(".".concat(NAMESPACE, "-list"));
						viewer.id = "".concat(NAMESPACE).concat(this.id);
						title.id = "".concat(NAMESPACE, "Title").concat(this.id);
						addClass(title, !options.title ? CLASS_HIDE : getResponsiveClass(Array.isArray(options.title) ? options.title[0] : options.title));
						addClass(navbar, !options.navbar ? CLASS_HIDE : getResponsiveClass(options.navbar));
						toggleClass(button, CLASS_HIDE, !options.button);
						if (options.keyboard) button.setAttribute("tabindex", 0);
						if (options.backdrop) {
							addClass(viewer, "".concat(NAMESPACE, "-backdrop"));
							if (!options.inline && options.backdrop !== "static") setData(canvas, DATA_ACTION, "hide");
						}
						if (isString(options.className) && options.className) options.className.split(REGEXP_SPACES).forEach(function(className) {
							addClass(viewer, className);
						});
						if (options.toolbar) {
							var list = document.createElement("ul");
							var custom = isPlainObject(options.toolbar);
							var zoomButtons = BUTTONS.slice(0, 3);
							var rotateButtons = BUTTONS.slice(7, 9);
							var scaleButtons = BUTTONS.slice(9);
							if (!custom) addClass(toolbar, getResponsiveClass(options.toolbar));
							forEach(custom ? options.toolbar : BUTTONS, function(value, index) {
								var deep = custom && isPlainObject(value);
								var name = custom ? hyphenate(index) : value;
								var show = deep && !isUndefined(value.show) ? value.show : value;
								if (!show || !options.zoomable && zoomButtons.indexOf(name) !== -1 || !options.rotatable && rotateButtons.indexOf(name) !== -1 || !options.scalable && scaleButtons.indexOf(name) !== -1) return;
								var size = deep && !isUndefined(value.size) ? value.size : value;
								var click = deep && !isUndefined(value.click) ? value.click : value;
								var item = document.createElement("li");
								if (options.keyboard) item.setAttribute("tabindex", 0);
								item.setAttribute("role", "button");
								addClass(item, "".concat(NAMESPACE, "-").concat(name));
								if (!isFunction(click)) setData(item, DATA_ACTION, name);
								if (isNumber(show)) addClass(item, getResponsiveClass(show));
								if (["small", "large"].indexOf(size) !== -1) addClass(item, "".concat(NAMESPACE, "-").concat(size));
								else if (name === "play") addClass(item, "".concat(NAMESPACE, "-large"));
								if (isFunction(click)) addListener(item, EVENT_CLICK, click);
								list.appendChild(item);
							});
							toolbar.appendChild(list);
						} else addClass(toolbar, CLASS_HIDE);
						if (!options.rotatable) {
							var rotates = toolbar.querySelectorAll("li[class*=\"rotate\"]");
							addClass(rotates, CLASS_INVISIBLE);
							forEach(rotates, function(rotate) {
								toolbar.appendChild(rotate);
							});
						}
						if (options.inline) {
							addClass(button, CLASS_FULLSCREEN);
							setStyle(viewer, { zIndex: options.zIndexInline });
							if (window.getComputedStyle(parent).position === "static") setStyle(parent, { position: "relative" });
							parent.insertBefore(viewer, element.nextSibling);
						} else {
							addClass(button, CLASS_CLOSE);
							addClass(viewer, CLASS_FIXED);
							addClass(viewer, CLASS_FADE);
							addClass(viewer, CLASS_HIDE);
							setStyle(viewer, { zIndex: options.zIndex });
							var container = options.container;
							if (isString(container)) container = element.ownerDocument.querySelector(container);
							if (!container) container = this.body;
							container.appendChild(viewer);
						}
						if (options.inline) {
							this.render();
							this.bind();
							this.isShown = true;
						}
						this.ready = true;
						if (isFunction(options.ready)) addListener(element, EVENT_READY, options.ready, { once: true });
						if (dispatchEvent(element, EVENT_READY) === false) {
							this.ready = false;
							return;
						}
						if (this.ready && options.inline) this.view(this.index);
					}
				}], [{
					key: "noConflict",
					value: function noConflict() {
						window.Viewer = AnotherViewer;
						return Viewer;
					}
				}, {
					key: "setDefaults",
					value: function setDefaults(options) {
						assign(DEFAULTS, isPlainObject(options) && options);
					}
				}]);
				return Viewer;
			}();
			assign(Viewer.prototype, render, events, handlers, methods, others);
			return Viewer;
		}));
	}));
	var require_md5 = __commonJSMin(((exports, module) => {
		(function($) {
			"use strict";
			function safeAdd(x, y) {
				var lsw = (x & 65535) + (y & 65535);
				return (x >> 16) + (y >> 16) + (lsw >> 16) << 16 | lsw & 65535;
			}
			function bitRotateLeft(num, cnt) {
				return num << cnt | num >>> 32 - cnt;
			}
			function md5cmn(q, a, b, x, s, t) {
				return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
			}
			function md5ff(a, b, c, d, x, s, t) {
				return md5cmn(b & c | ~b & d, a, b, x, s, t);
			}
			function md5gg(a, b, c, d, x, s, t) {
				return md5cmn(b & d | c & ~d, a, b, x, s, t);
			}
			function md5hh(a, b, c, d, x, s, t) {
				return md5cmn(b ^ c ^ d, a, b, x, s, t);
			}
			function md5ii(a, b, c, d, x, s, t) {
				return md5cmn(c ^ (b | ~d), a, b, x, s, t);
			}
			function binlMD5(x, len) {
				x[len >> 5] |= 128 << len % 32;
				x[(len + 64 >>> 9 << 4) + 14] = len;
				var i;
				var olda;
				var oldb;
				var oldc;
				var oldd;
				var a = 1732584193;
				var b = -271733879;
				var c = -1732584194;
				var d = 271733878;
				for (i = 0; i < x.length; i += 16) {
					olda = a;
					oldb = b;
					oldc = c;
					oldd = d;
					a = md5ff(a, b, c, d, x[i], 7, -680876936);
					d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
					c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
					b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
					a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
					d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
					c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
					b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
					a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
					d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
					c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
					b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
					a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
					d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
					c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
					b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
					a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
					d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
					c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
					b = md5gg(b, c, d, a, x[i], 20, -373897302);
					a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
					d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
					c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
					b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
					a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
					d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
					c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
					b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
					a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
					d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
					c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
					b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
					a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
					d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
					c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
					b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
					a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
					d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
					c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
					b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
					a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
					d = md5hh(d, a, b, c, x[i], 11, -358537222);
					c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
					b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
					a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
					d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
					c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
					b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
					a = md5ii(a, b, c, d, x[i], 6, -198630844);
					d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
					c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
					b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
					a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
					d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
					c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
					b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
					a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
					d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
					c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
					b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
					a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
					d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
					c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
					b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
					a = safeAdd(a, olda);
					b = safeAdd(b, oldb);
					c = safeAdd(c, oldc);
					d = safeAdd(d, oldd);
				}
				return [
					a,
					b,
					c,
					d
				];
			}
			function binl2rstr(input) {
				var i;
				var output = "";
				var length32 = input.length * 32;
				for (i = 0; i < length32; i += 8) output += String.fromCharCode(input[i >> 5] >>> i % 32 & 255);
				return output;
			}
			function rstr2binl(input) {
				var i;
				var output = [];
				output[(input.length >> 2) - 1] = void 0;
				for (i = 0; i < output.length; i += 1) output[i] = 0;
				var length8 = input.length * 8;
				for (i = 0; i < length8; i += 8) output[i >> 5] |= (input.charCodeAt(i / 8) & 255) << i % 32;
				return output;
			}
			function rstrMD5(s) {
				return binl2rstr(binlMD5(rstr2binl(s), s.length * 8));
			}
			function rstrHMACMD5(key, data) {
				var i;
				var bkey = rstr2binl(key);
				var ipad = [];
				var opad = [];
				var hash;
				ipad[15] = opad[15] = void 0;
				if (bkey.length > 16) bkey = binlMD5(bkey, key.length * 8);
				for (i = 0; i < 16; i += 1) {
					ipad[i] = bkey[i] ^ 909522486;
					opad[i] = bkey[i] ^ 1549556828;
				}
				hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
				return binl2rstr(binlMD5(opad.concat(hash), 640));
			}
			function rstr2hex(input) {
				var hexTab = "0123456789abcdef";
				var output = "";
				var x;
				var i;
				for (i = 0; i < input.length; i += 1) {
					x = input.charCodeAt(i);
					output += hexTab.charAt(x >>> 4 & 15) + hexTab.charAt(x & 15);
				}
				return output;
			}
			function str2rstrUTF8(input) {
				return unescape(encodeURIComponent(input));
			}
			function rawMD5(s) {
				return rstrMD5(str2rstrUTF8(s));
			}
			function hexMD5(s) {
				return rstr2hex(rawMD5(s));
			}
			function rawHMACMD5(k, d) {
				return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d));
			}
			function hexHMACMD5(k, d) {
				return rstr2hex(rawHMACMD5(k, d));
			}
			function md5(string, key, raw) {
				if (!key) {
					if (!raw) return hexMD5(string);
					return rawMD5(string);
				}
				if (!raw) return hexHMACMD5(key, string);
				return rawHMACMD5(key, string);
			}
			if (typeof define === "function" && define.amd) define(function() {
				return md5;
			});
			else if (typeof module === "object" && module.exports) module.exports = md5;
			else $.md5 = md5;
		})(exports);
	}));
	var import_toastify = __toESM(require_toastify(), 1);
	var import_localforage = __toESM(require_localforage(), 1);
	var import_viewer = __toESM(require_viewer(), 1);
	var import_md5 = __toESM(require_md5(), 1);
	_css("/*!\n * Toastify js 1.12.0\n * https://github.com/apvarun/toastify-js\n * @license MIT licensed\n *\n * Copyright (C) 2018 Varun A P\n */\n.toastify{color:#fff;opacity:0;cursor:pointer;z-index:2147483647;background:linear-gradient(135deg,#73a5ff,#5477f5);border-radius:2px;max-width:calc(50% - 20px);padding:12px 20px;text-decoration:none;transition:all .4s cubic-bezier(.215,.61,.355,1);display:inline-block;position:fixed;box-shadow:0 3px 6px -1px #0000001f,0 10px 36px -4px #4d60e84d}.toastify.on{opacity:1}.toast-close{color:#fff;cursor:pointer;opacity:.4;background:0 0;border:0;padding:0 5px;font-family:inherit;font-size:1em}.toastify-right{right:15px}.toastify-left{left:15px}.toastify-top{top:-150px}.toastify-bottom{bottom:-150px}.toastify-rounded{border-radius:25px}.toastify-avatar{border-radius:2px;width:1.5em;height:1.5em;margin:-7px 5px}.toastify-center{max-width:-moz-fit-content;margin-left:auto;margin-right:auto;left:0;right:0}@media only screen and (width<=360px){.toastify-right,.toastify-left{max-width:fit-content;margin-left:auto;margin-right:auto;left:0;right:0}}");
	_css("/*!\n * Viewer.js v1.11.1\n * https://fengyuanchen.github.io/viewerjs\n *\n * Copyright 2015-present Chen Fengyuan\n * Released under the MIT license\n *\n * Date: 2022-11-06T05:18:17.414Z\n */\n.viewer-close:before,.viewer-flip-horizontal:before,.viewer-flip-vertical:before,.viewer-fullscreen-exit:before,.viewer-fullscreen:before,.viewer-next:before,.viewer-one-to-one:before,.viewer-play:before,.viewer-prev:before,.viewer-reset:before,.viewer-rotate-left:before,.viewer-rotate-right:before,.viewer-zoom-in:before,.viewer-zoom-out:before{color:#0000;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:280px;width:20px;height:20px;font-size:0;line-height:0;display:block}.viewer-zoom-in:before{content:\"Zoom In\";background-position:0 0}.viewer-zoom-out:before{content:\"Zoom Out\";background-position:-20px 0}.viewer-one-to-one:before{content:\"One to One\";background-position:-40px 0}.viewer-reset:before{content:\"Reset\";background-position:-60px 0}.viewer-prev:before{content:\"Previous\";background-position:-80px 0}.viewer-play:before{content:\"Play\";background-position:-100px 0}.viewer-next:before{content:\"Next\";background-position:-120px 0}.viewer-rotate-left:before{content:\"Rotate Left\";background-position:-140px 0}.viewer-rotate-right:before{content:\"Rotate Right\";background-position:-160px 0}.viewer-flip-horizontal:before{content:\"Flip Horizontal\";background-position:-180px 0}.viewer-flip-vertical:before{content:\"Flip Vertical\";background-position:-200px 0}.viewer-fullscreen:before{content:\"Enter Full Screen\";background-position:-220px 0}.viewer-fullscreen-exit:before{content:\"Exit Full Screen\";background-position:-240px 0}.viewer-close:before{content:\"Close\";background-position:-260px 0}.viewer-container{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;user-select:none;direction:ltr;font-size:0;line-height:0;position:absolute;inset:0;overflow:hidden}.viewer-container ::-moz-selection{background-color:#0000}.viewer-container::-moz-selection{background-color:#0000}.viewer-container ::selection{background-color:#0000}.viewer-container::selection{background-color:#0000}.viewer-container:focus{outline:0}.viewer-container img{width:100%;height:auto;display:block;min-width:0!important;max-width:none!important;min-height:0!important;max-height:none!important}.viewer-canvas{position:absolute;inset:0;overflow:hidden}.viewer-canvas>img{width:auto;height:auto;margin:15px auto;max-width:90%!important}.viewer-footer{text-align:center;position:absolute;bottom:0;left:0;right:0;overflow:hidden}.viewer-navbar{background-color:#00000080;overflow:hidden}.viewer-list{box-sizing:content-box;height:50px;margin:0;padding:1px 0;overflow:hidden}.viewer-list>li{color:#0000;cursor:pointer;float:left;opacity:.5;width:30px;height:50px;font-size:0;line-height:0;transition:opacity .15s;overflow:hidden}.viewer-list>li:focus,.viewer-list>li:hover{opacity:.75}.viewer-list>li:focus{outline:0}.viewer-list>li+li{margin-left:1px}.viewer-list>.viewer-loading{position:relative}.viewer-list>.viewer-loading:after{border-width:2px;width:20px;height:20px;margin-top:-10px;margin-left:-10px}.viewer-list>.viewer-active,.viewer-list>.viewer-active:focus,.viewer-list>.viewer-active:hover{opacity:1}.viewer-player{cursor:none;z-index:1;background-color:#000;display:none;bottom:0;right:0}.viewer-player,.viewer-player>img{position:absolute;top:0;left:0}.viewer-toolbar>ul{margin:0 auto 5px;padding:6px 3px;display:inline-block;overflow:hidden}.viewer-toolbar>ul>li{cursor:pointer;float:left;background-color:#00000080;border-radius:50%;width:24px;height:24px;transition:background-color .15s;overflow:hidden}.viewer-toolbar>ul>li:focus,.viewer-toolbar>ul>li:hover{background-color:#000c}.viewer-toolbar>ul>li:focus{z-index:1;outline:0;position:relative;box-shadow:0 0 3px #fff}.viewer-toolbar>ul>li:before{margin:2px}.viewer-toolbar>ul>li+li{margin-left:1px}.viewer-toolbar>ul>.viewer-small{width:18px;height:18px;margin-top:3px;margin-bottom:3px}.viewer-toolbar>ul>.viewer-small:before{margin:-1px}.viewer-toolbar>ul>.viewer-large{width:30px;height:30px;margin-top:-3px;margin-bottom:-3px}.viewer-toolbar>ul>.viewer-large:before{margin:5px}.viewer-tooltip{color:#fff;text-align:center;background-color:#000c;border-radius:10px;width:50px;height:20px;margin-top:-10px;margin-left:-25px;font-size:12px;line-height:20px;display:none;position:absolute;top:50%;left:50%}.viewer-title{color:#ccc;opacity:.8;text-overflow:ellipsis;white-space:nowrap;max-width:90%;min-height:14px;margin:5px 5%;font-size:12px;line-height:1.2;transition:opacity .15s;display:inline-block;overflow:hidden}.viewer-title:hover{opacity:1}.viewer-button{-webkit-app-region:no-drag;cursor:pointer;background-color:#00000080;border-radius:50%;width:80px;height:80px;transition:background-color .15s;position:absolute;top:-40px;right:-40px;overflow:hidden}.viewer-button:focus,.viewer-button:hover{background-color:#000c}.viewer-button:focus{outline:0;box-shadow:0 0 3px #fff}.viewer-button:before{position:absolute;bottom:15px;left:15px}.viewer-fixed{position:fixed}.viewer-open{overflow:hidden}.viewer-show{display:block}.viewer-hide{display:none}.viewer-backdrop{background-color:#00000080}.viewer-invisible{visibility:hidden}.viewer-move{cursor:move;cursor:grab}.viewer-fade{opacity:0}.viewer-in{opacity:1}.viewer-transition{transition:all .3s}@keyframes viewer-spinner{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.viewer-loading:after{content:\"\";z-index:1;border:4px solid #ffffff1a;border-left-color:#ffffff80;border-radius:50%;width:40px;height:40px;margin-top:-20px;margin-left:-20px;animation:1s linear infinite viewer-spinner;display:inline-block;position:absolute;top:50%;left:50%}@media (width<=767px){.viewer-hide-xs-down{display:none}}@media (width<=991px){.viewer-hide-sm-down{display:none}}@media (width<=1199px){.viewer-hide-md-down{display:none}}");
	_css(".tabulator{text-align:left;background-color:#fff;font-size:14px;position:relative;overflow:hidden;transform:translateZ(0)}.tabulator[tabulator-layout=fitDataFill] .tabulator-tableholder .tabulator-table{min-width:100%}.tabulator[tabulator-layout=fitDataTable]{display:inline-block}.tabulator.tabulator-block-select,.tabulator.tabulator-ranges .tabulator-cell:not(.tabulator-editing){-webkit-user-select:none;user-select:none}.tabulator .tabulator-header{box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;white-space:nowrap;border-bottom:1px solid #999;outline:none;width:100%;position:relative;overflow:hidden}.tabulator .tabulator-header.tabulator-header-hidden{display:none}.tabulator .tabulator-header .tabulator-header-contents{position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-header-contents .tabulator-headers{display:inline-block}.tabulator .tabulator-header .tabulator-col{box-sizing:border-box;text-align:left;vertical-align:bottom;background:#f9fafb;border-right:1px solid #ddd;flex-direction:column;justify-content:flex-start;display:inline-flex;position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-col.tabulator-moving{pointer-events:none;background:#dae1e7;border:1px solid #999;position:absolute}.tabulator .tabulator-header .tabulator-col.tabulator-range-highlight{color:#000;background-color:#d6d6d6}.tabulator .tabulator-header .tabulator-col.tabulator-range-selected{color:#fff;background-color:#3876ca}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{box-sizing:border-box;padding:4px;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button{padding:0 8px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button:hover{cursor:pointer;opacity:.6}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title-holder{position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title{box-sizing:border-box;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap;width:100%;overflow:hidden}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title.tabulator-col-title-wrap{text-overflow:clip;white-space:normal}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-title-editor{box-sizing:border-box;background:#fff;border:1px solid #999;width:100%;padding:1px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-header-popup-button+.tabulator-title-editor{width:calc(100% - 22px)}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{align-items:center;display:flex;position:absolute;top:0;bottom:0;right:4px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:6px solid #bbb;border-left:6px solid #0000;border-right:6px solid #0000;width:0;height:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{border-top:1px solid #ddd;margin-right:-1px;display:flex;position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter{box-sizing:border-box;text-align:center;width:100%;margin-top:2px;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter textarea{height:auto!important}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter svg{margin-top:3px}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input::-ms-clear{width:0;height:0}.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-right:25px}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover{cursor:pointer;background-color:#dae1e7}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter{color:#bbb}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #bbb}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #666}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-top:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{color:#666;border-top:6px solid #666;border-bottom:none}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical .tabulator-col-content .tabulator-col-title{text-orientation:mixed;writing-mode:vertical-rl;justify-content:center;align-items:center;display:flex}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-col-vertical-flip .tabulator-col-title{transform:rotate(180deg)}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-title{padding-top:20px;padding-right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-vertical-flip .tabulator-col-title{padding-bottom:20px;padding-right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-sorter{justify-content:center;inset:4px 0 auto}.tabulator .tabulator-header .tabulator-frozen{z-index:11;position:sticky;left:0}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left{border-right:2px solid #ddd}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-right{border-left:2px solid #ddd}.tabulator .tabulator-header .tabulator-calcs-holder{box-sizing:border-box;border-top:1px solid #ddd;border-bottom:1px solid #ddd;display:inline-block;background:#fff!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row{background:#fff!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-header .tabulator-frozen-rows-holder{display:inline-block}.tabulator .tabulator-header .tabulator-frozen-rows-holder:empty{display:none}.tabulator .tabulator-tableholder{-webkit-overflow-scrolling:touch;white-space:nowrap;width:100%;position:relative;overflow:auto}.tabulator .tabulator-tableholder:focus{outline:none}.tabulator .tabulator-tableholder .tabulator-placeholder{box-sizing:border-box;justify-content:center;align-items:center;width:100%;min-width:100%;display:flex}.tabulator .tabulator-tableholder .tabulator-placeholder[tabulator-render-mode=virtual]{min-height:100%}.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents{color:#ccc;text-align:center;white-space:normal;padding:10px;font-size:20px;font-weight:700;display:inline-block}.tabulator .tabulator-tableholder .tabulator-table{color:#333;white-space:nowrap;background-color:#fff;display:inline-block;position:relative;overflow:visible}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs{font-weight:700;background:#e2e2e2!important}.tabulator .tabulator-tableholder .tabulator-range-overlay{pointer-events:none;z-index:10;position:absolute;inset:0}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range{box-sizing:border-box;border:1px solid #2975dd;position:absolute}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{content:\"\";background-color:#2975dd;border-radius:999px;width:6px;height:6px;position:absolute;bottom:-3px;right:-3px}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range-cell-active{box-sizing:border-box;border:2px solid #2975dd;position:absolute}.tabulator .tabulator-footer{color:#555;-webkit-user-select:none;user-select:none;-khtml-user-select:none;-o-user-select:none;white-space:nowrap;background-color:#fff;border-top:1px solid #999;font-weight:700}.tabulator .tabulator-footer .tabulator-footer-contents{flex-direction:row;justify-content:space-between;align-items:center;padding:5px 10px;display:flex}.tabulator .tabulator-footer .tabulator-footer-contents:empty{display:none}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs{margin-top:-5px;overflow-x:auto}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab{border:1px solid #22242626;border-top:none;border-bottom-right-radius:5px;border-bottom-left-radius:5px;padding:5px;font-size:.9em;display:inline-block}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab:hover{cursor:pointer;opacity:.7}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab.tabulator-spreadsheet-tab-active{background:#fff}.tabulator .tabulator-footer .tabulator-calcs-holder{box-sizing:border-box;text-align:left;border-top:1px solid #ddd;border-bottom:1px solid #ddd;width:100%;overflow:hidden}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row{display:inline-block}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-footer .tabulator-calcs-holder:only-child{margin-bottom:-5px}.tabulator .tabulator-footer>*+.tabulator-page-counter{margin-left:10px}.tabulator .tabulator-footer .tabulator-page-counter{font-weight:400}.tabulator .tabulator-footer .tabulator-paginator{color:#555;font-family:inherit;font-size:inherit;font-weight:inherit;text-align:right;flex:1}.tabulator .tabulator-footer .tabulator-page-size{border:1px solid #aaa;border-radius:3px;margin:0 5px;padding:2px 5px;display:inline-block}.tabulator .tabulator-footer .tabulator-pages{margin:0 7px}.tabulator .tabulator-footer .tabulator-page{background:#fff3;border:1px solid #aaa;border-radius:3px;margin:0 2px;padding:2px 5px;display:inline-block}.tabulator .tabulator-footer .tabulator-page.active{color:#d00}.tabulator .tabulator-footer .tabulator-page:disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-footer .tabulator-page:not(disabled):hover{color:#fff;cursor:pointer;background:#0003}}.tabulator .tabulator-col-resize-handle{vertical-align:middle;z-index:11;width:6px;margin-left:-3px;margin-right:-3px;display:inline-block;position:relative}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-col-resize-handle:hover{cursor:ew-resize}}.tabulator .tabulator-col-resize-handle:last-of-type{width:3px;margin-right:0}.tabulator .tabulator-col-resize-guide{opacity:.5;background-color:#999;width:4px;height:100%;margin-left:-.5px;position:absolute;top:0}.tabulator .tabulator-row-resize-guide{opacity:.5;background-color:#999;width:100%;height:4px;margin-top:-.5px;position:absolute;left:0}.tabulator .tabulator-alert{text-align:center;z-index:100;background:#0006;align-items:center;width:100%;height:100%;display:flex;position:absolute;top:0;left:0}.tabulator .tabulator-alert .tabulator-alert-msg{background:#fff;border-radius:10px;margin:0 auto;padding:10px 20px;font-size:16px;font-weight:700;display:inline-block}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg{color:#000;border:4px solid #333}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error{color:#590000;border:4px solid #d00}.tabulator-row{box-sizing:border-box;background-color:#fff;min-height:22px;position:relative}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selectable:hover{cursor:pointer;background-color:#bbb}}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selected:hover{cursor:pointer;background-color:#769bcc}}.tabulator-row.tabulator-row-moving{background:#fff;border:1px solid #000}.tabulator-row.tabulator-moving{pointer-events:none;z-index:15;border-top:1px solid #ddd;border-bottom:1px solid #ddd;position:absolute}.tabulator-row.tabulator-range-highlight .tabulator-cell.tabulator-range-row-header{color:#000;background-color:#d6d6d6}.tabulator-row.tabulator-range-highlight.tabulator-range-selected .tabulator-cell.tabulator-range-row-header,.tabulator-row.tabulator-range-selected .tabulator-cell.tabulator-range-row-header{color:#fff;background-color:#3876ca}.tabulator-row .tabulator-row-resize-handle{height:5px;position:absolute;bottom:0;left:0;right:0}.tabulator-row .tabulator-row-resize-handle.prev{top:0;bottom:auto}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-row-resize-handle:hover{cursor:ns-resize}}.tabulator-row .tabulator-responsive-collapse{box-sizing:border-box;border-top:1px solid #ddd;border-bottom:1px solid #ddd;padding:5px}.tabulator-row .tabulator-responsive-collapse:empty{display:none}.tabulator-row .tabulator-responsive-collapse table{font-size:14px}.tabulator-row .tabulator-responsive-collapse table tr td{position:relative}.tabulator-row .tabulator-responsive-collapse table tr td:first-of-type{padding-right:10px}.tabulator-row .tabulator-cell{box-sizing:border-box;text-overflow:ellipsis;white-space:nowrap;border-right:1px solid #ddd;outline:none;padding:4px;display:inline-block;position:relative;overflow:hidden}.tabulator-row .tabulator-cell.tabulator-row-header{background:#f9fafb;border-bottom:1px solid #ddd;border-right:1px solid #22242626}.tabulator-row .tabulator-cell.tabulator-frozen{background-color:inherit;z-index:11;display:inline-block;position:sticky;left:0}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-right:2px solid #ddd}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-left:2px solid #ddd}.tabulator-row .tabulator-cell.tabulator-editing{border:1px solid #1d68cd;outline:none;padding:0}.tabulator-row .tabulator-cell.tabulator-editing input,.tabulator-row .tabulator-cell.tabulator-editing select{background:0 0;border:1px;outline:none}.tabulator-row .tabulator-cell.tabulator-validation-fail{border:1px solid #db2828}.tabulator-row .tabulator-cell.tabulator-validation-fail input,.tabulator-row .tabulator-cell.tabulator-validation-fail select{color:#db2828;background:0 0;border:1px}.tabulator-row .tabulator-cell.tabulator-row-handle{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;justify-content:center;align-items:center;display:inline-flex}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box{width:80%}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box .tabulator-row-handle-bar{background:#666;width:100%;height:3px;margin-top:2px}.tabulator-row .tabulator-cell.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not(.tabulator-range-row-header){background-color:#9abcea}.tabulator-row .tabulator-cell .tabulator-data-tree-branch-empty{width:7px;display:inline-block}.tabulator-row .tabulator-cell .tabulator-data-tree-branch{vertical-align:middle;border-bottom:2px solid #ddd;border-left:2px solid #ddd;border-bottom-left-radius:1px;width:7px;height:9px;margin-top:-9px;margin-right:5px;display:inline-block}.tabulator-row .tabulator-cell .tabulator-data-tree-control{vertical-align:middle;background:#0000001a;border:1px solid #333;border-radius:2px;justify-content:center;align-items:center;width:11px;height:11px;margin-right:5px;display:inline-flex;overflow:hidden}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-data-tree-control:hover{cursor:pointer;background:#0003}}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:0 0;width:1px;height:7px;display:inline-block;position:relative}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;width:1px;height:7px;display:inline-block;position:relative}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;background:#666;border-radius:20px;justify-content:center;align-items:center;width:15px;height:15px;font-size:1.1em;font-weight:700;display:inline-flex}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle:hover{cursor:pointer;opacity:.7}}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-close{display:initial}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-open{display:none}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle svg{stroke:#fff}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle .tabulator-responsive-collapse-toggle-close{display:none}.tabulator-row .tabulator-cell .tabulator-traffic-light{border-radius:14px;width:14px;height:14px;display:inline-block}.tabulator-row.tabulator-group{box-sizing:border-box;background:#ccc;border-top:1px solid #999;border-bottom:1px solid #999;border-right:1px solid #ddd;min-width:100%;padding:5px 5px 5px 10px;font-weight:700}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-group:hover{cursor:pointer;background-color:#0000001a}}.tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow{border:6px solid #0000;border-top-color:#666;border-bottom:0;margin-right:10px}.tabulator-row.tabulator-group.tabulator-group-level-1{padding-left:30px}.tabulator-row.tabulator-group.tabulator-group-level-2{padding-left:50px}.tabulator-row.tabulator-group.tabulator-group-level-3{padding-left:70px}.tabulator-row.tabulator-group.tabulator-group-level-4{padding-left:90px}.tabulator-row.tabulator-group.tabulator-group-level-5{padding-left:110px}.tabulator-row.tabulator-group .tabulator-group-toggle{display:inline-block}.tabulator-row.tabulator-group .tabulator-arrow{vertical-align:middle;border:6px solid #0000;border-left-color:#666;border-right:0;width:0;height:0;margin-right:16px;display:inline-block}.tabulator-row.tabulator-group span{color:#d00;margin-left:10px}.tabulator-toggle{box-sizing:border-box;background:#dcdcdc;border:1px solid #ccc;flex-direction:row;display:flex}.tabulator-toggle.tabulator-toggle-on{background:#1c6cc2}.tabulator-toggle .tabulator-toggle-switch{box-sizing:border-box;background:#fff;border:1px solid #ccc}.tabulator-popup-container{-webkit-overflow-scrolling:touch;box-sizing:border-box;z-index:10000;background:#fff;border:1px solid #ddd;font-size:14px;display:inline-block;position:absolute;overflow-y:auto;box-shadow:0 0 5px #0003}.tabulator-popup{border-radius:3px;padding:5px}.tabulator-tooltip{box-shadow:none;pointer-events:none;border-radius:2px;max-width:min(500px,100%);padding:3px 5px;font-size:12px}.tabulator-menu .tabulator-menu-item{box-sizing:border-box;-webkit-user-select:none;user-select:none;padding:5px 10px;position:relative}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover{cursor:pointer;background:#efefef}}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu{padding-right:25px}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu:after{content:\"\";vertical-align:top;border:1px solid #ddd;border-width:1px 1px 0 0;width:7px;height:7px;display:inline-block;position:absolute;top:calc(5px + .4em);right:10px;transform:rotate(45deg)}.tabulator-menu .tabulator-menu-separator{border-top:1px solid #ddd}.tabulator-edit-list{-webkit-overflow-scrolling:touch;max-height:200px;font-size:14px;overflow-y:auto}.tabulator-edit-list .tabulator-edit-list-item{color:#333;outline:none;padding:4px}.tabulator-edit-list .tabulator-edit-list-item.active{color:#fff;background:#1d68cd}.tabulator-edit-list .tabulator-edit-list-item.active.focused{outline:1px solid #ffffff80}.tabulator-edit-list .tabulator-edit-list-item.focused{outline:1px solid #1d68cd}@media (hover:hover) and (pointer:fine){.tabulator-edit-list .tabulator-edit-list-item:hover{color:#fff;cursor:pointer;background:#1d68cd}}.tabulator-edit-list .tabulator-edit-list-placeholder{color:#333;text-align:center;padding:4px}.tabulator-edit-list .tabulator-edit-list-group{color:#333;border-bottom:1px solid #ddd;padding:6px 4px 4px;font-weight:700}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-2,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-2{padding-left:12px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-3,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-3{padding-left:20px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-4,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-4{padding-left:28px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-5,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-5{padding-left:36px}.tabulator.tabulator-ltr{direction:ltr}.tabulator.tabulator-rtl{text-align:initial;direction:rtl}.tabulator.tabulator-rtl .tabulator-header .tabulator-col{border-left:1px solid #ddd;border-right:initial;text-align:initial}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{margin-left:-1px;margin-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-left:25px;padding-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{left:8px;right:auto}.tabulator.tabulator-rtl .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{content:\"\";background-color:#2975dd;border-radius:999px;width:6px;height:6px;position:absolute;bottom:-3px;left:-3px;right:auto}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell{border-left:1px solid #ddd;border-right:initial}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-branch{border-left:initial;border-right:2px solid #ddd;border-bottom-right-radius:1px;border-bottom-left-radius:0;margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-control{margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-left:2px solid #ddd}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-right:2px solid #ddd}.tabulator.tabulator-rtl .tabulator-row .tabulator-col-resize-handle:last-of-type{width:3px;margin-left:0;margin-right:-3px}.tabulator.tabulator-rtl .tabulator-footer .tabulator-calcs-holder{text-align:initial}.tabulator-print-fullscreen{z-index:10000;position:absolute;inset:0}body.tabulator-print-fullscreen-hide>:not(.tabulator-print-fullscreen){display:none!important}.tabulator-print-table{border-collapse:collapse}.tabulator-print-table .tabulator-data-tree-branch{vertical-align:middle;border-bottom:2px solid #ddd;border-left:2px solid #ddd;border-bottom-left-radius:1px;width:7px;height:9px;margin-top:-9px;margin-right:5px;display:inline-block}.tabulator-print-table .tabulator-print-table-group{box-sizing:border-box;background:#ccc;border-top:1px solid #999;border-bottom:1px solid #999;border-right:1px solid #ddd;min-width:100%;padding:5px 5px 5px 10px;font-weight:700}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-print-table-group:hover{cursor:pointer;background-color:#0000001a}}.tabulator-print-table .tabulator-print-table-group.tabulator-group-visible .tabulator-arrow{border:6px solid #0000;border-top-color:#666;border-bottom:0;margin-right:10px}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-1 td{padding-left:30px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-2 td{padding-left:50px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-3 td{padding-left:70px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-4 td{padding-left:90px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-5 td{padding-left:110px!important}.tabulator-print-table .tabulator-print-table-group .tabulator-group-toggle{display:inline-block}.tabulator-print-table .tabulator-print-table-group .tabulator-arrow{vertical-align:middle;border:6px solid #0000;border-left-color:#666;border-right:0;width:0;height:0;margin-right:16px;display:inline-block}.tabulator-print-table .tabulator-print-table-group span{color:#d00;margin-left:10px}.tabulator-print-table .tabulator-data-tree-control{vertical-align:middle;background:#0000001a;border:1px solid #333;border-radius:2px;justify-content:center;align-items:center;width:11px;height:11px;margin-right:5px;display:inline-flex;overflow:hidden}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-data-tree-control:hover{cursor:pointer;background:#0003}}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:0 0;width:1px;height:7px;display:inline-block;position:relative}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;width:1px;height:7px;display:inline-block;position:relative}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{content:\"\";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator{box-shadow:none;color:#000000de;border:1px solid #22242626;border-radius:.28571rem;width:100%;margin:1em 0}.tabulator .tabulator-header{box-shadow:none;color:#000000de;font-style:none;text-transform:none;border-bottom:1px solid #2224261a;font-weight:700}.tabulator .tabulator-header,.tabulator .tabulator-header .tabulator-col{background-color:#f9fafb;border-right:none}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{padding:.92857em .78571em}.tabulator .tabulator-tableholder .tabulator-table{background-color:#0000}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs{background:#f2f2f2!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-top{border-bottom:2px solid #ddd}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-bottom{border-top:2px solid #ddd}.tabulator .tabulator-footer{box-shadow:none;color:#000000de;text-align:right;text-transform:none;background:#f9fafb;border-top:1px solid #22242626;padding:.78571em;font-style:normal;font-weight:400}.tabulator .tabulator-footer .tabulator-calcs-holder{margin:-.78571em -.78571em .78571em;background:#fff!important}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row{background:#fff!important}.tabulator .tabulator-footer .tabulator-calcs-holder:only-child{border-bottom:none;margin-bottom:-.78571em}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs{margin-top:calc(-.78571em - 5px)}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab.tabulator-spreadsheet-tab-active{color:#d00}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.positive,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.positive{box-shadow:inset 0 0 #a3c293;color:#21ba45!important;background:#fcfff5!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.positive:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.positive:hover{color:#13ae38!important;background:#f7ffe6!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.negative,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.negative{box-shadow:inset 0 0 #e0b4b4;color:#db2828!important;background:#fff6f6!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.negative:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.negative:hover{color:#d41616!important;background:#ffe7e7!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.error,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.error{box-shadow:inset 0 0 #e0b4b4;color:#db2828!important;background:#fff6f6!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.error:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.error:hover{color:#d12323!important;background:#ffe7e7!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.warning,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.warning{box-shadow:inset 0 0 #c9ba9b;color:#f2c037!important;background:#fffaf3!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.warning:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.warning:hover{color:#f1bb29!important;background:#fff4e4!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.active,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.active{box-shadow:inset 0 0 #000000de;color:#000000de!important;background:#e0e0e0!important}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.active:hover,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.active:hover{color:#13ae38!important;background:#f7ffe6!important}}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.active,.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.active{color:#0003;pointer-events:none}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.disabled:hover{color:#0003;pointer-events:none}}.tabulator.inverted{color:#ffffffe6;background:#333;border:none}.tabulator.inverted .tabulator-header{color:#ffffffe6;background-color:#00000026}.tabulator.inverted .tabulator-header,.tabulator.inverted .tabulator-header .tabulator-col{border-color:#ffffff1a!important}.tabulator.inverted .tabulator-tableholder .tabulator-table .tabulator-row{color:#ffffffe6;border:none}.tabulator.inverted .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{border-color:#ffffff1a!important}.tabulator.inverted .tabulator-footer{background:#fff}.tabulator.striped .tabulator-row:nth-child(2n){background-color:#f2f2f2}.tabulator.celled{border:1px solid #22242626}.tabulator.celled .tabulator-header .tabulator-col,.tabulator.celled .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{border-right:1px solid #2224261a}.tabulator[class*=single\\ line] .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{border-right:none}.tabulator.red{border-top:.2em solid #db2828}.tabulator.inverted.red{color:#fff!important;background-color:#db2828!important}.tabulator.orange{border-top:.2em solid #f2711c}.tabulator.inverted.orange{color:#fff!important;background-color:#f2711c!important}.tabulator.yellow{border-top:.2em solid #fbbd08}.tabulator.inverted.yellow{color:#fff!important;background-color:#fbbd08!important}.tabulator.olive{border-top:.2em solid #b5cc18}.tabulator.inverted.olive{color:#fff!important;background-color:#b5cc18!important}.tabulator.green{border-top:.2em solid #21ba45}.tabulator.inverted.green{color:#fff!important;background-color:#21ba45!important}.tabulator.teal{border-top:.2em solid #00b5ad}.tabulator.inverted.teal{color:#fff!important;background-color:#00b5ad!important}.tabulator.blue{border-top:.2em solid #2185d0}.tabulator.inverted.blue{color:#fff!important;background-color:#2185d0!important}.tabulator.violet{border-top:.2em solid #6435c9}.tabulator.inverted.violet{color:#fff!important;background-color:#6435c9!important}.tabulator.purple{border-top:.2em solid #a333c8}.tabulator.inverted.purple{color:#fff!important;background-color:#a333c8!important}.tabulator.pink{border-top:.2em solid #e03997}.tabulator.inverted.pink{color:#fff!important;background-color:#e03997!important}.tabulator.brown{border-top:.2em solid #a5673f}.tabulator.inverted.brown{color:#fff!important;background-color:#a5673f!important}.tabulator.grey{border-top:.2em solid #767676}.tabulator.inverted.grey{color:#fff!important;background-color:#767676!important}.tabulator.black{border-top:.2em solid #1b1c1d}.tabulator.inverted.black{color:#fff!important;background-color:#1b1c1d!important}.tabulator.padded .tabulator-header .tabulator-col .tabulator-col-content{padding:1em}.tabulator.padded .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:20px}.tabulator.padded .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:1em}.tabulator.padded.very .tabulator-header .tabulator-col .tabulator-col-content{padding:1.5em}.tabulator.padded.very .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:26px}.tabulator.padded.very .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:1.5em}.tabulator.compact .tabulator-header .tabulator-col .tabulator-col-content{padding:.5em .7em}.tabulator.compact .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:12px}.tabulator.compact .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:.5em .7em}.tabulator.compact.very .tabulator-header .tabulator-col .tabulator-col-content{padding:.4em .6em}.tabulator.compact.very .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{top:10px}.tabulator.compact.very .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:.4em .6em}.tabulator-row{border-bottom:1px solid #2224261a}.tabulator-row.tabulator-row-even{background-color:#fff}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selectable:hover{box-shadow:inset 0 0 #000000de;color:#000000de!important;background:#e0e0e0!important}}.tabulator-row.tabulator-selected{background-color:#9abcea!important}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selected:hover{cursor:pointer;background-color:#769bcc!important}}.tabulator-row.tabulator-moving{pointer-events:none!important}.tabulator-row .tabulator-cell{vertical-align:middle;border-right:none;padding:.78571em}.tabulator-row .tabulator-cell:last-of-type{border-right:none}.tabulator-row .tabulator-cell.tabulator-row-header{border-bottom:none}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle{color:#fff}.tabulator-row.tabulator-group{background:#fafafa}.tabulator-row.tabulator-group span{color:#666}.tabulator-menu{background:#fff}@media (hover:hover) and (pointer:fine){.tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover{background:#f9fafb}}.tabulator-edit-select-list{background:#fff}.tabulator-edit-select-list .tabulator-edit-select-list-item.active{color:#fff}.tabulator-edit-select-list .tabulator-edit-select-list-item.active.focused{outline:1px solid #ffffff80}@media (hover:hover) and (pointer:fine){.tabulator-edit-select-list .tabulator-edit-select-list-item:hover{color:#fff}}.tabulator-edit-select-list .tabulator-edit-select-list-notice{color:inherit}.tabulator-print-table .tabulator-print-table-group{background:#fafafa}.tabulator-print-table .tabulator-print-table-group span{color:#666}");
	window.layer = import_layer.default;
	window.Tabulator = TabulatorFull$1;
	window.Toastify = import_toastify.default;
	window.localforage = import_localforage.default;
	window.Viewer = import_viewer.default;
	window.md5 = import_md5.default;
	var currentHref = window.location.href;
	var isJavdbSite = currentHref.includes("javdb");
	var isMissavSite = /missav\.(ws|live|com)/.test(currentHref);
	var isSearchOrUserPage = currentHref.includes("/search?q") || currentHref.includes("/search/") || currentHref.includes("/users/");
	var JAVDB = "javdb";
	var ACTOR = "actor";
	var ACTRESS = "actress";
	var CENSORED = "censored";
	var UNCENSORED = "uncensored";
	function injectCss(css) {
		if (css) if (css.includes("<style>")) document.head.insertAdjacentHTML("beforeend", css);
		else {
			const el = document.createElement("style");
			el.textContent = css;
			document.head.appendChild(el);
		}
	}
	var GFRIENDS_SOURCES = [{
		name: "jsDelivr (全球CDN)",
		json: "https://cdn.jsdelivr.net/gh/gfriends/gfriends/Filetree.json",
		base: "https://cdn.jsdelivr.net/gh/gfriends/gfriends/Content/"
	}, {
		name: "GitHub Raw (备用)",
		json: "https://raw.githubusercontent.com/gfriends/gfriends/master/Filetree.json",
		base: "https://raw.githubusercontent.com/gfriends/gfriends/master/Content/"
	}];
	var GFRIENDS_CDN_INDEX_KEY = "jhs_img_cdn_index";
	var GFRIENDS_DB_NAME = "GfriendsAvatarDB";
	var FILETREE_STORE = "filetreeStore";
	var FILETREE_DATA_KEY = "filetree_data";
	async function withLoading(fn) {
		const loadingHandle = loading();
		try {
			return await fn();
		} finally {
			loadingHandle.close();
		}
	}
	var FiletreeDb = class {
		db = null;
		async open() {
			if (this.db) return this.db;
			return new Promise((resolve, reject) => {
				const request = indexedDB.open(GFRIENDS_DB_NAME, 1);
				request.onupgradeneeded = () => {
					const database = request.result;
					this.db = database;
					if (!database.objectStoreNames.contains("filetreeStore")) database.createObjectStore(FILETREE_STORE);
				};
				request.onsuccess = () => {
					const database = request.result;
					this.db = database;
					resolve(database);
				};
				request.onerror = () => {
					console.error("IndexedDB open error:", request.error);
					reject(new Error("Failed to open IndexedDB"));
				};
			});
		}
		async get(key) {
			const db = await this.open();
			return new Promise((resolve) => {
				const request = db.transaction([FILETREE_STORE], "readonly").objectStore(FILETREE_STORE).get(key);
				request.onsuccess = () => resolve(request.result ?? null);
				request.onerror = () => resolve(null);
			});
		}
		async set(key, value) {
			const db = await this.open();
			return new Promise((resolve, reject) => {
				const request = db.transaction([FILETREE_STORE], "readwrite").objectStore(FILETREE_STORE).put(value, key);
				request.onsuccess = () => resolve();
				request.onerror = () => {
					console.error("IndexedDB set error:", request.error);
					reject(new Error("Failed to write to IndexedDB"));
				};
			});
		}
	};
	var filetreeDb = new FiletreeDb();
	var cachedFiletreeRaw = null;
	var cachedFiletreeParsed = null;
	function clearCache() {
		cachedFiletreeRaw = null;
		cachedFiletreeParsed = null;
	}
	function getCurrentCdnSource() {
		const rawIndex = parseInt(localStorage.getItem("jhs_img_cdn_index") || "0", 10);
		const index = rawIndex >= 0 && rawIndex < GFRIENDS_SOURCES.length ? rawIndex : 0;
		const source = GFRIENDS_SOURCES[index];
		return {
			json: source.json,
			base: source.base,
			index
		};
	}
	function parseFiletree(data) {
		if (!data || !data.Content) return null;
		const result = {};
		const content = data.Content;
		const baseUrl = getCurrentCdnSource().base;
		for (const folderKey in content) {
			const encodedFolder = encodeURIComponent(folderKey);
			const folder = content[folderKey];
			for (const fileName in folder) {
				let namePart = fileName.replace(/\.jpg$/i, "").split("-")[0];
				if (namePart.startsWith("AI-Fix-")) namePart = namePart.substring(7);
				const normalizedName = namePart.toLowerCase().trim();
				if (normalizedName.length > 0) {
					const urlPath = folder[fileName];
					const queryIndex = urlPath.indexOf("?");
					let encodedPath;
					let queryString = "";
					if (queryIndex > -1) {
						encodedPath = encodeURIComponent(urlPath.substring(0, queryIndex));
						queryString = urlPath.substring(queryIndex);
					} else encodedPath = encodeURIComponent(urlPath);
					const fullUrl = `${baseUrl}${encodedFolder}/${encodedPath}${queryString}`;
					if (!result[normalizedName]) result[normalizedName] = [];
					if (!result[normalizedName].includes(fullUrl)) result[normalizedName].push(fullUrl);
				}
			}
		}
		return result;
	}
	async function ensureFiletreeLoaded() {
		if (cachedFiletreeRaw && cachedFiletreeParsed) return;
		let idbData = null;
		try {
			idbData = await filetreeDb.get(FILETREE_DATA_KEY);
		} catch (error) {
			console.error("读取 IndexedDB 失败:", error);
		}
		if (idbData && idbData.Content) {
			cachedFiletreeRaw = idbData;
			cachedFiletreeParsed = parseFiletree(idbData);
			if (cachedFiletreeParsed) return;
		}
		show.info("正在载入头像数据源...");
		const response = await fetch(getCurrentCdnSource().json);
		if (!response.ok) throw new Error(`请求头像源失败: ${response.status}`);
		const filetree = await response.json();
		if (filetree && filetree.Content) {
			cachedFiletreeRaw = filetree;
			cachedFiletreeParsed = parseFiletree(filetree);
			try {
				await filetreeDb.set(FILETREE_DATA_KEY, filetree);
				clog.debug("载入头像数据源并写入缓存成功!");
			} catch (error) {
				clog.error(error);
				show.error("头像数据源写入缓存失败,可能磁盘已满或其他权限问题。");
			}
			return;
		}
		console.log(filetree);
		throw new Error("解析头像数据源失败");
	}
	async function loadGfriends(actressNames) {
		try {
			await withLoading(() => ensureFiletreeLoaded());
		} catch (error) {
			show.error(error);
			return [];
		}
		const filetreeIndex = cachedFiletreeParsed;
		if (!filetreeIndex) return [];
		const urlSet = new Set();
		const normalizedNames = actressNames.map((name) => name.toLowerCase().trim()).filter((name) => name.length > 0);
		if (normalizedNames.length === 0) return [];
		for (const name of normalizedNames) {
			const urls = filetreeIndex[name];
			if (urls) urls.forEach((url) => urlSet.add(url));
		}
		return Array.from(urlSet);
	}
	var featureFlags = {
		upgradeSignature300s: true,
		caseInsensitiveCarNum: true,
		autoPageReplaceState: true,
		wantWatchBatchImport: true,
		movieShowTypeVisibility: true,
		storageCacheDeepCopy: true,
		webdavIdempotentMkdir: true,
		westernCarFormat: true,
		actressUserSelectAll: true,
		navBarNoPaste: false,
		translatePlugin: true,
		screenShotPlugin: true,
		javDbApiAggregate: true,
		magnetHubPlugin: true,
		imageRecognitionPlugin: true,
		fc2By123AvPlugin: true
	};
	(() => {
		try {
			const stored = JSON.parse(localStorage.getItem("jhs_upgrade_flags") || "{}");
			Object.assign(featureFlags, stored);
		} catch {}
	})();
	var WebDavClient = class {
		davUrl;
		username;
		password;
		folderName;
		constructor(davUrl, username, password) {
			this.davUrl = davUrl.endsWith("/") ? davUrl : davUrl + "/";
			this.username = username;
			this.password = password;
			this.folderName = null;
		}
		_getAuthHeaders() {
			return {
				Authorization: `Basic ${btoa(`${this.username}:${this.password}`)}`,
				Depth: "1"
			};
		}
		_sendRequest(method, path, headers = {}, body) {
			return new Promise((resolve, reject) => {
				const url = this.davUrl + path;
				const requestHeaders = {
					...this._getAuthHeaders(),
					...headers
				};
				GM_xmlhttpRequest({
					method,
					url,
					headers: requestHeaders,
					data: body,
					onload: (response) => {
						if (response.status >= 200 && response.status < 300) resolve(response);
						else {
							console.error(response);
							reject(new Error(`请求失败 ${response.status}: ${response.statusText}`));
						}
					},
					onerror: (error) => {
						console.error("请求WebDav发生错误:", error);
						reject(new Error("请求WebDav失败, 请检查服务是否启动, 凭证是否正确"));
					}
				});
			});
		}
		async checkFolderExists(path) {
			try {
				await this._sendRequest("PROPFIND", path, { Depth: "0" });
				return true;
			} catch (error) {
				const statusMatch = String(error?.message || "").match(/请求失败 (\d+):/);
				if ((statusMatch ? parseInt(statusMatch[1], 10) : 0) === 404) return false;
				throw error;
			}
		}
		async createFolder(folderName) {
			if (!featureFlags.webdavIdempotentMkdir) {
				await this._sendRequest("MKCOL", folderName);
				return;
			}
			try {
				if (!await this.checkFolderExists(folderName)) {
					clog.log(`目录 ${folderName} 不存在,正在创建...`);
					await this._sendRequest("MKCOL", folderName, { Depth: "0" });
					clog.log(`目录 ${folderName} 创建成功。`);
				}
			} catch (error) {
				clog.error(`创建目录 ${folderName} 时发生错误:`, error);
				throw error;
			}
		}
		async backup(folder, filename, content) {
			await this.createFolder(folder);
			const path = folder + "/" + filename;
			await this._sendRequest("PUT", path, { "Content-Type": "text/plain" }, content);
		}
		async getFileList(folder) {
			const responseText = (await this._sendRequest("PROPFIND", folder, { "Content-Type": "application/xml" }, "<?xml version=\"1.0\"?>\n                <d:propfind xmlns:d=\"DAV:\">\n                    <d:prop>\n                        <d:displayname />\n                        <d:getcontentlength />\n                        <d:creationdate />\n                        <d:getlastmodified />\n                        <d:iscollection />\n                    </d:prop>\n                </d:propfind>\n            ")).responseText;
			const responses = new DOMParser().parseFromString(responseText, "text/xml").getElementsByTagNameNS("DAV:", "response");
			const items = [];
			for (let index = 0; index < responses.length; index++) {
				if (index === 0) continue;
				const responseElement = responses[index];
				console.log(responseElement);
				const displayName = responseElement.getElementsByTagNameNS("DAV:", "displayname")[0]?.textContent || "";
				const contentLength = responseElement.getElementsByTagNameNS("DAV:", "getcontentlength")[0]?.textContent || "0";
				const createTime = responseElement.getElementsByTagNameNS("DAV:", "creationdate")[0]?.textContent || responseElement.getElementsByTagNameNS("DAV:", "getlastmodified")[0]?.textContent || "";
				if (contentLength !== "0") items.push({
					fileId: displayName,
					name: displayName,
					size: Number(contentLength),
					createTime
				});
			}
			items.reverse();
			return items;
		}
		async deleteFile(filename) {
			const path = this.folderName + "/" + encodeURI(filename);
			await this._sendRequest("DELETE", path, { "Cache-Control": "no-cache" });
		}
		async getBackupList(folder) {
			this.folderName = folder;
			await this.createFolder(folder);
			return this.getFileList(folder);
		}
		async getFileContent(filename) {
			const path = this.folderName + "/" + filename;
			return (await this._sendRequest("GET", path, { Accept: "application/octet-stream" })).responseText;
		}
	};
	function createLoading() {
		const container = document.createElement("div");
		container.className = "loading-container";
		const animation = document.createElement("div");
		animation.className = "loading-animation";
		container.appendChild(animation);
		document.body.appendChild(container);
		return { close: () => {
			if (container && container.parentNode) container.parentNode.removeChild(container);
		} };
	}
	var createToast = (message, type, position, duration, onClick) => {
		let userOptions;
		if (typeof position == "object") userOptions = position;
		else {
			userOptions = typeof duration == "object" ? duration : onClick || {};
			userOptions.gravity = position || "top";
			userOptions.position = typeof duration == "string" ? duration : "center";
		}
		if (!userOptions.gravity || userOptions.gravity === "center") userOptions.offset = { y: "calc(50vh - 150px)" };
		const infoFrom = "#60A5FA";
		const infoTo = "#93C5FD";
		const successFrom = "#10B981";
		const successTo = "#6EE7B7";
		const errorFrom = "#EF4444";
		const errorTo = "#FCA5A5";
		const baseStyle = {
			borderRadius: "12px",
			color: "white",
			padding: "12px 16px",
			boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
			minWidth: "150px",
			textAlign: "center",
			zIndex: 999999999
		};
		const toastOptions = {
			text: message,
			duration: 1e3,
			close: false,
			gravity: "top",
			position: "center",
			style: {
				info: {
					...baseStyle,
					background: `linear-gradient(to right, ${infoFrom}, ${infoTo})`
				},
				success: {
					...baseStyle,
					background: `linear-gradient(to right, ${successFrom}, ${successTo})`
				},
				error: {
					...baseStyle,
					background: `linear-gradient(to right, ${errorFrom}, ${errorTo})`
				}
			}[type],
			stopOnFocus: true,
			oldestFirst: false,
			...userOptions
		};
		if (toastOptions.duration === -1) toastOptions.close = true;
		const toast = Toastify(toastOptions);
		toast.showToast();
		toast.closeShow = () => {
			toast.toastElement.remove();
		};
		return toast;
	};
	var show$1 = {
		ok: (message, position = "center", duration, onClick) => createToast(message, "success", position, duration, onClick),
		error: (message, position = "center", duration, onClick) => createToast(message, "error", position, duration, onClick),
		info: (message, position = "center", duration, onClick) => createToast(message, "info", position, duration, onClick)
	};
	function failWithToast(msg) {
		show$1.error(msg);
		throw new Error(msg);
	}
	var VIEWER_CONFIG = (ctx) => ({
		zIndex: 999999990,
		navbar: false,
		zoomOnWheel: false,
		zoomRatio: .1,
		toggleOnDblclick: false,
		toolbar: {
			zoomIn: 1,
			zoomOut: 1,
			reset: 1,
			rotateLeft: 0,
			rotateRight: 0,
			flipHorizontal: 0,
			flipVertical: 0
		},
		title: false,
		keyboard: false,
		viewed() {
			const viewer = ctx.viewerRef.current;
			viewer.zoomTo(1.4);
			const offsetX = (viewer.viewerData.width - viewer.imageData.width) / 2;
			viewer.moveTo(offsetX, 0);
		},
		shown() {
			const viewer = ctx.viewerRef.current;
			if (ctx.isTemporary) ctx.container.remove();
			document.documentElement.style.overflow = "hidden";
			document.body.style.overflow = "hidden";
			viewer.handleKeydown = function(event) {
				if (event.key === "Escape" || event.key === " ") {
					event.preventDefault();
					event.stopPropagation();
					viewer.destroy();
					document.removeEventListener("keydown", viewer.handleKeydown);
					document.documentElement.style.overflow = "";
					document.body.style.overflow = "";
					ctx.resetOverflow();
				}
			};
			document.addEventListener("keydown", viewer.handleKeydown);
		},
		hidden() {
			const viewer = ctx.viewerRef.current;
			if (viewer && viewer.handleKeydown) document.removeEventListener("keydown", viewer.handleKeydown);
			viewer.destroy();
			document.documentElement.style.overflow = "";
			document.body.style.overflow = "";
			ctx.resetOverflow();
		}
	});
	var VOID_TAGS = new Set([
		"img",
		"input",
		"br",
		"hr",
		"meta",
		"link",
		"area",
		"base",
		"col",
		"embed",
		"param",
		"source",
		"track",
		"wbr"
	]);
	var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
	function isReactElement(node) {
		return node != null && typeof node === "object" && "type" in node && "props" in node && typeof node.props === "object" && node.props !== null;
	}
	function escapeText(s) {
		return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
	}
	function escapeAttr(s) {
		return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
	}
	function sanitizeUrl(url) {
		const trimmed = url.trim().toLowerCase();
		if (trimmed.startsWith("javascript:") || trimmed.startsWith("data:") || trimmed.startsWith("vbscript:")) return "#";
		return url;
	}
	function camelToKebab(s) {
		return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
	}
	function styleToCss(style) {
		return Object.entries(style).filter(([, v]) => v != null && v !== false).map(([k, v]) => `${camelToKebab(k)}:${v}`).join(";");
	}
	function renderAttrs(props) {
		const parts = [];
		for (const [key, value] of Object.entries(props)) {
			if (value == null || value === false) continue;
			if (key === "children") continue;
			if (key === "dangerouslySetInnerHTML") continue;
			if (key.startsWith("on")) continue;
			if (key === "className") {
				if (value !== "") parts.push(`class="${escapeAttr(String(value))}"`);
				continue;
			}
			if (key === "htmlFor") {
				parts.push(`for="${escapeAttr(String(value))}"`);
				continue;
			}
			if (key === "style") {
				if (typeof value === "string") parts.push(`style="${escapeAttr(value)}"`);
				else if (typeof value === "object" && value !== null) {
					const css = styleToCss(value);
					if (css) parts.push(`style="${escapeAttr(css)}"`);
				}
				continue;
			}
			if (value === true) {
				parts.push(key);
				continue;
			}
			const attrValue = key === "href" || key === "src" ? sanitizeUrl(String(value)) : String(value);
			parts.push(`${key}="${escapeAttr(attrValue)}"`);
		}
		return parts.length ? " " + parts.join(" ") : "";
	}
	function renderChildren(children) {
		if (children == null || typeof children === "boolean") return "";
		if (typeof children === "string") return escapeText(children);
		if (typeof children === "number" || typeof children === "bigint") return String(children);
		if (Array.isArray(children)) return children.map((c) => renderChildren(c)).join("");
		if (isReactElement(children)) return jsxToString(children);
		return "";
	}
	function jsxToString(node) {
		if (node == null || typeof node === "boolean") return "";
		if (typeof node === "string") return escapeText(node);
		if (typeof node === "number" || typeof node === "bigint") return String(node);
		if (Array.isArray(node)) return node.map(jsxToString).join("");
		if (!isReactElement(node)) return "";
		const { type, props } = node;
		if (type === REACT_FRAGMENT_TYPE) return renderChildren(props.children);
		if (typeof type === "function") return jsxToString(type(props));
		if (typeof type === "string") {
			const tag = type;
			const attrs = renderAttrs(props);
			if (VOID_TAGS.has(tag)) return `<${tag}${attrs} />`;
			const dsi = props.dangerouslySetInnerHTML;
			if (dsi && typeof dsi.__html === "string") return `<${tag}${attrs}>${dsi.__html}</${tag}>`;
			return `<${tag}${attrs}>${renderChildren(props.children)}</${tag}>`;
		}
		return "";
	}
	var require_react_jsx_runtime_production = __commonJSMin(((exports) => {
		var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
		function jsxProd(type, config, maybeKey) {
			var key = null;
			void 0 !== maybeKey && (key = "" + maybeKey);
			void 0 !== config.key && (key = "" + config.key);
			if ("key" in config) {
				maybeKey = {};
				for (var propName in config) "key" !== propName && (maybeKey[propName] = config[propName]);
			} else maybeKey = config;
			config = maybeKey.ref;
			return {
				$$typeof: REACT_ELEMENT_TYPE,
				type,
				key,
				ref: void 0 !== config ? config : null,
				props: maybeKey
			};
		}
		exports.Fragment = REACT_FRAGMENT_TYPE;
		exports.jsx = jsxProd;
		exports.jsxs = jsxProd;
	}));
	var import_jsx_runtime = __commonJSMin(((exports, module) => {
		module.exports = require_react_jsx_runtime_production();
	}))();
	var INDENT_BEFORE = "\n                ";
	var INDENT_BETWEEN = "\n                ";
	var INDENT_AFTER = "\n            ";
	var URL_PATTERN = /(?:https?|ftp):\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|]/gi;
	function linkifySafe(text) {
		const nodes = [];
		let lastIndex = 0;
		let match;
		URL_PATTERN.lastIndex = 0;
		while ((match = URL_PATTERN.exec(text)) !== null) {
			if (match.index > lastIndex) nodes.push(text.slice(lastIndex, match.index));
			const url = match[0];
			nodes.push((0, import_jsx_runtime.jsx)("a", {
				href: sanitizeUrl(url),
				target: "_blank",
				rel: "noopener noreferrer",
				children: url
			}, match.index));
			lastIndex = match.index + url.length;
		}
		if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
		return nodes;
	}
	function LoggerLogEntry({ timeStr, messageType, message }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			INDENT_BEFORE,
			(0, import_jsx_runtime.jsxs)("span", {
				className: "console-logger-timestamp",
				children: [
					"[",
					timeStr,
					"]"
				]
			}),
			INDENT_BETWEEN,
			(0, import_jsx_runtime.jsx)("span", {
				className: "console-logger-message",
				"data-type": messageType,
				children: linkifySafe(message)
			}),
			INDENT_AFTER
		] });
	}
	var LOG_TYPE_STYLES = {
		base: {
			label: "信息",
			background: "#e8f4fd",
			borderLeftColor: "#3498db"
		},
		warn: {
			label: "警告",
			background: "#fef9e7",
			borderLeftColor: "#f39c12"
		},
		error: {
			label: "错误",
			background: "#fdedec",
			borderLeftColor: "#e74c3c"
		},
		debug: {
			label: "调试",
			background: "#f4f6f6",
			borderLeftColor: "#95a5a6"
		}
	};
	var FILTER_TYPE_MAP = {
		base: [
			"base",
			"warn",
			"error"
		],
		warn: ["warn"],
		error: ["error"],
		debug: [
			"base",
			"warn",
			"error",
			"debug"
		]
	};
	var MAXIMIZE_KEY = "jhs_clog_maximize";
	var EXPAND_KEY = "jhs_clog_expand";
	var FILTER_KEY = "jhs_clog_filter";
	function createContainer(logger) {
		logger.container = document.createElement("div");
		logger.container.className = "console-logger-container";
		logger.container.style.display = "none";
		logger.toggleBtn = document.createElement("div");
		logger.toggleBtn.className = "console-logger-toggle collapsed";
		logger.container.appendChild(logger.toggleBtn);
		logger.window = document.createElement("div");
		logger.window.className = "console-logger-window collapsed";
		const header = document.createElement("div");
		header.className = "console-logger-header";
		const title = document.createElement("div");
		title.className = "console-logger-title";
		title.textContent = "JHS V3.3.2";
		const controls = document.createElement("div");
		controls.className = "console-logger-controls";
		logger.maximizeBtn = document.createElement("button");
		logger.maximizeBtn.textContent = "";
		logger.maximizeBtn.classList.add("console-logger-maximize-toggle");
		controls.appendChild(logger.maximizeBtn);
		const clearBtn = document.createElement("button");
		clearBtn.textContent = "清空";
		clearBtn.addEventListener("click", () => logger.clear());
		controls.appendChild(clearBtn);
		header.appendChild(title);
		header.appendChild(controls);
		logger.filtersContainer = document.createElement("div");
		logger.filtersContainer.className = "console-logger-filters";
		logger.filterButtonGroup = document.createElement("div");
		logger.filterButtonGroup.className = "console-logger-filter-group";
		logger.filtersContainer.appendChild(logger.filterButtonGroup);
		logger.scrollToBottomBtn = document.createElement("button");
		logger.scrollToBottomBtn.className = "console-logger-scroll-to-bottom";
		logger.scrollToBottomBtn.textContent = "到底部";
		logger.filtersContainer.appendChild(logger.scrollToBottomBtn);
		logger.content = document.createElement("div");
		logger.content.className = "console-logger-content jhs-scrollbar";
		logger.window.appendChild(header);
		logger.window.appendChild(logger.filtersContainer);
		logger.window.appendChild(logger.content);
		logger.container.appendChild(logger.window);
		document.body.appendChild(logger.container);
		Object.keys(LOG_TYPE_STYLES).forEach((typeName) => {
			const filterBtn = document.createElement("div");
			filterBtn.className = "console-logger-filter";
			if (typeName === logger.currentFilter) filterBtn.classList.add("active");
			filterBtn.textContent = LOG_TYPE_STYLES[typeName].label;
			filterBtn.dataset.type = typeName;
			filterBtn.addEventListener("click", () => logger.setFilter(typeName));
			logger.filterButtonGroup.appendChild(filterBtn);
		});
	}
	function bindEvents(logger) {
		logger.toggleBtn.addEventListener("click", () => {
			toggleExpandCollapsed(logger);
		});
		logger.maximizeBtn.addEventListener("click", () => toggleMaximize(logger));
		logger.scrollToBottomBtn.addEventListener("click", () => {
			logger.content.scrollTop = logger.content.scrollHeight;
			logger.userScrolledUp = false;
		});
		logger.content.addEventListener("scroll", () => {
			logger.userScrolledUp = !(logger.content.scrollHeight - logger.content.clientHeight <= logger.content.scrollTop + 5);
		});
		logger.content.addEventListener("wheel", (evt) => {
			const atTop = logger.content.scrollTop === 0;
			const atBottom = logger.content.scrollHeight - logger.content.clientHeight <= logger.content.scrollTop + 1;
			if (atTop && evt.deltaY < 0 || atBottom && evt.deltaY > 0) {
				evt.preventDefault();
				evt.stopPropagation();
			}
		}, { passive: false });
	}
	function toggleExpandCollapsed(logger) {
		const isCollapsed = logger.window.classList.toggle("collapsed");
		logger.toggleBtn.classList.toggle("collapsed");
		if (isCollapsed) localStorage.setItem(EXPAND_KEY, "no");
		else {
			localStorage.setItem(EXPAND_KEY, "yes");
			reRenderAllLogs(logger);
		}
	}
	function checkInitialCollapseState(logger) {
		const stored = localStorage.getItem(EXPAND_KEY);
		if (stored && stored !== "no") {
			logger.window.classList.toggle("collapsed");
			logger.toggleBtn.classList.toggle("collapsed");
			setTimeout(() => {
				logger.content.scrollTop = logger.content.scrollHeight;
			}, 0);
		} else {
			logger.window.classList.add("collapsed");
			logger.toggleBtn.classList.add("collapsed");
		}
	}
	function checkInitialMaximizeState(logger) {
		if (localStorage.getItem(MAXIMIZE_KEY) === "maximized") {
			logger.window.classList.add("maximized");
			logger.maximizeBtn.classList.add("active");
		}
	}
	function toggleMaximize(logger) {
		const isMaximized = logger.window.classList.toggle("maximized");
		logger.maximizeBtn.classList.toggle("active", isMaximized);
		if (isMaximized) localStorage.setItem(MAXIMIZE_KEY, "maximized");
		else localStorage.setItem(MAXIMIZE_KEY, "minimized");
		if (!logger.window.classList.contains("collapsed")) logger.content.scrollTop = logger.content.scrollHeight;
	}
	function renderLog(logger, entry) {
		if (logger.container.style.display === "none") return;
		if (logger.window.classList.contains("collapsed")) return;
		if (!(FILTER_TYPE_MAP[logger.currentFilter] || []).includes(entry.type)) return;
		const el = _createLogElement(entry);
		logger.content.appendChild(el);
		if (!logger.window.classList.contains("collapsed") && !logger.userScrolledUp) logger.content.scrollTop = logger.content.scrollHeight;
	}
	function reRenderAllLogs(logger) {
		if (logger.container.style.display !== "none") {
			if (!logger.window.classList.contains("collapsed")) setTimeout(() => {
				logger.content.innerHTML = "";
				if (logger.logs.length === 0) return;
				const filterTypes = FILTER_TYPE_MAP[logger.currentFilter] || [];
				const fragment = document.createDocumentFragment();
				logger.logs.forEach((entry) => {
					if (filterTypes.includes(entry.type)) {
						const el = _createLogElement(entry);
						fragment.appendChild(el);
					}
				});
				logger.content.appendChild(fragment);
				logger.content.scrollTop = logger.content.scrollHeight;
			}, 0);
		}
	}
	function _createLogElement(entry) {
		const el = document.createElement("div");
		el.className = "console-logger-entry";
		el.dataset.type = entry.type;
		el.dataset.id = String(entry.id);
		const style = LOG_TYPE_STYLES[entry.type] || LOG_TYPE_STYLES.base;
		el.style.borderLeft = "3px solid " + style.borderLeftColor;
		el.style.background = style.background;
		const timeStr = (entry.timestamp instanceof Date ? entry.timestamp : new Date(entry.timestamp)).toTimeString().split(" ")[0];
		el.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(LoggerLogEntry, {
			timeStr,
			messageType: entry.messageType,
			message: entry.message
		}));
		return el;
	}
	function setFilter(logger, filterType) {
		if (logger.currentFilter === filterType) return;
		logger.currentFilter = filterType;
		localStorage.setItem(FILTER_KEY, filterType);
		logger.filterButtonGroup.querySelectorAll(".console-logger-filter").forEach((btn) => {
			if (btn.dataset.type === filterType) btn.classList.add("active");
			else btn.classList.remove("active");
		});
		reRenderAllLogs(logger);
	}
	function clear(logger) {
		logger.logs = [];
		logger.content.innerHTML = "";
	}
	var Logger = class {
		currentFilter;
		logs = [];
		isInitialized = false;
		userScrolledUp = false;
		container;
		toggleBtn;
		window;
		maximizeBtn;
		filtersContainer;
		filterButtonGroup;
		scrollToBottomBtn;
		content;
		maxLogCount = 2e3;
		maxLogCountInitialized = false;
		constructor() {
			const stored = localStorage.getItem(FILTER_KEY);
			this.currentFilter = stored && LOG_TYPE_STYLES[stored] ? stored : "base";
		}
		tryInitialize() {
			return document.readyState !== "loading" && (this.isInitialized || (this.init(), this.isInitialized = true, true));
		}
		init() {
			createContainer(this);
			bindEvents(this);
			checkInitialMaximizeState(this);
			checkInitialCollapseState(this);
		}
		addLog(message, typeArg = "base", ...extraArgs) {
			if (!this.maxLogCountInitialized) {
				this.maxLogCountInitialized = true;
				storageManager.getSetting("clogMsgCount", 2e3).then((v) => {
					this.maxLogCount = v;
				}).catch(() => {});
			}
			const initialized = this.tryInitialize();
			let resolvedType;
			let resolvedExtra;
			if (LOG_TYPE_STYLES[typeArg]) {
				resolvedType = typeArg;
				resolvedExtra = extraArgs;
			} else {
				resolvedType = "base";
				resolvedExtra = [typeArg, ...extraArgs];
			}
			resolvedType = LOG_TYPE_STYLES[resolvedType] ? resolvedType : "base";
			const allParts = [message, ...resolvedExtra];
			let messageType = "msg";
			const parts = [];
			allParts.forEach((part) => {
				if (Object.prototype.toString.call(part) === "[object Error]") parts.push(String(part));
				else if (typeof part === "object" && part !== null) try {
					parts.push("\n" + JSON.stringify(part, null, 2));
					messageType = "json";
				} catch {
					parts.push(String(part));
					messageType = "msg";
				}
				else parts.push(String(part));
			});
			const entry = {
				message: parts.join("  "),
				messageType,
				type: resolvedType,
				timestamp: new Date(),
				id: Date.now() + Math.random()
			};
			this.logs.push(entry);
			if (this.logs.length > this.maxLogCount) {
				const firstEntry = this.logs[0];
				if (initialized) {
					const oldEl = this.content.querySelector(`.console-logger-entry[data-id="${firstEntry.id}"]`);
					if (oldEl) {
						this.logs.shift();
						this.content.removeChild(oldEl);
					}
				}
			}
			if (initialized) renderLog(this, entry);
		}
		log(...args) {
			const [first, ...rest] = args;
			setTimeout(() => {
				this.addLog(first, "base", ...rest);
			}, 0);
		}
		error(...args) {
			const [first, ...rest] = args;
			console.error(...args);
			setTimeout(() => {
				this.addLog(first, "error", ...rest);
			}, 0);
		}
		warn(...args) {
			const [first, ...rest] = args;
			setTimeout(() => {
				this.addLog(first, "warn", ...rest);
			}, 0);
		}
		debug(...args) {
			const [first, ...rest] = args;
			setTimeout(() => {
				this.addLog(first, "debug", ...rest);
			}, 0);
		}
		reRenderAllLogs() {
			reRenderAllLogs(this);
		}
		setFilter(filterType) {
			setFilter(this, filterType);
		}
		clear() {
			clear(this);
		}
		show() {
			if (this.isInitialized && this.container || this.tryInitialize() && this.container) {
				this.container.style.display = "";
				this.reRenderAllLogs();
			}
		}
		hide() {
			if (this.isInitialized && this.container) this.container.style.display = "none";
		}
		lowZIndex() {
			if (this.isInitialized && this.container) this.container.style.zIndex = "12345678";
		}
		highZIndex() {
			if (this.isInitialized && this.container) this.container.style.zIndex = "999999999";
		}
	};
	var REVISION_CHANNEL = "jhs-storage-revision";
	var StorageRevision = class {
		revision = 0;
		channel = null;
		senderId = Math.random().toString(36).slice(2, 10);
		callbacks = [];
		get current() {
			return this.revision;
		}
		init() {
			if (this.channel) return;
			try {
				this.channel = new BroadcastChannel(REVISION_CHANNEL);
				this.channel.addEventListener("message", (event) => {
					const msg = event.data;
					if (msg && typeof msg.revision === "number" && msg.senderId !== this.senderId) {
						if (msg.revision > this.revision) this.revision = msg.revision;
						for (const cb of this.callbacks) try {
							cb(msg.revision);
						} catch (err) {
							console.error("[StorageRevision] 回调执行失败", err);
						}
					}
				});
			} catch {}
		}
		increment() {
			this.revision++;
			try {
				this.channel?.postMessage({
					revision: this.revision,
					senderId: this.senderId
				});
			} catch {}
			return this.revision;
		}
		onRemoteChange(callback) {
			this.callbacks.push(callback);
		}
		destroy() {
			this.channel?.close();
			this.channel = null;
			this.callbacks.length = 0;
		}
	};
	var storageRevision = new StorageRevision();
	var FILTER_ACTION = "filter";
	var FAVORITE_ACTION = "favorite";
	var HAS_WATCH_ACTION = "hasWatch";
	var HAS_DOWN_ACTION = "hasDown";
	var BLOCK_TEXT = "🚫 屏蔽";
	var BLOCKED_TEXT = "🚫 已屏蔽";
	var BLOCK_COLOR = "#de3333";
	var FAVORITE_TEXT = "⭐ 收藏";
	var FAVORITED_TEXT = "⭐ 已收藏";
	var FAVORITE_COLOR = "#25b1dc";
	var WATCHED_TEXT = "🔍 已观看";
	var WATCHED_COLOR = "#d7a80c";
	var HAS_DOWN_TEXT$1 = "📥️ 已下载";
	var HAS_DOWN_COLOR = "#7bc73b";
	var HAS_DOWN_STATUS$1 = "hasDown";
	function saveSingleCar(input, list) {
		const { carNum, actionType, publishTime, starId, score } = input;
		let { url, names } = input;
		if (!carNum) failWithToast("番号为空!");
		if (!url) failWithToast("url为空!");
		if (!url.includes("http")) url = window.location.origin + url;
		if (names) names = names.trim();
		let car = featureFlags.caseInsensitiveCarNum ? list.find((item) => item.carNum.toLowerCase() === carNum.toLowerCase()) : list.find((item) => item.carNum === carNum);
		if (car) {
			if (names) car.names = names;
			if (url) car.url = url;
			if (publishTime) car.publishTime = publishTime;
			if (score !== void 0) car.score = score;
			car.updateDate = utils.getNowStr();
		} else {
			const now = utils.getNowStr();
			car = {
				carNum,
				url,
				names,
				status: "",
				createDate: now,
				updateDate: now,
				publishTime
			};
			if (starId) car.starId = starId;
			if (score !== void 0) car.score = score;
			list.push(car);
		}
		switch (actionType) {
			case FILTER_ACTION:
				if (car.status === "filter") failWithToast(`${carNum} 已在屏蔽列表中`);
				car.status = FILTER_ACTION;
				break;
			case FAVORITE_ACTION:
				if (car.status === "favorite") failWithToast(`${carNum} 已在收藏列表中`);
				car.status = FAVORITE_ACTION;
				break;
			case HAS_DOWN_STATUS$1:
				car.status = HAS_DOWN_STATUS$1;
				break;
			case HAS_WATCH_ACTION:
				car.status = HAS_WATCH_ACTION;
				break;
			default: failWithToast("actionType错误, 请联系作者更正: " + actionType);
		}
	}
	async function getCarList(sm) {
		if (featureFlags.storageCacheDeepCopy) {
			if (!sm.cacheCarList) sm.cacheCarList = await sm.forage.getItem(sm.car_list_key) || [];
			return utils.copyObj(sm.cacheCarList ?? []);
		}
		return await sm.forage.getItem(sm.car_list_key) || [];
	}
	async function getCar(sm, carNum) {
		const list = await getCarList(sm);
		if (featureFlags.caseInsensitiveCarNum) {
			const lower = carNum.toLowerCase();
			return list.find((car) => car.carNum.toLowerCase() === lower);
		}
		return list.find((car) => car.carNum === carNum);
	}
	async function saveCar(sm, input) {
		const list = await sm.forage.getItem(sm.car_list_key) || [];
		saveSingleCar(input, list);
		await sm.forage.setItem(sm.car_list_key, list);
		storageRevision.increment();
		sm.cacheCarList = list;
		await sm.removeNewVideoList([input.carNum]);
		const car = featureFlags.caseInsensitiveCarNum ? list.find((c) => c.carNum.toLowerCase() === input.carNum.toLowerCase()) : list.find((c) => c.carNum === input.carNum);
		if (car) sm.carListChangeCallback?.({
			action: "upsert",
			upserts: [car]
		});
	}
	async function updateCarInfo(sm, input) {
		const { carNum, url, actionType, remark } = input;
		let { names } = input;
		if (!carNum) failWithToast("番号为空!");
		if (!url) failWithToast("url为空!");
		if (names) names = names.trim();
		const list = await sm.forage.getItem(sm.car_list_key) || [];
		const car = list.find((item) => item.carNum === carNum);
		if (!car) failWithToast("数据不存在: " + carNum);
		car.names = names;
		car.url = url;
		car.remark = remark;
		car.updateDate = utils.getNowStr();
		switch (actionType) {
			case FAVORITE_ACTION:
				car.status = FAVORITE_ACTION;
				break;
			case HAS_WATCH_ACTION:
				car.status = HAS_WATCH_ACTION;
				break;
			default: failWithToast("actionType错误, 请联系作者更正: " + actionType);
		}
		await sm.forage.setItem(sm.car_list_key, list);
		storageRevision.increment();
		sm.cacheCarList = list;
		sm.carListChangeCallback?.({
			action: "upsert",
			upserts: [car]
		});
	}
	async function saveCarList(sm, inputs) {
		if (!inputs || !Array.isArray(inputs) || inputs.length === 0) failWithToast("记录列表为空!");
		const list = await sm.forage.getItem(sm.car_list_key) || [];
		for (const item of inputs) saveSingleCar(item, list);
		await sm.forage.setItem(sm.car_list_key, list);
		storageRevision.increment();
		sm.cacheCarList = list;
		const numSet = featureFlags.caseInsensitiveCarNum ? new Set(inputs.map((i) => i.carNum.toLowerCase())) : new Set(inputs.map((i) => i.carNum));
		const upserts = featureFlags.caseInsensitiveCarNum ? list.filter((c) => numSet.has(c.carNum.toLowerCase())) : list.filter((c) => numSet.has(c.carNum));
		if (upserts.length > 0) sm.carListChangeCallback?.({
			action: "upsert",
			upserts
		});
	}
	async function removeCar(sm, carNum) {
		const list = await getCarList(sm);
		const beforeLen = list.length;
		const filtered = list.filter((item) => item.carNum !== carNum);
		if (filtered.length === beforeLen) {
			show.error(`${carNum} 不存在`);
			return false;
		} else {
			await sm.forage.setItem(sm.car_list_key, filtered);
			storageRevision.increment();
			sm.cacheCarList = filtered;
			sm.carListChangeCallback?.({
				action: "delete",
				deletes: [carNum]
			});
			return true;
		}
	}
	async function batchRemoveCars(sm, carNums) {
		const list = await getCarList(sm);
		const beforeLen = list.length;
		const numSet = new Set(carNums);
		const filtered = list.filter((item) => !numSet.has(item.carNum));
		const removed = beforeLen - filtered.length;
		if (removed === 0) return false;
		await sm.forage.setItem(sm.car_list_key, filtered);
		storageRevision.increment();
		sm.cacheCarList = filtered;
		sm.carListChangeCallback?.({
			action: "delete",
			deletes: carNums
		});
		return removed;
	}
	async function getBlacklist(sm) {
		return await sm.forage.getItem(sm.blacklist_key) || [];
	}
	async function addBlacklistItem(sm, item) {
		const { starId, name, allName, role, movieType, url } = item;
		if (!starId) throw new Error("缺失starId");
		if (!name) throw new Error("缺失name");
		if (!role) throw new Error("缺失role");
		const list = await getBlacklist(sm);
		const existing = list.find((entry) => entry.starId === starId);
		if (existing) {
			existing.url = url;
			existing.role = role;
			existing.movieType = movieType;
			clog.log("更新黑名单演员信息", existing);
		} else {
			const created = {
				starId,
				name,
				allName: allName || [name],
				createTime: utils.getNowStr(),
				role,
				movieType,
				url
			};
			list.push(created);
			clog.log("增加黑名单演员信息", created);
		}
		await sm.forage.setItem(sm.blacklist_key, list);
		storageRevision.increment();
	}
	async function updateBlacklistItem(sm, item) {
		if (!item || !item.starId) throw new Error("参数不全");
		const list = await getBlacklist(sm);
		const existing = list.find((entry) => entry.starId === item.starId);
		if (!existing) throw new Error(`未找到黑名单演员信息:${item.name} ${item.starId}`);
		if (item.checkTime) existing.checkTime = item.checkTime;
		if (item.lastPublishTime) existing.lastPublishTime = item.lastPublishTime;
		await sm.forage.setItem(sm.blacklist_key, list);
		storageRevision.increment();
	}
	async function deleteBlacklistItem(sm, starId) {
		const list = await getBlacklist(sm);
		const filtered = list.filter((entry) => entry.starId !== starId);
		if (list.length !== filtered.length) {
			await sm.forage.setItem(sm.blacklist_key, filtered);
			storageRevision.increment();
		}
	}
	function ColoredTextCell({ text, color }) {
		return (0, import_jsx_runtime.jsx)("span", {
			style: { color },
			children: text
		});
	}
	function logColoredHtml(text) {
		return jsxToString((0, import_jsx_runtime.jsx)(ColoredTextCell, {
			text,
			color: "#f40"
		}));
	}
	async function getBlacklistCarList(sm) {
		const cached = sm.cache_filter_actor_actress_car_list;
		if (cached && cached.length > 0) {
			if (featureFlags.storageCacheDeepCopy) return utils.deepFreeze(utils.copyObj(cached));
			return cached;
		}
		const fresh = await sm.forage.getItem(sm.blacklist_car_list_key) || [];
		sm.cache_filter_actor_actress_car_list = fresh;
		if (featureFlags.storageCacheDeepCopy) return utils.deepFreeze(utils.copyObj(fresh));
		return fresh;
	}
	async function batchSaveBlacklistCarList(sm, inputs) {
		const list = await getBlacklistCarList(sm);
		const cloned = JSON.parse(JSON.stringify(list));
		let changed = false;
		const newCarNums = [];
		for (const item of inputs) if (!cloned.find((entry) => entry.carNum === item.carNum)) {
			saveSingleCar(item, cloned);
			clog.log("屏蔽演员番号: " + logColoredHtml(`${item.names} ${item.carNum}`));
			changed = true;
			newCarNums.push(item.carNum);
		}
		if (changed) {
			await sm.forage.setItem(sm.blacklist_car_list_key, cloned);
			storageRevision.increment();
			await sm.removeNewVideoList(newCarNums);
			window.cleanCache_filter_actor_actress_car_list();
		}
	}
	async function removeBlacklistCarList(sm, starId) {
		const list = await getBlacklistCarList(sm);
		const filtered = list.filter((item) => item.starId !== starId);
		if (filtered.length !== list.length) {
			await sm.forage.setItem(sm.blacklist_car_list_key, filtered);
			storageRevision.increment();
			window.cleanCache_filter_actor_actress_car_list();
		}
	}
	var UNCENSORED_TAG = "(無碼)";
	async function getFavoriteActressList(sm) {
		if (featureFlags.storageCacheDeepCopy) {
			if (!sm.cacheFavoriteActressList) sm.cacheFavoriteActressList = await sm.forage.getItem(sm.favorite_actresses_key) || [];
			return utils.copyObj(sm.cacheFavoriteActressList ?? []);
		}
		return await sm.forage.getItem(sm.favorite_actresses_key) || [];
	}
	async function addFavoriteActressList(sm, inputs) {
		const list = await getFavoriteActressList(sm);
		let count = 0;
		for (const item of inputs) {
			const { starId, avatar, lastCheckTime, lastPublishTime } = item;
			let { name, allName, actressType } = item;
			if (!starId) throw new Error("缺失starId");
			if (!name) throw new Error("缺失name");
			if (!allName) allName = [name];
			if (!actressType) actressType = name.includes(UNCENSORED_TAG) || allName.some((n) => n.includes(UNCENSORED_TAG)) ? UNCENSORED : CENSORED;
			name = name.replace(UNCENSORED_TAG, "");
			allName = allName.map((n) => n.replace(UNCENSORED_TAG, ""));
			const existing = list.find((entry) => entry.starId === starId);
			if (existing) {
				if (!existing.avatar || !existing.avatar.includes("https")) {
					if (avatar) {
						clog.log(avatar);
						existing.avatar = avatar;
						clog.log(logColoredHtml(`补全女优头像: ${name}`));
						count++;
					}
				}
				if (!existing.actressType && actressType) {
					existing.actressType = actressType;
					clog.log(logColoredHtml(`补全女优类别: ${name} ${actressType}`));
					count++;
				}
				if (existing.name.includes(UNCENSORED_TAG)) {
					existing.name = name;
					existing.allName = allName;
					clog.log(logColoredHtml(`更正女优名字: ${name} ${allName}`));
					count++;
				}
				continue;
			}
			const now = utils.getNowStr();
			list.push({
				starId,
				name,
				allName,
				avatar,
				lastCheckTime,
				lastPublishTime,
				createDate: now,
				updateDate: now,
				actressType
			});
			clog.log(logColoredHtml(`同步JavDB已收藏的演员: ${name}`));
			count++;
		}
		if (count > 0) {
			await sm.forage.setItem(sm.favorite_actresses_key, list);
			storageRevision.increment();
		} else clog.log("信息已记录, 无需要进行同步收藏的演员");
		return count;
	}
	async function removeFavoriteActress(sm, starId) {
		const list = await getFavoriteActressList(sm);
		const beforeLen = list.length;
		const filtered = list.filter((entry) => entry.starId !== starId);
		if (filtered.length === beforeLen) {
			clog.error(`移除演员失败, ${starId} 不存在`);
			return false;
		} else {
			await sm.forage.setItem(sm.favorite_actresses_key, filtered);
			storageRevision.increment();
			sm.cacheFavoriteActressList = filtered;
			return true;
		}
	}
	async function updateFavoriteActress(sm, item) {
		const list = await getFavoriteActressList(sm);
		const { starId, name, allName, avatar, lastCheckTime, newVideoList, lastPublishTime, actressType, remark } = item;
		if (!starId) throw new Error("缺失starId");
		const existing = list.find((entry) => entry.starId === starId);
		if (!existing) {
			clog.error("未找到演员信息", starId, name);
			return false;
		}
		if (name) existing.name = name;
		if (allName) existing.allName = allName;
		if (avatar) existing.avatar = avatar;
		if (actressType != null) existing.actressType = actressType;
		if (lastCheckTime) existing.lastCheckTime = lastCheckTime;
		if (newVideoList) existing.newVideoList = newVideoList;
		if (lastPublishTime) existing.lastPublishTime = lastPublishTime;
		if (remark) existing.remark = remark;
		existing.updateDate = utils.getNowStr();
		await sm.forage.setItem(sm.favorite_actresses_key, list);
		storageRevision.increment();
	}
	async function removeNewVideoList(sm, carNums) {
		const actressList = await getFavoriteActressList(sm);
		let changed = false;
		const updated = actressList.map((actress) => {
			if (!actress.newVideoList || !Array.isArray(actress.newVideoList)) return actress;
			const filtered = actress.newVideoList.filter((carNum) => {
				const matched = carNums.includes(carNum);
				if (matched) {
					clog.log("移除关联女优新作品", actress.name, carNum);
					changed = true;
				}
				return !matched;
			});
			return {
				...actress,
				newVideoList: filtered
			};
		});
		if (changed) await sm.forage.setItem(sm.favorite_actresses_key, updated);
	}
	async function saveKeyword(sm, keyword, key, label) {
		let list;
		if (Array.isArray(keyword)) list = [...keyword];
		else {
			list = await sm.forage.getItem(key) || [];
			if (list.includes(keyword)) failWithToast(`${keyword} ${label}已存在`);
			list.push(keyword);
		}
		await sm.forage.setItem(key, list);
		return list;
	}
	async function saveTitleFilterKeyword(sm, keyword) {
		await saveKeyword(sm, keyword, sm.filter_keyword_title_key, "标题关键词");
		storageRevision.increment();
		if (Array.isArray(keyword)) return null;
		const actressList = await getFavoriteActressList(sm);
		let changed = false;
		const updated = actressList.map((actress) => {
			if (!actress.newVideoList || !Array.isArray(actress.newVideoList)) return actress;
			const filtered = actress.newVideoList.filter((carNum) => {
				const matched = carNum.startsWith(keyword);
				if (matched) {
					clog.log("移除关联女优新作品", actress.name, carNum);
					changed = true;
				}
				return !matched;
			});
			return {
				...actress,
				newVideoList: filtered
			};
		});
		if (changed) await sm.forage.setItem(sm.favorite_actresses_key, updated);
	}
	async function saveReviewFilterKeyword(sm, keyword) {
		return saveKeyword(sm, keyword, sm.filter_keyword_review_key, "评论关键词");
	}
	async function getTitleFilterKeyword(sm) {
		return await sm.forage.getItem(sm.filter_keyword_title_key) || [];
	}
	async function getReviewFilterKeywordList(sm) {
		return await sm.forage.getItem(sm.filter_keyword_review_key) || [];
	}
	var SCHEMA_VERSION_KEY = "__jhs_schema_version";
	async function runMigrations(sm) {
		const run = async () => {
			let version = await sm.forage.getItem("__jhs_schema_version") ?? 0;
			if (version >= 6) return;
			const steps = [
				{
					target: 1,
					fn: () => merge_table_name(sm)
				},
				{
					target: 2,
					fn: () => clean_no_url_blacklist(sm)
				},
				{
					target: 3,
					fn: () => async_merge_other(sm)
				},
				{
					target: 4,
					fn: () => merge_blacklist(sm)
				},
				{
					target: 5,
					fn: () => merge_favoriteActress(sm)
				},
				{
					target: 6,
					fn: () => merge_tow_car_list_table(sm)
				}
			];
			for (const step of steps) {
				if (version >= step.target) continue;
				try {
					await step.fn();
					await sm.forage.setItem(SCHEMA_VERSION_KEY, step.target);
					version = step.target;
				} catch (err) {
					clog.error(`数据迁移 ${version}→${step.target} 失败,下次启动重试`, err);
					break;
				}
			}
			sm.cacheCarList = null;
			sm.cacheFavoriteActressList = null;
			sm.cache_filter_actor_actress_car_list = null;
			sm.cacheSettingObj = null;
		};
		if (typeof navigator !== "undefined" && navigator.locks) await navigator.locks.request("jhs-storage-migration", { mode: "exclusive" }, run);
		else await run();
	}
	async function merge_table_name(sm) {
		let oldKey = "filter_actor_actress_info_list";
		let items = await sm.forage.getItem(oldKey) || [];
		if (items && items.length > 0) {
			clog.debug("更正", oldKey);
			await sm.forage.setItem(sm.blacklist_key, items);
		}
		await sm.forage.removeItem(oldKey);
		oldKey = "favorite_actresses_info_list";
		items = await sm.forage.getItem(oldKey) || [];
		if (items && items.length > 0) {
			clog.debug("更正", oldKey);
			await sm.forage.setItem(sm.favorite_actresses_key, items);
		}
		await sm.forage.removeItem(oldKey);
		oldKey = "car_list_filter_actor_actress";
		items = await sm.forage.getItem(oldKey) || [];
		if (items && items.length > 0) {
			clog.debug("更正", oldKey);
			await sm.forage.setItem(sm.blacklist_car_list_key, items);
		}
		await sm.forage.removeItem(oldKey);
		oldKey = "title_filter_keyword";
		items = await sm.forage.getItem(oldKey) || [];
		if (items && items.length > 0) {
			clog.debug("更正", oldKey);
			await sm.forage.setItem(sm.filter_keyword_title_key, items);
		}
		await sm.forage.removeItem(oldKey);
		oldKey = "review_filter_keyword";
		items = await sm.forage.getItem(oldKey) || [];
		if (items && items.length > 0) {
			clog.debug("更正", oldKey);
			await sm.forage.setItem(sm.filter_keyword_review_key, items);
		}
		await sm.forage.removeItem(oldKey);
		oldKey = "highlightedTags";
		items = await sm.forage.getItem(oldKey) || [];
		if (items && items.length > 0) {
			clog.debug("更正", oldKey);
			await sm.forage.setItem(sm.highlighted_tags_key, items);
		}
		await sm.forage.removeItem(oldKey);
	}
	async function clean_no_url_blacklist(sm) {
		const [blacklistCars, blacklist] = await Promise.all([sm.forage.getItem(sm.blacklist_car_list_key) || [], sm.forage.getItem(sm.blacklist_key) || []]);
		if (!blacklistCars.length && !blacklist.length) return;
		const nameSet = new Set(blacklist.map((item) => item.name));
		const filteredCars = blacklistCars.filter((item) => !item.actress || nameSet.has(item.actress));
		if (blacklistCars.length !== filteredCars.length) {
			clog.debug("清理 blacklistCarList 前", blacklistCars.length);
			clog.debug("清理 blacklistCarList 后", filteredCars.length);
			await sm.forage.setItem(sm.blacklist_car_list_key, filteredCars);
			sm.cache_filter_actor_actress_car_list = null;
		}
		const actressSet = new Set(filteredCars.map((item) => item.actress));
		let cleanedBlacklist = blacklist.filter((item) => actressSet.has(item.name));
		cleanedBlacklist = cleanedBlacklist.map((item) => {
			const cleaned = { ...item };
			delete cleaned.key;
			delete cleaned.recordTime;
			if (item.recordTime !== void 0) cleaned.createTime = item.recordTime;
			return cleaned;
		});
		if (blacklist.length !== cleanedBlacklist.length || blacklist.some((item) => "key" in item || "recordTime" in item)) {
			clog.debug("清理 Blacklist 前", blacklist.length);
			clog.debug("清理 Blacklist 后", cleanedBlacklist.length);
			await sm.forage.setItem(sm.blacklist_key, cleanedBlacklist);
		}
	}
	async function async_merge_other(sm) {
		const setting = await sm.getSetting();
		let changed = false;
		for (const key of [
			"enableCheckFilterActorActress",
			"checkIntervalTime_filterActorActress",
			"checkIntervalTime_ruleTime",
			"checkIntervalTime_newVideo",
			"checkIntervalTime_favoriteActress",
			"checkFilterTime",
			"checkFilterConcurrencyCount",
			"checkFilterSleep",
			"enableCheckBlacklist",
			"checkBlacklist_intervalTime",
			"checkBlacklist_ruleTime",
			"enableCheckFavoriteActress",
			"checkFavoriteActress_IntervalTime",
			"enableCheckNewVideo",
			"checkNewVideo_intervalTime",
			"checkNewVideo_ruleTime",
			"checkConcurrencyCount",
			"checkRequestSleep"
		]) if (Object.prototype.hasOwnProperty.call(setting, key)) {
			delete setting[key];
			changed = true;
		}
		if (setting.downPath115) {
			delete setting.downPath115;
			changed = true;
		}
		if (changed) {
			await sm.saveSetting(setting);
			clog.debug("配置数据已更正");
		}
	}
	async function merge_blacklist(sm) {
		const list = await sm.forage.getItem(sm.blacklist_key) || [];
		if (!list.length) return;
		let changed = false;
		const merged = list.map((item) => {
			let itemChanged = false;
			if (Object.prototype.hasOwnProperty.call(item, "isActor") && !item.role) {
				item.role = item.isActor ? ACTOR : ACTRESS;
				delete item.isActor;
				itemChanged = true;
			}
			if (!item.starId && item.url) try {
				const extracted = new URL(item.url).pathname.split("/").filter((seg) => seg.trim() !== "").pop();
				if (item.starId !== extracted) {
					item.starId = extracted;
					itemChanged = true;
				}
			} catch (err) {
				clog.error("提取url-starId发生错误", item.url, err);
			}
			if (!item.allName) {
				item.allName = item.name ? [item.name] : [];
				itemChanged = true;
			}
			if (!item.movieType) {
				item.movieType = CENSORED;
				itemChanged = true;
			}
			if (item.url && item.url.includes("sort_type")) try {
				const urlObj = new URL(item.url);
				urlObj.searchParams.delete("sort_type");
				item.url = urlObj.toString();
				itemChanged = true;
				clog.debug("去除黑名单地址sort_type参数");
			} catch (err) {
				clog.error("去除黑名单地址sort_type参数失败", item.url, err);
			}
			if (itemChanged) changed = true;
			return item;
		});
		if (changed) {
			clog.debug("更正 Blacklist 数据结构");
			await sm.forage.setItem(sm.blacklist_key, merged);
		}
		const carList = await sm.forage.getItem(sm.blacklist_car_list_key) || [];
		changed = false;
		const mergedCars = carList.map((item) => {
			if (!item.starId) {
				const match = list.find((entry) => entry.name === item.actress);
				if (match) item.starId = match.starId;
				changed = true;
			}
			if (item.type) {
				delete item.type;
				changed = true;
			}
			return item;
		});
		if (changed) {
			clog.debug("更正 blacklistCarList 数据结构");
			await sm.forage.setItem(sm.blacklist_car_list_key, mergedCars);
			sm.cache_filter_actor_actress_car_list = null;
		}
	}
	async function merge_favoriteActress(sm) {
		const list = await sm.forage.getItem(sm.favorite_actresses_key) || [];
		if (!list.length) return;
		let changed = false;
		const merged = list.map((item) => {
			if (item.dbId) {
				item.starId = item.dbId;
				delete item.dbId;
				changed = true;
			}
			return item;
		});
		if (changed) {
			clog.debug("更正 favoriteActressesInfoList 数据结构");
			await sm.forage.setItem(sm.favorite_actresses_key, merged);
			sm.cacheFavoriteActressList = null;
		}
	}
	async function merge_tow_car_list_table(sm) {
		const blacklistCars = await sm.forage.getItem(sm.blacklist_car_list_key) || [];
		const carList = await sm.forage.getItem(sm.car_list_key) || [];
		let changed = false;
		const mergedBlacklistCars = blacklistCars.map((item) => {
			if (item.actress !== void 0) {
				item.names = item.actress;
				delete item.actress;
				changed = true;
			}
			return item;
		});
		if (changed) {
			clog.debug("更正 blacklistCarList 数据结构 actress->names");
			await sm.forage.setItem(sm.blacklist_car_list_key, mergedBlacklistCars);
			sm.cache_filter_actor_actress_car_list = null;
		}
		changed = false;
		const mergedCars = carList.map((item) => {
			if (item.actress !== void 0) {
				item.names = item.actress;
				delete item.actress;
				changed = true;
			}
			return item;
		});
		if (changed) {
			clog.debug("更正 carList 数据结构 actress->names");
			await sm.forage.setItem(sm.car_list_key, mergedCars);
			sm.cacheCarList = null;
		}
	}
	var StorageManager = class StorageManager {
		static instance = null;
		car_list_key = "car_list";
		filter_keyword_title_key = "filter_keyword_title";
		filter_keyword_review_key = "filter_keyword_review";
		setting_key = "setting";
		blacklist_key = "blacklist";
		blacklist_car_list_key = "blacklist_car_list";
		favorite_actresses_key = "favorite_actresses";
		highlighted_tags_key = "highlighted_tags";
		forage;
		cacheCarList = null;
		cacheFavoriteActressList = null;
		cache_filter_actor_actress_car_list = null;
		cacheSettingObj = null;
		carListChangeCallback;
		constructor(forageInstance) {
			if (StorageManager.instance) throw new Error("StorageManager已被实例化过了!");
			StorageManager.instance = this;
			this.forage = forageInstance ?? localforage.createInstance({
				driver: localforage.INDEXEDDB,
				name: "JAV-JHS",
				version: 1,
				storeName: "appData"
			});
		}
		static __resetForTesting() {
			StorageManager.instance = null;
		}
		setCarListChangeCallback(cb) {
			this.carListChangeCallback = cb;
		}
		clearFilterActorActressCarListCache() {
			this.cache_filter_actor_actress_car_list = null;
		}
		clearSettingCache() {
			this.cacheSettingObj = null;
		}
		clearCarListCache() {
			this.cacheCarList = null;
		}
		clearFavoriteActressListCache() {
			this.cacheFavoriteActressList = null;
		}
		async getCarList() {
			return getCarList(this);
		}
		async getCar(carNum) {
			return getCar(this, carNum);
		}
		_saveSingleCar(input, list) {
			saveSingleCar(input, list);
		}
		async saveCar(input) {
			return saveCar(this, input);
		}
		async updateCarInfo(input) {
			return updateCarInfo(this, input);
		}
		async saveCarList(inputs) {
			return saveCarList(this, inputs);
		}
		async removeCar(carNum) {
			return removeCar(this, carNum);
		}
		async batchRemoveCars(carNums) {
			return batchRemoveCars(this, carNums);
		}
		async getBlacklist() {
			return getBlacklist(this);
		}
		async addBlacklistItem(item) {
			return addBlacklistItem(this, item);
		}
		async updateBlacklistItem(item) {
			return updateBlacklistItem(this, item);
		}
		async deleteBlacklistItem(starId) {
			return deleteBlacklistItem(this, starId);
		}
		async getBlacklistCarList() {
			return getBlacklistCarList(this);
		}
		async batchSaveBlacklistCarList(inputs) {
			return batchSaveBlacklistCarList(this, inputs);
		}
		async removeBlacklistCarList(starId) {
			return removeBlacklistCarList(this, starId);
		}
		async getFavoriteActressList() {
			return getFavoriteActressList(this);
		}
		async addFavoriteActressList(inputs) {
			return addFavoriteActressList(this, inputs);
		}
		async removeFavoriteActress(starId) {
			return removeFavoriteActress(this, starId);
		}
		async updateFavoriteActress(item) {
			return updateFavoriteActress(this, item);
		}
		async removeNewVideoList(carNums) {
			return removeNewVideoList(this, carNums);
		}
		async getHighlightedTags() {
			return await this.forage.getItem(this.highlighted_tags_key) || [];
		}
		async setHighlightedTags(tags) {
			return await this.forage.setItem(this.highlighted_tags_key, tags);
		}
		async saveTitleFilterKeyword(keyword) {
			return saveTitleFilterKeyword(this, keyword);
		}
		async saveReviewFilterKeyword(keyword) {
			return saveReviewFilterKeyword(this, keyword);
		}
		async getTitleFilterKeyword() {
			return getTitleFilterKeyword(this);
		}
		async getReviewFilterKeywordList() {
			return getReviewFilterKeywordList(this);
		}
		async getSetting(key = null, defaultValue) {
			if (!this.cacheSettingObj) this.cacheSettingObj = await this.forage.getItem(this.setting_key) || {};
			const setting = featureFlags.storageCacheDeepCopy ? utils.copyObj(this.cacheSettingObj) : this.cacheSettingObj;
			if (key === null) return setting;
			const val = setting[key];
			if (val) if (val === "true" || val === "false") return val.toLowerCase() === "true";
			else if (typeof val != "string" || val.trim() === "" || isNaN(Number(val))) return val;
			else return Number(val);
			else return defaultValue;
		}
		async saveSetting(setting) {
			if (setting) {
				await this.forage.setItem(this.setting_key, setting);
				storageRevision.increment();
				window.clean_cacheSettingObj();
			} else show.error("设置对象为空");
		}
		async saveSettingItem(key, value) {
			if (!key) {
				show.error("key 不能为空");
				return;
			}
			const setting = await this.getSetting();
			setting[key] = value;
			await this.saveSetting(setting);
			window.clean_cacheSettingObj();
		}
		async importData(data) {
			if (typeof data !== "object" || data === null || Array.isArray(data)) throw new Error("备份数据格式非法:必须是键值对对象");
			const tempInstance = localforage.createInstance({
				driver: localforage.INDEXEDDB,
				name: "JAV-JHS",
				storeName: "appData_import_staging"
			});
			try {
				const tasks = [];
				for (const key in data) tasks.push(tempInstance.setItem(key, data[key]));
				await Promise.all(tasks);
				await tempInstance.iterate((value, key) => {
					return this.forage.setItem(key, value);
				});
				storageRevision.increment();
				await tempInstance.clear();
				await tempInstance.dropInstance();
			} catch (err) {
				try {
					await tempInstance.clear();
					await tempInstance.dropInstance();
				} catch {}
				throw err;
			}
			this.cacheCarList = null;
			this.cacheFavoriteActressList = null;
			this.cache_filter_actor_actress_car_list = null;
			this.cacheSettingObj = null;
			await this.runMigrations();
		}
		async exportData() {
			const data = {};
			await this.forage.iterate((value, key) => {
				data[key] = value;
			});
			if (Object.keys(data).length === 0) throw new Error("没有可导出的数据");
			return data;
		}
		async runMigrations() {
			return runMigrations(this);
		}
		async clean_no_url_blacklist() {
			return clean_no_url_blacklist(this);
		}
		async async_merge_other() {
			return async_merge_other(this);
		}
	};
	var MIME_TYPES = {
		txt: "text/plain",
		html: "text/html",
		css: "text/css",
		csv: "text/csv",
		json: "application/json",
		xml: "application/xml",
		jpg: "image/jpeg",
		jpeg: "image/jpeg",
		png: "image/png",
		gif: "image/gif",
		webp: "image/webp",
		svg: "image/svg+xml",
		pdf: "application/pdf",
		doc: "application/msword",
		docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
		xls: "application/vnd.ms-excel",
		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
		ppt: "application/vnd.ms-powerpoint",
		pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
		zip: "application/zip",
		rar: "application/x-rar-compressed",
		"7z": "application/x-7z-compressed",
		mp3: "audio/mpeg",
		wav: "audio/wav",
		mp4: "video/mp4",
		webm: "video/webm",
		ogg: "audio/ogg"
	};
	function download(data, filename) {
		show.info("开始请求下载...");
		const mimeType = MIME_TYPES[filename.split(".").pop().toLowerCase()] || "application/octet-stream";
		let blob;
		if (data instanceof Blob) blob = data;
		else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) blob = new Blob([data], { type: mimeType });
		else if (typeof data === "string" && data.startsWith("data:")) {
			const raw = atob(data.split(",")[1]);
			const buf = new ArrayBuffer(raw.length);
			const bytes = new Uint8Array(buf);
			for (let i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i);
			blob = new Blob([bytes], { type: mimeType });
		} else blob = new Blob([data], { type: mimeType });
		const url = URL.createObjectURL(blob);
		const anchor = document.createElement("a");
		anchor.href = url;
		anchor.download = filename;
		document.body.appendChild(anchor);
		anchor.click();
		setTimeout(() => {
			document.body.removeChild(anchor);
			URL.revokeObjectURL(url);
		}, 100);
	}
	function StyleBlock({ id, css }) {
		return (0, import_jsx_runtime.jsx)("style", {
			id,
			dangerouslySetInnerHTML: { __html: css }
		});
	}
	function styleBlockHtml(css, id) {
		return jsxToString((0, import_jsx_runtime.jsx)(StyleBlock, {
			id,
			css
		}));
	}
	function insertStyle(css) {
		if (css) {
			if (css.indexOf("<style>") === -1) css = styleBlockHtml(css);
			$("head").append(css);
		}
	}
	function importResource(url) {
		let el;
		if (url.indexOf("css") >= 0) {
			const link = document.createElement("link");
			link.setAttribute("rel", "stylesheet");
			link.href = url;
			el = link;
		} else {
			const script = document.createElement("script");
			script.setAttribute("type", "text/javascript");
			script.src = url;
			el = script;
		}
		document.documentElement.appendChild(el);
	}
	function smoothScrollToTop(duration = 500) {
		return new Promise((resolve) => {
			const startTime = performance.now();
			const startY = window.pageYOffset;
			window.requestAnimationFrame(function step(now) {
				const elapsed = now - startTime;
				const progress = Math.min(elapsed / duration, 1);
				const eased = progress < .5 ? progress * 4 * progress * progress : 1 - Math.pow(progress * -2 + 2, 3) / 2;
				window.scrollTo(0, startY * (1 - eased));
				if (progress < 1) window.requestAnimationFrame(step);
				else resolve();
			});
		});
	}
	function loopDetector(container, checkFn, onSuccess, intervalMs = 20, timeoutMs = 1e4, callOnTimeout = true) {
		const token = String(Math.random());
		const startTime = new Date().getTime();
		const finish = (triggered) => {
			clearInterval(container[token]);
			if (triggered && onSuccess) onSuccess();
			delete container[token];
		};
		container[token] = setInterval(() => {
			const elapsed = new Date().getTime() - startTime;
			if (checkFn()) finish(true);
			else if (elapsed >= timeoutMs) finish(callOnTimeout);
		}, intervalMs);
	}
	function rightClick(container, targetSelector, handler) {
		let el = null;
		if (typeof container === "string") el = document.querySelector(container);
		else if (container instanceof HTMLElement) el = container;
		if (!el) {
			clog.warn("rightClick(), 容器无效或未提供,将使用 document.body 进行全局委托。");
			el = document.body;
		}
		if (typeof targetSelector === "string" && targetSelector.trim() !== "") el.addEventListener("contextmenu", (event) => {
			const target = event.target.closest(targetSelector);
			if (target) handler(event, target);
		});
		else clog.error("rightClick(), 必须提供有效的 targetSelector。");
	}
	function htmlTo$dom(html) {
		const parser = new DOMParser();
		return $(parser.parseFromString(html, "text/html"));
	}
	function isHidden(el) {
		const node = el.jquery ? el[0] : el;
		return !node || node.offsetWidth <= 0 && node.offsetHeight <= 0 || window.getComputedStyle(node).display === "none";
	}
	function getNowStr(dateSep = "-", timeSep = ":", timestamp = null) {
		const date = timestamp ? new Date(timestamp) : new Date();
		const year = date.getFullYear();
		const month = String(date.getMonth() + 1).padStart(2, "0");
		const day = String(date.getDate()).padStart(2, "0");
		const hours = String(date.getHours()).padStart(2, "0");
		const minutes = String(date.getMinutes()).padStart(2, "0");
		const seconds = String(date.getSeconds()).padStart(2, "0");
		return `${[
			year,
			month,
			day
		].join(dateSep)} ${[
			hours,
			minutes,
			seconds
		].join(timeSep)}`;
	}
	function formatDate(input, dateSep = "-", timeSep = ":") {
		let date;
		if (input instanceof Date) date = input;
		else {
			if (typeof input !== "string") throw new Error("Invalid date input: must be Date object or date string");
			date = new Date(input);
			if (isNaN(date.getTime())) throw new Error("Invalid date string");
		}
		const year = date.getFullYear();
		const month = String(date.getMonth() + 1).padStart(2, "0");
		const day = String(date.getDate()).padStart(2, "0");
		const hours = String(date.getHours()).padStart(2, "0");
		const minutes = String(date.getMinutes()).padStart(2, "0");
		const seconds = String(date.getSeconds()).padStart(2, "0");
		return `${[
			year,
			month,
			day
		].join(dateSep)} ${[
			hours,
			minutes,
			seconds
		].join(timeSep)}`;
	}
	function getHourDifference(start, end) {
		const startMs = start.getTime();
		const endMs = end.getTime();
		const hours = Math.abs(endMs - startMs) / 36e5;
		return Math.floor(hours);
	}
	function isUnnecessaryCheck(timeStr, checkIntervalTime) {
		if (!checkIntervalTime) throw new Error("未传入checkIntervalTime");
		const hours = parseInt(String(checkIntervalTime), 10);
		if (isNaN(hours)) return false;
		return getHourDifference(new Date(timeStr), new Date()) < hours;
	}
	function q(event, content, onConfirm, onCancel) {
		let left;
		let top;
		if (event) {
			left = event.clientX - 130;
			top = event.clientY - 120;
		} else {
			left = window.innerWidth / 2 - 120;
			top = window.innerHeight / 2 - 120;
		}
		const layerIdx = layer.confirm(content, {
			offset: [String(top), String(left)],
			title: "提示",
			btn: ["确定", "取消"],
			shade: 0,
			zIndex: 999999991
		}, function() {
			if (onConfirm) onConfirm();
			layer.close(layerIdx);
		}, function() {
			if (onCancel) onCancel();
		});
	}
	function getDefaultArea() {
		return ["85%", "90%"];
	}
	function getResponsiveArea(area) {
		const width = window.innerWidth;
		if (width >= 1200) return area || getDefaultArea();
		else if (width >= 768) return ["70%", "90%"];
		else return ["95%", "95%"];
	}
	function closePage() {
		storageManager.getSetting("needClosePage", "yes").then((setting) => {
			if (setting !== "yes") return;
			parent.document.documentElement.style.overflow = "auto";
			[
				".layui-layer-shade",
				".layui-layer-move",
				".layui-layer"
			].forEach((selector) => {
				const matches = parent.document.querySelectorAll(selector);
				if (matches.length > 0) {
					const el = matches.length > 1 ? matches[matches.length - 1] : matches[0];
					el.parentNode?.removeChild(el);
				}
			});
			window.close();
		}).catch((err) => clog.error("needClosePage 设置读取失败", err));
	}
	async function retry(fn, maxRetries = 3) {
		let attempt = 0;
		while (attempt < maxRetries) try {
			const result = await fn();
			if (attempt > 0) clog.debug(`[重试] 请求成功,共发起 ${attempt + 1} 次。`);
			return result;
		} catch (err) {
			const msg = String(err);
			if (msg.includes("Just a moment") || msg.includes("重定向") || msg.toLowerCase().includes("404 not found")) throw err;
			attempt++;
			if (attempt === maxRetries) {
				clog.debug(`[重试] 达到最大重试次数 (${maxRetries}),最终失败:`, err);
				throw err;
			}
			clog.debug(`[重试] 请求失败,准备第 ${attempt + 1} 次重试, 错误信息: ${msg}`);
		}
	}
	function copyToClipboard$1(label, text) {
		navigator.clipboard.writeText(text).then(() => show.info(`${label}已复制到剪切板, ${text}`)).catch((err) => clog.error("复制失败: ", err));
	}
	function addCookie(cookieStr, options = {}) {
		const { maxAge = 604800, path = "/", domain = "", secure = false, sameSite = "Lax" } = options;
		cookieStr.split(";").forEach((pair) => {
			const trimmed = pair.trim();
			if (trimmed) {
				const parts = trimmed.split("=");
				if (parts.length >= 2 && parts[0].trim()) {
					const segments = [`${parts[0].trim()}=${parts.slice(1).join("=")}`];
					if (maxAge > 0) segments.push(`max-age=${maxAge}`);
					segments.push(`path=${path}`);
					if (domain) segments.push(`domain=${domain}`);
					if (secure) segments.push("Secure");
					if (sameSite) segments.push(`SameSite=${sameSite}`);
					document.cookie = segments.join("; ");
				}
			}
		});
	}
	function genericSort(data, sortConfigs, nullsFirst = true) {
		if (!Array.isArray(data) || data.length === 0) return [];
		if (!Array.isArray(sortConfigs) || sortConfigs.length === 0) return [...data];
		const items = [...data];
		const coerceDate = (value) => {
			if (value instanceof Date) return value;
			if (typeof value === "string") {
				const parsed = new Date(value);
				if (!isNaN(parsed.getTime())) return parsed;
			}
			return value;
		};
		return items.sort((itemA, itemB) => {
			for (const config of sortConfigs) {
				const { key, order = "asc" } = config;
				let valA = itemA;
				let valB = itemB;
				if (key != null) if (typeof key === "function") {
					valA = key(itemA);
					valB = key(itemB);
				} else {
					valA = itemA && typeof itemA === "object" ? itemA[key] : void 0;
					valB = itemB && typeof itemB === "object" ? itemB[key] : void 0;
				}
				const coercedA = coerceDate(valA);
				const coercedB = coerceDate(valB);
				let cmp;
				const aIsNull = valA == null;
				const bIsNull = valB == null;
				if (aIsNull && bIsNull) return 0;
				if (aIsNull) if (nullsFirst) return 1;
				else return -1;
				if (bIsNull) if (nullsFirst) return 1;
				else return -1;
				cmp = coercedA instanceof Date && coercedB instanceof Date ? coercedA.getTime() - coercedB.getTime() : typeof valA === "number" && typeof valB === "number" ? valA - valB : typeof valA === "string" && typeof valB === "string" ? valA.localeCompare(valB) : String(valA).localeCompare(String(valB));
				if (order === "desc") cmp *= -1;
				if (cmp !== 0) return cmp;
			}
			return 0;
		});
	}
	function isUrl(str) {
		try {
			new URL(str);
			return true;
		} catch {
			return false;
		}
	}
	function setHrefParam(key, value) {
		const url = new URL(window.location.href);
		url.searchParams.set(key, value);
		window.history.pushState({}, "", url.toString());
	}
	function getUrlParam(url, param) {
		const query = url.split("?")[1];
		if (!query) return null;
		const regex = new RegExp(`(?:^|&)${param}=([^&]*)`);
		const match = query.match(regex);
		let value = "";
		if (match && match[1]) value = decodeURIComponent(match[1].replace(/\+/g, " "));
		if (value) if (value === "true" || value === "false") return value.toLowerCase() === "true";
		else if (typeof value !== "string" || value.trim() === "" || isNaN(Number(value))) return value;
		else return Number(value);
		else return value;
	}
	function isMobile() {
		const ua = navigator.userAgent.toLowerCase();
		return [
			"iphone",
			"ipod",
			"ipad",
			"android",
			"blackberry",
			"windows phone",
			"nokia",
			"webos",
			"opera mini",
			"mobile",
			"mobi",
			"tablet"
		].some((keyword) => ua.includes(keyword));
	}
	function simpleId() {
		return crypto.randomUUID().replace("-", "");
	}
	function sleep(ms = 1e3) {
		return new Promise((resolve) => setTimeout(resolve, ms));
	}
	function copyObj(data) {
		return JSON.parse(JSON.stringify(data));
	}
	function deepFreeze(obj) {
		if (obj === null || typeof obj !== "object" || Object.isFrozen(obj)) return obj;
		const propNames = Object.getOwnPropertyNames(obj);
		for (const name of propNames) {
			const value = obj[name];
			if (value && typeof value === "object") deepFreeze(value);
		}
		return Object.freeze(obj);
	}
	function reBuildSignature$1() {
		const tsKey = "jhs_review_ts";
		const signKey = "jhs_review_sign";
		const nowSec = Math.floor(Date.now() / 1e3);
		if (nowSec - (Number(localStorage.getItem(tsKey)) || 0) <= 20) return localStorage.getItem(signKey);
		const sign = `${nowSec}.lpw6vgqzsp.${md5(`${nowSec}71cf27bb3c0bcdf207b64abecddc970098c7421ee7203b9cdae54478478a199e7d5a6e1a57691123c1a931c057842fb73ba3b3c83bcd69c17ccf174081e3d8aa`)}`;
		localStorage.setItem(tsKey, String(nowSec));
		localStorage.setItem(signKey, sign);
		return sign;
	}
	function time(timers, label = "default", unit = "s", precision = 2) {
		if (timers.has(label)) {
			const entry = timers.get(label);
			const elapsed = performance.now() - entry.startTime;
			let formatted;
			let unitLabel;
			if (entry.unit === "s") {
				formatted = (elapsed / 1e3).toFixed(entry.precision);
				unitLabel = "秒";
			} else {
				formatted = elapsed.toFixed(entry.precision);
				unitLabel = "毫秒";
			}
			timers.delete(label);
			return `${label}: ${formatted}${unitLabel}`;
		}
		timers.set(label, {
			startTime: performance.now(),
			unit,
			precision
		});
	}
	var escLayerGate = (() => {
		let w;
		try {
			w = window.top;
			w && w.location;
		} catch {
			w = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
		}
		if (!w.__jhsEscGate) w.__jhsEscGate = {
			locked: false,
			tryEnter() {
				if (this.locked) return false;
				this.locked = true;
				return true;
			},
			release() {
				this.locked = false;
			}
		};
		return w.__jhsEscGate;
	})();
	function getTopLayerEl() {
		const nodes = document.querySelectorAll(".layui-layer[times]");
		let topEl = null;
		let topZ = -Infinity;
		for (let i = 0; i < nodes.length; i++) {
			const el = nodes[i];
			const type = el.getAttribute("type") || "";
			if (type === "loading" || type === "tips") continue;
			if (el.getAttribute("data-jhs-esc-closing") === "1") continue;
			const cs = window.getComputedStyle(el);
			if (cs.display === "none" || cs.visibility === "hidden") continue;
			const z = parseInt(cs.zIndex, 10);
			const zVal = Number.isFinite(z) ? z : i;
			const times = Number(el.getAttribute("times"));
			if (!Number.isFinite(times)) continue;
			if (zVal >= topZ) {
				topZ = zVal;
				topEl = el;
			}
		}
		return topEl;
	}
	function syncLayerIndexStack(layerIndexStack) {
		return layerIndexStack.filter((idx) => document.getElementById(`layui-layer${idx}`) != null);
	}
	function _handleGlobalEscKey(event) {
		if (event.key !== "Escape" && event.keyCode !== 27) return;
		if ((event.originalEvent ?? event).repeat) {
			event.preventDefault();
			event.stopImmediatePropagation();
			return;
		}
		if (!escLayerGate.tryEnter()) {
			event.preventDefault();
			event.stopImmediatePropagation();
			return;
		}
		const topEl = getTopLayerEl();
		if (!topEl) {
			escLayerGate.release();
			return;
		}
		const layerIdx = Number(topEl.getAttribute("times"));
		if (!Number.isFinite(layerIdx)) {
			escLayerGate.release();
			return;
		}
		let hasViewer = $(topEl).find(".viewer-container").length > 0;
		let hasInnerLayer = false;
		if (!hasViewer) {
			const iframeEl = topEl.querySelector(`#layui-layer-iframe${layerIdx}`);
			if (iframeEl?.contentDocument) try {
				if (iframeEl.contentDocument.querySelector(".viewer-container")) hasViewer = true;
				if (!hasViewer) {
					const iframeLayers = iframeEl.contentDocument.querySelectorAll(".layui-layer[times]");
					for (const il of Array.from(iframeLayers)) {
						const ilType = il.getAttribute("type") || "";
						if (ilType === "loading" || ilType === "tips") continue;
						if (il.getAttribute("data-jhs-esc-closing") === "1") continue;
						const ilCs = window.getComputedStyle(il);
						if (ilCs.display === "none" || ilCs.visibility === "hidden") continue;
						hasInnerLayer = true;
						break;
					}
				}
			} catch {
				clog.warn("无法检查跨域 iframe 内的 .viewer-container");
			}
		}
		if (hasViewer) {
			escLayerGate.release();
			return;
		}
		if (hasInnerLayer) {
			const iframeEl = topEl.querySelector(`#layui-layer-iframe${layerIdx}`);
			if (iframeEl?.contentDocument) try {
				escLayerGate.release();
				const innerEvt = new KeyboardEvent("keydown", {
					key: "Escape",
					keyCode: 27,
					which: 27,
					bubbles: true,
					cancelable: true,
					composed: true
				});
				iframeEl.contentDocument.dispatchEvent(innerEvt);
				window.setTimeout(() => escLayerGate.release(), 100);
				return;
			} catch {
				escLayerGate.release();
				return;
			}
			escLayerGate.release();
			return;
		}
		event.preventDefault();
		event.stopImmediatePropagation();
		topEl.setAttribute("data-jhs-esc-closing", "1");
		topEl.style.display = "none";
		const shade = document.getElementById(`layui-layer-shade${layerIdx}`);
		if (shade) {
			shade.setAttribute("data-jhs-esc-closing", "1");
			shade.style.display = "none";
		}
		layer.close(layerIdx);
		window.setTimeout(() => escLayerGate.release(), 800);
	}
	function _handleGlobalEscKeyUp(event) {
		if (event.key === "Escape" || event.keyCode === 27) escLayerGate.release();
	}
	function setupEscClose(util, layerIdx) {
		if (!util._boundHandler) {
			util._boundHandler = util._handleGlobalEscKey.bind(util);
			util._boundEscKeyupHandler = util._handleGlobalEscKeyUp.bind(util);
			$(document).off("keydown.globalLayerEsc keyup.globalLayerEsc");
			document.removeEventListener("keydown", util._boundHandler, true);
			document.removeEventListener("keyup", util._boundEscKeyupHandler, true);
			document.addEventListener("keydown", util._boundHandler, true);
			document.addEventListener("keyup", util._boundEscKeyupHandler, true);
		}
		const numIdx = Number(layerIdx);
		if (Number.isFinite(numIdx) && util.layerIndexStack.indexOf(numIdx) === -1) util.layerIndexStack.push(numIdx);
		const iframeEl = document.getElementById(`layui-layer-iframe${layerIdx}`);
		if (iframeEl && iframeEl.getAttribute("data-esc-bound") !== "yes") {
			const bindIframe = () => {
				try {
					const doc = iframeEl.contentDocument;
					if (!doc || !util._boundHandler || !util._boundEscKeyupHandler) return;
					doc.removeEventListener("keydown", util._boundHandler, true);
					doc.removeEventListener("keyup", util._boundEscKeyupHandler, true);
					doc.addEventListener("keydown", util._boundHandler, true);
					doc.addEventListener("keyup", util._boundEscKeyupHandler, true);
					iframeEl.setAttribute("data-esc-bound", "yes");
				} catch (err) {
					clog.error("iframe监听失败 (跨域或未加载完毕):", err);
				}
			};
			if (iframeEl.contentDocument?.readyState === "complete") bindIframe();
			else iframeEl.addEventListener("load", bindIframe, { once: true });
		}
	}
	var CommonUtil = class CommonUtil {
		static instance;
		intervalContainer = {};
		mimeTypes = MIME_TYPES;
		timers = new Map();
		layerIndexStack = [];
		_boundHandler = null;
		_boundEscKeyupHandler = null;
		constructor() {
			CommonUtil.instance ||= this;
			return CommonUtil.instance;
		}
		insertStyle = (css) => insertStyle(css);
		importResource(url) {
			importResource(url);
		}
		smoothScrollToTop(duration = 500) {
			return smoothScrollToTop(duration);
		}
		loopDetector(checkFn, onSuccess, intervalMs = 20, timeoutMs = 1e4, callOnTimeout = true) {
			loopDetector(this.intervalContainer, checkFn, onSuccess, intervalMs, timeoutMs, callOnTimeout);
		}
		rightClick(container, targetSelector, handler) {
			rightClick(container, targetSelector, handler);
		}
		htmlTo$dom(html) {
			return htmlTo$dom(html);
		}
		isHidden(el) {
			return isHidden(el);
		}
		q(event, content, onConfirm, onCancel) {
			q(event, content, onConfirm, onCancel);
		}
		getDefaultArea() {
			return getDefaultArea();
		}
		getResponsiveArea(area) {
			return getResponsiveArea(area);
		}
		closePage() {
			closePage();
		}
		openPage(url, title, shadeClose, event) {
			shadeClose = shadeClose ?? true;
			if (event && (event.ctrlKey || event.metaKey)) {
				GM_openInTab(url.includes("http") ? url : window.location.origin + url, { insert: false });
				return;
			}
			let content = url;
			if (!url.includes("/actors/") && !url.includes("/star/")) content = url.includes("?") ? `${url}&hideNav=1` : `${url}?hideNav=1`;
			layer.open({
				type: 2,
				title,
				content,
				scrollbar: false,
				shadeClose,
				area: getResponsiveArea(["85%", "90%"]),
				isOutAnim: false,
				anim: -1,
				success: (_layerEl, layerIdx) => {
					this.setupEscClose(layerIdx);
				}
			});
		}
		getTopLayerEl() {
			return getTopLayerEl();
		}
		syncLayerIndexStack() {
			this.layerIndexStack = syncLayerIndexStack(this.layerIndexStack);
		}
		_handleGlobalEscKey(event) {
			_handleGlobalEscKey(event);
		}
		_handleGlobalEscKeyUp(event) {
			_handleGlobalEscKeyUp(event);
		}
		setupEscClose(layerIdx) {
			setupEscClose(this, layerIdx);
		}
		getNowStr(dateSep = "-", timeSep = ":", timestamp = null) {
			return getNowStr(dateSep, timeSep, timestamp);
		}
		formatDate(input, dateSep = "-", timeSep = ":") {
			return formatDate(input, dateSep, timeSep);
		}
		getHourDifference(start, end) {
			return getHourDifference(start, end);
		}
		isUnnecessaryCheck(timeStr, checkIntervalTime) {
			return isUnnecessaryCheck(timeStr, checkIntervalTime);
		}
		download(data, filename) {
			download(data, filename);
		}
		async retry(fn, maxRetries = 3) {
			return retry(fn, maxRetries);
		}
		copyToClipboard(label, text) {
			copyToClipboard$1(label, text);
		}
		addCookie(cookieStr, options = {}) {
			addCookie(cookieStr, options);
		}
		genericSort(data, sortConfigs, nullsFirst = true) {
			return genericSort(data, sortConfigs, nullsFirst);
		}
		isUrl(str) {
			return isUrl(str);
		}
		setHrefParam(key, value) {
			setHrefParam(key, value);
		}
		getUrlParam(url, param) {
			return getUrlParam(url, param);
		}
		isMobile() {
			return isMobile();
		}
		simpleId() {
			return simpleId();
		}
		sleep(ms = 1e3) {
			return sleep(ms);
		}
		copyObj(data) {
			return copyObj(data);
		}
		deepFreeze(obj) {
			return deepFreeze(obj);
		}
		reBuildSignature() {
			return reBuildSignature$1();
		}
		time(label = "default", unit = "s", precision = 2) {
			return time(this.timers, label, unit, precision);
		}
	};
	var GmHttp = class {
		async get(url, queryParams = {}, headers = {}, followRedirect) {
			return this.gmRequest("GET", url, null, queryParams, headers, followRedirect);
		}
		post(url, body = {}, headers = {}) {
			const requestHeaders = {
				"Content-Type": "application/json",
				...headers
			};
			const bodyString = JSON.stringify(body);
			return this.gmRequest("POST", url, bodyString, null, requestHeaders);
		}
		postForm(url, formData = {}, headers = {}) {
			const requestHeaders = headers || {};
			requestHeaders["Content-Type"] ||= "application/x-www-form-urlencoded";
			let bodyString = "";
			if (formData && Object.keys(formData).length > 0) bodyString = Object.entries(formData).map(([key, value]) => `${key}=${String(value)}`).join("&");
			return this.gmRequest("POST", url, bodyString, null, requestHeaders);
		}
		postFileFormData(url, formFields = {}, headers = {}) {
			const requestHeaders = headers || {};
			const boundary = `----WebKitFormBoundary${Math.random().toString(36).substring(2)}`;
			requestHeaders["Content-Type"] = `multipart/form-data; boundary=${boundary}`;
			let body = "";
			if (formFields && Object.keys(formFields).length > 0) body = Object.entries(formFields).map(([key, value]) => `--${boundary}\r\nContent-Disposition: form-data; name="${key}"\r\n\r\n${String(value)}\r\n`).join("");
			body += `--${boundary}--`;
			return this.gmRequest("POST", url, body, null, requestHeaders);
		}
		async downloadFileInChunks(url, headers = {}, filename, transform) {
			if (!filename) throw new Error("请提供文件名 (filename) 用于保存。");
			const timeout = await storageManager.getSetting("httpTimeout", 5e3);
			const retryCount = await storageManager.getSetting("httpRetryCount", 3);
			let fileSize;
			let mimeType;
			clog.log(`[${filename}] 正在获取文件大小...`);
			try {
				const sizeResponse = await utils.retry(() => new Promise((resolve, reject) => {
					GM_xmlhttpRequest({
						method: "GET",
						url,
						headers: {
							...headers,
							Range: "bytes=0-0"
						},
						timeout,
						onload: resolve,
						onerror: () => reject(new Error("网络错误:无法获取文件大小")),
						ontimeout: () => reject(new Error("超时:获取文件大小"))
					});
				}), retryCount);
				if (sizeResponse.status !== 206 && sizeResponse.status !== 200) throw new Error(`请求文件大小失败,状态码: ${sizeResponse.status}`);
				{
					const contentRangeMatch = sizeResponse.responseHeaders.match(/content-range:\s*bytes\s*\d+-\d+\/(\d+)/i);
					const contentTypeMatch = sizeResponse.responseHeaders.match(/content-type:\s*([^\s;]+)/i);
					if (contentRangeMatch && contentRangeMatch[1]) fileSize = parseInt(contentRangeMatch[1], 10);
					else {
						const contentLengthMatch = sizeResponse.responseHeaders.match(/content-length:\s*(\d+)/i);
						if (!contentLengthMatch || sizeResponse.status !== 200) throw new Error("无法从响应头中获取文件总大小,服务器可能不支持 Range 请求。");
						fileSize = parseInt(contentLengthMatch[1], 10);
						clog.warn(`[${filename}] 服务器返回 200 状态码,可能不支持 Range 请求。将尝试完整下载。`);
					}
					if (contentTypeMatch && contentTypeMatch[1]) mimeType = contentTypeMatch[1];
					clog.log(`[${filename}] 文件总大小:${(fileSize / 1024 / 1024).toFixed(2)} MB, MIME 类型: ${mimeType || "未知"}`);
				}
			} catch (err) {
				clog.error(`[${filename}] 获取文件大小失败:`, err instanceof Error ? err.message : String(err));
				throw err;
			}
			if (!fileSize || fileSize <= 0) throw new Error("获取到的文件大小无效或服务器拒绝提供大小信息。");
			const chunkSize = 1048576;
			const chunkCount = Math.ceil(fileSize / chunkSize);
			const promises = [];
			const chunks = new Array(chunkCount);
			clog.log(`[${filename}] 文件将被分为 ${chunkCount} 块进行下载 (每块约 ${1 .toFixed(2)} MB)`);
			for (let index = 0; index < chunkCount; index++) {
				const start = index * chunkSize;
				const rangeHeader = `bytes=${start}-${Math.min(start + chunkSize - 1, fileSize - 1)}`;
				await utils.retry(() => new Promise((resolve, reject) => {
					const requestHeaders = {
						...headers,
						Range: rangeHeader,
						Accept: "application/octet-stream"
					};
					GM_xmlhttpRequest({
						method: "GET",
						url,
						headers: requestHeaders,
						timeout,
						responseType: "arraybuffer",
						onload: (response) => {
							if (response.status === 206 || response.status === 200) {
								const chunkData = response.response;
								if (chunkData instanceof ArrayBuffer) {
									chunks[index] = chunkData;
									clog.log(`[${filename}] 成功下载第 ${index + 1}/${chunkCount} 块 (${rangeHeader})`);
									resolve();
								} else reject(new Error(`第 ${index + 1} 块响应不是 ArrayBuffer。`));
							} else reject(new Error(`第 ${index + 1} 块请求失败,状态码: ${response.status}`));
						},
						onerror: (errorEvent) => reject(new Error(`第 ${index + 1} 块网络错误: ${errorEvent.error}`)),
						ontimeout: () => reject(new Error(`第 ${index + 1} 块超时。`))
					});
				}), retryCount);
				promises.push(Promise.resolve());
			}
			try {
				await Promise.all(promises);
				clog.log(`[${filename}] 所有分块下载完成,开始合并...`);
			} catch (err) {
				clog.error(`[${filename}] 分块下载过程中发生错误:`, err instanceof Error ? err.message : String(err));
				throw err;
			}
			const blob = new Blob(chunks);
			if (blob.size !== fileSize) clog.warn(`[${filename}] 警告:合并后的 Blob 大小 (${blob.size}) 与预期文件大小 (${fileSize}) 不匹配!`);
			const text = await blob.text();
			const content = transform ? transform(text) : text;
			utils.download(content, filename);
			clog.log(`[${filename}] 文件合并完成,已触发浏览器下载。`);
		}
		async gmRequest(method, url, data = {}, queryParams = {}, headers = {}, followRedirect = false) {
			let requestUrl = url;
			if (queryParams && Object.keys(queryParams).length) {
				const queryString = new URLSearchParams(queryParams).toString();
				requestUrl += (requestUrl.includes("?") ? "&" : "?") + queryString;
			}
			const timeout = await storageManager.getSetting("httpTimeout", 5e3);
			const retryCount = await storageManager.getSetting("httpRetryCount", 3);
			const requestData = data || void 0;
			return await utils.retry(() => new Promise((resolve, reject) => {
				GM_xmlhttpRequest({
					method,
					url: requestUrl,
					headers,
					timeout,
					data: requestData,
					onload: (response) => {
						try {
							if (followRedirect && response.finalUrl && response.finalUrl !== requestUrl) {
								reject("请求被重定向了,URL是:" + response.finalUrl);
								return;
							}
							if (response.status >= 200 && response.status < 300) if (response.responseText) try {
								resolve(JSON.parse(response.responseText));
							} catch {
								resolve(response.responseText);
							}
							else resolve(response.responseText || response);
							else {
								clog.error("请求失败,状态码:", response.status, requestUrl);
								if (response.responseText) try {
									reject(JSON.parse(response.responseText));
								} catch {
									reject(new Error(response.responseText || `请求发生错误 ${response.status}`));
								}
								else reject(new Error(`请求发生错误 ${response.status}`));
							}
						} catch (err) {
							reject(err);
						}
					},
					onerror: (errorEvent) => {
						clog.error("网络错误:", requestUrl);
						reject(new Error(errorEvent.error || "网络错误"));
					},
					ontimeout: () => {
						reject(new Error("请求超时: " + requestUrl));
					}
				});
			}), retryCount);
		}
	};
	var layer_fix_default = "/**\n * 修复 layui-layer 关闭按钮不可见 + IE hack 被 lightningcss 误删的属性。\n *\n * 背景:layer.css 含 `*right` / `_display` 等 IE 前缀 hack,vite lightningcss\n * (errorRecovery)解析时连带丢掉相邻标准属性,导致:\n * - `.layui-layer-setwin` 丢失 `position:absolute; right:15px` → 关闭钮不在右上角\n * - `.layui-layer-close2` 几乎只剩无效 `_display:none` → 无标题层关闭钮失效\n *\n * 本文件用无 hack 的标准 CSS 覆盖还原。\n */\n\n.layui-layer-setwin {\n    position: absolute !important;\n    right: 15px !important;\n    top: 15px !important;\n    font-size: 0;\n    line-height: initial;\n    z-index: 10;\n}\n\n.layui-layer-setwin a {\n    position: relative;\n    display: inline-block;\n    width: 16px;\n    height: 16px;\n    margin-left: 10px;\n    font-size: 12px;\n    vertical-align: top;\n}\n\n.layui-layer-setwin .layui-layer-close1 {\n    cursor: pointer;\n    background-position: 0 -40px;\n}\n\n.layui-layer-setwin .layui-layer-close1:hover {\n    opacity: 0.7;\n}\n\n.layui-layer-setwin .layui-layer-close2 {\n    position: absolute !important;\n    right: -28px !important;\n    top: -28px !important;\n    width: 30px !important;\n    height: 30px !important;\n    margin-left: 0 !important;\n    background-position: -149px -31px !important;\n    display: inline-block !important;\n    cursor: pointer;\n}\n\n.layui-layer-setwin .layui-layer-close2:hover {\n    background-position: -180px -31px !important;\n}\n";
	function resetOverflowByShadeCount(delay = 10) {
		setTimeout(() => {
			const shadeCount = document.querySelectorAll(".layui-layer-shade").length;
			document.documentElement.style.overflow = shadeCount > 0 ? "hidden" : "";
		}, delay);
	}
	function removeFromEscStack(index) {
		try {
			const stack = window.utils?.layerIndexStack;
			if (!stack || index == null) return;
			const num = Number(index);
			for (let i = stack.length - 1; i >= 0; i--) if (stack[i] === num) stack.splice(i, 1);
		} catch {}
	}
	function setupLayerWrapper() {
		injectCss(layer_fix_default);
		const originalClose = layer.close;
		layer.close = function(index) {
			removeFromEscStack(index);
			const result = originalClose.call(this, index);
			resetOverflowByShadeCount();
			return result;
		};
		const originalCloseAll = layer.closeAll;
		if (typeof originalCloseAll === "function") layer.closeAll = function(type) {
			try {
				const stack = window.utils?.layerIndexStack;
				if (stack) stack.length = 0;
			} catch {}
			const result = originalCloseAll.call(this, type);
			resetOverflowByShadeCount();
			return result;
		};
		const originalOpen = layer.open;
		layer.open = function(options) {
			const opts = options || {};
			if (opts.closeBtn === void 0 || opts.closeBtn === null) opts.closeBtn = 1;
			if (opts.shadeClose === void 0 && (opts.type === 1 || opts.type === 2)) opts.shadeClose = true;
			const originalSuccess = opts.success;
			opts.success = function(el, index) {
				if (typeof originalSuccess == "function") originalSuccess.call(this, el, index);
				utils.setupEscClose(index);
			};
			return originalOpen.call(this, opts);
		};
	}
	var tooltip_default = ".js-tooltip {\n    /* 通用样式 */\n    position: fixed;\n    padding: 8px 12px;\n    border-radius: 6px;\n    white-space: normal;\n    max-width: 600px;\n    pointer-events: none;\n    font-size: 14px;\n    line-height: 1.5;\n    z-index: var(--jhs-z-top);\n    background: #f0fdf4;\n    color: #166534;\n    border: none;\n    box-shadow: 0 6px 20px rgb(0, 0, 0, 0.3);\n    display: none;\n}\n\n.js-tooltip.is-active {\n    display: block !important;\n}\n";
	var TOOLTIP_SELECTOR = "[data-tip-top], [data-tip-bottom], [data-tip-left], [data-tip-right], [data-tip]";
	function createTooltipElement(content) {
		const wrapper = document.createElement("div");
		wrapper.classList.add("js-tooltip");
		const inner = document.createElement("div");
		inner.textContent = content;
		wrapper.appendChild(inner);
		document.body.appendChild(wrapper);
		return wrapper;
	}
	function positionTooltip(element, content, direction) {
		const tooltip = createTooltipElement(content);
		tooltip.style.display = "block";
		const elementRect = element.getBoundingClientRect();
		const tooltipRect = tooltip.getBoundingClientRect();
		tooltip.style.display = "none";
		const viewportWidth = window.innerWidth;
		const viewportHeight = window.innerHeight;
		let left;
		let top;
		let actualDirection = direction;
		const fitsVertically = (y) => y >= 8 && y + tooltipRect.height <= viewportHeight - 8;
		const fitsHorizontally = (x) => x >= 8 && x + tooltipRect.width <= viewportWidth - 8;
		const centerX = elementRect.left + elementRect.width / 2 - tooltipRect.width / 2;
		const centerY = elementRect.top + elementRect.height / 2 - tooltipRect.height / 2;
		switch (direction) {
			case "top":
				top = elementRect.top - tooltipRect.height - 0;
				if (top < 8 && fitsVertically(elementRect.bottom + 0)) {
					top = elementRect.bottom + 0;
					actualDirection = "bottom";
				}
				break;
			case "bottom":
				top = elementRect.bottom + 0;
				if (top + tooltipRect.height > viewportHeight - 8 && fitsVertically(elementRect.top - tooltipRect.height - 0)) {
					top = elementRect.top - tooltipRect.height - 0;
					actualDirection = "top";
				}
				break;
			case "left":
				left = elementRect.left - tooltipRect.width - 0;
				if (left < 8 && fitsHorizontally(elementRect.right + 0)) {
					left = elementRect.right + 0;
					actualDirection = "right";
				}
				break;
			case "right":
				left = elementRect.right + 0;
				if (left + tooltipRect.width > viewportWidth - 8 && fitsHorizontally(elementRect.left - tooltipRect.width - 0)) {
					left = elementRect.left - tooltipRect.width - 0;
					actualDirection = "left";
				}
				break;
		}
		const isHorizontal = actualDirection === "left" || actualDirection === "right";
		if (actualDirection === "top" || actualDirection === "bottom") {
			left = centerX;
			if (left < 8) left = 8;
			else if (left + tooltipRect.width > viewportWidth - 8) left = viewportWidth - tooltipRect.width - 8;
		} else if (isHorizontal) {
			top = centerY;
			if (top < 8) top = 8;
			else if (top + tooltipRect.height > viewportHeight - 8) top = viewportHeight - tooltipRect.height - 8;
		}
		tooltip.style.left = `${left}px`;
		tooltip.style.top = `${top}px`;
		tooltip.classList.add("is-active");
		element.tooltipElement = tooltip;
	}
	function setupTooltip() {
		injectCss(tooltip_default);
		document.addEventListener("mouseover", (event) => {
			const target = event.target.closest(TOOLTIP_SELECTOR);
			if (target && !target.tooltipElement) {
				let content = "";
				let direction = "top";
				if (target.hasAttribute("data-tip-bottom")) {
					content = target.getAttribute("data-tip-bottom") ?? "";
					direction = "bottom";
				} else if (target.hasAttribute("data-tip-left")) {
					content = target.getAttribute("data-tip-left") ?? "";
					direction = "left";
				} else if (target.hasAttribute("data-tip-right")) {
					content = target.getAttribute("data-tip-right") ?? "";
					direction = "right";
				} else if (target.hasAttribute("data-tip-top")) {
					content = target.getAttribute("data-tip-top") ?? "";
					direction = "top";
				} else if (target.hasAttribute("data-tip")) {
					content = target.getAttribute("data-tip") ?? "";
					direction = "top";
				}
				if (!content) return;
				target.hoverTimeout = window.setTimeout(() => {
					if (target.matches(":hover") && !target.tooltipElement) positionTooltip(target, content, direction);
				}, 50);
			}
		});
		document.addEventListener("mouseout", (event) => {
			const target = event.target.closest(TOOLTIP_SELECTOR);
			if (!target) return;
			if (target.hoverTimeout) {
				clearTimeout(target.hoverTimeout);
				target.hoverTimeout = null;
			}
			if (!target.contains(event.relatedTarget)) {
				if (target.tooltipElement) {
					target.tooltipElement.remove();
					target.tooltipElement = null;
				}
			}
		});
	}
	var WEBDAV_SALT = "x7k9p3";
	function encryptCredential(value) {
		return (WEBDAV_SALT + value + WEBDAV_SALT).split("").map((ch) => {
			const code = ch.codePointAt(0);
			return String.fromCodePoint(code + 5);
		}).join("");
	}
	function decryptCredential(value) {
		return value.split("").map((ch) => {
			const code = ch.codePointAt(0);
			return String.fromCodePoint(code - 5);
		}).join("").slice(6, -6);
	}
	var BADGE_BASE = {
		display: "inline-block",
		padding: "1px 6px",
		borderRadius: "3px",
		fontSize: "11px",
		lineHeight: "16px",
		margin: "1px",
		whiteSpace: "nowrap"
	};
	var BADGE_COLORS = {
		ok: {
			background: "#dcfce7",
			color: "#166534"
		},
		fail: {
			background: "#fee2e2",
			color: "#991b1b"
		},
		skip: {
			background: "#f1f5f9",
			color: "#64748b"
		},
		page: {
			background: "#e0e7ff",
			color: "#3730a3"
		},
		site: {
			background: "#fef3c7",
			color: "#92400e"
		},
		flag: {
			background: "#fce7f3",
			color: "#9d174d"
		}
	};
	var TIME_COLORS = {
		fast: "#16a34a",
		medium: "#ca8a04",
		slow: "#dc2626"
	};
	function summarize(plugins) {
		return {
			total: plugins.length,
			cssOk: plugins.filter((p) => p.cssStatus === "fulfilled").length,
			handleOk: plugins.filter((p) => p.handleStatus === "fulfilled").length,
			failed: plugins.filter((p) => p.cssStatus === "rejected" || p.handleStatus === "rejected").length,
			skipped: plugins.filter((p) => p.cssStatus === "skipped" && p.handleStatus === "skipped").length,
			flagged: plugins.filter((p) => p.isFeatureFlagged).length,
			totalMs: plugins.reduce((sum, p) => sum + (p.totalDurationMs ?? 0), 0)
		};
	}
	function sortRows(plugins) {
		const isFailed = (p) => p.cssStatus === "rejected" || p.handleStatus === "rejected";
		return [...plugins].sort((a, b) => {
			const failDiff = Number(isFailed(b)) - Number(isFailed(a));
			if (failDiff !== 0) return failDiff;
			return (b.totalDurationMs ?? 0) - (a.totalDurationMs ?? 0);
		});
	}
	function StatusBadge({ status, durationMs }) {
		const tone = status === "fulfilled" ? "ok" : status === "rejected" ? "fail" : "skip";
		const icon = status === "fulfilled" ? "✅" : status === "rejected" ? "❌" : "⏭";
		return (0, import_jsx_runtime.jsxs)("span", {
			style: {
				...BADGE_BASE,
				...BADGE_COLORS[tone]
			},
			children: [
				icon,
				" ",
				durationMs != null ? `${durationMs}ms` : status === "skipped" ? "跳过" : "-"
			]
		});
	}
	function DurationCell({ ms }) {
		if (ms == null) return (0, import_jsx_runtime.jsx)("span", {
			style: {
				color: "#94a3b8",
				fontSize: "11px"
			},
			children: "-"
		});
		return (0, import_jsx_runtime.jsxs)("span", {
			style: {
				fontFamily: "monospace",
				fontSize: "11px",
				color: ms < 100 ? TIME_COLORS.fast : ms <= 500 ? TIME_COLORS.medium : TIME_COLORS.slow
			},
			children: [ms, "ms"]
		});
	}
	function BadgeListCell({ values, tone }) {
		if (values.length === 0) return (0, import_jsx_runtime.jsx)("span", {
			style: {
				color: "#94a3b8",
				fontSize: "11px"
			},
			children: "全部"
		});
		return (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: values.map((value) => (0, import_jsx_runtime.jsx)("span", {
			style: {
				...BADGE_BASE,
				...BADGE_COLORS[tone]
			},
			children: value
		}, value)) });
	}
	function DiagnosticsTable({ data }) {
		const summary = summarize(data);
		const rows = sortRows(data);
		const th = {
			padding: "8px 6px",
			textAlign: "left",
			fontWeight: 600,
			borderBottom: "2px solid #e2e8f0",
			background: "#f1f5f9",
			whiteSpace: "nowrap"
		};
		const td = {
			padding: "6px",
			borderBottom: "1px solid #f1f5f9",
			verticalAlign: "top"
		};
		return (0, import_jsx_runtime.jsxs)("div", {
			style: { fontSize: "13px" },
			children: [(0, import_jsx_runtime.jsxs)("div", {
				className: "jhs-diag-summary",
				style: {
					background: "#f8fafc",
					border: "1px solid #e2e8f0",
					borderRadius: "6px",
					padding: "10px 12px",
					marginBottom: "12px",
					lineHeight: 1.8
				},
				children: [
					(0, import_jsx_runtime.jsx)("div", {
						style: {
							fontWeight: 700,
							fontSize: "14px",
							marginBottom: "4px"
						},
						children: "📊 插件诊断报告"
					}),
					(0, import_jsx_runtime.jsxs)("div", { children: [
						"总计: ",
						(0, import_jsx_runtime.jsx)("b", { children: summary.total }),
						" 个插件 | ✅ CSS: ",
						summary.cssOk,
						"/",
						summary.total,
						" | ✅ Handle:",
						" ",
						summary.handleOk,
						"/",
						summary.total,
						" | ⏱ 总耗时: ",
						(0, import_jsx_runtime.jsxs)("b", { children: [summary.totalMs, "ms"] })
					] }),
					(0, import_jsx_runtime.jsxs)("div", { children: [
						(0, import_jsx_runtime.jsxs)("span", {
							style: { color: summary.failed > 0 ? "#dc2626" : "#64748b" },
							children: [
								"❌ 失败: ",
								summary.failed,
								" 个插件"
							]
						}),
						" ",
						"| ⏭ 跳过: ",
						summary.skipped,
						" 个插件 | 🚩 Feature Flag: ",
						summary.flagged,
						" 个"
					] })
				]
			}), (0, import_jsx_runtime.jsxs)("table", {
				className: "jhs-diag-table",
				style: {
					width: "100%",
					borderCollapse: "collapse",
					fontSize: "12px"
				},
				children: [(0, import_jsx_runtime.jsx)("thead", { children: (0, import_jsx_runtime.jsxs)("tr", { children: [
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "#"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "插件名"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "页面类型"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "站点"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "CSS"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "Handle"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "耗时"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "错误信息"
					}),
					(0, import_jsx_runtime.jsx)("th", {
						style: th,
						children: "Flag"
					})
				] }) }), (0, import_jsx_runtime.jsx)("tbody", { children: rows.map((p, index) => {
					const failed = p.cssStatus === "rejected" || p.handleStatus === "rejected";
					const error = p.cssError ?? p.handleError;
					return (0, import_jsx_runtime.jsxs)("tr", {
						className: failed ? "jhs-diag-failed" : void 0,
						style: failed ? { background: "rgba(239,68,68,0.04)" } : void 0,
						children: [
							(0, import_jsx_runtime.jsx)("td", {
								style: {
									...td,
									color: "#94a3b8"
								},
								children: index + 1
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: {
									...td,
									fontWeight: failed ? 600 : 400
								},
								children: p.name
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: td,
								children: (0, import_jsx_runtime.jsx)(BadgeListCell, {
									values: p.pageTypes,
									tone: "page"
								})
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: td,
								children: (0, import_jsx_runtime.jsx)(BadgeListCell, {
									values: p.sites,
									tone: "site"
								})
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: td,
								children: (0, import_jsx_runtime.jsx)(StatusBadge, {
									status: p.cssStatus,
									durationMs: p.cssDurationMs
								})
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: td,
								children: (0, import_jsx_runtime.jsx)(StatusBadge, {
									status: p.handleStatus,
									durationMs: p.handleDurationMs
								})
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: td,
								children: (0, import_jsx_runtime.jsx)(DurationCell, { ms: p.totalDurationMs })
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: td,
								children: error ? (0, import_jsx_runtime.jsx)("span", {
									className: "jhs-diag-error",
									title: error,
									style: {
										color: "#dc2626",
										fontSize: "11px",
										display: "inline-block",
										maxWidth: "200px",
										overflow: "hidden",
										textOverflow: "ellipsis",
										whiteSpace: "nowrap",
										verticalAlign: "bottom"
									},
									children: error.length > 60 ? `${error.slice(0, 60)}…` : error
								}) : (0, import_jsx_runtime.jsx)("span", {
									style: {
										color: "#94a3b8",
										fontSize: "11px"
									},
									children: "-"
								})
							}),
							(0, import_jsx_runtime.jsx)("td", {
								style: td,
								children: p.isFeatureFlagged ? (0, import_jsx_runtime.jsxs)("span", {
									style: {
										...BADGE_BASE,
										...BADGE_COLORS.flag
									},
									children: ["🚩 ", p.featureFlagName]
								}) : null
							})
						]
					}, p.name);
				}) })]
			})]
		});
	}
	function DiagnosticsWrapper({ html }) {
		return (0, import_jsx_runtime.jsx)("div", {
			style: { padding: "15px" },
			dangerouslySetInnerHTML: { __html: html }
		});
	}
	function renderDiagnosticsHtml(pluginManager) {
		return jsxToString((0, import_jsx_runtime.jsx)(DiagnosticsTable, { data: pluginManager.getDiagnostics().plugins }));
	}
	function renderDiagnosticsText(pluginManager) {
		const diag = pluginManager.getDiagnostics();
		const plugins = diag.plugins;
		const cssOk = plugins.filter((p) => p.cssStatus === "fulfilled").length;
		const handleOk = plugins.filter((p) => p.handleStatus === "fulfilled").length;
		const failed = plugins.filter((p) => p.cssStatus === "rejected" || p.handleStatus === "rejected");
		const skipped = plugins.filter((p) => p.cssStatus === "skipped" && p.handleStatus === "skipped");
		const flagged = plugins.filter((p) => p.isFeatureFlagged);
		const totalMs = plugins.reduce((sum, p) => sum + (p.totalDurationMs ?? 0), 0);
		const lines = plugins.map((p) => {
			const parts = [
				`${p.cssStatus === "rejected" || p.handleStatus === "rejected" ? "❌" : p.cssStatus === "skipped" && p.handleStatus === "skipped" ? "⏭️" : "✅"} ${p.name}`,
				`CSS:${p.cssStatus}${p.cssDurationMs != null ? `(${p.cssDurationMs}ms)` : ""}`,
				`Handle:${p.handleStatus}${p.handleDurationMs != null ? `(${p.handleDurationMs}ms)` : ""}`,
				`总耗时:${p.totalDurationMs != null ? `${p.totalDurationMs}ms` : "-"}`
			];
			if (p.pageTypes.length) parts.push(`页面:[${p.pageTypes.join(",")}]`);
			if (p.sites.length) parts.push(`站点:[${p.sites.join(",")}]`);
			if (p.isFeatureFlagged) parts.push(`Flag:${p.featureFlagName}`);
			if (p.cssError) parts.push(`CSS错误:${p.cssError}`);
			if (p.handleError) parts.push(`Handle错误:${p.handleError}`);
			return parts.join(" | ");
		});
		return [
			"JavDB Power Tools 插件诊断报告",
			`总计 ${diag.total} 个插件 | CSS ${cssOk}/${diag.total} | Handle ${handleOk}/${diag.total} | 总耗时 ${totalMs}ms`,
			`失败 ${failed.length} 个 | 跳过 ${skipped.length} 个 | Feature Flag ${flagged.length} 个`,
			"",
			...lines
		].join("\n");
	}
	function registerDiagnosticsMenu(pluginManager) {
		GM_registerMenuCommand("📊 插件诊断", () => {
			const diag = pluginManager.getDiagnostics();
			const failed = diag.handle.filter((p) => p.status === "rejected");
			layer.open({
				type: 1,
				title: `插件诊断 — 共 ${diag.total} 个插件,${failed.length} 个失败`,
				area: ["600px", "70%"],
				content: jsxToString((0, import_jsx_runtime.jsx)(DiagnosticsWrapper, { html: renderDiagnosticsHtml(pluginManager) }))
			});
		});
	}
	function detectPageContext() {
		const href = window.location.href;
		const isDetailPage = href.split("?")[0].includes("/v/");
		const isListPage = typeof $ !== "undefined" && ($(".movie-list").length > 0 || href.includes("advanced_search"));
		const isFc2Page = href.includes("advanced_search?type=3") || href.includes("advanced_search?type=100");
		return {
			site: isJavdbSite ? "javdb" : isMissavSite ? "missav" : "unknown",
			pageType: isDetailPage ? "detail" : isFc2Page ? "fc2" : isListPage ? "list" : "unknown",
			isDetailPage,
			isListPage,
			isFc2Page,
			isJavdbSite,
			isMissavSite
		};
	}
	var pageContext = {
		site: "unknown",
		pageType: "unknown",
		isDetailPage: false,
		isListPage: false,
		isFc2Page: false,
		isJavdbSite: false,
		isMissavSite: false
	};
	function initPageContext() {
		pageContext = detectPageContext();
		return pageContext;
	}
	function TemporaryImageContainer({ src, alt = "" }) {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "temporary-container",
			style: { display: "none" },
			children: (0, import_jsx_runtime.jsx)("img", {
				src,
				alt
			})
		});
	}
	var PluginManager = class {
		plugins = new Map();
		registrationComplete = false;
		lastCssResults = [];
		lastHandleResults = [];
		featureFlags = new Map();
		matchesPage(plugin) {
			const types = plugin.pageTypes;
			if (!types || types.length === 0) return true;
			return types.includes(pageContext.pageType);
		}
		register(pluginClass, featureFlag) {
			if (typeof pluginClass !== "function") throw new Error("插件必须是一个类");
			const instance = new pluginClass();
			instance.pluginManager = this;
			const pluginName = instance.getName();
			if (this.plugins.has(pluginName)) throw new Error(`插件"${pluginName}"已注册`);
			if (featureFlag) this.featureFlags.set(pluginName, featureFlag);
			this.plugins.set(pluginName, instance);
		}
		getBean(name) {
			const plugin = this.plugins.get(name);
			if (!plugin && this.registrationComplete) clog.warn(`[PluginManager] getBean("${name}") 未找到已注册插件`);
			return plugin;
		}
		async processCss() {
			this.registrationComplete = true;
			const results = await Promise.all(Array.from(this.plugins).map(async ([name, plugin]) => {
				if (!this.matchesPage(plugin)) return {
					name,
					status: "skipped"
				};
				const start = performance.now();
				try {
					if (typeof plugin.initCss === "function") {
						const css = await plugin.initCss();
						if (css) utils.insertStyle(css);
						return {
							name,
							status: "fulfilled",
							durationMs: Math.round(performance.now() - start)
						};
					}
					return {
						name,
						status: "skipped"
					};
				} catch (err) {
					clog.error(`插件 ${name} 加载 CSS 失败`, err);
					return {
						name,
						status: "rejected",
						error: err,
						durationMs: Math.round(performance.now() - start)
					};
				}
			}));
			this.lastCssResults = results;
			const failed = results.filter((result) => result.status === "rejected");
			if (failed.length) clog.error("以下插件的 CSS 加载失败:", failed.map((result) => result.name));
			return results;
		}
		async processPlugins() {
			const results = await Promise.all(Array.from(this.plugins).map(async ([name, plugin]) => {
				if (!this.matchesPage(plugin)) return {
					name,
					status: "skipped"
				};
				const start = performance.now();
				try {
					if (typeof plugin.handle === "function") {
						await plugin.handle();
						return {
							name,
							status: "fulfilled",
							durationMs: Math.round(performance.now() - start)
						};
					}
					return {
						name,
						status: "skipped"
					};
				} catch (err) {
					clog.error(`插件 ${name} 执行失败`, err);
					return {
						name,
						status: "rejected",
						error: err,
						durationMs: Math.round(performance.now() - start)
					};
				}
			}));
			this.lastHandleResults = results;
			const failed = results.filter((result) => result.status === "rejected");
			if (failed.length) clog.error("以下插件执行失败:", failed.map((result) => result.name));
			return results;
		}
		getDiagnostics() {
			const cssByName = new Map(this.lastCssResults.map((result) => [result.name, result]));
			const handleByName = new Map(this.lastHandleResults.map((result) => [result.name, result]));
			const plugins = Array.from(this.plugins).map(([name, plugin]) => {
				const css = cssByName.get(name);
				const handle = handleByName.get(name);
				const cssDurationMs = css?.durationMs ?? null;
				const handleDurationMs = handle?.durationMs ?? null;
				const featureFlagName = this.featureFlags.get(name) ?? null;
				return {
					name,
					cssStatus: css?.status ?? "skipped",
					handleStatus: handle?.status ?? "skipped",
					cssDurationMs,
					handleDurationMs,
					totalDurationMs: cssDurationMs == null && handleDurationMs == null ? null : (cssDurationMs ?? 0) + (handleDurationMs ?? 0),
					cssError: css?.status === "rejected" ? css.error instanceof Error ? css.error.message : String(css.error) : null,
					handleError: handle?.status === "rejected" ? handle.error instanceof Error ? handle.error.message : String(handle.error) : null,
					pageTypes: [...plugin.pageTypes],
					sites: [...plugin.sites],
					isFeatureFlagged: featureFlagName != null,
					featureFlagName
				};
			});
			return {
				total: this.plugins.size,
				css: this.lastCssResults,
				handle: this.lastHandleResults,
				plugins
			};
		}
		destroyAll() {
			for (const [name, plugin] of this.plugins) try {
				plugin.destroy();
			} catch (err) {
				clog.error(`插件 ${name} 销毁失败`, err);
			}
		}
	};
	var EDIT_SVG = "<svg t=\"1760920692801\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"3545\" width=\"200\" height=\"200\"><path d=\"M1013.929675 128.26571a143.759824 143.759824 0 0 1 10.44409 53.858738 84.576649 84.576649 0 0 1-5.836403 30.308339 92.870485 92.870485 0 0 1-18.635533 29.284408 1314.726599 1314.726599 0 0 1-24.983901 24.574329c-7.372299 7.06512-13.82306 13.311095-19.249891 18.737926-6.143582 6.143582-12.082378 11.672806-17.406817 16.382886L720.266444 82.598415c9.317766-8.601015 20.478607-18.942712 33.277737-31.02509s23.448006-21.604931 31.946628-28.67005a102.085858 102.085858 0 0 1 68.193763-22.731255c11.263234 0.307179 22.116896 2.047861 32.560985 5.222045 10.546483 3.071791 19.659463 6.655547 27.441334 10.546483 16.280493 8.601015 34.301667 23.550399 54.063524 45.052936 19.864249 21.502538 35.120812 43.82422 46.076867 67.272226z m-907.20231 570.943576l32.560986-33.38013c17.099637-17.509209 38.397389-39.216533 64.098041-64.917186l84.986221-85.395793 94.303987-94.815953 250.350976-251.477299L850.817567 389.163169 600.46659 640.640468l-93.177663 94.815953c-31.02509 30.410732-58.978389 58.364031-83.859898 83.655111-24.779115 25.29108-45.360116 46.17926-61.743001 62.562146a504.797674 504.797674 0 0 1-55.804206 50.274981c-10.239304 7.884264-20.581 14.130239-31.537055 18.737926a507.152714 507.152714 0 0 1-47.715156 19.86425 1609.311367 1609.311367 0 0 1-131.063087 42.185931c-20.478607 5.426831-35.837563 8.908194-45.974474 10.546483-20.88818 2.35504-34.813633-0.819144-41.981145-9.42016-6.860333-8.601015-8.805801-22.93604-5.73401-43.312254a396.261054 396.261054 0 0 1 11.058448-47.305584c5.836403-20.683394 12.082378-42.185931 18.635532-64.40522 6.553154-22.219289 13.003916-42.697897 19.249891-61.435822 6.143582-18.635533 11.263234-31.537055 15.15417-38.602176 4.607687-10.853662 9.829732-20.785787 15.666135-29.796373a192.49891 192.49891 0 0 1 25.086294-29.796374z\" fill=\"#FF9500\" p-id=\"3546\"></path></svg>";
	var DELETE_SVG = "<svg t=\"1760921450746\" class=\"jhs-icon icon\" viewBox=\"0 0 1194 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4530\" width=\"200\" height=\"200\"><path d=\"M761.086847 36.028779s309.754321-147.538628 424.952209 231.50509c2.047962 6.570546 71.337359 253.862013-220.838618 415.139055-12.970429 7.167869-267.515096 145.746661-370.339877 341.327076 0 0-90.963666-205.649563-393.379455-351.566888-6.399883-3.071944-304.549083-156.583796-163.751664-487.2444 3.669266-8.533177 163.666333-336.20717 466.423449-99.411511l24.575549 27.391498L387.931021 324.279495l237.648977 159.570408-109.139333 145.746661L625.579998 849.069874l-30.719437-205.820227 166.226286-169.81022-216.486698-168.103585L761.086847 36.028779z\" fill=\"#F4382E\" p-id=\"4531\"></path></svg>";
	var REFRESH_SVG = "<svg t=\"1760926993643\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"5942\" width=\"200\" height=\"200\"><path d=\"M511.966722 0a511.966722 511.966722 0 1 0 179.828311 32.445891l-22.46254 59.964102A447.970882 447.970882 0 1 1 511.966722 63.99584a31.99792 31.99792 0 0 0 0-63.99584z\" fill=\"#333333\" p-id=\"5943\"></path><path d=\"M649.2378 9.151405A30.909991 30.909991 0 0 1 671.316364 0h193.267438a31.99792 31.99792 0 0 1 31.357962 31.99792c0 17.662852-13.759106 31.99792-31.357962 31.99792H703.954243v160.629559a31.99792 31.99792 0 0 1-31.99792 31.357962 31.485953 31.485953 0 0 1-31.99792-31.357962V31.357962c0-8.511447 3.647763-16.318939 9.343392-21.950573z\" fill=\"#333333\" p-id=\"5944\"></path></svg>";
	var BasePlugin = class {
		pluginManager;
		get sites() {
			return [];
		}
		get pageTypes() {
			return [];
		}
		destroy() {}
		editSvg = EDIT_SVG;
		deleteSvg = DELETE_SVG;
		refreshSvg = REFRESH_SVG;
		getName() {
			throw new Error(`${this.constructor.name} 未显示getName()`);
		}
		getBean(name) {
			return this.pluginManager.getBean(name);
		}
		async initCss() {
			return "";
		}
		async handle() {}
		getPageInfo() {
			let carNum = null;
			let url = null;
			let actress = null;
			let actors = null;
			let publishTime = null;
			const href = window.location.href;
			if (isJavdbSite) {
				carNum = $("a[title=\"複製番號\"]").attr("data-clipboard-text") ?? null;
				url = href.split("?")[0].split("#")[0];
				actress = $(".female").prev().map((_index, el) => $(el).text()).get().join(" ");
				actors = $(".male").prev().map((_index, el) => $(el).text()).get().join(" ");
				publishTime = $("strong:contains(\"日期:\")").parent(".panel-block").find(".value").text().trim();
			}
			return {
				carNum,
				url,
				actress,
				actors,
				publishTime
			};
		}
		getActressId() {
			const match = currentHref.match(/\/actors\/([^/?]+)/);
			if (match && match.length > 1) return match[1];
			else return null;
		}
		getActressPageInfo() {
			const href = window.location.href;
			if (!href.includes("/actors/") && !href.includes("/star/")) throw new Error("接口调用错误, 非演员详情页");
			const allName = [];
			const nameEl = $(".actor-section-name");
			if (nameEl.length) nameEl.text().trim().split(",").forEach((part) => {
				allName.push(part.trim());
			});
			const metaEl = $(".section-meta:not(:contains('影片'))");
			if (metaEl.length) metaEl.text().trim().split(",").forEach((part) => {
				allName.push(part.trim());
			});
			const role = $(".section-meta:contains('男優')").length > 0 ? ACTOR : ACTRESS;
			let movieType = CENSORED;
			if (allName.some((part) => part.includes("無碼"))) movieType = UNCENSORED;
			if (href.includes("uncensored")) movieType = UNCENSORED;
			let blacklistUrl = null;
			let starId = null;
			const urlObj = new URL(href);
			if (isJavdbSite) {
				starId = urlObj.pathname.split("/").filter((seg) => seg.trim() !== "").pop() ?? null;
				const searchParams = urlObj.searchParams;
				searchParams.delete("sort_type");
				searchParams.delete("page");
				blacklistUrl = urlObj.toString();
			}
			return {
				starId,
				name: allName[0],
				allName,
				role,
				movieType,
				blacklistUrl
			};
		}
		getSelector(siteType) {
			const type = siteType || "javdb";
			const selectors = { javdb: {
				boxSelector: ".movie-list",
				itemSelector: ".movie-list .item",
				coverImgSelector: ".cover img",
				requestDomItemSelector: ".movie-list .item",
				nextPageSelector: ".pagination-next"
			} };
			if (!type || !selectors[type]) throw new Error("类型错误: 无法确定选择器类型 (JavDb)");
			return selectors[type];
		}
		parseMovieId(url) {
			return url.split("/").pop().split(/[?#]/)[0];
		}
		getBoxCarInfo(boxEl) {
			let titleAttr;
			let imgTitleAttr;
			let dataTitleAttr;
			const linkEl = boxEl.find("a");
			const url = linkEl.attr("href");
			let carNum = null;
			let title = null;
			let publishTime = null;
			const videoTitleEl = boxEl.find(".video-title");
			if (videoTitleEl.length > 0) {
				const strongEl = videoTitleEl.find("strong");
				if (strongEl.length > 0) carNum = strongEl.text().trim();
				title = (titleAttr = linkEl.attr("title")) == null ? void 0 : titleAttr.trim();
				if (!title) {
					const text = videoTitleEl.text().trim();
					title = carNum && text.includes(carNum) ? text.replace(carNum, "").trim() : text;
				}
				publishTime = boxEl.find(".meta").text().trim();
			}
			if (!carNum) {
				const imgEl = boxEl.find("img");
				if (imgEl.length > 0) title = ((imgTitleAttr = imgEl.attr("title")) == null ? void 0 : imgTitleAttr.trim()) || ((dataTitleAttr = imgEl.attr("data-title")) == null ? void 0 : dataTitleAttr.trim());
				const dates = boxEl.find("date").map((_index, el) => $(el).text().trim()).get();
				const isDate = (val) => /^\d{4}-\d{1,2}-\d{1,2}$/.test(val);
				publishTime = dates.find(isDate) || null;
				carNum = dates.find((val) => !isDate(val)) || null;
			}
			if (!carNum) {
				const msg = "提取番号信息失败: carNum 为空";
				clog.error("Error in getBoxCarInfo:", msg, "Box Element:", boxEl.get(0));
				failWithToast(msg);
			}
			if (featureFlags.westernCarFormat) carNum = this._formatWesternCar(carNum, publishTime || "");
			return {
				carNum,
				url: url || "",
				title: title || "",
				publishTime: publishTime || ""
			};
		}
		_formatWesternCar(carNum, rawDate) {
			if (!carNum || !rawDate) return carNum;
			if (!/^[a-zA-Z\s]+$/.test(carNum)) return carNum;
			const dateMatch = rawDate.match(/\d{2}(\d{2})-(\d{2})-(\d{2})/);
			if (dateMatch) return `${carNum.replace(/\s+/g, "")}.${dateMatch[1]}.${dateMatch[2]}.${dateMatch[3]}`;
			return carNum;
		}
		getBoxCarInfoList(boxEls = null) {
			boxEls ||= $(this.getSelector().itemSelector);
			if (boxEls.length === 0) {
				clog.error("获取当前列表页所有item的番号信息失败!");
				return [];
			}
			const list = [];
			boxEls.each((index, element) => {
				const itemEl = $(element);
				try {
					const info = this.getBoxCarInfo(itemEl);
					list.push(info);
				} catch (err) {
					clog.error("[getBoxCarInfoList] 提取单个 boxCar 信息失败:", err instanceof Error ? err.message : String(err), "元素索引:", index);
				}
			});
			return list;
		}
		checkDuplicateCarNumbers(list, other) {
			if (!list || list.length === 0 || !other || other.length === 0) return false;
			const existing = new Set(list.map((item) => item.carNum).filter(Boolean));
			if (existing.size === 0) return false;
			let duplicateCount = 0;
			for (const item of other) if (item && item.carNum && existing.has(item.carNum)) duplicateCount++;
			if (duplicateCount / other.length >= .5) {
				clog.warn("警告: 检测到大量番号信息重复, 该类别可能已被限制页码。");
				return true;
			}
			return false;
		}
	};
	var DetailPagePlugin = class extends BasePlugin {
		getName() {
			return "DetailPagePlugin";
		}
		get pageTypes() {
			return ["detail"];
		}
		constructor() {
			super();
		}
		async handle() {
			if (window.isDetailPage) {
				$(".video-meta-panel a").each((_index, element) => {
					const href = $(element).attr("href");
					if (href && (href.startsWith("http://") || href.startsWith("https://") || href.startsWith("/"))) $(element).attr("target", "_blank");
				});
				this.handleFancyBox();
			}
		}
		handleFancyBox() {
			document.addEventListener("click", (event) => {
				if (event.target.closest(".fancybox-button--thumbs")) {
					const thumbsVisible = !$(".fancybox-thumbs").is(":hidden");
					localStorage.setItem("jhs_fancyboxThumbs", thumbsVisible.toString());
					unsafeWindow.$.fancybox.defaults.thumbs.autoStart = thumbsVisible;
				}
			});
			if (unsafeWindow.$.fancybox !== void 0) {
				const storedValue = localStorage.getItem("jhs_fancyboxThumbs");
				unsafeWindow.$.fancybox.defaults.thumbs.autoStart = storedValue === "true";
			}
		}
	};
	var HighlightMagnetPlugin = class extends BasePlugin {
		getName() {
			return "HighlightMagnetPlugin";
		}
		get pageTypes() {
			return ["detail"];
		}
		doFilterMagnet() {
			this.handleDb();
		}
		handleDb() {
			if (!isJavdbSite) return;
			const nameEls = $("#magnets-content .name");
			if (nameEls.length === 0) return;
			const highQualityMarkers = [
				"4k",
				"-c",
				"-u",
				"-uc"
			];
			let hasHighQuality = false;
			nameEls.each((_index, element) => {
				const nameEl = $(element);
				const nameText = nameEl.text().toLowerCase();
				const isHighQuality = highQualityMarkers.some((marker) => nameText.includes(marker));
				nameEl.parent().parent().parent().addClass("magnet-row");
				if (nameText.includes("4k")) nameEl.css("color", "#f40");
				if (isHighQuality) {
					hasHighQuality = true;
					nameEl.parent().parent().parent().addClass("high-quality");
				}
			});
			if (hasHighQuality) $("#magnets-content .magnet-row").not(".high-quality").hide();
			else $("#enable-magnets-filter").addClass("do-hide");
		}
		showAll() {
			if (isJavdbSite) $("#magnets-content .item").toArray().forEach((element) => $(element).show());
		}
	};
	function FoldCategorySectionButton() {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "foldCategoryBtn",
			children: (0, import_jsx_runtime.jsxs)("a", {
				className: "jhs-toolbar-menu-btn",
				style: {
					backgroundColor: "#d23e60 !important",
					marginLeft: "20px",
					borderBottom: "none !important",
					borderRadius: "3px"
				},
				children: [(0, import_jsx_runtime.jsx)("span", {}), (0, import_jsx_runtime.jsx)("i", { style: { marginLeft: "10px" } })]
			})
		});
	}
	function FoldCategoryToolbar({ selectedTagsText }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				display: "flex",
				alignItems: "center",
				flexGrow: 1,
				justifyContent: "flex-end"
			},
			children: [(0, import_jsx_runtime.jsxs)("div", { children: ["已选分类: ", (0, import_jsx_runtime.jsx)("span", {
				id: "jhs-check-tag",
				children: selectedTagsText
			})] }), (0, import_jsx_runtime.jsxs)("a", {
				className: "jhs-toolbar-menu-btn  main-tab-btn",
				id: "foldCategoryBtn",
				style: { backgroundColor: "#d23e60 !important" },
				children: [(0, import_jsx_runtime.jsx)("span", {}), (0, import_jsx_runtime.jsx)("i", { style: { marginLeft: "10px" } })]
			})]
		});
	}
	function HighlightButton() {
		return (0, import_jsx_runtime.jsx)("button", {
			className: "highlight-btn",
			title: "高亮显示",
			children: "★"
		});
	}
	var fold_category_plugin_default = "#tags a.tag,\n.tags a.tag {\n    position: relative;\n}\n\n.highlight-btn {\n    position: absolute;\n    top: -10px;\n    right: -10px;\n    background-color: #4caf50;\n    color: white;\n    border: none;\n    border-radius: 50%;\n    width: 24px;\n    height: 24px;\n    font-size: 14px;\n    line-height: 24px;\n    text-align: center;\n    cursor: pointer;\n    box-shadow: 0 2px 4px rgb(0, 0, 0, 0.2);\n    display: none;\n    z-index: 999;\n}\n\n/* 当父元素被高亮时,按钮变为其他颜色 */\n.highlighted .highlight-btn {\n    background-color: #ff5722;\n}\n\n/* 高亮状态下的标签样式 */\n.highlighted {\n    /* 浅黄色 */\n    border: __HIGHLIGHTED_TAG_NUMBER__px solid __HIGHLIGHTED_TAG_COLOR__;\n}\n";
	var FoldCategoryPlugin = class extends BasePlugin {
		getName() {
			return "FoldCategoryPlugin";
		}
		get pageTypes() {
			return ["list"];
		}
		async initCss() {
			const settings = await storageManager.getSetting();
			return fold_category_plugin_default.replace("__HIGHLIGHTED_TAG_NUMBER__", String(settings.highlightedTagNumber || 1)).replace("__HIGHLIGHTED_TAG_COLOR__", settings.highlightedTagColor || "#ce2222");
		}
		async handle() {
			if (window.isListPage) {
				if (!currentHref.includes("advanced_search")) {
					this.highlightTag();
					utils.loopDetector(() => currentHref.includes("/actors/") || $("#waitCheckBtn").length > 0, () => {
						this.createFoldBtn();
					}, 1, 1e4, true);
					$("#tags .tag-category .tag-expand").each((_index, expandEl) => {
						if ($(expandEl).parent().hasClass("collapse")) expandEl.click();
					});
				}
			}
		}
		highlightTag() {
			(async () => {
				const highlightedTags = await storageManager.getHighlightedTags();
				if (highlightedTags) highlightedTags.forEach((tagName) => {
					$(`#tags a.tag:contains(${tagName})`).addClass("highlighted");
					$(`.tags a.tag:contains(${tagName})`).addClass("highlighted");
				});
			})().then();
			$("#tags a.tag, .tags a.tag").hover(function() {
				const tagEl = $(this);
				const btnEl = $(jsxToString((0, import_jsx_runtime.jsx)(HighlightButton, {})));
				tagEl.append(btnEl);
				btnEl.fadeIn(0);
			}, function() {
				$(this).find(".highlight-btn").fadeOut(0, function() {
					$(this).remove();
				});
			});
			$(document).on("click", ".highlight-btn", async function(event) {
				event.stopPropagation();
				event.preventDefault();
				const tagEl = $(this).closest("a.tag");
				const cloneEl = tagEl.clone();
				cloneEl.find(".highlight-btn").remove();
				const tagName = cloneEl.text().trim().replace(/\s*\(\d+\)$/, "");
				let highlightedTags = await storageManager.getHighlightedTags();
				if (highlightedTags.includes(tagName)) {
					highlightedTags = highlightedTags.filter((item) => item !== tagName);
					tagEl.removeClass("highlighted");
				} else {
					highlightedTags.push(tagName);
					tagEl.addClass("highlighted");
				}
				await storageManager.setHighlightedTags(highlightedTags);
			});
		}
		async createFoldBtn() {
			let tagsEl = $("#tags");
			const selectedTagsText = $("#tags dl div.tag.is-info").map(function() {
				return $(this).text().replace(/\n/g, "").replace(/ /g, "");
			}).get().join(" ");
			if (!selectedTagsText) return;
			$(".tabs").append(jsxToString((0, import_jsx_runtime.jsx)(FoldCategoryToolbar, { selectedTagsText })));
			const sectionTitleEl = $("h2.section-title");
			if (sectionTitleEl.length > 0) {
				sectionTitleEl.append(jsxToString((0, import_jsx_runtime.jsx)(FoldCategorySectionButton, {})));
				tagsEl = $("section > div > div.box");
			}
			if (!tagsEl) return;
			const foldBtnEl = $("#foldCategoryBtn");
			let isFolded = localStorage.getItem("jhs_foldCategory") === "yes";
			const [label, iconClass] = isFolded ? ["展开", "icon-angle-double-down"] : ["折叠", "icon-angle-double-up"];
			foldBtnEl.find("span").text(label).end().find("i").attr("class", iconClass);
			if (!window.location.href.includes("noFold=1")) tagsEl[isFolded ? "hide" : "show"]();
			foldBtnEl.on("click", async (event) => {
				event.preventDefault();
				isFolded = !isFolded;
				localStorage.setItem("jhs_foldCategory", isFolded ? "yes" : "no");
				const [nextLabel, nextIconClass] = isFolded ? ["展开", "icon-angle-double-down"] : ["折叠", "icon-angle-double-up"];
				foldBtnEl.find("span").text(nextLabel).end().find("i").attr("class", nextIconClass);
				tagsEl[isFolded ? "hide" : "show"]();
			});
		}
	};
	function ActressInfoDetailSegment({ actressName, info, wikiApiUrl }) {
		const nameNode = (0, import_jsx_runtime.jsxs)("strong", {
			style: { marginRight: "5px" },
			children: [(0, import_jsx_runtime.jsx)("span", {
				style: { userSelect: "all" },
				children: actressName
			}), ":"]
		});
		if (info) return (0, import_jsx_runtime.jsxs)("div", {
			className: "panel-block actress-info",
			children: [nameNode, (0, import_jsx_runtime.jsxs)("a", {
				href: info.url,
				style: { marginLeft: "5px" },
				target: "_blank",
				children: [
					(0, import_jsx_runtime.jsxs)("span", {
						className: "info-tag",
						children: [
							info.birthday,
							" ",
							info.age
						]
					}),
					(0, import_jsx_runtime.jsxs)("span", {
						className: "info-tag",
						children: [
							info.height,
							" ",
							info.weight
						]
					}),
					(0, import_jsx_runtime.jsxs)("span", {
						className: "info-tag",
						children: [
							info.threeSizeText,
							" ",
							info.braSize
						]
					})
				]
			})]
		});
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "panel-block actress-info",
			children: [(0, import_jsx_runtime.jsx)("a", {
				href: wikiApiUrl + actressName,
				target: "_blank",
				children: nameNode
			}), (0, import_jsx_runtime.jsx)("span", {
				style: {
					marginLeft: "5px",
					color: "#999"
				},
				children: "暂无此演员信息"
			})]
		});
	}
	function ActressInfoStarPageHtml({ info }) {
		if (info) return (0, import_jsx_runtime.jsx)("a", {
			className: "actress-info",
			href: info.url,
			target: "_blank",
			children: (0, import_jsx_runtime.jsxs)("div", {
				style: {
					fontSize: "17px",
					fontWeight: "normal",
					marginTop: "5px"
				},
				children: [(0, import_jsx_runtime.jsxs)("div", {
					style: {
						display: "flex",
						marginBottom: "10px"
					},
					children: [
						(0, import_jsx_runtime.jsxs)("span", {
							style: { width: "300px" },
							children: ["出生日期: ", info.birthday]
						}),
						(0, import_jsx_runtime.jsxs)("span", {
							style: { width: "200px" },
							children: ["年龄: ", info.age]
						}),
						(0, import_jsx_runtime.jsxs)("span", {
							style: { width: "200px" },
							children: ["身高: ", info.height]
						})
					]
				}), (0, import_jsx_runtime.jsxs)("div", {
					style: {
						display: "flex",
						marginBottom: "10px"
					},
					children: [
						(0, import_jsx_runtime.jsxs)("span", {
							style: { width: "300px" },
							children: ["体重: ", info.weight]
						}),
						(0, import_jsx_runtime.jsxs)("span", {
							style: { width: "200px" },
							children: ["三围: ", info.threeSizeText]
						}),
						(0, import_jsx_runtime.jsxs)("span", {
							style: { width: "200px" },
							children: ["罩杯: ", info.braSize]
						})
					]
				})]
			})
		});
		return (0, import_jsx_runtime.jsx)("div", {
			className: "actress-info",
			style: {
				fontSize: "17px",
				fontWeight: "normal",
				marginTop: "5px"
			},
			children: "无此相关演员信息"
		});
	}
	var actress_info_plugin_default = ".info-tag {\n    background-color: #ecf5ff;\n    display: inline-block;\n    height: 32px;\n    padding: 0 10px;\n    line-height: 30px;\n    font-size: 12px;\n    color: #409eff;\n    border: 1px solid #d9ecff;\n    border-radius: 4px;\n    box-sizing: border-box;\n    white-space: nowrap;\n}\n";
	var ActressInfoPlugin = class extends BasePlugin {
		apiUrl = "https://ja.wikipedia.org/wiki/";
		getName() {
			return "ActressInfoPlugin";
		}
		async handle() {
			if (await storageManager.getSetting("enableLoadActressInfo", "yes") === "yes") this.loadActressInfo();
		}
		loadActressInfo() {
			this.handleDetailPage().then();
			this.handleStarPage().then();
		}
		async initCss() {
			return actress_info_plugin_default;
		}
		async handleDetailPage() {
			if ($(".actress-info").length > 0) return;
			const actressNames = $(".female").prev().map((_index, element) => $(element).text().trim()).get();
			if (!actressNames.length) return;
			const storageKey = "jhs_actress_info";
			const rawCache = localStorage.getItem(storageKey);
			let cache = {};
			try {
				if (rawCache) cache = JSON.parse(rawCache);
			} catch {}
			let info;
			let html = "";
			for (const actressName of actressNames) {
				info = cache[actressName];
				if (!info) try {
					info = await this.searchInfo(actressName);
					if (info) cache[actressName] = info;
				} catch {
					clog.error("该名称查询失败,尝试其它名称");
				}
				const segment = jsxToString((0, import_jsx_runtime.jsx)(ActressInfoDetailSegment, {
					actressName,
					info,
					wikiApiUrl: this.apiUrl
				}));
				html += segment;
			}
			$("strong:contains(\"演員\")").parent().after(html);
			localStorage.setItem(storageKey, JSON.stringify(cache));
		}
		async handleStarPage() {
			if ($(".actress-info").length > 0) return;
			const names = [];
			const nameSectionEl = $(".actor-section-name");
			if (nameSectionEl.length) nameSectionEl.text().trim().split(",").forEach((name) => {
				names.push(name.trim());
			});
			const metaEl = $(".section-meta:not(:contains('影片'))");
			if (metaEl.length) metaEl.text().trim().split(",").forEach((name) => {
				names.push(name.trim());
			});
			if (!names.length) return;
			const storageKey = "jhs_actress_info";
			const rawCache = localStorage.getItem(storageKey);
			let cache = {};
			try {
				if (rawCache) cache = JSON.parse(rawCache);
			} catch {}
			let info = null;
			for (const actressName of names) {
				info = cache[actressName];
				if (info) break;
				try {
					info = await this.searchInfo(actressName);
				} catch {
					clog.error("该名称查询失败,尝试其它名称");
				}
				if (info) break;
			}
			if (info) names.forEach((actressName) => {
				cache[actressName] = info;
			});
			const html = jsxToString((0, import_jsx_runtime.jsx)(ActressInfoStarPageHtml, { info }));
			nameSectionEl.parent().append(html);
			localStorage.setItem(storageKey, JSON.stringify(cache));
		}
		async searchInfo(actressName) {
			if (actressName === "三上悠亞") actressName = "三上悠亜";
			const url = this.apiUrl + actressName;
			const responseHtml = String(await gmHttp.get(url));
			const domParser = new DOMParser();
			const $parsed = $(domParser.parseFromString(responseHtml, "text/html"));
			const birthday = $parsed.find("a[title=\"誕生日\"]").parent().parent().find("td").text().trim();
			const age = $parsed.find("th:contains('現年齢')").parent().find("td").text().trim() ? parseInt($parsed.find("th:contains('現年齢')").parent().find("td").text().trim()) + "岁" : "";
			const height = $parsed.find("tr:has(a[title=\"身長\"]) td").text().trim().split(" ")[0] + "cm";
			let weight = $parsed.find("tr:has(a[title=\"体重\"]) td").text().trim().split("/")[1].trim();
			if (weight === "― kg") weight = "";
			return {
				birthday,
				age,
				height,
				weight,
				threeSizeText: $parsed.find("a[title=\"スリーサイズ\"]").closest("tr").find("td").text().replace("cm", "").trim(),
				braSize: $parsed.find("th:contains(\"ブラサイズ\")").next("td").contents().first().text().trim(),
				url
			};
		}
	};
	var API_BASE = "https://jdforrepam.com/api";
	var SIGNATURE_TIME_KEY = "jhs_review_ts";
	var SIGNATURE_VALUE_KEY = "jhs_review_sign";
	var SIGNATURE_SINGLE_KEY = "jhs_jdsignature";
	var SIGNATURE_TTL_SECONDS = 20;
	var SIGNATURE_TTL_SECONDS_V2 = 300;
	var SIGNATURE_NAMESPACE = "lpw6vgqzsp";
	var SIGNATURE_SALT = "71cf27bb3c0bcdf207b64abecddc970098c7421ee7203b9cdae54478478a199e7d5a6e1a57691123c1a931c057842fb73ba3b3c83bcd69c17ccf174081e3d8aa";
	function reBuildSignature() {
		const now = Math.floor(Date.now() / 1e3);
		if (featureFlags.upgradeSignature300s) {
			const stored = localStorage.getItem(SIGNATURE_SINGLE_KEY);
			if (stored) {
				const parts = stored.split(".");
				if (parts.length === 3 && now - parseInt(parts[0], 10) <= SIGNATURE_TTL_SECONDS_V2) return stored;
			}
			const sig = `${now}.${SIGNATURE_NAMESPACE}.${md5(`${now}${SIGNATURE_SALT}`)}`;
			localStorage.setItem(SIGNATURE_SINGLE_KEY, sig);
			return sig;
		}
		if (now - Number(localStorage.getItem(SIGNATURE_TIME_KEY) || 0) <= SIGNATURE_TTL_SECONDS) return localStorage.getItem(SIGNATURE_VALUE_KEY);
		const sig = `${now}.${SIGNATURE_NAMESPACE}.${md5(`${now}${SIGNATURE_SALT}`)}`;
		localStorage.setItem(SIGNATURE_TIME_KEY, String(now));
		localStorage.setItem(SIGNATURE_VALUE_KEY, sig);
		return sig;
	}
	function _updateImgServer(str) {
		return str.replace(/https:\/\/.*?\/rhe951l4q/g, "https://c0.jdbstatic.com");
	}
	async function fetchMovieReviews(movieId, page = 1, limit = 20) {
		const url = `${API_BASE}/v1/movies/${encodeURIComponent(movieId)}/reviews`;
		const headers = { jdSignature: await reBuildSignature() };
		return (await gmHttp.get(url, {
			page,
			sort_by: "hotly",
			limit
		}, headers)).data.reviews;
	}
	async function fetchMovieDetail(movieId) {
		const url = `${API_BASE}/v4/movies/${encodeURIComponent(movieId)}`;
		const headers = { jdSignature: await reBuildSignature() };
		const resp = await gmHttp.get(url, void 0, headers);
		if (!resp.data) failWithToast("获取视频详情失败: " + resp.message);
		const movie = resp.data.movie;
		const imgList = [];
		movie.preview_images.forEach((img) => {
			imgList.push(_updateImgServer(img.large_url));
		});
		return {
			movieId: movie.id,
			actors: movie.actors,
			duration: movie.duration,
			title: movie.origin_title,
			carNum: movie.number,
			score: movie.score,
			releaseDate: movie.release_date,
			watchedCount: movie.watched_count,
			imgList
		};
	}
	async function fetchRelatedCollections(movieId, page = 1, limit = 20) {
		const url = `${API_BASE}/v1/lists/related?movie_id=${encodeURIComponent(movieId)}&page=${page}&limit=${limit}`;
		const headers = { jdSignature: await reBuildSignature() };
		const resp = await gmHttp.get(url, void 0, headers);
		const list = [];
		resp.data.lists.forEach((item) => {
			list.push({
				relatedId: item.id,
				name: item.name,
				movieCount: item.movies_count,
				collectionCount: item.collections_count,
				viewCount: item.views_count,
				createTime: utils.formatDate(item.created_at)
			});
		});
		return list;
	}
	async function fetchPlaybackRanking(period = "daily", filterBy = "high_score") {
		const url = `${API_BASE}/v1/rankings/playback?period=${period}&filter_by=${filterBy}`;
		const headers = { jdSignature: await reBuildSignature() };
		return (await gmHttp.get(url, void 0, headers)).data.movies;
	}
	var APP_AUTH_KEY$1 = "jhs_appAuthorization";
	async function DEFAULT_REQUEST_HEADERS() {
		return {
			"user-agent": "Dart/3.5 (dart:io)",
			"accept-language": "zh-TW",
			host: "jdforrepam.com",
			authorization: "Bearer " + (localStorage.getItem(APP_AUTH_KEY$1) || ""),
			jdsignature: await reBuildSignature()
		};
	}
	async function fetchTopMovies(type = "all", typeValue = "", page = 1, limit = 40) {
		const url = `${API_BASE}/v1/movies/top?start_rank=1&type=${type}&type_value=${typeValue}&ignore_watched=false&page=${page}&limit=${limit}`;
		const headers = await DEFAULT_REQUEST_HEADERS();
		return await gmHttp.get(url, void 0, headers);
	}
	function HitShowMovieItem({ movie }) {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "item",
			id: String(movie.id),
			children: (0, import_jsx_runtime.jsxs)("a", {
				href: `/v/${movie.id}`,
				className: "box",
				title: movie.origin_title,
				children: [
					(0, import_jsx_runtime.jsx)("div", {
						className: "cover ",
						children: (0, import_jsx_runtime.jsx)("img", {
							loading: "lazy",
							src: _updateImgServer(movie.cover_url || ""),
							alt: ""
						})
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "video-title",
						children: [
							(0, import_jsx_runtime.jsx)("strong", { children: movie.number }),
							" ",
							movie.origin_title
						]
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: "score",
						id: `score_${movie.id}`
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: "meta",
						children: movie.release_date
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "tags has-addons",
						children: [
							movie.has_cnsub ? (0, import_jsx_runtime.jsx)("span", {
								className: "tag is-warning",
								children: "含中字磁鏈"
							}) : movie.magnets_count > 0 ? (0, import_jsx_runtime.jsx)("span", {
								className: "tag is-success",
								children: "含磁鏈"
							}) : (0, import_jsx_runtime.jsx)("span", {
								className: "tag is-info",
								children: "无磁鏈"
							}),
							" ",
							movie.new_magnets ? (0, import_jsx_runtime.jsx)("span", {
								className: "tag is-info",
								children: "今日新種"
							}) : null
						]
					})
				]
			})
		});
	}
	function getStarRating(score) {
		const stars = [];
		const fullStars = Math.floor(score);
		for (let i = 0; i < fullStars; i++) stars.push((0, import_jsx_runtime.jsx)("i", { className: "icon-star" }));
		for (let i = 0; i < 5 - fullStars; i++) stars.push((0, import_jsx_runtime.jsx)("i", { className: "icon-star gray" }));
		return stars;
	}
	function HitShowScore({ score, watchedCount }) {
		return (0, import_jsx_runtime.jsxs)("span", {
			className: "value",
			children: [
				(0, import_jsx_runtime.jsx)("span", {
					className: "score-stars",
					children: getStarRating(score)
				}),
				" \xA0 ",
				score,
				"分,由",
				watchedCount,
				"人評價"
			]
		});
	}
	function HitShowToolBar({ period }) {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "button-group",
			style: { marginTop: "18px" },
			children: (0, import_jsx_runtime.jsxs)("div", {
				className: "buttons has-addons",
				id: "conditionBox",
				children: [
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${period === "daily" ? "is-info" : ""}`,
						href: "/advanced_search?handlePlayback=1&period=daily",
						children: "日榜"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${period === "weekly" ? "is-info" : ""}`,
						href: "/advanced_search?handlePlayback=1&period=weekly",
						children: "周榜"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${period === "monthly" ? "is-info" : ""}`,
						href: "/advanced_search?handlePlayback=1&period=monthly",
						children: "月榜"
					})
				]
			})
		});
	}
	function RankingContainers() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", {
			className: "tool-box",
			style: { marginTop: "10px" }
		}), (0, import_jsx_runtime.jsx)("div", {
			className: "movie-list h cols-4 vcols-8",
			style: { marginTop: "10px" }
		})] });
	}
	var HitShowPlugin = class extends BasePlugin {
		contentBox = $(".section .container");
		getName() {
			return "HitShowPlugin";
		}
		async handle() {
			$("a[href*=\"rankings/playback\"]").on("click", (event) => {
				event.preventDefault();
				event.stopPropagation();
				window.location.href = "/advanced_search?handlePlayback=1&period=daily";
			});
			this.handlePlayback().then();
		}
		hookPage() {
			const titleEl = $("h2.section-title");
			titleEl.contents().first().replaceWith("热播");
			titleEl.css("marginBottom", "0");
			$(".empty-message").remove();
			$(".section .container .box").remove();
			$("#sort-toggle-btn").remove();
			this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(RankingContainers, {})));
		}
		async handlePlayback() {
			if (!window.location.href.includes("handlePlayback=1")) return;
			const period = new URLSearchParams(window.location.search).get("period");
			this.toolBar(period);
			this.hookPage();
			const movieListEl = $(".movie-list");
			movieListEl.html("");
			await withLoading(async () => {
				let success = false;
				for (let attempt = 1; attempt <= 3 && !success; attempt++) try {
					const movies = await fetchPlaybackRanking(period ?? "daily");
					const html = this.markDataListHtml(movies);
					movieListEl.html(html);
					this.loadScore(movies);
					success = true;
				} catch (error) {
					if (attempt < 3) {
						clog.error(`获取热播数据失败 (第 ${attempt} 次重试)`, error);
						await new Promise((resolve) => setTimeout(resolve, 1e3));
					} else clog.error("所有重试尝试均失败,无法获取数据。", error);
				}
			});
		}
		toolBar(period) {
			this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(HitShowToolBar, { period })));
		}
		loadScore(movies) {
			if (movies.length === 0) return;
			(async () => {
				const storageKey = "jhs_score_info";
				for (const movie of movies) try {
					const movieId = movie.id;
					if (!$(`#score_${movieId}`).length) return;
					if ($(`#${movieId}`).is(":hidden")) continue;
					const rawCache = localStorage.getItem(storageKey);
					const cache = rawCache ? JSON.parse(rawCache) : {};
					const cachedHtml = cache[movieId];
					if (cachedHtml) {
						this.appendScoreHtml(movieId, cachedHtml);
						continue;
					}
					while (!document.hasFocus()) await new Promise((resolve) => setTimeout(resolve, 500));
					const detail = await fetchMovieDetail(movieId);
					const score = detail.score;
					const watchedCount = detail.watchedCount;
					const scoreHtml = jsxToString((0, import_jsx_runtime.jsx)(HitShowScore, {
						score,
						watchedCount
					}));
					this.appendScoreHtml(movieId, scoreHtml);
					cache[movieId] = scoreHtml;
					localStorage.setItem(storageKey, JSON.stringify(cache));
					await new Promise((resolve) => setTimeout(resolve, 500));
				} catch (error) {
					clog.error(`🚨 解析评分数据失败 | 编号: ${movie.number}\n`, `错误详情: ${error instanceof Error ? error.message : String(error)}\n`, error instanceof Error && error.stack ? `调用栈:\n${error.stack}` : "");
				}
			})();
		}
		appendScoreHtml(movieId, html) {
			const scoreEl = $(`#score_${movieId}`);
			if (scoreEl.length && scoreEl.html().trim() === "") scoreEl.slideUp(0, function() {
				$(this).html(html).slideDown(500);
			});
		}
		markDataListHtml(movies) {
			let html = "";
			movies.forEach((movie) => {
				html += jsxToString((0, import_jsx_runtime.jsx)(HitShowMovieItem, { movie }));
			});
			return html;
		}
	};
	function LoginDialog() {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				padding: "30px",
				fontFamily: "'Helvetica Neue', Arial, sans-serif"
			},
			children: [
				(0, import_jsx_runtime.jsx)("div", {
					style: { marginBottom: "25px" },
					children: (0, import_jsx_runtime.jsx)("input", {
						type: "text",
						id: "username",
						name: "username",
						style: {
							width: "100%",
							padding: "12px 15px",
							border: "1px solid #e0e0e0",
							borderRadius: "4px",
							boxSizing: "border-box",
							transition: "all 0.3s",
							fontSize: "14px",
							background: "#f9f9f9",
							color: "#333"
						},
						placeholder: "用户名 | 邮箱"
					})
				}),
				(0, import_jsx_runtime.jsx)("div", {
					style: { marginBottom: "15px" },
					children: (0, import_jsx_runtime.jsx)("input", {
						type: "password",
						id: "password",
						name: "password",
						style: {
							width: "100%",
							padding: "12px 15px",
							border: "1px solid #e0e0e0",
							borderRadius: "4px",
							boxSizing: "border-box",
							transition: "all 0.3s",
							fontSize: "14px",
							background: "#f9f9f9",
							color: "#333"
						},
						placeholder: "密码"
					})
				}),
				(0, import_jsx_runtime.jsx)("button", {
					id: "loginBtn",
					style: {
						width: "100%",
						padding: "12px",
						background: "#4a8bfc",
						color: "white",
						border: "none",
						borderRadius: "4px",
						fontSize: "15px",
						cursor: "pointer",
						transition: "background 0.3s"
					},
					children: "登录"
				})
			]
		});
	}
	function Top250ErrorMessage({ message }) {
		return (0, import_jsx_runtime.jsx)("h3", { children: message });
	}
	function Top250LoadError() {
		return (0, import_jsx_runtime.jsx)("h3", { children: "无法加载数据,请稍后再试。" });
	}
	function Top250NavLink() {
		return (0, import_jsx_runtime.jsx)("a", {
			href: "/rankings/top",
			children: (0, import_jsx_runtime.jsx)("span", { children: "Top250" })
		});
	}
	function Top250Pagination({ page }) {
		const hasMore = page >= 5;
		return (0, import_jsx_runtime.jsxs)("nav", {
			className: "pagination",
			children: [
				(0, import_jsx_runtime.jsx)("a", {
					className: `pagination-previous ${page <= 1 ? "do-hide" : ""}`,
					"data-page": page - 1,
					children: "上一頁"
				}),
				(0, import_jsx_runtime.jsx)("a", {
					className: `pagination-next ${hasMore ? "do-hide" : ""}`,
					"data-page": page + 1,
					children: "下一頁"
				}),
				(0, import_jsx_runtime.jsx)("ul", {
					className: "pagination-list",
					children: Array.from({ length: 5 }, (_, i) => i + 1).map((i) => (0, import_jsx_runtime.jsx)("li", { children: (0, import_jsx_runtime.jsx)("a", {
						className: `pagination-link ${page === i ? "is-current" : ""}`,
						"data-page": i,
						children: i
					}) }, i))
				})
			]
		});
	}
	function Top250ToolBar({ handleType, typeValue, hasCnsub, yearButtonsHtml }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "button-group",
			children: [(0, import_jsx_runtime.jsxs)("div", {
				className: "buttons has-addons",
				id: "conditionBox",
				style: { marginBottom: "0!important" },
				children: [
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${handleType === "all" ? "is-info" : ""}`,
						href: `/advanced_search?handleTop=1&handleType=all&type_value=&has_cnsub=${hasCnsub}`,
						children: "全部"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${typeValue === "0" ? "is-info" : ""}`,
						href: `/advanced_search?handleTop=1&handleType=video_type&type_value=0&has_cnsub=${hasCnsub}`,
						children: "有码"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${typeValue === "1" ? "is-info" : ""}`,
						href: `/advanced_search?handleTop=1&handleType=video_type&type_value=1&has_cnsub=${hasCnsub}`,
						children: "无码"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${typeValue === "2" ? "is-info" : ""}`,
						href: `/advanced_search?handleTop=1&handleType=video_type&type_value=2&has_cnsub=${hasCnsub}`,
						children: "欧美"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${typeValue === "3" ? "is-info" : ""}`,
						href: `/advanced_search?handleTop=1&handleType=video_type&type_value=3&has_cnsub=${hasCnsub}`,
						children: "Fc2"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: {
							padding: "18px 18px !important",
							marginLeft: "50px"
						},
						className: `button is-small ${hasCnsub === "1" ? "is-info" : ""}`,
						"data-cnsub-value": "1",
						children: "含中字磁鏈"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: `button is-small ${hasCnsub === "0" ? "is-info" : ""}`,
						"data-cnsub-value": "0",
						children: "无字幕"
					}),
					" ",
					(0, import_jsx_runtime.jsx)("a", {
						style: { padding: "18px 18px !important" },
						className: "button is-small",
						"data-cnsub-value": "",
						children: "重置"
					})
				]
			}), (0, import_jsx_runtime.jsx)("div", {
				className: "buttons has-addons",
				id: "conditionBox",
				dangerouslySetInnerHTML: { __html: yearButtonsHtml }
			})]
		});
	}
	function Top250YearButton({ year, typeValue, hasCnsub }) {
		return (0, import_jsx_runtime.jsx)("a", {
			style: { padding: "18px 18px !important" },
			className: `button is-small ${typeValue === year.toString() ? "is-info" : ""}`,
			href: `/advanced_search?handleTop=1&handleType=year&type_value=${year}&has_cnsub=${hasCnsub}`,
			children: year
		});
	}
	var APP_AUTH_KEY = "jhs_appAuthorization";
	var Top250Plugin = class extends BasePlugin {
		hasCnsub = "";
		contentBox = $(".section .container");
		movies = [];
		getName() {
			return "Top250Plugin";
		}
		async handle() {
			$(".main-tabs ul li:contains(\"猜你喜歡\")").html(jsxToString((0, import_jsx_runtime.jsx)(Top250NavLink, {})));
			$("a[href*=\"rankings/top\"]").on("click", (event) => {
				event.preventDefault();
				event.stopPropagation();
				const target = $(event.target);
				const href = (target.is("a") ? target : target.closest("a")).attr("href");
				const queryString = href?.includes("?") ? href.split("?")[1] : href ?? "";
				const params = new URLSearchParams(queryString);
				this.checkLogin(event, params);
			});
			this.handleTop().then();
		}
		hookPage() {
			$("h2.section-title").contents().first().replaceWith("Top250");
			$(".empty-message").remove();
			$(".section .container .box").remove();
			$("#sort-toggle-btn").remove();
			this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(RankingContainers, {})));
			this.renderPagination();
		}
		renderPagination() {
			const params = new URLSearchParams(window.location.search);
			const page = parseInt(params.get("page") ?? "") || 1;
			this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(Top250Pagination, { page })));
			this.contentBox.on("click", ".pagination-link, .pagination-previous, .pagination-next", (event) => {
				event.preventDefault();
				const pageNum = parseInt($(event.currentTarget).data("page"));
				if (!isNaN(pageNum) && pageNum > 0) ((targetPage) => {
					params.set("page", String(targetPage));
					window.history.pushState({}, "", "?" + params.toString());
					window.location.reload();
				})(pageNum);
			});
		}
		async handleTop() {
			if (!window.location.href.includes("handleTop=1")) return;
			const params = new URLSearchParams(window.location.search);
			const handleType = params.get("handleType") || "all";
			const typeValue = params.get("type_value") || "";
			this.hasCnsub = params.get("has_cnsub") || "";
			const page = parseInt(params.get("page") ?? "") || 1;
			this.toolBar(handleType, typeValue, page);
			this.hookPage();
			const movieListEl = $(".movie-list");
			movieListEl.html("");
			await withLoading(async () => {
				let success = false;
				for (let attempt = 1; attempt <= 3 && !success; attempt++) try {
					const response = await fetchTopMovies(handleType, typeValue, page, 50);
					const successFlag = response.success;
					const message = response.message;
					const action = response.action;
					if (successFlag === 1) {
						const movies = response.data.movies;
						if (movies.length === 0) {
							show.error("无数据");
							return;
						}
						this.movies = movies;
						const filteredMovies = movies.filter((movie) => this.hasCnsub === "1" ? movie.has_cnsub : this.hasCnsub !== "0" || !movie.has_cnsub);
						const hitShowPlugin = this.getBean("HitShowPlugin");
						const html = hitShowPlugin.markDataListHtml(filteredMovies);
						movieListEl.html(html);
						hitShowPlugin.loadScore(filteredMovies);
						success = true;
					} else {
						console.error(response);
						movieListEl.html(jsxToString((0, import_jsx_runtime.jsx)(Top250ErrorMessage, { message })));
						show.error(message);
						if (action === "JWTVerificationError") {
							await localStorage.removeItem(APP_AUTH_KEY);
							await this.checkLogin(null, new URLSearchParams(window.location.search));
						}
						success = true;
					}
				} catch (error) {
					if (attempt < 3) {
						clog.error(`获取Top数据失败 (第 ${attempt} 次重试):`, error);
						await new Promise((resolve) => setTimeout(resolve, 1e3));
					} else {
						clog.error("所有重试尝试均失败,无法获取Top数据。", error);
						movieListEl.html(jsxToString((0, import_jsx_runtime.jsx)(Top250LoadError, {})));
					}
				}
			});
		}
		toolBar(handleType, typeValue, page) {
			if (page.toString() === "5") $(".pagination-next").remove();
			$(".pagination-ellipsis").closest("li").remove();
			$(".pagination-list li a").each(function() {
				if (parseInt($(this).text()) > 5) $(this).closest("li").remove();
			});
			let yearButtonsHtml = "";
			for (let year = new Date().getFullYear(); year >= 2008; year--) yearButtonsHtml += jsxToString((0, import_jsx_runtime.jsx)(Top250YearButton, {
				year,
				typeValue,
				hasCnsub: this.hasCnsub
			}));
			this.contentBox.append(jsxToString((0, import_jsx_runtime.jsx)(Top250ToolBar, {
				handleType,
				typeValue,
				hasCnsub: this.hasCnsub,
				yearButtonsHtml
			})));
			$("a[data-cnsub-value]").on("click", (event) => {
				const cnsubValue = $(event.currentTarget).data("cnsub-value");
				this.hasCnsub = cnsubValue.toString();
				$("a[data-cnsub-value]").removeClass("is-info");
				$(event.currentTarget).addClass("is-info");
				$(".toolbar a.button").not("[data-cnsub-value]").each((_index, el) => {
					const hrefEl = $(el);
					const url = new URL(hrefEl.attr("href") ?? "", window.location.origin);
					url.searchParams.set("has_cnsub", cnsubValue);
					hrefEl.attr("href", url.toString());
				});
				const filteredMovies = this.movies.filter((movie) => this.hasCnsub === "1" ? movie.has_cnsub : this.hasCnsub !== "0" || !movie.has_cnsub);
				const hitShowPlugin = this.getBean("HitShowPlugin");
				const listHtml = hitShowPlugin.markDataListHtml(filteredMovies);
				$(".movie-list").html(listHtml);
				hitShowPlugin.loadScore(filteredMovies);
			});
		}
		async checkLogin(event, params) {
			if (!localStorage.getItem(APP_AUTH_KEY)) {
				show.error("该类别依赖移动端接口,请先完成登录");
				this.openLoginDialog();
				return;
			}
			let handleType = "all";
			let typeValue = "";
			const tValue = params.get("t") || "";
			if (/^y\d+$/.test(tValue)) {
				handleType = "year";
				typeValue = tValue.substring(1);
			} else if (tValue !== "") {
				handleType = "video_type";
				typeValue = tValue;
			}
			const path = `/advanced_search?handleTop=1&handleType=${handleType}&type_value=${typeValue}`;
			if (event && (event.ctrlKey || event.metaKey)) GM_openInTab(window.location.origin + path, { insert: false });
			else window.location.href = path;
		}
		openLoginDialog() {
			layer.open({
				type: 1,
				title: "JavDB",
				closeBtn: 1,
				area: ["360px", "auto"],
				shadeClose: false,
				content: jsxToString((0, import_jsx_runtime.jsx)(LoginDialog, {})),
				success: (_layero, index) => {
					$("#username, #password").on("focus", function() {
						this.style.borderColor = "#4a8bfc";
						this.style.background = "#fff";
					}).on("blur", function() {
						this.style.borderColor = "#e0e0e0";
						this.style.background = "#f9f9f9";
					});
					$("#loginBtn").on("mouseover", function() {
						this.style.background = "#3a7be0";
					}).on("mouseout", function() {
						this.style.background = "#4a8bfc";
					});
					$("#loginBtn").click(function() {
						const username = $("#username").val();
						const password = $("#password").val();
						if (!username || !password) {
							show.error("请输入用户名和密码");
							return;
						}
						withLoading(async () => {
							const response = await (async (username, password) => {
								const url = `${API_BASE}/v1/sessions?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&device_uuid=04b9534d-5118-53de-9f87-2ddded77111e&device_name=iPhone&device_model=iPhone&platform=ios&system_version=17.4&app_version=official&app_version_number=1.9.29&app_channel=official`;
								const headers = {
									"user-agent": "Dart/3.5 (dart:io)",
									"accept-language": "zh-TW",
									"content-type": "multipart/form-data; boundary=--dio-boundary-2210433284",
									jdsignature: await reBuildSignature()
								};
								return await gmHttp.post(url, void 0, headers);
							})(username, password);
							const successFlag = response.success;
							if (successFlag === 0) show.error(response.message);
							else {
								if (successFlag !== 1) {
									clog.error("登录失败", response);
									throw new Error(response.message);
								}
								{
									const token = response.data.token;
									await localStorage.setItem(APP_AUTH_KEY, token);
									show.ok("登录成功");
									layer.close(index);
									window.location.href = "/advanced_search?handleTop=1&period=daily";
								}
							}
						}).catch((error) => {
							clog.error("登录异常:", error);
							show.error(error instanceof Error ? error.message : String(error));
						});
					});
				}
			});
		}
	};
	function NavOtherDropdown() {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "navbar-item has-dropdown is-hoverable",
			children: [(0, import_jsx_runtime.jsx)("a", {
				className: "navbar-link",
				children: "其它"
			}), (0, import_jsx_runtime.jsxs)("div", {
				className: "navbar-dropdown is-boxed",
				children: [(0, import_jsx_runtime.jsx)("a", {
					className: "navbar-item",
					href: "/feedbacks/new",
					target: "_blank",
					children: "反饍"
				}), (0, import_jsx_runtime.jsx)("a", {
					className: "navbar-item",
					rel: "nofollow noopener",
					target: "_blank",
					href: "https://theporndude.com/zh",
					children: "ThePornDude"
				})]
			})]
		});
	}
	function NavSearchBox() {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "navbar-menu",
			id: "search-box",
			children: (0, import_jsx_runtime.jsxs)("div", {
				className: "navbar-start",
				style: {
					display: "flex",
					alignItems: "center",
					gap: "5px"
				},
				children: [
					(0, import_jsx_runtime.jsxs)("select", {
						id: "search-type",
						style: {
							padding: "8px 12px",
							border: "1px solid #555",
							borderRadius: "4px",
							backgroundColor: "#333",
							color: "#eee",
							fontSize: "14px",
							outline: "none"
						},
						children: [
							(0, import_jsx_runtime.jsx)("option", {
								value: "all",
								children: "影片"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "actor",
								children: "演員"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "series",
								children: "系列"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "maker",
								children: "片商"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "director",
								children: "導演"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "code",
								children: "番號"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "list",
								children: "清單"
							})
						]
					}),
					(0, import_jsx_runtime.jsx)("input", {
						id: "search-keyword",
						type: "text",
						placeholder: "輸入影片番號,演員名等關鍵字進行檢索",
						style: {
							padding: "8px 12px",
							border: "1px solid #555",
							borderRadius: "4px",
							flexGrow: "1",
							fontSize: "14px",
							backgroundColor: "#333",
							color: "#eee",
							outline: "none"
						}
					}),
					(0, import_jsx_runtime.jsx)("a", {
						href: "/advanced_search?noFold=1",
						title: "進階檢索",
						style: {
							padding: "6px 12px",
							backgroundColor: "#444",
							borderRadius: "4px",
							textDecoration: "none",
							color: "#ddd",
							fontSize: "14px",
							border: "1px solid #555"
						},
						children: (0, import_jsx_runtime.jsx)("span", { children: "..." })
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "search-img-btn",
						title: "以图识图",
						style: {
							padding: "6px 16px",
							backgroundColor: "#444",
							color: "#fff",
							borderRadius: "4px",
							textDecoration: "none",
							fontWeight: "500",
							cursor: "pointer",
							border: "1px solid #555"
						},
						children: "识图"
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "search-btn",
						style: {
							padding: "6px 16px",
							backgroundColor: "#444",
							color: "#fff",
							borderRadius: "4px",
							textDecoration: "none",
							fontWeight: "500",
							cursor: "pointer",
							border: "1px solid #555"
						},
						children: "检索"
					})
				]
			})
		});
	}
	var nav_bar_plugin_default = ".highlight-red {\n    /* 核心要求:高亮红色文本 */\n    color: red !important;\n\n    /* 建议:增加字体加粗,效果更明显 */\n    font-weight: bold;\n\n    /* 建议:增加背景色,效果更突出 */\n\n    /* background-color: yellow; */\n}\n";
	var NavBarPlugin = class extends BasePlugin {
		getName() {
			return "NavBarPlugin";
		}
		async initCss() {
			return nav_bar_plugin_default;
		}
		async handle() {
			this.mergeNav();
			this.hookSearch();
			this.hookOldSearch();
			this.toggleOtherNavItem();
			$(window).resize(this.toggleOtherNavItem);
			if (window.location.href.includes("/search")) {
				const params = new URLSearchParams(window.location.search);
				const keyword = params.get("q");
				const searchType = params.get("f");
				$("#search-keyword").val(keyword ?? "");
				if (searchType) $("#search-type").val(searchType);
				if (keyword) this.highlightKeyword(keyword);
			}
		}
		highlightKeyword(keyword) {
			const trimmed = keyword.trim();
			if (!trimmed) return;
			const lower = trimmed.toLowerCase();
			$(".video-title strong, .actor-box strong").each(function() {
				const el = $(this);
				if (el.text().toLowerCase().includes(lower)) el.addClass("highlight-red");
			});
		}
		hookSearch() {
			$("#navbar-menu-hero").after(jsxToString((0, import_jsx_runtime.jsx)(NavSearchBox, {})));
			const $keyword = $("#search-keyword");
			if (!featureFlags.navBarNoPaste) $keyword.on("paste", (event) => {
				const items = event.originalEvent.clipboardData.items;
				for (let index = 0; index < items.length; index++) if (items[index].type.indexOf("image") !== -1) return;
				setTimeout(() => {
					$("#search-btn").click();
				}, 0);
			});
			$keyword.on("keypress", (event) => {
				if (event.key === "Enter") setTimeout(() => {
					$("#search-btn").click();
				}, 0);
			});
			$("#search-btn").on("click", (_event) => {
				const keyword = String($("#search-keyword").val() ?? "");
				const searchType = String($("#search-type option:selected").val() ?? "");
				if (keyword !== "") if (window.location.href.includes("/search")) window.location.href = "/search?q=" + encodeURIComponent(keyword) + "&f=" + encodeURIComponent(searchType);
				else window.open("/search?q=" + encodeURIComponent(keyword) + "&f=" + encodeURIComponent(searchType), "_blank", "noopener,noreferrer");
			});
			if (featureFlags.imageRecognitionPlugin) $("#search-img-btn").on("click", (e) => {
				e.preventDefault();
				this.getBean("ImageRecognitionPlugin")?.open?.();
			});
			else $("#search-img-btn").hide();
		}
		hookOldSearch() {
			const searchImageEl = document.querySelector(".search-image");
			if (!searchImageEl) return;
			const clonedEl = searchImageEl.cloneNode(true);
			searchImageEl.parentNode.replaceChild(clonedEl, searchImageEl);
			$("#button-search-image").attr("data-tooltip", "以图识图");
			if (featureFlags.imageRecognitionPlugin) $(".search-image").on("click", (event) => {
				event.preventDefault();
				event.stopPropagation();
				this.getBean("ImageRecognitionPlugin")?.open?.();
			});
		}
		mergeNav() {
			$("a[href*=\"/feedbacks/new\"]").remove();
			$("a[href*=\"theporndude.com\"]").remove();
			$("a.navbar-link[href=\"/makers\"]").parent().after(jsxToString((0, import_jsx_runtime.jsx)(NavOtherDropdown, {})));
		}
		toggleOtherNavItem() {
			const searchBox = $("#search-box");
			const searchBarContainer = $("#search-bar-container");
			if (($(window).width() ?? 0) > 1023) {
				searchBox.show();
				searchBarContainer.hide();
			}
		}
	};
	var AsyncTaskQueue = class {
		concurrency;
		running = 0;
		pending = [];
		idleWaiters = [];
		constructor(concurrency = 1) {
			this.concurrency = Math.max(1, Math.floor(Number(concurrency)) || 1);
		}
		setConcurrency(concurrency) {
			this.concurrency = Math.max(1, Math.floor(Number(concurrency)) || 1);
			this.pump();
		}
		getConcurrency() {
			return this.concurrency;
		}
		addTask(task) {
			this.pending.push(task);
			this.pump();
		}
		async waitAllFinished() {
			if (this.running === 0 && this.pending.length === 0) return;
			return new Promise((resolve) => {
				this.idleWaiters.push(resolve);
				this.pump();
			});
		}
		pump() {
			while (this.running < this.concurrency && this.pending.length > 0) {
				const task = this.pending.shift();
				this.running++;
				Promise.resolve().then(() => task()).catch((err) => {
					clog.error("执行异步队列任务失败:", err);
				}).finally(() => {
					this.running--;
					this.pump();
					this.notifyIdle();
				});
			}
			this.notifyIdle();
		}
		notifyIdle() {
			if (this.running !== 0 || this.pending.length !== 0) return;
			const waiters = this.idleWaiters.splice(0);
			for (const w of waiters) w();
		}
	};
	var TaskSupervisor = class {
		controller = new AbortController();
		entries = [];
		_aborted = false;
		get aborted() {
			return this._aborted;
		}
		get signal() {
			return this.controller.signal;
		}
		setTimeout(fn, ms) {
			if (this._aborted) return -1;
			const id = window.setTimeout(() => {
				this.removeEntry(id, "timer");
				fn();
			}, ms);
			this.entries.push({
				type: "timer",
				cleanup: () => window.clearTimeout(id)
			});
			return id;
		}
		setInterval(fn, ms) {
			if (this._aborted) return -1;
			const id = window.setInterval(fn, ms);
			this.entries.push({
				type: "interval",
				cleanup: () => window.clearInterval(id)
			});
			return id;
		}
		observe(target, callback, options) {
			const observer = new MutationObserver(callback);
			if (!this._aborted) observer.observe(target, options);
			this.entries.push({
				type: "observer",
				cleanup: () => observer.disconnect()
			});
			return observer;
		}
		addEventListener(target, type, listener, options) {
			if (this._aborted) return;
			const opts = {
				...options,
				signal: this.controller.signal
			};
			target.addEventListener(type, listener, opts);
			this.entries.push({
				type: "listener",
				cleanup: () => target.removeEventListener(type, listener, options)
			});
		}
		abort() {
			if (this._aborted) return;
			this._aborted = true;
			this.controller.abort();
			for (const entry of this.entries) try {
				entry.cleanup();
			} catch {}
			this.entries.length = 0;
		}
		removeEntry(id, type) {
			const index = this.entries.findIndex((e) => e.type === type && e.cleanup.toString().includes(String(id)));
			if (index !== -1) this.entries.splice(index, 1);
		}
	};
	var ENABLED_SITES_KEY = "jhs_enabled_sites";
	function getEnabledSites(plugin) {
		const stored = localStorage.getItem(ENABLED_SITES_KEY);
		if (stored) try {
			return JSON.parse(stored);
		} catch {}
		return plugin.siteConfigs.map((siteConfig) => siteConfig.id);
	}
	function saveEnabledSites(siteIds) {
		localStorage.setItem(ENABLED_SITES_KEY, JSON.stringify(siteIds));
	}
	var PRELOAD_CACHE_MAX = 5e3;
	function evictStaleCache(cache) {
		const keys = Object.keys(cache);
		if (keys.length > 5e3) {
			const tsOf = (k) => {
				return cache[k]?.ts ?? 0;
			};
			const sorted = keys.filter((k) => tsOf(k) !== 0).sort((a, b) => tsOf(a) - tsOf(b));
			const toRemove = [...keys.filter((k) => tsOf(k) === 0), ...sorted].slice(0, keys.length - PRELOAD_CACHE_MAX);
			for (const k of toRemove) delete cache[k];
		}
	}
	function isCacheEntryValid(entry, preloadCacheTTLDays) {
		if (!entry) return false;
		if (!preloadCacheTTLDays) return true;
		const ts = entry.ts;
		if (!ts) return true;
		return Date.now() - ts < preloadCacheTTLDays * 864e5;
	}
	function buildBrowserNavHeaders(baseUrl) {
		let origin;
		try {
			origin = new URL(baseUrl).origin;
		} catch {
			origin = baseUrl.replace(/\/[^/]*$/, "");
		}
		return {
			"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
			"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
			"Referer": origin + "/",
			"Sec-Fetch-Dest": "document",
			"Sec-Fetch-Mode": "navigate",
			"Sec-Fetch-Site": "same-origin",
			"Sec-Fetch-User": "?1",
			"Upgrade-Insecure-Requests": "1"
		};
	}
	function getItemPreloadStatus(item) {
		const badge = item.querySelector(".jhs-preload-status .jhs-ps-badge");
		if (!badge) return "none";
		for (const key of [
			"queued",
			"requesting",
			"success",
			"failed"
		]) if (badge.classList.contains(`jhs-ps-${key}`)) return key;
		return "none";
	}
	var PRELOAD_CHIPS = [
		{
			value: "queued",
			label: "排队中"
		},
		{
			value: "requesting",
			label: "请求中"
		},
		{
			value: "success",
			label: "成功匹配"
		},
		{
			value: "failed",
			label: "匹配失败"
		}
	];
	var PRELOAD_HIDDEN_ATTR = "data-preload-hidden";
	var OTHER_HIDDEN_ATTRS = [
		"data-hide",
		"data-lrs-hidden",
		"data-status-tag-hidden",
		"data-video-lists-tag-hidden"
	];
	function initFilterBar(plugin) {
		if (!plugin.preloadStatusEnabled) return;
		if (tryBuildFilterBar(plugin)) return;
		let retries = 0;
		plugin.filterBarObserver = plugin.supervisor.observe(document.body, () => {
			if (document.querySelector(".preload-filter-bar")) {
				plugin.filterBarObserver?.disconnect();
				plugin.filterBarObserver = null;
				return;
			}
			if (tryBuildFilterBar(plugin) || ++retries > 50) {
				plugin.filterBarObserver?.disconnect();
				plugin.filterBarObserver = null;
			}
		}, {
			childList: true,
			subtree: true
		});
		plugin.supervisor.setTimeout(() => {
			plugin.filterBarObserver?.disconnect();
			plugin.filterBarObserver = null;
		}, 1e4);
	}
	function tryBuildFilterBar(plugin) {
		if (document.querySelector(".preload-filter-bar")) return true;
		const target = findFilterMountTarget();
		if (!target) return false;
		buildFilterBar$1(plugin, target);
		return true;
	}
	function findFilterMountTarget() {
		const stf = document.querySelector(".status-tag-filter-bar");
		if (stf) return stf;
		const vlt = document.querySelector(".jhs-vlt-filter-bar");
		if (vlt) return vlt;
		if (/^\/actors\//.test(window.location.pathname)) {
			const actorTags = document.querySelector("body > section > div > div.actor-tags.tags");
			if (actorTags) return actorTags;
		} else {
			const tabsBoxed = document.querySelector("body > section > div > div.tabs.is-boxed");
			if (tabsBoxed) return tabsBoxed;
		}
		const section = document.querySelector("body > section > div > div");
		if (section && section.firstElementChild) {
			if (!section.firstElementChild.matches(".preload-filter-bar, .status-tag-filter-bar, .jhs-vlt-filter-bar")) return section.firstElementChild;
		}
		const container = document.querySelector("body > section > div");
		if (container && container.firstElementChild) {
			if (!container.firstElementChild.matches(".preload-filter-bar, .status-tag-filter-bar, .jhs-vlt-filter-bar")) return container.firstElementChild;
		}
		return null;
	}
	function buildFilterBar$1(_plugin, mountTarget) {
		const bar = document.createElement("div");
		bar.className = "preload-filter-bar";
		const label = document.createElement("span");
		label.className = "preload-filter-label";
		label.textContent = "预加载:";
		bar.appendChild(label);
		const chipsContainer = document.createElement("div");
		chipsContainer.className = "preload-filter-chips";
		bar.appendChild(chipsContainer);
		const refreshChips = () => {
			const activeValues = new Set(Array.from(chipsContainer.querySelectorAll(".preload-filter-chip.active")).map((c) => c.dataset.value || ""));
			chipsContainer.innerHTML = "";
			const counts = collectPreloadCounts();
			for (const chip of PRELOAD_CHIPS) {
				const el = document.createElement("span");
				el.className = "preload-filter-chip";
				el.dataset.value = chip.value;
				const dot = document.createElement("span");
				dot.className = "pf-dot";
				el.appendChild(dot);
				el.appendChild(document.createTextNode(`${chip.label} ${counts[chip.value] ?? 0}`));
				if (activeValues.has(chip.value)) el.classList.add("active");
				el.addEventListener("click", () => {
					el.classList.toggle("active");
					applyPreloadFilter();
				});
				chipsContainer.appendChild(el);
			}
		};
		refreshChips();
		if (mountTarget.matches(".status-tag-filter-bar, .jhs-vlt-filter-bar, .actor-tags.tags, .tabs.is-boxed")) mountTarget.insertAdjacentElement("afterend", bar);
		else mountTarget.insertAdjacentElement("beforebegin", bar);
		bar._refreshChips = refreshChips;
	}
	function collectPreloadCounts() {
		const counts = {
			queued: 0,
			requesting: 0,
			success: 0,
			failed: 0
		};
		document.querySelectorAll(".movie-list .item").forEach((item) => {
			if (OTHER_HIDDEN_ATTRS.some((a) => item.hasAttribute(a))) return;
			const st = getItemPreloadStatus(item);
			if (st in counts) counts[st]++;
		});
		return counts;
	}
	function applyPreloadFilter() {
		const activeChips = document.querySelectorAll(".preload-filter-chip.active");
		const selected = new Set(Array.from(activeChips).map((c) => c.dataset.value || ""));
		const HIDDEN = PRELOAD_HIDDEN_ATTR;
		if (selected.size === 0) {
			document.querySelectorAll(`.item[${HIDDEN}]`).forEach((item) => {
				const el = item;
				if (OTHER_HIDDEN_ATTRS.some((a) => el.hasAttribute(a))) return;
				el.removeAttribute(HIDDEN);
				el.style.display = "";
			});
			return;
		}
		document.querySelectorAll(".movie-list .item").forEach((item) => {
			const el = item;
			if (OTHER_HIDDEN_ATTRS.some((a) => el.hasAttribute(a))) return;
			if (el.style.display === "none" && !el.hasAttribute(HIDDEN)) return;
			const st = getItemPreloadStatus(el);
			if (selected.has(st)) {
				el.removeAttribute(HIDDEN);
				el.style.display = "";
			} else {
				el.setAttribute(HIDDEN, "");
				el.style.display = "none";
			}
		});
	}
	function refreshFilterBar(plugin) {
		if (!plugin.preloadStatusEnabled) return;
		clearTimeout(plugin.filterRefreshDebounce);
		plugin.filterRefreshDebounce = plugin.supervisor.setTimeout(() => {
			const bar = document.querySelector(".preload-filter-bar");
			if (bar && bar._refreshChips) {
				bar._refreshChips();
				applyPreloadFilter();
			}
		}, 150);
	}
	function ensureFilterBar(plugin) {
		if (!plugin.preloadStatusEnabled) return;
		if (!document.querySelector(".preload-filter-bar")) tryBuildFilterBar(plugin);
		const bar = document.querySelector(".preload-filter-bar");
		if (!bar) return;
		const stf = document.querySelector(".status-tag-filter-bar");
		if (stf && bar.previousElementSibling !== stf) {
			stf.insertAdjacentElement("afterend", bar);
			refreshFilterBar(plugin);
			return;
		}
		const vlt = document.querySelector(".jhs-vlt-filter-bar");
		if (!stf && vlt && bar.previousElementSibling !== vlt) {
			vlt.insertAdjacentElement("afterend", bar);
			refreshFilterBar(plugin);
		}
	}
	var PRELOAD_STATUS_MAP = {
		queued: {
			cls: "jhs-ps-queued",
			text: "排队中"
		},
		requesting: {
			cls: "jhs-ps-requesting",
			text: "请求中"
		},
		success: {
			cls: "jhs-ps-success",
			text: "成功匹配"
		},
		failed: {
			cls: "jhs-ps-failed",
			text: "匹配失败"
		}
	};
	function PreloadStatusBar() {
		return (0, import_jsx_runtime.jsx)("div", { className: "jhs-preload-status-bar" });
	}
	function PreloadStatusBadge({ siteId, siteName, status }) {
		const { cls, text } = PRELOAD_STATUS_MAP[status];
		return (0, import_jsx_runtime.jsxs)("span", {
			className: "jhs-preload-status",
			"data-site-id": siteId,
			children: [(0, import_jsx_runtime.jsx)("span", {
				className: "jhs-ps-name",
				children: siteName
			}), (0, import_jsx_runtime.jsx)("span", {
				className: `jhs-ps-badge ${cls}`,
				children: text
			})]
		});
	}
	var PRELOAD_LOG = "[OtherSite 预加载]";
	async function preloadListPage(plugin) {
		if (await storageManager.getSetting("enableLoadOtherSite", "yes") !== "yes") {
			console.log(`${PRELOAD_LOG} 已禁用,跳过预加载`);
			return;
		}
		const listPagePlugin = plugin.getBean("ListPagePlugin");
		if (!listPagePlugin) {
			console.log(`${PRELOAD_LOG} ListPagePlugin 未就绪,跳过`);
			return;
		}
		const enabledSiteIds = getEnabledSites(plugin);
		const $items = $(".movie-list .item");
		if ($items.length === 0) {
			console.log(`${PRELOAD_LOG} 无 .item,跳过`);
			return;
		}
		const storageKey = "jhs_other_site";
		let cache = {};
		try {
			const raw = localStorage.getItem(storageKey);
			if (raw) cache = JSON.parse(raw);
		} catch {}
		let cachedCount = 0;
		let skippedHiddenCount = 0;
		let preloadCount = 0;
		$items.each((_index, itemEl) => {
			const $item = $(itemEl);
			if ($item.attr("data-hide") === "yes") {
				skippedHiddenCount++;
				return;
			}
			let carNum;
			try {
				carNum = listPagePlugin.findCarNumAndHref($item).carNum;
			} catch {
				return;
			}
			if (!carNum) return;
			for (const siteConfig of plugin.siteConfigs) {
				if (!enabledSiteIds.includes(siteConfig.id)) continue;
				if (siteConfig.condition && siteConfig.condition(siteConfig.sourceCarNum) === false) continue;
				if (plugin.blockedSiteIds.has(siteConfig.id)) continue;
				if (siteConfig.initUrl) continue;
				const cacheKey = carNum + "_" + siteConfig.id.replace("Btn", "");
				if (isCacheEntryValid(cache[cacheKey], plugin.preloadCacheTTLDays)) {
					cachedCount++;
					continue;
				}
				updatePreloadStatus(plugin, $item, siteConfig.id, "queued");
				plugin.preloadQueue.addTask(async () => {
					if (plugin.blockedSiteIds.has(siteConfig.id)) {
						updatePreloadStatus(plugin, $item, siteConfig.id, "failed");
						return;
					}
					updatePreloadStatus(plugin, $item, siteConfig.id, "requesting");
					await preloadSite(plugin, carNum, siteConfig, $item);
				});
				preloadCount++;
			}
		});
		console.log(`${PRELOAD_LOG} ${$items.length} 个 item(屏蔽 ${skippedHiddenCount})| 已缓存 ${cachedCount} | 入队 ${preloadCount} 个任务` + (plugin.blockedSiteIds.size > 0 ? ` | 被拦截站点: ${[...plugin.blockedSiteIds].map((id) => id.replace("Btn", "")).join(", ")}` : ""));
	}
	async function preloadSite(plugin, carNum, siteConfig, $item) {
		const dedupeKey = `${carNum}_${siteConfig.id}`;
		const existing = plugin.inflightPreloads.get(dedupeKey);
		if (existing) return existing;
		const promise = doPreloadSite(plugin, carNum, siteConfig, $item);
		plugin.inflightPreloads.set(dedupeKey, promise);
		try {
			await promise;
		} finally {
			plugin.inflightPreloads.delete(dedupeKey);
		}
	}
	async function doPreloadSite(plugin, carNum, siteConfig, $item) {
		try {
			const baseUrl = await siteConfig.getBaseUrl();
			const searchUrl = siteConfig.searchPath(baseUrl, carNum);
			const htmlContent = await gmHttp.get(searchUrl, void 0, {
				...buildBrowserNavHeaders(baseUrl),
				...siteConfig.headers
			}, true);
			const $dom = utils.htmlTo$dom(String(htmlContent));
			const bodyText = $dom.text() || "";
			const titleText = $dom.find("title").text() || "";
			if ($dom.find("form[action*=\"login\"], form[action*=\"signin\"], input[type=\"password\"]").length > 0 || /登录|登陆|登入|sign\s*in|log\s*in/i.test(titleText) || bodyText.includes("登入你的帳戶") || bodyText.includes("註冊一個新帳戶")) {
				updatePreloadStatus(plugin, $item, siteConfig.id, "failed");
				console.warn(`${PRELOAD_LOG} ⚠ ${siteConfig.id.replace("Btn", "")} 搜索页需要登录,跳过预加载`);
				return;
			}
			const detailHrefs = [];
			$dom.find(siteConfig.itemSelector).each((_index, element) => {
				const itemEl = $(element);
				if (!siteConfig.findCarNumOrTitle(itemEl).toLowerCase().includes(carNum.toLowerCase())) return;
				let href = siteConfig.getDetailPageHref(itemEl, baseUrl, carNum);
				if (!href) throw new Error("解析href失败");
				if (!href.includes("http")) href = baseUrl + (href.startsWith("/") ? href : "/" + href);
				detailHrefs.push(href);
			});
			let resultData = null;
			if (detailHrefs.length === 1) resultData = {
				type: "single",
				url: detailHrefs[0]
			};
			else if (detailHrefs.length > 1) resultData = {
				type: "multiple",
				url: searchUrl
			};
			if (resultData) {
				updatePreloadStatus(plugin, $item, siteConfig.id, "success");
				const storageKey = "jhs_other_site";
				let cache = {};
				try {
					const raw = localStorage.getItem(storageKey);
					if (raw) cache = JSON.parse(raw);
				} catch {}
				const cacheKey = carNum + "_" + siteConfig.id.replace("Btn", "");
				cache[cacheKey] = {
					...resultData,
					ts: Date.now()
				};
				evictStaleCache(cache);
				localStorage.setItem(storageKey, JSON.stringify(cache));
				console.log(`${PRELOAD_LOG} ✓ ${carNum} ${siteConfig.id.replace("Btn", "")} ${resultData.type === "single" ? "命中" : "多结果"}`);
			} else {
				updatePreloadStatus(plugin, $item, siteConfig.id, "failed");
				console.log(`${PRELOAD_LOG} ✗ ${carNum} ${siteConfig.id.replace("Btn", "")} 未命中`);
			}
		} catch (error) {
			const siteName = siteConfig.id.replace("Btn", "");
			const errorMsg = String(error);
			if (errorMsg.includes("Just a moment") || errorMsg.includes("403")) {
				plugin.blockedSiteIds.add(siteConfig.id);
				updatePreloadStatus(plugin, $item, siteConfig.id, "failed");
				console.warn(`${PRELOAD_LOG} ⚠ ${siteName} 被 Cloudflare 拦截,跳过本轮剩余任务`);
				return;
			}
			if (errorMsg.includes("重定向")) {
				updatePreloadStatus(plugin, $item, siteConfig.id, "failed");
				console.warn(`${PRELOAD_LOG} ⚠ ${siteName} 域名失效(被重定向): ${errorMsg.slice(0, 60)}`);
				return;
			}
			updatePreloadStatus(plugin, $item, siteConfig.id, "failed");
			console.warn(`${PRELOAD_LOG} ✗ ${carNum} ${siteName} 失败: ${errorMsg.slice(0, 60)}`);
		}
	}
	function updatePreloadStatus(plugin, $item, siteId, status) {
		if (!plugin.preloadStatusEnabled) return;
		const $videoTitle = $item.find(".video-title").first();
		if ($videoTitle.length === 0) return;
		if ($item.find(".jhs-preload-status-bar").length === 0) $videoTitle.after(jsxToString((0, import_jsx_runtime.jsx)(PreloadStatusBar, {})));
		const $bar = $item.find(".jhs-preload-status-bar");
		const $badge = $bar.find(`[data-site-id="${siteId}"]`);
		if ($badge.length === 0) {
			$bar.append(jsxToString((0, import_jsx_runtime.jsx)(PreloadStatusBadge, {
				siteId,
				siteName: siteId.replace("Btn", ""),
				status
			})));
			return;
		}
		const { cls, text } = PRELOAD_STATUS_MAP[status];
		$badge.find(".jhs-ps-badge").attr("class", `jhs-ps-badge ${cls}`).text(text);
		refreshFilterBar(plugin);
	}
	function getPreloadableSites(plugin) {
		const enabled = getEnabledSites(plugin);
		return plugin.siteConfigs.filter((s) => enabled.includes(s.id) && !s.initUrl);
	}
	function syncAllBadges(plugin) {
		if (!plugin.preloadStatusEnabled) return;
		const listPagePlugin = plugin.getBean("ListPagePlugin");
		if (!listPagePlugin) return;
		const sites = getPreloadableSites(plugin);
		if (sites.length === 0) return;
		let cache = {};
		try {
			const raw = localStorage.getItem("jhs_other_site");
			if (raw) cache = JSON.parse(raw);
		} catch {}
		$(".movie-list .item").each((_index, el) => {
			const $item = $(el);
			if ($item.attr("data-hide") === "yes") return;
			let carNum;
			try {
				carNum = listPagePlugin.findCarNumAndHref($item).carNum;
			} catch {
				return;
			}
			if (!carNum) return;
			for (const site of sites) {
				const cacheKey = carNum + "_" + site.id.replace("Btn", "");
				if (isCacheEntryValid(cache[cacheKey], plugin.preloadCacheTTLDays)) {
					const $badge = $item.find(`[data-site-id="${site.id}"] .jhs-ps-badge`);
					if (!$badge.length || !$badge.hasClass("jhs-ps-success")) updatePreloadStatus(plugin, $item, site.id, "success");
				} else if (!$item.find(`[data-site-id="${site.id}"]`).length) updatePreloadStatus(plugin, $item, site.id, "queued");
			}
		});
	}
	function startPreloadObserver(plugin) {
		const containerEl = document.querySelector(".movie-list");
		if (!containerEl) return;
		plugin.supervisor.observe(containerEl, () => {
			syncAllBadges(plugin);
			ensureFilterBar(plugin);
			refreshFilterBar(plugin);
			clearTimeout(plugin.preloadDebounce);
			plugin.preloadDebounce = plugin.supervisor.setTimeout(() => {
				preloadListPage(plugin).then();
			}, plugin.preloadDebounceMs);
		}, { childList: true });
	}
	function SiteResultTag() {
		return (0, import_jsx_runtime.jsx)("span", {
			className: "site-tag",
			style: { top: "-15px" },
			children: "多结果"
		});
	}
	async function probeSite(plugin, carNum, siteConfig) {
		const buttonEl = $(`#${siteConfig.id}`);
		if (siteConfig.initUrl) {
			buttonEl.attr("href", await siteConfig.initUrl(carNum));
			buttonEl.css("backgroundColor", plugin.warnBackgroundColor);
		}
		if (siteConfig.noHandle && siteConfig.noHandle === true) {
			const dmmStorageKey = "jhs_other_site_dmm";
			let dmmCache = {};
			try {
				const raw = localStorage.getItem(dmmStorageKey);
				if (raw) dmmCache = JSON.parse(raw);
			} catch {}
			const dmmCachedResult = dmmCache[carNum];
			if (dmmCachedResult) {
				if (dmmCachedResult.type === "single") {
					buttonEl.attr("href", dmmCachedResult.url);
					buttonEl.css("backgroundColor", plugin.okBackgroundColor);
				} else if (dmmCachedResult.type === "multiple") {
					buttonEl.attr("href", dmmCachedResult.url);
					buttonEl.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
					buttonEl.css("backgroundColor", plugin.okBackgroundColor);
				}
			}
		} else try {
			if (buttonEl.attr("href")) return;
			if (utils.isHidden(buttonEl)) return;
			const storageKey = "jhs_other_site";
			let cache = {};
			try {
				const raw = localStorage.getItem(storageKey);
				if (raw) cache = JSON.parse(raw);
			} catch {}
			const cacheKey = carNum + "_" + siteConfig.id.replace("Btn", "");
			const cachedResult = cache[cacheKey];
			if (isCacheEntryValid(cachedResult, plugin.preloadCacheTTLDays)) {
				if (cachedResult.type === "single") {
					buttonEl.attr("href", cachedResult.url);
					buttonEl.css("backgroundColor", plugin.okBackgroundColor);
				} else if (cachedResult.type === "multiple") {
					buttonEl.attr("href", cachedResult.url);
					buttonEl.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
					buttonEl.css("backgroundColor", plugin.okBackgroundColor);
				}
				return;
			}
			const baseUrl = await siteConfig.getBaseUrl();
			const searchUrl = siteConfig.searchPath(baseUrl, carNum);
			buttonEl.attr("href", searchUrl);
			const htmlContent = await gmHttp.get(searchUrl, void 0, {
				...buildBrowserNavHeaders(baseUrl),
				...siteConfig.headers
			}, true);
			const $dom = utils.htmlTo$dom(String(htmlContent));
			const siteName = siteConfig.id.replace("Btn", "");
			const bodyText = $dom.text() || "";
			if (bodyText.includes("登入你的帳戶") || bodyText.includes("登录") || bodyText.includes("註冊一個新帳戶") || bodyText.includes("登入你的帳戶")) {
				buttonEl.attr("title", "请求失败:搜索页需要登录");
				buttonEl.css("backgroundColor", plugin.warnBackgroundColor);
				clog.warn(`检测第三方资源失败, ${siteName} 搜索页需要登录`);
				return;
			}
			if ($dom.find("form[action*=\"login\"], form[action*=\"signin\"], form[id*=\"login\"], input[name*=\"password\"], input[type=\"password\"]").length > 0 || /\u767b\u5f55|\u767b\u9646|\u767b\u5165|sign\s*in|log\s*in/i.test($dom.text())) {
				buttonEl.attr("title", "该站点需登录后才能搜索");
				buttonEl.css("backgroundColor", plugin.warnBackgroundColor);
				clog.warn(`检测到登录页,跳过 ${siteConfig.id.replace("Btn", "")}`);
				return;
			}
			const detailHrefs = [];
			$dom.find(siteConfig.itemSelector).each((_index, element) => {
				const itemEl = $(element);
				if (!siteConfig.findCarNumOrTitle(itemEl).toLowerCase().includes(carNum.toLowerCase())) return;
				let href = siteConfig.getDetailPageHref(itemEl, baseUrl, carNum);
				if (!href) throw new Error("解析href失败");
				if (!href.includes("http")) href = baseUrl + (href.startsWith("/") ? href : "/" + href);
				detailHrefs.push(href);
			});
			let tagHtml = "";
			let resultData = null;
			if (detailHrefs.length === 1) {
				const detailHref = detailHrefs[0];
				buttonEl.attr("href", detailHref);
				buttonEl.css("backgroundColor", plugin.okBackgroundColor);
				resultData = {
					type: "single",
					url: detailHref
				};
			} else if (detailHrefs.length > 1) {
				buttonEl.attr("href", searchUrl);
				tagHtml += jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {}));
				buttonEl.css("backgroundColor", plugin.okBackgroundColor);
				resultData = {
					type: "multiple",
					url: searchUrl
				};
			} else {
				buttonEl.attr("href", searchUrl);
				buttonEl.attr("title", "未查询到, 点击前往搜索页");
				buttonEl.css("backgroundColor", plugin.errorBackgroundColor);
			}
			if (resultData) new AsyncTaskQueue().addTask(() => {
				let cache = {};
				try {
					const raw = localStorage.getItem(storageKey);
					if (raw) cache = JSON.parse(raw);
				} catch {}
				cache[cacheKey] = {
					...resultData,
					ts: Date.now()
				};
				evictStaleCache(cache);
				localStorage.setItem(storageKey, JSON.stringify(cache));
			});
			if (tagHtml) buttonEl.append(tagHtml);
		} catch (error) {
			const errorMsg = String(error);
			const siteName = siteConfig.id.replace("Btn", "");
			if (errorMsg.includes("Just a moment")) {
				buttonEl.attr("title", "请求失败:Cloudflare 安全检查。");
				buttonEl.css("backgroundColor", plugin.warnBackgroundColor);
				clog.warn(`检测第三方资源失败, ${siteName} 需Cloudflare安全检查`);
			} else if (errorMsg.includes("重定向")) {
				buttonEl.attr("title", "域名失效");
				buttonEl.css("backgroundColor", plugin.domainErrorBackgroundColor);
				clog.warn(`检测第三方资源失败, ${siteName} 域名被重定向`);
			} else if (errorMsg.includes("404 Page Not Found")) {
				buttonEl.attr("title", "未查询到, 点击前往搜索页");
				buttonEl.css("backgroundColor", plugin.errorBackgroundColor);
			} else {
				clog.error(error);
				buttonEl.attr("title", "请求失败。");
				buttonEl.css("backgroundColor", plugin.errorBackgroundColor);
				clog.warn(`检测第三方资源失败, ${siteName}`);
			}
		}
	}
	function OtherSiteBox({ siteButtonsHtml, isJavdbSite }) {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "otherSiteBox",
			className: "panel-block",
			style: {
				marginTop: isJavdbSite ? "8px" : "10px",
				fontSize: "13px",
				userSelect: "none"
			},
			children: (0, import_jsx_runtime.jsx)("div", {
				style: {
					display: "flex",
					gap: "5px",
					flexWrap: "wrap"
				},
				dangerouslySetInnerHTML: { __html: siteButtonsHtml }
			})
		});
	}
	function OtherSiteBtn({ id, enabled }) {
		return (0, import_jsx_runtime.jsx)("a", {
			target: "_blank",
			className: "site-btn",
			style: enabled ? void 0 : { display: "none" },
			id,
			children: (0, import_jsx_runtime.jsx)("span", { children: id.replace("Btn", "") })
		});
	}
	function OtherSiteCheckbox({ id, isEnabled, isJavdbSite }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				marginRight: "15px",
				display: "flex",
				alignItems: isJavdbSite ? "center" : "flex-start"
			},
			children: [(0, import_jsx_runtime.jsx)("input", {
				type: "checkbox",
				id: `checkbox-${id}`,
				"data-site-id": id,
				checked: isEnabled,
				style: {
					marginRight: "8px",
					cursor: "pointer"
				}
			}), (0, import_jsx_runtime.jsx)("label", {
				for: `checkbox-${id}`,
				style: {
					color: "#333",
					fontWeight: "500",
					cursor: "pointer"
				},
				children: id.replace("Btn", "")
			})]
		});
	}
	var other_site_plugin_default = ".site-btn {\n    position: relative !important;\n    min-width: 80px;\n    display: inline-block;\n    padding: 5px 10px;\n    color: white !important;\n    background-color: #938585;\n    text-decoration: none;\n    border-radius: 4px;\n    text-align: center;\n    margin-bottom: 5px;\n}\n\n.site-btn:hover {\n    color: white;\n    transform: translateY(-2px);\n    box-shadow: 0 2px 5px rgb(0, 0, 0, 0.1);\n}\n\n.site-tag {\n    position: absolute;\n    top: -15px;\n    right: 0;\n    background-color: #ffc107;\n    color: #333;\n    font-size: 12px;\n    padding: 2px 6px;\n    border-radius: 4px;\n}\n";
	var preload_status_badge_default = "/**\n * 预加载状态徽标 + 筛选栏样式(OtherSitePlugin 列表页预加载实时状态)。\n *\n * 两部分:\n * 1. .jhs-preload-status-bar / .jhs-preload-status —— .item 卡片内 .video-title\n *    下方每站点状态徽标(排队中/请求中/成功匹配/匹配失败)。\n * 2. .preload-filter-bar / .preload-filter-chip —— 筛选栏(与 .status-tag-filter-bar\n *    同行挂载),按状态过滤卡片,实时刷新计数。\n *\n * 样式风格与 .status-tag-filter-bar 对齐(药丸芯片、border、active 配色),\n * 确保多个筛选栏视觉统一。\n */\n\n/* ========== 卡片内状态徽标 ========== */\n.jhs-preload-status-bar {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 4px;\n    margin-top: 4px;\n    line-height: 1.2;\n}\n\n.jhs-preload-status {\n    display: inline-flex;\n    align-items: center;\n    gap: 4px;\n    padding: 1px 7px;\n    border-radius: 9px;\n    background-color: rgb(0, 0, 0, 0.05);\n    font-size: 11px;\n    line-height: 1.5;\n    white-space: nowrap;\n}\n\n.jhs-ps-name {\n    font-weight: 600;\n    color: #9b9b9b;\n}\n\n.jhs-ps-badge {\n    display: inline-flex;\n    align-items: center;\n    gap: 3px;\n    font-weight: 600;\n}\n\n.jhs-ps-queued {\n    color: #8a8a8a;\n}\n\n.jhs-ps-requesting {\n    color: #d97706;\n}\n\n.jhs-ps-requesting::before {\n    content: '';\n    width: 6px;\n    height: 6px;\n    border-radius: 50%;\n    background-color: #d97706;\n    animation: jhs-ps-pulse 1s ease-in-out infinite;\n}\n\n.jhs-ps-success {\n    color: #198754;\n}\n\n.jhs-ps-success::before {\n    content: '\\2713';\n    font-weight: 700;\n}\n\n.jhs-ps-failed {\n    color: #dc2626;\n}\n\n.jhs-ps-failed::before {\n    content: '\\2715';\n    font-weight: 700;\n}\n\n@keyframes jhs-ps-pulse {\n    0%,\n    100% {\n        opacity: 1;\n    }\n\n    50% {\n        opacity: 0.2;\n    }\n}\n\n/* ========== 筛选栏 ========== */\n\n.preload-filter-chip {\n    display: inline-flex;\n    align-items: center;\n}\n\n.preload-filter-chip .pf-dot {\n    display: inline-block;\n    width: 7px;\n    height: 7px;\n    border-radius: 50%;\n    margin-right: 5px;\n}\n\n.preload-filter-chip[data-value='queued'] .pf-dot {\n    background-color: #8a8a8a;\n}\n\n.preload-filter-chip[data-value='requesting'] .pf-dot {\n    background-color: #d97706;\n}\n\n.preload-filter-chip[data-value='success'] .pf-dot {\n    background-color: #198754;\n}\n\n.preload-filter-chip[data-value='failed'] .pf-dot {\n    background-color: #dc2626;\n}\n\n.preload-filter-chip.active[data-value='queued'] {\n    background: #8a8a8a;\n    border-color: #8a8a8a;\n    color: #fff;\n}\n\n.preload-filter-chip.active[data-value='requesting'] {\n    background: #d97706;\n    border-color: #d97706;\n    color: #fff;\n}\n\n.preload-filter-chip.active[data-value='success'] {\n    background: #198754;\n    border-color: #198754;\n    color: #fff;\n}\n\n.preload-filter-chip.active[data-value='failed'] {\n    background: #dc2626;\n    border-color: #dc2626;\n    color: #fff;\n}\n";
	var OtherSitePlugin = class extends BasePlugin {
		okBackgroundColor = "#7bc73b";
		errorBackgroundColor = "#de3333";
		warnBackgroundColor = "#d7a80c";
		domainErrorBackgroundColor = "#d7780c";
		siteConfigs = [{
			id: "missAvBtn",
			getBaseUrl: async () => await this.getMissAvUrl(),
			itemSelector: ".text-secondary",
			searchPath: (baseUrl, carNum) => `${baseUrl}/search/${carNum}`,
			getDetailPageHref: (item) => item.attr("href"),
			findCarNumOrTitle: (item) => item.text()
		}, {
			id: "supJavBtn",
			getBaseUrl: async () => await this.getSupJavUrl(),
			itemSelector: ".posts post",
			searchPath: (baseUrl, carNum) => `${baseUrl}/?s=${carNum}`,
			getDetailPageHref: (item) => item.attr("href"),
			findCarNumOrTitle: (item) => item.attr("title"),
			initUrl: async (carNum) => `${await this.getSupJavUrl()}/?s=${carNum}`
		}];
		settingCache = null;
		lastFetchTime = 0;
		CACHE_DURATION = 1e4;
		preloadQueue = new AsyncTaskQueue();
		supervisor = new TaskSupervisor();
		preloadDebounce = 0;
		blockedSiteIds = new Set();
		filterBarObserver = null;
		filterRefreshDebounce = 0;
		preloadStatusEnabled = true;
		preloadDebounceMs = 300;
		preloadConcurrency = 1;
		preloadCacheTTLDays = 0;
		inflightPreloads = new Map();
		getName() {
			return "OtherSitePlugin";
		}
		get pageTypes() {
			return ["detail", "list"];
		}
		async initCss() {
			return `${other_site_plugin_default}\n${preload_status_badge_default}`;
		}
		async handle() {
			this.blockedSiteIds.clear();
			if (await storageManager.getSetting("enableLoadOtherSite", "yes") !== "yes") return;
			if (window.isDetailPage) this.loadOtherSite().then();
			else if (document.querySelector(".movie-list")) {
				if (await storageManager.getSetting("enablePreload", "yes") !== "yes") return;
				this.preloadStatusEnabled = await storageManager.getSetting("enablePreloadStatus", "yes") === "yes";
				const debounceRaw = await storageManager.getSetting("preloadDebounce", 300);
				this.preloadDebounceMs = typeof debounceRaw === "number" ? debounceRaw : Number(debounceRaw);
				if (isNaN(this.preloadDebounceMs) || this.preloadDebounceMs < 0) this.preloadDebounceMs = 300;
				const concRaw = await storageManager.getSetting("preloadConcurrency", 1);
				let conc = typeof concRaw === "number" ? concRaw : Number(concRaw);
				if (isNaN(conc) || conc < 1) conc = 1;
				if (conc > 10) conc = 10;
				this.preloadConcurrency = Math.floor(conc);
				this.preloadQueue.setConcurrency(this.preloadConcurrency);
				this.preloadCacheTTLDays = Number(await storageManager.getSetting("preloadCacheTTL", 0)) || 0;
				syncAllBadges(this);
				preloadListPage(this).then();
				startPreloadObserver(this);
				initFilterBar(this);
			}
		}
		async loadOtherSite(carNum, sourceCarNum) {
			if (await storageManager.getSetting("enableLoadOtherSite", "yes") !== "yes") return;
			carNum ||= this.getPageInfo().carNum ?? "";
			const enabledSiteIds = this.getEnabledSites();
			const boxHtml = jsxToString((0, import_jsx_runtime.jsx)(OtherSiteBox, {
				siteButtonsHtml: this.siteConfigs.map((siteConfig) => {
					siteConfig.sourceCarNum = sourceCarNum;
					if (siteConfig.condition && siteConfig.condition(siteConfig.sourceCarNum) === false) return "";
					return jsxToString((0, import_jsx_runtime.jsx)(OtherSiteBtn, {
						id: siteConfig.id,
						enabled: enabledSiteIds.includes(siteConfig.id)
					}));
				}).join(""),
				isJavdbSite
			}));
			$(".movie-panel-info").append(boxHtml);
			$(".container .info").append(boxHtml);
			await Promise.all(this.siteConfigs.map(async (siteConfig) => {
				if (!siteConfig.condition || siteConfig.condition(siteConfig.sourceCarNum) !== false) await this.handleSite(carNum, siteConfig);
			}));
			this.renderSettingsArea();
			this.setupEventListeners();
		}
		async handleSite(carNum, siteConfig) {
			return probeSite(this, carNum, siteConfig);
		}
		async getSettingCache() {
			const now = Date.now();
			if (!this.settingCache || now - this.lastFetchTime > this.CACHE_DURATION) {
				this.settingCache = await storageManager.getSetting();
				this.lastFetchTime = now;
			}
			return this.settingCache;
		}
		async getMissAvUrl() {
			return (await this.getSettingCache()).missAvUrl || "https://missav.live";
		}
		async getJavDbUrl() {
			return (await this.getSettingCache()).javDbUrl || "https://javdb.com";
		}
		async getSupJavUrl() {
			return (await this.getSettingCache()).supJavUrl || "https://supjav.com";
		}
		getEnabledSites() {
			return getEnabledSites(this);
		}
		saveEnabledSites(siteIds) {
			saveEnabledSites(siteIds);
		}
		renderSettingsArea() {
			const enabledSiteIds = this.getEnabledSites();
			const checkboxContainer = document.getElementById("siteCheckboxes");
			if (checkboxContainer) checkboxContainer.innerHTML = this.siteConfigs.map((siteConfig) => {
				const isEnabled = enabledSiteIds.includes(siteConfig.id);
				return jsxToString((0, import_jsx_runtime.jsx)(OtherSiteCheckbox, {
					id: siteConfig.id,
					isEnabled,
					isJavdbSite
				}));
			}).join("");
		}
		setupEventListeners() {
			const settingsArea = document.getElementById("settingsArea");
			if (settingsArea) this.supervisor.addEventListener(settingsArea, "change", (event) => {
				const target = event.target;
				if (target.type === "checkbox") {
					const siteId = target.getAttribute("data-site-id");
					if (target.checked) {
						$(`#${siteId}`).show();
						const carNum = this.getPageInfo().carNum ?? "";
						const siteConfig = this.siteConfigs.find((config) => config.id === siteId);
						this.handleSite(carNum, siteConfig).then();
					} else $(`#${siteId}`).hide();
					const checkedSiteIds = Array.from(settingsArea.querySelectorAll("input[type=\"checkbox\"]:checked")).map((checkbox) => checkbox.getAttribute("data-site-id"));
					this.saveEnabledSites(checkedSiteIds);
				}
			});
		}
		destroy() {
			this.supervisor.abort();
		}
	};
	var SAFE_INLINE_TAGS = {
		B: true,
		I: true,
		EM: true,
		STRONG: true,
		BR: true,
		P: true,
		SPAN: true
	};
	function parseInlineStyle(s) {
		if (!s) return void 0;
		try {
			const o = {};
			for (const part of s.split(";")) {
				const idx = part.indexOf(":");
				if (idx <= 0) continue;
				const k = part.slice(0, idx).trim();
				const v = part.slice(idx + 1).trim();
				if (!k || !v) continue;
				o[k.replace(/-([a-z])/g, (_m, c) => c.toUpperCase())] = v;
			}
			return Object.keys(o).length ? o : void 0;
		} catch {
			return;
		}
	}
	function safeReviewNodes(html) {
		const doc = new DOMParser().parseFromString(html, "text/html");
		const walk = (nodes, keyPrefix) => {
			const res = [];
			Array.from(nodes).forEach((node, i) => {
				const key = `${keyPrefix}${i}`;
				if (node.nodeType === Node.TEXT_NODE) {
					const t = node.textContent ?? "";
					if (t) res.push(t);
				} else if (node.nodeType === Node.ELEMENT_NODE) {
					const el = node;
					const tag = el.tagName.toUpperCase();
					const cls = el.getAttribute("class") || void 0;
					const stl = parseInlineStyle(el.getAttribute("style"));
					if (tag === "A") res.push((0, import_jsx_runtime.jsx)("a", {
						href: sanitizeUrl(el.getAttribute("href") || ""),
						target: "_blank",
						rel: "noopener noreferrer",
						className: cls,
						style: stl,
						children: walk(el.childNodes, key + "-")
					}, key));
					else if (tag === "BR") res.push((0, import_jsx_runtime.jsx)("br", {}, key));
					else if (SAFE_INLINE_TAGS[tag]) {
						const inner = walk(el.childNodes, key + "-");
						if (tag === "P") res.push((0, import_jsx_runtime.jsx)("p", {
							className: cls,
							style: stl,
							children: inner
						}, key));
						else if (tag === "B") res.push((0, import_jsx_runtime.jsx)("b", {
							className: cls,
							style: stl,
							children: inner
						}, key));
						else if (tag === "I") res.push((0, import_jsx_runtime.jsx)("i", {
							className: cls,
							style: stl,
							children: inner
						}, key));
						else if (tag === "EM") res.push((0, import_jsx_runtime.jsx)("em", {
							className: cls,
							style: stl,
							children: inner
						}, key));
						else if (tag === "STRONG") res.push((0, import_jsx_runtime.jsx)("strong", {
							className: cls,
							style: stl,
							children: inner
						}, key));
						else if (tag === "SPAN") res.push((0, import_jsx_runtime.jsx)("span", {
							className: cls,
							style: stl,
							children: inner
						}, key));
					} else res.push(...walk(el.childNodes, key + "-"));
				}
			});
			return res;
		};
		return walk(doc.body.childNodes, "");
	}
	function ReviewItem({ floor, username, stars, time, likesCount, content }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "item columns is-desktop",
			style: {
				display: "block",
				marginTop: "6px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px",
				wordBreak: "break-word",
				position: "relative"
			},
			children: [
				(0, import_jsx_runtime.jsxs)("span", {
					style: {
						position: "absolute",
						top: "5px",
						right: "10px",
						color: "#999",
						fontSize: "12px"
					},
					children: [
						"#",
						floor,
						"楼"
					]
				}),
				username,
				" \xA0\xA0",
				" ",
				(0, import_jsx_runtime.jsx)("span", {
					className: "score-stars",
					dangerouslySetInnerHTML: { __html: stars }
				}),
				" ",
				(0, import_jsx_runtime.jsx)("span", {
					className: "time",
					children: time
				}),
				" \xA0\xA0 点赞:",
				likesCount,
				(0, import_jsx_runtime.jsx)("p", {
					className: "review-content",
					style: { marginTop: "5px" },
					children: safeReviewNodes(content)
				})
			]
		});
	}
	function ReviewLinkContent({ match }) {
		if (match.startsWith("ed2k://")) return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			" ",
			(0, import_jsx_runtime.jsx)("span", {
				style: {
					wordBreak: "break-all",
					background: "#e0f2fe",
					color: "#0369a1"
				},
				children: match
			}),
			" "
		] });
		if (match.startsWith("magnet:")) return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			" ",
			(0, import_jsx_runtime.jsx)("a", {
				href: match,
				className: "a-primary",
				style: {
					padding: 0,
					wordBreak: "break-all",
					whiteSpace: "pre-wrap"
				},
				target: "_blank",
				rel: "noopener noreferrer",
				children: match
			}),
			" "
		] });
		if (match.startsWith("http://") || match.startsWith("https://")) return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			" ",
			(0, import_jsx_runtime.jsx)("a", {
				href: match,
				className: "a-primary",
				style: {
					padding: 0,
					wordBreak: "break-all",
					whiteSpace: "pre-wrap"
				},
				target: "_blank",
				rel: "noopener noreferrer",
				children: match
			}),
			" "
		] });
		return match;
	}
	function ReviewStarIcon() {
		return (0, import_jsx_runtime.jsx)("i", { className: "icon-star" });
	}
	function SectionContainers({ containerId, footerId }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", { id: containerId }), (0, import_jsx_runtime.jsx)("div", { id: footerId })] });
	}
	function SectionEndMessage({ text }) {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				textAlign: "center",
				padding: "10px",
				color: "#666",
				marginTop: "10px"
			},
			children: text
		});
	}
	function SectionErrorMessage({ text, retryId, linkColor }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: [text, (0, import_jsx_runtime.jsx)("a", {
				id: retryId,
				style: {
					marginLeft: "10px",
					color: linkColor,
					textDecoration: "none",
					cursor: "pointer"
				},
				children: "重试"
			})]
		});
	}
	function SectionHeader({ title, foldId, linkColor, tooltip, foldText, iconText }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				display: "flex",
				alignItems: "center",
				margin: "16px 0",
				color: "#666",
				fontSize: "14px"
			},
			children: [
				(0, import_jsx_runtime.jsx)("span", { style: {
					flex: 1,
					height: "1px",
					background: "linear-gradient(to right, transparent, #999, transparent)"
				} }),
				(0, import_jsx_runtime.jsx)("span", {
					style: { padding: "0 10px" },
					"data-tip": tooltip,
					children: title
				}),
				(0, import_jsx_runtime.jsxs)("a", {
					id: foldId,
					style: {
						marginLeft: "8px",
						color: linkColor,
						textDecoration: "none",
						display: "flex",
						alignItems: "center"
					},
					children: [(0, import_jsx_runtime.jsx)("span", {
						className: "toggle-text",
						children: foldText
					}), (0, import_jsx_runtime.jsx)("span", {
						className: "toggle-icon",
						style: { marginLeft: "4px" },
						children: iconText
					})]
				}),
				(0, import_jsx_runtime.jsx)("span", { style: {
					flex: 1,
					height: "1px",
					background: "linear-gradient(to right, transparent, #999, transparent)"
				} })
			]
		});
	}
	function SectionLoadMore({ loadMoreId, endId, text, endText }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("button", {
			id: loadMoreId,
			style: {
				width: "100%",
				backgroundColor: "#e1f5fe",
				border: "none",
				padding: "10px",
				marginTop: "10px",
				cursor: "pointer",
				color: "#0277bd",
				fontWeight: "bold",
				borderRadius: "4px"
			},
			children: text
		}), (0, import_jsx_runtime.jsx)("div", {
			id: endId,
			style: {
				display: "none",
				textAlign: "center",
				padding: "10px",
				color: "#666",
				marginTop: "10px"
			},
			children: endText
		})] });
	}
	function SectionStatusMessage({ text, id }) {
		return (0, import_jsx_runtime.jsx)("div", {
			id,
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: text
		});
	}
	var ReviewPlugin = class extends BasePlugin {
		floorIndex = 1;
		isInit = false;
		constructor() {
			super();
		}
		getName() {
			return "ReviewPlugin";
		}
		get pageTypes() {
			return ["detail"];
		}
		async handle() {
			if (window.isDetailPage) {
				if (isJavdbSite) {
					const movieId = this.parseMovieId(window.location.href);
					await this.showReview(movieId);
					await this.getBean("RelatedPlugin").showRelated($("#magnets-content"), movieId);
				}
			}
		}
		async showReview(movieId, container) {
			const isExpanded = await storageManager.getSetting("enableLoadReview", "yes");
			const target = container || $("#magnets-content");
			target.append(jsxToString((0, import_jsx_runtime.jsx)(SectionHeader, {
				title: "❓ 评论区",
				foldId: "reviewsFold",
				linkColor: "#1890ff",
				tooltip: "想要发表评论? 滑上去, 点击上面的按钮-看过",
				foldText: isExpanded === "yes" ? "折叠" : "展开",
				iconText: isExpanded === "yes" ? "▲" : "▼"
			})));
			$("#reviewsFold").on("click", (event) => {
				event.preventDefault();
				event.stopPropagation();
				const toggleText = $("#reviewsFold .toggle-text");
				const toggleIcon = $("#reviewsFold .toggle-icon");
				const isExpand = toggleText.text() === "展开";
				toggleText.text(isExpand ? "折叠" : "展开");
				toggleIcon.text(isExpand ? "▲" : "▼");
				if (isExpand) {
					$("#reviewsContainer").show();
					$("#reviewsFooter").show();
					if (!this.isInit) {
						this.fetchAndDisplayReviews(movieId);
						this.isInit = true;
					}
					storageManager.saveSettingItem("enableLoadReview", "yes");
				} else {
					$("#reviewsContainer").hide();
					$("#reviewsFooter").hide();
					storageManager.saveSettingItem("enableLoadReview", "no");
				}
			});
			target.append(jsxToString((0, import_jsx_runtime.jsx)(SectionContainers, {
				containerId: "reviewsContainer",
				footerId: "reviewsFooter"
			})));
			if (isExpanded === "yes") await this.fetchAndDisplayReviews(movieId);
		}
		async fetchAndDisplayReviews(movieId) {
			const container = $("#reviewsContainer");
			const footer = $("#reviewsFooter");
			container.append(jsxToString((0, import_jsx_runtime.jsx)(SectionStatusMessage, {
				text: "获取评论中...",
				id: "reviewsLoading"
			})));
			const limit = await storageManager.getSetting("reviewCount", 20);
			let reviews = null;
			try {
				reviews = await fetchMovieReviews(movieId, 1, limit);
			} catch (err) {
				if (String(err).includes("簽名已過期")) show.error("生成签名失败, 请检查系统时间及时区是否正确!");
				clog.error("获取评论失败:", err);
			} finally {
				$("#reviewsLoading").remove();
			}
			if (!reviews) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(SectionErrorMessage, {
					text: "获取评论失败",
					retryId: "retryFetchReviews",
					linkColor: "#1890ff"
				})));
				$("#retryFetchReviews").on("click", async () => {
					$("#retryFetchReviews").parent().remove();
					await this.fetchAndDisplayReviews(movieId);
				});
				return;
			}
			if (reviews.length === 0) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(SectionStatusMessage, { text: "无评论" })));
				return;
			}
			this.displayReviews(reviews, container);
			if (reviews.length === limit) {
				footer.html(jsxToString((0, import_jsx_runtime.jsx)(SectionLoadMore, {
					loadMoreId: "loadMoreReviews",
					endId: "reviewsEnd",
					text: "加载更多评论",
					endText: "已加载全部评论"
				})));
				let page = 1;
				const loadMoreBtn = $("#loadMoreReviews");
				loadMoreBtn.on("click", async () => {
					let moreReviews;
					loadMoreBtn.text("加载中...").prop("disabled", true);
					page++;
					try {
						moreReviews = await fetchMovieReviews(movieId, page, limit);
					} catch (err) {
						clog.error("加载更多评论失败:", err);
					} finally {
						loadMoreBtn.text("加载失败, 请点击重试").prop("disabled", false);
					}
					if (moreReviews) {
						this.displayReviews(moreReviews, container);
						if (moreReviews.length < limit) {
							loadMoreBtn.remove();
							$("#reviewsEnd").show();
						} else loadMoreBtn.text("加载更多评论").prop("disabled", false);
					}
				});
			} else footer.html(jsxToString((0, import_jsx_runtime.jsx)(SectionEndMessage, { text: "已加载全部评论" })));
		}
		displayReviews(reviews, container) {
			if (reviews.length) reviews.forEach((review) => {
				const stars = Array(review.score).fill(jsxToString((0, import_jsx_runtime.jsx)(ReviewStarIcon, {}))).join("");
				const content = review.content.replace(/ed2k:\/\/\|file\|[^|]+\|\d+\|[a-fA-F0-9]{32}\|\/|magnet:\?[^\s"'<>`\u4e00-\u9fa5,。?!()【】]+|https?:\/\/[^\s"'<>`\u4e00-\u9fa5,。?!()【】]+/g, (match) => jsxToString((0, import_jsx_runtime.jsx)(ReviewLinkContent, { match })));
				const html = jsxToString((0, import_jsx_runtime.jsx)(ReviewItem, {
					floor: this.floorIndex++,
					username: review.username,
					stars,
					time: utils.formatDate(review.created_at),
					likesCount: review.likes_count,
					content
				}));
				container.append(html);
			});
		}
	};
	var BLACKLIST_DEFAULT_LABEL = "加入黑名单";
	var BLACKLIST_DEFAULT_COLOR = "#d22020";
	var BLACKLIST_TIP = "将演员加入黑名单, 后续有作品更新也会纳入屏蔽中";
	var SORT_DEFAULT_LABEL = "当前排序方式: 默认";
	function menuBtnStyle(backgroundColor) {
		return { backgroundColor: `${backgroundColor} !important` };
	}
	function MenuButtonBoxHtml({ blacklistLabel = BLACKLIST_DEFAULT_LABEL, blacklistColor = BLACKLIST_DEFAULT_COLOR, tagsPage = false, advancedSearch = false, searchOrUserPage = false, sortLabel = SORT_DEFAULT_LABEL, newVideoCount = 0 }) {
		const showSortToggle = !searchOrUserPage && !advancedSearch;
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsxs)("div", {
			style: {
				display: "flex",
				alignItems: "center",
				flexGrow: advancedSearch ? void 0 : 1
			},
			children: [
				(0, import_jsx_runtime.jsx)("a", {
					id: "waitCheckBtn",
					className: "jhs-toolbar-menu-btn main-tab-btn",
					style: menuBtnStyle("#56c938"),
					children: (0, import_jsx_runtime.jsx)("span", { children: "打开待鉴定" })
				}),
				(0, import_jsx_runtime.jsx)("a", {
					id: "waitDownBtn",
					className: "jhs-toolbar-menu-btn main-tab-btn",
					style: menuBtnStyle("#2caac0"),
					children: (0, import_jsx_runtime.jsx)("span", { children: "打开已收藏" })
				}),
				tagsPage && (0, import_jsx_runtime.jsx)("a", {
					id: "addBlacklistBtn",
					className: "jhs-toolbar-menu-btn main-tab-btn",
					style: menuBtnStyle(blacklistColor),
					"data-tip": BLACKLIST_TIP,
					children: (0, import_jsx_runtime.jsx)("span", { children: blacklistLabel })
				})
			]
		}), (0, import_jsx_runtime.jsxs)("div", {
			style: {
				display: "flex",
				alignItems: "center"
			},
			children: [
				(0, import_jsx_runtime.jsx)("a", {
					id: "newVideoBtn",
					className: "jhs-toolbar-menu-btn main-tab-btn",
					style: menuBtnStyle("#2c6cc0"),
					children: (0, import_jsx_runtime.jsxs)("span", { children: [
						"新作品检测 (",
						(0, import_jsx_runtime.jsx)("span", {
							id: "newVideoCount",
							children: newVideoCount
						}),
						")"
					] })
				}),
				(0, import_jsx_runtime.jsx)("a", {
					id: "blacklistBtn",
					className: "jhs-toolbar-menu-btn main-tab-btn",
					style: menuBtnStyle("#34393f"),
					children: (0, import_jsx_runtime.jsx)("span", { children: "演员黑名单" })
				}),
				showSortToggle && (0, import_jsx_runtime.jsx)("a", {
					id: "sort-toggle-btn",
					className: "jhs-toolbar-menu-btn main-tab-btn",
					style: menuBtnStyle("#8783ab"),
					children: ` ${sortLabel} `
				})
			]
		})] });
	}
	var HAS_DOWN_TEXT = "📥️ 已下载";
	var ListPageButtonPlugin = class extends BasePlugin {
		getName() {
			return "ListPageButtonPlugin";
		}
		get pageTypes() {
			return ["list"];
		}
		async handle() {
			if (!window.isListPage) return;
			await this.createMenuBtn();
			this.bindEvent();
		}
		async createMenuBtn() {
			if (isJavdbSite) {
				let containerEl = $(".main-tabs, .tabs");
				const blacklistLabel = "加入黑名单";
				const blacklistColor = "#d22020";
				let tagBlacklistEntry = null;
				if (currentHref.includes("/tags")) utils.loopDetector(() => $("#jhs-check-tag").text().trim() !== "", async () => {
					const addBlacklistBtnEl = $("#addBlacklistBtn");
					addBlacklistBtnEl.attr("data-tip", "将当前分类标签加入到黑名单, 后续有作品更新也会纳入屏蔽中");
					const tagName = $("#jhs-check-tag").text().trim();
					if (!tagName) return;
					const tagStarId = "no-" + tagName;
					tagBlacklistEntry = (await storageManager.getBlacklist()).find((entry) => entry.starId === tagStarId);
					if (tagBlacklistEntry) {
						addBlacklistBtnEl.css("backgroundColor", "#885d5d");
						$("#addBlacklistBtn span").text("已加入黑名单");
					}
				});
				const isAdvancedSearch = currentHref.includes("advanced_search");
				if (isAdvancedSearch) containerEl = $("h2.section-title");
				const sortMethod = localStorage.getItem("jhs_sortMethod");
				const sortLabel = "当前排序方式: " + (sortMethod === "rateCount" ? "评价人数" : sortMethod === "date" ? "时间" : "默认");
				containerEl.append(jsxToString((0, import_jsx_runtime.jsx)(MenuButtonBoxHtml, {
					blacklistLabel,
					blacklistColor,
					tagsPage: currentHref.includes("/tags"),
					advancedSearch: isAdvancedSearch,
					searchOrUserPage: isSearchOrUserPage,
					sortLabel
				})));
			}
		}
		bindEvent() {
			$("#waitCheckBtn").on("click", () => {
				this.openWaitCheck().then();
			});
			$("#waitDownBtn").on("click", () => {
				this.openFavorite().then();
			});
			$("#newVideoBtn").on("click", () => {
				this.getBean("NewVideoPlugin").openDialog();
			});
			$("#blacklistBtn").on("click", () => {
				this.getBean("BlacklistPlugin").openBlacklistDialog();
			});
			$("#sort-toggle-btn").on("click", (event) => {
				const currentMethod = localStorage.getItem("jhs_sortMethod");
				const nextMethod = currentMethod && currentMethod !== "default" ? currentMethod === "rateCount" ? "date" : "default" : "rateCount";
				$(event.target).text(`当前排序方式: ${{
					default: "默认",
					rateCount: "评价人数",
					date: "时间"
				}[nextMethod]}`);
				localStorage.setItem("jhs_sortMethod", nextMethod);
				this.sortItems().then();
			});
			const blacklistPlugin = this.getBean("BlacklistPlugin");
			$("#addBlacklistBtn").on("click", async (event) => {
				await blacklistPlugin.addBlacklist(event);
			});
		}
		async sortItems() {
			if (currentHref.includes("handle") || currentHref.includes("advanced_search")) return;
			if (isSearchOrUserPage) return;
			const sortMethod = localStorage.getItem("jhs_sortMethod");
			if (!sortMethod) return;
			$(".movie-list .item").each((index, element) => {
				if (!$(element).attr("data-original-index")) $(element).attr("data-original-index", index);
			});
			const listEl = $(".movie-list");
			const itemEls = $(".item", listEl);
			if (sortMethod === "default") itemEls.get().sort((itemA, itemB) => $(itemA).data("original-index") - $(itemB).data("original-index")).forEach((el) => listEl.append(el));
			else {
				const items = itemEls.get();
				items.sort((itemA, itemB) => {
					if (sortMethod === "rateCount") {
						const getRateCount = (el) => {
							const match = $(el).find(".score .value").text().match(/由(\d+)人/);
							if (match) return parseFloat(match[1]);
							else return 0;
						};
						return getRateCount(itemB) - getRateCount(itemA);
					} else {
						const getDate = (el) => {
							const dateStr = $(el).find(".meta").text().trim();
							return new Date(dateStr).getTime();
						};
						return getDate(itemB) - getDate(itemA);
					}
				});
				listEl.empty().append(items);
			}
		}
		async openWaitCheck() {
			const selectorConfig = this.getSelector();
			const maxCount = await storageManager.getSetting("waitCheckCount", 5);
			const skipTags = [
				BLOCKED_TEXT,
				FAVORITED_TEXT,
				HAS_DOWN_TEXT,
				WATCHED_TEXT
			];
			let openedCount = 0;
			$(`${selectorConfig.itemSelector}:visible`).each((_index, element) => {
				if (openedCount >= maxCount) return false;
				const itemEl = $(element);
				if (skipTags.some((tagText) => itemEl.find(`span.tag:contains('${tagText}')`).length > 0)) return;
				const { carNum, aHref } = this.getBean("ListPagePlugin").findCarNumAndHref(itemEl);
				if (carNum.includes("FC2-")) {
					const movieId = this.parseMovieId(aHref);
					this.getBean("Fc2Plugin")?.openFc2Page(movieId, carNum, aHref);
				} else {
					const url = aHref + (aHref.includes("?") ? "&autoPlay=1" : "?autoPlay=1");
					window.open(url, "_blank", "noopener,noreferrer");
				}
				openedCount++;
			});
			if (openedCount === 0) show.info("没有需鉴定的视频");
		}
		async openFavorite() {
			const maxCount = await storageManager.getSetting("waitCheckCount", 5);
			const favoriteList = (await storageManager.getCarList()).filter((item) => item.status === FAVORITE_ACTION).sort((a, b) => Number(b.createDate) - Number(a.createDate));
			for (let i = 0; i < maxCount; i++) {
				if (i >= favoriteList.length) return;
				const carInfo = favoriteList[i];
				const carNum = carInfo.carNum;
				const url = carInfo.url;
				if (carNum.includes("FC2-")) {
					const movieId = this.parseMovieId(url);
					await this.getBean("Fc2Plugin")?.openFc2Page(movieId, carNum, url);
				} else window.open(url, "_blank", "noopener,noreferrer");
				clog.debug("打开已收藏", carNum, url);
			}
		}
	};
	var PaginationStateMachine = class {
		_phase = "idle";
		_hasMore = false;
		get phase() {
			return this._phase;
		}
		get hasMore() {
			return this._hasMore;
		}
		get canLoad() {
			return this._phase === "idle" && this._hasMore;
		}
		get isLoading() {
			return this._phase === "loading";
		}
		init(hasMore) {
			this._hasMore = hasMore;
			this._phase = hasMore ? "idle" : "exhausted";
		}
		startLoading() {
			if (!this.canLoad) return false;
			this._phase = "loading";
			return true;
		}
		loadSuccess(hasMore) {
			this._hasMore = hasMore;
			this._phase = hasMore ? "idle" : "exhausted";
		}
		loadError() {
			this._phase = "error";
		}
		retry() {
			if (this._phase === "error") this._phase = "idle";
		}
		reset() {
			this._phase = "idle";
			this._hasMore = false;
		}
	};
	async function loadNextPage$1(plugin) {
		if (!plugin.pagination.canLoad || !plugin.nextUrl) return;
		plugin.pagination.startLoading();
		plugin.setState("waterfall-loading", "加载中...");
		const selectorConfig = plugin.getSelector();
		try {
			const pageNum = utils.getUrlParam(plugin.nextUrl, "page");
			let maxPage = 60;
			if (currentHref.includes("c11")) maxPage = 30;
			if (isJavdbSite && Number(pageNum) > maxPage || currentHref.includes("month")) {
				const beyond60Plugin = plugin.getBean("Beyond60Plugin");
				if (beyond60Plugin) {
					const { html, nextUrl: beyondNextUrl, hasMore: beyondHasMore } = await beyond60Plugin.handleBeyond60(plugin.nextUrl);
					if (html) {
						const scrollHeight = plugin.container.scrollHeight;
						plugin.pageItems.push({
							page: plugin.currentPage + 1,
							top: scrollHeight,
							url: plugin.nextUrl
						});
						$(".movie-list").append(html);
					}
					plugin.pagination.loadSuccess(beyondHasMore);
					plugin.nextUrl = beyondNextUrl;
					const paginationHtml = beyond60Plugin.createPagination(Number(pageNum), beyondHasMore);
					$(".pagination").html(paginationHtml);
					plugin.setState("", "");
					if (!plugin.pagination.hasMore) plugin.setState("waterfall-no-more", "已经到底了");
					return;
				}
			}
			const responseHtml = await gmHttp.get(plugin.nextUrl);
			clog.log("请求下一页内容:", plugin.nextUrl);
			const $dom = utils.htmlTo$dom(String(responseHtml));
			const items = $dom.find(plugin.getSelector().requestDomItemSelector);
			const existingList = plugin.getBoxCarInfoList();
			const newList = plugin.getBoxCarInfoList(items);
			if (plugin.checkDuplicateCarNumbers(existingList, newList)) {
				plugin.nextUrl = null;
				plugin.pagination.loadError();
				plugin.setState("waterfall-error", "翻页内容出现重复数据, 页码受JavDB限制, 已停止瀑布流");
				return;
			}
			const scrollHeight = plugin.container.scrollHeight;
			plugin.pageItems.push({
				page: plugin.currentPage + 1,
				top: scrollHeight,
				url: plugin.nextUrl
			});
			const listPagePlugin = plugin.getBean("ListPagePlugin");
			const coverImgs = $dom.find(plugin.getSelector().coverImgSelector);
			listPagePlugin.replaceHdImg(coverImgs);
			$(plugin.getSelector().boxSelector).append(items);
			const nextLinkEl = $dom.find(selectorConfig.nextPageSelector);
			plugin.nextUrl = nextLinkEl == null ? void 0 : nextLinkEl.attr("href");
			plugin.pagination.loadSuccess(!!plugin.nextUrl);
			const paginationEl = $dom.find(".pagination");
			$(".pagination").replaceWith(paginationEl);
			plugin.setState("", "");
			if (!plugin.pagination.hasMore) plugin.setState("waterfall-no-more", "已经到底了");
		} catch (err) {
			clog.error("加载失败:", err);
			plugin.pagination.loadError();
			plugin.setState("waterfall-error", "加载失败,点击重试");
		} finally {
			if (plugin.loadMode === "click" && plugin.pagination.hasMore && plugin.nextUrl) plugin.checkLoad();
		}
	}
	function checkScrollPosition(plugin) {
		const scrollY = window.scrollY;
		for (let i = plugin.pageItems.length - 1; i >= 0; i--) {
			const item = plugin.pageItems[i];
			if (scrollY >= item.top) {
				if (plugin.currentPage !== item.page) plugin.currentPage = item.page;
				break;
			}
		}
	}
	function checkLoad$1(plugin) {
		if (!plugin.loader) return;
		if (plugin.loader.getBoundingClientRect().top < window.innerHeight + plugin.preloadDistance) if (plugin.loadMode === "click") {
			if (plugin.pagination.isLoading || !plugin.pagination.hasMore || !plugin.nextUrl || plugin.loader.classList.contains("waterfall-error") || plugin.loader.classList.contains("waterfall-loading") || plugin.loader.classList.contains("waterfall-no-more")) return;
			plugin.setState("waterfall-click", "点击加载下一页");
		} else plugin.loadNextPage().then();
	}
	function setLoadMode(plugin, mode) {
		plugin.loadMode = mode === "click" ? "click" : "auto";
		if (plugin.loadMode === "auto") plugin.checkLoad();
		else if (plugin.loader && plugin.pagination.hasMore && plugin.nextUrl && !plugin.pagination.isLoading && !plugin.loader.classList.contains("waterfall-no-more")) {
			if (plugin.loader.getBoundingClientRect().top < window.innerHeight + plugin.preloadDistance) plugin.setState("waterfall-click", "点击加载下一页");
		}
	}
	function showLoadAllBtn(plugin) {
		if (plugin.loadAllBtn) return;
		if (!plugin.container || !plugin.pagination.hasMore) return;
		plugin.createLoadAllBtn();
	}
	function hideLoadAllBtn(plugin) {
		if (!plugin.loadAllBtn) return;
		plugin.loadAllBtn.remove();
		plugin.loadAllBtn = null;
	}
	function createLoadAllBtn(plugin) {
		const btn = document.createElement("div");
		btn.className = "jhs-load-all-btn";
		btn.textContent = "加载全部";
		plugin.supervisor.addEventListener(btn, "click", () => {
			if (!plugin.isLoadingAll) plugin.loadAllPages().then();
		});
		document.body.appendChild(btn);
		plugin.loadAllBtn = btn;
	}
	async function loadAllPages(plugin) {
		if (plugin.isLoadingAll || !plugin.pagination.hasMore) return;
		plugin.isLoadingAll = true;
		plugin.updateLoadAllBtn("加载中...", true);
		try {
			while (plugin.pagination.hasMore && plugin.nextUrl) {
				const before = plugin.pageItems.length;
				await plugin.loadNextPage();
				if (plugin.pageItems.length === before) break;
				plugin.updateLoadAllBtn(`加载中...(第 ${plugin.currentPage} 页)`, true);
			}
			if (plugin.loader?.classList.contains("waterfall-error")) if ((plugin.loader?.textContent || "").includes("重复")) plugin.updateLoadAllBtn("已停止(页码受限)", false);
			else plugin.updateLoadAllBtn("加载失败,点击重试", false);
			else {
				plugin.updateLoadAllBtn("✓ 已全部加载", false);
				plugin.supervisor.setTimeout(() => {
					plugin.loadAllBtn?.classList.add("jhs-load-all-fadeout");
					plugin.supervisor.setTimeout(() => {
						plugin.loadAllBtn?.remove();
						plugin.loadAllBtn = null;
					}, 500);
				}, 2e3);
			}
		} catch {
			plugin.updateLoadAllBtn("加载失败,点击重试", false);
		} finally {
			plugin.isLoadingAll = false;
		}
	}
	function updateLoadAllBtn(plugin, text, disabled) {
		if (!plugin.loadAllBtn) return;
		plugin.loadAllBtn.textContent = text;
		if (disabled) plugin.loadAllBtn.classList.add("jhs-load-all-disabled");
		else plugin.loadAllBtn.classList.remove("jhs-load-all-disabled");
	}
	function setState$1(plugin, stateClass, text) {
		plugin.loader.className = `jhs-scroll ${stateClass}`;
		plugin.loader.textContent = text;
	}
	var auto_page_plugin_default = ".jhs-scroll {\n    text-align: center;\n    padding-top: 20px;\n    font-size: 14px;\n}\n\n.jhs-scroll.waterfall-loading {\n    color: #000;\n}\n\n.jhs-scroll.waterfall-error {\n    color: #f44336;\n    cursor: pointer;\n}\n\n.jhs-scroll.waterfall-no-more {\n    color: #4caf50;\n}\n\n.jhs-scroll.waterfall-click {\n    color: #1976d2;\n    cursor: pointer;\n    font-weight: 600;\n}\n\n.jhs-scroll.waterfall-click:hover {\n    color: #0d47a1;\n    text-decoration: underline;\n}\n\n.jhs-load-all-btn {\n    position: fixed;\n    right: 20px;\n    bottom: 80px;\n    z-index: var(--jhs-z-page);\n    padding: 10px 20px;\n    background: linear-gradient(to right, #5d87c2, #4a90d9);\n    color: #fff;\n    border-radius: 20px;\n    cursor: pointer;\n    font-size: 14px;\n    box-shadow: 0 2px 8px rgb(0, 0, 0, 0.3);\n    transition: opacity 0.5s, transform 0.2s;\n    user-select: none;\n}\n\n.jhs-load-all-btn:hover {\n    transform: translateY(-2px);\n    box-shadow: 0 4px 12px rgb(0, 0, 0, 0.4);\n}\n\n.jhs-load-all-btn.jhs-load-all-disabled {\n    opacity: 0.6;\n    cursor: wait;\n}\n\n.jhs-load-all-btn.jhs-load-all-fadeout {\n    opacity: 0;\n}\n";
	var AutoPagePlugin = class extends BasePlugin {
		preloadDistance = 500;
		currentPage = this.getInitialPageNumber();
		pageItems = [];
		container = null;
		loader = null;
		nextUrl = void 0;
		pagination = new PaginationStateMachine();
		loadAllBtn = null;
		isLoadingAll = false;
		loadMode = "auto";
		supervisor = new TaskSupervisor();
		getName() {
			return "AutoPagePlugin";
		}
		destroy() {
			this.supervisor.abort();
		}
		get pageTypes() {
			return ["list"];
		}
		async initCss() {
			return auto_page_plugin_default;
		}
		async handle() {
			this.waterfall().then();
		}
		getInitialPageNumber() {
			if (isJavdbSite) {
				const match = currentHref.match(/[?&]page=(\d+)/);
				if (match) return parseInt(match[1], 10);
				else return 1;
			}
			return 1;
		}
		async waterfall() {
			if (await this.shouldDisablePaging()) return;
			const selectorConfig = this.getSelector();
			this.container = document.querySelector(selectorConfig.boxSelector);
			if (!this.container) {
				clog.error("没有找到容器节点,停止瀑布流!");
				return;
			}
			const container = this.container;
			this.loader = document.createElement("div");
			const loader = this.loader;
			loader.className = "jhs-scroll";
			container.parentNode.insertBefore(loader, container.nextSibling);
			this.pageItems.push({
				page: this.currentPage,
				top: 0,
				url: window.location.href
			});
			this.supervisor.addEventListener(loader, "click", () => {
				if (loader.classList.contains("waterfall-error") || loader.classList.contains("waterfall-click")) {
					this.pagination.retry();
					this.loadNextPage().then();
				}
			});
			this.supervisor.addEventListener(window, "scroll", () => {
				this.checkLoad();
				this.checkScrollPosition();
			});
			const nextLinkEl = document.querySelector(selectorConfig.nextPageSelector);
			this.nextUrl = nextLinkEl == null ? void 0 : nextLinkEl.href;
			this.pagination.init(!!this.nextUrl);
			const mode = await storageManager.getSetting("autoPageLoadMode", "auto");
			this.loadMode = mode === "click" ? "click" : "auto";
			this.supervisor.setTimeout(() => {
				this.checkLoad();
			}, 1e3);
			if (!this.pagination.hasMore) this.setState("waterfall-no-more", "已经到底了");
			else this.showLoadAllBtn();
		}
		async loadNextPage() {
			return loadNextPage$1(this);
		}
		checkScrollPosition() {
			checkScrollPosition(this);
		}
		checkLoad() {
			checkLoad$1(this);
		}
		setLoadMode(mode) {
			setLoadMode(this, mode);
		}
		showLoadAllBtn() {
			showLoadAllBtn(this);
		}
		hideLoadAllBtn() {
			hideLoadAllBtn(this);
		}
		createLoadAllBtn() {
			createLoadAllBtn(this);
		}
		async loadAllPages() {
			return loadAllPages(this);
		}
		updateLoadAllBtn(text, disabled) {
			updateLoadAllBtn(this, text, disabled);
		}
		setState(stateClass, text) {
			setState$1(this, stateClass, text);
		}
		async shouldDisablePaging() {
			if (!window.isListPage) return true;
			return [
				"search?q",
				"handlePlayback=1",
				"handleTop=1",
				"/want_watch_videos",
				"/watched_videos",
				"/advanced_search?type=100"
			].some((pattern) => currentHref.includes(pattern));
		}
		updatePageUrl_old(_url) {}
		updatePageUrl(_url) {}
	};
	var TABULATOR_ZH_CN = { pagination: {
		first: "首页",
		first_title: "首页",
		last: "尾页",
		last_title: "尾页",
		prev: "上一页",
		prev_title: "上一页",
		next: "下一页",
		next_title: "下一页",
		all: "所有",
		page_size: "每页行数"
	} };
	function createTabulatorOptions(columns, data) {
		const options = {
			layout: "fitColumns",
			placeholder: "暂无数据",
			virtualDom: true,
			responsiveLayout: "collapse",
			responsiveLayoutCollapse: true,
			columnDefaults: {
				headerHozAlign: "center",
				hozAlign: "center"
			},
			columns,
			locale: "zh-cn",
			langs: { "zh-cn": TABULATOR_ZH_CN }
		};
		if (data) options.data = data;
		return options;
	}
	function BlacklistActionCell() {
		return (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: (0, import_jsx_runtime.jsxs)("a", {
			className: "a-danger delete-btn",
			children: [
				" ",
				(0, import_jsx_runtime.jsx)("span", { children: "✂️ 删除" }),
				" "
			]
		}) });
	}
	function BlacklistNameCell({ url, name }) {
		return (0, import_jsx_runtime.jsx)("a", {
			className: "open-url",
			"data-url": url,
			href: url,
			"data-name": name,
			target: "_blank",
			children: name
		});
	}
	function BlacklistPaginationCounter({ actorCount, currentCarCount }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			"演员: ",
			actorCount,
			" \xA0\xA0\xA0番号总数: ",
			currentCarCount,
			"  ",
			(0, import_jsx_runtime.jsx)("span", {
				id: "checkBlacklistMsg",
				style: { marginLeft: "10px" }
			})
		] });
	}
	function BlacklistStatusCell({ tipText, statusText }) {
		return (0, import_jsx_runtime.jsx)("span", {
			"data-tip": tipText,
			style: { color: tipText ? "#cc4444" : void 0 },
			children: statusText
		});
	}
	function BlacklistUrlTypeCell({ hasTag }) {
		return (0, import_jsx_runtime.jsx)("span", {
			style: { color: hasTag ? "#cc4444" : void 0 },
			children: hasTag ? "按所选分类屏蔽" : "未筛选分类"
		});
	}
	function buildBlacklistTableOptions(plugin, data) {
		return {
			...createTabulatorOptions([
				{
					title: "演员",
					field: "name",
					sorter: "string",
					minWidth: 100,
					responsive: 0,
					headerSort: false,
					formatter: (cell, _formatterParams, _onRendered) => {
						const rowData = cell.getData();
						return jsxToString((0, import_jsx_runtime.jsx)(BlacklistNameCell, {
							url: rowData.url,
							name: rowData.name
						}));
					}
				},
				{
					title: "性别角色",
					field: "role",
					sorter: "string",
					width: 120,
					responsive: 5,
					formatter: (cell, _formatterParams, _onRendered) => {
						const role = cell.getData().role;
						let roleText = role;
						if (role === "actor") roleText = "男演员";
						else if (role === "actress") roleText = "女演员";
						return roleText;
					}
				},
				{
					title: "影视类别",
					field: "movieType",
					sorter: "string",
					width: 120,
					responsive: 5,
					formatter: (cell, _formatterParams, _onRendered) => {
						const movieType = cell.getData().movieType;
						let movieTypeText = movieType;
						if (movieType === "censored") movieTypeText = "有码";
						else if (movieType === "uncensored") movieTypeText = "无码";
						return movieTypeText;
					}
				},
				{
					title: "屏蔽类型",
					field: "url",
					sorter: "string",
					minWidth: 120,
					responsive: 4,
					visible: isJavdbSite,
					formatter: (cell, _formatterParams, _onRendered) => {
						return jsxToString((0, import_jsx_runtime.jsx)(BlacklistUrlTypeCell, { hasTag: cell.getData().url.includes("t=") }));
					}
				},
				{
					title: "番号数量",
					field: "count",
					sorter: "number",
					width: 170,
					responsive: 1
				},
				{
					title: "创建时间",
					field: "createTime",
					sorter: "string",
					width: 170,
					responsive: 5
				},
				{
					title: "最后发行时间",
					field: "lastPublishTime",
					sorter: "string",
					width: 170,
					responsive: 1
				},
				{
					title: "状态",
					field: "isUnCheck",
					sorter: "string",
					width: 120,
					responsive: 1,
					formatter: (cell, _formatterParams, _onRendered) => {
						let tipText = "";
						let statusText = "正常检测";
						if (cell.getData().isUnCheck) {
							tipText = `停更${plugin.checkBlacklist_ruleTime / 24 / 365}年以上, 下轮任务不再进行检测`;
							statusText = "停止检测";
						}
						return jsxToString((0, import_jsx_runtime.jsx)(BlacklistStatusCell, {
							tipText,
							statusText
						}));
					}
				},
				{
					title: "操作",
					sorter: "string",
					cssClass: "action-cell-dropdown",
					minWidth: 150,
					responsive: 0,
					headerSort: false,
					formatter: (cell, _formatterParams, onRendered) => {
						const rowData = cell.getData();
						onRendered(() => {
							const deleteBtn = cell.getElement().querySelector(".delete-btn");
							if (deleteBtn != null) deleteBtn.addEventListener("click", (event) => {
								const name = rowData.name;
								const starId = rowData.starId;
								if (name) if (starId) utils.q(event, `是否移除对 ${name} 的屏蔽?`, async () => {
									await storageManager.removeBlacklistCarList(starId);
									await storageManager.deleteBlacklistItem(starId);
									show.info("操作成功");
									plugin.reloadTable().then();
								});
								else show.error("获取starId失败");
								else show.error("获取名称失败");
							});
							const keywordBtn = cell.getElement().querySelector(".keyword-btn");
							if (keywordBtn != null) keywordBtn.addEventListener("click", () => {
								const prefixCounts = rowData.carList.reduce((acc, carItem) => {
									const prefix = carItem.carNum.split("-")[0] + "-";
									acc[prefix] = (acc[prefix] || 0) + 1;
									return acc;
								}, {});
								const sortedPrefixes = Object.entries(prefixCounts).map(([prefix, count]) => ({
									prefix,
									count
								})).sort((a, b) => b.count - a.count);
								console.log(sortedPrefixes);
							});
						});
						return jsxToString((0, import_jsx_runtime.jsx)(BlacklistActionCell, {}));
					}
				}
			], data),
			pagination: true,
			paginationMode: "local",
			paginationSize: 20,
			paginationSizeSelector: [
				20,
				50,
				100,
				1e3,
				99999
			],
			paginationCounter: (_pageSize, _pageNo, _maxPage, actorCount, _pages) => jsxToString((0, import_jsx_runtime.jsx)(BlacklistPaginationCounter, {
				actorCount,
				currentCarCount: plugin.currentCarCount
			})),
			index: "starId",
			initialSort: [{
				column: "createTime",
				dir: "desc"
			}]
		};
	}
	function MovieListWrapper({ html, nextUrl }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", {
			className: "movie-list",
			dangerouslySetInnerHTML: { __html: html }
		}), nextUrl ? (0, import_jsx_runtime.jsx)("a", {
			className: "pagination-next",
			href: nextUrl
		}) : null] });
	}
	async function filterAllVideo(plugin, names, $dom) {
		let items;
		let nextPageHref;
		if ($dom) {
			items = $dom.find(plugin.getSelector().requestDomItemSelector);
			nextPageHref = $dom.find(plugin.getSelector().nextPageSelector).attr("href");
		} else {
			items = $(plugin.getSelector().itemSelector);
			nextPageHref = $(plugin.getSelector().nextPageSelector).attr("href");
		}
		if (nextPageHref && items.length === 0) failWithToast("解析列表失败");
		for (const itemEl of items) {
			const $item = $(itemEl);
			const { carNum, url, publishTime } = plugin.getBean("ListPagePlugin").findCarNumAndHref($item);
			if (url && carNum) try {
				if (await storageManager.getCar(carNum)) continue;
				await storageManager.saveCar({
					carNum,
					url,
					names,
					actionType: FILTER_ACTION,
					publishTime
				});
				clog.log("屏蔽演员番号", names, carNum);
			} catch (error) {
				clog.error(`保存失败 [${carNum}]:`, error);
			}
		}
		if (nextPageHref) {
			show.info("请不要关闭窗口, 正在解析下一页:" + nextPageHref);
			await new Promise((resolve) => setTimeout(resolve, 500));
			const pageHtml = await gmHttp.get(nextPageHref);
			const domParser = new DOMParser();
			await filterAllVideo(plugin, names, $(domParser.parseFromString(String(pageHtml), "text/html")));
		} else {
			show.ok("执行结束!");
			refresh();
		}
	}
	async function filterActorVideo(plugin, name, starId, $dom) {
		const { nextPageLink } = await parseAndSaveFilterInfo(plugin, $dom, name, starId);
		plugin.nextPageLink = nextPageLink;
		if (nextPageLink) {
			let nextDom;
			plugin.lastPageLink = nextPageLink;
			show.info("请不要关闭窗口, 正在解析下一页:" + nextPageLink);
			const pageNum = utils.getUrlParam(nextPageLink, "page") || 0;
			const beyond60Plugin = plugin.getBean("Beyond60Plugin");
			if (isJavdbSite && beyond60Plugin && Number(pageNum) > 60) {
				const { html, nextUrl, hasMore: _hasMore } = await beyond60Plugin.handleBeyond60(nextPageLink);
				const wrapperHtml = jsxToString((0, import_jsx_runtime.jsx)(MovieListWrapper, {
					html,
					nextUrl
				}));
				nextDom = utils.htmlTo$dom(wrapperHtml);
			} else {
				clog.log("正在请求下一页内容:", nextPageLink);
				const pageHtml = await gmHttp.get(nextPageLink);
				nextDom = utils.htmlTo$dom(String(pageHtml));
			}
			await filterActorVideo(plugin, name, starId, nextDom);
		} else {
			show.ok("执行结束!");
			refresh();
		}
	}
	async function parseAndSaveFilterInfo(plugin, $dom, names, starId) {
		let items;
		let nextPageHref;
		if ($dom) {
			const siteType = JAVDB;
			items = $dom.find(plugin.getSelector(siteType).requestDomItemSelector);
			nextPageHref = $dom.find(plugin.getSelector(siteType).nextPageSelector).attr("href");
		} else {
			items = $(plugin.getSelector().itemSelector);
			nextPageHref = $(plugin.getSelector().nextPageSelector).attr("href");
		}
		if (nextPageHref && items.length === 0) return {
			nextPageLink: void 0,
			lastPublishTime: null
		};
		const carList = [];
		let lastPublishTime = null;
		for (const itemEl of items) {
			const $item = $(itemEl);
			const { carNum, url, publishTime } = plugin.getBean("ListPagePlugin").findCarNumAndHref($item);
			lastPublishTime ||= publishTime;
			if (url && carNum) carList.push({
				carNum,
				url,
				names,
				actionType: FILTER_ACTION,
				starId: starId ?? void 0,
				publishTime
			});
		}
		try {
			await storageManager.batchSaveBlacklistCarList(carList);
		} catch (error) {
			clog.error("保存失败:", error);
		}
		return {
			nextPageLink: nextPageHref,
			lastPublishTime
		};
	}
	function BlacklistConfirmMessage({ tagName, name, isAlreadyBlacklisted, isActress, notFirstPageByQuery }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			isAlreadyBlacklisted ? isActress ? "演员 " : "分类 " : isActress ? "是否将该演员 " : "是否将分类 ",
			(0, import_jsx_runtime.jsx)("span", {
				style: { color: "#f40" },
				children: isActress ? name : tagName
			}),
			isAlreadyBlacklisted ? " 已在黑名单中, 是否从当前页开始追加屏蔽?" : " 加入到黑名单中?",
			notFirstPageByQuery && (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("br", {}), " 注意: 当前页面非第一页, 屏蔽数据将从此页面开始"] })
		] });
	}
	async function addBlacklist(plugin, event) {
		const position = {
			clientX: event.clientX,
			clientY: event.clientY + 80
		};
		const isAlreadyBlacklisted = $("#addBlacklistBtn span").text().includes("已加入");
		let blacklistInfo;
		let isActress;
		let tagName = "";
		if (currentHref.includes("/tags")) {
			const tagUrl = new URL(currentHref);
			tagUrl.searchParams.delete("page");
			tagName = $("#jhs-check-tag").text().trim();
			blacklistInfo = {
				starId: "no-" + tagName,
				name: "虚拟演员-" + tagName,
				allName: ["虚拟演员"],
				role: "虚拟演员",
				movieType: tagName,
				blacklistUrl: tagUrl.toString()
			};
			isActress = false;
		} else {
			blacklistInfo = plugin.getActressPageInfo();
			isActress = true;
		}
		const { starId, name, allName, role, movieType, blacklistUrl } = blacklistInfo;
		const notFirstPageByQuery = currentHref.includes("page") && !currentHref.includes("page=1");
		const confirmMessage = jsxToString((0, import_jsx_runtime.jsx)(BlacklistConfirmMessage, {
			tagName,
			name,
			isAlreadyBlacklisted,
			isActress,
			notFirstPageByQuery
		}));
		utils.q(position, confirmMessage, async () => {
			navigator.locks.request("checkNewActressActorFilterCar", { ifAvailable: true }, async (lock) => {
				clog.debug("获取锁", lock);
				if (lock) {
					plugin.loadObj = loading();
					try {
						await storageManager.addBlacklistItem({
							starId: starId ?? void 0,
							name,
							allName,
							role,
							movieType,
							url: blacklistUrl ?? void 0
						});
						await plugin.filterActorVideo(name, starId);
						const okShow = show.ok(`屏蔽结束,是否跳转到最后一页: ${plugin.lastPageLink}`, {
							duration: -1,
							close: true,
							onClick: () => {
								okShow.closeShow?.();
								window.location.href = plugin.lastPageLink;
							}
						});
					} catch (error) {
						clog.error(error);
						const errorShow = show.error("发生错误, 是否填转到解析失败的那一页? (点击并跳转)", {
							duration: -1,
							close: true,
							onClick: () => {
								errorShow.closeShow?.();
								window.location.href = plugin.nextPageLink;
							}
						});
					} finally {
						plugin.loadObj.close();
					}
				} else show.error("当前有定时任务在后台执行中, 无法发起此操作");
			}).catch((lockError) => {
				clog.error("锁任务出现错误:", lockError);
			});
		});
	}
	function BlacklistDataTypeOptions({ totalCount, actorCount, actressCount }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsxs)("option", {
				value: "",
				children: [
					"所有 (",
					totalCount,
					")"
				]
			}),
			(0, import_jsx_runtime.jsxs)("option", {
				value: "actor",
				children: [
					"男演员 (",
					actorCount,
					")"
				]
			}),
			(0, import_jsx_runtime.jsxs)("option", {
				value: "actress",
				children: [
					"女演员 (",
					actressCount,
					")"
				]
			})
		] });
	}
	async function getTableData(plugin) {
		const blacklist = await storageManager.getBlacklist();
		const blacklistCars = await storageManager.getBlacklistCarList();
		const searchValue = $("#searchValue").val();
		const statusType = $("#statusType").val();
		const $dataTypeSelect = $("#dataType");
		const dataType = $dataTypeSelect.val();
		const urlType = $("#urlType").val();
		const totalCount = blacklist.length;
		let actorCount = 0;
		let actressCount = 0;
		const enrichedList = blacklist.map((item) => {
			if (item.role === "actor") actorCount++;
			else if (item.role === "actress") actressCount++;
			let isUnCheck = false;
			if (item.lastPublishTime) isUnCheck = !utils.isUnnecessaryCheck(item.lastPublishTime, plugin.checkBlacklist_ruleTime);
			return {
				...item,
				isUnCheck
			};
		}).filter((item) => (!searchValue || !!item.name.includes(searchValue)) && (statusType !== "normal" || !item.isUnCheck) && (statusType !== "stop" || !!item.isUnCheck) && (dataType ? item.role === dataType : (urlType !== "hasT" || !!item.url.includes("t=")) && (urlType !== "noT" || !item.url.includes("t="))));
		$dataTypeSelect.html(jsxToString((0, import_jsx_runtime.jsx)(BlacklistDataTypeOptions, {
			totalCount,
			actorCount,
			actressCount
		})));
		$dataTypeSelect.val(dataType);
		const carsByStarId = new Map();
		for (const carItem of blacklistCars) {
			const starId = carItem.starId;
			if (!carsByStarId.has(starId)) carsByStarId.set(starId, []);
			carsByStarId.get(starId).push(carItem);
		}
		const finalData = enrichedList.map((item) => {
			const starId = item.starId;
			const cars = carsByStarId.get(starId) || [];
			return {
				...item,
				carList: cars,
				count: cars.length
			};
		});
		plugin.currentCarCount = finalData.reduce((sum, row) => sum + (row.count || 0), 0);
		return finalData;
	}
	function BlacklistDialog({ showUrlType }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				padding: "10px 20px",
				height: "100%",
				overflow: "hidden"
			},
			children: [(0, import_jsx_runtime.jsxs)("div", {
				style: {
					display: "flex",
					justifyContent: "space-between"
				},
				children: [(0, import_jsx_runtime.jsx)("div", { style: {
					display: "flex",
					gap: "5px"
				} }), (0, import_jsx_runtime.jsxs)("div", {
					style: {
						display: "flex",
						gap: "5px"
					},
					children: [
						(0, import_jsx_runtime.jsxs)("select", {
							id: "dataType",
							style: {
								textAlign: "center",
								minWidth: "150px"
							},
							children: [
								(0, import_jsx_runtime.jsx)("option", {
									value: "",
									selected: true,
									children: "所有"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "actor",
									children: "男演员"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "actress",
									children: "女演员"
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("select", {
							id: "statusType",
							style: {
								textAlign: "center",
								minWidth: "150px"
							},
							children: [
								(0, import_jsx_runtime.jsx)("option", {
									value: "",
									selected: true,
									children: "--检测状态--"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "normal",
									children: "正常检测"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "stop",
									children: "停止检测"
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("select", {
							id: "urlType",
							"data-tip": "在演员页屏蔽时,是否选择了分类",
							style: {
								textAlign: "center",
								minWidth: "150px",
								display: showUrlType ? void 0 : "none"
							},
							children: [
								(0, import_jsx_runtime.jsx)("option", {
									value: "",
									selected: true,
									children: "--屏蔽类型--"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "hasT",
									children: "按所选分类屏蔽"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "noT",
									children: "未筛选分类"
								})
							]
						}),
						(0, import_jsx_runtime.jsx)("input", {
							id: "searchValue",
							type: "text",
							placeholder: "搜索演员",
							style: { padding: "4px 5px" }
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "cleanQueryBtn",
							className: "a-info",
							style: { marginLeft: "0" },
							children: "重置"
						})
					]
				})]
			}), (0, import_jsx_runtime.jsx)("div", {
				id: "table-container",
				style: { height: "calc(100% - 50px)" }
			})]
		});
	}
	var BlacklistPlugin = class extends BasePlugin {
		loadObj = null;
		tableObj;
		nextPageLink;
		lastPageLink;
		checkBlacklist_ruleTime = 8760;
		currentCarCount = 0;
		getName() {
			return "BlacklistPlugin";
		}
		async addBlacklist(event) {
			return addBlacklist(this, event);
		}
		async resetBtnTip() {
			this.checkBlacklist_ruleTime = await storageManager.getSetting("checkBlacklist_ruleTime", 8760);
		}
		async openBlacklistDialog() {
			const dialogHtml = jsxToString((0, import_jsx_runtime.jsx)(BlacklistDialog, { showUrlType: isJavdbSite }));
			layer.open({
				type: 1,
				title: "演员黑名单",
				content: dialogHtml,
				scrollbar: false,
				area: utils.getResponsiveArea(["80%", "90%"]),
				anim: -1,
				success: async (_layerEl) => {
					await this.loadTableData();
					$(".layui-layer-content").on("click", "#cleanQueryBtn", async (_event) => {
						$("#searchValue").val("");
						$("#dataType").val("");
						$("#statusType").val("");
						await this.reloadTable();
					}).on("focusout keydown", "#searchValue", async (event) => {
						if (event.type === "focusout" || event.key === "Enter") {
							if (event.key === "Enter") event.preventDefault();
							if (event.type === "keydown" && event.key !== "Enter") return;
							$("#dataType").val("");
							await this.reloadTable();
						}
					}).on("change", "#dataType", async () => {
						$("#searchValue").val("");
						await this.reloadTable();
					}).on("change", "#statusType", async () => {
						await this.reloadTable();
					}).on("change", "#urlType", async () => {
						await this.reloadTable();
					}).on("click", ".open-url", (event) => {
						event.preventDefault();
						const $link = $(event.currentTarget);
						const url = $link.attr("data-url");
						const name = $link.attr("data-name");
						utils.openPage(url ?? "", name ?? "", true, event);
					});
				},
				end: () => {
					if (this.tableObj) {
						this.tableObj.destroy();
						this.tableObj = null;
					}
					refresh();
				}
			});
		}
		async reloadTable() {
			if (!this.tableObj) return;
			const data = await this.getTableData();
			this.tableObj.setData(data);
		}
		async getTableData() {
			return getTableData(this);
		}
		async loadTableData() {
			this.checkBlacklist_ruleTime = await storageManager.getSetting("checkBlacklist_ruleTime") || 8760;
			const data = await this.getTableData();
			this.tableObj = new Tabulator("#table-container", buildBlacklistTableOptions(this, data));
		}
		getCurrentStarUrl() {
			let url = window.location.href.replace(/([&?])sort_type=[^&]+(&|$)/, "$1");
			url = url.replace(/[&?]$/, "");
			url = url.replace(/\?&/, "?");
			let result = url;
			result = result.replace(/([&?])page=\d+(&|$)/, "$1");
			result = result.replace(/[&?]$/, "");
			result = result.replace(/\?&/, "?");
			result = result.replace(/\/(\d+)(?:\/(\d+))?(\?|$)/, (match, seg1, seg2, tail) => seg2 !== void 0 ? `/${seg1}${tail}` : match);
			return result;
		}
		parseUrlId(url) {
			if (!url) throw new Error("url未传入");
			return new URL(url).pathname.split("/").filter((seg) => seg.trim() !== "").pop();
		}
		async filterAllVideo(names, $dom) {
			return filterAllVideo(this, names, $dom);
		}
		async filterActorVideo(name, starId, $dom) {
			return filterActorVideo(this, name, starId, $dom);
		}
		async parseAndSaveFilterInfo($dom, names, starId) {
			return parseAndSaveFilterInfo(this, $dom, names, starId);
		}
	};
	function ConfirmWarn({ text }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsx)("br", {}),
			" ",
			(0, import_jsx_runtime.jsx)(ColoredTextCell, {
				text,
				color: "#f40"
			})
		] });
	}
	function WantWatchedHintSpan({ variant }) {
		return (0, import_jsx_runtime.jsxs)("span", {
			style: {
				marginLeft: "8px",
				color: "#888",
				fontSize: "12px"
			},
			children: [
				"(JHS 现已在详情页自动同步\"",
				variant === "want" ? "想看" : "看過",
				"\",本页按钮仅用于初始补录)"
			]
		});
	}
	function WantWatchedImportButton({ variant }) {
		return (0, import_jsx_runtime.jsx)("a", {
			className: variant === "want" ? "a-primary" : "a-success",
			id: "wantWatchBtn",
			style: { padding: "10px" },
			children: "导入至 JHS"
		});
	}
	var WantAndWatchedVideosPlugin = class extends BasePlugin {
		type = null;
		currentPage = 1;
		getName() {
			return "WantAndWatchedVideosPlugin";
		}
		async handle() {
			if (window.location.href.includes("/want_watch_videos")) {
				$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedImportButton, { variant: "want" })));
				$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedHintSpan, { variant: "want" })));
				$("#wantWatchBtn").on("click", (clickEvent) => {
					this.type = FAVORITE_ACTION;
					this.importWantWatchVideos(clickEvent, "是否将 想看的影片 导入到 JHS-收藏?");
				});
			}
			if (window.location.href.includes("/watched_videos")) {
				$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedImportButton, { variant: "watched" })));
				$("h3").append(jsxToString((0, import_jsx_runtime.jsx)(WantWatchedHintSpan, { variant: "watched" })));
				$("#wantWatchBtn").on("click", (clickEvent) => {
					this.type = HAS_WATCH_ACTION;
					this.importWantWatchVideos(clickEvent, "是否将 看过的影片 导入到 JHS-已观看?");
				});
			}
		}
		importWantWatchVideos(_clickEvent, confirmMessage) {
			utils.q(null, confirmMessage + " " + jsxToString((0, import_jsx_runtime.jsx)(ConfirmWarn, { text: "执行此功能前请记得备份数据" })), async () => {
				await withLoading(async () => {
					this.currentPage = 1;
					await this.parseMovieList();
				}).catch((error) => {
					clog.error(error);
				});
			});
		}
		async parseMovieList(rootEl) {
			if (featureFlags.wantWatchBatchImport) {
				await this.parseMovieListBatch(rootEl);
				return;
			}
			let itemElements;
			let nextPageHref;
			if (rootEl) {
				itemElements = rootEl.find(this.getSelector().itemSelector);
				nextPageHref = rootEl.find(".pagination-next").attr("href") ?? "";
			} else {
				itemElements = $(this.getSelector().itemSelector);
				nextPageHref = $(".pagination-next").attr("href") ?? "";
			}
			for (const rawItem of itemElements) {
				const $item = $(rawItem);
				const href = $item.find("a").attr("href") ?? "";
				const carNum = $item.find(".video-title strong").text().trim();
				const metaText = $item.find(".meta").text().trim();
				if (href && carNum) try {
					if (await storageManager.getCar(carNum)) {
						show.info(`${carNum} 已存在, 跳过`);
						continue;
					}
					await storageManager.saveCar({
						carNum,
						url: href,
						names: void 0,
						actionType: this.type,
						publishTime: metaText ?? void 0
					});
				} catch (error) {
					clog.error(`保存失败 [${carNum}]:`, error);
				}
			}
			if (nextPageHref) {
				show.info("发现下一页,正在解析:", nextPageHref);
				await new Promise((resolve) => setTimeout(resolve, 1e3));
				$.ajax({
					url: nextPageHref,
					method: "GET",
					success: (responseHtml) => {
						const domParser = new DOMParser();
						const $parsedDom = $(domParser.parseFromString(responseHtml, "text/html"));
						this.parseMovieList($parsedDom);
					},
					error: function(request) {
						clog.error(request);
						show.error("加载下一页失败:" + request.message);
					}
				});
			} else {
				show.ok("导入结束!");
				refresh();
			}
		}
		async parseMovieListBatch(rootEl) {
			const container = rootEl || $("body");
			const movieList = container.find(this.getSelector().itemSelector);
			const nextPageLink = container.find(".pagination-next").attr("href");
			if (movieList.length === 0) {
				show.ok("导入结束!");
				refresh();
				return;
			}
			show.info(`正在处理第 ${this.currentPage} 页...`);
			const allLocalCars = await storageManager.getCarList();
			const carNumCache = new Set(allLocalCars.map((c) => featureFlags.caseInsensitiveCarNum ? c.carNum.toLowerCase() : c.carNum));
			const currentPageRecords = [];
			movieList.each((_i, element) => {
				const item = $(element);
				const carNum2 = item.find(".video-title strong").text().trim();
				const href = item.find("a").attr("href");
				const publishTime = item.find(".meta").text().trim();
				const key = featureFlags.caseInsensitiveCarNum ? carNum2.toLowerCase() : carNum2;
				if (carNum2 && href && !carNumCache.has(key)) {
					currentPageRecords.push({
						carNum: carNum2,
						url: href,
						names: null,
						actionType: this.type,
						publishTime
					});
					carNumCache.add(key);
				}
			});
			if (currentPageRecords.length > 0) try {
				await storageManager.saveCarList(currentPageRecords);
				clog.log(`第 ${this.currentPage} 页:成功写入 ${currentPageRecords.length} 条`);
			} catch (e) {
				clog.error("批量保存失败:", e);
			}
			this.currentPage++;
			if (!nextPageLink) {
				show.ok("导入结束!");
				refresh();
				return;
			}
			await new Promise((resolve) => setTimeout(resolve, 200));
			try {
				const html = await gmHttp.get(nextPageLink);
				const next$dom = utils.htmlTo$dom(String(html));
				await this.parseMovieListBatch(next$dom);
			} catch (e) {
				clog.error("请求下一页失败", e);
				show.error("加载下一页失败");
			}
		}
	};
	function RelatedItem({ index, relatedId, name, movieCount, collectionCount, viewCount, createTime }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "item columns is-desktop",
			style: {
				display: "block",
				marginTop: "6px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px",
				wordBreak: "break-word",
				position: "relative"
			},
			children: [
				(0, import_jsx_runtime.jsxs)("span", {
					style: {
						position: "absolute",
						top: "5px",
						right: "10px",
						color: "#999",
						fontSize: "12px"
					},
					children: ["#", index]
				}),
				(0, import_jsx_runtime.jsxs)("span", {
					style: {
						position: "absolute",
						bottom: "5px",
						right: "10px",
						color: "#999",
						fontSize: "12px"
					},
					children: ["创建时间: ", createTime]
				}),
				(0, import_jsx_runtime.jsx)("p", { children: (0, import_jsx_runtime.jsx)("a", {
					href: `/lists/${relatedId}`,
					target: "_blank",
					style: { color: "#2e8abb" },
					children: name
				}) }),
				(0, import_jsx_runtime.jsxs)("p", {
					style: { marginTop: "5px" },
					children: ["视频个数: ", movieCount]
				}),
				(0, import_jsx_runtime.jsxs)("p", {
					style: { marginTop: "5px" },
					children: [
						"收藏次数: ",
						collectionCount,
						" 被查看次数: ",
						viewCount
					]
				})
			]
		});
	}
	var RelatedPlugin = class extends BasePlugin {
		floorIndex = 1;
		isInit = false;
		getName() {
			return "RelatedPlugin";
		}
		async showRelated(container, movieId) {
			const isExpanded = await storageManager.getSetting("enableLoadRelated", "no");
			const target = container || $("#magnets-content");
			target.append(jsxToString((0, import_jsx_runtime.jsx)(SectionHeader, {
				title: "相关清单",
				foldId: "relatedFold",
				linkColor: "#1897ff",
				foldText: isExpanded === "yes" ? "折叠" : "展开",
				iconText: isExpanded === "yes" ? "▲" : "▼"
			})));
			$("#relatedFold").on("click", (event) => {
				event.preventDefault();
				event.stopPropagation();
				const toggleText = $("#relatedFold .toggle-text");
				const toggleIcon = $("#relatedFold .toggle-icon");
				const isExpand = toggleText.text() === "展开";
				toggleText.text(isExpand ? "折叠" : "展开");
				toggleIcon.text(isExpand ? "▲" : "▼");
				if (isExpand) {
					$("#relatedContainer").show();
					$("#relatedFooter").show();
					if (!this.isInit) {
						this.fetchAndDisplayRelateds(movieId);
						this.isInit = true;
					}
					storageManager.saveSettingItem("enableLoadRelated", "yes");
				} else {
					$("#relatedContainer").hide();
					$("#relatedFooter").hide();
					storageManager.saveSettingItem("enableLoadRelated", "no");
				}
			});
			target.append(jsxToString((0, import_jsx_runtime.jsx)(SectionContainers, {
				containerId: "relatedContainer",
				footerId: "relatedFooter"
			})));
			if (isExpanded === "yes") await this.fetchAndDisplayRelateds(movieId);
		}
		async fetchAndDisplayRelateds(movieId) {
			const container = $("#relatedContainer");
			const footer = $("#relatedFooter");
			container.append(jsxToString((0, import_jsx_runtime.jsx)(SectionStatusMessage, {
				text: "获取清单中...",
				id: "relatedLoading"
			})));
			const limit = 20;
			let list = null;
			try {
				list = await fetchRelatedCollections(movieId, 1, limit);
			} catch (err) {
				if (String(err).includes("簽名已過期")) show.error("生成签名失败, 请检查系统时间及时区是否正确!");
				clog.error("获取清单失败:", err);
			} finally {
				$("#relatedLoading").remove();
			}
			if (!list) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(SectionErrorMessage, {
					text: "获取清单失败",
					retryId: "retryFetchRelateds",
					linkColor: "#1897ff"
				})));
				$("#retryFetchRelateds").on("click", async () => {
					$("#retryFetchRelateds").parent().remove();
					await this.fetchAndDisplayRelateds(movieId);
				});
				return;
			}
			if (list.length === 0) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(SectionStatusMessage, { text: "无清单" })));
				return;
			}
			this.displayRelateds(list, container);
			if (list.length === limit) {
				footer.html(jsxToString((0, import_jsx_runtime.jsx)(SectionLoadMore, {
					loadMoreId: "loadMoreRelateds",
					endId: "relatedEnd",
					text: "加载更多清单",
					endText: "已加载全部清单"
				})));
				let page = 1;
				const loadMoreBtn = $("#loadMoreRelateds");
				loadMoreBtn.on("click", async () => {
					let moreList;
					loadMoreBtn.text("加载中...").prop("disabled", true);
					page++;
					try {
						moreList = await fetchRelatedCollections(movieId, page, limit);
					} catch (err) {
						clog.error("加载更多清单失败:", err);
					} finally {
						loadMoreBtn.text("加载失败, 请点击重试").prop("disabled", false);
					}
					if (moreList) {
						this.displayRelateds(moreList, container);
						if (moreList.length < limit) {
							loadMoreBtn.remove();
							$("#relatedEnd").show();
						} else loadMoreBtn.text("加载更多清单").prop("disabled", false);
					}
				});
			} else footer.html(jsxToString((0, import_jsx_runtime.jsx)(SectionEndMessage, { text: "已加载全部清单" })));
		}
		displayRelateds(list, container) {
			if (list.length) list.forEach((item) => {
				const html = jsxToString((0, import_jsx_runtime.jsx)(RelatedItem, {
					index: this.floorIndex++,
					relatedId: item.relatedId,
					name: item.name,
					movieCount: item.movieCount,
					collectionCount: item.collectionCount,
					viewCount: item.viewCount,
					createTime: item.createTime
				}));
				container.append(html);
			});
		}
	};
	function FavoriteActressAvatarColumn() {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "column actor-avatar",
			children: (0, import_jsx_runtime.jsx)("div", {
				className: "image",
				children: (0, import_jsx_runtime.jsx)("span", { className: "avatar" })
			})
		});
	}
	var FavoriteActressesPlugin = class extends BasePlugin {
		getName() {
			return "FavoriteActressesPlugin";
		}
		async initCss() {
			const settings = await storageManager.getSetting();
			return fold_category_plugin_default.replace("__HIGHLIGHTED_TAG_NUMBER__", String(settings.highlightedTagNumber || 1)).replace("__HIGHLIGHTED_TAG_COLOR__", settings.highlightedTagColor || "#ce2222");
		}
		async handle() {
			this.bindEvent();
			await this.highlightActress();
			this.replaceActressAvatar();
		}
		async highlightActress() {
			if (!window.isDetailPage) return;
			if (await storageManager.getSetting("enableFavoriteActresses", "yes") !== "yes") return;
			const favoriteActresses = await storageManager.getFavoriteActressList();
			if (!favoriteActresses || favoriteActresses.length === 0) return;
			const starIdSet = new Set();
			favoriteActresses.forEach((actress) => {
				if (actress.starId) starIdSet.add(String(actress.starId).trim());
			});
			if (starIdSet.size !== 0) $(".female").prev().each((_index, element) => {
				const $link = $(element);
				const href = $link.attr("href");
				let urlStarId = null;
				if (href) {
					const segments = (href.endsWith("/") ? href.slice(0, -1) : href).split("/");
					const lastSegment = segments[segments.length - 1];
					if (lastSegment) urlStarId = lastSegment.trim();
				}
				let isFavorite = false;
				if (urlStarId) isFavorite = starIdSet.has(urlStarId);
				if (isFavorite) {
					$link.addClass("highlighted");
					$link.attr("title", "高亮已收藏演员, 可在设置-基础配置中关闭");
				}
			});
		}
		async removeActorFromStorage(starId) {
			if (await storageManager.removeFavoriteActress(starId)) clog.log("移除演员成功");
		}
		bindEvent() {
			const actorIdRegex = /\/actors\/(\w+)\/(collect|uncollect)/;
			$(document).on("confirm:complete", "a[href*=\"/actors/\"][href*=\"/uncollect\"]", async (event) => {
				const [confirmResult] = event.detail;
				if (!confirmResult) return;
				const match = $(event.currentTarget).attr("href")?.match(actorIdRegex);
				const actorId = match ? match[1] : null;
				if (actorId) await this.removeActorFromStorage(actorId);
			});
			$("#button-collect-actor").click(async (_event) => {
				const match = $("#button-collect-actor").attr("href")?.match(actorIdRegex);
				const actorId = match ? match[1] : null;
				const actressNames = [];
				const $nameSection = $(".actor-section-name");
				if ($nameSection.length) $nameSection.text().trim().split(",").forEach((name) => {
					actressNames.push(name.trim());
				});
				const $metaSection = $(".section-meta:not(:contains('影片'))");
				if ($metaSection.length) $metaSection.text().trim().split(",").forEach((name) => {
					actressNames.push(name.trim());
				});
				if (!actressNames) {
					clog.error("获取演员名称失败");
					return;
				}
				const firstName = actressNames[0];
				if (!actorId) {
					clog.error("无法获取演员ID进行收藏操作。");
					return;
				}
				const actressData = {
					starId: actorId,
					name: firstName,
					allName: actressNames,
					avatar: ($(".avatar").first().css("background-image") || "").replace(/^url\(["']?|["']?\)$/g, "")
				};
				if (await storageManager.addFavoriteActressList([actressData]) === 1) clog.log(`收藏演员成功: ${firstName} (ID: ${actorId})`);
				else clog.log(`收藏演员失败: ${firstName} (ID: ${actorId})`);
			});
			$("#button-uncollect-actor").click(async (_event) => {
				const match = $("#button-uncollect-actor").attr("href")?.match(actorIdRegex);
				const actorId = match ? match[1] : null;
				if (actorId) await this.removeActorFromStorage(actorId);
				else clog.error("无法获取演员ID进行取消收藏操作。");
			});
		}
		async replaceActressAvatar() {
			const actressId = this.getActressId();
			if (!actressId) return;
			const matchedActress = (await storageManager.getFavoriteActressList()).find((actress) => actress.starId === actressId);
			if (matchedActress && matchedActress.avatar) {
				const cssUrl = `url('${matchedActress.avatar}')`;
				let $avatar = $(".avatar").first();
				if ($avatar.length === 0) {
					const avatarColumnHtml = jsxToString((0, import_jsx_runtime.jsx)(FavoriteActressAvatarColumn, {}));
					$(".section-columns").prepend(avatarColumnHtml);
					$avatar = $(".avatar").first();
				}
				if ($avatar.length === 0) return;
				if ($avatar.css("background-image").trim().toLowerCase() !== cssUrl.trim().toLowerCase()) {
					$avatar.css("background-image", cssUrl);
					$avatar.css("background-size", "cover");
					$avatar.css("background-position", "top center");
					$avatar.css("background-repeat", "no-repeat");
				}
			}
		}
	};
	function ActressCard({ starId, avatar, name, allNameText, actressUrl, lastCheckTime, lastPublishTime, isStale, ruleTimeYears, remark, editSvg, deleteSvg, btnStyle, typeLabel, typeColor, newVideoCount }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "actress-card",
			"data-starId": starId,
			style: {
				...isStale ? { background: "#d4cece" } : null,
				minHeight: "370px"
			},
			children: [
				(0, import_jsx_runtime.jsx)("a", {
					href: actressUrl,
					target: "_blank",
					style: {
						textDecoration: "none",
						color: "inherit",
						display: "block",
						flexGrow: 1
					},
					children: (0, import_jsx_runtime.jsx)("img", {
						src: avatar,
						alt: allNameText,
						className: "actress-card-avatar"
					})
				}),
				(0, import_jsx_runtime.jsxs)("div", { children: [(0, import_jsx_runtime.jsx)("a", {
					href: actressUrl,
					target: "_blank",
					style: {
						textDecoration: "none",
						color: "inherit",
						display: "block",
						flexGrow: 1
					},
					children: (0, import_jsx_runtime.jsx)("div", {
						className: "actress-card-name",
						children: name
					})
				}), (0, import_jsx_runtime.jsx)("div", {
					className: "actress-card-allname",
					title: allNameText,
					children: allNameText
				})] }),
				(0, import_jsx_runtime.jsx)("div", {
					style: {
						fontSize: "0.8em",
						marginTop: "5px"
					},
					children: (0, import_jsx_runtime.jsxs)("span", { children: ["上次检测: ", lastCheckTime] })
				}),
				(0, import_jsx_runtime.jsx)("div", {
					style: {
						fontSize: "0.8em",
						marginTop: "5px"
					},
					children: (0, import_jsx_runtime.jsxs)("span", { children: ["最后发行作品: ", lastPublishTime] })
				}),
				(0, import_jsx_runtime.jsx)("div", {
					style: {
						fontSize: "0.7em",
						color: "#cc4444",
						marginTop: "5px",
						minHeight: "18px"
					},
					children: (0, import_jsx_runtime.jsx)("span", { children: isStale ? `停更${ruleTimeYears}年以上, 下轮任务不再进行检测` : "" })
				}),
				(0, import_jsx_runtime.jsx)("div", {
					style: {
						fontSize: "0.8em",
						marginTop: "5px",
						color: "#3765c5",
						minHeight: "10px"
					},
					children: (0, import_jsx_runtime.jsx)("span", { children: remark })
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: {
						marginTop: "10px",
						display: "flex",
						justifyContent: "center",
						gap: "10px"
					},
					children: [(0, import_jsx_runtime.jsx)("a", {
						title: "编辑",
						className: "card-btn btn-edit-actress",
						style: btnStyle,
						"data-starId": starId,
						dangerouslySetInnerHTML: { __html: editSvg }
					}), (0, import_jsx_runtime.jsx)("a", {
						title: "取消收藏",
						className: "card-btn btn-delete-actress",
						style: btnStyle,
						"data-starId": starId,
						dangerouslySetInnerHTML: { __html: deleteSvg }
					})]
				}),
				(0, import_jsx_runtime.jsx)("div", {
					className: "card-tag",
					style: { backgroundColor: typeColor },
					children: typeLabel
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					className: "card-new-count-tag",
					"data-tip": `最新作品数量: ${newVideoCount}`,
					children: ["🔔 ", newVideoCount]
				})
			]
		});
	}
	var NAV_BTN_STYLE = {
		padding: "8px 12px",
		margin: "0 5px",
		background: "#f0f0f0",
		border: "1px solid #ddd",
		borderRadius: "4px",
		cursor: "pointer"
	};
	var PAGE_BTN_BASE_STYLE = {
		padding: "8px 12px",
		margin: "0 3px",
		border: "1px solid #ddd",
		borderRadius: "4px",
		cursor: "pointer"
	};
	var ACTIVE_STYLE = {
		background: "#007bff",
		color: "white",
		borderColor: "#007bff"
	};
	function ActressPagination({ totalCount, totalPages, page }) {
		if (totalPages === 0) return (0, import_jsx_runtime.jsx)("span", {
			style: { color: "#666" },
			children: "共 0 条记录"
		});
		let rangeStart = Math.max(1, page - Math.floor(2.5));
		const rangeEnd = Math.min(totalPages, rangeStart + 5 - 1);
		if (rangeEnd - rangeStart < 4) rangeStart = Math.max(1, rangeEnd - 5 + 1);
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			page > 1 && totalPages > 5 && (0, import_jsx_runtime.jsx)("button", {
				className: "pagination-btn",
				"data-page": 1,
				style: NAV_BTN_STYLE,
				children: "首页"
			}),
			page > 1 && (0, import_jsx_runtime.jsx)("button", {
				className: "pagination-btn",
				"data-page": page - 1,
				style: NAV_BTN_STYLE,
				children: "上一页"
			}),
			Array.from({ length: rangeEnd - rangeStart + 1 }, (_, i) => {
				const pageNum = rangeStart + i;
				return (0, import_jsx_runtime.jsx)("button", {
					className: `pagination-btn page-number-btn ${pageNum === page ? "active" : ""}`,
					"data-page": pageNum,
					style: {
						...PAGE_BTN_BASE_STYLE,
						...pageNum === page ? ACTIVE_STYLE : null
					},
					children: pageNum
				}, pageNum);
			}),
			page < totalPages && (0, import_jsx_runtime.jsx)("button", {
				className: "pagination-btn",
				"data-page": page + 1,
				style: NAV_BTN_STYLE,
				children: "下一页"
			}),
			page < totalPages && totalPages > 5 && (0, import_jsx_runtime.jsx)("button", {
				className: "pagination-btn",
				"data-page": totalPages,
				style: NAV_BTN_STYLE,
				children: "尾页"
			}),
			(0, import_jsx_runtime.jsxs)("span", {
				style: {
					marginLeft: "20px",
					color: "#666"
				},
				children: [
					"共 ",
					totalCount,
					" 条记录 (第 ",
					page,
					"/",
					totalPages,
					" 页)"
				]
			})
		] });
	}
	var ACTRESS_TYPE_MAP = {
		[UNCENSORED]: {
			label: "无码",
			color: "#4CAF50"
		},
		[CENSORED]: {
			label: "有码",
			color: "#FF9800"
		}
	};
	var DEFAULT_TYPE = {
		label: "未知",
		color: "#9E9E9E"
	};
	async function renderActressCards(plugin) {
		const $container = $("#actress-card-container");
		if (!$container.length) return;
		let favoriteActresses = await storageManager.getFavoriteActressList();
		const typeFilter = String($("#paramActressType").val() ?? "");
		if (typeFilter !== "all") favoriteActresses = favoriteActresses.filter((actress) => actress.actressType === typeFilter);
		const sortedActresses = utils.genericSort(favoriteActresses, [{
			key: (actress) => actress.newVideoList?.length ?? 0,
			order: "desc"
		}, {
			key: "lastPublishTime",
			order: "desc"
		}]);
		const totalCount = sortedActresses.length;
		const totalPages = Math.ceil(totalCount / plugin.pageSize);
		const startIndex = (plugin.currentPage - 1) * plugin.pageSize;
		const endIndex = startIndex + plugin.pageSize;
		const pageActresses = sortedActresses.slice(startIndex, endIndex);
		const javDbUrl = await plugin.getBean("OtherSitePlugin").getJavDbUrl();
		const ruleTimeHours = await storageManager.getSetting("checkNewVideo_ruleTime") || 8760;
		const cardsHtml = pageActresses.map((actress) => {
			const allNameText = Array.isArray(actress.allName) ? actress.allName.join(",") : "";
			if (Array.isArray(actress.newVideoList)) actress.newVideoList.join(",");
			const actressUrl = `${javDbUrl}/actors/${actress.starId}?t=d`;
			let isStale = false;
			if (actress.lastPublishTime) isStale = !utils.isUnnecessaryCheck(actress.lastPublishTime, ruleTimeHours);
			const typeInfo = ACTRESS_TYPE_MAP[actress.actressType ?? ""] ?? DEFAULT_TYPE;
			let btnStyle = {};
			if (isStale) btnStyle = {
				background: "linear-gradient(145deg, #e0e0e0 0%, #cabdbd 100%)",
				boxShadow: "none"
			};
			return jsxToString((0, import_jsx_runtime.jsx)(ActressCard, {
				starId: actress.starId,
				avatar: actress.avatar || "https://c0.jdbstatic.com/images/actor_unknow.jpg",
				name: actress.name,
				allNameText,
				actressUrl,
				lastCheckTime: actress.lastCheckTime || "",
				lastPublishTime: actress.lastPublishTime || "",
				isStale,
				ruleTimeYears: ruleTimeHours / 24 / 365,
				remark: actress.remark || "",
				editSvg: plugin.editSvg,
				deleteSvg: plugin.deleteSvg,
				btnStyle,
				typeLabel: typeInfo.label,
				typeColor: typeInfo.color,
				newVideoCount: actress.newVideoList?.length || 0
			}));
		}).join("");
		$container.html(cardsHtml);
		$(".btn-delete-actress").off("click").on("click", (event) => {
			event.preventDefault();
			const starId = $(event.currentTarget).attr("data-starId") ?? "";
			const actress = sortedActresses.find((item) => item.starId === starId);
			if (!actress) return;
			utils.q(event, `是否取消收藏 ${actress.name}?`, async () => {
				const uncollectUrl = `${await plugin.getBean("OtherSitePlugin").getJavDbUrl()}/actors/${starId}/uncollect`;
				const csrfToken = document.querySelector("meta[name=csrf-token]")?.getAttribute("content") ?? "";
				const response = await gmHttp.post(uncollectUrl, void 0, { "x-csrf-token": csrfToken });
				if (response.includes("removeClass")) {
					await storageManager.removeFavoriteActress(starId);
					plugin.loadData();
				} else {
					show.error("移除失败");
					clog.error("移除失败,返回值:", response);
				}
			});
		});
		$(".btn-edit-actress").off("click").on("click", (event) => {
			event.preventDefault();
			const starId = $(event.currentTarget).attr("data-starId") ?? "";
			const actress = sortedActresses.find((item) => item.starId === starId);
			if (actress) plugin.editActress(actress);
			else show.error(`未找到 starId 为 ${starId} 的女优记录。`);
		});
		renderPagination$1(plugin, totalCount, totalPages);
		show.ok("加载完成");
	}
	function renderPagination$1(plugin, totalCount, totalPages) {
		const page = plugin.currentPage;
		$("#actress-pagination").html(jsxToString((0, import_jsx_runtime.jsx)(ActressPagination, {
			totalCount,
			totalPages,
			page
		})));
		$(".pagination-btn").off("click").on("click", (event) => {
			if ($(event.currentTarget).is("[disabled]")) return;
			const targetPage = parseInt($(event.currentTarget).data("page"));
			if (targetPage >= 1 && targetPage <= totalPages && targetPage !== plugin.currentPage) {
				plugin.currentPage = targetPage;
				plugin.renderActressCards();
			}
		});
	}
	function AvatarSelectDialog({ avatarUrls }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			id: "gfriends-image-list-container",
			children: [(0, import_jsx_runtime.jsxs)("p", {
				id: "gfriends-prompt",
				style: {
					textAlign: "center",
					fontSize: "15px",
					marginBottom: "15px"
				},
				children: [
					"点击图片即可选择(初始共 ",
					avatarUrls.length,
					" 张)"
				]
			}), (0, import_jsx_runtime.jsx)("div", {
				style: {
					overflowY: "auto",
					height: "calc(100% - 40px)"
				},
				children: (0, import_jsx_runtime.jsx)("div", {
					id: "gfriends-image-list",
					children: avatarUrls.map((url, index) => (0, import_jsx_runtime.jsxs)("div", {
						id: `wrapper-${index}`,
						className: "gfriends-image-item-wrapper",
						children: [(0, import_jsx_runtime.jsx)("img", {
							alt: "",
							src: url,
							"data-url": url,
							className: "gfriends-selectable-img",
							"data-wrapper-id": `wrapper-${index}`
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "gfriends-size-tag",
							"data-size-for": `wrapper-${index}`,
							children: "..."
						})]
					}, index))
				})
			})]
		});
	}
	var avatar_select_dialog_default = "/* 保持上一个回答的美化样式 */\n#gfriends-image-list-container {\n    padding: 15px;\n    height: 100%;\n    box-sizing: border-box;\n    background-color: #f8f9fa;\n}\n\n#gfriends-prompt {\n    color: #555;\n    font-weight: 500;\n    border-bottom: 1px solid #eee;\n    padding-bottom: 10px;\n}\n\n#gfriends-image-list {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 15px;\n    justify-content: center;\n}\n\n.gfriends-image-item-wrapper {\n    width: 160px;\n    height: 225px; /* 增加高度以容纳尺寸标签 */\n    overflow: hidden;\n    border-radius: 6px;\n    box-shadow: 0 4px 8px rgb(0, 0, 0, 0.1);\n    transition:\n        transform 0.2s ease,\n        box-shadow 0.2s ease;\n    cursor: pointer;\n    position: relative;\n    padding-bottom: 25px; /* 为尺寸标签留出空间 */\n}\n\n.gfriends-selectable-img {\n    width: 100%;\n    height: 200px; /* 固定图片高度 */\n    object-fit: cover;\n    border: 3px solid transparent;\n    border-radius: 6px;\n    transition: border 0.2s ease;\n}\n\n.gfriends-image-item-wrapper:hover {\n    transform: translateY(-4px) scale(1.02);\n    box-shadow: 0 8px 16px rgb(0, 0, 0, 0.2);\n}\n\n.gfriends-selectable-img.is-selected {\n    border-color: #ff6347;\n    box-shadow: 0 0 0 3px #ff6347;\n}\n\n/* 新增:尺寸标签样式 */\n.gfriends-size-tag {\n    position: absolute;\n    bottom: 0; /* 定位到图片容器底部 */\n    left: 0;\n    right: 0;\n    height: 25px;\n    line-height: 25px;\n    text-align: center;\n    background-color: rgb(0, 0, 0, 0.7); /* 半透明背景 */\n    color: #fff;\n    font-size: 11px;\n    font-weight: bold;\n    border-bottom-left-radius: 6px;\n    border-bottom-right-radius: 6px;\n    user-select: none;\n}\n";
	async function searchAvatar() {
		const $nameInput = $("#edit-actress-name");
		const $allNameInput = $("#edit-actress-allname");
		const nameText = $nameInput.val().trim();
		const searchNames = $allNameInput.val().trim().split(/[\uff0c,]/).map((name) => name.trim()).filter((name) => name.length > 0);
		if (nameText) searchNames.unshift(nameText);
		if (searchNames.length === 0) {
			show.error("请先填写女优主名称或别名进行搜索。");
			return;
		}
		const loader = loading("正在搜索头像...");
		let avatarUrls = [];
		try {
			avatarUrls = await loadGfriends(searchNames);
		} catch (error) {
			show.error(`头像数据加载或搜索失败: ${error instanceof Error ? error.message : String(error)}`);
			return;
		} finally {
			loader.close();
		}
		if (avatarUrls.length === 0) {
			show.error(`未找到与 '${searchNames.join("、")}' 相关的头像。请检查名称。`);
			return;
		}
		const dialogContent = jsxToString((0, import_jsx_runtime.jsx)(StyleBlock, { css: avatar_select_dialog_default })) + jsxToString((0, import_jsx_runtime.jsx)(AvatarSelectDialog, { avatarUrls }));
		let errorCount = 0;
		layer.open({
			type: 1,
			title: `选择女优头像 (${avatarUrls.length} 张)`,
			area: utils.getResponsiveArea(["900px", "85%"]),
			content: dialogContent,
			btn: ["关闭"],
			success: (layerEl, layerIndex) => {
				const $layer = $(layerEl);
				const $images = $layer.find(".gfriends-selectable-img");
				const $prompt = $layer.find("#gfriends-prompt");
				$images.each((_index, element) => {
					const $img = $(element);
					const wrapperId = String($img.data("wrapper-id") ?? "");
					const $wrapper = $layer.find(`#${wrapperId}`);
					const $sizeTag = $layer.find(`.gfriends-size-tag[data-size-for="${wrapperId}"]`);
					$img.on("load", () => {
						const width = element.naturalWidth;
						const height = element.naturalHeight;
						$sizeTag.text(`${width} x ${height}`);
					});
					$img.on("error", () => {
						$wrapper.remove();
						errorCount++;
						const remaining = avatarUrls.length - errorCount;
						$prompt.text(`点击图片即可选择(已移除 ${errorCount} 张错误图片,剩余 ${remaining} 张)`);
						if (remaining === 0) {
							show.error("所有搜索到的头像链接均已失效,无法选择。");
							layer.close(layerIndex);
						}
					});
					if (element.complete) if (element.naturalWidth > 0) $img.trigger("load");
					else $img.trigger("error");
				});
				$images.on("click", (event) => {
					const $img = $(event.currentTarget);
					const url = String($img.data("url") ?? "");
					$("#edit-actress-avatar").val(url);
					$("#edit-avatar-preview").attr("src", url);
					$images.removeClass("is-selected");
					$img.addClass("is-selected");
					setTimeout(() => {
						layer.close(layerIndex);
					}, 150);
				});
				utils.setupEscClose(layerIndex);
			}
		});
	}
	var LABEL_STYLE$1 = {
		display: "block",
		marginBottom: "5px",
		fontWeight: "bold"
	};
	var FIELD_ROW_STYLE$1 = { marginBottom: "15px" };
	function EditActressDialog({ avatar, name, textareaStyle, allNameText, actressType, newVideoText, remark }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: { padding: "20px" },
			children: [
				(0, import_jsx_runtime.jsxs)("div", {
					style: {
						marginBottom: "15px",
						textAlign: "center"
					},
					children: [(0, import_jsx_runtime.jsx)("img", {
						id: "edit-avatar-preview",
						src: avatar,
						alt: "Avatar Preview",
						style: {
							width: "100px",
							height: "100px",
							borderRadius: "50%",
							objectFit: "cover",
							marginBottom: "10px",
							border: "2px solid #ddd"
						}
					}), (0, import_jsx_runtime.jsxs)("div", {
						style: { textAlign: "left" },
						children: [
							(0, import_jsx_runtime.jsx)("label", {
								style: LABEL_STYLE$1,
								children: "头像链接:"
							}),
							(0, import_jsx_runtime.jsx)("input", {
								type: "text",
								id: "edit-actress-avatar",
								value: avatar,
								style: {
									width: "100%",
									padding: "8px",
									border: "1px solid #ccc",
									borderRadius: "4px"
								}
							}),
							(0, import_jsx_runtime.jsxs)("div", {
								style: {
									display: "flex",
									gap: "5px",
									marginTop: "5px"
								},
								children: [(0, import_jsx_runtime.jsx)("button", {
									type: "button",
									id: "search-avatar-btn",
									style: {
										flexGrow: 1,
										padding: "8px",
										backgroundColor: "#007bff",
										color: "white",
										border: "none",
										borderRadius: "4px",
										cursor: "pointer"
									},
									children: "搜索头像"
								}), (0, import_jsx_runtime.jsx)("button", {
									type: "button",
									id: "select-cdn-btn",
									style: {
										width: "100px",
										padding: "8px",
										backgroundColor: "#6c757d",
										color: "white",
										border: "none",
										borderRadius: "4px",
										cursor: "pointer",
										fontSize: "12px"
									},
									children: "选择 CDN 源"
								})]
							})
						]
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE$1,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE$1,
						children: "主名称:"
					}), (0, import_jsx_runtime.jsx)("input", {
						type: "text",
						id: "edit-actress-name",
						value: name,
						style: {
							width: "100%",
							padding: "8px",
							border: "1px solid #ccc",
							borderRadius: "4px"
						}
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE$1,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE$1,
						children: "所有别名(用逗号隔开):"
					}), (0, import_jsx_runtime.jsx)("textarea", {
						id: "edit-actress-allname",
						style: textareaStyle,
						children: allNameText
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE$1,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE$1,
						children: "演员类别:"
					}), (0, import_jsx_runtime.jsxs)("select", {
						id: "actressType",
						style: {
							width: "100%",
							padding: "10px",
							border: "1px solid #ddd"
						},
						children: [
							(0, import_jsx_runtime.jsx)("option", {
								value: "",
								selected: actressType === "",
								children: "未知"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "censored",
								selected: actressType === "censored",
								children: "有码"
							}),
							(0, import_jsx_runtime.jsx)("option", {
								value: "uncensored",
								selected: actressType === "uncensored",
								children: "无码"
							})
						]
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE$1,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE$1,
						children: "最新作品(用逗号隔开):"
					}), (0, import_jsx_runtime.jsx)("textarea", {
						id: "edit-actress-newvideolist",
						style: textareaStyle,
						children: newVideoText
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE$1,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE$1,
						children: "备注:"
					}), (0, import_jsx_runtime.jsx)("textarea", {
						id: "edit-remark",
						style: textareaStyle,
						children: remark
					})]
				})
			]
		});
	}
	function CdnSelectDialog({ sources, currentIndex }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: { padding: "20px" },
			children: [
				(0, import_jsx_runtime.jsxs)("p", {
					style: {
						marginBottom: "15px",
						fontWeight: "bold",
						color: "#333"
					},
					children: [
						"请选择头像数据源 (当前: ",
						sources[currentIndex].name,
						"):"
					]
				}),
				sources.map((source, index) => (0, import_jsx_runtime.jsxs)("div", {
					style: { marginBottom: "10px" },
					children: [(0, import_jsx_runtime.jsx)("input", {
						type: "radio",
						id: `cdn-${index}`,
						name: "cdn-source",
						value: index,
						checked: index === currentIndex,
						style: { marginRight: "10px" }
					}), (0, import_jsx_runtime.jsxs)("label", {
						for: `cdn-${index}`,
						children: [
							source.name,
							" ",
							source.json.includes("jsdelivr") ? "(推荐)" : ""
						]
					})]
				}, index)),
				(0, import_jsx_runtime.jsx)("p", {
					style: {
						marginTop: "20px",
						color: "#555",
						fontSize: "12px"
					},
					children: "切换源会清除本地缓存的数据,并在下次搜索时重新加载。"
				})
			]
		});
	}
	async function editActress(plugin, actress) {
		const name = actress.name;
		const avatar = actress.avatar;
		const remark = actress.remark || "";
		const allNameText = Array.isArray(actress.allName) ? actress.allName.join(",") : "";
		const newVideoText = Array.isArray(actress.newVideoList) ? actress.newVideoList.join(",") : "";
		const starId = actress.starId;
		const dialogContent = jsxToString((0, import_jsx_runtime.jsx)(EditActressDialog, {
			avatar,
			name,
			textareaStyle: {
				width: "100%",
				padding: "8px",
				border: "1px solid #ccc",
				borderRadius: "4px",
				minHeight: "60px",
				overflowY: "hidden"
			},
			allNameText,
			actressType: actress.actressType || "",
			newVideoText,
			remark
		}));
		layer.open({
			type: 1,
			title: `编辑女优: ${name} (${starId})`,
			area: ["500px", "750px"],
			content: dialogContent,
			btn: ["保存", "取消"],
			success: (_layerEl, layerIndex) => {
				const autoHeight = ($textarea) => {
					$textarea.css("height", "auto");
					$textarea.css("height", $textarea[0].scrollHeight + 15 + "px");
				};
				$("#edit-actress-avatar").on("input", (event) => {
					const val = $(event.currentTarget).val();
					$("#edit-avatar-preview").attr("src", val);
				});
				const $allNameArea = $("#edit-actress-allname");
				$allNameArea.on("input", (event) => {
					autoHeight($(event.currentTarget));
				});
				autoHeight($allNameArea);
				const $newVideoArea = $("#edit-actress-newvideolist");
				$newVideoArea.on("input", (event) => {
					autoHeight($(event.currentTarget));
				});
				autoHeight($newVideoArea);
				$("#search-avatar-btn").on("click", async () => {
					await plugin.searchAvatar();
				});
				$("#select-cdn-btn").on("click", async () => {
					const currentIndex = getCurrentCdnSource().index;
					const cdnDialogContent = jsxToString((0, import_jsx_runtime.jsx)(CdnSelectDialog, {
						sources: GFRIENDS_SOURCES,
						currentIndex
					}));
					layer.open({
						type: 1,
						title: "选择 CDN 源",
						area: ["400px", "auto"],
						content: cdnDialogContent,
						btn: ["确定", "取消"],
						success: (_cdnLayerEl, cdnLayerIndex) => {
							utils.setupEscClose(cdnLayerIndex);
						},
						yes: async (cdnLayerIndex) => {
							const selectedValue = String($("input[name=\"cdn-source\"]:checked").val() ?? "");
							const selectedIndex = parseInt(selectedValue, 10);
							if (selectedIndex !== currentIndex) {
								localStorage.setItem(GFRIENDS_CDN_INDEX_KEY, selectedIndex.toString());
								clearCache();
								try {
									await window.filetreeDb.set(FILETREE_DATA_KEY, null);
								} catch (error) {
									clog.error("清除 IndexedDB 缓存失败:", error);
								}
								show.ok(`CDN 源已切换为: ${GFRIENDS_SOURCES[selectedIndex].name}`);
								layer.close(cdnLayerIndex);
							} else layer.close(cdnLayerIndex);
						}
					});
				});
				utils.setupEscClose(layerIndex);
			},
			yes: async (layerIndex) => {
				const avatar = String($("#edit-actress-avatar").val() ?? "").trim();
				const name = String($("#edit-actress-name").val() ?? "").trim();
				const allNameText = String($("#edit-actress-allname").val() ?? "").trim();
				const newVideoText = String($("#edit-actress-newvideolist").val() ?? "").trim();
				const remark = String($("#edit-remark").val() ?? "").trim();
				const actressType = String($("#actressType").val() ?? "");
				if (!name) {
					show.error("主名称不能为空");
					return false;
				}
				const allNameArray = allNameText.split(/[\uff0c,]/).map((part) => part.trim()).filter((part) => part.length > 0);
				const newVideoArray = newVideoText.split(/[\uff0c,]/).map((part) => part.trim()).filter((part) => part.length > 0);
				actress.avatar = avatar;
				actress.name = name;
				actress.allName = allNameArray;
				actress.newVideoList = newVideoArray;
				actress.actressType = actressType;
				actress.remark = remark;
				if (await storageManager.updateFavoriteActress(actress)) show.error("修改失败");
				else {
					plugin.renderActressCards().then();
					show.ok(`女优 ${name} 信息已更新`);
					layer.close(layerIndex);
				}
			}
		});
	}
	function NewVideoDialog({ refreshSvg }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "newVideoToolBox",
			style: {
				display: "flex",
				flexDirection: "column",
				height: "100%",
				overflow: "hidden",
				padding: "10px"
			},
			children: [
				(0, import_jsx_runtime.jsxs)("div", {
					style: {
						marginBottom: "15px",
						display: "flex",
						justifyContent: "space-between"
					},
					children: [(0, import_jsx_runtime.jsx)("div", { children: (0, import_jsx_runtime.jsx)("span", { id: "checkNewVideoMsg" }) }), (0, import_jsx_runtime.jsxs)("div", {
						style: {
							display: "flex",
							alignItems: "flex-start"
						},
						children: [(0, import_jsx_runtime.jsxs)("select", {
							id: "paramActressType",
							style: {
								textAlign: "center",
								height: "100%",
								minWidth: "150px",
								border: "1px solid #ddd",
								marginRight: "10px"
							},
							children: [
								(0, import_jsx_runtime.jsx)("option", {
									value: "all",
									selected: true,
									children: "所有"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "uncensored",
									children: "无码"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "censored",
									children: "有码"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "",
									children: "未知"
								})
							]
						}), (0, import_jsx_runtime.jsx)("a", {
							className: "a-normal",
							id: "reLoad",
							dangerouslySetInnerHTML: { __html: `${refreshSvg} &nbsp;&nbsp; 刷新` }
						})]
					})]
				}),
				(0, import_jsx_runtime.jsx)("div", {
					id: "actress-card-container",
					className: "jhs-scrollbar"
				}),
				(0, import_jsx_runtime.jsx)("div", { id: "actress-pagination" })
			]
		});
	}
	function NewVideoDialogTitle() {
		return (0, import_jsx_runtime.jsx)("span", {
			style: { padding: "0 10px" },
			"data-tip": "数据来源: 女优页面首页,含磁链分类",
			children: "新作品检测 ❓"
		});
	}
	var new_video_plugin_default = "#actress-card-container {\n    display: grid;\n    grid-template-columns: repeat(auto-fill, minmax(243px, 1fr)); /* 响应式3-5列 */\n    gap: 20px;\n    padding-bottom: 20px;\n    padding-right: 10px;\n    background: #f9f9f9;\n    border-radius: 5px;\n    overflow-y: auto;\n}\n\n.actress-card {\n    background: #fff;\n    border: 1px solid #e0e0e0;\n    border-radius: 8px;\n    box-shadow: 0 4px 8px rgb(0, 0, 0, 0.08);\n    padding: 15px;\n    text-align: center;\n    display: flex;\n    flex-direction: column;\n    justify-content: space-between;\n    position: relative;\n    overflow: hidden;\n}\n\n.actress-card:hover {\n    box-shadow: 0 8px 15px rgb(0, 0, 0, 0.15);\n}\n\n.actress-card-name {\n    font-size: 1.2em;\n    font-weight: bold;\n    color: #007bff;\n    margin-top: 10px;\n}\n\n.actress-card-allname {\n    font-size: 0.9em;\n    color: #999;\n    margin-top: 5px;\n    height: 30px; /* 保证高度一致性 */\n    overflow: hidden;\n    white-space: nowrap; /* 防止文字换行 */\n    text-overflow: ellipsis; /* 当文本溢出时,显示省略号 */\n}\n\n.actress-card-avatar {\n    width: 100px;\n    height: 100px;\n    border-radius: 50%;\n    object-fit: contain;\n    margin: 0 auto;\n    border: 4px solid #f0f0f0;\n    box-shadow: 0 2px 4px rgb(0, 0, 0, 0.1);\n}\n\n.card-tag {\n    position: absolute;\n    top: 15px; /* 调整标签距离顶部的距离 */\n    right: -50px; /* 调整标签距离右侧的距离,负值让它移到外面一点 */\n    width: 150px; /* 标签的宽度,影响斜角长度 */\n    padding: 5px 0; /* 上下内边距 */\n    text-align: center;\n    background-color: #ff4757; /* 标签颜色 */\n    color: white; /* 文字颜色 */\n    font-size: 14px;\n    font-weight: bold;\n    z-index: 10; /* 确保标签在其他内容之上 */\n\n    /* 3. 核心:旋转标签,使其倾斜 */\n    transform: rotate(45deg); /* 45度斜角 */\n\n    /* 可选:添加一些阴影或边框效果 */\n    box-shadow: 0 0 10px rgb(0, 0, 0, 0.3);\n}\n\n.card-new-count-tag {\n    position: absolute;\n    top: 5px;\n    text-align: center;\n    font-size: 14px;\n    font-weight: bold;\n    z-index: 10;\n}\n\n#actress-pagination {\n    padding-top: 10px;\n    text-align: center;\n    border-top: 1px solid #ddd;\n}\n\n@media (width <= 600px) {\n    .page-number-btn {\n        display: none !important;\n    }\n}\n\n.card-btn {\n    width: 44px;\n    height: 44px;\n    border-radius: 50%;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    text-decoration: none;\n    border: none;\n    cursor: pointer;\n    background: linear-gradient(145deg, #e0e0e0 0%, #f7f7f7 100%);\n    box-shadow:\n        8px 8px 16px rgb(0, 0, 0, 0.08),\n        -8px -8px 16px rgb(255, 255, 255, 1);\n    transition:\n        box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        background-color 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n.card-btn svg,\n.card-btn svg path {\n    transition: fill 0.3s ease;\n}\n\n.card-btn:hover {\n    box-shadow:\n        inset 5px 5px 10px rgb(0, 0, 0, 0.1),\n        inset -5px -5px 10px rgb(255, 255, 255, 0.9);\n    transform: scale(0.97);\n    background: #e0e0e0;\n}\n\n.btn-check-actress svg path {\n    fill: #4caf50;\n}\n\n.btn-check-actress:hover svg path {\n    fill: #388e3c;\n}\n\n.btn-edit-actress svg path {\n    fill: #ffc107;\n}\n\n.btn-edit-actress:hover svg path {\n    fill: #ffb300;\n}\n\n.btn-delete-actress svg path {\n    fill: #f44336;\n}\n\n.btn-delete-actress:hover svg path {\n    fill: #d32f2f;\n}\n";
	var NewVideoPlugin = class extends BasePlugin {
		currentPage = 1;
		pageSize = 30;
		getName() {
			return "NewVideoPlugin";
		}
		async initCss() {
			return new_video_plugin_default;
		}
		async handle() {
			await this.showNewVideoCount();
		}
		async showNewVideoCount() {
			const totalCount = (await storageManager.getFavoriteActressList()).reduce((total, actress) => {
				return total + (actress.newVideoList?.length ?? 0);
			}, 0);
			$("#newVideoCount").text(`${totalCount}`);
		}
		async resetBtnTip() {}
		async openDialog() {
			const dialogContent = jsxToString((0, import_jsx_runtime.jsx)(NewVideoDialog, { refreshSvg: this.refreshSvg }));
			layer.open({
				type: 1,
				title: jsxToString((0, import_jsx_runtime.jsx)(NewVideoDialogTitle, {})),
				content: dialogContent,
				scrollbar: false,
				area: utils.getResponsiveArea(["80%", "90%"]),
				anim: -1,
				success: async (_layerEl, layerIndex) => {
					this.loadData();
					this.bindClick();
					utils.setupEscClose(layerIndex);
				}
			});
		}
		bindClick() {
			$("#reLoad").on("click", (_event) => {
				this.loadData();
				$("#checkNewVideoMsg").text("");
			});
			$("#paramActressType").on("change", (_event) => {
				this.loadData();
			});
		}
		loadData() {
			this.currentPage = 1;
			this.renderActressCards().then();
		}
		async renderActressCards() {
			await renderActressCards(this);
		}
		async editActress(actress) {
			await editActress(this, actress);
		}
		renderPagination(totalCount, totalPages) {
			renderPagination$1(this, totalCount, totalPages);
		}
		async searchAvatar() {
			await searchAvatar();
		}
	};
	function handleBatchAction(plugin, event, btn) {
		event.preventDefault();
		event.stopPropagation();
		const selectedRows = plugin.tableObj.getSelectedData();
		let actionLabel = "";
		let actionType = "";
		if (btn.hasClass("multiple-history-filterBtn")) {
			actionLabel = "屏蔽";
			actionType = FILTER_ACTION;
		} else if (btn.hasClass("multiple-history-favoriteBtn")) {
			actionLabel = "收藏";
			actionType = FAVORITE_ACTION;
		} else if (btn.hasClass("multiple-history-hasWatchBtn")) {
			actionLabel = "已观看";
			actionType = HAS_WATCH_ACTION;
		} else if (btn.hasClass("multiple-history-deleteBtn")) {
			actionLabel = "移除";
			actionType = "delete";
		}
		utils.q(event, `当前已勾选${selectedRows.length}条数据, 是否全标记为 ${actionLabel}?`, async () => {
			const loader = loading();
			try {
				if (actionType === "delete") {
					const carNums = selectedRows.map((row) => row.carNum);
					const removed = await storageManager.batchRemoveCars(carNums);
					if (Number(removed) > 0) show.ok(`已成功删除 ${removed} 个番号`);
					else if (removed === false) show.error("提供的番号中没有一个存在于列表中。");
				} else {
					const updates = JSON.parse(JSON.stringify(selectedRows));
					updates.forEach((item) => {
						item.actionType = actionType;
					});
					await storageManager.saveCarList(updates);
					show.ok("操作成功");
				}
				plugin.tableObj.deselectRow();
				plugin.reloadTable().then();
			} catch (err) {
				clog.error("批量操作失败:", err);
				show.error("操作失败: " + (err instanceof Error ? err.message : String(err)));
			} finally {
				loader.close();
			}
		});
	}
	function HistoryActionButtons({ carNum, url, watchedColor, watchedText, favoriteColor, favoriteText, blockColor, blockText }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "action-btns",
			style: {
				display: "flex",
				gap: "5px",
				justifyContent: "center"
			},
			"data-car-num": carNum,
			"data-href": url,
			children: [(0, import_jsx_runtime.jsxs)("div", {
				className: "sub-btns",
				children: [(0, import_jsx_runtime.jsx)("a", {
					className: "jhs-toolbar-menu-btn sub-btns-toggle",
					style: {
						backgroundColor: "#c59d36",
						color: "white",
						marginBottom: "5px"
					},
					children: (0, import_jsx_runtime.jsx)("span", { children: "✏️ 变更" })
				}), (0, import_jsx_runtime.jsxs)("div", {
					className: "sub-btns-menu",
					children: [
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn history-editBtn",
							style: {
								backgroundColor: "#007bff",
								color: "white",
								marginBottom: "5px"
							},
							children: (0, import_jsx_runtime.jsx)("span", { children: "✏️ 编辑" })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn history-deleteBtn",
							style: {
								backgroundColor: "#8c8080",
								color: "white",
								marginBottom: "5px"
							},
							children: (0, import_jsx_runtime.jsx)("span", { children: "✂️ 移除" })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn history-hasWatchBtn",
							style: {
								backgroundColor: watchedColor,
								marginBottom: "5px"
							},
							children: watchedText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn history-favoriteBtn",
							style: {
								backgroundColor: favoriteColor,
								marginBottom: "5px"
							},
							children: favoriteText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn history-filterBtn",
							style: {
								backgroundColor: blockColor,
								marginBottom: "5px"
							},
							children: blockText
						})
					]
				})]
			}), (0, import_jsx_runtime.jsx)("a", {
				className: "jhs-toolbar-menu-btn history-detailBtn",
				style: {
					backgroundColor: "#3397de",
					color: "white",
					marginBottom: "5px"
				},
				children: (0, import_jsx_runtime.jsx)("span", { children: "📄 详情页" })
			})]
		});
	}
	function TableLinkParam({ text }) {
		return (0, import_jsx_runtime.jsx)("a", {
			className: "table-link-param",
			children: text
		});
	}
	function buildHistoryTableOptions(plugin) {
		return {
			...createTabulatorOptions([
				{
					formatter: "rowSelection",
					titleFormatter: "rowSelection",
					hozAlign: "center",
					headerSort: false,
					responsive: 0,
					width: 40,
					titleFormatterParams: { rowRange: "active" },
					cellClick: (_event, cell) => {
						cell.getRow().toggleSelect();
					}
				},
				{
					title: "番号",
					field: "carNum",
					width: 120,
					sorter: "string",
					responsive: 0,
					formatter: (cell, _formatterParams, _onRendered) => {
						const carNum = cell.getData().carNum;
						const dashIndex = carNum.indexOf("-");
						if (dashIndex === -1) return carNum;
						return jsxToString((0, import_jsx_runtime.jsx)(TableLinkParam, { text: carNum.substring(0, dashIndex + 1) })) + carNum.substring(dashIndex + 1);
					}
				},
				{
					title: "演员",
					field: "names",
					minWidth: 200,
					sorter: "string",
					responsive: 5,
					headerSort: true,
					formatter: (cell, _formatterParams, _onRendered) => (cell.getData().names || "").split(" ").filter((part) => part.trim() !== "").map((part) => jsxToString((0, import_jsx_runtime.jsx)(TableLinkParam, { text: part }))).join(" ")
				},
				{
					title: "创建时间",
					field: "createDate",
					width: 170,
					sorter: "string",
					responsive: 4
				},
				{
					title: "修改时间",
					field: "updateDate",
					width: 170,
					sorter: "string",
					responsive: 4
				},
				{
					title: "发行时间",
					field: "publishTime",
					width: 170,
					sorter: "string",
					responsive: 4
				},
				{
					title: "来源",
					field: "url",
					width: 80,
					sorter: "string",
					responsive: 5,
					hozAlign: "left",
					formatter: (cell, _formatterParams, _onRendered) => {
						const url = cell.getData().url;
						if (url) if (url.includes("javdb")) return jsxToString((0, import_jsx_runtime.jsx)(ColoredTextCell, {
							text: "Javdb",
							color: "#d34f9e"
						}));
						else return jsxToString((0, import_jsx_runtime.jsx)(ColoredTextCell, {
							text: url,
							color: "#050505"
						}));
						else return "";
					}
				},
				{
					title: "状态",
					field: "status",
					width: 100,
					sorter: "string",
					responsive: 1,
					headerSort: false,
					formatter: (cell, _formatterParams, _onRendered) => {
						const status = cell.getData().status;
						let color = "";
						let text;
						switch (status) {
							case "filter":
								color = BLOCK_COLOR;
								text = BLOCK_TEXT;
								break;
							case "favorite":
								color = FAVORITE_COLOR;
								text = FAVORITE_TEXT;
								break;
							case "hasWatch":
								color = WATCHED_COLOR;
								text = WATCHED_TEXT;
								break;
							default: text = status;
						}
						return jsxToString((0, import_jsx_runtime.jsx)(ColoredTextCell, {
							text,
							color
						}));
					}
				},
				{
					title: "备注",
					field: "remark",
					width: 100,
					sorter: "string",
					responsive: 6
				},
				{
					title: "操作",
					sorter: "string",
					minWidth: 150,
					cssClass: "action-cell-dropdown",
					responsive: 0,
					headerSort: false,
					formatter: (cell, _formatterParams, onRendered) => {
						const data = cell.getData();
						onRendered(() => {
							const editBtn = cell.getElement().querySelector(".history-editBtn");
							if (editBtn != null) editBtn.addEventListener("click", () => {
								plugin.editRecord(data);
							});
						});
						return jsxToString((0, import_jsx_runtime.jsx)(HistoryActionButtons, {
							carNum: data.carNum,
							url: data.url || "",
							watchedColor: WATCHED_COLOR,
							watchedText: WATCHED_TEXT,
							favoriteColor: FAVORITE_COLOR,
							favoriteText: FAVORITE_TEXT,
							blockColor: BLOCK_COLOR,
							blockText: BLOCK_TEXT
						}));
					}
				}
			]),
			pagination: true,
			paginationMode: "remote",
			sortMode: "remote",
			ajaxURL: "queryRealm",
			dataLoader: false,
			ajaxRequestFunc: async (_url, _config, params) => {
				const page = params.page;
				const size = params.size;
				const sort = params.sort;
				return await plugin.getDataList(page, size, sort);
			},
			dataReceiveParams: {
				last_page: "maxPage",
				last_row: "totalCount",
				data: "dataList"
			},
			paginationSize: 50,
			paginationSizeSelector: [
				50,
				100,
				1e3,
				99999
			],
			paginationCounter: (_pageNumber, _pageSize, _totalPages, recordCount, _data) => `共 ${recordCount} 条记录`,
			selectableRowsPersistence: false,
			index: "carNum",
			initialSort: [{
				column: "updateDate",
				dir: "desc"
			}]
		};
	}
	async function getDataList(plugin, page, size, sort) {
		const carList = await storageManager.getCarList();
		plugin.allCount = carList.length;
		plugin.filterCount = 0;
		plugin.favoriteCount = 0;
		plugin.hasWatchCount = 0;
		carList.forEach((car) => {
			switch (car.status) {
				case FILTER_ACTION:
					plugin.filterCount++;
					break;
				case FAVORITE_ACTION:
					plugin.favoriteCount++;
					break;
				case HAS_WATCH_ACTION: plugin.hasWatchCount++;
			}
		});
		$("#dataType option[value=\"all\"]").text(`所有 (${plugin.allCount})`);
		$("#dataType option[value=\"filter\"]").text(`${BLOCKED_TEXT} (${plugin.filterCount})`);
		$("#dataType option[value=\"favorite\"]").text(`${FAVORITED_TEXT} (${plugin.favoriteCount})`);
		$("#dataType option[value=\"hasWatch\"]").text(`${WATCHED_TEXT} (${plugin.hasWatchCount})`);
		const selectedType = $("#dataType").val();
		let filtered = selectedType === "all" ? carList : carList.filter((car) => car.status === selectedType);
		const searchText = String($("#searchCarNum").val() ?? "").trim();
		if (searchText) {
			const normalizedSearch = searchText.toLowerCase().replace("-c", "").replace("-uc", "").replace("-4k", "");
			filtered = filtered.filter((row) => {
				const matchCar = row.carNum.toLowerCase().includes(normalizedSearch);
				const matchName = (row.names ? row.names : "").toLowerCase().includes(normalizedSearch);
				return matchCar || matchName;
			});
		}
		if (sort && sort.length > 0) {
			const sortConfig = sort[0];
			const field = sortConfig.field;
			const dir = sortConfig.dir;
			filtered.sort((rowA, rowB) => {
				const valA = rowA[field];
				const valB = rowB[field];
				const isEmptyA = valA == null || valA === "";
				const isEmptyB = valB == null || valB === "";
				if (isEmptyA && !isEmptyB) return 1;
				else if (!isEmptyA && isEmptyB) return -1;
				else if (isEmptyA && isEmptyB) return 0;
				else if (valA < valB) if (dir === "asc") return -1;
				else return 1;
				else if (valA > valB) if (dir === "asc") return 1;
				else return -1;
				else return 0;
			});
		}
		const totalCount = filtered.length;
		const maxPage = Math.ceil(totalCount / size);
		const start = (page - 1) * size;
		const end = start + size;
		filtered = filtered.slice(start, end);
		return {
			maxPage,
			dataList: filtered,
			totalCount
		};
	}
	var LABEL_STYLE = {
		display: "block",
		marginBottom: "5px",
		fontWeight: "bold"
	};
	var FIELD_ROW_STYLE = { marginBottom: "15px" };
	function EditRecordDialog({ carNum, names, status, url, remark, inputStyle, textareaStyle, statusOptions }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: { padding: "20px" },
			children: [
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE,
						children: "番号:"
					}), (0, import_jsx_runtime.jsx)("input", {
						type: "text",
						id: "edit-carNum",
						value: carNum,
						style: {
							...inputStyle,
							backgroundColor: "#f0f0f0"
						},
						readOnly: true
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE,
						children: "演员 (用空格隔开):"
					}), (0, import_jsx_runtime.jsx)("textarea", {
						id: "edit-names",
						style: textareaStyle,
						children: names
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE,
						children: "状态:"
					}), (0, import_jsx_runtime.jsxs)("select", {
						id: "edit-status",
						style: {
							width: "100%",
							padding: "10px",
							border: "1px solid #ddd"
						},
						children: [(0, import_jsx_runtime.jsx)("option", {
							value: "",
							selected: status === "",
							children: "-- 请选择 --"
						}), statusOptions.map((opt) => (0, import_jsx_runtime.jsx)("option", {
							value: opt.value,
							selected: status === opt.value,
							children: opt.text
						}, opt.value))]
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE,
						children: "链接:"
					}), (0, import_jsx_runtime.jsx)("input", {
						type: "text",
						id: "edit-url",
						value: url,
						style: inputStyle
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: FIELD_ROW_STYLE,
					children: [(0, import_jsx_runtime.jsx)("label", {
						style: LABEL_STYLE,
						children: "备注:"
					}), (0, import_jsx_runtime.jsx)("textarea", {
						id: "edit-remark",
						style: textareaStyle,
						children: remark
					})]
				})
			]
		});
	}
	function HistoryDialog({ blockedText, favoritedText, watchedText, watchedColor, favoriteColor, favoriteText, blockColor, blockText }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				padding: "10px 20px",
				height: "100%",
				overflow: "hidden"
			},
			children: [
				(0, import_jsx_runtime.jsxs)("div", {
					id: "filterBox",
					style: {
						display: "flex",
						gap: "5px"
					},
					children: [
						(0, import_jsx_runtime.jsxs)("select", {
							id: "dataType",
							style: {
								textAlign: "center",
								minWidth: "150px"
							},
							children: [
								(0, import_jsx_runtime.jsx)("option", {
									value: "all",
									selected: true,
									children: "所有"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "filter",
									children: blockedText
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "favorite",
									children: favoritedText
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "hasWatch",
									children: watchedText
								})
							]
						}),
						(0, import_jsx_runtime.jsx)("input", {
							id: "searchCarNum",
							type: "text",
							placeholder: "搜索番号|演员",
							style: { padding: "4px 5px" }
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "clearSearchbtn",
							className: "a-info",
							style: { marginLeft: "0" },
							children: "重置"
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					id: "allSelectBox",
					style: {
						marginTop: "8px",
						display: "none"
					},
					children: [
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn multiple-history-deleteBtn",
							style: {
								backgroundColor: "#8c8080",
								color: "white",
								marginBottom: "5px"
							},
							children: (0, import_jsx_runtime.jsx)("span", { children: "✂️ 移除" })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn multiple-history-hasWatchBtn",
							style: {
								backgroundColor: watchedColor,
								marginBottom: "5px"
							},
							children: watchedText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn multiple-history-favoriteBtn",
							style: {
								backgroundColor: favoriteColor,
								marginBottom: "5px"
							},
							children: favoriteText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-toolbar-menu-btn multiple-history-filterBtn",
							style: {
								backgroundColor: blockColor,
								marginBottom: "5px"
							},
							children: blockText
						})
					]
				}),
				(0, import_jsx_runtime.jsx)("div", {
					id: "table-container",
					style: {
						height: "calc(100% - 50px)",
						overflowX: "hidden"
					}
				})
			]
		});
	}
	function HistoryNavButton({ variant }) {
		switch (variant) {
			case "desktop": return (0, import_jsx_runtime.jsx)("div", {
				className: "navbar-item has-sub-btns is-hoverable historyBtnBox",
				children: (0, import_jsx_runtime.jsx)("a", {
					id: "historyBtn",
					className: "navbar-link nav-btn",
					style: {
						color: "#aade66 !important",
						paddingRight: "15px !important"
					},
					children: "鉴定记录"
				})
			});
			case "mini": return (0, import_jsx_runtime.jsx)("div", {
				className: "navbar-item miniHistoryBtnBox",
				children: (0, import_jsx_runtime.jsx)("a", {
					id: "miniHistoryBtn",
					className: "navbar-link nav-btn",
					style: {
						color: "#aade66 !important",
						paddingLeft: "0 !important",
						paddingRight: "0 !important"
					},
					children: "鉴定记录"
				})
			});
			default: return null;
		}
	}
	var history_plugin_default = "/* 下拉菜单容器(相对定位) */\n.sub-btns {\n    position: relative;\n    display: inline-block;\n}\n\n/* 下拉菜单内容(默认隐藏) */\n.sub-btns-menu {\n    display: none;\n    position: absolute;\n    right: 80px;\n    top: -10px;\n    background: white;\n    padding: 10px;\n    box-shadow: 0 2px 8px rgb(0, 0, 0, 0.15);\n    z-index: 100;\n    border-radius: 4px;\n    overflow: hidden;\n}\n\n/* 点击后显示菜单(JS 控制) */\n.sub-btns-menu.show {\n    display: flex !important;\n    flex-direction: column;\n}\n\n.table-link-param {\n    cursor: pointer;\n}\n";
	var HistoryPlugin = class extends BasePlugin {
		tableObj = null;
		allCount = 0;
		filterCount = 0;
		favoriteCount = 0;
		hasWatchCount = 0;
		constructor() {
			super();
		}
		getName() {
			return "HistoryPlugin";
		}
		async initCss() {
			return history_plugin_default;
		}
		handleResize() {
			if ($(".navbar-search").is(":hidden")) {
				$(".historyBtnBox").show();
				$(".miniHistoryBtnBox").hide();
			} else {
				$(".historyBtnBox").hide();
				$(".miniHistoryBtnBox").show();
			}
		}
		async handle() {
			if (isJavdbSite) {
				$(".navbar-end").prepend(jsxToString((0, import_jsx_runtime.jsx)(HistoryNavButton, { variant: "desktop" })));
				$(".navbar-search").css("margin-left", "0").before(jsxToString((0, import_jsx_runtime.jsx)(HistoryNavButton, { variant: "mini" })));
				this.handleResize();
				$(window).resize(() => {
					this.handleResize();
				});
				$("#historyBtn,#miniHistoryBtn").on("click", () => this.openHistory());
			}
			this.bindClick();
		}
		openHistory() {
			layer.open({
				type: 1,
				title: "鉴定记录",
				content: jsxToString((0, import_jsx_runtime.jsx)(HistoryDialog, {
					blockedText: BLOCKED_TEXT,
					favoritedText: FAVORITED_TEXT,
					watchedText: WATCHED_TEXT,
					watchedColor: WATCHED_COLOR,
					favoriteColor: FAVORITE_COLOR,
					favoriteText: FAVORITE_TEXT,
					blockColor: BLOCK_COLOR,
					blockText: BLOCK_TEXT
				})),
				scrollbar: false,
				shadeClose: true,
				area: utils.getResponsiveArea(["70%", "90%"]),
				anim: -1,
				success: async () => {
					await this.loadTableData();
					$(".layui-layer-content").on("click", "#clearSearchbtn", async () => {
						$("#searchCarNum").val("");
						$("#dataType").val("all");
						await this.reloadTable();
						$("#allSelectBox").hide();
					}).on("focusout keydown", "#searchCarNum", async (event) => {
						if (event.type === "focusout" || event.key === "Enter") {
							if (event.key === "Enter") event.preventDefault();
							if (event.type === "keydown" && event.key !== "Enter") return;
							await this.reloadTable();
						}
					}).on("click", ".table-link-param", async (event) => {
						const link = $(event.currentTarget);
						$("#searchCarNum").val(link.text());
						await this.reloadTable();
					}).on("change", "#dataType", async () => {
						await this.reloadTable();
					});
				},
				end: () => {
					if (this.tableObj) {
						this.tableObj.destroy();
						this.tableObj = null;
					}
					refresh();
				}
			});
		}
		async reloadTable() {
			this.tableObj.deselectRow();
			this.tableObj.setPage(1);
		}
		bindClick() {
			document.addEventListener("click", function(event) {
				const target = event.target;
				if (target.closest(".sub-btns-toggle")) {
					const menu = target.closest(".sub-btns").querySelector(".sub-btns-menu");
					document.querySelectorAll(".sub-btns-menu.show").forEach((el) => {
						if (el !== menu) el.classList.remove("show");
					});
					menu.classList.toggle("show");
				} else document.querySelectorAll(".sub-btns-menu.show").forEach((el) => {
					el.classList.remove("show");
				});
			});
			$(document).on("click", ".history-deleteBtn, .history-filterBtn, .history-favoriteBtn, .history-hasWatchBtn, .history-detailBtn", (event) => {
				event.preventDefault();
				event.stopPropagation();
				const btn = $(event.currentTarget);
				const actionBtns = btn.closest(".action-btns");
				const carNum = actionBtns.attr("data-car-num");
				const href = actionBtns.attr("data-href");
				const applyAction = async (actionType) => {
					await storageManager.saveCar({
						carNum: carNum ?? "",
						url: href,
						names: void 0,
						actionType
					});
					refresh();
					await this.reloadTable();
				};
				if (btn.hasClass("history-filterBtn")) utils.q(event, `是否屏蔽${carNum}?`, () => applyAction(FILTER_ACTION));
				else if (btn.hasClass("history-favoriteBtn")) applyAction(FAVORITE_ACTION).then();
				else if (btn.hasClass("history-hasWatchBtn")) applyAction(HAS_WATCH_ACTION).then();
				else if (btn.hasClass("history-deleteBtn")) this.handleDelete(event, carNum);
				else if (btn.hasClass("history-detailBtn")) this.handleClickDetail(event, {
					carNum,
					url: href
				}).then();
			});
			$(document).on("click", ".multiple-history-deleteBtn, .multiple-history-filterBtn, .multiple-history-favoriteBtn, .multiple-history-hasWatchBtn", (event) => {
				handleBatchAction(this, event, $(event.currentTarget));
			});
		}
		async getDataList(page, size, sort) {
			return getDataList(this, page, size, sort);
		}
		async loadTableData() {
			this.tableObj = new Tabulator("#table-container", buildHistoryTableOptions(this));
			this.tableObj.on("rowSelectionChanged", (rows, _deselectedRows, _selected, _deselected) => {
				const selectBox = $("#allSelectBox");
				const filterBox = $("#filterBox");
				if (rows && rows.length > 0) {
					filterBox.hide();
					selectBox.show();
				} else {
					filterBox.show();
					selectBox.hide();
				}
			});
			this.tableObj.on("rowDblClick", (_event, row) => {
				row.toggleSelect();
			});
			this.tableObj.on("tableBuilt", async () => {});
		}
		handleDelete(event, carNum) {
			utils.q(event, `是否移除${carNum}?`, async () => {
				await storageManager.removeCar(carNum);
				this.getBean("ListPagePlugin").showCarNumBox(carNum);
				this.reloadTable().then();
			});
		}
		async handleClickDetail(event, carInfo) {
			if (isJavdbSite) if (carInfo.carNum.includes("FC2-")) {
				const movieId = this.parseMovieId(carInfo.url);
				this.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carInfo.carNum, carInfo.url);
			} else {
				if (!carInfo.url) {
					window.open("/search?q=" + encodeURIComponent(carInfo.carNum), "_blank", "noopener,noreferrer");
					return;
				}
				utils.openPage(carInfo.url, carInfo.carNum, false, event);
			}
		}
		async editRecord(record) {
			const carNum = record.carNum;
			const names = record.names || "";
			const url = record.url || "";
			const status = record.status;
			const remark = record.remark || "";
			const textareaStyle = {
				width: "100%",
				padding: "8px",
				border: "1px solid #ccc",
				borderRadius: "4px",
				minHeight: "60px",
				overflowY: "hidden"
			};
			const inputStyle = {
				width: "100%",
				padding: "8px",
				border: "1px solid #ccc",
				borderRadius: "4px"
			};
			const statusOptions = [
				{
					value: FILTER_ACTION,
					text: BLOCK_TEXT
				},
				{
					value: FAVORITE_ACTION,
					text: FAVORITE_TEXT
				},
				{
					value: HAS_WATCH_ACTION,
					text: WATCHED_TEXT
				}
			];
			console.log(statusOptions);
			layer.open({
				type: 1,
				title: `编辑记录: ${carNum}`,
				area: ["500px", "650px"],
				content: jsxToString((0, import_jsx_runtime.jsx)(EditRecordDialog, {
					carNum,
					names,
					status,
					url,
					remark,
					inputStyle,
					textareaStyle,
					statusOptions
				})),
				btn: ["保存", "取消"],
				success: () => {
					const autoResize = (el) => {
						el.css("height", "auto");
						el.css("height", el[0].scrollHeight + 15 + "px");
					};
					const namesInput = $("#edit-names");
					namesInput.on("input", (event) => autoResize($(event.currentTarget)));
					autoResize(namesInput);
					const remarkInput = $("#edit-remark");
					remarkInput.on("input", (event) => autoResize($(event.currentTarget)));
					autoResize(remarkInput);
				},
				yes: async (index) => {
					const names = String($("#edit-names").val() ?? "").trim();
					const status = $("#edit-status").val();
					const url = String($("#edit-url").val() ?? "").trim();
					const remark = String($("#edit-remark").val() ?? "").trim();
					const updated = {
						...record,
						names,
						actionType: status,
						url,
						remark
					};
					await storageManager.updateCarInfo(updated);
					this.tableObj.setData();
					layer.close(index);
				}
			});
		}
	};
	var VIDEO_QUALITY_LIST = [
		{
			id: "video-mhb",
			quality: "dmb_w",
			text: "旧视频源-中画质宽版 (404p)",
			canSelect: false
		},
		{
			id: "video-mhb",
			quality: "sm_s",
			text: "旧视频源-低画质 (240p)",
			canSelect: false
		},
		{
			id: "video-mhb",
			quality: "dm_s",
			text: "旧视频源-中画质 (360p)",
			canSelect: false
		},
		{
			id: "video-mhb",
			quality: "dmb_s",
			text: "旧视频源-中画质 (480p)",
			canSelect: false
		},
		{
			id: "video-mhb",
			quality: "mhb_w",
			text: "旧视频源-高画质宽版 (404p)",
			canSelect: false
		},
		{
			id: "video-mmb",
			quality: "mmb",
			text: "中画质 (432p)",
			canSelect: true
		},
		{
			id: "video-mhb",
			quality: "mhb",
			text: "高画质 (576p)",
			canSelect: true
		},
		{
			id: "video-hmb",
			quality: "hmb",
			text: "HD (720p)",
			canSelect: true
		},
		{
			id: "video-hhb",
			quality: "hhb",
			text: "FullHD (1080p)",
			canSelect: true
		},
		{
			id: "video-hhbs",
			quality: "hhbs",
			text: "FullHD (1080p60fps)",
			canSelect: true
		},
		{
			id: "video-4k",
			quality: "4k",
			text: "4K (2160p)",
			canSelect: true
		},
		{
			id: "video-4ks",
			quality: "4ks",
			text: "4K (2160p60fps)",
			canSelect: true
		}
	];
	var CREDENTIAL_ID_KEY = "jhs:credential_id";
	var LAST_AUTO_BACKUP_DATE_KEY = "jhs:last_auto_backup_date";
	var DEFAULT_AUTO_BACKUP_CONFIG = {
		enabled: true,
		frequency: "daily"
	};
	function generateUuid() {
		if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
		const bytes = new Uint8Array(16);
		crypto.getRandomValues(bytes);
		bytes[6] = bytes[6] & 15 | 64;
		bytes[8] = bytes[8] & 63 | 128;
		const hex = [];
		bytes.forEach((b) => hex.push(b.toString(16).padStart(2, "0")));
		return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
	}
	function getCredentialId() {
		let id = GM_getValue(CREDENTIAL_ID_KEY, void 0);
		if (!id) {
			id = generateUuid();
			GM_setValue(CREDENTIAL_ID_KEY, id);
		}
		return id;
	}
	function getTodayStr() {
		const now = new Date();
		return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
	}
	function shouldAutoBackup(config) {
		if (!config.enabled || config.frequency === "disabled") return false;
		if (config.frequency === "everyOpen") return true;
		return getTodayStr() !== GM_getValue(LAST_AUTO_BACKUP_DATE_KEY, void 0);
	}
	function markAutoBackupDone() {
		GM_setValue(LAST_AUTO_BACKUP_DATE_KEY, getTodayStr());
	}
	function getAutoBackupFileName() {
		return `auto_${getCredentialId()}.json`;
	}
	var require_react_production = __commonJSMin(((exports) => {
		var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element");
		var ReactNoopUpdateQueue = {
			isMounted: function() {
				return !1;
			},
			enqueueForceUpdate: function() {},
			enqueueReplaceState: function() {},
			enqueueSetState: function() {}
		}, assign = Object.assign, emptyObject = {};
		function Component(props, context, updater) {
			this.props = props;
			this.context = context;
			this.refs = emptyObject;
			this.updater = updater || ReactNoopUpdateQueue;
		}
		Component.prototype.isReactComponent = {};
		Component.prototype.setState = function(partialState, callback) {
			if ("object" !== typeof partialState && "function" !== typeof partialState && null != partialState) throw Error("takes an object of state variables to update or a function which returns an object of state variables.");
			this.updater.enqueueSetState(this, partialState, callback, "setState");
		};
		Component.prototype.forceUpdate = function(callback) {
			this.updater.enqueueForceUpdate(this, callback, "forceUpdate");
		};
		function ComponentDummy() {}
		ComponentDummy.prototype = Component.prototype;
		function PureComponent(props, context, updater) {
			this.props = props;
			this.context = context;
			this.refs = emptyObject;
			this.updater = updater || ReactNoopUpdateQueue;
		}
		var pureComponentPrototype = PureComponent.prototype = new ComponentDummy();
		pureComponentPrototype.constructor = PureComponent;
		assign(pureComponentPrototype, Component.prototype);
		pureComponentPrototype.isPureReactComponent = !0;
		Array.isArray;
		var hasOwnProperty = Object.prototype.hasOwnProperty;
		function ReactElement(type, key, props) {
			var refProp = props.ref;
			return {
				$$typeof: REACT_ELEMENT_TYPE,
				type,
				key,
				ref: void 0 !== refProp ? refProp : null,
				props
			};
		}
		exports.createElement = function(type, config, children) {
			var propName, props = {}, key = null;
			if (null != config) for (propName in void 0 !== config.key && (key = "" + config.key), config) hasOwnProperty.call(config, propName) && "key" !== propName && "__self" !== propName && "__source" !== propName && (props[propName] = config[propName]);
			var childrenLength = arguments.length - 2;
			if (1 === childrenLength) props.children = children;
			else if (1 < childrenLength) {
				for (var childArray = Array(childrenLength), i = 0; i < childrenLength; i++) childArray[i] = arguments[i + 2];
				props.children = childArray;
			}
			if (type && type.defaultProps) for (propName in childrenLength = type.defaultProps, childrenLength) void 0 === props[propName] && (props[propName] = childrenLength[propName]);
			return ReactElement(type, key, props);
		};
	}));
	var import_react = __commonJSMin(((exports, module) => {
		module.exports = require_react_production();
	}))();
	function HelpDialog() {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "help-container",
			children: [
				(0, import_jsx_runtime.jsx)("h1", {
					style: {
						fontSize: "22px",
						marginBottom: "20px",
						color: "#2c3e50",
						borderBottom: "1px solid #eee",
						paddingBottom: "10px"
					},
					children: "使用说明"
				}),
				(0, import_jsx_runtime.jsxs)("details", {
					className: "help-section",
					children: [(0, import_jsx_runtime.jsx)("summary", { children: "1. 无法查看预览视频,提示分流?" }), (0, import_jsx_runtime.jsxs)("div", {
						className: "help-content",
						children: [
							(0, import_jsx_runtime.jsx)("p", { children: "JavDB限制日本IP的访问,而预览视频来自DMM,需要日本IP才能访问。" }),
							(0, import_jsx_runtime.jsx)("p", { children: "这样会导致二者无法同时使用,需要对其一进行代理转发。" }),
							(0, import_jsx_runtime.jsx)("p", { children: "将 cc3001.dmm.co.jp 及 dmm.co 分流到日本ip。" }),
							(0, import_jsx_runtime.jsxs)("p", { children: [
								(0, import_jsx_runtime.jsxs)("a", {
									href: "https://youtu.be/wQUK8z_YeU4?t=121",
									target: "_blank",
									children: ["Clash Verge分流规则设置", " "]
								}),
								" ",
								"(如果你是别的代理软件,自行搜索如何分流)"
							] })
						]
					})]
				}),
				(0, import_jsx_runtime.jsxs)("details", {
					className: "help-section",
					children: [(0, import_jsx_runtime.jsx)("summary", { children: "2. 如何屏蔽某一系列的番号?" }), (0, import_jsx_runtime.jsx)("div", {
						className: "help-content",
						children: (0, import_jsx_runtime.jsx)("p", { children: "设置中-屏蔽配置-添加视频标题关键词,如: VENX-" })
					})]
				}),
				(0, import_jsx_runtime.jsxs)("details", {
					className: "help-section",
					children: [(0, import_jsx_runtime.jsx)("summary", { children: "3. 屏蔽某演员,如何只屏蔽单体影片?" }), (0, import_jsx_runtime.jsxs)("div", {
						className: "help-content",
						children: [(0, import_jsx_runtime.jsx)("p", { children: "屏蔽演员前,先筛选分类,再点屏蔽" }), (0, import_jsx_runtime.jsx)("img", {
							src: "https://imgur.com/Ue7eCAi.png",
							alt: "屏蔽演员前,先筛选分类,再点屏蔽"
						})]
					})]
				})
			]
		});
	}
	var help_dialog_default = ".help-container {\n    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n    color: #333;\n    padding: 15px;\n    max-height: 100%;\n    overflow-y: auto;\n}\n\n.help-section {\n    margin-bottom: 25px;\n}\n\n.help-section summary {\n    font-size: 18px;\n    color: #3498db;\n    margin-bottom: 12px;\n    cursor: pointer;\n}\n\n.help-content {\n    background-color: #f9f9f9;\n    border-radius: 5px;\n    padding: 15px;\n    border-left: 4px solid #3498db;\n}\n\n.help-content p {\n    line-height: 1.6;\n    margin-bottom: 10px;\n}\n\n.help-section img {\n    max-width: 100%;\n    height: auto;\n    border: 1px solid #ddd;\n    border-radius: 4px;\n    box-shadow: 0 2px 4px rgb(0, 0, 0, 0.1);\n}\n";
	var GM_KEY_WEBDAV_URL = "jhs_webdav_url";
	var GM_KEY_WEBDAV_USERNAME = "jhs_webdav_username";
	var GM_KEY_WEBDAV_PASSWORD = "jhs_webdav_password";
	var GM_KEY_BACKUP_PASSWORD = "jhs_backup_password";
	var PBKDF2_ITERATIONS = 1e5;
	var SALT_BYTES = 16;
	var IV_BYTES = 12;
	function base64ToBytes(b64) {
		const binary = atob(b64);
		const bytes = new Uint8Array(binary.length);
		for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
		return bytes;
	}
	function bytesToBase64(bytes) {
		let binary = "";
		for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
		return btoa(binary);
	}
	async function deriveKey(password, salt) {
		const encoder = new TextEncoder();
		const keyMaterial = await crypto.subtle.importKey("raw", encoder.encode(password), "PBKDF2", false, ["deriveKey"]);
		return crypto.subtle.deriveKey({
			name: "PBKDF2",
			salt,
			iterations: PBKDF2_ITERATIONS,
			hash: "SHA-256"
		}, keyMaterial, {
			name: "AES-GCM",
			length: 256
		}, false, ["encrypt", "decrypt"]);
	}
	async function encryptBackupV2(plaintext, password) {
		const encoder = new TextEncoder();
		const salt = crypto.getRandomValues(new Uint8Array(SALT_BYTES));
		const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));
		const key = await deriveKey(password, salt);
		const ciphertext = await crypto.subtle.encrypt({
			name: "AES-GCM",
			iv
		}, key, encoder.encode(plaintext));
		const envelope = {
			v: 2,
			alg: "AES-GCM",
			kdf: "PBKDF2-SHA-256",
			iter: PBKDF2_ITERATIONS,
			salt: bytesToBase64(salt),
			iv: bytesToBase64(iv),
			ct: bytesToBase64(new Uint8Array(ciphertext)),
			ts: new Date().toISOString()
		};
		return JSON.stringify(envelope);
	}
	async function decryptBackupV2(envelopeJson, password) {
		const envelope = JSON.parse(envelopeJson);
		if (envelope.v !== 2) throw new Error(`不支持的备份格式版本: ${envelope.v}`);
		const salt = base64ToBytes(envelope.salt);
		const iv = base64ToBytes(envelope.iv);
		const ct = base64ToBytes(envelope.ct);
		const key = await deriveKey(password, salt);
		const plainBuffer = await crypto.subtle.decrypt({
			name: "AES-GCM",
			iv
		}, key, ct);
		return new TextDecoder().decode(plainBuffer);
	}
	function isBackupV2(content) {
		try {
			const parsed = JSON.parse(content);
			return parsed && parsed.v === 2 && parsed.alg === "AES-GCM";
		} catch {
			return false;
		}
	}
	var BACKUP_LOCAL_STORAGE_KEYS = [
		"jhs_other_site",
		"jhs_other_site_dmm",
		"jhs_dmm_video",
		"jhs_translate",
		"jhs_actress_info",
		"jhs_score_info",
		"jhs_screenShot",
		"jhs_visit_history",
		"jdb:rating_cache_v2",
		"jhs_enabled_sites",
		"jhs_foldCategory",
		"jhs_sortMethod",
		"jhs_fancyboxThumbs",
		"jhs_upgrade_flags",
		"jhs_videoMuted",
		"jhs_magnetHub_selectedEngine",
		"jhs_appAuthorization"
	];
	var BACKUP_GM_KEYS = [
		"jdb:list-reading-status",
		"jdb:list-rating",
		"jdb:list-last-uri",
		"jdb:list-sort",
		"jdb:list-filter-read",
		"jdb:list-filter-rating",
		"jdb:list-waterfall-enabled"
	];
	function collectLocalStorageBackup() {
		const out = {};
		for (const key of BACKUP_LOCAL_STORAGE_KEYS) try {
			const v = localStorage.getItem(key);
			if (v != null && v !== "") out[key] = v;
		} catch {}
		return out;
	}
	function collectGmStorageBackup() {
		const out = {};
		for (const key of BACKUP_GM_KEYS) try {
			const v = GM_getValue(key, void 0);
			if (v !== void 0) out[key] = v;
		} catch {}
		return out;
	}
	var ALLOWED_LOCALSTORAGE_KEYS = new Set(BACKUP_LOCAL_STORAGE_KEYS);
	var ALLOWED_GM_KEYS = new Set(BACKUP_GM_KEYS);
	function stripBackupExtras(data) {
		const ls = data.__localStorage;
		const gm = data.__gmStorage;
		delete data.__localStorage;
		delete data.__gmStorage;
		return {
			ls: ls && typeof ls === "object" ? ls : void 0,
			gm: gm && typeof gm === "object" ? gm : void 0
		};
	}
	function applyBackupExtras(extras) {
		if (extras.ls) for (const key of Object.keys(extras.ls)) {
			if (!ALLOWED_LOCALSTORAGE_KEYS.has(key)) {
				console.warn(`[JHS 备份] 跳过未授权的 localStorage 键: ${key}`);
				continue;
			}
			const raw = extras.ls[key];
			if (raw == null || raw === "") continue;
			try {
				localStorage.setItem(key, typeof raw === "string" ? raw : JSON.stringify(raw));
			} catch (err) {
				console.warn(`[JHS 备份] 恢复 localStorage.${key} 失败:`, err instanceof Error ? err.message : err);
			}
		}
		if (extras.gm) for (const key of Object.keys(extras.gm)) {
			if (!ALLOWED_GM_KEYS.has(key)) {
				console.warn(`[JHS 备份] 跳过未授权的 GM 键: ${key}`);
				continue;
			}
			try {
				GM_setValue(key, extras.gm[key]);
			} catch (err) {
				console.warn(`[JHS 备份] 恢复 GM.${key} 失败:`, err instanceof Error ? err.message : err);
			}
		}
	}
	var STATUS_LIST = [
		"filter",
		"favorite",
		"hasDown",
		"hasWatch"
	];
	var STATUS_CONFIG = {
		favorite: {
			label: "⭐ 已收藏",
			color: "#25b1dc"
		},
		hasWatch: {
			label: "🔍 已观看",
			color: "#d7a80c"
		},
		filter: {
			label: "🚫 已屏蔽",
			color: "#de3333"
		},
		hasDown: {
			label: "💾 已下载",
			color: "#1f7a3d"
		}
	};
	var GM_KEY_CAR_STATUS_DATA = "jhs_car_status_data";
	var GM_KEY_CAR_STATUS_DELTA = "jhs_car_status_delta";
	var GM_KEY_CAR_STATUS_REVISION = "jhs_car_status_revision";
	var MISSAV_DB_NAME = "MissAV-CarStatus";
	var MISSAV_DB_STORE = "cars";
	var MISSAV_DB_META_STORE = "sync_meta";
	var MISSAV_SYNC_META_KEY = "car_status_revision";
	var MISSAV_SYNC_LOCK_NAME = "jhs-missav-car-status-sync";
	var LOG_PREFIX_JHS = "[JHS CarSync]";
	var LOG_PREFIX_MISSAV = "[MissAV]";
	function normalizeUrl(rawUrl) {
		let path;
		try {
			if (/^https?:\/\//.test(rawUrl)) {
				const u = new URL(rawUrl);
				path = u.pathname + (u.search || "");
			} else if (rawUrl.startsWith("/")) path = rawUrl;
			else return {
				code: rawUrl,
				malformed: true
			};
		} catch {
			return {
				code: rawUrl,
				malformed: true
			};
		}
		if (path.startsWith("/v/")) return {
			code: path.slice(3),
			malformed: false
		};
		return {
			code: path,
			malformed: false
		};
	}
	function buildJavdbUrl(urlPath) {
		if (!urlPath) return "https://javdb.com";
		if (urlPath.startsWith("/")) return "https://javdb.com" + urlPath;
		return "https://javdb.com/v/" + urlPath;
	}
	function toColumnar(carList) {
		const groups = Object.create(null);
		let dropped = 0;
		let malformed = 0;
		for (const item of carList) {
			if (!item || typeof item !== "object") {
				dropped++;
				continue;
			}
			if (!item.carNum || !item.url || !item.status) {
				dropped++;
				continue;
			}
			const status = item.status;
			if (!groups[status]) groups[status] = new Map();
			const { code, malformed: bad } = normalizeUrl(item.url);
			if (bad) malformed++;
			groups[status].set(item.carNum, {
				url: code,
				updateDate: item.updateDate || ""
			});
		}
		const byStatus = {};
		for (const status of Object.keys(groups)) {
			const map = groups[status];
			const carNums = [];
			const urls = [];
			const update_date = [];
			for (const [carNum, { url, updateDate }] of map) {
				carNums.push(carNum);
				urls.push(url);
				update_date.push(updateDate);
			}
			byStatus[status] = {
				carNums,
				urls,
				update_date
			};
		}
		return {
			byStatus,
			dropped,
			malformed
		};
	}
	function columnarToFlat(store) {
		const records = [];
		for (const status of Object.keys(store)) {
			const group = store[status];
			if (!group || !group.carNums || !group.urls) continue;
			const { carNums, urls } = group;
			for (let i = 0; i < carNums.length; i++) records.push({
				carNum: carNums[i],
				status,
				url_path: urls[i]
			});
		}
		return records;
	}
	function countColumnar(store) {
		let n = 0;
		for (const status of Object.keys(store)) {
			const col = store[status];
			if (col && col.carNums) n += col.carNums.length;
		}
		return n;
	}
	async function gzipToBase64(value) {
		try {
			if (typeof CompressionStream === "undefined") return null;
			const json = JSON.stringify(value);
			const blob = new Blob([json], { type: "application/json" });
			const cs = new CompressionStream("gzip");
			const stream = blob.stream().pipeThrough(cs);
			const buf = await new Response(stream).arrayBuffer();
			const bytes = new Uint8Array(buf);
			let binary = "";
			const chunkSize = 32768;
			for (let i = 0; i < bytes.length; i += chunkSize) binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
			return btoa(binary);
		} catch {
			return null;
		}
	}
	async function gunzipFromBase64(base64) {
		try {
			if (typeof DecompressionStream === "undefined") return null;
			const binary = atob(base64);
			const bytes = new Uint8Array(binary.length);
			for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
			const ds = new DecompressionStream("gzip");
			const stream = new Blob([bytes]).stream().pipeThrough(ds);
			const text = await new Response(stream).text();
			return JSON.parse(text);
		} catch {
			return null;
		}
	}
	var CONTROL_CHAR_REGEX$1 = new RegExp(`[\\u0000-\\u001f\\u007f]`);
	function isPlainRecord(value) {
		if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
		const prototype = Object.getPrototypeOf(value);
		return prototype === Object.prototype || prototype === null;
	}
	function isStringArray(value) {
		return Array.isArray(value) && value.every((item) => typeof item === "string");
	}
	function isSafeUrlPath(value) {
		const raw = value.trim();
		if (!raw || CONTROL_CHAR_REGEX$1.test(raw)) return false;
		if (/^https?:\/\//i.test(raw) || raw.startsWith("/")) return !normalizeUrl(raw).malformed;
		return !raw.startsWith("//") && !/^[a-z][a-z\d+.-]*:/i.test(raw);
	}
	function validateColumnarSnapshot(store, expectedCount) {
		if (!Number.isInteger(expectedCount) || expectedCount < 0) return {
			ok: false,
			reason: "快照 count 必须是非负整数"
		};
		if (!isPlainRecord(store)) return {
			ok: false,
			reason: "快照列存必须是普通对象"
		};
		const validStatuses = new Set(STATUS_LIST);
		const seenCarNums = new Set();
		const records = [];
		for (const [status, rawGroup] of Object.entries(store)) {
			if (!validStatuses.has(status)) return {
				ok: false,
				reason: `快照包含未知状态:${status}`
			};
			if (!isPlainRecord(rawGroup)) return {
				ok: false,
				reason: `状态 ${status} 的列不是普通对象`
			};
			const carNums = rawGroup.carNums;
			const urls = rawGroup.urls;
			const updateDates = rawGroup.update_date;
			if (!isStringArray(carNums) || !isStringArray(urls)) return {
				ok: false,
				reason: `状态 ${status} 的 carNums/urls 必须是字符串数组`
			};
			if (carNums.length !== urls.length) return {
				ok: false,
				reason: `状态 ${status} 的 carNums/urls 长度不一致`
			};
			if (updateDates !== void 0 && (!isStringArray(updateDates) || updateDates.length !== carNums.length)) return {
				ok: false,
				reason: `状态 ${status} 的 update_date 长度或类型无效`
			};
			for (let index = 0; index < carNums.length; index++) {
				const carNum = carNums[index].trim();
				const urlPath = urls[index].trim();
				if (!carNum || !urlPath) return {
					ok: false,
					reason: `状态 ${status} 包含空番号或空路径`
				};
				if (!isSafeUrlPath(urlPath)) return {
					ok: false,
					reason: `状态 ${status} 包含不安全链接`
				};
				const normalizedCarNum = carNum.toUpperCase();
				if (seenCarNums.has(normalizedCarNum)) return {
					ok: false,
					reason: `快照包含重复番号:${carNum}`
				};
				seenCarNums.add(normalizedCarNum);
				records.push({
					carNum,
					status,
					url_path: urlPath
				});
			}
		}
		const count = expectedCount;
		if (records.length !== count) return {
			ok: false,
			reason: `快照记录数不一致:声明 ${count},实际 ${records.length}`
		};
		return {
			ok: true,
			records,
			count
		};
	}
	async function withExclusiveLock(lockName, task) {
		const browserNavigator = typeof navigator === "undefined" ? void 0 : navigator;
		if (!browserNavigator?.locks) return task();
		return browserNavigator.locks.request(lockName, { mode: "exclusive" }, task);
	}
	var KeyedQueue = class {
		queues = new Map();
		enqueue(key, task) {
			const prev = this.queues.get(key) ?? Promise.resolve();
			let resolveTail;
			const tail = new Promise((resolve) => {
				resolveTail = resolve;
			});
			this.queues.set(key, tail);
			const result = prev.then(task, task);
			result.then(() => resolveTail(), () => resolveTail());
			tail.then(() => {
				if (this.queues.get(key) === tail) this.queues.delete(key);
			});
			return result;
		}
	};
	var INTENT_PREFIX = "jhs:car-sync-intent:";
	function writeIntent(revision, kind) {
		try {
			localStorage.setItem(INTENT_PREFIX + revision, JSON.stringify({
				type: kind,
				revision,
				ts: Date.now()
			}));
		} catch {}
	}
	function clearIntent(revision) {
		try {
			localStorage.removeItem(INTENT_PREFIX + revision);
		} catch {}
	}
	function readPendingIntents() {
		const intents = [];
		try {
			for (let i = 0; i < localStorage.length; i++) {
				const key = localStorage.key(i);
				if (key?.startsWith(INTENT_PREFIX)) try {
					const value = JSON.parse(localStorage.getItem(key) || "");
					if (value && typeof value.revision === "number") intents.push(value);
				} catch {}
			}
		} catch {}
		return intents.sort((a, b) => a.ts - b.ts);
	}
	function cleanStaleIntents(maxAgeMs = 864e5) {
		const cutoff = Date.now() - maxAgeMs;
		try {
			const staleKeys = [];
			for (let i = 0; i < localStorage.length; i++) {
				const key = localStorage.key(i);
				if (key?.startsWith(INTENT_PREFIX)) try {
					const value = JSON.parse(localStorage.getItem(key) || "");
					if (value && typeof value.ts === "number" && value.ts < cutoff) staleKeys.push(key);
				} catch {
					staleKeys.push(key);
				}
			}
			staleKeys.forEach((k) => localStorage.removeItem(k));
		} catch {}
	}
	function openLocalDB() {
		return new Promise((resolve, reject) => {
			const request = indexedDB.open(MISSAV_DB_NAME, 2);
			request.onupgradeneeded = (event) => {
				const db = event.target.result;
				const oldVersion = event.oldVersion;
				if (!db.objectStoreNames.contains("cars")) db.createObjectStore(MISSAV_DB_STORE, { keyPath: "carNum" });
				if (oldVersion < 2 && !db.objectStoreNames.contains("sync_meta")) db.createObjectStore(MISSAV_DB_META_STORE, { keyPath: "key" });
			};
			request.onsuccess = () => resolve(request.result);
			request.onerror = () => reject(request.error);
			request.onblocked = () => reject(new Error("数据库被阻塞,请关闭其他标签页后刷新"));
		});
	}
	async function queryLocalCars(carNums) {
		if (!carNums || carNums.length === 0) return new Map();
		const db = await openLocalDB();
		try {
			return await new Promise((resolve) => {
				const store = db.transaction(MISSAV_DB_STORE, "readonly").objectStore(MISSAV_DB_STORE);
				const result = new Map();
				let pending = carNums.length;
				if (pending === 0) {
					resolve(result);
					return;
				}
				for (const cn of carNums) {
					const req = store.get(cn);
					req.onsuccess = () => {
						if (req.result) result.set(cn, {
							status: req.result.status,
							url: req.result.url
						});
						pending--;
						if (pending === 0) resolve(result);
					};
					req.onerror = () => {
						pending--;
						if (pending === 0) resolve(result);
					};
				}
			});
		} finally {
			db.close();
		}
	}
	async function deleteLocalCars(carNums) {
		if (!carNums || carNums.length === 0) return;
		const db = await openLocalDB();
		try {
			await new Promise((resolve) => {
				const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
				const store = tx.objectStore(MISSAV_DB_STORE);
				for (const cn of carNums) store.delete(cn);
				tx.oncomplete = () => resolve();
				tx.onerror = () => resolve();
			});
		} finally {
			db.close();
		}
	}
	async function exportLocalDB() {
		const db = await openLocalDB();
		try {
			return await new Promise((resolve, reject) => {
				const store = db.transaction(MISSAV_DB_STORE, "readonly").objectStore(MISSAV_DB_STORE);
				const result = [];
				const req = store.openCursor();
				req.onsuccess = (event) => {
					const cursor = event.target.result;
					if (cursor) {
						result.push({
							carNum: cursor.value.carNum,
							status: cursor.value.status,
							url: cursor.value.url
						});
						cursor.continue();
					} else resolve(result);
				};
				req.onerror = () => reject(req.error);
			});
		} finally {
			db.close();
		}
	}
	var CONTROL_CHAR_REGEX = new RegExp(`[\\u0000-\\u001f\\u007f]`);
	var JAVDB_BASE_URL = "https://javdb.com";
	var JAVDB_HOSTNAME = "javdb.com";
	function normalizeJavdbUrlPath(value) {
		if (typeof value !== "string") throw new Error("车辆记录链接必须是字符串");
		const raw = value.trim();
		if (!raw || CONTROL_CHAR_REGEX.test(raw)) throw new Error("车辆记录链接为空或包含控制字符");
		let candidate;
		try {
			if (/^https?:\/\//i.test(raw)) candidate = new URL(raw);
			else if (raw.startsWith("/")) {
				if (raw.startsWith("//")) throw new Error("不允许协议相对链接");
				candidate = new URL(raw, JAVDB_BASE_URL);
			} else {
				if (/^[a-z][a-z\d+.-]*:/i.test(raw)) throw new Error("不允许非 HTTPS 链接");
				candidate = new URL(`/v/${raw}`, JAVDB_BASE_URL);
				if (!candidate.pathname.startsWith("/v/")) throw new Error("车辆短码路径无效");
			}
		} catch (error) {
			throw new Error(`车辆记录链接无效:${error instanceof Error ? error.message : String(error)}`);
		}
		if (candidate.protocol !== "https:" || candidate.hostname !== JAVDB_HOSTNAME) throw new Error("车辆记录链接必须指向 https://javdb.com");
		if (candidate.pathname === "/") throw new Error("车辆记录链接路径为空");
		const suffix = candidate.pathname.startsWith("/v/") ? candidate.pathname.slice(3) : candidate.pathname;
		if (!suffix) throw new Error("车辆记录链接路径为空");
		return `${suffix}${candidate.search}${candidate.hash}`;
	}
	function normalizeLocalRecord(record) {
		if (record === null || typeof record !== "object") throw new Error("车辆记录格式无效");
		if (typeof record.carNum !== "string" || record.carNum.trim() === "") throw new Error("车辆记录番号为空");
		if (typeof record.status !== "string" || !STATUS_LIST.includes(record.status.trim())) throw new Error(`车辆记录状态无效:${String(record.status)}`);
		return {
			carNum: record.carNum.trim().toUpperCase(),
			status: record.status.trim(),
			url_path: normalizeJavdbUrlPath(record.url_path)
		};
	}
	function canApplyRevision(incomingRevision, incomingKind, current) {
		if (!Number.isInteger(incomingRevision) || incomingRevision < 0) return false;
		if (!current) return true;
		if (incomingRevision < current.revision) return false;
		if (incomingRevision === current.revision && incomingKind === "full") return false;
		return true;
	}
	async function readAppliedRevision() {
		const db = await openLocalDB();
		try {
			return await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_META_STORE, "readonly");
				const request = tx.objectStore(MISSAV_DB_META_STORE).get(MISSAV_SYNC_META_KEY);
				request.onsuccess = () => {
					const value = request.result;
					if (value && value.key === "car_status_revision" && typeof value.revision === "number" && Number.isInteger(value.revision) && value.revision >= 0 && (value.kind === "full" || value.kind === "delta")) resolve(value);
					else resolve(null);
				};
				request.onerror = () => reject(request.error || new Error("读取同步修订号失败"));
				tx.onerror = () => reject(tx.error || new Error("读取同步元数据事务失败"));
			});
		} finally {
			db.close();
		}
	}
	async function writeAppliedRevision(meta) {
		const db = await openLocalDB();
		try {
			await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_META_STORE, "readwrite");
				tx.objectStore(MISSAV_DB_META_STORE).put(meta);
				tx.oncomplete = () => resolve();
				tx.onerror = () => reject(tx.error || new Error("写入同步修订号失败"));
				tx.onabort = () => reject(tx.error || new Error("写入同步修订号事务中止"));
			});
		} finally {
			db.close();
		}
	}
	async function clearAppliedRevision() {
		const db = await openLocalDB();
		try {
			await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_META_STORE, "readwrite");
				tx.objectStore(MISSAV_DB_META_STORE).delete(MISSAV_SYNC_META_KEY);
				tx.oncomplete = () => resolve();
				tx.onerror = () => reject(tx.error || new Error("清理同步修订号失败"));
				tx.onabort = () => reject(tx.error || new Error("清理同步修订号事务中止"));
			});
		} finally {
			db.close();
		}
	}
	async function withSyncRevision(revision, kind, task, rollback) {
		return withExclusiveLock(MISSAV_SYNC_LOCK_NAME, async () => {
			const current = await readAppliedRevision();
			if (!canApplyRevision(revision, kind, current)) return { applied: false };
			let metadataWriteStarted = false;
			try {
				const value = await task();
				metadataWriteStarted = true;
				await writeAppliedRevision({
					key: MISSAV_SYNC_META_KEY,
					revision,
					kind
				});
				return {
					applied: true,
					value
				};
			} catch (applyError) {
				const recoveryErrors = [];
				if (rollback) try {
					await rollback();
				} catch (rollbackError) {
					recoveryErrors.push(`数据回滚失败:${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
				}
				if (metadataWriteStarted) try {
					if (current) await writeAppliedRevision(current);
					else await clearAppliedRevision();
				} catch (metadataRollbackError) {
					recoveryErrors.push(`修订号回滚失败:${metadataRollbackError instanceof Error ? metadataRollbackError.message : String(metadataRollbackError)}`);
				}
				if (recoveryErrors.length > 0) {
					const applyMessage = applyError instanceof Error ? applyError.message : String(applyError);
					throw new Error(`同步提交失败(${applyMessage});${recoveryErrors.join(";")}`);
				}
				throw applyError;
			}
		});
	}
	async function upsertLocalCars(records) {
		const BATCH_SIZE = 3e3;
		const normalizedRecords = records.map(normalizeLocalRecord);
		let totalWritten = 0;
		const db = await openLocalDB();
		try {
			for (let i = 0; i < normalizedRecords.length; i += BATCH_SIZE) {
				const batch = normalizedRecords.slice(i, i + BATCH_SIZE);
				totalWritten += await new Promise((resolveBatch, rejectBatch) => {
					const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
					const store = tx.objectStore(MISSAV_DB_STORE);
					let count = 0;
					for (const rec of batch) {
						const req = store.put({
							carNum: rec.carNum,
							status: rec.status,
							url: buildJavdbUrl(rec.url_path),
							updateDate: ""
						});
						req.onsuccess = () => count++;
						req.onerror = () => console.warn("[MissAV] 写入失败", rec.carNum, req.error);
					}
					tx.oncomplete = () => resolveBatch(count);
					tx.onerror = () => rejectBatch(tx.error || new Error("事务失败"));
					tx.onabort = () => rejectBatch(tx.error || new Error("事务中止"));
				});
			}
			return totalWritten;
		} finally {
			db.close();
		}
	}
	async function readLocalCarsSnapshot() {
		const db = await openLocalDB();
		try {
			return await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_STORE, "readonly");
				const store = tx.objectStore(MISSAV_DB_STORE);
				const records = [];
				const request = store.openCursor();
				request.onsuccess = () => {
					const cursor = request.result;
					if (!cursor) return;
					records.push(cursor.value);
					cursor.continue();
				};
				request.onerror = () => reject(request.error || new Error("读取本地状态快照失败"));
				tx.oncomplete = () => resolve(records);
				tx.onerror = () => reject(tx.error || new Error("读取本地状态快照事务失败"));
				tx.onabort = () => reject(tx.error || new Error("读取本地状态快照事务中止"));
			});
		} finally {
			db.close();
		}
	}
	async function restoreLocalCarsSnapshot(snapshot) {
		const snapshotKeys = new Set(snapshot.map((record) => String(record.carNum)));
		const db = await openLocalDB();
		try {
			await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
				const store = tx.objectStore(MISSAV_DB_STORE);
				const request = store.openCursor();
				request.onsuccess = () => {
					const cursor = request.result;
					if (cursor) {
						if (!snapshotKeys.has(String(cursor.primaryKey))) cursor.delete();
						cursor.continue();
						return;
					}
					for (const record of snapshot) store.put(record);
				};
				request.onerror = () => reject(request.error || new Error("恢复本地状态游标失败"));
				tx.oncomplete = () => resolve();
				tx.onerror = () => reject(tx.error || new Error("恢复本地状态事务失败"));
				tx.onabort = () => reject(tx.error || new Error("恢复本地状态事务中止"));
			});
		} finally {
			db.close();
		}
	}
	async function readLocalCarsSelection(carNums) {
		const normalizedCarNums = Array.from(new Set(carNums.map((carNum) => carNum.trim().toUpperCase()).filter(Boolean)));
		if (normalizedCarNums.length === 0) return {
			carNums: [],
			records: []
		};
		const db = await openLocalDB();
		try {
			return {
				carNums: normalizedCarNums,
				records: await new Promise((resolve, reject) => {
					const tx = db.transaction(MISSAV_DB_STORE, "readonly");
					const store = tx.objectStore(MISSAV_DB_STORE);
					const snapshot = [];
					let settled = false;
					const rejectOnce = (error) => {
						if (settled) return;
						settled = true;
						reject(error);
					};
					for (const carNum of normalizedCarNums) {
						const request = store.get(carNum);
						request.onsuccess = () => {
							if (request.result) snapshot.push(request.result);
						};
						request.onerror = () => rejectOnce(request.error || new Error(`读取增量回滚快照失败:${carNum}`));
					}
					tx.oncomplete = () => {
						if (settled) return;
						settled = true;
						resolve(snapshot);
					};
					tx.onerror = () => rejectOnce(tx.error || new Error("读取增量回滚快照事务失败"));
					tx.onabort = () => rejectOnce(tx.error || new Error("读取增量回滚快照事务中止"));
				})
			};
		} finally {
			db.close();
		}
	}
	async function restoreLocalCarsSelection(snapshot) {
		if (snapshot.carNums.length === 0) return;
		const db = await openLocalDB();
		try {
			await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
				const store = tx.objectStore(MISSAV_DB_STORE);
				for (const carNum of snapshot.carNums) store.delete(carNum);
				for (const record of snapshot.records) store.put(record);
				tx.oncomplete = () => resolve();
				tx.onerror = () => reject(tx.error || new Error("恢复增量回滚快照事务失败"));
				tx.onabort = () => reject(tx.error || new Error("恢复增量回滚快照事务中止"));
			});
		} finally {
			db.close();
		}
	}
	async function replaceLocalCars(records, previousSnapshot) {
		const recordsByCarNum = new Map();
		for (const record of records) {
			const normalized = normalizeLocalRecord(record);
			if (recordsByCarNum.has(normalized.carNum)) throw new Error(`快照包含重复番号:${normalized.carNum}`);
			recordsByCarNum.set(normalized.carNum, normalized);
		}
		const validRecords = Array.from(recordsByCarNum.values());
		const rollbackSnapshot = previousSnapshot ?? await readLocalCarsSnapshot();
		try {
			const written = await upsertLocalCars(validRecords);
			if (written !== validRecords.length) throw new Error(`快照写入条数不一致:声明 ${validRecords.length},实际 ${written},已停止删除旧数据`);
			const snapshotKeys = new Set(recordsByCarNum.keys());
			const db = await openLocalDB();
			let deleted = 0;
			try {
				deleted = await new Promise((resolve, reject) => {
					const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
					const request = tx.objectStore(MISSAV_DB_STORE).openCursor();
					let deletedCount = 0;
					request.onsuccess = () => {
						const cursor = request.result;
						if (!cursor) return;
						const rawCarNum = String(cursor.primaryKey);
						const carNum = rawCarNum.toUpperCase();
						if (!snapshotKeys.has(carNum) || rawCarNum !== carNum) {
							cursor.delete();
							deletedCount++;
						}
						cursor.continue();
					};
					request.onerror = () => reject(request.error || new Error("快照对账游标读取失败"));
					tx.oncomplete = () => resolve(deletedCount);
					tx.onerror = () => reject(tx.error || new Error("快照对账事务失败"));
					tx.onabort = () => reject(tx.error || new Error("快照对账事务中止"));
				});
			} finally {
				db.close();
			}
			return {
				written,
				deleted
			};
		} catch (replaceError) {
			try {
				await restoreLocalCarsSnapshot(rollbackSnapshot);
			} catch (rollbackError) {
				const replaceMessage = replaceError instanceof Error ? replaceError.message : String(replaceError);
				const rollbackMessage = rollbackError instanceof Error ? rollbackError.message : String(rollbackError);
				throw new Error(`状态快照对账失败且回滚失败(对账错误:${replaceMessage};回滚错误:${rollbackMessage})`);
			}
			throw replaceError;
		}
	}
	async function importLocalDB(records) {
		return withExclusiveLock(MISSAV_SYNC_LOCK_NAME, async () => {
			if (!Array.isArray(records)) throw new Error("导入记录必须是数组");
			const normalizedRecords = records.map((record) => normalizeLocalRecord({
				carNum: record?.carNum,
				status: record?.status,
				url_path: record?.url
			}));
			const [previousCars, previousRevision] = await Promise.all([readLocalCarsSnapshot(), readAppliedRevision()]);
			let replaced = false;
			try {
				const { written } = await replaceLocalCars(normalizedRecords, previousCars);
				replaced = true;
				await clearAppliedRevision();
				return written;
			} catch (importError) {
				if (!replaced) throw importError;
				const recoveryErrors = [];
				try {
					await restoreLocalCarsSnapshot(previousCars);
				} catch (rollbackError) {
					recoveryErrors.push(`状态数据回滚失败:${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
				}
				try {
					if (previousRevision) await writeAppliedRevision(previousRevision);
					else await clearAppliedRevision();
				} catch (metadataRollbackError) {
					recoveryErrors.push(`修订号回滚失败:${metadataRollbackError instanceof Error ? metadataRollbackError.message : String(metadataRollbackError)}`);
				}
				if (recoveryErrors.length > 0) {
					const importMessage = importError instanceof Error ? importError.message : String(importError);
					throw new Error(`导入失败(${importMessage});${recoveryErrors.join(";")}`);
				}
				throw importError;
			}
		});
	}
	var DB_NAME = "JAV-JHS";
	var STORE_NAME = "appData";
	var MAX_COUNT = 501;
	var BOOTSTRAP_COLORS$1 = [
		{
			name: "primary",
			bg: "#0d6efd",
			text: "#fff"
		},
		{
			name: "secondary",
			bg: "#6c757d",
			text: "#fff"
		},
		{
			name: "success",
			bg: "#198754",
			text: "#fff"
		},
		{
			name: "danger",
			bg: "#dc3545",
			text: "#fff"
		},
		{
			name: "warning",
			bg: "#ffc107",
			text: "#212529"
		},
		{
			name: "info",
			bg: "#0dcaf0",
			text: "#212529"
		},
		{
			name: "dark",
			bg: "#212529",
			text: "#fff"
		}
	];
	var KEYS = {
		MOVIES: "vlt_movies",
		INVENTORY: "vlt_inventory",
		MOVIE_INVENTORY: "vlt_movie_inventory",
		META: "vlt_meta"
	};
	function randomBootstrapStyle() {
		return BOOTSTRAP_COLORS$1[Math.floor(Math.random() * BOOTSTRAP_COLORS$1.length)];
	}
	function openDb() {
		return new Promise((resolve, reject) => {
			const request = indexedDB.open(DB_NAME);
			request.onsuccess = () => resolve(request.result);
			request.onerror = () => reject(request.error);
			request.onupgradeneeded = (event) => {
				const db = event.target.result;
				if (!db.objectStoreNames.contains(STORE_NAME)) db.createObjectStore(STORE_NAME);
			};
		});
	}
	function requestResult(request) {
		return new Promise((resolve, reject) => {
			request.onsuccess = () => resolve(request.result);
			request.onerror = () => reject(request.error);
		});
	}
	function transactionDone(transaction) {
		return new Promise((resolve, reject) => {
			transaction.oncomplete = () => resolve();
			transaction.onabort = () => reject(transaction.error || new Error("IndexedDB 事务已中止"));
			transaction.onerror = () => reject(transaction.error || new Error("IndexedDB 事务失败"));
		});
	}
	function normalizeMeta(value) {
		return {
			...value,
			epoch: Number.isFinite(Number(value?.epoch)) ? Number(value?.epoch) : 0,
			listRevisions: value?.listRevisions ? { ...value.listRevisions } : {}
		};
	}
	function associationDesignations(movieInventory, listId) {
		const suffix = `::${listId}`;
		return Object.keys(movieInventory).filter((key) => movieInventory[key] && key.endsWith(suffix)).map((key) => key.slice(0, -suffix.length));
	}
	function listFingerprint(movieInventory, listId) {
		return associationDesignations(movieInventory, listId).sort().join("");
	}
	function bumpListRevision(meta, listId) {
		meta.listRevisions[listId] = (meta.listRevisions[listId] || 0) + 1;
	}
	async function withState(mode, callback) {
		const db = await openDb();
		const transaction = db.transaction(STORE_NAME, mode);
		const done = transactionDone(transaction);
		const store = transaction.objectStore(STORE_NAME);
		try {
			const [moviesValue, inventoryValue, movieInventoryValue, metaValue] = await Promise.all([
				requestResult(store.get(KEYS.MOVIES)),
				requestResult(store.get(KEYS.INVENTORY)),
				requestResult(store.get(KEYS.MOVIE_INVENTORY)),
				requestResult(store.get(KEYS.META))
			]);
			const state = {
				movies: moviesValue || {},
				inventory: inventoryValue || {},
				movieInventory: movieInventoryValue || {},
				meta: normalizeMeta(metaValue)
			};
			const result = callback(state);
			if (mode === "readwrite") {
				store.put(state.movies, KEYS.MOVIES);
				store.put(state.inventory, KEYS.INVENTORY);
				store.put(state.movieInventory, KEYS.MOVIE_INVENTORY);
				store.put(state.meta, KEYS.META);
			}
			await done;
			return result;
		} catch (error) {
			try {
				transaction.abort();
			} catch {}
			await done.catch(() => {});
			throw error;
		} finally {
			db.close();
		}
	}
	function validateSnapshot(snapshot) {
		if (!snapshot.listId || !snapshot.name || !snapshot.url) throw new Error("服务端清单快照缺少 listId/name/url");
		if (!Number.isInteger(snapshot.expectedCount) || snapshot.expectedCount < 0) throw new Error("服务端清单快照数量无效");
		if (snapshot.movies.length !== snapshot.expectedCount) throw new Error(`服务端清单快照不完整:期望 ${snapshot.expectedCount},实际 ${snapshot.movies.length}`);
		const designations = new Set();
		for (const movie of snapshot.movies) {
			if (!movie.designation || !movie.href) throw new Error("服务端清单快照包含空番号或空链接");
			if (designations.has(movie.designation)) throw new Error(`服务端清单快照包含重复番号:${movie.designation}`);
			designations.add(movie.designation);
		}
	}
	async function sync(designation, listId, movie, list, action, options = {}) {
		return withState("readwrite", (state) => {
			const { movies, inventory, movieInventory, meta } = state;
			const movieExisted = !!movies[designation];
			const score = movie.score != null ? Number(movie.score) : null;
			const previousMovie = movies[designation];
			movies[designation] = {
				designation,
				href: movie.href,
				title: movie.title ?? null,
				coverSrc: movie.cover_src ?? null,
				score: Number.isFinite(score) ? score : null,
				releaseDate: movie.release_date ?? null,
				createdAt: previousMovie?.createdAt ?? new Date().toISOString(),
				series: movie.series ?? null,
				code: movie.code ?? null
			};
			const listExisted = !!inventory[listId];
			if (!listExisted) inventory[listId] = {
				listId,
				name: list.name,
				url: list.url ?? null,
				count: 0,
				style: randomBootstrapStyle()
			};
			const assocKey = `${designation}::${listId}`;
			const actualCount = associationDesignations(movieInventory, listId).length;
			inventory[listId].count = actualCount;
			let association;
			if (action === "add") if (movieInventory[assocKey]) association = "existed";
			else if (actualCount >= MAX_COUNT && !options.serverConfirmed) association = "limit_exceeded";
			else {
				movieInventory[assocKey] = true;
				inventory[listId].count = actualCount + 1;
				association = "created";
			}
			else if (movieInventory[assocKey]) {
				delete movieInventory[assocKey];
				inventory[listId].count = Math.max(0, actualCount - 1);
				association = "deleted";
			} else association = "unchanged";
			bumpListRevision(meta, listId);
			return {
				movie: movieExisted ? "existed" : "created",
				list: listExisted ? "existed" : "created",
				association
			};
		});
	}
	async function queryMoviesLists(designations) {
		return withState("readonly", (state) => {
			const result = {};
			for (const designation of designations) result[designation] = [];
			for (const key of Object.keys(state.movieInventory)) {
				if (!state.movieInventory[key]) continue;
				const separator = key.indexOf("::");
				if (separator < 0) continue;
				const designation = key.slice(0, separator);
				if (result[designation] === void 0) continue;
				const listId = key.slice(separator + 2);
				const list = state.inventory[listId];
				if (!list) continue;
				result[designation].push({
					name: list.name,
					url: list.url,
					style: list.style
				});
			}
			return result;
		});
	}
	async function check(designation, listId) {
		return withState("readonly", (state) => ({
			movie: !!state.movies[designation],
			inventory: !!state.inventory[listId],
			movieInventory: !!state.movieInventory[`${designation}::${listId}`]
		}));
	}
	async function getAllInventory() {
		return withState("readonly", (state) => state.inventory);
	}
	async function deleteList(listId) {
		return withState("readwrite", (state) => {
			const inventoryDeleted = !!state.inventory[listId];
			delete state.inventory[listId];
			const suffix = `::${listId}`;
			let associations = 0;
			for (const key of Object.keys(state.movieInventory)) {
				if (!key.endsWith(suffix)) continue;
				delete state.movieInventory[key];
				associations++;
			}
			bumpListRevision(state.meta, listId);
			return {
				inventory: inventoryDeleted,
				associations
			};
		});
	}
	async function renameList(listId, newName) {
		return withState("readwrite", (state) => {
			if (!state.inventory[listId]) return false;
			state.inventory[listId].name = newName;
			bumpListRevision(state.meta, listId);
			return true;
		});
	}
	async function getListReconcileState(listId, designation) {
		return withState("readonly", (state) => ({
			inventory: state.inventory[listId] || null,
			actualCount: associationDesignations(state.movieInventory, listId).length,
			hasDesignation: designation === void 0 ? null : !!state.movieInventory[`${designation}::${listId}`],
			guard: {
				epoch: state.meta.epoch,
				revision: state.meta.listRevisions[listId] || 0,
				fingerprint: listFingerprint(state.movieInventory, listId)
			}
		}));
	}
	async function getListAssociationCounts() {
		return withState("readonly", (state) => {
			const counts = {};
			for (const listId of Object.keys(state.inventory)) counts[listId] = 0;
			for (const key of Object.keys(state.movieInventory)) {
				if (!state.movieInventory[key]) continue;
				const separator = key.indexOf("::");
				if (separator < 0) continue;
				const listId = key.slice(separator + 2);
				counts[listId] = (counts[listId] || 0) + 1;
			}
			return counts;
		});
	}
	async function reconcileListSnapshot(snapshot, guard) {
		validateSnapshot(snapshot);
		return withState("readwrite", (state) => {
			const currentGuard = {
				epoch: state.meta.epoch,
				revision: state.meta.listRevisions[snapshot.listId] || 0,
				fingerprint: listFingerprint(state.movieInventory, snapshot.listId)
			};
			if (currentGuard.epoch !== guard.epoch || currentGuard.revision !== guard.revision || currentGuard.fingerprint !== guard.fingerprint) return { status: "conflict" };
			const previous = new Set(associationDesignations(state.movieInventory, snapshot.listId));
			const incoming = new Set(snapshot.movies.map((movie) => movie.designation));
			const now = new Date().toISOString();
			for (const movie of snapshot.movies) {
				const existing = state.movies[movie.designation];
				state.movies[movie.designation] = existing ? {
					...existing,
					href: movie.href || existing.href,
					title: movie.title ?? existing.title,
					coverSrc: movie.coverSrc ?? existing.coverSrc,
					score: movie.score ?? existing.score,
					releaseDate: movie.releaseDate ?? existing.releaseDate,
					series: movie.series ?? existing.series,
					code: movie.code ?? existing.code,
					createdAt: existing.createdAt ?? movie.createdAt ?? now
				} : {
					...movie,
					createdAt: movie.createdAt ?? now
				};
			}
			const suffix = `::${snapshot.listId}`;
			for (const key of Object.keys(state.movieInventory)) if (key.endsWith(suffix)) delete state.movieInventory[key];
			for (const designation of incoming) state.movieInventory[`${designation}::${snapshot.listId}`] = true;
			const existingList = state.inventory[snapshot.listId];
			state.inventory[snapshot.listId] = {
				listId: snapshot.listId,
				name: snapshot.name,
				url: snapshot.url,
				count: snapshot.expectedCount,
				style: existingList?.style ?? randomBootstrapStyle()
			};
			bumpListRevision(state.meta, snapshot.listId);
			let added = 0;
			let removed = 0;
			for (const designation of incoming) if (!previous.has(designation)) added++;
			for (const designation of previous) if (!incoming.has(designation)) removed++;
			return {
				status: "applied",
				added,
				removed,
				count: snapshot.expectedCount
			};
		});
	}
	async function importData$1(data) {
		return withState("readwrite", (state) => {
			const nextEpoch = state.meta.epoch + 1;
			state.movies = data.movies;
			state.inventory = data.inventory;
			state.movieInventory = data.movieInventory;
			state.meta = {
				version: data._version,
				exportedAt: data._exportedAt,
				importedAt: new Date().toISOString(),
				source: data._source,
				epoch: nextEpoch,
				listRevisions: {}
			};
			return {
				movies: Object.keys(data.movies).length,
				inventory: Object.keys(data.inventory).length,
				movieInventory: Object.keys(data.movieInventory).length
			};
		});
	}
	async function isImported() {
		return withState("readonly", (state) => !!state.meta.importedAt);
	}
	async function exportData$1() {
		return withState("readonly", (state) => ({
			_version: state.meta.version ?? 1,
			_exportedAt: state.meta.exportedAt ?? new Date().toISOString(),
			_source: "IndexedDB (local export)",
			movies: state.movies,
			inventory: state.inventory,
			movieInventory: state.movieInventory
		}));
	}
	var VltDb = class {
		static sync = sync;
		static queryMoviesLists = queryMoviesLists;
		static check = check;
		static getListReconcileState = getListReconcileState;
		static getListAssociationCounts = getListAssociationCounts;
		static reconcileListSnapshot = reconcileListSnapshot;
		static importData = importData$1;
		static isImported = isImported;
		static getAllInventory = getAllInventory;
		static deleteList = deleteList;
		static renameList = renameList;
		static exportData = exportData$1;
	};
	var TOAST_SVG_ICONS = {
		success: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>",
		error: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/></svg>",
		warning: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"17.01\"/></svg>",
		info: "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"8.01\"/></svg>"
	};
	function VltToastContent({ type, msg }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("span", {
			className: "jdb-toast__icon",
			dangerouslySetInnerHTML: { __html: TOAST_SVG_ICONS[type] }
		}), (0, import_jsx_runtime.jsx)("span", {
			className: "jdb-toast__msg",
			children: msg
		})] });
	}
	var queue$1 = {
		MAX_VISIBLE: 2,
		SIMULTANEOUS_WINDOW: 500,
		EXTRA_DURATION: 1e3,
		visible: [],
		overflow: [],
		lastAddTime: 0
	};
	function getToastContainer() {
		let el = document.getElementById("jdb-toast-container");
		if (!el) {
			el = document.createElement("div");
			el.id = "jdb-toast-container";
			document.body.appendChild(el);
		}
		return el;
	}
	function promoteOverflow() {
		if (queue$1.overflow.length === 0 || queue$1.visible.length >= queue$1.MAX_VISIBLE) return;
		const stacked = queue$1.visible.find((v) => v.el.classList.contains("jdb-toast--stacked"));
		if (stacked) stacked.el.classList.remove("jdb-toast--stacked");
		const next = queue$1.overflow.shift();
		getToastContainer().appendChild(next.el);
		next.el.offsetHeight;
		const now = Date.now();
		const isSimultaneous = now - queue$1.lastAddTime < queue$1.SIMULTANEOUS_WINDOW;
		let adjustedDuration = next.duration;
		if (isSimultaneous) adjustedDuration += queue$1.EXTRA_DURATION;
		queue$1.lastAddTime = now;
		queue$1.visible.push({
			el: next.el,
			timerId: setTimeout(() => dismissToast(next.el), adjustedDuration),
			createdAt: now
		});
	}
	function dismissToast(el) {
		const idx = queue$1.visible.findIndex((v) => v.el === el);
		if (idx < 0) return;
		const onTransitionEnd = () => {
			el.removeEventListener("transitionend", onTransitionEnd);
			el.remove();
			const i = queue$1.visible.findIndex((v) => v.el === el);
			if (i >= 0) queue$1.visible.splice(i, 1);
			promoteOverflow();
		};
		el.classList.add("removing");
		el.addEventListener("transitionend", onTransitionEnd);
		setTimeout(() => {
			if (el.parentNode) {
				el.remove();
				const i = queue$1.visible.findIndex((v) => v.el === el);
				if (i >= 0) queue$1.visible.splice(i, 1);
				promoteOverflow();
			}
		}, 300);
		if (idx >= 0) clearTimeout(queue$1.visible[idx].timerId);
	}
	function showToast$1(msg, type = "info", duration = 2500) {
		const container = getToastContainer();
		const toast = document.createElement("div");
		toast.className = `jdb-toast jdb-toast--${type}`;
		toast.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(VltToastContent, {
			type,
			msg
		}));
		toast.addEventListener("click", () => dismissToast(toast));
		if (queue$1.visible.length < queue$1.MAX_VISIBLE) {
			const now = Date.now();
			const isSimultaneous = now - queue$1.lastAddTime < queue$1.SIMULTANEOUS_WINDOW;
			let adjustedDuration = duration;
			if (isSimultaneous) adjustedDuration += queue$1.EXTRA_DURATION;
			queue$1.lastAddTime = now;
			container.appendChild(toast);
			queue$1.visible.push({
				el: toast,
				timerId: setTimeout(() => dismissToast(toast), adjustedDuration),
				createdAt: now
			});
		} else {
			toast.classList.add("jdb-toast--stacked");
			toast.addEventListener("click", (e) => {
				e.stopPropagation();
				if (queue$1.overflow.find((o) => o.el === toast)) {
					const i = queue$1.overflow.findIndex((o) => o.el === toast);
					queue$1.overflow.splice(i, 1);
					promoteOverflow();
				}
			});
			queue$1.overflow.push({
				el: toast,
				msg,
				type,
				duration
			});
		}
	}
	function downloadJson(content, filename) {
		const blob = new Blob([content], { type: "application/json" });
		const url = URL.createObjectURL(blob);
		const anchor = document.createElement("a");
		anchor.href = url;
		anchor.download = filename;
		document.body.appendChild(anchor);
		anchor.click();
		document.body.removeChild(anchor);
		URL.revokeObjectURL(url);
	}
	async function buildBackupPayload(settings) {
		const exportData = await storageManager.exportData();
		exportData.__meta = {
			credentialId: getCredentialId(),
			autoBackupConfig: settings.autoBackupConfig || DEFAULT_AUTO_BACKUP_CONFIG,
			backupTime: utils.getNowStr("_", "_")
		};
		exportData.__localStorage = collectLocalStorageBackup();
		exportData.__gmStorage = collectGmStorageBackup();
		return exportData;
	}
	function importData(_plugin) {
		try {
			const fileInput = document.createElement("input");
			fileInput.type = "file";
			fileInput.accept = ".json";
			fileInput.onchange = (event) => {
				const file = event.target.files?.[0];
				if (!file) return;
				const reader = new FileReader();
				reader.onload = async (loadEvent) => {
					try {
						let fileContent = String(loadEvent.target?.result ?? "");
						if (isBackupV2(fileContent)) {
							const backupPassword = GM_getValue(GM_KEY_BACKUP_PASSWORD, "");
							if (!backupPassword) {
								show.error("该备份使用 V2 加密,请先在备份面板设置备份口令");
								return;
							}
							try {
								fileContent = await decryptBackupV2(fileContent, backupPassword);
							} catch {
								show.error("备份口令错误或文件已损坏");
								return;
							}
						}
						const parsedData = JSON.parse(fileContent);
						layer.confirm("确定是否要覆盖导入?", {
							icon: 3,
							title: "确认覆盖",
							btn: ["确定", "取消"]
						}, async (layerIndex) => {
							const extras = stripBackupExtras(parsedData);
							await storageManager.importData(parsedData);
							applyBackupExtras(extras);
							show.ok("数据导入成功");
							layer.close(layerIndex);
							location.reload();
						});
					} catch (err) {
						console.error(err);
						show.error("导入失败:文件内容不是有效的JSON格式 " + (err instanceof Error ? err.message : String(err)));
					}
				};
				reader.onerror = () => {
					show.error("读取文件时出错");
				};
				reader.readAsText(file);
			};
			document.body.appendChild(fileInput);
			fileInput.click();
			setTimeout(() => document.body.removeChild(fileInput), 1e3);
		} catch (err) {
			console.error(err);
			show.error("导入数据时出错: " + (err instanceof Error ? err.message : String(err)));
		}
	}
	async function exportData(_plugin) {
		try {
			const settings = await storageManager.getSetting();
			const backupPassword = GM_getValue(GM_KEY_BACKUP_PASSWORD, "");
			let exportText;
			if (backupPassword) exportText = await encryptBackupV2(JSON.stringify(await buildBackupPayload(settings)), backupPassword);
			else exportText = JSON.stringify(await buildBackupPayload(settings));
			const fileName = `${utils.getNowStr("_", "_")}.json`;
			utils.download(exportText, fileName);
			show.ok("数据导出成功");
		} catch (err) {
			console.error(err);
			show.error("导出数据时出错: " + (err instanceof Error ? err.message : String(err)));
		}
	}
	function handleVltImportClick() {
		$("#vlt-file-input").trigger("click");
	}
	async function handleVltFileChange(event) {
		const input = event.target;
		const file = input.files?.[0];
		if (!file) return;
		const $status = $("#vlt-status");
		$status.text("⏳ 导入中...").css("color", "#0d6efd");
		try {
			const text = await file.text();
			const data = JSON.parse(text);
			const stats = await VltDb.importData(data);
			$status.html(`✓ 导入完成:${stats.movies} 部影片, ${stats.inventory} 个清单, ${stats.movieInventory} 条关联`).css("color", "#198754");
			showToast$1(`✓ 导入完成:${stats.movies} 部影片, ${stats.inventory} 个清单, ${stats.movieInventory} 条关联`, "success");
			setTimeout(() => window.location.reload(), 1500);
		} catch (err) {
			const msg = err instanceof Error ? err.message : String(err);
			$status.text(`✗ 导入失败:${msg}`).css("color", "#dc3545");
			showToast$1(`✗ 导入失败:${msg}`, "error");
		}
		input.value = "";
	}
	async function handleVltExportClick() {
		const $status = $("#vlt-status");
		$status.text("⏳ 导出中...").css("color", "#0d6efd");
		try {
			const data = await VltDb.exportData();
			downloadJson(JSON.stringify(data, null, 2), `vlt-export-${new Date().toISOString().split("T")[0]}.json`);
			$status.html(`✓ 导出完成:${Object.keys(data.movies).length} 部影片, ${Object.keys(data.inventory).length} 个清单, ${Object.keys(data.movieInventory).length} 条关联`).css("color", "#198754");
			showToast$1("✓ 导出完成", "success");
		} catch (err) {
			const msg = err instanceof Error ? err.message : String(err);
			$status.text(`✗ 导出失败:${msg}`).css("color", "#dc3545");
			showToast$1(`✗ 导出失败:${msg}`, "error");
		}
	}
	async function handleMissavSync() {
		const $status = $("#missav-status");
		$status.text("⏳ 同步中...").css("color", "#0d6efd");
		try {
			const carList = await storageManager.getCarList();
			if (carList.length === 0) {
				$status.text("✗ car_list 为空").css("color", "#dc3545");
				return;
			}
			const colRes = toColumnar(carList);
			const count = countColumnar(colRes.byStatus);
			const base64 = await gzipToBase64(colRes.byStatus);
			if (!base64) {
				$status.text("✗ 压缩失败").css("color", "#dc3545");
				return;
			}
			const payload = {
				data: base64,
				hwm: new Date().toISOString(),
				count,
				ts: Date.now()
			};
			GM_setValue(GM_KEY_CAR_STATUS_DATA, payload);
			$status.html(`✓ 同步完成:${count} 条记录已推送到 GM 存储`).css("color", "#198754");
			showToast$1(`✓ 同步完成:${count} 条`, "success");
		} catch (err) {
			const msg = err instanceof Error ? err.message : String(err);
			$status.text(`✗ 同步失败:${msg}`).css("color", "#dc3545");
			showToast$1(`✗ 同步失败:${msg}`, "error");
		}
	}
	function handleMissavImportClick() {
		$("#missav-file-input").trigger("click");
	}
	async function handleMissavFileChange(event) {
		const input = event.target;
		const file = input.files?.[0];
		if (!file) return;
		const $status = $("#missav-status");
		$status.text("⏳ 导入中...").css("color", "#0d6efd");
		try {
			const text = await file.text();
			const data = JSON.parse(text);
			let records;
			if (Array.isArray(data)) records = data;
			else if (data.records && Array.isArray(data.records)) records = data.records;
			else records = columnarToFlat(data).map((r) => ({
				carNum: r.carNum,
				status: r.status,
				url: buildJavdbUrl(r.url_path)
			}));
			const written = await importLocalDB(records);
			$status.html(`✓ 导入完成:${written} 条记录`).css("color", "#198754");
			showToast$1(`✓ 导入完成:${written} 条`, "success");
		} catch (err) {
			const msg = err instanceof Error ? err.message : String(err);
			$status.text(`✗ 导入失败:${msg}`).css("color", "#dc3545");
			showToast$1(`✗ 导入失败:${msg}`, "error");
		}
		input.value = "";
	}
	async function handleMissavExportClick() {
		const $status = $("#missav-status");
		$status.text("⏳ 导出中...").css("color", "#0d6efd");
		try {
			const records = await exportLocalDB();
			downloadJson(JSON.stringify(records, null, 2), `missav-status-${new Date().toISOString().split("T")[0]}.json`);
			$status.html(`✓ 导出完成:${records.length} 条记录`).css("color", "#198754");
			showToast$1("✓ 导出完成", "success");
		} catch (err) {
			const msg = err instanceof Error ? err.message : String(err);
			$status.text(`✗ 导出失败:${msg}`).css("color", "#dc3545");
			showToast$1(`✗ 导出失败:${msg}`, "error");
		}
	}
	function PreloadCacheStatsText({ count, missAv, supJav, size }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			"共 ",
			(0, import_jsx_runtime.jsx)("b", { children: count }),
			" 条(MissAv ",
			missAv,
			" / SupJav ",
			supJav,
			")|占用 ",
			size
		] });
	}
	function getCacheStats(key) {
		const raw = localStorage.getItem(key);
		if (!raw) return {
			size: 0,
			count: 0
		};
		const size = new Blob([raw]).size;
		let count = 0;
		try {
			const parsed = JSON.parse(raw);
			if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) count = Object.keys(parsed).length;
			else if (Array.isArray(parsed)) count = parsed.length;
		} catch {}
		return {
			size,
			count
		};
	}
	function formatSize(bytes) {
		if (bytes === 0) return "0 B";
		if (bytes < 1024) return `${bytes} B`;
		if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
		return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
	}
	function refreshCacheStats(_plugin, cacheKey) {
		const stats = getCacheStats(cacheKey);
		const $item = $(`.cache-item[data-cache-key="${cacheKey}"]`);
		$item.find(".cache-size").text(formatSize(stats.size));
		$item.find(".cache-count").text(stats.count > 0 ? `${stats.count} 条` : "空");
	}
	function refreshAllCacheStats(plugin) {
		let totalSize = 0;
		for (const item of plugin.cacheItems) {
			const stats = getCacheStats(item.key);
			totalSize += stats.size;
			const $item = $(`.cache-item[data-cache-key="${item.key}"]`);
			$item.find(".cache-size").text(formatSize(stats.size));
			$item.find(".cache-count").text(stats.count > 0 ? `${stats.count} 条` : "空");
		}
		totalSize += getCacheStats("jhs_other_site_dmm").size;
		$("#cache-total-size").text(`总占用 ${formatSize(totalSize)}`);
	}
	function refreshPreloadCacheStats(_plugin) {
		const stats = getCacheStats("jhs_other_site");
		const raw = localStorage.getItem("jhs_other_site");
		let missAv = 0;
		let supJav = 0;
		if (raw) try {
			const cache = JSON.parse(raw);
			const keys = Object.keys(cache);
			missAv = keys.filter((k) => k.endsWith("_missAv")).length;
			supJav = keys.filter((k) => k.endsWith("_supJav")).length;
		} catch {}
		$("#preload-cache-stats").html(jsxToString((0, import_react.createElement)(PreloadCacheStatsText, {
			count: stats.count,
			missAv,
			supJav,
			size: formatSize(stats.size)
		})));
	}
	function handleCleanCache(plugin, event) {
		const cacheKey = String($(event.currentTarget).data("key"));
		const cacheItem = plugin.cacheItems.find((item) => item.key === cacheKey);
		localStorage.removeItem(cacheKey);
		if (cacheKey === "jhs_dmm_video") localStorage.removeItem("jhs_other_site_dmm");
		show.ok(`${cacheItem.text} 清理成功`);
		$("#cache-data-display").hide();
		refreshCacheStats(plugin, cacheKey);
		refreshAllCacheStats(plugin);
	}
	function handleCleanAllCache(plugin) {
		plugin.cacheItems.forEach((item) => localStorage.removeItem(item.key));
		localStorage.removeItem("jhs_other_site_dmm");
		show.ok("全部缓存已清理");
		$("#cache-data-display").hide();
		refreshAllCacheStats(plugin);
	}
	function handleViewCache(event) {
		const cacheKey = String($(event.currentTarget).data("key"));
		const cachedData = localStorage.getItem(cacheKey);
		const $display = $("#cache-data-display");
		const $pre = $display.find("pre");
		$display.show();
		if (cachedData) try {
			const parsed = JSON.parse(cachedData);
			$pre.text(JSON.stringify(parsed, null, 2));
		} catch {
			$pre.text(cachedData);
		}
		else $pre.text("无数据");
	}
	function handleExportCache(plugin, event) {
		const cacheKey = String($(event.currentTarget).data("key"));
		const cachedData = localStorage.getItem(cacheKey);
		if (!cachedData) {
			show.error("缓存为空,无可导出数据");
			return;
		}
		const cacheItem = plugin.cacheItems.find((item) => item.key === cacheKey);
		downloadJson(cachedData, `${cacheKey}-${new Date().toISOString().split("T")[0]}.json`);
		show.ok(`${cacheItem.text} 已导出`);
	}
	async function loadForm(plugin) {
		const settings = await storageManager.getSetting();
		$("#videoQuality").val(settings.videoQuality);
		$("#reviewCount").val(settings.reviewCount || 20);
		$("#tagPosition").val(settings.tagPosition || "rightTop");
		$("#movieShowType").val(settings.movieShowType || "hide");
		$("#waitCheckCount").val(settings.waitCheckCount || 5);
		const tagNumber = settings.highlightedTagNumber || 1;
		const tagColor = settings.highlightedTagColor || "#ce2222";
		$("#highlightedTagNumber").val(settings.highlightedTagNumber || 1);
		$("#highlightedTagColor").val(settings.highlightedTagColor || "#ce2222");
		$("#highlightedTagLabel").css("border", `${tagNumber}px solid ${tagColor}`);
		$("#enableClog").val(settings.enableClog || "yes");
		$("#clogMsgCount").val(settings.clogMsgCount || 2e3);
		$("#httpTimeout").val(settings.httpTimeout || 5e3);
		$("#httpRetryCount").val(settings.httpRetryCount || 3);
		const webDavUrl = GM_getValue("jhs_webdav_url", "") || settings.webDavUrl || "";
		const webDavUsername = GM_getValue("jhs_webdav_username", "") || settings.webDavUsername || "";
		const webDavPassword = GM_getValue("jhs_webdav_password", "") || settings.webDavPassword || "";
		const backupPwd = GM_getValue("jhs_backup_password", "") || settings.backupPassword || "";
		if (webDavUrl && !GM_getValue("jhs_webdav_url", "")) GM_setValue(GM_KEY_WEBDAV_URL, webDavUrl);
		if (webDavUsername && !GM_getValue("jhs_webdav_username", "")) GM_setValue(GM_KEY_WEBDAV_USERNAME, webDavUsername);
		if (webDavPassword && !GM_getValue("jhs_webdav_password", "")) GM_setValue(GM_KEY_WEBDAV_PASSWORD, webDavPassword);
		if (backupPwd && !GM_getValue("jhs_backup_password", "")) GM_setValue(GM_KEY_BACKUP_PASSWORD, backupPwd);
		$("#webDavUrl").val(webDavUrl);
		$("#webDavUsername").val(webDavUsername);
		$("#webDavPassword").val(webDavPassword);
		$("#backupPassword").val(backupPwd);
		const autoBackupConfig = settings.autoBackupConfig || DEFAULT_AUTO_BACKUP_CONFIG;
		$("#enableAutoBackup").prop("checked", autoBackupConfig.enabled);
		$("#autoBackupFrequency").val(autoBackupConfig.frequency);
		$("#credentialIdDisplay").val(getCredentialId());
		$("#enableFavoriteActresses").prop("checked", !settings.enableFavoriteActresses || settings.enableFavoriteActresses === "yes");
		$("#enableSaveActressCarInfo").prop("checked", !!settings.enableSaveActressCarInfo && settings.enableSaveActressCarInfo === "yes");
		const otherSitePlugin = plugin.getBean("OtherSitePlugin");
		const missAvUrl = await otherSitePlugin.getMissAvUrl();
		const supJavUrl = await otherSitePlugin.getSupJavUrl();
		$("#missAvUrl").val(missAvUrl);
		$("#supJavUrl").val(supJavUrl);
		$("#enablePreload").prop("checked", !settings.enablePreload || settings.enablePreload === "yes");
		$("#enablePreloadStatus").prop("checked", !settings.enablePreloadStatus || settings.enablePreloadStatus === "yes");
		$("#preloadDebounce").val(settings.preloadDebounce || 300);
		$("#preloadConcurrency").val(settings.preloadConcurrency || 1);
		$("#preloadCacheTTL").val(settings.preloadCacheTTL ?? 0);
		const enabledSites = otherSitePlugin.getEnabledSites();
		$("#preload-enable-missAvBtn").prop("checked", enabledSites.includes("missAvBtn"));
		$("#preload-enable-supJavBtn").prop("checked", enabledSites.includes("supJavBtn"));
		refreshPreloadCacheStats(plugin);
		const titleFilterKeyword = await storageManager.getTitleFilterKeyword();
		if (titleFilterKeyword) titleFilterKeyword.forEach((keyword) => {
			plugin.addLabelTag("#filterKeywordContainer", keyword);
		});
		$("#filterKeywordContainer .add-tag-btn").on("click", () => plugin.addKeyword("#filterKeywordContainer"));
		$("#filterKeywordContainer .keyword-input").on("keypress", (event) => {
			if (event.key === "Enter") plugin.addKeyword("#filterKeywordContainer");
		});
	}
	async function saveForm(plugin) {
		const settings = await storageManager.getSetting();
		settings.videoQuality = $("#videoQuality").val();
		settings.reviewCount = $("#reviewCount").val();
		settings.tagPosition = $("#tagPosition").val();
		settings.movieShowType = $("#movieShowType").val();
		settings.waitCheckCount = $("#waitCheckCount").val();
		settings.highlightedTagNumber = $("#highlightedTagNumber").val();
		settings.highlightedTagColor = $("#highlightedTagColor").val();
		settings.httpTimeout = $("#httpTimeout").val();
		settings.httpRetryCount = $("#httpRetryCount").val();
		settings.enableClog = $("#enableClog").val();
		if (settings.enableClog === "yes") clog.show();
		else clog.hide();
		settings.clogMsgCount = $("#clogMsgCount").val();
		GM_setValue(GM_KEY_WEBDAV_URL, $("#webDavUrl").val() || "");
		GM_setValue(GM_KEY_WEBDAV_USERNAME, $("#webDavUsername").val() || "");
		GM_setValue(GM_KEY_WEBDAV_PASSWORD, $("#webDavPassword").val() || "");
		GM_setValue(GM_KEY_BACKUP_PASSWORD, $("#backupPassword").val() || "");
		delete settings.webDavUrl;
		delete settings.webDavUsername;
		delete settings.webDavPassword;
		settings.autoBackupConfig = {
			enabled: $("#enableAutoBackup").is(":checked"),
			frequency: $("#autoBackupFrequency").val()
		};
		settings.missAvUrl = String($("#missAvUrl").val() ?? "").replace(/\/$/, "");
		settings.supJavUrl = String($("#supJavUrl").val() ?? "").replace(/\/$/, "");
		settings.enablePreload = $("#enablePreload").is(":checked") ? "yes" : "no";
		settings.enablePreloadStatus = $("#enablePreloadStatus").is(":checked") ? "yes" : "no";
		settings.preloadDebounce = $("#preloadDebounce").val();
		settings.preloadConcurrency = $("#preloadConcurrency").val();
		settings.preloadCacheTTL = $("#preloadCacheTTL").val();
		const otherSitePluginForSave = plugin.getBean("OtherSitePlugin");
		const enabledSiteIds = [];
		if ($("#preload-enable-missAvBtn").is(":checked")) enabledSiteIds.push("missAvBtn");
		if ($("#preload-enable-supJavBtn").is(":checked")) enabledSiteIds.push("supJavBtn");
		otherSitePluginForSave.saveEnabledSites(enabledSiteIds);
		settings.enableFavoriteActresses = $("#enableFavoriteActresses").is(":checked") ? "yes" : "no";
		settings.enableSaveActressCarInfo = $("#enableSaveActressCarInfo").is(":checked") ? "yes" : "no";
		await storageManager.saveSetting(settings);
		const titleFilterKeywordList = [];
		$("#filterKeywordContainer .keyword-label").toArray().forEach((label) => {
			const keyword = $(label).text().replace("×", "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
			titleFilterKeywordList.push(keyword);
		});
		await storageManager.saveTitleFilterKeyword(titleFilterKeywordList);
		show.ok("保存成功");
		refresh();
		const newVideoPlugin = plugin.getBean("NewVideoPlugin");
		if (newVideoPlugin) newVideoPlugin.resetBtnTip();
		plugin.getBean("BlacklistPlugin").resetBtnTip();
		plugin.getBean("BlacklistPlugin").reloadTable();
	}
	function BackupFileDialog() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				height: "100%",
				overflow: "hidden"
			},
			children: (0, import_jsx_runtime.jsx)("div", {
				id: "table-container",
				style: { margin: "auto auto !important" }
			})
		});
	}
	function BackupActionCell() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsx)("a", {
				className: "a-danger",
				children: "删除"
			}),
			" ",
			(0, import_jsx_runtime.jsx)("a", {
				className: "a-primary",
				children: "下载"
			}),
			" ",
			(0, import_jsx_runtime.jsx)("a", {
				className: "a-success",
				children: "导入"
			})
		] });
	}
	function getWebDavCredentials() {
		const url = $("#webDavUrl").val() || GM_getValue("jhs_webdav_url", "");
		const username = $("#webDavUsername").val() || GM_getValue("jhs_webdav_username", "");
		const password = $("#webDavPassword").val() || GM_getValue("jhs_webdav_password", "");
		if (!url) {
			show.error("请填写webDav服务地址并保存后, 再试此功能");
			return null;
		}
		if (!username) {
			show.error("请填写webDav用户名并保存后, 再试此功能");
			return null;
		}
		if (!password) {
			show.error("请填写webDav密码并保存后, 再试此功能");
			return null;
		}
		return {
			url,
			username,
			password
		};
	}
	function getWebDavCredentialsFromGm() {
		const url = GM_getValue(GM_KEY_WEBDAV_URL, "");
		if (!url) return null;
		const username = GM_getValue(GM_KEY_WEBDAV_USERNAME, "");
		const password = GM_getValue(GM_KEY_WEBDAV_PASSWORD, "");
		if (!username || !password) return null;
		return {
			url,
			username,
			password
		};
	}
	async function backupDataByWebDav(plugin) {
		const creds = getWebDavCredentials();
		if (!creds) return;
		const settings = await storageManager.getSetting();
		const fileName = utils.getNowStr("_", "_") + ".json";
		const exportText = JSON.stringify(await buildBackupPayload(settings));
		try {
			await withLoading(async () => {
				await new window.WebDavClient(creds.url, creds.username, creds.password).backup(plugin.folderName, fileName, exportText);
				show.ok("备份完成");
			});
		} catch (err) {
			console.error(err);
			show.error(String(err));
		}
	}
	async function backupListBtnByWebDav(plugin) {
		const creds = getWebDavCredentials();
		if (!creds) return;
		try {
			await withLoading(async () => {
				const webdavClient = new window.WebDavClient(creds.url, creds.username, creds.password);
				openFileListDialog(plugin, await webdavClient.getBackupList(plugin.folderName), webdavClient, "WebDav");
			});
		} catch (err) {
			console.error(err);
			show.error(`发生错误: ${err instanceof Error ? err.message : String(err)}`);
		}
	}
	function openFileListDialog(plugin, backupList, webdavClient, titlePrefix) {
		layer.open({
			type: 1,
			title: titlePrefix + "备份文件",
			content: jsxToString((0, import_react.createElement)(BackupFileDialog)),
			area: ["800px", "70%"],
			anim: -1,
			success: () => {
				const table = new Tabulator("#table-container", {
					layout: "fitColumns",
					placeholder: "暂无数据",
					virtualDom: true,
					data: backupList,
					responsiveLayout: "collapse",
					responsiveLayoutCollapse: true,
					columnDefaults: {
						headerHozAlign: "center",
						hozAlign: "center"
					},
					columns: [
						{
							title: "文件名",
							field: "name",
							width: 200,
							headerSort: false,
							responsive: 0
						},
						{
							title: "文件大小",
							field: "size",
							responsive: 1,
							headerSort: false,
							formatter: (cell) => {
								const units = [
									"B",
									"KB",
									"MB",
									"GB",
									"TB",
									"PB"
								];
								let unitIndex = 0;
								let size = cell.getData().size;
								while (size >= 1024 && unitIndex < units.length - 1) {
									size /= 1024;
									unitIndex++;
								}
								return `${size % 1 == 0 ? size.toFixed(0) : size.toFixed(2)} ${units[unitIndex]}`;
							}
						},
						{
							title: "备份日期",
							field: "createTime",
							responsive: 2,
							headerSort: false,
							formatter: (cell) => {
								const data = cell.getData();
								return `${utils.getNowStr("-", ":", new Date(data.createTime).getTime())}`;
							}
						},
						{
							title: "操作",
							minWidth: 250,
							responsive: 0,
							headerSort: false,
							formatter: (cell, _params, onRendered) => {
								const rowData = cell.getData();
								onRendered(() => {
									const $dangerBtn = cell.getElement().querySelector(".a-danger");
									const $primaryBtn = cell.getElement().querySelector(".a-primary");
									const $successBtn = cell.getElement().querySelector(".a-success");
									if ($dangerBtn) $dangerBtn.addEventListener("click", () => {
										layer.confirm(`是否删除 ${rowData.name} ?`, {
											icon: 3,
											title: "提示",
											btn: ["确定", "取消"]
										}, async (layerIndex) => {
											layer.close(layerIndex);
											try {
												await withLoading(async () => {
													await webdavClient.deleteFile(rowData.fileId);
													const newList = await webdavClient.getBackupList(plugin.folderName);
													table.replaceData(newList);
													layer.alert("删除成功");
												});
											} catch (err) {
												console.error(err);
												show.error(`发生错误: ${err instanceof Error ? err.message : String(err)}`);
											}
										});
									});
									if ($primaryBtn) $primaryBtn.addEventListener("click", async () => {
										try {
											await withLoading(async () => {
												const fileContent = await webdavClient.getFileContent(rowData.fileId);
												const backupPassword = GM_getValue(GM_KEY_BACKUP_PASSWORD, "");
												let decrypted;
												if (isBackupV2(fileContent)) {
													if (!backupPassword) {
														show.error("该备份使用 V2 加密,请先设置备份口令");
														return;
													}
													decrypted = await decryptBackupV2(fileContent, backupPassword);
												} else decrypted = window.decryptCredential(fileContent);
												utils.download(decrypted, rowData.name);
											});
										} catch (err) {
											clog.error(err);
											show.error("下载失败: " + (err instanceof Error ? err.message : String(err)));
										}
									});
									if ($successBtn) $successBtn.addEventListener("click", () => {
										layer.confirm(`是否将该云备份数据 ${rowData.name} 导入?`, {
											icon: 3,
											title: "提示",
											btn: ["确定", "取消"]
										}, async (layerIndex) => {
											layer.close(layerIndex);
											try {
												await withLoading(async () => {
													let fileContent = await webdavClient.getFileContent(rowData.fileId);
													show.info("解密文件内容...");
													const backupPassword = GM_getValue(GM_KEY_BACKUP_PASSWORD, "");
													if (isBackupV2(fileContent)) {
														if (!backupPassword) {
															show.error("该备份使用 V2 加密,请先设置备份口令");
															return;
														}
														fileContent = await decryptBackupV2(fileContent, backupPassword);
													} else fileContent = window.decryptCredential(fileContent);
													show.info("解密完成, 开始导入...");
													const parsedData = JSON.parse(fileContent);
													const extras = stripBackupExtras(parsedData);
													await storageManager.importData(parsedData);
													applyBackupExtras(extras);
													show.ok("导入成功!");
													window.location.reload();
												});
											} catch (err) {
												console.error(err);
												show.error(String(err));
											}
										});
									});
								});
								return jsxToString((0, import_react.createElement)(BackupActionCell));
							}
						}
					],
					locale: "zh-cn",
					langs: { "zh-cn": { pagination: {
						first: "首页",
						first_title: "首页",
						last: "尾页",
						last_title: "尾页",
						prev: "上一页",
						prev_title: "上一页",
						next: "下一页",
						next_title: "下一页",
						all: "所有",
						page_size: "每页行数"
					} } }
				});
			}
		});
	}
	function bindClick$1(plugin) {
		$(".side-menu-item").on("click", function() {
			$(".side-menu-item").removeClass("active");
			$(this).addClass("active");
			$(".content-panel").hide();
			const panelName = $(this).data("panel");
			$("#" + panelName).show();
			if (panelName === "cache-panel") {
				$("#saveBtn").hide();
				$("#clean-all").show();
				refreshAllCacheStats(plugin);
			} else if (panelName === "vlt-panel") {
				$("#saveBtn").hide();
				$("#clean-all").hide();
			} else if (panelName === "missav-panel") {
				$("#saveBtn").hide();
				$("#clean-all").hide();
			} else if (panelName === "preload-panel") {
				$("#saveBtn").show();
				$("#clean-all").hide();
				refreshPreloadCacheStats(plugin);
			} else if (panelName === "diagnostics-panel") {
				$("#saveBtn").hide();
				$("#clean-all").hide();
				plugin.refreshDiagnostics();
			} else {
				$("#saveBtn").show();
				$("#clean-all").hide();
			}
		});
		$("#importBtn").on("click", () => importData(plugin));
		$("#exportBtn").on("click", () => exportData(plugin));
		$("#webdavBackupBtn").on("click", () => backupDataByWebDav(plugin));
		$("#webdavBackupListBtn").on("click", () => backupListBtnByWebDav(plugin));
		$("#saveBtn").on("click", () => saveForm(plugin));
		$("#copy-diagnostics-btn").on("click", () => {
			const text = renderDiagnosticsText(plugin.pluginManager);
			navigator.clipboard.writeText(text).then(() => show.ok("诊断报告已复制到剪贴板"), () => show.error("复制失败,请手动选择文本复制"));
		});
		$("#refresh-diagnostics-btn").on("click", () => {
			plugin.refreshDiagnostics();
			show.ok("诊断报告已刷新");
		});
		refreshAllCacheStats(plugin);
		$(".clean-btn").on("click", (event) => handleCleanCache(plugin, event));
		$("#clean-all").on("click", () => handleCleanAllCache(plugin));
		$(".view-btn").on("click", (event) => handleViewCache(event));
		$(".export-btn").on("click", (event) => handleExportCache(plugin, event));
		const $tagNumber = $("#highlightedTagNumber");
		const $tagColor = $("#highlightedTagColor");
		const $tagLabel = $("#highlightedTagLabel");
		function updateBorder() {
			const number = $tagNumber.val();
			const color = $tagColor.val();
			$tagLabel.css("border", `${number}px solid ${color}`);
		}
		$tagNumber.on("input", updateBorder);
		$tagColor.on("input", updateBorder);
		$("#vlt-import-btn").on("click", () => handleVltImportClick());
		$("#vlt-file-input").on("change", (event) => handleVltFileChange(event));
		$("#vlt-export-btn").on("click", () => handleVltExportClick());
		$("#missav-sync-btn").on("click", () => handleMissavSync());
		$("#missav-import-btn").on("click", () => handleMissavImportClick());
		$("#missav-file-input").on("change", (event) => handleMissavFileChange(event));
		$("#missav-export-btn").on("click", () => handleMissavExportClick());
	}
	async function initSimpleSettingForm(plugin) {
		const settings = await storageManager.getSetting();
		const ns = ".jhsQs";
		$("#containerColumns").val(settings.containerColumns || 4);
		$("#showContainerColumns").text(settings.containerColumns || 4);
		$("#containerWidth").val((settings.containerWidth || 70) - 70);
		$("#showContainerWidth").text((settings.containerWidth || 70) + "%");
		$("#dialogOpenDetail").prop("checked", !settings.dialogOpenDetail || settings.dialogOpenDetail === "yes");
		$("#needClosePage").prop("checked", !settings.needClosePage || settings.needClosePage === "yes");
		const loadMode = settings.autoPageLoadMode === "click" ? "click" : "auto";
		$("#autoPageLoadMode").attr("data-value", loadMode);
		$("#autoPageLoadMode .jhs-qs-seg-btn").removeClass("is-active").filter(`[data-value="${loadMode}"]`).addClass("is-active");
		$("#translateTitle").prop("checked", !settings.translateTitle || settings.translateTitle === "yes");
		$("#enableLoadActressInfo").prop("checked", !settings.enableLoadActressInfo || settings.enableLoadActressInfo === "yes");
		$("#enableLoadOtherSite").prop("checked", !settings.enableLoadOtherSite || settings.enableLoadOtherSite === "yes");
		$("#containerColumns").off(`input${ns}`).on(`input${ns}`, async () => {
			const columns = $("#containerColumns").val();
			$("#showContainerColumns").text(String(columns ?? ""));
			if (isJavdbSite) {
				const movieListEl = document.querySelector(".movie-list");
				if (movieListEl) movieListEl.style.gridTemplateColumns = `repeat(${columns}, minmax(0, 1fr))`;
			}
			await storageManager.saveSettingItem("containerColumns", columns);
			plugin.applyImageMode();
		});
		$("#containerWidth").off(`input${ns}`).on(`input${ns}`, async (event) => {
			const rangeValue = parseInt(String($(event.target).val()), 10) || 0;
			const widthPercent = rangeValue + 70 + "%";
			$("#showContainerWidth").text(widthPercent);
			if (isJavdbSite) {
				const containerEl = document.querySelector("section .container");
				if (containerEl) containerEl.style.minWidth = widthPercent;
			}
			storageManager.saveSettingItem("containerWidth", rangeValue + 70);
		});
		$("#dialogOpenDetail").off(`change${ns}`).on(`change${ns}`, () => {
			const value = $("#dialogOpenDetail").is(":checked") ? "yes" : "no";
			storageManager.saveSettingItem("dialogOpenDetail", value);
		});
		$("#showFilterItem").prop("checked", !!settings.showFilterItem && settings.showFilterItem === "yes");
		$("#showFilterActorItem").prop("checked", !!settings.showFilterActorItem && settings.showFilterActorItem === "yes");
		$("#showFilterKeywordItem").prop("checked", !!settings.showFilterKeywordItem && settings.showFilterKeywordItem === "yes");
		$("#showFavoriteItem").prop("checked", !settings.showFavoriteItem || settings.showFavoriteItem === "yes");
		$("#showHasWatchItem").prop("checked", !settings.showHasWatchItem || settings.showHasWatchItem === "yes");
		$("#showFilterItem").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#showFilterItem").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("showFilterItem", value);
			refresh();
		});
		$("#showFilterActorItem").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#showFilterActorItem").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("showFilterActorItem", value);
			refresh();
		});
		$("#showFilterKeywordItem").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#showFilterKeywordItem").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("showFilterKeywordItem", value);
			refresh();
		});
		$("#showFavoriteItem").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#showFavoriteItem").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("showFavoriteItem", value);
			refresh();
		});
		$("#showHasWatchItem").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#showHasWatchItem").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("showHasWatchItem", value);
			refresh();
		});
		const $filterCheckboxes = $("#showFilterItem, #showFilterActorItem, #showFilterKeywordItem, #showFavoriteItem, #showHasWatchItem");
		const updateDisabledState = () => {
			const isChecked = $("#showAllItem").is(":checked");
			$filterCheckboxes.prop("disabled", isChecked);
			if (isChecked) {
				$filterCheckboxes.attr("data-tip", "请先关闭显示所有才可点击");
				$("#jhs-qs-filter-group").addClass("is-disabled");
			} else {
				$filterCheckboxes.removeAttr("data-tip");
				$("#jhs-qs-filter-group").removeClass("is-disabled");
			}
		};
		$("#showAllItem").prop("checked", !!settings.showAllItem && settings.showAllItem === "yes");
		$("#showAllItem").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#showAllItem").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("showAllItem", value);
			updateDisabledState();
			refresh();
		});
		updateDisabledState();
		$("#needClosePage").off(`change${ns}`).on(`change${ns}`, async () => {
			await storageManager.saveSettingItem("needClosePage", $("#needClosePage").is(":checked") ? "yes" : "no");
			refresh();
		});
		$("#autoPageLoadMode").off(`click${ns}`).on(`click${ns}`, ".jhs-qs-seg-btn", async (event) => {
			const value = $(event.currentTarget).attr("data-value") === "click" ? "click" : "auto";
			const $seg = $("#autoPageLoadMode");
			if ($seg.attr("data-value") === value) return;
			$seg.attr("data-value", value);
			$seg.find(".jhs-qs-seg-btn").removeClass("is-active");
			$(event.currentTarget).addClass("is-active");
			await storageManager.saveSettingItem("autoPageLoadMode", value);
			const autoPagePlugin = plugin.getBean("AutoPagePlugin");
			autoPagePlugin?.setLoadMode?.(value);
			autoPagePlugin?.showLoadAllBtn?.();
		});
		$("#translateTitle").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#translateTitle").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("translateTitle", value);
			if (value === "yes") await plugin.getBean("ListPagePlugin").doFilter();
			else {
				await plugin.getBean("ListPagePlugin").revertTranslation();
				$(".translated-title").remove();
			}
		});
		$("#enableLoadActressInfo").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#enableLoadActressInfo").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("enableLoadActressInfo", value);
			if (value === "yes") plugin.getBean("ActressInfoPlugin").loadActressInfo();
			else $(".actress-info").remove();
		});
		$("#enableLoadOtherSite").off(`change${ns}`).on(`change${ns}`, async () => {
			const value = $("#enableLoadOtherSite").is(":checked") ? "yes" : "no";
			await storageManager.saveSettingItem("enableLoadOtherSite", value);
			if (value === "yes") plugin.getBean("OtherSitePlugin").loadOtherSite().then();
			else $("#otherSiteBox").remove();
		});
		$("#moreBtn").off(`click${ns}`).on(`click${ns}`, () => {
			plugin.cancelSimpleSettingHide();
			$(".simple-setting, .mini-simple-setting").html("").hide();
			plugin.openSettingDialog("base-panel");
		});
		$("#helpBtn").off(`click${ns}`).on(`click${ns}`, () => {
			layer.open({
				type: 1,
				title: "",
				shadeClose: true,
				scrollbar: false,
				content: jsxToString((0, import_react.createElement)(StyleBlock, { css: help_dialog_default })) + jsxToString((0, import_react.createElement)(HelpDialog, null)),
				area: utils.getResponsiveArea(["50%", "90%"])
			});
		});
	}
	function KeywordLabel({ keyword, bgColor, textColor, variant, href }) {
		const style = {
			backgroundColor: bgColor,
			color: textColor
		};
		if (variant === "link") return (0, import_jsx_runtime.jsxs)("a", {
			className: "keyword-label",
			"data-keyword": keyword,
			style,
			href,
			target: "_blank",
			children: [keyword, (0, import_jsx_runtime.jsx)("span", {
				className: "keyword-remove",
				children: "×"
			})]
		});
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "keyword-label",
			"data-keyword": keyword,
			style,
			children: [keyword, (0, import_jsx_runtime.jsx)("span", {
				className: "keyword-remove",
				children: "×"
			})]
		});
	}
	function addLabelTag(containerSelector, keyword) {
		const $tagBox = $(`${containerSelector} .tag-box`);
		let $label;
		const bgColor = "#cbd5e1";
		let textColor = "#333";
		if (/^[a-z]{2,}-/i.test(keyword) && isJavdbSite) {
			textColor = "#3477ad";
			$label = $(jsxToString((0, import_react.createElement)(KeywordLabel, {
				keyword,
				bgColor,
				textColor,
				variant: "link",
				href: `/video_codes/${keyword.replace("-", "")}`
			})));
		} else $label = $(jsxToString((0, import_react.createElement)(KeywordLabel, {
			keyword,
			bgColor,
			textColor,
			variant: "div"
		})));
		$label.find(".keyword-remove").click((event) => {
			event.stopPropagation();
			event.preventDefault();
			const $removeBtn = $(event.currentTarget);
			const removeKeyword = ($removeBtn.closest(".keyword-label").attr("data-keyword") ?? "").split(" ")[0];
			utils.q(event, `是否移除屏蔽词  ${removeKeyword}?`, async () => {
				$removeBtn.parent().remove();
			});
		});
		$tagBox.append($label);
	}
	function addKeyword(containerSelector) {
		const $input = $(`${containerSelector} .keyword-input`);
		const keyword = String($input.val() ?? "").trim();
		if (keyword) {
			addLabelTag(containerSelector, keyword);
			$input.val("");
		}
	}
	function SettingButton({ id, color, children }) {
		return (0, import_jsx_runtime.jsx)("a", {
			id,
			className: `jhs-setting-btn jhs-setting-btn--${color}`,
			children
		});
	}
	function SettingCheckbox({ id, label }) {
		return (0, import_jsx_runtime.jsxs)("label", {
			className: "jhs-checkbox-label",
			children: [(0, import_jsx_runtime.jsx)("input", {
				id,
				type: "checkbox"
			}), (0, import_jsx_runtime.jsx)("span", { children: label })]
		});
	}
	function SettingInput({ id, type = "text", placeholder, readOnly, min, max, step, style }) {
		return (0, import_jsx_runtime.jsx)("input", {
			id,
			type,
			placeholder,
			readOnly,
			min,
			max,
			step,
			style
		});
	}
	function SettingRow({ label, tooltip, children, className }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: `setting-item${className ? " " + className : ""}`,
			children: [(0, import_jsx_runtime.jsxs)("span", {
				className: "setting-label",
				children: [label, tooltip ? (0, import_jsx_runtime.jsx)("span", {
					className: "jhs-tooltip-icon",
					"data-tip": tooltip,
					children: "?"
				}) : null]
			}), (0, import_jsx_runtime.jsx)("div", {
				className: "form-content",
				children
			})]
		});
	}
	function SettingSection({ title, icon, children }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "jhs-setting-section",
			children: [title ? (0, import_jsx_runtime.jsxs)("div", {
				className: "jhs-setting-section-title",
				children: [icon ? (0, import_jsx_runtime.jsx)("span", { children: icon }) : null, title]
			}) : null, children]
		});
	}
	function SettingSelect({ id, children, dangerouslySetInnerHTML }) {
		return (0, import_jsx_runtime.jsx)("select", {
			id,
			dangerouslySetInnerHTML,
			children
		});
	}
	function BackupPanel({ panelName }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			id: "backup-panel",
			className: "content-panel",
			style: { display: panelName === "backup-panel" ? "block" : "none" },
			children: [
				(0, import_jsx_runtime.jsx)(SettingSection, { children: (0, import_jsx_runtime.jsxs)("div", {
					style: {
						display: "flex",
						gap: "10px"
					},
					children: [(0, import_jsx_runtime.jsx)(SettingButton, {
						id: "importBtn",
						color: "pink",
						children: "📥 导入数据"
					}), (0, import_jsx_runtime.jsx)(SettingButton, {
						id: "exportBtn",
						color: "mint",
						children: "📤 导出数据"
					})]
				}) }),
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "WebDav 备份",
					icon: "☁️",
					children: [
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "WebDav备份",
							children: (0, import_jsx_runtime.jsxs)("div", {
								style: {
									display: "flex",
									gap: "8px"
								},
								children: [(0, import_jsx_runtime.jsx)(SettingButton, {
									id: "webdavBackupListBtn",
									color: "primary",
									children: "查看备份"
								}), (0, import_jsx_runtime.jsx)(SettingButton, {
									id: "webdavBackupBtn",
									color: "success",
									children: "备份数据"
								})]
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "服务地址:",
							children: (0, import_jsx_runtime.jsx)(SettingInput, { id: "webDavUrl" })
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "用户名:",
							children: (0, import_jsx_runtime.jsx)(SettingInput, { id: "webDavUsername" })
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "密码:",
							children: (0, import_jsx_runtime.jsx)(SettingInput, {
								id: "webDavPassword",
								type: "password"
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "备份口令:",
							children: (0, import_jsx_runtime.jsx)(SettingInput, {
								id: "backupPassword",
								type: "password",
								placeholder: "加密备份的口令(V2 格式)"
							})
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "自动备份",
					icon: "⏰",
					children: [
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "启用自动备份",
							children: (0, import_jsx_runtime.jsx)(SettingCheckbox, {
								id: "enableAutoBackup",
								label: "开启后按频率自动备份到 WebDav"
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "备份频率:",
							children: (0, import_jsx_runtime.jsxs)(SettingSelect, {
								id: "autoBackupFrequency",
								children: [
									(0, import_jsx_runtime.jsx)("option", {
										value: "daily",
										children: "每天第一次打开(推荐)"
									}),
									(0, import_jsx_runtime.jsx)("option", {
										value: "everyOpen",
										children: "每次打开"
									}),
									(0, import_jsx_runtime.jsx)("option", {
										value: "disabled",
										children: "不自动备份"
									})
								]
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "本机凭证:",
							children: (0, import_jsx_runtime.jsx)(SettingInput, {
								id: "credentialIdDisplay",
								readOnly: true,
								style: {
									fontSize: "11px",
									fontFamily: "monospace"
								}
							})
						})
					]
				})
			]
		});
	}
	function SettingColorRow({ numberId, colorId, labelId, label, className }) {
		return (0, import_jsx_runtime.jsx)(SettingRow, {
			label,
			className,
			children: (0, import_jsx_runtime.jsxs)("div", {
				style: {
					display: "flex",
					gap: "8px",
					alignItems: "center"
				},
				children: [
					(0, import_jsx_runtime.jsx)("input", {
						id: numberId,
						type: "number",
						style: {
							width: "80px",
							flexShrink: 0
						}
					}),
					(0, import_jsx_runtime.jsx)("input", {
						id: colorId,
						type: "color",
						style: { flexShrink: 0 }
					}),
					(0, import_jsx_runtime.jsx)("span", {
						id: labelId,
						style: {
							display: "inline-block",
							padding: "4px 12px",
							borderRadius: "4px",
							fontSize: "13px",
							border: "1px solid #ce2222"
						},
						children: "示例标签"
					})
				]
			})
		});
	}
	function SettingToggle({ id, label, tooltip, className }) {
		return (0, import_jsx_runtime.jsx)(SettingRow, {
			label,
			tooltip,
			className,
			children: (0, import_jsx_runtime.jsx)("input", {
				id,
				type: "checkbox",
				className: "jhs-toggle"
			})
		});
	}
	function BasePanel({ panelName, qualityOptionsHtml, isJavdbSite }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			id: "base-panel",
			className: "content-panel",
			style: { display: panelName === "base-panel" ? "block" : "none" },
			children: [
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "展示配置",
					icon: "🎛️",
					children: [
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "打开待鉴定|已收藏 窗口数:",
							children: (0, import_jsx_runtime.jsx)(SettingInput, {
								id: "waitCheckCount",
								type: "number",
								min: "1",
								max: "20"
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "已鉴定标签展示位置:",
							children: (0, import_jsx_runtime.jsxs)(SettingSelect, {
								id: "tagPosition",
								children: [(0, import_jsx_runtime.jsx)("option", {
									value: "rightTop",
									children: "右上"
								}), (0, import_jsx_runtime.jsx)("option", {
									value: "leftTop",
									children: "左上"
								})]
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "已鉴定内容展示方式",
							tooltip: "hide=直接隐藏;visibility=透明占位保留布局",
							children: (0, import_jsx_runtime.jsxs)(SettingSelect, {
								id: "movieShowType",
								children: [(0, import_jsx_runtime.jsx)("option", {
									value: "hide",
									children: "隐藏 (hide)"
								}), (0, import_jsx_runtime.jsx)("option", {
									value: "visibility",
									children: "透明占位 (visibility)"
								})]
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingToggle, {
							id: "enableSaveActressCarInfo",
							label: "鉴定补录演员信息",
							tooltip: "在列表页进行鉴定是获取不到演员名称的, 开启后, 额外解析详情页补录演员名称, 因发请求解析费时, 会被以往慢1秒左右"
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "播放与评论",
					icon: "🎬",
					children: [
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "预览视频默认画质:",
							children: (0, import_jsx_runtime.jsx)(SettingSelect, {
								id: "videoQuality",
								dangerouslySetInnerHTML: { __html: qualityOptionsHtml }
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "评论区条数:",
							children: (0, import_jsx_runtime.jsxs)(SettingSelect, {
								id: "reviewCount",
								children: [
									(0, import_jsx_runtime.jsx)("option", {
										value: "10",
										children: "10条"
									}),
									(0, import_jsx_runtime.jsx)("option", {
										value: "20",
										children: "20条"
									}),
									(0, import_jsx_runtime.jsx)("option", {
										value: "30",
										children: "30条"
									}),
									(0, import_jsx_runtime.jsx)("option", {
										value: "40",
										children: "40条"
									}),
									(0, import_jsx_runtime.jsx)("option", {
										value: "50",
										children: "50条"
									})
								]
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingToggle, {
							id: "enableFavoriteActresses",
							label: "高亮已收藏演员",
							tooltip: "详情页, 对已收藏的演员进行边框高亮提醒",
							className: isJavdbSite ? "" : "do-hide"
						}),
						(0, import_jsx_runtime.jsx)(SettingColorRow, {
							numberId: "highlightedTagNumber",
							colorId: "highlightedTagColor",
							labelId: "highlightedTagLabel",
							label: "分类标签|高亮演员-边框样式:",
							className: isJavdbSite ? "" : "do-hide"
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "网络请求",
					icon: "🌐",
					children: [(0, import_jsx_runtime.jsx)(SettingRow, {
						label: "请求超时时间(毫秒):",
						children: (0, import_jsx_runtime.jsx)(SettingInput, {
							id: "httpTimeout",
							type: "number",
							min: "1000",
							max: "10000"
						})
					}), (0, import_jsx_runtime.jsx)(SettingRow, {
						label: "请求失败重试次数:",
						children: (0, import_jsx_runtime.jsx)(SettingInput, {
							id: "httpRetryCount",
							type: "number",
							min: "0",
							max: "10"
						})
					})]
				}),
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "日志",
					icon: "📝",
					children: [(0, import_jsx_runtime.jsx)(SettingRow, {
						label: "启用控制台日志:",
						children: (0, import_jsx_runtime.jsxs)(SettingSelect, {
							id: "enableClog",
							children: [(0, import_jsx_runtime.jsx)("option", {
								value: "no",
								children: "禁用"
							}), (0, import_jsx_runtime.jsx)("option", {
								value: "yes",
								children: "开启"
							})]
						})
					}), (0, import_jsx_runtime.jsx)(SettingRow, {
						label: "日志最大行数:",
						children: (0, import_jsx_runtime.jsx)(SettingInput, {
							id: "clogMsgCount",
							type: "number",
							min: "100",
							max: "3000"
						})
					})]
				})
			]
		});
	}
	function FilterPanel({ panelName }) {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "filter-panel",
			className: "content-panel",
			style: { display: panelName === "filter-panel" ? "block" : "none" },
			children: (0, import_jsx_runtime.jsx)(SettingSection, {
				title: "屏蔽关键词",
				icon: "🚫",
				children: (0, import_jsx_runtime.jsxs)("div", {
					id: "filterKeywordContainer",
					className: "filter-keyword-container",
					children: [(0, import_jsx_runtime.jsx)("div", { className: "tag-box" }), (0, import_jsx_runtime.jsxs)("div", {
						style: {
							display: "flex",
							gap: "8px",
							marginTop: "8px"
						},
						children: [(0, import_jsx_runtime.jsx)("input", {
							type: "text",
							className: "keyword-input",
							placeholder: "输入关键词后按回车添加",
							style: { flex: 1 }
						}), (0, import_jsx_runtime.jsx)("a", {
							className: "add-tag-btn jhs-setting-btn jhs-setting-btn--primary",
							style: { flexShrink: 0 },
							children: "添加"
						})]
					})]
				})
			})
		});
	}
	function DomainPanel({ panelName }) {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "domain-panel",
			className: "content-panel",
			style: { display: panelName === "domain-panel" ? "block" : "none" },
			children: (0, import_jsx_runtime.jsxs)(SettingSection, {
				title: "第三方视频资源域名",
				icon: "🌐",
				children: [(0, import_jsx_runtime.jsx)(SettingRow, {
					label: "域名 - MissAv:",
					children: (0, import_jsx_runtime.jsx)(SettingInput, { id: "missAvUrl" })
				}), (0, import_jsx_runtime.jsx)(SettingRow, {
					label: "域名 - SupJav:",
					children: (0, import_jsx_runtime.jsx)(SettingInput, { id: "supJavUrl" })
				})]
			})
		});
	}
	function CachePanel({ panelName, cacheItemsHtml }) {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "cache-panel",
			className: "content-panel",
			style: { display: panelName === "cache-panel" ? "block" : "none" },
			children: (0, import_jsx_runtime.jsxs)(SettingSection, {
				title: "缓存管理",
				icon: "🧹",
				children: [
					(0, import_jsx_runtime.jsx)("div", {
						style: {
							display: "flex",
							justifyContent: "space-between",
							alignItems: "center",
							marginBottom: "4px"
						},
						children: (0, import_jsx_runtime.jsx)("span", {
							id: "cache-total-size",
							style: {
								fontSize: "13px",
								color: "#999"
							}
						})
					}),
					(0, import_jsx_runtime.jsx)("p", {
						style: {
							color: "#999",
							fontSize: "12px",
							margin: "0 0 16px 0"
						},
						children: "以下操作不会对核心数据造成影响,可安全清理"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						style: {
							display: "grid",
							gridTemplateColumns: "repeat(2, 1fr)",
							gap: "15px"
						},
						dangerouslySetInnerHTML: { __html: cacheItemsHtml }
					}),
					(0, import_jsx_runtime.jsx)("div", {
						id: "cache-data-display",
						style: {
							marginTop: "20px",
							display: "none"
						},
						children: (0, import_jsx_runtime.jsx)("pre", { style: {
							background: "#f5f5f5",
							padding: "10px",
							borderRadius: "5px",
							maxHeight: "400px",
							overflow: "auto"
						} })
					})
				]
			})
		});
	}
	function SyncPanel({ panelId, panelName, title, icon, description, buttons, statusId, fileInputId }) {
		return (0, import_jsx_runtime.jsx)("div", {
			id: panelId,
			className: "content-panel",
			style: { display: panelName === panelId ? "block" : "none" },
			children: (0, import_jsx_runtime.jsxs)(SettingSection, {
				title,
				icon,
				children: [
					(0, import_jsx_runtime.jsx)("p", {
						style: {
							margin: "0 0 16px 0",
							color: "#6c757d",
							fontSize: "13px",
							lineHeight: "1.6"
						},
						children: description
					}),
					(0, import_jsx_runtime.jsx)("div", {
						style: {
							display: "flex",
							gap: "12px",
							marginBottom: "20px"
						},
						children: buttons.map((btn) => (0, import_jsx_runtime.jsx)(SettingButton, {
							id: btn.id,
							color: btn.color,
							children: btn.text
						}, btn.id))
					}),
					(0, import_jsx_runtime.jsx)("div", {
						id: statusId,
						style: {
							fontSize: "13px",
							color: "#6c757d",
							marginTop: "8px"
						}
					}),
					(0, import_jsx_runtime.jsx)("input", {
						type: "file",
						id: fileInputId,
						accept: ".json,application/json",
						style: { display: "none" }
					})
				]
			})
		});
	}
	function PreloadPanel({ panelName }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			id: "preload-panel",
			className: "content-panel",
			style: { display: panelName === "preload-panel" ? "block" : "none" },
			children: [
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "预加载行为",
					icon: "⚡",
					children: [
						(0, import_jsx_runtime.jsx)(SettingToggle, {
							id: "enablePreload",
							label: "列表页预加载",
							tooltip: "在视频流(列表页/清单详情页/搜索页)后台预加载 missav 等站点搜索结果并缓存,打开详情页时按钮零延迟变绿。关闭后不预加载、不显示状态徽标与筛选栏(详情页按钮仍受「外部网站功能」总开关控制)"
						}),
						(0, import_jsx_runtime.jsx)(SettingToggle, {
							id: "enablePreloadStatus",
							label: "显示状态徽标与筛选栏",
							tooltip: "在每个卡片标题下方显示预加载状态(排队中/请求中/成功匹配/匹配失败),并在筛选栏实时计数、可点击过滤。关闭后仍后台预加载缓存,但不显示 UI"
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "预加载防抖延迟 (毫秒)",
							tooltip: "列表页瀑布流追加新卡片后,等待多久再开始批量入队预加载。过小可能与页面渲染抢资源;过大则新卡片状态延迟出现。缺省 300",
							children: (0, import_jsx_runtime.jsx)(SettingInput, {
								id: "preloadDebounce",
								type: "number",
								min: "0",
								max: "5000",
								step: "50"
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "预加载并发数 (1-10)",
							tooltip: "同时向 missav 等站点发起预加载请求的数量。1=串行最稳(默认,降低 Cloudflare 拦截风险);2~5 可明显加快列表预加载;过高易被拦截并触发本轮跳过该站点。建议从 2 试起",
							children: (0, import_jsx_runtime.jsx)(SettingInput, {
								id: "preloadConcurrency",
								type: "number",
								min: "1",
								max: "10",
								step: "1"
							})
						}),
						(0, import_jsx_runtime.jsx)(SettingRow, {
							label: "预加载缓存有效期 (天)",
							tooltip: "命中缓存超过此天数后视为过期,下次打开列表页会重新预加载。0=永不过期(缺省)。建议 7-30 天平衡新鲜度与请求量",
							children: (0, import_jsx_runtime.jsx)(SettingInput, {
								id: "preloadCacheTTL",
								type: "number",
								min: "0",
								max: "365",
								step: "1"
							})
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "预加载站点",
					icon: "🌍",
					children: [(0, import_jsx_runtime.jsx)(SettingRow, {
						label: "预加载站点:",
						children: (0, import_jsx_runtime.jsxs)("div", {
							style: {
								display: "flex",
								gap: "16px",
								flexWrap: "wrap",
								alignItems: "center"
							},
							children: [(0, import_jsx_runtime.jsx)(SettingCheckbox, {
								id: "preload-enable-missAvBtn",
								label: "MissAv"
							}), (0, import_jsx_runtime.jsx)(SettingCheckbox, {
								id: "preload-enable-supJavBtn",
								label: "SupJav"
							})]
						})
					}), (0, import_jsx_runtime.jsx)("p", {
						style: {
							fontSize: "12px",
							color: "#6c757d",
							margin: "8px 0 0"
						},
						children: "SupJav 全站 Cloudflare 拦截严重,列表页预加载已跳过(仅详情页显示黄色搜索页链接),MissAv 为主要预加载源。"
					})]
				}),
				(0, import_jsx_runtime.jsxs)(SettingSection, {
					title: "缓存状态",
					icon: "📦",
					children: [(0, import_jsx_runtime.jsx)(SettingRow, {
						label: "预加载缓存状态:",
						children: (0, import_jsx_runtime.jsx)("div", {
							id: "preload-cache-stats",
							style: {
								fontSize: "13px",
								color: "#495057",
								lineHeight: "1.8"
							},
							children: "加载中..."
						})
					}), (0, import_jsx_runtime.jsx)("p", {
						style: {
							fontSize: "12px",
							color: "#6c757d",
							margin: "8px 0 0"
						},
						children: "此缓存即「缓存管理」面板的「第三方站点缓存」(jhs_other_site),清理请前往该面板。总开关「外部网站功能」位于快捷设置面板。"
					})]
				})
			]
		});
	}
	function DiagnosticsPanel({ panelName }) {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "diagnostics-panel",
			className: "content-panel",
			style: {
				display: panelName === "diagnostics-panel" ? "block" : "none",
				overflowY: "auto"
			},
			children: (0, import_jsx_runtime.jsxs)(SettingSection, {
				title: "插件执行状态",
				icon: "📊",
				children: [(0, import_jsx_runtime.jsx)("div", { id: "diagnostics-content" }), (0, import_jsx_runtime.jsxs)("div", {
					style: { marginTop: "12px" },
					children: [(0, import_jsx_runtime.jsx)("button", {
						id: "copy-diagnostics-btn",
						className: "jhs-setting-btn jhs-setting-btn--primary",
						type: "button",
						children: "📋 复制诊断报告"
					}), (0, import_jsx_runtime.jsx)("button", {
						id: "refresh-diagnostics-btn",
						className: "jhs-setting-btn",
						type: "button",
						style: { marginLeft: "8px" },
						children: "🔄 刷新诊断"
					})]
				})]
			})
		});
	}
	function SettingDialog({ panelName, cacheItemsHtml, qualityOptionsHtml, isJavdbSite }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				display: "flex",
				height: "100%"
			},
			children: [(0, import_jsx_runtime.jsxs)("div", {
				style: {
					width: "170px",
					flexShrink: 0,
					padding: "12px 0",
					background: "#fbfcfd",
					borderRight: "1px solid #e2e8f0",
					overflowY: "auto"
				},
				children: [
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "backup-panel" ? "active" : ""}`,
						"data-panel": "backup-panel",
						children: "💾 数据备份"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "base-panel" ? "active" : ""}`,
						"data-panel": "base-panel",
						children: "⚙️ 基础配置"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "filter-panel" ? "active" : ""}`,
						"data-panel": "filter-panel",
						children: "🚫 屏蔽配置"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "domain-panel" ? "active" : ""}`,
						"data-panel": "domain-panel",
						title: "第三方视频资源域名配置",
						children: "🌐 外部网站"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "cache-panel" ? "active" : ""}`,
						"data-panel": "cache-panel",
						children: "🧹 缓存管理"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "vlt-panel" ? "active" : ""}`,
						"data-panel": "vlt-panel",
						children: "📋 收藏清单关系"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "missav-panel" ? "active" : ""}`,
						"data-panel": "missav-panel",
						children: "🎬 MissAV 同步"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "preload-panel" ? "active" : ""}`,
						"data-panel": "preload-panel",
						title: "视频流外部网站预加载配置",
						children: "⚡ 预加载配置"
					}),
					(0, import_jsx_runtime.jsx)("div", {
						className: `side-menu-item ${panelName === "diagnostics-panel" ? "active" : ""}`,
						"data-panel": "diagnostics-panel",
						title: "插件执行状态诊断",
						children: "📊 插件诊断"
					})
				]
			}), (0, import_jsx_runtime.jsxs)("div", {
				style: {
					flex: 1,
					display: "flex",
					flexDirection: "column",
					height: "100%"
				},
				children: [
					(0, import_jsx_runtime.jsxs)("div", {
						style: {
							flex: 1,
							margin: "0 10px",
							paddingBottom: "20px",
							overflow: "hidden"
						},
						children: [
							(0, import_jsx_runtime.jsx)(BackupPanel, { panelName }),
							(0, import_jsx_runtime.jsx)(BasePanel, {
								panelName,
								qualityOptionsHtml,
								isJavdbSite
							}),
							(0, import_jsx_runtime.jsx)(FilterPanel, { panelName }),
							(0, import_jsx_runtime.jsx)(DomainPanel, { panelName }),
							(0, import_jsx_runtime.jsx)(CachePanel, {
								panelName,
								cacheItemsHtml
							}),
							(0, import_jsx_runtime.jsx)(SyncPanel, {
								panelId: "vlt-panel",
								panelName,
								title: "收藏清单关系",
								icon: "📋",
								description: (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
									"管理影片与清单的关联数据(本地 IndexedDB,随 WebDav 备份)。",
									(0, import_jsx_runtime.jsx)("br", {}),
									(0, import_jsx_runtime.jsx)("strong", { children: "导入" }),
									":从 JSON 文件导入数据(如 PostgreSQL 迁移数据)。",
									(0, import_jsx_runtime.jsx)("br", {}),
									(0, import_jsx_runtime.jsx)("strong", { children: "导出" }),
									":将当前数据导出为 JSON 文件(备份/迁移)。"
								] }),
								buttons: [{
									id: "vlt-import-btn",
									text: "导入数据",
									color: "primary"
								}, {
									id: "vlt-export-btn",
									text: "导出数据",
									color: "success"
								}],
								statusId: "vlt-status",
								fileInputId: "vlt-file-input"
							}),
							(0, import_jsx_runtime.jsx)(SyncPanel, {
								panelId: "missav-panel",
								panelName,
								title: "MissAV 状态标签同步",
								icon: "🎬",
								description: (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
									"在 MissAV 站点显示 JHS 鉴定状态标签(已收藏/已观看/已屏蔽/已下载)。",
									(0, import_jsx_runtime.jsx)("br", {}),
									"数据通过油猴 GM 存储跨域同步,无需后端服务器。",
									(0, import_jsx_runtime.jsx)("br", {}),
									(0, import_jsx_runtime.jsx)("strong", { children: "立即同步" }),
									":读取当前 car_list 并推送到 GM 存储。",
									(0, import_jsx_runtime.jsx)("br", {}),
									(0, import_jsx_runtime.jsx)("strong", { children: "导入" }),
									":从后端服务器导出的 JSON 导入历史数据。",
									(0, import_jsx_runtime.jsx)("br", {}),
									(0, import_jsx_runtime.jsx)("strong", { children: "导出" }),
									":将 MissAV 本地 IndexedDB 数据导出为 JSON(可走 WebDav 备份)。"
								] }),
								buttons: [
									{
										id: "missav-sync-btn",
										text: "立即同步",
										color: "primary"
									},
									{
										id: "missav-import-btn",
										text: "导入数据",
										color: "primary"
									},
									{
										id: "missav-export-btn",
										text: "导出数据",
										color: "success"
									}
								],
								statusId: "missav-status",
								fileInputId: "missav-file-input"
							}),
							(0, import_jsx_runtime.jsx)(PreloadPanel, { panelName })
						]
					}),
					(0, import_jsx_runtime.jsx)(DiagnosticsPanel, { panelName }),
					(0, import_jsx_runtime.jsxs)("div", {
						style: {
							flexShrink: 0,
							padding: "14px 20px",
							textAlign: "right",
							borderTop: "1px solid #e2e8f0",
							background: "#fbfcfd",
							display: "flex",
							justifyContent: "flex-end",
							gap: "10px",
							alignItems: "center"
						},
						children: [(0, import_jsx_runtime.jsx)("button", {
							id: "saveBtn",
							className: "jhs-setting-btn jhs-setting-btn--success",
							children: "💾 保存设置"
						}), (0, import_jsx_runtime.jsx)("button", {
							id: "clean-all",
							className: "jhs-setting-btn jhs-setting-btn--danger",
							style: { display: "none" },
							children: "♾️ 清理全部缓存"
						})]
					})
				]
			})]
		});
	}
	function BackToTopButton() {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "jhs-back-to-top",
			title: "回到顶部",
			children: (0, import_jsx_runtime.jsx)("svg", {
				viewBox: "0 0 24 24",
				children: (0, import_jsx_runtime.jsx)("path", { d: "M12 4l-8 8h6v8h4v-8h6z" })
			})
		});
	}
	function CacheItemHtml({ text, cacheKey, title, size, count }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "cache-item",
			"data-cache-key": cacheKey,
			style: {
				border: "1px solid #eee",
				borderRadius: "8px",
				padding: "12px"
			},
			children: [
				(0, import_jsx_runtime.jsx)("div", {
					style: {
						fontWeight: "bold",
						marginBottom: "4px"
					},
					children: text
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: {
						fontSize: "12px",
						color: "#999",
						marginBottom: "8px"
					},
					children: [
						(0, import_jsx_runtime.jsx)("span", {
							className: "cache-size",
							children: size
						}),
						" · ",
						(0, import_jsx_runtime.jsx)("span", {
							className: "cache-count",
							children: count
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: {
						display: "flex",
						gap: "6px"
					},
					children: [
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-setting-menu-btn clean-btn",
							"data-key": cacheKey,
							style: {
								backgroundColor: "#448cc2",
								flex: 1,
								textAlign: "center",
								fontSize: "13px"
							},
							title,
							children: (0, import_jsx_runtime.jsx)("span", { children: "清理" })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-setting-menu-btn view-btn",
							"data-key": cacheKey,
							style: {
								backgroundColor: "#b2bec0",
								flex: 1,
								textAlign: "center",
								fontSize: "13px"
							},
							children: (0, import_jsx_runtime.jsx)("span", { children: "查看" })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "jhs-setting-menu-btn export-btn",
							"data-key": cacheKey,
							style: {
								backgroundColor: "#85d0a3",
								flex: 1,
								textAlign: "center",
								fontSize: "13px"
							},
							title: "导出为 JSON 文件",
							children: (0, import_jsx_runtime.jsx)("span", { children: "导出" })
						})
					]
				})
			]
		});
	}
	function SettingMountBox({ variant }) {
		switch (variant) {
			case "navbar": return (0, import_jsx_runtime.jsxs)("div", {
				className: "navbar-item has-dropdown is-hoverable setting-box",
				style: { position: "relative" },
				children: [(0, import_jsx_runtime.jsx)("a", {
					id: "setting-btn",
					className: "navbar-link nav-btn",
					style: {
						color: "#ff8400 !important",
						paddingRight: "15px !important"
					},
					children: "设置"
				}), (0, import_jsx_runtime.jsx)("div", { className: "simple-setting" })]
			});
			case "mini": return (0, import_jsx_runtime.jsxs)("div", {
				className: "navbar-item mini-setting-box",
				style: {
					position: "relative",
					marginLeft: "auto"
				},
				children: [(0, import_jsx_runtime.jsx)("a", {
					id: "mini-setting-btn",
					className: "navbar-link nav-btn",
					style: {
						color: "#ff8400 !important",
						paddingLeft: "0 !important",
						paddingRight: "0 !important"
					},
					children: "设置"
				}), (0, import_jsx_runtime.jsx)("div", { className: "mini-simple-setting" })]
			});
		}
	}
	function Row({ label, tip, children, stacked }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: stacked ? "jhs-qs-row jhs-qs-row-stacked" : "jhs-qs-row",
			children: [(0, import_jsx_runtime.jsxs)("div", {
				className: "jhs-qs-label",
				children: [tip ? (0, import_jsx_runtime.jsx)("span", {
					className: "jhs-qs-tip",
					"data-tip": tip,
					children: "?"
				}) : null, (0, import_jsx_runtime.jsx)("span", { children: label })]
			}), (0, import_jsx_runtime.jsx)("div", {
				className: "jhs-qs-control",
				children
			})]
		});
	}
	function SimpleSettingPanel({ isJavdbSite }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "jhs-qs-panel",
			children: [
				(0, import_jsx_runtime.jsxs)("div", {
					className: "jhs-qs-header",
					children: [(0, import_jsx_runtime.jsx)("span", {
						className: "jhs-qs-title",
						children: "快捷设置"
					}), (0, import_jsx_runtime.jsx)("span", {
						className: "jhs-qs-sub",
						children: "改动即时生效"
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					className: "jhs-qs-body jhs-scrollbar",
					children: [
						(0, import_jsx_runtime.jsxs)("div", {
							className: "jhs-qs-section",
							children: [
								(0, import_jsx_runtime.jsx)("div", {
									className: "jhs-qs-section-title",
									children: "列表显示"
								}),
								(0, import_jsx_runtime.jsx)(Row, {
									label: "显示所有已鉴定",
									tip: "开启后忽略下方分项,强制显示全部已鉴定内容",
									children: (0, import_jsx_runtime.jsx)("input", {
										type: "checkbox",
										id: "showAllItem",
										className: "mini-switch"
									})
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "jhs-qs-subcard",
									id: "jhs-qs-filter-group",
									children: [
										(0, import_jsx_runtime.jsx)(Row, {
											label: "屏蔽单番号",
											children: (0, import_jsx_runtime.jsx)("input", {
												type: "checkbox",
												id: "showFilterItem",
												className: "mini-switch"
											})
										}),
										(0, import_jsx_runtime.jsx)(Row, {
											label: "屏蔽演员",
											children: (0, import_jsx_runtime.jsx)("input", {
												type: "checkbox",
												id: "showFilterActorItem",
												className: "mini-switch"
											})
										}),
										(0, import_jsx_runtime.jsx)(Row, {
											label: "屏蔽关键词",
											children: (0, import_jsx_runtime.jsx)("input", {
												type: "checkbox",
												id: "showFilterKeywordItem",
												className: "mini-switch"
											})
										}),
										(0, import_jsx_runtime.jsx)(Row, {
											label: "收藏",
											children: (0, import_jsx_runtime.jsx)("input", {
												type: "checkbox",
												id: "showFavoriteItem",
												className: "mini-switch"
											})
										}),
										(0, import_jsx_runtime.jsx)(Row, {
											label: "已观看",
											children: (0, import_jsx_runtime.jsx)("input", {
												type: "checkbox",
												id: "showHasWatchItem",
												className: "mini-switch"
											})
										})
									]
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							className: "jhs-qs-section",
							children: [
								(0, import_jsx_runtime.jsx)("div", {
									className: "jhs-qs-section-title",
									children: "浏览行为"
								}),
								(0, import_jsx_runtime.jsx)(Row, {
									label: "弹窗打开详情",
									tip: "点击封面:弹窗打开,或新窗口打开",
									children: (0, import_jsx_runtime.jsx)("input", {
										type: "checkbox",
										id: "dialogOpenDetail",
										className: "mini-switch"
									})
								}),
								(0, import_jsx_runtime.jsx)(Row, {
									label: "鉴定后关闭页面",
									children: (0, import_jsx_runtime.jsx)("input", {
										type: "checkbox",
										id: "needClosePage",
										className: "mini-switch"
									})
								}),
								(0, import_jsx_runtime.jsx)(Row, {
									label: "触底加载",
									tip: "瀑布流常开。自动=滑到底自动加载下一页;点按钮=滑到底后点「点击加载下一页」。右下角「加载全部」始终可用",
									children: (0, import_jsx_runtime.jsxs)("div", {
										id: "autoPageLoadMode",
										className: "jhs-qs-seg",
										role: "group",
										"aria-label": "触底加载方式",
										children: [(0, import_jsx_runtime.jsx)("button", {
											type: "button",
											className: "jhs-qs-seg-btn",
											"data-value": "auto",
											children: "自动"
										}), (0, import_jsx_runtime.jsx)("button", {
											type: "button",
											className: "jhs-qs-seg-btn",
											"data-value": "click",
											children: "点按钮"
										})]
									})
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							className: "jhs-qs-section",
							children: [
								(0, import_jsx_runtime.jsx)("div", {
									className: "jhs-qs-section-title",
									children: "功能"
								}),
								(0, import_jsx_runtime.jsx)(Row, {
									label: "标题翻译",
									children: (0, import_jsx_runtime.jsx)("input", {
										type: "checkbox",
										id: "translateTitle",
										className: "mini-switch"
									})
								}),
								isJavdbSite ? (0, import_jsx_runtime.jsx)(Row, {
									label: "加载女优信息",
									tip: "详情页展示年龄、三围等信息",
									children: (0, import_jsx_runtime.jsx)("input", {
										type: "checkbox",
										id: "enableLoadActressInfo",
										className: "mini-switch"
									})
								}) : null,
								(0, import_jsx_runtime.jsx)(Row, {
									label: "第三方视频资源",
									tip: "详情页 missAv / SupJav 等检测",
									children: (0, import_jsx_runtime.jsx)("input", {
										type: "checkbox",
										id: "enableLoadOtherSite",
										className: "mini-switch"
									})
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							className: "jhs-qs-section",
							children: [
								(0, import_jsx_runtime.jsx)("div", {
									className: "jhs-qs-section-title",
									children: "页面布局"
								}),
								(0, import_jsx_runtime.jsx)(Row, {
									label: "列数",
									stacked: true,
									children: (0, import_jsx_runtime.jsxs)("div", {
										className: "jhs-qs-range",
										children: [(0, import_jsx_runtime.jsx)("input", {
											type: "range",
											id: "containerColumns",
											min: "2",
											max: "10",
											step: "1"
										}), (0, import_jsx_runtime.jsx)("span", {
											id: "showContainerColumns",
											className: "jhs-qs-range-val"
										})]
									})
								}),
								(0, import_jsx_runtime.jsx)(Row, {
									label: "宽度",
									stacked: true,
									children: (0, import_jsx_runtime.jsxs)("div", {
										className: "jhs-qs-range",
										children: [(0, import_jsx_runtime.jsx)("input", {
											type: "range",
											id: "containerWidth",
											min: "0",
											max: "30",
											step: "1"
										}), (0, import_jsx_runtime.jsx)("span", {
											id: "showContainerWidth",
											className: "jhs-qs-range-val"
										})]
									})
								})
							]
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					className: "jhs-qs-footer",
					children: [(0, import_jsx_runtime.jsx)("button", {
						type: "button",
						id: "helpBtn",
						className: "jhs-qs-btn jhs-qs-btn-ghost",
						children: "常见问题"
					}), (0, import_jsx_runtime.jsx)("button", {
						type: "button",
						id: "moreBtn",
						className: "jhs-qs-btn jhs-qs-btn-primary",
						children: "更多设置"
					})]
				})
			]
		});
	}
	function VideoQualityOption({ quality, text }) {
		return (0, import_jsx_runtime.jsx)("option", {
			value: quality,
			children: text
		});
	}
	var setting_plugin_default = "/* stylelint-disable-next-line selector-type-case -- 运行时占位符(须保持大写),由 setting-plugin.tsx initCss() 的 replace 调用替换为动态容器宽度 CSS */\n__CSS_TEXT__\n\n.nav-btn::after {\n    content: none !important;\n}\n\n#cache-data-display pre {\n    font-family: Consolas, Monaco, 'Andale Mono', monospace;\n    white-space: pre-wrap;\n    overflow-wrap: break-word;\n    line-height: 1.5;\n    color: #333;\n    border: 1px solid #ddd;\n}\n\n.cache-item {\n    transition: box-shadow 0.2s ease, transform 0.2s ease;\n}\n\n.cache-item:hover {\n    box-shadow: 0 2px 8px rgb(0, 0, 0, 0.1);\n    transform: translateY(-2px);\n}\n\n.tooltip-icon {\n    display: inline-block;\n    width: 16px;\n    height: 16px;\n    line-height: 16px;\n    text-align: center;\n    border-radius: 50%;\n    background-color: #ccc;\n    color: white;\n    font-size: 12px;\n    margin-right: 5px;\n    cursor: help;\n}\n\n/* ===== 设置项布局(统一表单网格)===== */\n.setting-item {\n    display: grid;\n    grid-template-columns: 180px 1fr;\n    align-items: center;\n    gap: 12px;\n    padding: 8px 12px;\n    border-radius: 6px;\n    transition: background 0.15s ease;\n}\n\n.setting-item:hover {\n    background: rgb(93, 135, 194, 0.04);\n}\n\n.simple-setting .setting-item {\n    align-items: center;\n}\n\n.setting-label {\n    display: flex;\n    align-items: center;\n    justify-content: flex-end;\n    gap: 5px;\n    font-size: 13px;\n    font-weight: 600;\n    color: #475569;\n    text-align: right;\n    min-width: 0;\n}\n\n.form-content {\n    min-width: 0;\n}\n\n/* form-content 内开关/颜色选择器宽度显式锁定,避免被通用控件规则拉宽 */\n.form-content .jhs-toggle {\n    width: 40px !important;\n    min-width: 40px;\n    padding: 0 !important;\n}\n\n.form-content input[type='color'] {\n    width: 36px !important;\n    min-width: 36px;\n    padding: 2px !important;\n}\n\n/* 统一表单控件(text/number/password/url/select/textarea) */\n.setting-item input[type='text'],\n.setting-item input[type='number'],\n.setting-item input[type='password'],\n.setting-item input[type='url'],\n.setting-item input:not([type]),\n.setting-item select,\n.setting-item textarea {\n    width: 100%;\n    height: 36px;\n    padding: 6px 12px;\n    border: 1px solid #d1d5db;\n    border-radius: 6px;\n    font-size: 13px;\n    color: #1e293b;\n    background: #fff;\n    box-sizing: border-box;\n    transition:\n        border-color 0.15s,\n        box-shadow 0.15s;\n    outline: none;\n}\n\n.setting-item textarea {\n    height: auto;\n    min-height: 72px;\n    resize: vertical;\n}\n\n.setting-item input:focus,\n.setting-item select:focus,\n.setting-item textarea:focus {\n    border-color: #5d87c2;\n    box-shadow: 0 0 0 2px rgb(93, 135, 194, 0.15);\n}\n\n.setting-item input[readonly] {\n    background: #f8fafc;\n    color: #94a3b8;\n    cursor: default;\n    border-color: #e2e8f0;\n}\n\n/* 原生颜色选择器 */\n.setting-item input[type='color'] {\n    width: 36px;\n    height: 36px;\n    padding: 2px;\n    border: 1px solid #d1d5db;\n    border-radius: 6px;\n    cursor: pointer;\n    background: #fff;\n    box-sizing: border-box;\n}\n\n/* 行内问号提示图标 */\n.jhs-tooltip-icon {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    width: 15px;\n    height: 15px;\n    flex-shrink: 0;\n    border-radius: 50%;\n    background: #cbd5e1;\n    color: #fff;\n    font-size: 10px;\n    font-weight: 700;\n    line-height: 1;\n    cursor: help;\n}\n\n/* iOS 风格开关(设置面板内) */\n.jhs-toggle {\n    position: relative;\n    width: 40px;\n    height: 22px;\n    appearance: none;\n    -webkit-appearance: none;\n    background: #d1d5db;\n    border-radius: 11px;\n    cursor: pointer;\n    transition: background 0.2s;\n    border: none;\n    outline: none;\n    flex-shrink: 0;\n    margin: 0;\n    padding: 0;\n    box-sizing: border-box;\n    accent-color: unset;\n}\n\n.jhs-toggle:checked {\n    background: #22c55e;\n}\n\n.jhs-toggle::before {\n    content: '';\n    position: absolute;\n    top: 2px;\n    left: 2px;\n    width: 18px;\n    height: 18px;\n    background: #fff;\n    border-radius: 50%;\n    transition: transform 0.2s;\n    box-shadow: 0 1px 3px rgb(0, 0, 0, 0.15);\n}\n\n.jhs-toggle:checked::before {\n    transform: translateX(18px);\n}\n\n/* 面板分区(替代渐变 hr 分隔线) */\n.jhs-setting-section {\n    margin-top: 20px;\n    padding-top: 16px;\n    border-top: 1px solid #e5e7eb;\n}\n\n.jhs-setting-section:first-child {\n    margin-top: 0;\n    padding-top: 0;\n    border-top: none;\n}\n\n.jhs-setting-section-title {\n    display: flex;\n    align-items: center;\n    gap: 6px;\n    font-size: 14px;\n    font-weight: 600;\n    color: #5d87c2;\n    margin-bottom: 12px;\n}\n\n/* 面板操作按钮(语义色修饰符) */\n.jhs-setting-btn {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    gap: 6px;\n    height: 34px;\n    padding: 6px 16px;\n    border: none;\n    border-radius: 6px;\n    font-size: 13px;\n    font-weight: 500;\n    cursor: pointer;\n    transition:\n        opacity 0.15s,\n        transform 0.1s;\n    color: #fff;\n    text-decoration: none;\n    white-space: nowrap;\n    box-sizing: border-box;\n}\n\n.jhs-setting-btn:hover {\n    opacity: 0.9;\n}\n\n.jhs-setting-btn:active {\n    transform: scale(0.97);\n}\n\n.jhs-setting-btn--primary {\n    background: #5d87c2;\n}\n\n.jhs-setting-btn--success {\n    background: #22c55e;\n}\n\n.jhs-setting-btn--danger {\n    background: #ef4444;\n}\n\n.jhs-setting-btn--pink {\n    background: #d25a88;\n}\n\n.jhs-setting-btn--mint {\n    background: #85d0a3;\n}\n\n/* 复选框 + 文字标签 */\n.jhs-checkbox-label {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    cursor: pointer;\n    font-size: 13px;\n    color: #475569;\n}\n\n.jhs-checkbox-label input[type='checkbox'] {\n    width: 16px;\n    height: 16px;\n    accent-color: #5d87c2;\n    cursor: pointer;\n    margin: 0;\n    flex-shrink: 0;\n}\n\n.keyword-label {\n    display: inline-flex;\n    align-items: center;\n    padding: 4px 8px;\n    border-radius: 4px;\n    font-size: 14px;\n    position: relative;\n    margin-left: 8px;\n    margin-bottom: 5px;\n}\n\n.keyword-remove {\n    margin-left: 6px;\n    cursor: pointer;\n    font-size: 12px;\n    line-height: 1;\n}\n\n.keyword-input {\n    padding: 6px 12px;\n    border: 1px solid #cbd5e1;\n    border-radius: 6px;\n    font-size: 14px;\n    float: right;\n}\n\n.add-tag-btn {\n    padding: 6px 12px;\n    background-color: #e2e8f0;\n    color: #334155;\n    border: none;\n    border-radius: 6px;\n    cursor: pointer;\n    font-size: 14px;\n    margin-left: 8px;\n    float: right;\n}\n\n.add-tag-btn:hover {\n    background-color: #cbd5e1;\n}\n\n.tag-box {\n    margin-top: 15px;\n}\n\n/* 屏蔽关键词容器:标签流式换行 + 输入行自然布局 */\n.filter-keyword-container {\n    padding: 8px 0;\n}\n\n.filter-keyword-container .tag-box {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 6px;\n    min-height: 32px;\n    margin-top: 0;\n}\n\n/* ===== 通用按钮(jhs-setting-menu-btn 统一样式)===== */\n.jhs-setting-menu-btn {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    padding: 7px 16px;\n    border-radius: 6px;\n    text-decoration: none;\n    font-size: 13px;\n    font-weight: 500;\n    transition: opacity 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;\n    cursor: pointer;\n    border: none;\n    white-space: nowrap;\n    color: #fff !important;\n}\n\n.jhs-setting-menu-btn span {\n    color: #fff !important;\n}\n\n.jhs-setting-menu-btn:hover {\n    opacity: 0.88;\n    transform: translateY(-1px);\n    box-shadow: 0 2px 8px rgb(0, 0, 0, 0.15);\n}\n\n.jhs-setting-menu-btn:active {\n    transform: translateY(0);\n}\n\n/* ===== 底部操作按钮(jhs-setting-btn 统一按钮系统)===== */\n#saveBtn,\n#clean-all {\n    margin-top: 0;\n}\n\n/* ===== 悬浮快捷设置面板 ===== */\n.simple-setting,\n.mini-simple-setting {\n    display: none;\n    position: absolute;\n    top: calc(100% + 6px);\n    right: 0;\n    left: auto;\n    z-index: 10000;\n    width: 340px;\n    max-width: min(340px, 92vw);\n    padding: 0;\n    margin: 0;\n    color: #1e293b;\n    background: #fff;\n    border: 1px solid #e2e8f0;\n    border-radius: 12px;\n    box-shadow:\n        0 10px 40px rgb(15, 23, 42, 0.12),\n        0 2px 8px rgb(15, 23, 42, 0.06);\n    overflow: hidden;\n}\n\n/* 与触发按钮之间的隐形热区,减少移入时误关 */\n.simple-setting::before,\n.mini-simple-setting::before {\n    content: '';\n    position: absolute;\n    top: -10px;\n    left: 0;\n    right: 0;\n    height: 10px;\n}\n\n.mini-simple-setting {\n    right: 0;\n    left: auto;\n}\n\n/* 快捷设置内部布局 */\n.jhs-qs-panel {\n    display: flex;\n    flex-direction: column;\n    max-height: min(78vh, 560px);\n}\n\n.jhs-qs-header {\n    display: flex;\n    align-items: baseline;\n    justify-content: space-between;\n    gap: 8px;\n    padding: 14px 16px 10px;\n    border-bottom: 1px solid #f1f5f9;\n    background: linear-gradient(180deg, #f8fafc 0%, #fff 100%);\n}\n\n.jhs-qs-title {\n    font-size: 15px;\n    font-weight: 700;\n    color: #0f172a;\n    letter-spacing: 0.02em;\n}\n\n.jhs-qs-sub {\n    font-size: 11px;\n    color: #94a3b8;\n    font-weight: 500;\n}\n\n.jhs-qs-body {\n    flex: 1;\n    overflow-x: hidden;\n    overflow-y: auto;\n    padding: 8px 10px 12px;\n}\n\n.jhs-qs-section {\n    margin-bottom: 10px;\n    padding: 8px 8px 4px;\n    background: #f8fafc;\n    border: 1px solid #f1f5f9;\n    border-radius: 10px;\n}\n\n.jhs-qs-section:last-child {\n    margin-bottom: 0;\n}\n\n.jhs-qs-section-title {\n    font-size: 11px;\n    font-weight: 700;\n    color: #64748b;\n    text-transform: none;\n    letter-spacing: 0.04em;\n    padding: 2px 6px 8px;\n}\n\n.jhs-qs-row {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    gap: 12px;\n    min-height: 36px;\n    padding: 6px 8px;\n    margin-bottom: 2px;\n    border-radius: 8px;\n    transition: background 0.12s ease;\n}\n\n.jhs-qs-row:hover {\n    background: rgb(255, 255, 255, 0.9);\n}\n\n.jhs-qs-row-stacked {\n    flex-direction: column;\n    align-items: stretch;\n    gap: 6px;\n    min-height: 0;\n    padding-bottom: 10px;\n}\n\n.jhs-qs-label {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n    font-size: 13px;\n    font-weight: 600;\n    color: #334155;\n    line-height: 1.35;\n    min-width: 0;\n}\n\n.jhs-qs-tip {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    width: 15px;\n    height: 15px;\n    flex-shrink: 0;\n    border-radius: 50%;\n    background: #cbd5e1;\n    color: #fff;\n    font-size: 10px;\n    font-weight: 700;\n    cursor: help;\n    line-height: 1;\n}\n\n.jhs-qs-control {\n    display: flex;\n    align-items: center;\n    justify-content: flex-end;\n    flex-shrink: 0;\n}\n\n.jhs-qs-row-stacked .jhs-qs-control {\n    justify-content: stretch;\n}\n\n.jhs-qs-subcard {\n    margin: 2px 0 6px;\n    padding: 4px;\n    background: #fff;\n    border: 1px solid #e2e8f0;\n    border-radius: 8px;\n}\n\n.jhs-qs-subcard.is-disabled {\n    opacity: 0.55;\n    pointer-events: none;\n}\n\n.jhs-qs-subcard .jhs-qs-row {\n    min-height: 32px;\n    padding: 4px 8px;\n}\n\n.jhs-qs-subcard .jhs-qs-label {\n    font-weight: 500;\n    font-size: 12.5px;\n    color: #475569;\n}\n\n/* 触底加载等二选一:分段按钮 */\n.jhs-qs-seg {\n    display: inline-flex;\n    align-items: stretch;\n    flex-shrink: 0;\n    padding: 2px;\n    background: #e2e8f0;\n    border-radius: 9px;\n    box-sizing: border-box;\n}\n\n.jhs-qs-seg-btn {\n    appearance: none;\n    border: none;\n    margin: 0;\n    padding: 6px 12px;\n    min-width: 64px;\n    border-radius: 7px;\n    font-size: 12px;\n    font-weight: 600;\n    line-height: 1.2;\n    color: #64748b;\n    background: transparent;\n    cursor: pointer;\n    transition:\n        background 0.15s ease,\n        color 0.15s ease,\n        box-shadow 0.15s ease;\n    white-space: nowrap;\n}\n\n.jhs-qs-seg-btn:hover:not(.is-active) {\n    color: #334155;\n    background: rgb(255, 255, 255, 0.55);\n}\n\n.jhs-qs-seg-btn.is-active {\n    color: #fff;\n    background: linear-gradient(135deg, #5d87c2, #4a90d9);\n    box-shadow: 0 1px 4px rgb(74, 144, 217, 0.35);\n}\n\n.jhs-qs-seg-btn:focus-visible {\n    outline: 2px solid #5d87c2;\n    outline-offset: 1px;\n}\n\n.jhs-qs-range {\n    display: flex;\n    align-items: center;\n    gap: 10px;\n    width: 100%;\n}\n\n.jhs-qs-range input[type='range'] {\n    flex: 1;\n    min-width: 0;\n    height: 6px;\n    padding: 0 !important;\n    accent-color: #5d87c2;\n    cursor: pointer;\n}\n\n.jhs-qs-range-val {\n    min-width: 36px;\n    text-align: right;\n    font-size: 12px;\n    font-weight: 700;\n    color: #5d87c2;\n    font-variant-numeric: tabular-nums;\n}\n\n.jhs-qs-footer {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    gap: 10px;\n    padding: 10px 14px 12px;\n    border-top: 1px solid #f1f5f9;\n    background: #fafbfc;\n}\n\n.jhs-qs-btn {\n    flex: 1;\n    padding: 8px 12px;\n    border: none;\n    border-radius: 8px;\n    font-size: 13px;\n    font-weight: 600;\n    cursor: pointer;\n    transition:\n        background 0.15s ease,\n        transform 0.12s ease,\n        box-shadow 0.15s ease;\n}\n\n.jhs-qs-btn:hover {\n    transform: translateY(-1px);\n}\n\n.jhs-qs-btn:active {\n    transform: translateY(0);\n}\n\n.jhs-qs-btn-ghost {\n    background: #fff;\n    color: #64748b;\n    border: 1px solid #e2e8f0;\n}\n\n.jhs-qs-btn-ghost:hover {\n    background: #f8fafc;\n    color: #475569;\n    border-color: #cbd5e1;\n}\n\n.jhs-qs-btn-primary {\n    background: linear-gradient(135deg, #5d87c2, #4a90d9);\n    color: #fff;\n    box-shadow: 0 2px 8px rgb(74, 144, 217, 0.28);\n}\n\n.jhs-qs-btn-primary:hover {\n    box-shadow: 0 4px 12px rgb(74, 144, 217, 0.35);\n}\n\n/* 快捷设置内开关:避免被 form-content 通配拉宽 */\n.jhs-qs-panel input.mini-switch[type='checkbox'] {\n    width: 40px !important;\n    min-width: 40px !important;\n    max-width: 40px !important;\n}\n\n/* ===== 开关(mini-switch)===== */\n\n/* 排除 form-content 通配与 content-panel checkbox 规则的干扰 */\ninput.mini-switch[type='checkbox'] {\n    appearance: none;\n    -webkit-appearance: none;\n    width: 40px;\n    height: 20px;\n    min-width: 40px;\n    max-width: 40px;\n    padding: 0;\n    margin: 0;\n    background: #e0e0e0;\n    border: none;\n    border-radius: 20px;\n    position: relative;\n    cursor: pointer;\n    outline: none;\n    box-sizing: border-box;\n    flex-shrink: 0;\n    vertical-align: middle;\n    accent-color: unset;\n}\n\ninput.mini-switch[type='checkbox']:checked {\n    background: #4caf50;\n}\n\ninput.mini-switch[type='checkbox']::before {\n    content: '';\n    position: absolute;\n    width: 16px;\n    height: 16px;\n    border-radius: 50%;\n    background: white;\n    top: 2px;\n    left: 2px;\n    box-shadow: 0 1px 3px rgb(0, 0, 0, 0.2);\n    transition: left 0.15s ease;\n}\n\ninput.mini-switch[type='checkbox']:checked::before {\n    left: calc(100% - 18px);\n}\n\n/* ===== 侧栏导航 ===== */\n.side-menu-item {\n    padding: 11px 16px;\n    cursor: pointer;\n    color: #64748b;\n    border-left: 3px solid transparent;\n    transition: color 0.2s, background-color 0.2s, border-color 0.2s;\n    display: flex;\n    align-items: center;\n    gap: 6px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    font-size: 14px;\n    font-weight: 500;\n}\n\n.side-menu-item .icon {\n    height: 24px;\n    width: 24px;\n}\n\n.side-menu-item:hover {\n    background-color: rgb(93, 135, 194, 0.08);\n    color: #5d87c2;\n}\n\n.side-menu-item.active {\n    background-color: rgb(93, 135, 194, 0.12);\n    border-left: 3px solid #5d87c2;\n    color: #5d87c2;\n    font-weight: 600;\n}\n\n/* ===== 内容面板 ===== */\n.content-panel {\n    display: none;\n    margin-top: 16px;\n    padding: 0 12px 10px 4px;\n    height: 100%;\n    overflow-x: hidden;\n    overflow-y: auto;\n}\n\n.content-panel.active {\n    display: block;\n}\n\n/* 表单控件统一样式已收敛至「设置项布局」区块的 .setting-item 作用域规则 */\n\n/* ===== 复选框美化(不含开关)===== */\n.content-panel input[type='checkbox']:not(.mini-switch, .jhs-toggle) {\n    width: 16px;\n    height: 16px;\n    accent-color: #5d87c2;\n    cursor: pointer;\n}\n\ninput[type='checkbox']:disabled {\n    opacity: 0.6;\n    cursor: default !important;\n}\n\n";
	var back_to_top_button_default = "#jhs-back-to-top,\n#jdb-wf-back-to-top {\n    position: fixed;\n    bottom: 40px;\n    right: 40px;\n    width: 44px;\n    height: 44px;\n    background-color: rgb(30, 30, 30, 0.9);\n    backdrop-filter: blur(4px);\n    color: #e0e0e0;\n    border-radius: 50%;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    cursor: pointer;\n    z-index: var(--jhs-z-page);\n    opacity: 0;\n    visibility: hidden;\n    transform: translateY(20px) scale(0.9);\n    transition:\n        opacity 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        visibility 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        background-color 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        color 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n        border-color 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n    box-shadow: 0 4px 12px rgb(0, 0, 0, 0.3);\n    border: 1px solid rgb(255, 255, 255, 0.05);\n    user-select: none;\n}\n\n#jhs-back-to-top:hover,\n#jdb-wf-back-to-top:hover {\n    background-color: #ff8400;\n    color: #fff;\n    transform: translateY(0) scale(1);\n    box-shadow: 0 8px 20px rgb(255, 132, 0, 0.3);\n    border-color: #ff8400;\n}\n\n#jhs-back-to-top.show,\n#jdb-wf-back-to-top.show {\n    opacity: 1;\n    visibility: visible;\n    transform: translateY(0) scale(1);\n}\n\n#jhs-back-to-top svg,\n#jdb-wf-back-to-top svg {\n    width: 22px;\n    height: 22px;\n    fill: currentcolor;\n    stroke: currentcolor;\n    stroke-width: 0;\n}\n";
	var setting_image_mode_horizontal_default = ".cover {\n    min-height: auto !important;\n    padding-top: 67% !important;\n}\n\n.cover img {\n    object-fit: contain !important;\n    object-position: 50% 50% !important;\n}\n\n/* bus的 */\n.masonry .movie-box img {\n    min-height: auto !important;\n    object-fit: contain !important;\n    object-position: top;\n}\n";
	var SettingPlugin = class extends BasePlugin {
		folderName = "JHS-数据备份";
		simpleSettingHideTimer = null;
		cacheItems = [
			{
				key: "jhs_dmm_video",
				text: "🎥 预览视频缓存",
				title: "DMM 预告片画质→URL 映射(联动清理 jhs_other_site_dmm)"
			},
			{
				key: "jhs_other_site",
				text: "🌍 第三方站点缓存",
				title: "missav/supjav 等站点搜索结果(随 WebDav 备份)"
			},
			{
				key: "jhs_other_site_dmm",
				text: "🌍 DMM 预览伴生缓存",
				title: "DMM 预览相关第三方链接(随 WebDav 备份)"
			},
			{
				key: "jhs_translate",
				text: "🆎 标题翻译",
				title: "番号→中文标题翻译(Google Translate,随备份)"
			},
			{
				key: "jhs_actress_info",
				text: "👩 演员信息",
				title: "演员身高/体重/三围/罩杯/生日(随备份)"
			},
			{
				key: "jhs_score_info",
				text: "⭐ Top250|热播 评分数据",
				title: "影片评分 HTML 快照(随备份)"
			},
			{
				key: "jhs_screenShot",
				text: "🖼️ 截图墙缓存",
				title: "javstore 截图墙(随备份)"
			},
			{
				key: "jhs_visit_history",
				text: "🕐 访问记录",
				title: "页面访问时间记录(随备份)"
			},
			{
				key: "jdb:rating_cache_v2",
				text: "⭐ 列表评分缓存",
				title: "评分显示插件缓存(随备份)"
			}
		];
		getName() {
			return "SettingPlugin";
		}
		async initCss() {
			const settings = await storageManager.getSetting();
			const containerWidth = (settings == null ? void 0 : settings.containerWidth) ?? "70";
			const containerColumns = utils.isMobile() && window.innerWidth < 1e3 ? 1 : (settings == null ? void 0 : settings.containerColumns) ?? 4;
			this.applyImageMode().then();
			const cssText = `\n            section .container{\n                max-width: 1000px !important;\n                min-width: ${containerWidth}%;\n            }\n            .movie-list, .movie-list.v{\n                grid-template-columns: repeat(${containerColumns}, minmax(0, 1fr));\n            }\n        `;
			return setting_plugin_default.replace("__CSS_TEXT__", cssText);
		}
		cancelSimpleSettingHide() {
			if (this.simpleSettingHideTimer != null) {
				clearTimeout(this.simpleSettingHideTimer);
				this.simpleSettingHideTimer = null;
			}
		}
		scheduleSimpleSettingHide(selector) {
			this.cancelSimpleSettingHide();
			this.simpleSettingHideTimer = setTimeout(() => {
				$(selector).html("").hide();
				this.simpleSettingHideTimer = null;
			}, 220);
		}
		openSimpleSetting(selector) {
			this.cancelSimpleSettingHide();
			$(selector).html(this.simpleSetting()).show();
			this.initSimpleSettingForm().then();
			clog.lowZIndex();
		}
		async handle() {
			if (await storageManager.getSetting("enableClog", "yes") === "yes") clog.show();
			if (isJavdbSite) {
				const toggleSettingBox = function() {
					if ($(".navbar-search").is(":hidden")) {
						$(".mini-setting-box").hide();
						$(".setting-box").show();
					} else {
						$(".mini-setting-box").show();
						$(".setting-box").hide();
					}
				};
				$("#navbar-menu-user .navbar-end").prepend(jsxToString((0, import_jsx_runtime.jsx)(SettingMountBox, { variant: "navbar" })));
				utils.loopDetector(() => $("#miniHistoryBtn").length > 0, () => {
					$(".miniHistoryBtnBox").before(jsxToString((0, import_jsx_runtime.jsx)(SettingMountBox, { variant: "mini" })));
					toggleSettingBox();
				});
				$(window).resize(toggleSettingBox);
			}
			$(".main-nav, .container-fluid").on("click", "#setting-btn, #mini-setting-btn", () => {
				clog.lowZIndex();
				this.openSettingDialog();
			});
			$(".main-nav, .container-fluid").on("mouseenter", ".setting-box", () => {
				this.openSimpleSetting(".simple-setting");
			}).on("mouseleave", ".setting-box", () => {
				this.scheduleSimpleSettingHide(".simple-setting");
			});
			$(".main-nav, .container-fluid").on("mouseenter", ".mini-setting-box", () => {
				this.openSimpleSetting(".mini-simple-setting");
			}).on("mouseleave", ".mini-setting-box", () => {
				this.scheduleSimpleSettingHide(".mini-simple-setting");
			});
			this.addBackToTopBtn();
		}
		addBackToTopBtn() {
			utils.insertStyle(back_to_top_button_default);
			const btn = $(jsxToString((0, import_jsx_runtime.jsx)(BackToTopButton, {})));
			$("body").append(btn);
			btn.on("click", () => {
				utils.smoothScrollToTop(500);
			});
			let ticking = false;
			$(window).on("scroll", () => {
				if (!ticking) {
					window.requestAnimationFrame(() => {
						if (($(window).scrollTop() ?? 0) > 300) btn.addClass("show");
						else btn.removeClass("show");
						ticking = false;
					});
					ticking = true;
				}
			});
		}
		async openSettingDialog(panelName = "backup-panel", callback) {
			const cacheItemsHtml = this.cacheItems.map((item) => {
				const stats = getCacheStats(item.key);
				return jsxToString((0, import_jsx_runtime.jsx)(CacheItemHtml, {
					text: item.text,
					cacheKey: item.key,
					title: item.title,
					size: formatSize(stats.size),
					count: stats.count > 0 ? `${stats.count} 条` : "空"
				}));
			}).join("");
			let qualityOptionsHtml = "";
			VIDEO_QUALITY_LIST.forEach((option) => {
				if (option.canSelect) qualityOptionsHtml += jsxToString((0, import_jsx_runtime.jsx)(VideoQualityOption, {
					quality: option.quality,
					text: option.text
				}));
			});
			const dialogHtml = jsxToString((0, import_jsx_runtime.jsx)(SettingDialog, {
				panelName,
				cacheItemsHtml,
				qualityOptionsHtml,
				isJavdbSite
			}));
			layer.open({
				type: 1,
				title: "设置",
				content: dialogHtml,
				area: utils.getResponsiveArea(["55%", "90%"]),
				scrollbar: false,
				success: (layerEl, layerIndex) => {
					$(layerEl).find(".layui-layer-content").css("position", "relative");
					this.loadForm();
					this.bindClick();
					utils.setupEscClose(layerIndex);
					if (callback) callback();
				}
			});
		}
		simpleSetting() {
			return jsxToString((0, import_jsx_runtime.jsx)(SimpleSettingPanel, { isJavdbSite }));
		}
		async applyImageMode() {
			$("#verticalImgStyle").remove();
			$(jsxToString((0, import_jsx_runtime.jsx)(StyleBlock, {
				id: "verticalImgStyle",
				css: setting_image_mode_horizontal_default
			}))).appendTo("head");
		}
		refreshDiagnostics() {
			$("#diagnostics-content").html(renderDiagnosticsHtml(this.pluginManager));
		}
		addLabelTag(containerSelector, keyword) {
			addLabelTag(containerSelector, keyword);
		}
		addKeyword(containerSelector) {
			addKeyword(containerSelector);
		}
		async autoBackup() {
			const settings = await storageManager.getSetting();
			if (!shouldAutoBackup(settings.autoBackupConfig || DEFAULT_AUTO_BACKUP_CONFIG)) return;
			const creds = getWebDavCredentialsFromGm();
			if (!creds) return;
			try {
				const exportText = JSON.stringify(await this.buildBackupPayload(settings));
				await new window.WebDavClient(creds.url, creds.username, creds.password).backup(this.folderName, getAutoBackupFileName(), exportText);
				markAutoBackupDone();
				console.log("[JHS 自动备份] 完成");
			} catch (err) {
				console.warn("[JHS 自动备份] 失败:", err instanceof Error ? err.message : String(err));
			}
		}
		async loadForm() {
			return loadForm(this);
		}
		async saveForm() {
			return saveForm(this);
		}
		bindClick() {
			bindClick$1(this);
		}
		async initSimpleSettingForm() {
			return initSimpleSettingForm(this);
		}
		refreshCacheStats(cacheKey) {
			refreshCacheStats(this, cacheKey);
		}
		refreshPreloadCacheStats() {
			refreshPreloadCacheStats(this);
		}
		refreshAllCacheStats() {
			refreshAllCacheStats(this);
		}
		importData() {
			importData(this);
		}
		async exportData() {
			return exportData(this);
		}
		async buildBackupPayload(settings) {
			return buildBackupPayload(settings);
		}
		async backupDataByWebDav() {
			return backupDataByWebDav(this);
		}
		async backupListBtnByWebDav() {
			return backupListBtnByWebDav(this);
		}
		openFileListDialog(backupList, webdavClient, titlePrefix) {
			openFileListDialog(this, backupList, webdavClient, titlePrefix);
		}
	};
	function broadcastSend(key, payload, opts = {}) {
		const { eventName = key, eventDetail = payload, onError } = opts;
		const json = JSON.stringify(payload);
		try {
			GM_setValue(key, json);
		} catch (error) {
			onError?.("gm", error);
		}
		try {
			localStorage.setItem(key, json);
		} catch (error) {
			onError?.("localStorage", error);
		}
		try {
			document.dispatchEvent(new CustomEvent(eventName, { detail: eventDetail }));
		} catch (error) {
			onError?.("customEvent", error);
		}
	}
	function broadcastSubscribe(key, handler, opts = {}) {
		const eventName = opts.eventName ?? key;
		const raw = opts.raw === true;
		const onDelivery = opts.onDelivery;
		document.addEventListener(eventName, (e) => {
			onDelivery?.({ channel: "customEvent" });
			handler(e.detail, { channel: "customEvent" });
		});
		window.addEventListener("storage", (e) => {
			if (e.key !== key) return;
			const delivery = {
				channel: "storage",
				rawValue: e.newValue ?? void 0
			};
			onDelivery?.(delivery);
			if (!e.newValue) return;
			if (raw) {
				handler(e.newValue, delivery);
				return;
			}
			let payload;
			try {
				payload = JSON.parse(e.newValue);
			} catch {
				return;
			}
			handler(payload, delivery);
		});
		try {
			GM_addValueChangeListener(key, (_name, _oldValue, newValue, remote) => {
				const delivery = {
					channel: "gm",
					rawValue: newValue,
					remote
				};
				onDelivery?.(delivery);
				if (!newValue) return;
				if (raw) {
					handler(newValue, delivery);
					return;
				}
				let payload;
				try {
					payload = JSON.parse(newValue);
				} catch {
					return;
				}
				handler(payload, delivery);
			});
		} catch {}
	}
	function hookWantAndWatchedButtons(plugin) {
		if (!isJavdbSite) return;
		if (plugin._wantWatchedObserved) return;
		const self = plugin;
		const ensure = () => {
			const container = document.querySelector("body > section > div > div.video-detail > div.video-meta-panel > div > div:nth-child(2) > nav > div.review-buttons");
			if (!container) {
				setTimeout(ensure, 200);
				return;
			}
			if (container.__jhsObserved) return;
			container.__jhsObserved = true;
			self._wantWatchedObserved = true;
			self._lastWantState = self.detectWantWatchedState(container);
			new MutationObserver(() => {
				if (self._wantWatchedSyncing) return;
				clearTimeout(self._wantWatchedDebounce ?? void 0);
				self._wantWatchedDebounce = setTimeout(() => {
					self._wantWatchedSyncing = true;
					try {
						const currentState = self.detectWantWatchedState(container);
						const lastState = self._lastWantState || {
							want: false,
							watched: false
						};
						if (currentState.want !== lastState.want) if (currentState.want) self.onWantAdded();
						else self.onWantRemoved();
						if (currentState.watched !== lastState.watched) if (currentState.watched) self.onWatchedAdded();
						else self.onWatchedRemoved();
						self._lastWantState = currentState;
					} finally {
						self._wantWatchedSyncing = false;
					}
				}, 150);
			}).observe(container, {
				childList: true,
				subtree: true
			});
		};
		ensure();
	}
	function detectWantWatchedState(container) {
		const wantTag = container.querySelector("a[href='/users/want_watch_videos'] .tag.is-info.is-light");
		const watchedTag = container.querySelector("a[href='/users/watched_videos'] .tag.is-success.is-light");
		return {
			want: !!wantTag,
			watched: !!watchedTag
		};
	}
	async function onWantAdded(plugin) {
		const pageInfo = plugin.getPageInfo();
		try {
			const carRecord = await storageManager.getCar(pageInfo.carNum);
			if (carRecord && carRecord.status === "favorite") {} else {
				await storageManager.saveCar({
					carNum: pageInfo.carNum,
					url: pageInfo.url ?? void 0,
					names: pageInfo.actress ?? void 0,
					actionType: FAVORITE_ACTION,
					publishTime: pageInfo.publishTime ?? void 0
				});
				plugin.broadcastWantWatchedSync({
					carNum: pageInfo.carNum,
					status: FAVORITE_ACTION,
					op: "add"
				});
				show.ok(`${pageInfo.carNum} 已收藏`);
			}
		} catch (err) {
			clog.error("[JHS-想看自动同步] 写入失败", err);
		}
		plugin.showStatus(pageInfo.carNum).then();
	}
	async function onWantRemoved(plugin) {
		const pageInfo = plugin.getPageInfo();
		try {
			if (await plugin.removeCarIfStatus(pageInfo.carNum, "favorite")) {
				plugin.broadcastWantWatchedSync({
					carNum: pageInfo.carNum,
					status: FAVORITE_ACTION,
					op: "remove"
				});
				show.ok(`${pageInfo.carNum} 已取消收藏`);
			}
		} catch (err) {
			clog.error("[JHS-想看自动同步] 移除失败", err);
		}
		plugin.showStatus(pageInfo.carNum).then();
	}
	async function onWatchedAdded(plugin) {
		const pageInfo = plugin.getPageInfo();
		try {
			const carRecord = await storageManager.getCar(pageInfo.carNum);
			if (carRecord && carRecord.status === "hasWatch") {} else {
				await storageManager.saveCar({
					carNum: pageInfo.carNum,
					url: pageInfo.url ?? void 0,
					names: pageInfo.actress ?? void 0,
					actionType: HAS_WATCH_ACTION,
					publishTime: pageInfo.publishTime ?? void 0
				});
				plugin.broadcastWantWatchedSync({
					carNum: pageInfo.carNum,
					status: HAS_WATCH_ACTION,
					op: "add"
				});
				show.ok(`${pageInfo.carNum} 已标记看过`);
			}
		} catch (err) {
			clog.error("[JHS-观看自动同步] 写入失败", err);
		}
		plugin.showStatus(pageInfo.carNum).then();
	}
	async function onWatchedRemoved(plugin) {
		const pageInfo = plugin.getPageInfo();
		try {
			if (await plugin.removeCarIfStatus(pageInfo.carNum, "hasWatch")) {
				plugin.broadcastWantWatchedSync({
					carNum: pageInfo.carNum,
					status: HAS_WATCH_ACTION,
					op: "remove"
				});
				show.ok(`${pageInfo.carNum} 已取消看过`);
			}
		} catch (err) {
			clog.error("[JHS-观看自动同步] 移除失败", err);
		}
		plugin.showStatus(pageInfo.carNum).then();
	}
	async function removeCarIfStatus(carNum, status) {
		const carRecord = await storageManager.getCar(carNum);
		if (!carRecord) return false;
		if (carRecord.status !== status) return false;
		return await storageManager.removeCar(carNum);
	}
	function broadcastWantWatchedSync$1(payload) {
		try {
			broadcastSend("jdb:want-watched-sync", {
				...payload,
				time: Date.now()
			}, {
				eventDetail: payload,
				onError: () => {}
			});
		} catch (err) {
			clog.error("[JHS-想看/观看同步] 广播失败", err);
		}
	}
	function setupWantWatchedSyncListener(plugin) {
		if (!isJavdbSite) return;
		if (plugin._wantWatchedListenerInstalled) return;
		plugin._wantWatchedListenerInstalled = true;
		const self = plugin;
		const handleSync = (rawData) => {
			const payload = rawData?.detail || (() => {
				try {
					return JSON.parse(rawData);
				} catch {
					return null;
				}
			})();
			if (!payload || !payload.carNum) return;
			storageManager.clearCarListCache();
			try {
				const currentCarNum = self.getPageInfo().carNum;
				if (currentCarNum && payload.carNum === currentCarNum) self.showStatus(currentCarNum).then(() => {});
			} catch {}
			self.refreshItemStatusTag(payload.carNum);
		};
		broadcastSubscribe("jdb:want-watched-sync", (rawData) => handleSync(rawData), { raw: true });
	}
	function refreshItemStatusTag(plugin, carNum) {
		try {
			const itemSelector = plugin.getSelector().itemSelector;
			const items = document.querySelectorAll(itemSelector);
			for (const item of items) {
				const strongEl = item.querySelector("a > div.video-title > strong");
				if (!strongEl || strongEl.innerHTML !== carNum) continue;
				const listPagePlugin = plugin.getBean("ListPagePlugin");
				if (!listPagePlugin) continue;
				listPagePlugin.renderItemStatusTag(item, carNum);
			}
		} catch (err) {
			clog.error("[JHS-想看/观看] 刷新列表项 status-tag 失败", err);
		}
	}
	function RatingBarHtml() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", {
			className: "jhs-stars",
			"data-score": 0,
			children: [
				1,
				2,
				3,
				4,
				5
			].map((n) => (0, import_jsx_runtime.jsx)("span", {
				className: "jhs-star",
				"data-score": n,
				children: "★"
			}, n))
		}), (0, import_jsx_runtime.jsxs)("div", {
			className: "jhs-rating-actions",
			children: [
				(0, import_jsx_runtime.jsx)("button", {
					className: "jhs-fav-btn",
					type: "button",
					title: "设为想看(收藏)",
					children: "♥ 收藏"
				}),
				(0, import_jsx_runtime.jsx)("button", {
					className: "jhs-read-btn",
					type: "button",
					title: "设为已观看(0星)",
					children: "已读"
				}),
				(0, import_jsx_runtime.jsx)("button", {
					className: "jhs-block-btn",
					type: "button",
					title: "拉黑该影片(屏蔽,设为已读0星后关闭页面)",
					children: "🚫 拉黑"
				})
			]
		})] });
	}
	var rating_bar_default = "/* 隐藏 review-buttons 内第二个 panel-block(下載/訂正磁力按钮) */\n.review-buttons > .panel-block ~ .panel-block {\n    display: none !important;\n}\n\n/* 隐藏 review-buttons 后紧跟的 panel-block(N人想看/看過统计) */\n.review-buttons + .panel-block {\n    display: none !important;\n}\n\n/* 隐藏原生评价状态标签和按钮(星星组件已替代) */\n.review-buttons .review-title {\n    display: none !important;\n}\n\n.review-buttons .buttons.are-small.review-buttons {\n    display: none !important;\n}\n\n/* 永久隐藏清单 modal(DOM 保留供 Stimulus ajax 操作) */\n#modal-save-list {\n    display: none !important;\n}\n\n/* 星星评分组件 */\n.jhs-rating-bar {\n    display: flex;\n    flex-direction: column;\n    gap: 6px;\n    margin: 4px 0 12px;\n    user-select: none;\n}\n\n.jhs-stars {\n    display: inline-flex;\n    gap: 6px;\n    align-items: center;\n}\n\n.jhs-star {\n    font-size: 26px;\n    line-height: 1.2;\n    padding: 2px 4px;\n    cursor: pointer;\n    color: #d0d0d0;\n    transition:\n        color 0.15s,\n        transform 0.15s;\n}\n\n.jhs-star:hover {\n    transform: scale(1.15);\n}\n\n.jhs-star.is-preview {\n    color: #f5b301;\n}\n\n.jhs-star.is-active {\n    color: #f5b301;\n}\n\n.jhs-star.is-active:hover {\n    color: #ffce3a;\n}\n\n.jhs-star.is-popping {\n    animation: jhs-star-pop 0.3s ease;\n}\n\n@keyframes jhs-star-pop {\n    0% {\n        transform: scale(1);\n    }\n\n    40% {\n        transform: scale(1.4);\n    }\n\n    100% {\n        transform: scale(1);\n    }\n}\n\n.jhs-stars.is-disabled .jhs-star {\n    cursor: default;\n    opacity: 0.4;\n    pointer-events: none;\n}\n\n.jhs-rating-actions {\n    display: flex;\n    gap: 8px;\n    align-items: center;\n}\n\n.jhs-read-btn,\n.jhs-fav-btn,\n.jhs-block-btn {\n    border: 1px solid #dbdbdb;\n    border-radius: 6px;\n    padding: 5px 16px;\n    font-size: 14px;\n    background: #fff;\n    cursor: pointer;\n    transition: color 0.15s, background-color 0.15s, border-color 0.15s, box-shadow 0.15s;\n    white-space: nowrap;\n}\n\n.jhs-read-btn:hover,\n.jhs-fav-btn:hover,\n.jhs-block-btn:hover {\n    border-color: #b5b5b5;\n    box-shadow: 0 1px 4px rgb(0, 0, 0, 0.08);\n}\n\n.jhs-read-btn.is-active {\n    background: #48c774;\n    border-color: #48c774;\n    color: #fff;\n}\n\n.jhs-fav-btn.is-active {\n    background: #3273dc;\n    border-color: #3273dc;\n    color: #fff;\n}\n\n.jhs-block-btn.is-active {\n    background: #de3333;\n    border-color: #de3333;\n    color: #fff;\n}\n\n.jhs-read-btn.is-popping,\n.jhs-fav-btn.is-popping,\n.jhs-block-btn.is-popping {\n    animation: jhs-star-pop 0.3s ease;\n}\n\n.jhs-rating-bar.is-busy {\n    pointer-events: none;\n    opacity: 0.6;\n}\n\n/* 详情页清单面板(位于 #otherSiteBox 下方) */\n.jhs-list-panel {\n    --jhs-list-accent: #3273dc;\n    --jhs-list-border: #dfe4ea;\n    --jhs-list-muted: #5f6b7a;\n    --jhs-list-surface: #fff;\n    --jhs-list-subtle: #f6f8fa;\n\n    display: block;\n    margin: 10px 0 0;\n    padding: 0;\n    background: var(--jhs-list-surface);\n    border: 1px solid var(--jhs-list-border);\n    border-radius: 10px;\n    color: #2f3540;\n}\n\n.jhs-list-panel__header {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    gap: 10px;\n    min-height: 48px;\n    padding: 8px 10px;\n    border-bottom: 1px solid #edf0f3;\n}\n\n.jhs-list-panel__heading {\n    display: flex;\n    min-width: 0;\n    flex-direction: column;\n    gap: 1px;\n}\n\n.jhs-list-panel__title {\n    margin: 0;\n    color: #2f3540;\n    font-size: 14px;\n    font-weight: 700;\n    line-height: 1.3;\n}\n\n.jhs-list-panel__summary {\n    color: var(--jhs-list-muted);\n    font-size: 12px;\n    line-height: 1.3;\n}\n\n.jhs-list-panel__summary.is-error {\n    color: #a32626;\n    font-weight: 600;\n}\n\n.jhs-list-panel__sort {\n    display: inline-flex;\n    flex-shrink: 0;\n    align-items: center;\n    gap: 5px;\n    color: var(--jhs-list-muted);\n    font-size: 12px;\n    font-weight: 600;\n}\n\n.jhs-list-panel__sort-select {\n    height: 32px;\n    padding: 0 8px;\n    border: 1px solid #cbd2da;\n    border-radius: 6px;\n    background: #fff;\n    color: #3d4652;\n    cursor: pointer;\n    font-size: 12px;\n    font-weight: 600;\n}\n\n.jhs-list-panel__sort-select:hover:not(:disabled) {\n    border-color: #9aa6b2;\n}\n\n.jhs-list-panel__sort-select:disabled {\n    cursor: wait;\n    opacity: 0.58;\n}\n\n.jhs-list-panel__search-wrap {\n    position: relative;\n    display: flex;\n    align-items: center;\n    margin: 10px;\n}\n\n.jhs-list-panel__search-icon {\n    position: absolute;\n    left: 10px;\n    color: #6b7683;\n    font-size: 15px;\n    line-height: 1;\n    pointer-events: none;\n}\n\n.jhs-list-panel__search {\n    width: 100%;\n    height: 34px;\n    padding: 6px 32px 6px 30px;\n    border: 1px solid #cbd2da;\n    border-radius: 7px;\n    background: #fff;\n    color: #2f3540;\n    font-size: 13px;\n    outline: none;\n    transition:\n        border-color 0.15s ease,\n        box-shadow 0.15s ease;\n}\n\n.jhs-list-panel__search::placeholder {\n    color: #667281;\n}\n\n.jhs-list-panel__search::-webkit-search-cancel-button {\n    display: none;\n}\n\n.jhs-list-panel__search:focus-visible,\n.jhs-list-panel__sort-select:focus-visible {\n    border-color: var(--jhs-list-accent);\n    box-shadow: 0 0 0 2px rgb(50, 115, 220, 0.2);\n    outline: none;\n}\n\n.jhs-list-panel__search:disabled {\n    cursor: wait;\n    opacity: 0.58;\n}\n\n.jhs-list-panel__search-clear {\n    position: absolute;\n    right: 5px;\n    display: inline-flex;\n    width: 26px;\n    height: 26px;\n    align-items: center;\n    justify-content: center;\n    padding: 0;\n    border: 0;\n    border-radius: 50%;\n    background: transparent;\n    color: #596574;\n    cursor: pointer;\n    font-size: 18px;\n    line-height: 1;\n}\n\n.jhs-list-panel__search-clear[hidden] {\n    display: none !important;\n}\n\n.jhs-list-panel__search-clear:hover {\n    background: #e9edf2;\n    color: #27313c;\n}\n\n.jhs-list-panel__search-clear:focus-visible,\n.jhs-list-panel__retry:focus-visible {\n    outline: 2px solid var(--jhs-list-accent);\n    outline-offset: 2px;\n}\n\n.jhs-list-panel__items {\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr));\n    gap: 6px;\n    max-height: 320px;\n    padding: 0 10px 10px;\n    overflow-y: auto;\n    overscroll-behavior-y: auto;\n}\n\n.jhs-list-panel .jhs-list-item {\n    min-width: 0;\n    margin: 0;\n}\n\n.jhs-list-panel .jhs-list-item[hidden] {\n    display: none !important;\n}\n\n.jhs-list-panel .jhs-list-item__label {\n    display: grid;\n    grid-template-columns: auto minmax(0, 1fr) auto;\n    min-height: 40px;\n    align-items: center;\n    gap: 7px;\n    padding: 6px 8px;\n    border: 1px solid #e0e5eb;\n    border-radius: 8px;\n    background: #fff;\n    color: #3d4652;\n    cursor: pointer;\n    font-size: 13px;\n    line-height: 1.25;\n    transition:\n        border-color 0.15s ease,\n        background-color 0.15s ease,\n        color 0.15s ease;\n}\n\n.jhs-list-panel .jhs-list-item__label:hover {\n    border-color: #aeb8c3;\n    background: #f8fafc;\n}\n\n.jhs-list-panel .jhs-list-item__label:focus-within {\n    border-color: var(--jhs-list-accent);\n    box-shadow: 0 0 0 2px rgb(50, 115, 220, 0.18);\n}\n\n.jhs-list-panel .jhs-list-item:has(input:checked) .jhs-list-item__label {\n    border-color: var(--jhs-list-accent);\n    background: #eef4ff;\n    color: #234f96;\n}\n\n.jhs-list-panel .jhs-list-item:has(input:disabled) .jhs-list-item__label {\n    border-color: #e1e5ea;\n    background: #f7f8fa;\n    color: #65707d;\n    cursor: not-allowed;\n}\n\n.jhs-list-panel\n    .jhs-list-item:has(input[data-vlt-was-disabled])\n    .jhs-list-item__label {\n    border-color: #eadba7;\n    background: #fffdf5;\n    cursor: wait;\n}\n\n.jhs-list-panel .jhs-list-item__label input[type='checkbox'] {\n    width: 16px;\n    height: 16px;\n    margin: 0;\n    accent-color: var(--jhs-list-accent);\n}\n\n.jhs-list-item__name {\n    display: -webkit-box;\n    min-width: 0;\n    max-height: 2.5em;\n    overflow: hidden;\n    font-weight: 600;\n    overflow-wrap: anywhere;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 2;\n    white-space: normal;\n}\n\n.jhs-list-item__count {\n    min-width: 24px;\n    padding: 2px 6px;\n    border-radius: 50rem;\n    background: #edf0f4;\n    color: #4d5967;\n    font-size: 11px;\n    font-variant-numeric: tabular-nums;\n    font-weight: 700;\n    text-align: center;\n}\n\n.jhs-list-panel .jhs-list-item:has(input:checked) .jhs-list-item__count {\n    background: #d9e7ff;\n    color: #234f96;\n}\n\n.jhs-list-item__status {\n    display: inline-flex;\n    min-width: 32px;\n    align-items: center;\n    justify-content: center;\n    padding: 2px 5px;\n    border-radius: 50rem;\n    background: #edf0f4;\n    color: #596574;\n    font-size: 10px;\n    font-weight: 700;\n    white-space: nowrap;\n}\n\n.jhs-list-item__status[hidden] {\n    display: none !important;\n}\n\n.jhs-list-item__status[data-state='busy'] {\n    background: #fff3cd;\n    color: #725500;\n}\n\n.jhs-list-item__status[data-state='full'],\n.jhs-list-item__status[data-state='unavailable'] {\n    background: #f8e2e2;\n    color: #8d2929;\n}\n\n.jhs-list-panel .jhs-list-item:has(.jhs-list-item__status:not([hidden])) .jhs-list-item__count {\n    display: none;\n}\n\n.jhs-list-panel__empty {\n    margin: 0;\n    padding: 4px 12px 14px;\n    color: var(--jhs-list-muted);\n    font-size: 12px;\n    line-height: 1.45;\n    text-align: center;\n}\n\n.jhs-list-panel__skeleton {\n    height: 40px;\n    border-radius: 8px;\n    background: linear-gradient(90deg, #edf0f3 25%, #f7f8fa 50%, #edf0f3 75%);\n    background-size: 200% 100%;\n    animation: jhs-list-skeleton 1.1s ease-in-out infinite;\n}\n\n@keyframes jhs-list-skeleton {\n    from {\n        background-position: 100% 0;\n    }\n\n    to {\n        background-position: -100% 0;\n    }\n}\n\n.jhs-list-panel__error {\n    grid-column: 1 / -1;\n    display: flex;\n    min-height: 56px;\n    align-items: center;\n    justify-content: center;\n    gap: 8px;\n    color: #a32626;\n    font-size: 12px;\n    text-align: center;\n}\n\n.jhs-list-panel__retry {\n    padding: 5px 9px;\n    border: 1px solid #c5ccd5;\n    border-radius: 6px;\n    background: #fff;\n    color: #344252;\n    cursor: pointer;\n    font-size: 12px;\n    font-weight: 600;\n}\n\n.jhs-list-panel__retry:hover {\n    border-color: #8e9aa7;\n    background: #f6f8fa;\n}\n\n@media (width <= 768px) {\n    .jhs-list-panel__header {\n        align-items: flex-start;\n        flex-wrap: wrap;\n    }\n\n    .jhs-list-panel__sort {\n        margin-left: auto;\n    }\n\n    .jhs-list-panel__sort-select,\n    .jhs-list-panel__search {\n        height: 44px;\n    }\n\n    .jhs-list-panel__search {\n        padding-right: 48px;\n    }\n\n    .jhs-list-panel__search-clear {\n        right: 0;\n        width: 44px;\n        height: 44px;\n    }\n\n    .jhs-list-panel__items {\n        grid-template-columns: 1fr;\n        max-height: none;\n        overflow: visible;\n    }\n\n    .jhs-list-panel .jhs-list-item__label,\n    .jhs-list-panel__skeleton {\n        min-height: 44px;\n    }\n\n    .jhs-list-panel__retry {\n        min-width: 44px;\n        min-height: 44px;\n    }\n}\n\n@media (prefers-reduced-motion: reduce) {\n    .jhs-list-panel *,\n    .jhs-list-panel *::before,\n    .jhs-list-panel *::after {\n        scroll-behavior: auto !important;\n        animation-duration: 0.01ms !important;\n        animation-iteration-count: 1 !important;\n        transition-duration: 0.01ms !important;\n    }\n}\n\n/* 隐藏详情页菜单按钮组的状态行(屏蔽/收藏/已观看)\n   快捷评分条(星星+已读+收藏)已覆盖这三个功能,拉黑待第二步移入评分条\n   DOM 保留:createMenuBtn 的事件绑定 + showStatus 文案更新仍可运行 */\n.jhs-menu-status-row {\n    display: none !important;\n}\n";
	var LOG_PREFIX$6 = "[JavDB]";
	var PENDING_SYNC_PREFIX = "jdb:vlt-pending-server-sync:";
	function getSeries$1(d) {
		if (!d) return d;
		const i = d.indexOf("-");
		return i > 0 ? d.slice(0, i) : d;
	}
	function getCode$2(d) {
		if (!d) return null;
		const i = d.indexOf("-");
		return i > 0 ? d.slice(i + 1) : null;
	}
	function getScore$1() {
		const spans = document.querySelectorAll("nav span");
		const found = Array.from(spans).find((s) => s.textContent?.trim().endsWith("人評價"));
		if (!found) return 0;
		const m = found.innerHTML.match(/(\d+\.\d+)/);
		return m ? parseFloat(m[1]) : 0;
	}
	var _cachedScore;
	function getScoreCached() {
		if (_cachedScore === void 0) _cachedScore = getScore$1();
		return _cachedScore;
	}
	function getMovieInfo(videoId) {
		const detail = document.querySelector(".video-detail");
		if (!detail) {
			console.warn(`${LOG_PREFIX$6} 未找到 .video-detail,跳过`);
			return null;
		}
		const desEl = detail.querySelector(".panel-block.first-block a[data-clipboard-text]");
		if (!desEl) {
			console.warn(`${LOG_PREFIX$6} 未找到番号元素,跳过`);
			return null;
		}
		const designation = desEl.dataset.clipboardText || "";
		if (!designation) {
			console.warn(`${LOG_PREFIX$6} 番号为空,跳过`);
			return null;
		}
		const href = "https://javdb.com/v/" + videoId;
		const titleEl = detail.querySelector("strong.current-title");
		const title = titleEl ? titleEl.innerHTML : "";
		const dateEl = detail.querySelector(".video-meta-panel nav > div:nth-child(2) > span");
		const release_date = dateEl ? dateEl.innerHTML : "";
		const coverEl = detail.querySelector(".column-video-cover img");
		return {
			designation,
			info: {
				href,
				title,
				release_date,
				cover_src: coverEl ? coverEl.src : "",
				score: getScoreCached(),
				series: getSeries$1(designation),
				code: getCode$2(designation) || ""
			}
		};
	}
	function extractListNameFromInput(input) {
		const label = input.closest("label");
		if (!label) return "";
		const clone = label.cloneNode(true);
		clone.querySelector("input")?.remove();
		(clone.querySelector(".jhs-list-item__count") || clone.querySelector("span"))?.remove();
		return (clone.textContent || "").replace(/\s+/g, " ").trim();
	}
	function getListName(listId) {
		const modalInputs = Array.from(document.querySelectorAll("#modal-save-list input[data-list-id]"));
		const panelInputs = Array.from(document.querySelectorAll(".jhs-list-panel input[data-list-id]"));
		const input = modalInputs.find((item) => item.dataset.listId === listId) || panelInputs.find((item) => item.dataset.listId === listId) || null;
		if (!input) return "";
		return extractListNameFromInput(input);
	}
	function getListInfo(listId) {
		return {
			list_id: listId,
			info: {
				url: "https://javdb.com/lists/" + listId + "?locale=zh",
				name: getListName(listId)
			}
		};
	}
	function normalizeListName(value) {
		return value.normalize("NFKC").replace(/\s+/g, " ").trim();
	}
	function extractListIdFromHref(href) {
		const m = href.match(/[?&]id=([^&]+)/);
		return m ? m[1] : null;
	}
	function getCsrfToken$1() {
		return document.querySelector("meta[name=\"csrf-token\"]")?.content || "";
	}
	function getCurrentListContainer() {
		return document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
	}
	function getCheckboxCount(input) {
		const label = input.closest("label");
		const match = ((label?.querySelector(".jhs-list-item__count") || label?.querySelector("span"))?.textContent || "").match(/\d+/);
		if (!match) return null;
		const count = Number(match[0]);
		return Number.isSafeInteger(count) ? count : null;
	}
	function matchingListCheckboxes(listId) {
		return Array.from(document.querySelectorAll("#modal-save-list input[type=\"checkbox\"][data-list-id], .jhs-list-panel input[type=\"checkbox\"][data-list-id]")).filter((input) => input.dataset.listId === listId);
	}
	function setListCheckboxState(listId, checked) {
		for (const input of matchingListCheckboxes(listId)) input.checked = checked;
	}
	function setListCheckboxBusy(listId, busy) {
		const panel = document.querySelector(".jhs-list-panel");
		const activeElement = document.activeElement;
		if (busy && panel && activeElement instanceof HTMLInputElement && panel.contains(activeElement) && activeElement.dataset.listId === listId) panel.__jhsPendingFocusListId = listId;
		for (const input of matchingListCheckboxes(listId)) if (busy) {
			if (input.dataset.vltWasDisabled === void 0) input.dataset.vltWasDisabled = input.disabled ? "1" : "0";
			input.disabled = true;
			input.setAttribute("aria-busy", "true");
		} else {
			if (input.dataset.vltWasDisabled === void 0) continue;
			input.disabled = input.dataset.vltWasDisabled === "1";
			delete input.dataset.vltWasDisabled;
			input.removeAttribute("aria-busy");
		}
		if (!busy && panel?.__jhsPendingFocusListId === listId) {
			delete panel.__jhsPendingFocusListId;
			requestAnimationFrame(() => {
				const currentActive = document.activeElement;
				if (!(!currentActive || currentActive === document.body || currentActive instanceof HTMLInputElement && currentActive.dataset.listId === listId)) return;
				Array.from(panel.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).find((input) => input.dataset.listId === listId && !input.disabled)?.focus({ preventScroll: true });
			});
		}
	}
	function setListDisplayedCount(listId, count) {
		for (const input of matchingListCheckboxes(listId)) {
			const label = input.closest("label");
			const span = label?.querySelector(".jhs-list-item__count") || label?.querySelector("span");
			if (!span) continue;
			if (span.classList.contains("jhs-list-item__count")) {
				span.textContent = String(count);
				span.setAttribute("title", `清单内 ${count} 部影片`);
				span.setAttribute("aria-label", `${count} 部影片`);
			} else span.textContent = `(${count})`;
		}
	}
	function getActressNames() {
		try {
			return $(".female").prev().map((_index, el) => $(el).text()).get().join(" ").trim();
		} catch {
			return "";
		}
	}
	function triggerJavdbWantAndSyncRatingBar(carNum) {
		try {
			const detailPlugin = pluginManager?.getBean?.("DetailPageButtonPlugin");
			if (!detailPlugin) {
				console.warn(`${LOG_PREFIX$6} DetailPageButtonPlugin 未注册,跳过星标评分联动`);
				return;
			}
			detailPlugin._reviewChain = (detailPlugin._reviewChain || Promise.resolve()).then(async () => {
				detailPlugin._wantWatchedSyncing = true;
				try {
					await detailPlugin._triggerJavdbWant();
					detailPlugin._syncRatingBar();
				} finally {
					detailPlugin._wantWatchedSyncing = false;
				}
			}).catch(() => {});
		} catch (err) {
			clog.error(`${LOG_PREFIX$6} 星标评分联动失败: ${carNum}`, err);
		}
	}
	function refreshListPanel() {
		const panel = document.querySelector(".jhs-list-panel");
		if (!panel) return;
		if (panel.__jhsRefresh) {
			panel.__jhsRefresh();
			return;
		}
		const lc = document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
		if (!lc) return;
		const items = panel.querySelector(".jhs-list-panel__items") || panel;
		items.innerHTML = "";
		Array.from(lc.children).forEach((child) => {
			if (/[预預][设設]清[单單]/.test(child.textContent)) return;
			items.appendChild(child.cloneNode(true));
		});
	}
	var LOG_PREFIX$5 = "[JavDB]";
	var LAST_SYNC_KEY$1 = "jdb:last-sync";
	var WANT_WATCHED_SYNC_KEY = "jdb:want-watched-sync";
	var LIST_MGMT_KEY$1 = "jdb:list-mgmt";
	function broadcastWantWatchedSync(carNum, status, op) {
		try {
			broadcastSend(WANT_WATCHED_SYNC_KEY, {
				carNum,
				status,
				op,
				time: Date.now()
			}, { onError: () => {} });
		} catch (err) {
			clog.error(`${LOG_PREFIX$5} 自动收藏广播失败`, err);
		}
	}
	function broadcastSyncComplete(designation, action, association) {
		broadcastSend(LAST_SYNC_KEY$1, {
			designation,
			action,
			association,
			time: Date.now()
		}, {
			eventName: "jdb:sync-complete",
			onError: (channel, error) => {
				console.warn(`${LOG_PREFIX$5} ${channel === "gm" ? "GM 同步广播失败" : channel === "localStorage" ? "localStorage 同步广播失败" : "页面同步广播失败"}`, error);
			}
		});
	}
	function broadcastListMgmt(type, listId, extra) {
		broadcastSend(LIST_MGMT_KEY$1, {
			type,
			listId,
			newName: extra?.newName,
			time: Date.now()
		}, { onError: () => {} });
	}
	var LOG_PREFIX$4 = "[JavDB][清单对账]";
	var MAX_PAGES$1 = 100;
	var AUTO_RECONCILE_DELAY = 350;
	var reconcileQueues = new Map();
	var automaticReconciliationInstalled = false;
	var automaticReconciliationInstalling = false;
	var automaticReconciliationTimer = null;
	var automaticReconciliationRunning = false;
	function normalizeText(value) {
		return (value || "").replace(/\s+/g, " ").trim();
	}
	function getSeries(designation) {
		const index = designation.indexOf("-");
		return index > 0 ? designation.slice(0, index) : designation || null;
	}
	function getCode$1(designation) {
		const index = designation.indexOf("-");
		return index > 0 ? designation.slice(index + 1) : null;
	}
	function getDisplayedListCount(input) {
		const label = input.closest("label");
		const match = (label?.querySelector("span")?.textContent || label?.textContent || "").match(/\((\d+)\)/);
		if (!match) return null;
		const count = Number(match[1]);
		return Number.isSafeInteger(count) ? count : null;
	}
	function getDisplayedListName(input) {
		return normalizeText(input.closest("label")?.textContent).replace(/\s*\(\d+\).*$/, "").trim();
	}
	async function fetchHtmlDocument(url) {
		let response = null;
		for (let attempt = 0; attempt < 3; attempt++) {
			response = await fetch(url, {
				method: "GET",
				credentials: "same-origin",
				cache: "no-store",
				headers: { Accept: "text/html,application/xhtml+xml" }
			});
			if (response.ok) break;
			if (![
				429,
				502,
				503,
				504
			].includes(response.status) || attempt === 2) throw new Error(`清单页面请求失败:HTTP ${response.status}`);
			await new Promise((resolve) => setTimeout(resolve, 400 * (attempt + 1)));
		}
		if (!response?.ok) throw new Error("清单页面请求失败");
		const html = await response.text();
		const documentNode = new DOMParser().parseFromString(html, "text/html");
		const title = normalizeText(documentNode.title).toLowerCase();
		if (!documentNode.body || title.includes("cloudflare") || title.includes("just a moment") || documentNode.querySelector("form[action*=\"sign_in\"]")) throw new Error("清单页面被登录页或人机验证页替代");
		return documentNode;
	}
	function parseExpectedCountAndName(documentNode) {
		const headings = Array.from(documentNode.querySelectorAll("h1, h2, h3, .title"));
		for (const heading of headings) {
			const match = normalizeText(heading.textContent).match(/^(.*?)\s+(\d+)\s*部影片/);
			if (!match) continue;
			return {
				name: match[1].trim(),
				expectedCount: Number(match[2])
			};
		}
		throw new Error("无法从清单标题读取服务端影片总数");
	}
	function parseMovie(item, pageUrl) {
		const link = item.querySelector("a[href*=\"/v/\"]");
		const designation = normalizeText(item.querySelector(".video-title strong")?.textContent);
		const hrefValue = link?.getAttribute("href") || "";
		if (!designation || !hrefValue) throw new Error("清单分页中存在无法识别的影片卡片");
		const titleText = normalizeText(item.querySelector(".video-title")?.textContent);
		const title = titleText.startsWith(designation) ? titleText.slice(designation.length).trim() : titleText;
		const image = item.querySelector("img");
		const coverValue = image?.getAttribute("src") || image?.getAttribute("data-src") || image?.currentSrc || "";
		const scoreMatch = normalizeText(item.querySelector(".score")?.textContent).match(/(\d+(?:\.\d+)?)/);
		const releaseDate = normalizeText(item.querySelector(".meta")?.textContent);
		return {
			designation,
			href: new URL(hrefValue, pageUrl).href,
			title: title || null,
			coverSrc: coverValue ? new URL(coverValue, pageUrl).href : null,
			score: scoreMatch ? Number(scoreMatch[1]) : null,
			releaseDate: releaseDate || null,
			createdAt: null,
			series: getSeries(designation),
			code: getCode$1(designation)
		};
	}
	function parseListPage(documentNode, pageUrl, listId, firstPage) {
		const heading = firstPage ? parseExpectedCountAndName(documentNode) : null;
		const movies = Array.from(documentNode.querySelectorAll(".movie-list .item")).map((item) => parseMovie(item, pageUrl));
		const nextHref = documentNode.querySelector("a.pagination-next")?.getAttribute("href");
		let nextUrl = null;
		if (nextHref) {
			const candidate = new URL(nextHref, pageUrl);
			const expectedPath = `/lists/${encodeURIComponent(listId)}`;
			if (candidate.origin !== window.location.origin || candidate.pathname !== expectedPath) throw new Error(`清单下一页地址异常:${candidate.href}`);
			nextUrl = candidate.href;
		}
		return {
			expectedCount: heading?.expectedCount ?? null,
			name: heading?.name ?? null,
			movies,
			nextUrl
		};
	}
	async function fetchCompleteListPass(listId) {
		const firstUrl = new URL(`/lists/${encodeURIComponent(listId)}`, window.location.origin);
		firstUrl.searchParams.set("locale", "zh");
		const visited = new Set();
		const movies = [];
		let expectedCount = null;
		let name = null;
		let nextUrl = firstUrl.href;
		while (nextUrl) {
			if (visited.size >= MAX_PAGES$1) throw new Error(`清单分页超过 ${MAX_PAGES$1} 页,已中止`);
			const normalizedUrl = new URL(nextUrl).href;
			if (visited.has(normalizedUrl)) throw new Error("清单分页出现循环,已中止");
			visited.add(normalizedUrl);
			const parsed = parseListPage(await fetchHtmlDocument(normalizedUrl), normalizedUrl, listId, visited.size === 1);
			if (visited.size === 1) {
				expectedCount = parsed.expectedCount;
				name = parsed.name;
			}
			movies.push(...parsed.movies);
			nextUrl = parsed.nextUrl;
		}
		if (expectedCount === null || name === null) throw new Error("清单首页信息不完整");
		const uniqueDesignations = new Set(movies.map((movie) => movie.designation));
		if (movies.length !== expectedCount || uniqueDesignations.size !== expectedCount) throw new Error(`清单分页不完整或含重复番号:服务端 ${expectedCount},抓取 ${movies.length},唯一 ${uniqueDesignations.size}`);
		return {
			listId,
			name,
			url: firstUrl.href,
			expectedCount,
			movies
		};
	}
	async function fetchCompleteListSnapshot(listId) {
		const first = await fetchCompleteListPass(listId);
		await new Promise((resolve) => setTimeout(resolve, 250));
		const second = await fetchCompleteListPass(listId);
		const firstSequence = first.movies.map((movie) => movie.designation).join("");
		const secondSequence = second.movies.map((movie) => movie.designation).join("");
		if (first.expectedCount !== second.expectedCount || first.name !== second.name || firstSequence !== secondSequence) throw new Error("清单在两次完整抓取之间发生变化,已放弃本次快照");
		return second;
	}
	function snapshotMatchesExpectation(snapshot, expectation) {
		if (expectation.expectedCount !== void 0 && snapshot.expectedCount !== expectation.expectedCount) return false;
		if (expectation.designation !== void 0 && expectation.checked !== void 0) return snapshot.movies.some((movie) => movie.designation === expectation.designation) === expectation.checked;
		return true;
	}
	async function performReconciliation(listId, expectation) {
		try {
			for (let attempt = 0; attempt < 2; attempt++) {
				const state = await VltDb.getListReconcileState(listId);
				const snapshot = await fetchCompleteListSnapshot(listId);
				if (!snapshotMatchesExpectation(snapshot, expectation)) throw new Error("服务端清单状态已变化,与触发对账时的状态不一致");
				const result = await VltDb.reconcileListSnapshot(snapshot, state.guard);
				if (result.status === "conflict") {
					console.warn(`${LOG_PREFIX$4} 本地数据在抓取期间变化,准备重试 listId=${listId}`);
					continue;
				}
				console.log(`${LOG_PREFIX$4} 完成 listId=${listId} count=${result.count} added=${result.added} removed=${result.removed}`);
				if (!expectation.quiet && (result.added > 0 || result.removed > 0)) showToast$1(`✓ 已按 JavDB 校准「${snapshot.name}」:新增 ${result.added},移除 ${result.removed}`, "success");
				return true;
			}
			throw new Error("本地清单持续变化,两次对账均发生冲突");
		} catch (error) {
			clog.error(`${LOG_PREFIX$4} 失败 listId=${listId}`, error);
			if (!expectation.quiet) showToast$1(`⚠ 清单自动校准失败:${error instanceof Error ? error.message : String(error)}`, "warning");
			return false;
		}
	}
	function reconcileListWithJavdb(listId, expectation = {}) {
		const current = (reconcileQueues.get(listId) || Promise.resolve(true)).catch(() => false).then(() => performReconciliation(listId, expectation));
		reconcileQueues.set(listId, current);
		current.finally(() => {
			if (reconcileQueues.get(listId) === current) reconcileQueues.delete(listId);
		});
		return current;
	}
	async function reconcileListBeforeMutation(input, designation, checkedBeforeMutation) {
		const listId = input.dataset.listId || "";
		const serverCount = getDisplayedListCount(input);
		if (!listId || serverCount === null) return;
		const state = await VltDb.getListReconcileState(listId, designation);
		if (!state.inventory) return;
		if (state.actualCount === serverCount && state.hasDesignation === checkedBeforeMutation) return;
		console.warn(`${LOG_PREFIX$4} 检测到差异 listId=${listId} local=${state.actualCount} server=${serverCount} localChecked=${state.hasDesignation} serverChecked=${checkedBeforeMutation}`);
		await reconcileListWithJavdb(listId, {
			expectedCount: serverCount,
			designation,
			checked: checkedBeforeMutation,
			quiet: false
		});
	}
	function reconcileAfterConfirmedMutation(listId, designation, checked) {
		return reconcileListWithJavdb(listId, {
			designation,
			checked,
			quiet: false
		});
	}
	async function runAutomaticReconciliation(designation) {
		if (automaticReconciliationRunning) return;
		automaticReconciliationRunning = true;
		try {
			const inputs = Array.from(document.querySelectorAll("#modal-save-list input[type=\"checkbox\"][data-list-id][data-action=\"change->list#listCheckboxChanged\"]"));
			for (const input of inputs) {
				const listId = input.dataset.listId || "";
				const serverCount = getDisplayedListCount(input);
				if (!listId || serverCount === null) continue;
				const state = await VltDb.getListReconcileState(listId, designation);
				if (!state.inventory) continue;
				if (state.actualCount === serverCount && state.hasDesignation === input.checked) continue;
				console.warn(`${LOG_PREFIX$4} 页面加载发现差异「${getDisplayedListName(input)}」 local=${state.actualCount} server=${serverCount}`);
				await reconcileListWithJavdb(listId, {
					expectedCount: serverCount,
					designation,
					checked: input.checked,
					quiet: false
				});
			}
		} finally {
			automaticReconciliationRunning = false;
		}
	}
	function setupAutomaticListReconciliation(designation) {
		if (automaticReconciliationInstalled || automaticReconciliationInstalling) return;
		automaticReconciliationInstalling = true;
		const schedule = () => {
			if (automaticReconciliationTimer) clearTimeout(automaticReconciliationTimer);
			automaticReconciliationTimer = setTimeout(() => {
				automaticReconciliationTimer = null;
				runAutomaticReconciliation(designation).then();
			}, AUTO_RECONCILE_DELAY);
		};
		const attach = () => {
			const modal = document.querySelector("#modal-save-list");
			if (!modal) {
				setTimeout(attach, 250);
				return;
			}
			automaticReconciliationInstalling = false;
			automaticReconciliationInstalled = true;
			new MutationObserver(schedule).observe(modal, {
				childList: true,
				subtree: true
			});
			schedule();
		};
		attach();
	}
	var queue = new KeyedQueue();
	var LOCK_PREFIX = "javdb-power-tools:vlt:";
	function enqueueAssociationTask(key, task) {
		return queue.enqueue(key, () => withExclusiveLock(LOCK_PREFIX + key, task));
	}
	var SIMPLE_LISTS_PAGE_TIMEOUT_MS = 1e4;
	async function fetchSimpleListsPage(url, vid) {
		const controller = new AbortController();
		const timeout = window.setTimeout(() => controller.abort(), SIMPLE_LISTS_PAGE_TIMEOUT_MS);
		try {
			const response = await fetch(url, {
				credentials: "same-origin",
				cache: "no-store",
				headers: { Accept: "application/json" },
				signal: controller.signal
			});
			if (!response.ok) throw new Error(`清单分页请求失败:HTTP ${response.status}`);
			const payload = await response.json();
			if (typeof payload.lists !== "string") throw new Error("清单分页响应格式异常");
			const pageHtml = typeof payload.page === "string" ? payload.page : "";
			const nextHref = new DOMParser().parseFromString(pageHtml, "text/html").querySelector("a[rel=\"next\"]")?.getAttribute("href");
			if (!nextHref) return {
				entries: payload.lists,
				nextUrl: null
			};
			const nextUrl = new URL(nextHref, url);
			if (nextUrl.origin !== window.location.origin || nextUrl.pathname !== "/users/simple_lists") throw new Error("清单下一页地址异常");
			if (vid) nextUrl.searchParams.set("vid", vid);
			return {
				entries: payload.lists,
				nextUrl: nextUrl.href
			};
		} finally {
			window.clearTimeout(timeout);
		}
	}
	function createPendingJournal(entry) {
		try {
			const randomPart = typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `${Math.random().toString(36).slice(2)}-${Date.now()}`;
			const key = `${PENDING_SYNC_PREFIX}${entry.createdAt}:${randomPart}`;
			localStorage.setItem(key, JSON.stringify(entry));
			return key;
		} catch (error) {
			clog.error(`${LOG_PREFIX$6} 无法写入清单同步恢复日志`, error);
			return null;
		}
	}
	function removePendingJournal(key) {
		if (!key) return;
		try {
			localStorage.removeItem(key);
		} catch {}
	}
	function readPendingJournals() {
		const keys = [];
		try {
			for (let index = 0; index < localStorage.length; index++) {
				const key = localStorage.key(index);
				if (key?.startsWith("jdb:vlt-pending-server-sync:")) keys.push(key);
			}
		} catch {
			return [];
		}
		const entries = [];
		for (const key of keys) try {
			const value = localStorage.getItem(key);
			if (!value) continue;
			const entry = JSON.parse(value);
			if (entry.version !== 1 || !entry.videoId || !entry.movieInfo?.designation || !entry.listInfo?.list_id || typeof entry.desiredChecked !== "boolean" || typeof entry.createdAt !== "number") {
				removePendingJournal(key);
				continue;
			}
			entries.push({
				key,
				entry
			});
		} catch {
			removePendingJournal(key);
		}
		return entries.sort((left, right) => left.entry.createdAt - right.entry.createdAt);
	}
	async function postJavdbListMutation(videoId, listId, checked) {
		const csrfToken = getCsrfToken$1();
		if (!csrfToken) return {
			kind: "rejected",
			message: "无法获取 CSRF token"
		};
		try {
			const response = await fetch(new URL("/users/save_video_to_list", window.location.origin).href, {
				method: "POST",
				body: JSON.stringify({
					video_id: videoId,
					checked,
					list_id: listId
				}),
				headers: {
					"Content-Type": "application/json",
					"X-CSRF-Token": csrfToken
				},
				credentials: "same-origin"
			});
			const data = await response.json().catch(() => null);
			const message = typeof data?.message === "string" ? data.message : `HTTP ${response.status}`;
			if (response.ok && data?.success === true) return {
				kind: "confirmed",
				message
			};
			if (response.ok && data?.success === false) return {
				kind: "rejected",
				message
			};
			return {
				kind: "unknown",
				message
			};
		} catch (error) {
			return {
				kind: "unknown",
				message: error instanceof Error ? error.message : String(error)
			};
		}
	}
	async function fetchAuthoritativeCheckboxState(videoId, listId) {
		try {
			let url = new URL("/users/simple_lists", window.location.origin);
			url.searchParams.set("vid", videoId);
			const visited = new Set();
			for (let page = 0; url && page < 50; page++) {
				if (visited.has(url.href)) return null;
				visited.add(url.href);
				const result = await fetchSimpleListsPage(url.href, videoId);
				const documentNode = new DOMParser().parseFromString(result.entries, "text/html");
				const input = Array.from(documentNode.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).find((item) => item.dataset.listId === listId);
				if (input) return {
					checked: input.checked,
					count: getCheckboxCount(input),
					name: extractListNameFromInput(input) || null
				};
				if (!result.nextUrl) return {
					checked: false,
					count: null,
					name: null
				};
				url = new URL(result.nextUrl);
			}
			return null;
		} catch (error) {
			clog.error(`${LOG_PREFIX$6} 查询 JavDB 权威清单状态失败`, error);
			return null;
		}
	}
	async function commitAuthoritativeState(entry, authoritative, notify) {
		const listInfo = {
			...entry.listInfo,
			info: {
				...entry.listInfo.info,
				name: authoritative.name || entry.listInfo.info.name
			}
		};
		let reconciledBeforeCommit = false;
		if (authoritative.count !== null) {
			const before = await VltDb.getListReconcileState(entry.listInfo.list_id, entry.movieInfo.designation);
			if (before.actualCount + (authoritative.checked && before.hasDesignation === false ? 1 : !authoritative.checked && before.hasDesignation === true ? -1 : 0) !== authoritative.count) {
				reconciledBeforeCommit = await reconcileListWithJavdb(entry.listInfo.list_id, {
					expectedCount: authoritative.count,
					designation: entry.movieInfo.designation,
					checked: authoritative.checked,
					quiet: !notify
				});
				if (!reconciledBeforeCommit) return false;
			}
		}
		if (!await handleCheckboxChange(entry.movieInfo, listInfo, authoritative.checked, {
			serverConfirmed: true,
			silent: !notify || reconciledBeforeCommit,
			skipAutomation: !notify
		})) return false;
		setListCheckboxState(entry.listInfo.list_id, authoritative.checked);
		if (authoritative.count !== null) {
			setListDisplayedCount(entry.listInfo.list_id, authoritative.count);
			const state = await VltDb.getListReconcileState(entry.listInfo.list_id, entry.movieInfo.designation);
			if (state.inventory && (state.actualCount !== authoritative.count || state.hasDesignation !== authoritative.checked)) return reconcileListWithJavdb(entry.listInfo.list_id, {
				expectedCount: authoritative.count,
				designation: entry.movieInfo.designation,
				checked: authoritative.checked,
				quiet: !notify
			});
		}
		return true;
	}
	async function recoverPendingServerSyncs() {
		for (const { key, entry } of readPendingJournals()) await enqueueAssociationTask(`${entry.movieInfo.designation}::${entry.listInfo.list_id}`, async () => {
			const authoritative = await fetchAuthoritativeCheckboxState(entry.videoId, entry.listInfo.list_id);
			if (!authoritative) return;
			if (await commitAuthoritativeState(entry, authoritative, false)) {
				removePendingJournal(key);
				console.log(`${LOG_PREFIX$6} 已恢复未完成清单同步:${entry.movieInfo.designation} ${authoritative.checked ? "add" : "remove"} ${entry.listInfo.list_id}`);
			}
		});
	}
	var checkboxListenerInstalled = false;
	async function performServerCheckboxMutation(movieInfo, listInfo, checked, input, checkedBeforeMutation) {
		const listId = listInfo.list_id;
		let confirmedChecked = null;
		setListCheckboxState(listId, checked);
		setListCheckboxBusy(listId, true);
		try {
			if (input) await reconcileListBeforeMutation(input, movieInfo.designation, checkedBeforeMutation);
			const pending = {
				version: 1,
				videoId: input?.value || movieInfo.info.href.match(/\/v\/([^/?#]+)/)?.[1] || "",
				desiredChecked: checked,
				movieInfo,
				listInfo,
				createdAt: Date.now()
			};
			if (!pending.videoId) throw new Error("无法识别 JavDB 影片 ID");
			const journalKey = createPendingJournal(pending);
			if (!journalKey) throw new Error("无法建立清单同步恢复日志,本次操作已取消");
			const serverResult = await postJavdbListMutation(pending.videoId, listId, checked);
			if (serverResult.kind === "rejected") {
				removePendingJournal(journalKey);
				setListCheckboxState(listId, checkedBeforeMutation);
				showToast$1(`✗ JavDB 清单更新失败:${serverResult.message}`, "error");
				return;
			}
			if (serverResult.kind === "unknown") {
				const observed = await fetchAuthoritativeCheckboxState(pending.videoId, listId);
				setListCheckboxState(listId, observed?.checked ?? checkedBeforeMutation);
				if (observed?.count !== null && observed?.count !== void 0) setListDisplayedCount(listId, observed.count);
				showToast$1(`⚠ 无法确认 JavDB 最终状态(${serverResult.message}),本地未改动;下次打开页面会自动核对`, "warning");
				return;
			}
			confirmedChecked = checked;
			const authoritative = await fetchAuthoritativeCheckboxState(pending.videoId, listId);
			if (authoritative) {
				confirmedChecked = authoritative.checked;
				if (await commitAuthoritativeState(pending, authoritative, true)) removePendingJournal(journalKey);
				else showToast$1("⚠ JavDB 已更新,本地完整清单将在下次打开页面时继续校准", "warning");
				return;
			}
			setListCheckboxState(listId, checked);
			if (await reconcileAfterConfirmedMutation(listId, movieInfo.designation, checked) ? await handleCheckboxChange(movieInfo, listInfo, checked, { serverConfirmed: true }) : null) removePendingJournal(journalKey);
			else showToast$1("⚠ JavDB 已更新,但暂时无法复核最终清单;恢复日志已保留", "warning");
		} catch (error) {
			setListCheckboxState(listId, confirmedChecked === null ? checkedBeforeMutation : confirmedChecked);
			const message = error instanceof Error ? error.message : String(error);
			console.error(`${LOG_PREFIX$6} JavDB 清单同步失败`, error);
			showToast$1(confirmedChecked === null ? `✗ JavDB 清单同步失败:${message}` : `⚠ JavDB 已更新,本地镜像将在下次打开页面时继续恢复:${message}`, confirmedChecked === null ? "error" : "warning");
		} finally {
			setListCheckboxBusy(listId, false);
		}
	}
	function enqueueServerCheckboxMutation(movieInfo, listInfo, checked, input, checkedBeforeMutation) {
		return enqueueAssociationTask(`${movieInfo.designation}::${listInfo.list_id}`, () => performServerCheckboxMutation(movieInfo, listInfo, checked, input, checkedBeforeMutation));
	}
	function setupCheckboxListener() {
		if (checkboxListenerInstalled) return;
		checkboxListenerInstalled = true;
		document.addEventListener("change", (event) => {
			const input = event.target;
			if (input.tagName !== "INPUT" || input.type !== "checkbox" || input.dataset.action !== "change->list#listCheckboxChanged" || !input.closest("#modal-save-list")) return;
			event.preventDefault();
			event.stopImmediatePropagation();
			const checked = input.checked;
			const checkedBeforeMutation = !checked;
			const movieInfo = getMovieInfo(input.value);
			const listInfo = getListInfo(input.dataset.listId || "");
			if (!movieInfo || !listInfo.list_id || !listInfo.info.name) {
				setListCheckboxState(listInfo.list_id, checkedBeforeMutation);
				showToast$1("✗ 无法读取影片或清单信息,本次操作已取消", "error");
				return;
			}
			enqueueServerCheckboxMutation(movieInfo, listInfo, checked, input, checkedBeforeMutation).then();
		}, true);
		const currentVideoId = window.location.pathname.match(/\/v\/([^/?#]+)/)?.[1];
		const currentMovie = currentVideoId ? getMovieInfo(currentVideoId) : null;
		if (currentMovie) setupAutomaticListReconciliation(currentMovie.designation);
		recoverPendingServerSyncs().then();
	}
	var ASSOC_TOAST = {
		created: (des, lname, created) => {
			return {
				msg: `✓ [${des}] 已添加至「${lname}」${created.length > 0 ? `(已登记${created.join("和")})` : ""}`,
				type: "success"
			};
		},
		existed: (des, lname) => ({
			msg: `✓ [${des}] 已在「${lname}」中,数据一致`,
			type: "success"
		}),
		limit_exceeded: (des, lname) => ({
			msg: `✗ [${des}]「${lname}」已达收藏上限(501 条)`,
			type: "error"
		}),
		deleted: (des, lname) => ({
			msg: `✓ [${des}] 已从「${lname}」移除`,
			type: "success"
		}),
		unchanged: (des, lname) => ({
			msg: `✓ [${des}] 未关联「${lname}」,数据一致`,
			type: "success"
		})
	};
	async function syncMoviesLists(movieInfo, listInfo, action, serverConfirmed = false) {
		console.log(`${LOG_PREFIX$6} 同步(IDB): ${movieInfo.designation} → ${listInfo.info.name} (${action})`);
		const result = await VltDb.sync(movieInfo.designation, listInfo.list_id, {
			href: movieInfo.info.href,
			title: movieInfo.info.title,
			cover_src: movieInfo.info.cover_src,
			score: movieInfo.info.score,
			release_date: movieInfo.info.release_date,
			series: movieInfo.info.series,
			code: movieInfo.info.code
		}, {
			url: listInfo.info.url,
			name: listInfo.info.name
		}, action, { serverConfirmed });
		console.log(`${LOG_PREFIX$6} 同步结果: movie=${result.movie} list=${result.list} association=${result.association}`);
		return result;
	}
	async function autoFavoriteIfPendingUpdate(movieInfo, lname) {
		if (!lname.includes("等待更新")) return;
		const des = movieInfo.designation;
		try {
			const carRecord = await storageManager.getCar(des);
			if (carRecord && carRecord.status === "favorite") return;
			if (carRecord && carRecord.status) {
				showToast$1(`ℹ️ [${des}] 已标记为「${carRecord.status}」,跳过自动收藏`, "info");
				return;
			}
			await storageManager.saveCar({
				carNum: des,
				url: movieInfo.info.href,
				names: getActressNames(),
				actionType: FAVORITE_ACTION,
				publishTime: movieInfo.info.release_date
			});
			broadcastWantWatchedSync(des, FAVORITE_ACTION, "add");
			showToast$1(`⭐ [${des}] 已自动收藏(添加至「${lname}」)`, "success");
			console.log(`${LOG_PREFIX$6} 自动收藏: ${des}(触发清单:${lname})`);
			triggerJavdbWantAndSyncRatingBar(des);
		} catch (err) {
			const message = err instanceof Error ? err.message : "未知错误";
			clog.error(`${LOG_PREFIX$6} 自动收藏失败: ${des}`, err);
			showToast$1(`✗ [${des}] 自动收藏失败:${message}`, "error");
		}
	}
	async function handleCheckboxChange(movieInfo, listInfo, checked, options = {}) {
		const des = movieInfo.designation;
		const lname = listInfo.info.name;
		const action = checked ? "add" : "remove";
		console.log(`${LOG_PREFIX$6} ═══ ${checked ? "勾选" : "取消"} [${des}] → ${lname} ═══`);
		let result;
		try {
			result = await syncMoviesLists(movieInfo, listInfo, action, options.serverConfirmed === true);
		} catch (err) {
			const message = err instanceof Error ? err.message : "请检查 IndexedDB";
			clog.error(`${LOG_PREFIX$6} 同步失败`, err);
			if (!options.silent) showToast$1(`✗ [${des}] 同步失败:${message}`, "error");
			return null;
		}
		const created = [];
		if (result.movie === "created") created.push("影片");
		if (result.list === "created") created.push("清单");
		if (!options.silent) {
			const entry = ASSOC_TOAST[result.association];
			if (entry) {
				const { msg, type } = entry(des, lname, created);
				showToast$1(msg, type);
			} else showToast$1(`✗ [${des}] 未知响应:${result.association}`, "error");
		}
		if (checked && !options.skipAutomation && result.association !== "limit_exceeded") {
			autoFavoriteIfPendingUpdate(movieInfo, lname).then();
			if (!lname.includes("等待更新")) uncheckPendingUpdateListCheckboxes();
		}
		console.log(`${LOG_PREFIX$6} ═══ 完成 ═══`);
		broadcastSyncComplete(des, action, result.association);
		return result;
	}
	async function autoRemoveFromPendingUpdateOnWatch() {
		try {
			if (uncheckPendingUpdateListCheckboxes() > 0) return;
			const pending = await findPendingUpdateListsForCurrentMovie();
			if (pending.length === 0) return;
			for (let i = 0; i < 15; i++) {
				await new Promise((r) => setTimeout(r, 200));
				if (uncheckPendingUpdateListCheckboxes() > 0) return;
			}
			for (const item of pending) {
				const movieInfo = getMovieInfo(item.videoId);
				if (!movieInfo) continue;
				await enqueueServerCheckboxMutation(movieInfo, {
					list_id: item.listId,
					info: {
						url: item.url,
						name: item.name
					}
				}, false, null, true);
			}
		} catch (err) {
			clog.error(`${LOG_PREFIX$6} 评分后移出「等待更新」失败`, err);
		}
	}
	function uncheckPendingUpdateListCheckboxes() {
		const inputs = document.querySelectorAll("#modal-save-list input[type=\"checkbox\"][data-action=\"change->list#listCheckboxChanged\"]");
		const seen = new Set();
		let count = 0;
		for (const input of inputs) {
			if (!input.checked) continue;
			const listId = input.dataset.listId || "";
			if (!listId || seen.has(listId)) continue;
			const name = getListName(listId);
			if (!name.includes("等待更新")) continue;
			seen.add(listId);
			count++;
			input.checked = false;
			input.dispatchEvent(new Event("change", { bubbles: true }));
			const panelCb = document.querySelector(`.jhs-list-panel input[data-list-id="${listId}"]`);
			if (panelCb) panelCb.checked = false;
			console.log(`${LOG_PREFIX$6} 评分后取消勾选「${name}」(listId=${listId})`);
		}
		return count;
	}
	async function findPendingUpdateListsForCurrentMovie() {
		const videoId = window.location.pathname.match(/\/v\/([^/?#]+)/)?.[1];
		if (!videoId) return [];
		const movieInfo = getMovieInfo(videoId);
		if (!movieInfo) return [];
		const lists = (await VltDb.queryMoviesLists([movieInfo.designation]))[movieInfo.designation] || [];
		const result = [];
		for (const item of lists) {
			if (!item.name.includes("等待更新")) continue;
			const listId = item.url?.match(/\/lists\/([^/?#]+)/)?.[1];
			if (!listId) continue;
			result.push({
				videoId,
				listId,
				name: item.name,
				url: item.url || `https://javdb.com/lists/${listId}?locale=zh`
			});
		}
		return result;
	}
	async function createList(listName) {
		const modal = document.querySelector("#modal-save-list");
		if (!modal) {
			showToast$1("✗ 未找到存入清单弹窗,请重新进入详情页", "error");
			return "failed";
		}
		const nameInput = modal.querySelector("input[data-list-target=\"listNewNameInput\"]");
		const form = modal.querySelector("#new_list");
		const listContainer = modal.querySelector("[data-list-target=\"listContainer\"]");
		if (!nameInput || !form || !listContainer) {
			showToast$1("✗ 清单新建表单未就绪,请重新进入详情页", "error");
			return "failed";
		}
		const formData = {};
		Array.from(form.querySelectorAll("input, textarea, select")).forEach((el) => {
			const field = el;
			if (field.name && field.type !== "submit" && field.type !== "button" && field.type !== "reset") formData[field.name] = field.value;
		});
		if (nameInput.name) formData[nameInput.name] = listName;
		const csrfToken = document.querySelector("meta[name=\"csrf-token\"]")?.content || formData["authenticity_token"] || "";
		const beforeIds = new Set(Array.from(listContainer.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).map((el) => el.dataset.listId));
		const videoId = formData["video_id"] || form.querySelector("input[name=\"video_id\"]")?.value || "";
		if (!videoId) {
			showToast$1("✗ 无法识别当前影片,清单未新建", "error");
			return "failed";
		}
		showToast$1("正在新建清单…", "info");
		console.log(`${LOG_PREFIX$6} ═══ 新增清单「${listName}」(video_id=${videoId}) ═══`);
		let responseText;
		try {
			responseText = await new Promise((resolve, reject) => {
				GM_xmlhttpRequest({
					method: "POST",
					url: "https://javdb.com/lists/remote_create",
					headers: {
						"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
						Accept: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*;q=0.01",
						"X-CSRF-Token": csrfToken,
						"X-Requested-With": "XMLHttpRequest"
					},
					data: Object.entries(formData).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&"),
					timeout: 15e3,
					onload: (r) => {
						if (r.status >= 200 && r.status < 300) resolve(r.responseText || "");
						else reject(new Error(`HTTP ${r.status}: ${r.responseText?.slice(0, 200) || ""}`));
					},
					onerror: () => reject(new Error("网络错误")),
					ontimeout: () => reject(new Error("请求超时"))
				});
			});
		} catch (err) {
			const message = err instanceof Error ? err.message : "请稍后重试";
			console.error(`${LOG_PREFIX$6} 新增清单失败`, err);
			showToast$1(`✗ 新建清单失败:${message}`, "error");
			return "failed";
		}
		console.log(`${LOG_PREFIX$6} 服务端响应(前 500 字): ${responseText.slice(0, 500)}`);
		if (responseText.trim()) try {
			const script = document.createElement("script");
			script.textContent = responseText;
			(document.body || document.documentElement).appendChild(script);
			script.remove();
			console.log(`${LOG_PREFIX$6} JS 响应已注入执行`);
		} catch (e) {
			console.warn(`${LOG_PREFIX$6} JS 响应注入失败`, e);
		}
		if (/\btoastr\s*(?:\.\s*error|\[\s*['"]error['"]\s*\])\s*\(/i.test(responseText)) {
			showToast$1("✗ JavDB 拒绝新建清单,请检查名称后重试", "error");
			return "failed";
		}
		let newCheckboxes = await pollForNewCheckboxes(modal, beforeIds, 200);
		if (newCheckboxes.length > 0) {
			console.log(`${LOG_PREFIX$6} 侦测到 ${newCheckboxes.length} 个新 checkbox,走正常完成流程`);
			const confirmedCheckbox = await resolveCreatedListCheckbox(newCheckboxes, listName, videoId, beforeIds);
			if (confirmedCheckbox) {
				finishCreateList(confirmedCheckbox, listName);
				return "created";
			}
		}
		const listIdMatch = responseText.match(/data-list-id=["']([^"']+)["']/);
		if (listIdMatch) {
			const listId = listIdMatch[1];
			const confirmedCheckbox = await resolveAuthoritativeCreatedCheckbox(listId, listName, videoId, beforeIds);
			if (confirmedCheckbox) {
				console.log(`${LOG_PREFIX$6} 从响应提取并权威确认 list-id=${listId}`);
				finishCreateList(confirmedCheckbox, listName);
				return "created";
			}
		}
		console.log(`${LOG_PREFIX$6} 响应无 list-id,通过切换 #save-list-button 重载清单列表`);
		const saveListBtn = document.querySelector("#save-list-button");
		if (saveListBtn) {
			saveListBtn.click();
			await new Promise((r) => setTimeout(r, 200));
			saveListBtn.click();
			newCheckboxes = await pollForNewCheckboxes(modal, beforeIds, 5e3);
			if (newCheckboxes.length > 0) {
				console.log(`${LOG_PREFIX$6} 重载后侦测到 ${newCheckboxes.length} 个新 checkbox,走正常完成流程`);
				const confirmedCheckbox = await resolveCreatedListCheckbox(newCheckboxes, listName, videoId, beforeIds);
				if (confirmedCheckbox) {
					finishCreateList(confirmedCheckbox, listName);
					return "created";
				}
			}
		}
		console.log(`${LOG_PREFIX$6} 按钮重载未找到新 checkbox,尝试 /users/lists 作为最后手段`);
		const listId = await fetchListIdByName(listName);
		if (listId) {
			const confirmedCheckbox = await resolveAuthoritativeCreatedCheckbox(listId, listName, videoId, beforeIds);
			if (confirmedCheckbox) {
				console.log(`${LOG_PREFIX$6} 从 /users/lists 查得并权威确认 list_id=${listId}`);
				finishCreateList(confirmedCheckbox, listName);
				return "created";
			}
		}
		console.error(`${LOG_PREFIX$6} 新增清单后无法定位新 checkbox。响应前 300 字: ${responseText.slice(0, 300)}`);
		refreshListPanel();
		showToast$1(`⚠ 清单「${listName}」可能已新建,请刷新页面确认`, "warning");
		return "unknown";
	}
	function pollForNewCheckboxes(modal, beforeIds, timeoutMs) {
		return new Promise((resolve) => {
			const start = Date.now();
			const check = () => {
				const lc = modal.querySelector("[data-list-target=\"listContainer\"]");
				if (lc) {
					const newOnes = Array.from(lc.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).filter((cb) => !beforeIds.has(cb.dataset.listId));
					if (newOnes.length > 0) {
						resolve(newOnes);
						return;
					}
				}
				if (Date.now() - start < timeoutMs) setTimeout(check, 100);
				else resolve([]);
			};
			check();
		});
	}
	function findCurrentListCheckbox(listId) {
		const container = getCurrentListContainer();
		if (!container) return null;
		return Array.from(container.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).find((input) => input.dataset.listId === listId) || null;
	}
	async function resolveAuthoritativeCreatedCheckbox(listId, listName, videoId, beforeIds) {
		if (!listId || !videoId || beforeIds.has(listId)) return null;
		const authoritative = await fetchAuthoritativeCheckboxState(videoId, listId);
		if (!authoritative?.checked || !authoritative.name || normalizeListName(authoritative.name) !== normalizeListName(listName) || authoritative.count !== null && authoritative.count < 1) return null;
		let input = findCurrentListCheckbox(listId);
		if (!input) {
			const container = getCurrentListContainer();
			input = container ? manuallyBuildCheckbox(container, listId, authoritative.name, videoId, authoritative.count ?? 1) : null;
		}
		if (!input) return null;
		input.checked = true;
		if (authoritative.count !== null) setListDisplayedCount(listId, authoritative.count);
		return input;
	}
	async function resolveCreatedListCheckbox(candidates, listName, videoId, beforeIds) {
		const candidateIds = Array.from(new Set(candidates.map((input) => input.dataset.listId).filter(Boolean)));
		const confirmed = [];
		for (const listId of candidateIds) {
			const input = await resolveAuthoritativeCreatedCheckbox(listId, listName, videoId, beforeIds);
			if (input) confirmed.push(input);
		}
		if (confirmed.length === 1) return confirmed[0];
		if (confirmed.length > 1) console.warn(`${LOG_PREFIX$6} 新建清单出现多个权威候选,拒绝写入本地`, candidateIds);
		return null;
	}
	async function fetchListIdByName(listName) {
		try {
			const html = await new Promise((resolve, reject) => {
				GM_xmlhttpRequest({
					method: "GET",
					url: "https://javdb.com/users/lists",
					timeout: 1e4,
					onload: (r) => {
						if (r.status >= 200 && r.status < 300) resolve(r.responseText || "");
						else reject(new Error(`HTTP ${r.status}`));
					},
					onerror: () => reject(new Error("网络错误")),
					ontimeout: () => reject(new Error("请求超时"))
				});
			});
			const doc = new DOMParser().parseFromString(html, "text/html");
			let links = doc.querySelectorAll("a[href*=\"/lists/\"]");
			if (links.length === 0) links = doc.querySelectorAll("[href*=\"/lists/\"]");
			console.log(`${LOG_PREFIX$6} /users/lists 页面解析到 ${links.length} 条 /lists/ 链接`);
			const matchedIds = new Set();
			const expectedName = normalizeListName(listName);
			for (const link of Array.from(links)) {
				const m = (link.getAttribute("href") || "").match(/\/lists\/([^/?#]+)/);
				if (!m) continue;
				const id = m[1];
				if (id === "users" || id === "" || id === "new") continue;
				if (normalizeListName((link.textContent || "").replace(/\s*\(\d+\)\s*$/, "")) === expectedName) matchedIds.add(id);
			}
			if (matchedIds.size === 1) {
				const [id] = matchedIds;
				console.log(`${LOG_PREFIX$6} /users/lists 精确匹配清单「${listName}」→ list_id=${id}`);
				return id;
			}
			if (matchedIds.size > 1) {
				console.warn(`${LOG_PREFIX$6} /users/lists 存在重名清单,拒绝猜测 list-id`, matchedIds);
				return null;
			}
			const bodyText = doc.body?.textContent?.slice(0, 1e3) || "";
			console.warn(`${LOG_PREFIX$6} /users/lists 未精确找到「${listName}」(共 ${links.length} 条链接)。页面文本前 500 字: ${bodyText.slice(0, 500)}`);
			return null;
		} catch (err) {
			console.error(`${LOG_PREFIX$6} 获取 /users/lists 失败`, err);
			return null;
		}
	}
	function manuallyBuildCheckbox(listContainer, listId, listName, videoId, count) {
		const duplicate = Array.from(listContainer.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).find((input) => input.dataset.listId === listId);
		if (duplicate) {
			duplicate.checked = true;
			return duplicate;
		}
		const existingCb = listContainer.querySelector("input[type=\"checkbox\"][data-list-id]");
		if (!existingCb) return null;
		const existingLabel = existingCb.closest("label");
		if (!existingLabel) return null;
		const clone = (existingLabel.closest("p.control") || existingLabel).cloneNode(true);
		const label = clone.matches("label") ? clone : clone.querySelector("label");
		const cb = label?.querySelector("input[type=\"checkbox\"]");
		if (!label || !cb) return null;
		cb.dataset.listId = listId;
		cb.value = videoId;
		cb.checked = true;
		cb.disabled = false;
		cb.removeAttribute("id");
		cb.removeAttribute("disabled");
		delete cb.dataset.vltWasDisabled;
		cb.removeAttribute("aria-busy");
		label.removeAttribute("for");
		for (const node of Array.from(label.childNodes)) if (node.nodeType === Node.TEXT_NODE) node.remove();
		const countSpan = label.querySelector("span");
		const nameNode = document.createTextNode(` ${listName} `);
		if (cb.parentNode === label) label.insertBefore(nameNode, cb.nextSibling);
		else label.appendChild(nameNode);
		if (countSpan) countSpan.textContent = `(${count})`;
		else {
			const createdCount = document.createElement("span");
			createdCount.textContent = `(${count})`;
			label.appendChild(createdCount);
		}
		listContainer.appendChild(clone);
		return cb;
	}
	function finishCreateList(checkbox, listName) {
		const modal = document.querySelector("#modal-save-list");
		if (modal) try {
			modal.querySelector("a[data-action=\"list#cancelNewList\"]")?.click();
		} catch {}
		restoreCreateListUi();
		showToast$1(`✓ 清单「${listName}」已新建,并已关联当前影片`, "success");
		refreshListPanel();
		const movieInfo = getMovieInfo(checkbox.value);
		if (!movieInfo) {
			console.warn(`${LOG_PREFIX$6} 新建清单后无法取得影片资讯,跳过同步`, checkbox);
			return;
		}
		const listInfo = getListInfo(checkbox.dataset.listId || "");
		if (!listInfo.info.name) {
			console.warn(`${LOG_PREFIX$6} 新建清单后无法从 DOM 取得清单名称,使用传入名称「${listName}」`);
			listInfo.info.name = listName;
		}
		handleCheckboxChange(movieInfo, listInfo, true, { serverConfirmed: true }).then();
	}
	function restoreCreateListUi() {
		const w = document.querySelector(".jhs-list-create-wrap");
		if (!w) return;
		const activeElement = document.activeElement;
		const shouldRestoreFocus = !activeElement || activeElement === document.body || w.contains(activeElement);
		const btn = w.querySelector(".jhs-list-create-btn");
		const f = w.querySelector(".jhs-list-create-form");
		const inp = w.querySelector(".jhs-list-create-input");
		if (btn) {
			btn.style.display = "inline-flex";
			btn.setAttribute("aria-expanded", "false");
		}
		if (f) f.style.display = "none";
		if (inp) inp.value = "";
		if (btn && shouldRestoreFocus) btn.focus({ preventScroll: true });
	}
	function VltCreateListForm() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("button", {
			type: "button",
			className: "button is-info is-small jhs-list-create-btn",
			"aria-expanded": "false",
			"aria-controls": "jhs-list-create-form",
			children: "+ 新建清单"
		}), (0, import_jsx_runtime.jsxs)("span", {
			id: "jhs-list-create-form",
			className: "jhs-list-create-form",
			style: { display: "none" },
			children: [
				(0, import_jsx_runtime.jsx)("label", {
					className: "jhs-visually-hidden",
					htmlFor: "jhs-list-create-input",
					children: "清单名称"
				}),
				(0, import_jsx_runtime.jsx)("input", {
					id: "jhs-list-create-input",
					type: "text",
					className: "input is-small jhs-list-create-input",
					placeholder: "清单名称",
					maxLength: 50,
					autoComplete: "off"
				}),
				(0, import_jsx_runtime.jsx)("button", {
					type: "button",
					className: "button is-info is-small jhs-list-create-save",
					children: "新建"
				}),
				(0, import_jsx_runtime.jsx)("button", {
					type: "button",
					className: "button is-light is-small jhs-list-create-cancel",
					children: "取消"
				})
			]
		})] });
	}
	var _createListUiInjected = false;
	var _createListInFlight = false;
	function setupCreateListButton() {
		if (_createListUiInjected) return;
		const panel = document.querySelector(".jhs-list-panel");
		if (!panel) {
			setTimeout(setupCreateListButton, 400);
			return;
		}
		if (document.querySelector(".jhs-list-create-wrap")) {
			_createListUiInjected = true;
			return;
		}
		const wrap = document.createElement("div");
		wrap.className = "jhs-list-create-wrap";
		wrap.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(VltCreateListForm, {}));
		panel.insertAdjacentElement("afterend", wrap);
		bindCreateListEvents(wrap);
		bindCreateListAvailability(panel, wrap);
		_createListUiInjected = true;
	}
	function bindCreateListAvailability(panel, wrap) {
		const items = panel.querySelector(".jhs-list-panel__items");
		const btn = wrap.querySelector(".jhs-list-create-btn");
		if (!items || !btn) return;
		const sync = () => {
			const ready = isCreateListPanelReady();
			btn.disabled = !ready;
			btn.title = ready ? "新建清单" : "清单载入后可新建";
		};
		const observer = new MutationObserver(sync);
		observer.observe(items, {
			attributes: true,
			attributeFilter: ["aria-busy"]
		});
		observer.observe(panel, {
			attributes: true,
			attributeFilter: ["data-list-coverage"]
		});
		sync();
	}
	function isCreateListPanelReady() {
		const panel = document.querySelector(".jhs-list-panel");
		const items = document.querySelector(".jhs-list-panel__items");
		return panel?.dataset.listCoverage === "complete" && items?.getAttribute("aria-busy") === "false" && Boolean(getCurrentListContainer()?.querySelector("input[data-list-id]"));
	}
	function bindCreateListEvents(wrap) {
		const btn = wrap.querySelector(".jhs-list-create-btn");
		const form = wrap.querySelector(".jhs-list-create-form");
		const input = wrap.querySelector(".jhs-list-create-input");
		const saveBtn = wrap.querySelector(".jhs-list-create-save");
		const cancelBtn = wrap.querySelector(".jhs-list-create-cancel");
		btn.addEventListener("click", () => {
			btn.style.display = "none";
			btn.setAttribute("aria-expanded", "true");
			form.style.display = "inline-flex";
			input.value = "";
			input.focus();
		});
		cancelBtn.addEventListener("click", () => {
			if (_createListInFlight) return;
			restoreCreateListUi();
		});
		saveBtn.addEventListener("click", async () => {
			if (_createListInFlight) return;
			if (!isCreateListPanelReady()) {
				showToast$1("清单仍在载入,请稍后再新建", "warning");
				return;
			}
			const name = input.value.trim();
			if (!name) {
				showToast$1("请输入清单名称", "warning");
				input.focus();
				return;
			}
			_createListInFlight = true;
			setCreateListBusy(wrap, true);
			let result = "failed";
			try {
				result = await createList(name);
			} catch (error) {
				console.error(`${LOG_PREFIX$6} 新增清单发生未处理异常`, error);
				showToast$1("✗ 新增清单失败,请稍后重试", "error");
			} finally {
				_createListInFlight = false;
				setCreateListBusy(wrap, false);
			}
			if (result !== "created") input.focus();
		});
		input.addEventListener("keydown", (e) => {
			if (e.isComposing) return;
			if (e.key === "Enter") {
				e.preventDefault();
				saveBtn.click();
			} else if (e.key === "Escape") cancelBtn.click();
		});
	}
	function setCreateListBusy(wrap, busy) {
		const input = wrap.querySelector(".jhs-list-create-input");
		const saveBtn = wrap.querySelector(".jhs-list-create-save");
		const cancelBtn = wrap.querySelector(".jhs-list-create-cancel");
		wrap.setAttribute("aria-busy", String(busy));
		if (input) input.disabled = busy;
		if (saveBtn) {
			saveBtn.disabled = busy;
			saveBtn.textContent = busy ? "新建中…" : "新建";
		}
		if (cancelBtn) cancelBtn.disabled = busy;
	}
	function setupListManagementListener() {
		console.log(`${LOG_PREFIX$6} /users/lists 清单管理监听已启动`);
		document.addEventListener("click", (e) => {
			const deleteLink = e.target.closest?.("a[href*=\"remove_list\"][data-method=\"delete\"]");
			if (!deleteLink) return;
			e.preventDefault();
			e.stopPropagation();
			const href = deleteLink.getAttribute("href") || "";
			const listId = extractListIdFromHref(href);
			if (!listId) {
				console.warn(`${LOG_PREFIX$6} 删除链接无法提取 listId: ${href}`);
				return;
			}
			const confirmMsg = deleteLink.dataset.confirm || "確認移除嗎?";
			if (!confirm(confirmMsg)) return;
			handleListDeletion(listId, href).then();
		}, true);
		const editing = {
			listId: "",
			oldName: ""
		};
		document.addEventListener("click", (e) => {
			const editBtn = e.target.closest?.(".modal-edit-list-button");
			if (!editBtn) return;
			const listId = editBtn.dataset.listId || "";
			if (!listId) return;
			const nameEl = editBtn.closest("[id^=\"list-\"]")?.querySelector(".list-name");
			editing.listId = listId;
			editing.oldName = nameEl?.textContent?.trim() || "";
			console.log(`${LOG_PREFIX$6} 编辑清单快照: listId=${listId} oldName=${editing.oldName}`);
		}, true);
		document.addEventListener("click", (e) => {
			if (!e.target.closest?.("[data-action=\"list#updateList\"]")) return;
			e.preventDefault();
			e.stopPropagation();
			if (!editing.listId) {
				console.warn(`${LOG_PREFIX$6} 保存清单改名但无快照,跳过`);
				return;
			}
			const newName = (document.querySelector("#modal-edit-list")?.querySelector("[data-list-target=\"inputName\"]"))?.value?.trim() || "";
			if (!newName) {
				showToast$1("請輸入清單名稱", "warning");
				return;
			}
			if (newName === editing.oldName) {
				console.log(`${LOG_PREFIX$6} 清单改名前后名称相同(${newName}),跳过`);
				closeEditModal();
				return;
			}
			handleListRename(editing.listId, newName).then();
		}, true);
	}
	function closeEditModal() {
		const modal = document.querySelector("#modal-edit-list");
		if (!modal) return;
		modal.classList.remove("is-active");
		document.documentElement.classList.remove("is-clipped");
	}
	async function handleListDeletion(listId, href) {
		const csrfToken = getCsrfToken$1();
		if (!csrfToken) {
			showToast$1("✗ 无法获取 CSRF token,删除失败", "error");
			return;
		}
		console.log(`${LOG_PREFIX$6} ═══ 删除清单 listId=${listId} ═══`);
		showToast$1("正在同步删除…", "info");
		const serverOk = await sendDeleteRequest(href, csrfToken);
		if (!serverOk) {
			showToast$1("✗ JavDB 删除清单失败,本地数据未改动", "error");
			return;
		}
		const idbResult = await VltDb.deleteList(listId);
		document.querySelector(`#list-${listId}`)?.remove();
		console.log(`${LOG_PREFIX$6} 删除完成: listId=${listId} server=${serverOk} inventory=${idbResult.inventory} associations=${idbResult.associations}`);
		broadcastListMgmt("delete", listId);
		showToast$1(`✓ 清单已删除(${idbResult.associations} 条关联已清除)`, "success");
		console.log(`${LOG_PREFIX$6} ═══ 删除完成 ═══`);
	}
	function sendDeleteRequest(href, csrfToken) {
		return new Promise((resolve) => {
			GM_xmlhttpRequest({
				method: "DELETE",
				url: window.location.origin + href,
				headers: {
					"X-CSRF-Token": csrfToken,
					"X-Requested-With": "XMLHttpRequest",
					Accept: "text/javascript, application/javascript, application/xhtml+xml, */*"
				},
				timeout: 15e3,
				onload: (r) => resolve(r.status >= 200 && r.status < 400),
				onerror: () => resolve(false),
				ontimeout: () => resolve(false)
			});
		});
	}
	async function handleListRename(listId, newName) {
		const csrfToken = getCsrfToken$1();
		if (!csrfToken) {
			showToast$1("✗ 无法获取 CSRF token,改名失败", "error");
			return;
		}
		showToast$1("正在改名…", "info");
		console.log(`${LOG_PREFIX$6} ═══ 改名清单 listId=${listId} newName=${newName} ═══`);
		try {
			const response = await new Promise((resolve) => {
				GM_xmlhttpRequest({
					method: "POST",
					url: "https://javdb.com/users/update_list",
					headers: {
						"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
						"X-CSRF-Token": csrfToken,
						"X-Requested-With": "XMLHttpRequest",
						Accept: "application/json, text/javascript, */*;q=0.01"
					},
					data: `id=${encodeURIComponent(listId)}&name=${encodeURIComponent(newName)}`,
					timeout: 15e3,
					onload: (r) => {
						if (r.status >= 200 && r.status < 300) try {
							resolve(JSON.parse(r.responseText));
						} catch {
							resolve({
								success: false,
								name: "",
								message: "响应解析失败"
							});
						}
						else resolve({
							success: false,
							name: "",
							message: `HTTP ${r.status}`
						});
					},
					onerror: () => resolve({
						success: false,
						name: "",
						message: "网络错误"
					}),
					ontimeout: () => resolve({
						success: false,
						name: "",
						message: "请求超时"
					})
				});
			});
			if (!response.success) {
				showToast$1(`✗ 改名失败:${response.message || "未知错误"}`, "error");
				return;
			}
			const finalName = response.name || newName;
			console.log(`${LOG_PREFIX$6} 服务端改名成功: listId=${listId} name=${finalName}`);
			if (await VltDb.renameList(listId, finalName)) console.log(`${LOG_PREFIX$6} IDB 清单改名完成: listId=${listId} name=${finalName}`);
			else console.warn(`${LOG_PREFIX$6} IDB 清单改名跳过: listId=${listId} 不在本地 inventory 中`);
			broadcastListMgmt("rename", listId, { newName: finalName });
			const nameEl = document.querySelector(`#list-${listId} .list-name`);
			if (nameEl) nameEl.textContent = finalName;
			closeEditModal();
			showToast$1(`✓ 清单已改名为「${finalName}」`, "success");
			console.log(`${LOG_PREFIX$6} ═══ 改名完成 ═══`);
		} catch (err) {
			const message = err instanceof Error ? err.message : "未知错误";
			console.error(`${LOG_PREFIX$6} 清单改名失败: listId=${listId}`, err);
			showToast$1(`✗ 清单改名失败:${message}`, "error");
		}
	}
	function removeDetailPageCheckbox(listId) {
		const panelCb = document.querySelector(`.jhs-list-panel input[data-list-id="${listId}"]`);
		if (panelCb) (panelCb.closest("p.control") ?? panelCb.closest("label"))?.remove();
		const modalCb = document.querySelector(`#modal-save-list input[data-list-id="${listId}"]`);
		if (modalCb) (modalCb.closest("p.control") ?? modalCb.closest("label"))?.remove();
		refreshListPanel();
		console.log(`${LOG_PREFIX$6} 详情页已移除清单 ${listId} 的 checkbox`);
	}
	function updateDetailPageCheckboxLabel(listId, newName) {
		document.querySelectorAll(`input[data-list-id="${listId}"]`).forEach((cb) => {
			const label = cb.closest("label");
			if (!label) return;
			const displayName = label.querySelector(".jhs-list-item__name");
			if (displayName) {
				displayName.textContent = newName;
				return;
			}
			Array.from(label.childNodes).forEach((node) => {
				if (node.nodeType === Node.TEXT_NODE) node.textContent = "";
			});
			const inputEl = label.querySelector("input");
			if (inputEl && inputEl.nextSibling) inputEl.nextSibling.textContent = `\u00A0\n    ${newName}\u00A0\n    `;
			else if (inputEl) inputEl.insertAdjacentText("afterend", `\u00A0${newName}\u00A0`);
		});
		refreshListPanel();
		console.log(`${LOG_PREFIX$6} 详情页已更新清单 ${listId} 的标签为「${newName}」`);
	}
	function QuickBlockConfirmMessage({ carNum }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			"是否拉黑 ",
			carNum,
			"?",
			(0, import_jsx_runtime.jsx)("br", {}),
			(0, import_jsx_runtime.jsx)("span", {
				style: { color: "#f40" },
				children: "拉黑后该影片将被屏蔽,列表页自动隐藏,且设为已读0星。此操作不可在详情页撤销。"
			})
		] });
	}
	async function quickSetHasWatch(plugin, score) {
		const pageInfo = plugin.getPageInfo();
		if (!pageInfo.carNum) return;
		try {
			const carRecord = await storageManager.getCar(pageInfo.carNum);
			if (carRecord && carRecord.status === "favorite") await storageManager.removeCar(pageInfo.carNum);
			if (carRecord && carRecord.status === "hasWatch" && carRecord.score === score) {
				show.ok(pageInfo.carNum + " 评分未变化");
				return;
			}
			await storageManager.saveCar({
				carNum: pageInfo.carNum,
				url: pageInfo.url ?? void 0,
				names: pageInfo.actress ?? void 0,
				actionType: HAS_WATCH_ACTION,
				publishTime: pageInfo.publishTime ?? void 0,
				score
			});
			plugin.broadcastWantWatchedSync({
				carNum: pageInfo.carNum,
				status: HAS_WATCH_ACTION,
				op: "add",
				score
			});
			show.ok(pageInfo.carNum + " 已标记看过 " + (score > 0 ? "★" + score : ""));
			autoRemoveFromPendingUpdateOnWatch().then();
		} catch (err) {
			clog.error("[JHS-快键] 设为已观看失败", err);
			show.error("操作失败: " + (err instanceof Error ? err.message : String(err)));
			return;
		}
		plugin._reviewChain = (plugin._reviewChain || Promise.resolve()).then(async () => {
			plugin._wantWatchedSyncing = true;
			try {
				await plugin._triggerJavdbReview(score);
				plugin._syncRatingBar();
			} finally {
				plugin._wantWatchedSyncing = false;
			}
		}).catch(() => {});
	}
	async function quickBlock(plugin) {
		const pageInfo = plugin.getPageInfo();
		if (!pageInfo.carNum) return;
		utils.q(null, jsxToString((0, import_jsx_runtime.jsx)(QuickBlockConfirmMessage, { carNum: pageInfo.carNum })), async () => {
			plugin._setRatingBusy(true);
			try {
				if (await storageManager.getCar(pageInfo.carNum)) await storageManager.removeCar(pageInfo.carNum);
				await storageManager.saveCar({
					carNum: pageInfo.carNum,
					url: pageInfo.url ?? void 0,
					names: pageInfo.actress ?? void 0,
					actionType: FILTER_ACTION,
					publishTime: pageInfo.publishTime ?? void 0
				});
				plugin.broadcastWantWatchedSync({
					carNum: pageInfo.carNum,
					status: FILTER_ACTION,
					op: "add"
				});
				show.ok(`${pageInfo.carNum} 已拉黑`);
			} catch (err) {
				clog.error("[JHS-快键] 拉黑失败", err);
				show.error("操作失败: " + (err instanceof Error ? err.message : String(err)));
				return;
			}
			plugin._reviewChain = (plugin._reviewChain || Promise.resolve()).then(async () => {
				plugin._wantWatchedSyncing = true;
				try {
					await plugin._triggerJavdbReview(0);
					plugin._syncRatingBar();
				} finally {
					plugin._wantWatchedSyncing = false;
				}
			}).catch(() => {});
			plugin.showStatus(pageInfo.carNum).then();
			refresh();
			utils.closePage();
		});
	}
	async function quickConvertToFav(plugin) {
		const pageInfo = plugin.getPageInfo();
		if (!pageInfo.carNum) return;
		try {
			const carRecord = await storageManager.getCar(pageInfo.carNum);
			if (carRecord && carRecord.status === "favorite") {
				show.ok(pageInfo.carNum + " 已是已收藏");
				return;
			}
			if (carRecord) await storageManager.removeCar(pageInfo.carNum);
			await storageManager.saveCar({
				carNum: pageInfo.carNum,
				url: pageInfo.url ?? void 0,
				names: pageInfo.actress ?? void 0,
				actionType: FAVORITE_ACTION,
				publishTime: pageInfo.publishTime ?? void 0
			});
			plugin.broadcastWantWatchedSync({
				carNum: pageInfo.carNum,
				status: FAVORITE_ACTION,
				op: "add"
			});
			show.ok(pageInfo.carNum + " 已转为收藏");
		} catch (err) {
			clog.error("[JHS-快键] 转为已收藏失败", err);
			show.error("操作失败: " + (err instanceof Error ? err.message : String(err)));
			return;
		}
		plugin._reviewChain = (plugin._reviewChain || Promise.resolve()).then(async () => {
			plugin._wantWatchedSyncing = true;
			try {
				await plugin._triggerJavdbWant();
				plugin._syncRatingBar();
			} finally {
				plugin._wantWatchedSyncing = false;
			}
		}).catch(() => {});
	}
	function getCsrfToken() {
		const meta = document.querySelector("meta[name=\"csrf-token\"]");
		return meta ? meta.content : null;
	}
	function getVideoId() {
		return location.pathname.match(/\/v\/([^/]+)/)?.[1] || null;
	}
	function getReviewId() {
		const del = document.querySelector(".review-buttons a[data-method='delete'][href*='/reviews/']");
		if (!del) return null;
		return del.getAttribute("href")?.match(/\/reviews\/(\d+)/)?.[1] || null;
	}
	function execRailsJs(jsText) {
		try {
			const script = document.createElement("script");
			script.textContent = jsText;
			document.head?.appendChild(script);
			script.remove();
		} catch (err) {
			clog.error("[JHS-快键] 执行 Rails JS 失败", err);
		}
	}
	async function javdbReviewApi(plugin, action, score = 0) {
		const token = getCsrfToken();
		if (!token) throw new Error("无法获取 CSRF token");
		const videoId = getVideoId();
		if (!videoId) throw new Error("无法获取 videoId");
		const reviewId = getReviewId();
		const headers = {
			"Content-Type": "application/x-www-form-urlencoded",
			"X-CSRF-Token": token
		};
		const tokenParam = `authenticity_token=${encodeURIComponent(token)}`;
		if (action === "watched") {
			const url = reviewId ? `/v/${videoId}/reviews/${reviewId}` : `/v/${videoId}/reviews`;
			const body = `${tokenParam}${reviewId ? "&_method=patch" : ""}&video_review[status]=watched&video_review[score]=${score}&video_review[content]=`;
			const res = await fetch(url, {
				method: "POST",
				headers,
				body,
				credentials: "same-origin"
			});
			if (!res.ok) throw new Error(`设为已观看失败: HTTP ${res.status}`);
			execRailsJs(await res.text());
		} else if (action === "wanted") {
			if (reviewId) {
				const delRes = await fetch(`/v/${videoId}/reviews/${reviewId}`, {
					method: "POST",
					headers,
					body: `${tokenParam}&_method=delete`,
					credentials: "same-origin"
				});
				if (!delRes.ok) throw new Error(`删除旧评价失败: HTTP ${delRes.status}`);
				execRailsJs(await delRes.text());
			}
			const res = await fetch(`/v/${videoId}/reviews/want_to_watch`, {
				method: "POST",
				headers,
				body: tokenParam,
				credentials: "same-origin"
			});
			if (!res.ok) throw new Error(`设为想看失败: HTTP ${res.status}`);
			execRailsJs(await res.text());
		}
		const rb = document.querySelector(".review-buttons");
		if (rb && plugin._wantWatchedObserved) plugin._lastWantState = plugin.detectWantWatchedState(rb);
	}
	async function triggerJavdbReview(plugin, score) {
		await javdbReviewApi(plugin, "watched", score);
	}
	async function triggerJavdbWant(plugin) {
		await javdbReviewApi(plugin, "wanted");
	}
	function addQuickActionButtons(plugin) {
		if (!window.isDetailPage) return;
		if (plugin._quickActionAdded) return;
		plugin._quickActionAdded = true;
		const self = plugin;
		plugin._injectRatingStyles();
		const ensure = () => {
			const nav = document.querySelector("body > section > div > div.video-detail > div.video-meta-panel > div > div:nth-child(2) > nav");
			if (!nav) {
				setTimeout(ensure, 400);
				return;
			}
			self._buildRatingBar(nav);
			self._syncRatingBar();
			self._ensureListPanel(nav);
			const rb = nav.querySelector(".review-buttons");
			if (rb && !rb.__jhsRatingObserved) {
				rb.__jhsRatingObserved = true;
				new MutationObserver(() => {
					if (self._wantWatchedSyncing) return;
					clearTimeout(self._ratingSyncDebounce ?? void 0);
					self._ratingSyncDebounce = setTimeout(() => {
						self._buildRatingBar(nav);
						self._syncRatingBar();
					}, 200);
				}).observe(rb, {
					childList: true,
					subtree: true
				});
			}
		};
		ensure();
	}
	function buildRatingBar(plugin, nav) {
		const column = nav.querySelector("div.review-buttons > div:nth-child(1) > div > div");
		if (!column) return;
		if (column.querySelector(".jhs-rating-bar")) return;
		const self = plugin;
		const bar = document.createElement("div");
		bar.className = "jhs-rating-bar";
		bar.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(RatingBarHtml, {}));
		const starsEl = bar.querySelector(".jhs-stars");
		const stars = bar.querySelectorAll(".jhs-star");
		const readBtn = bar.querySelector(".jhs-read-btn");
		const favBtn = bar.querySelector(".jhs-fav-btn");
		const blockBtn = bar.querySelector(".jhs-block-btn");
		if (!starsEl || !readBtn || !favBtn || !blockBtn) return;
		starsEl.addEventListener("pointerover", (e) => {
			const star = e.target.closest(".jhs-star");
			if (!star) return;
			const score = +star.dataset.score;
			stars.forEach((s, i) => s.classList.toggle("is-preview", i < score));
		});
		starsEl.addEventListener("pointerleave", () => stars.forEach((s) => s.classList.remove("is-preview")));
		stars.forEach((star) => {
			star.addEventListener("click", async (e) => {
				e.preventDefault();
				const score = +star.dataset.score;
				star.classList.add("is-popping");
				setTimeout(() => star.classList.remove("is-popping"), 300);
				self._setRatingBusy(true);
				try {
					await self.quickSetHasWatch(score);
				} finally {
					self._setRatingBusy(false);
					self.showStatus(self.getPageInfo().carNum).then();
				}
			});
		});
		readBtn.addEventListener("click", async (e) => {
			e.preventDefault();
			readBtn.classList.add("is-popping");
			setTimeout(() => readBtn.classList.remove("is-popping"), 300);
			self._setRatingBusy(true);
			try {
				await self.quickSetHasWatch(0);
			} finally {
				self._setRatingBusy(false);
				self.showStatus(self.getPageInfo().carNum).then();
			}
		});
		favBtn.addEventListener("click", async (e) => {
			e.preventDefault();
			favBtn.classList.add("is-popping");
			setTimeout(() => favBtn.classList.remove("is-popping"), 300);
			self._setRatingBusy(true);
			try {
				await self.quickConvertToFav();
			} finally {
				self._setRatingBusy(false);
				self.showStatus(self.getPageInfo().carNum).then();
			}
		});
		blockBtn.addEventListener("click", async (e) => {
			e.preventDefault();
			blockBtn.classList.add("is-popping");
			setTimeout(() => blockBtn.classList.remove("is-popping"), 300);
			await self.quickBlock();
		});
		column.insertBefore(bar, column.firstChild);
	}
	function injectRatingStyles() {
		if (document.getElementById("jhs-rating-styles")) return;
		const style = document.createElement("style");
		style.id = "jhs-rating-styles";
		style.textContent = rating_bar_default;
		document.head?.appendChild(style);
	}
	function syncRatingBar(plugin) {
		let bar = document.querySelector(".jhs-rating-bar");
		if (!bar) {
			const nav = document.querySelector("body > section > div > div.video-detail > div.video-meta-panel > div > div:nth-child(2) > nav");
			if (nav) plugin._buildRatingBar(nav);
			bar = document.querySelector(".jhs-rating-bar");
		}
		if (!bar) return;
		const rb = document.querySelector(".review-buttons");
		if (!rb) return;
		const want = !!rb.querySelector("a[href='/users/want_watch_videos'] .tag.is-info.is-light");
		const watched = !!rb.querySelector("a[href='/users/watched_videos'] .tag.is-success.is-light");
		const checked = rb.querySelector("input[name=\"video_review[score]\"][checked]");
		const score = checked ? +checked.value : 0;
		const stars = bar.querySelectorAll(".jhs-star");
		const starsEl = bar.querySelector(".jhs-stars");
		const readBtn = bar.querySelector(".jhs-read-btn");
		const favBtn = bar.querySelector(".jhs-fav-btn");
		const blockBtn = bar.querySelector(".jhs-block-btn");
		if (!starsEl || !readBtn || !favBtn || !blockBtn) return;
		stars.forEach((s) => s.classList.remove("is-active"));
		starsEl.classList.remove("is-disabled");
		readBtn.classList.remove("is-active");
		favBtn.classList.remove("is-active");
		blockBtn.classList.remove("is-active");
		if (want) favBtn.classList.add("is-active");
		else if (watched) {
			stars.forEach((s, i) => s.classList.toggle("is-active", i < score));
			readBtn.classList.toggle("is-active", score === 0);
		}
		const carNum = plugin.getPageInfo().carNum;
		if (carNum) storageManager.getCar(carNum).then((carRecord) => {
			if (carRecord && carRecord.status === "filter") blockBtn.classList.add("is-active");
		});
	}
	function setRatingBusy(busy) {
		const bar = document.querySelector(".jhs-rating-bar");
		if (bar) bar.classList.toggle("is-busy", busy);
	}
	function ListPanel() {
		return (0, import_jsx_runtime.jsxs)("section", {
			className: "jhs-list-panel",
			"aria-labelledby": "jhs-list-panel-title",
			children: [
				(0, import_jsx_runtime.jsxs)("header", {
					className: "jhs-list-panel__header",
					children: [(0, import_jsx_runtime.jsxs)("div", {
						className: "jhs-list-panel__heading",
						children: [(0, import_jsx_runtime.jsx)("h3", {
							id: "jhs-list-panel-title",
							className: "jhs-list-panel__title",
							children: "加入清单"
						}), (0, import_jsx_runtime.jsx)("span", {
							className: "jhs-list-panel__summary",
							"aria-live": "polite",
							children: "正在读取…"
						})]
					}), (0, import_jsx_runtime.jsxs)("label", {
						className: "jhs-list-panel__sort",
						children: [(0, import_jsx_runtime.jsx)("span", { children: "排序" }), (0, import_jsx_runtime.jsxs)("select", {
							className: "jhs-list-panel__sort-select",
							"aria-label": "清单排序",
							disabled: true,
							children: [(0, import_jsx_runtime.jsx)("option", {
								value: "name-desc",
								children: "名称降序"
							}), (0, import_jsx_runtime.jsx)("option", {
								value: "name-asc",
								children: "名称升序"
							})]
						})]
					})]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					className: "jhs-list-panel__search-wrap",
					children: [
						(0, import_jsx_runtime.jsx)("span", {
							className: "jhs-list-panel__search-icon",
							"aria-hidden": "true",
							children: "⌕"
						}),
						(0, import_jsx_runtime.jsx)("input", {
							className: "jhs-list-panel__search",
							type: "search",
							placeholder: "搜索清单",
							"aria-label": "搜索清单",
							autoComplete: "off",
							disabled: true
						}),
						(0, import_jsx_runtime.jsx)("button", {
							className: "jhs-list-panel__search-clear",
							type: "button",
							"aria-label": "清空清单搜索",
							title: "清空搜索",
							hidden: true,
							children: "×"
						})
					]
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					className: "jhs-list-panel__items",
					role: "group",
					"aria-label": "清单列表",
					"aria-busy": "true",
					children: [
						(0, import_jsx_runtime.jsx)("span", {
							className: "jhs-list-panel__skeleton",
							"aria-hidden": "true"
						}),
						(0, import_jsx_runtime.jsx)("span", {
							className: "jhs-list-panel__skeleton",
							"aria-hidden": "true"
						}),
						(0, import_jsx_runtime.jsx)("span", {
							className: "jhs-list-panel__skeleton",
							"aria-hidden": "true"
						}),
						(0, import_jsx_runtime.jsx)("span", {
							className: "jhs-list-panel__skeleton",
							"aria-hidden": "true"
						})
					]
				}),
				(0, import_jsx_runtime.jsx)("p", {
					className: "jhs-list-panel__empty",
					role: "status",
					hidden: true
				})
			]
		});
	}
	function ListPanelSkeletonSpan() {
		return (0, import_jsx_runtime.jsx)("span", {
			className: "jhs-list-panel__skeleton",
			"aria-hidden": "true"
		});
	}
	function createListPanelEntry(plugin, source) {
		const element = source.cloneNode(true);
		const label = element.matches("label") ? element : element.querySelector("label");
		const input = element.querySelector("input[type=\"checkbox\"]");
		const originalCount = label?.querySelector("span") || null;
		const listId = input?.dataset.listId || "";
		if (!label || !input || !listId) return null;
		input.removeAttribute("id");
		input.removeAttribute("name");
		input.removeAttribute("data-action");
		label.removeAttribute("for");
		const name = Array.from(label.childNodes).filter((node) => node !== input && node !== originalCount).map((node) => node.textContent || "").join(" ").replace(/\s+/g, " ").trim() || "未命名清单";
		const countMatch = originalCount?.textContent?.match(/\d+/);
		const count = countMatch ? Number(countMatch[0]) : null;
		const nameElement = document.createElement("span");
		nameElement.className = "jhs-list-item__name";
		nameElement.textContent = name;
		nameElement.title = name;
		const countElement = document.createElement("span");
		countElement.className = "jhs-list-item__count";
		countElement.textContent = count === null ? "—" : String(count);
		countElement.title = count === null ? "影片数量未知" : `清单内 ${count} 部影片`;
		countElement.setAttribute("aria-label", count === null ? "影片数量未知" : `${count} 部影片`);
		const statusElement = document.createElement("span");
		statusElement.className = "jhs-list-item__status";
		statusElement.setAttribute("aria-live", "polite");
		statusElement.setAttribute("aria-atomic", "true");
		statusElement.hidden = true;
		element.classList.add("jhs-list-item");
		element.dataset.listId = listId;
		element.dataset.listName = name;
		label.classList.add("jhs-list-item__label");
		label.replaceChildren(input, nameElement, countElement, statusElement);
		plugin._updateListPanelEntryState(input);
		return { element };
	}
	function showListPanelLoading(plugin, panel) {
		const items = panel.querySelector(".jhs-list-panel__items");
		const summary = panel.querySelector(".jhs-list-panel__summary");
		const empty = panel.querySelector(".jhs-list-panel__empty");
		const search = panel.querySelector(".jhs-list-panel__search");
		const sort = panel.querySelector(".jhs-list-panel__sort-select");
		const clear = panel.querySelector(".jhs-list-panel__search-clear");
		plugin._clearListPanelNotice(panel);
		if (summary) summary.textContent = "正在读取…";
		if (empty) empty.hidden = true;
		if (search) search.disabled = true;
		if (sort) sort.disabled = true;
		if (clear) clear.hidden = true;
		if (items) {
			if (items.getAttribute("aria-busy") === "true" && items.firstElementChild) return;
			items.setAttribute("aria-busy", "true");
			items.innerHTML = Array.from({ length: 4 }, () => jsxToString((0, import_jsx_runtime.jsx)(ListPanelSkeletonSpan, {}))).join("");
		}
	}
	function showListPanelError(plugin, panel, message) {
		const items = panel.querySelector(".jhs-list-panel__items");
		const summary = panel.querySelector(".jhs-list-panel__summary");
		const search = panel.querySelector(".jhs-list-panel__search");
		const sort = panel.querySelector(".jhs-list-panel__sort-select");
		const clear = panel.querySelector(".jhs-list-panel__search-clear");
		plugin._clearListPanelNotice(panel);
		if (summary) summary.textContent = "读取失败";
		if (search) search.disabled = true;
		if (sort) sort.disabled = true;
		if (clear) clear.hidden = true;
		if (!items) return;
		items.setAttribute("aria-busy", "false");
		items.replaceChildren();
		const state = document.createElement("div");
		state.className = "jhs-list-panel__error";
		state.setAttribute("role", "alert");
		const text = document.createElement("span");
		text.textContent = message;
		const retry = document.createElement("button");
		retry.type = "button";
		retry.className = "jhs-list-panel__retry";
		retry.dataset.listPanelRetry = "true";
		retry.textContent = "重新加载";
		state.append(text, retry);
		items.appendChild(state);
	}
	var LIST_PANEL_MAX_PAGES = 50;
	function loadAllListPages(plugin, panel, container) {
		if (plugin._listPanelPaginationPromise) return;
		const videoId = window.location.pathname.match(/\/v\/([^/?#]+)/)?.[1];
		if (!videoId) {
			container.dataset.jhsPagesStatus = "complete";
			plugin._scheduleListPanelSync(0);
			return;
		}
		container.dataset.jhsPagesStatus = "loading";
		const generation = plugin._listPanelPaginationGeneration;
		plugin._listPanelPaginationPromise = plugin._fetchAllListPageEntries(videoId).then((fetchedEntries) => {
			const currentContainer = document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
			if (!currentContainer) throw new Error("原生清单容器已移除");
			if (generation !== plugin._listPanelPaginationGeneration || currentContainer !== container) return;
			const existingIds = new Set(Array.from(currentContainer.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).map((input) => input.dataset.listId));
			const fragment = document.createDocumentFragment();
			for (const entry of fetchedEntries) {
				const listId = entry.querySelector("input[type=\"checkbox\"][data-list-id]")?.dataset.listId;
				if (!listId || existingIds.has(listId)) continue;
				existingIds.add(listId);
				fragment.appendChild(document.importNode(entry, true));
			}
			currentContainer.dataset.jhsPagesStatus = "complete";
			currentContainer.appendChild(fragment);
		}).catch((error) => {
			if (generation !== plugin._listPanelPaginationGeneration) return;
			const currentContainer = document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
			if (currentContainer) currentContainer.dataset.jhsPagesStatus = "partial";
			console.warn("详情页清单分页聚合失败,将显示当前已加载内容", error);
			plugin._showListPanelNotice(panel, "部分清单未载入,排序与搜索仅覆盖已显示项");
		}).finally(() => {
			plugin._listPanelPaginationPromise = null;
			plugin._scheduleListPanelSync(0);
		});
	}
	async function fetchAllListPageEntries(videoId) {
		const entries = [];
		const visited = new Set();
		let url = new URL("/users/simple_lists", window.location.origin);
		url.searchParams.set("vid", videoId);
		while (url) {
			if (visited.size >= LIST_PANEL_MAX_PAGES) throw new Error(`清单分页超过 ${LIST_PANEL_MAX_PAGES} 页`);
			if (visited.has(url.href)) throw new Error("清单分页出现循环");
			visited.add(url.href);
			const page = await fetchSimpleListsPage(url.href, videoId);
			const listDocument = new DOMParser().parseFromString(page.entries, "text/html");
			for (const child of Array.from(listDocument.body.children)) if (child.querySelector("input[type=\"checkbox\"][data-list-id]")) entries.push(child);
			if (!page.nextUrl) {
				url = null;
				continue;
			}
			url = new URL(page.nextUrl);
		}
		return entries;
	}
	var DETAIL_LIST_COLLATOR = new Intl.Collator("zh-CN", {
		numeric: true,
		sensitivity: "base"
	});
	var LIST_PANEL_INIT_TIMEOUT_MS = 1e4;
	var DETAIL_DOM_WAIT_TIMEOUT_MS = 15e3;
	function ensureListPanel(plugin, nav, startTime = Date.now()) {
		if (plugin._listPanelEnsured) return;
		const otherSite = nav.querySelector("#otherSiteBox");
		if (!otherSite) if (Date.now() - startTime > DETAIL_DOM_WAIT_TIMEOUT_MS) clog.warn("[JHS] 清单面板:等待 #otherSiteBox 超时,回退挂载到 nav");
		else {
			setTimeout(() => ensureListPanel(plugin, nav, startTime), 400);
			return;
		}
		plugin._listPanelEnsured = true;
		if (!nav.querySelector(".jhs-list-panel")) if (otherSite) otherSite.insertAdjacentHTML("afterend", jsxToString((0, import_jsx_runtime.jsx)(ListPanel, {})));
		else nav.insertAdjacentHTML("beforeend", jsxToString((0, import_jsx_runtime.jsx)(ListPanel, {})));
		const listPanel = nav.querySelector(".jhs-list-panel");
		if (!listPanel) return;
		plugin._bindListPanelControls(listPanel);
		listPanel.__jhsRefresh = () => plugin._scheduleListPanelSync(0);
		plugin._initListPanel();
	}
	function bindListPanelControls(plugin, panel) {
		if (panel.__jhsListControlsBound) return;
		panel.__jhsListControlsBound = true;
		const search = panel.querySelector(".jhs-list-panel__search");
		const sort = panel.querySelector(".jhs-list-panel__sort-select");
		const clear = panel.querySelector(".jhs-list-panel__search-clear");
		search?.addEventListener("input", () => plugin._applyListPanelView(panel));
		sort?.addEventListener("change", () => plugin._applyListPanelView(panel));
		clear?.addEventListener("click", () => {
			if (!search) return;
			search.value = "";
			search.focus();
			plugin._applyListPanelView(panel);
		});
		panel.addEventListener("click", (event) => {
			const target = event.target;
			if (!(target instanceof Element) || !target.closest("[data-list-panel-retry]")) return;
			plugin._listPanelIniting = false;
			plugin._showListPanelLoading(panel);
			plugin._initListPanel(true);
		});
		panel.addEventListener("change", (event) => {
			const displayInput = event.target;
			if (!(displayInput instanceof HTMLInputElement) || displayInput.type !== "checkbox") return;
			plugin._forwardListPanelChange(panel, displayInput);
		});
	}
	function forwardListPanelChange(plugin, panel, displayInput) {
		const checkedBeforeMutation = !displayInput.checked;
		const listId = displayInput.dataset.listId;
		const listContainer = document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
		const sourceInput = listId ? Array.from(listContainer?.querySelectorAll("input[type=\"checkbox\"][data-list-id]") || []).find((input) => input.dataset.listId === listId) ?? null : null;
		if (!sourceInput || sourceInput.disabled) {
			displayInput.checked = checkedBeforeMutation;
			plugin._applyListPanelView(panel);
			const message = "清单状态已变化,已恢复原选择,请稍后重试";
			plugin._showListPanelNotice(panel, message);
			show.error(message, { duration: 3e3 });
			plugin._scheduleListPanelSync(80);
			return;
		}
		sourceInput.checked = displayInput.checked;
		sourceInput.dispatchEvent(new Event("change", { bubbles: true }));
		plugin._applyListPanelView(panel);
	}
	function initListPanel(plugin, forceReload = false) {
		if (plugin._listPanelIniting) return;
		plugin._listPanelIniting = true;
		const startedAt = Date.now();
		const ensure = () => {
			const btn = document.querySelector("#save-list-button");
			const modal = document.querySelector("#modal-save-list");
			const panel = document.querySelector(".jhs-list-panel");
			if (!panel) return;
			if (!btn || !modal) {
				if (Date.now() - startedAt >= LIST_PANEL_INIT_TIMEOUT_MS) {
					plugin._listPanelIniting = false;
					plugin._showListPanelError(panel, "清单加载失败,请重试");
					return;
				}
				setTimeout(ensure, 400);
				return;
			}
			if (!plugin._listPanelObserver) {
				plugin._listPanelObserver = new MutationObserver((mutations) => {
					if (mutations.some((mutation) => mutation.type === "childList" && Array.from(mutation.removedNodes).some((node) => node instanceof Element && (node.matches("input[data-list-id]") || Boolean(node.querySelector("input[data-list-id]")))))) {
						plugin._listPanelPaginationGeneration++;
						const currentContainer = document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
						if (currentContainer) delete currentContainer.dataset.jhsPagesStatus;
					}
					if (mutations.every((mutation) => mutation.type === "attributes" && mutation.target instanceof HTMLInputElement)) {
						for (const mutation of mutations) plugin._syncListPanelInputState(mutation.target);
						const currentPanel = document.querySelector(".jhs-list-panel");
						if (currentPanel) plugin._applyListPanelView(currentPanel);
						return;
					}
					plugin._scheduleListPanelSync();
				});
				plugin._listPanelObserver.observe(modal, {
					childList: true,
					subtree: true,
					characterData: true,
					attributes: true,
					attributeFilter: ["checked", "disabled"]
				});
			}
			plugin._startListPanelLoadTimeout(panel);
			if (forceReload && plugin._listAjaxTriggered) {
				btn.click();
				setTimeout(() => btn.click(), 200);
			} else if (!plugin._listAjaxTriggered) {
				plugin._listAjaxTriggered = true;
				btn.click();
			}
			setTimeout(() => plugin._scheduleListPanelSync(0), 500);
		};
		ensure();
	}
	function syncListPanelInputState(plugin, sourceInput) {
		const listId = sourceInput.dataset.listId;
		if (!listId) return;
		const displayInput = Array.from(document.querySelectorAll(".jhs-list-panel input[type=\"checkbox\"][data-list-id]")).find((input) => input.dataset.listId === listId) || null;
		if (!displayInput) return;
		displayInput.checked = sourceInput.checked;
		displayInput.disabled = sourceInput.disabled;
		if (sourceInput.dataset.vltWasDisabled !== void 0) {
			displayInput.dataset.vltWasDisabled = sourceInput.dataset.vltWasDisabled;
			displayInput.setAttribute("aria-busy", "true");
		} else {
			delete displayInput.dataset.vltWasDisabled;
			displayInput.removeAttribute("aria-busy");
		}
		plugin._updateListPanelEntryState(displayInput);
	}
	function updateListPanelEntryState(input) {
		const label = input.closest(".jhs-list-item__label");
		const status = label?.querySelector(".jhs-list-item__status");
		if (!label || !status) return;
		const countMatch = (label.querySelector(".jhs-list-item__count")?.textContent || "").match(/\d+/);
		const count = countMatch ? Number(countMatch[0]) : null;
		const state = input.dataset.vltWasDisabled !== void 0 ? "busy" : input.disabled && count !== null && count >= 501 && !input.checked ? "full" : input.disabled ? "unavailable" : null;
		label.removeAttribute("title");
		status.hidden = state === null;
		if (state === null) {
			status.textContent = "";
			delete status.dataset.state;
		} else {
			status.dataset.state = state;
			status.textContent = state === "busy" ? "同步中" : state === "full" ? "已满" : "不可用";
		}
	}
	function scheduleListPanelSync(plugin, delay = 48) {
		if (plugin._listPanelSyncTimer !== null) window.clearTimeout(plugin._listPanelSyncTimer);
		plugin._listPanelSyncTimer = window.setTimeout(() => {
			plugin._listPanelSyncTimer = null;
			plugin._renderListPanel();
		}, delay);
	}
	function renderListPanel(plugin) {
		const panel = document.querySelector(".jhs-list-panel");
		const listContainer = document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
		const itemsContainer = panel?.querySelector(".jhs-list-panel__items");
		if (!panel || !itemsContainer) return;
		if (!plugin._isListContainerLoaded(listContainer)) {
			plugin._showListPanelLoading(panel);
			plugin._startListPanelLoadTimeout(panel);
			return;
		}
		const nativeContainer = listContainer;
		const pagesStatus = nativeContainer.dataset.jhsPagesStatus;
		if (!pagesStatus || pagesStatus === "loading") {
			plugin._showListPanelLoading(panel);
			plugin._loadAllListPages(panel, nativeContainer);
			return;
		}
		panel.dataset.listCoverage = pagesStatus;
		const activeElement = document.activeElement;
		const activeListId = activeElement instanceof HTMLInputElement && itemsContainer.contains(activeElement) ? activeElement.dataset.listId : void 0;
		const entries = Array.from(listContainer.children).filter((child) => !/[预預][设設]清[单單]/.test(child.textContent || "")).map((child) => plugin._createListPanelEntry(child)).filter((entry) => entry !== null);
		itemsContainer.replaceChildren(...entries.map((entry) => entry.element));
		itemsContainer.setAttribute("aria-busy", "false");
		plugin._clearListPanelLoadTimeout();
		plugin._listPanelIniting = false;
		const search = panel.querySelector(".jhs-list-panel__search");
		const sort = panel.querySelector(".jhs-list-panel__sort-select");
		if (search) search.disabled = false;
		if (sort) sort.disabled = false;
		plugin._applyListPanelView(panel);
		if (activeListId) Array.from(itemsContainer.querySelectorAll("input[type=\"checkbox\"][data-list-id]")).find((input) => input.dataset.listId === activeListId)?.focus({ preventScroll: true });
	}
	function applyListPanelView(panel) {
		const itemsContainer = panel.querySelector(".jhs-list-panel__items");
		const sortSelect = panel.querySelector(".jhs-list-panel__sort-select");
		const searchInput = panel.querySelector(".jhs-list-panel__search");
		const clearButton = panel.querySelector(".jhs-list-panel__search-clear");
		const summary = panel.querySelector(".jhs-list-panel__summary");
		const empty = panel.querySelector(".jhs-list-panel__empty");
		if (!itemsContainer || !sortSelect || !searchInput || !summary || !empty) return;
		const sort = sortSelect.value === "name-asc" ? "name-asc" : "name-desc";
		if (sortSelect.value !== sort) sortSelect.value = sort;
		const direction = sort === "name-asc" ? 1 : -1;
		const items = Array.from(itemsContainer.querySelectorAll(".jhs-list-item"));
		items.sort((left, right) => {
			const nameResult = DETAIL_LIST_COLLATOR.compare(left.dataset.listName || "", right.dataset.listName || "");
			if (nameResult !== 0) return nameResult * direction;
			return DETAIL_LIST_COLLATOR.compare(left.dataset.listId || "", right.dataset.listId || "");
		});
		itemsContainer.append(...items);
		const query = searchInput.value.trim().toLocaleLowerCase();
		let visibleCount = 0;
		let selectedCount = 0;
		for (const item of items) {
			if (item.querySelector("input[type=\"checkbox\"]")?.checked) selectedCount++;
			const visible = !query || (item.dataset.listName || "").toLocaleLowerCase().includes(query);
			item.hidden = !visible;
			if (visible) visibleCount++;
		}
		if (clearButton) clearButton.hidden = query.length === 0;
		const coverageSuffix = panel.dataset.listCoverage === "partial" ? " · 部分清单" : "";
		const summaryText = query ? `已加入 ${selectedCount} · 显示 ${visibleCount}/${items.length}${coverageSuffix}` : `已加入 ${selectedCount} / ${items.length}${coverageSuffix}`;
		summary.textContent = panel.__jhsNotice || summaryText;
		summary.classList.toggle("is-error", Boolean(panel.__jhsNotice));
		empty.hidden = visibleCount > 0;
		empty.textContent = items.length === 0 ? "还没有自建清单,可在下方创建。" : `没有找到"${searchInput.value.trim()}"`;
	}
	function isListContainerLoaded(container) {
		return Boolean(container?.querySelector("input[type=\"checkbox\"][data-list-id]"));
	}
	function startListPanelLoadTimeout(plugin, panel) {
		if (plugin._listPanelLoadTimer !== null) return;
		plugin._listPanelLoadTimer = window.setTimeout(() => {
			plugin._listPanelLoadTimer = null;
			const container = document.querySelector("#modal-save-list [data-list-target=\"listContainer\"]");
			if (plugin._isListContainerLoaded(container)) return;
			plugin._listPanelIniting = false;
			plugin._showListPanelError(panel, "清单内容未能载入,请重试");
		}, LIST_PANEL_INIT_TIMEOUT_MS);
	}
	function clearListPanelLoadTimeout(plugin) {
		if (plugin._listPanelLoadTimer === null) return;
		window.clearTimeout(plugin._listPanelLoadTimer);
		plugin._listPanelLoadTimer = null;
	}
	function showListPanelNotice(plugin, panel, message) {
		if (panel.__jhsNoticeTimer !== void 0) window.clearTimeout(panel.__jhsNoticeTimer);
		panel.__jhsNotice = message;
		plugin._applyListPanelView(panel);
		panel.__jhsNoticeTimer = window.setTimeout(() => {
			delete panel.__jhsNotice;
			delete panel.__jhsNoticeTimer;
			plugin._applyListPanelView(panel);
		}, 3e3);
	}
	function clearListPanelNotice(panel) {
		if (panel.__jhsNoticeTimer !== void 0) window.clearTimeout(panel.__jhsNoticeTimer);
		delete panel.__jhsNotice;
		delete panel.__jhsNoticeTimer;
		panel.querySelector(".jhs-list-panel__summary")?.classList.remove("is-error");
	}
	function SubtitleActionCell() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsx)("a", {
				className: "a-primary",
				children: "预览"
			}),
			" ",
			(0, import_jsx_runtime.jsx)("a", {
				className: "a-success",
				children: "下载"
			})
		] });
	}
	function SubtitleLine({ paddedNum, line }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsx)("span", {
				style: { color: "#AAA" },
				children: `${paddedNum}. `
			}),
			line,
			"\n"
		] });
	}
	function SubtitlePreviewDialog({ content }) {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				padding: "15px 5px",
				background: "#1E1E1E",
				color: "#FFF",
				fontFamily: "Consolas,Monaco,monospace",
				whiteSpace: "pre-wrap",
				overflow: "auto",
				height: "100%"
			},
			dangerouslySetInnerHTML: { __html: content }
		});
	}
	function SubtitleTableDialog() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				height: "100%",
				overflow: "hidden"
			},
			children: (0, import_jsx_runtime.jsx)("div", {
				id: "xunlei-table-container",
				style: {
					height: "100%",
					paddingBottom: "20px"
				}
			})
		});
	}
	async function searchXunLeiSubtitle(plugin, carNum) {
		try {
			await withLoading(async () => {
				const subtitleList = (await gmHttp.get(`https://api-shoulei-ssl.xunlei.com/oracle/subtitle?gcid=&cid=&name=${carNum}`)).data;
				if (subtitleList && subtitleList.length !== 0) layer.open({
					type: 1,
					title: "迅雷字幕",
					content: jsxToString((0, import_jsx_runtime.jsx)(SubtitleTableDialog, {})),
					scrollbar: false,
					area: utils.getResponsiveArea(["60%", "70%"]),
					anim: -1,
					success: (_layero, index) => {
						new Tabulator("#xunlei-table-container", createTabulatorOptions([
							{
								title: "文件名",
								field: "name",
								headerSort: false,
								responsive: 0
							},
							{
								title: "类型",
								field: "ext",
								headerSort: false,
								responsive: 0
							},
							{
								title: "操作",
								responsive: 0,
								headerSort: false,
								formatter: (cell, _formatterParams, onRendered) => {
									const rowData = cell.getData();
									onRendered(() => {
										const previewBtn = cell.getElement().querySelector(".a-primary");
										const downloadBtn = cell.getElement().querySelector(".a-success");
										if (previewBtn) previewBtn.addEventListener("click", async (_event) => {
											const subUrl = rowData.url;
											const subFilename = carNum + "." + rowData.ext;
											plugin.previewSubtitle(subUrl, subFilename);
										});
										if (downloadBtn) downloadBtn.addEventListener("click", async (_event) => {
											const subUrl = rowData.url;
											const subFilename = carNum + "." + rowData.ext;
											const content = await gmHttp.get(subUrl);
											utils.download(content, subFilename);
										});
									});
									return jsxToString((0, import_jsx_runtime.jsx)(SubtitleActionCell, {}));
								}
							}
						], subtitleList));
						utils.setupEscClose(index);
					}
				});
				else show.error("迅雷中找不到相关字幕!");
			});
		} catch (err) {
			clog.error(err);
			show.error("字幕搜索失败: " + (err instanceof Error ? err.message : String(err)));
		}
	}
	async function previewSubtitle(url, filename) {
		if (!url) {
			clog.error("未提供文件URL");
			return;
		}
		const ext = url.split(".").pop().toLowerCase();
		if (ext === "ass" || ext === "srt") try {
			const subtitleContent = await gmHttp.get(url);
			let title = "字幕预览";
			if (ext === "ass") title = "ASS字幕预览 - " + filename;
			else if (ext === "srt") title = "SRT字幕预览 - " + filename;
			const lines = subtitleContent.split("\n");
			let output = "";
			const numWidth = String(lines.length).length;
			lines.forEach((line, idx) => {
				const paddedNum = String(idx + 1).padStart(numWidth, " ");
				output += jsxToString((0, import_jsx_runtime.jsx)(SubtitleLine, {
					paddedNum,
					line
				}));
			});
			const htmlContent = output;
			layer.open({
				type: 1,
				title,
				area: ["80%", "80%"],
				scrollbar: false,
				content: jsxToString((0, import_jsx_runtime.jsx)(SubtitlePreviewDialog, { content: htmlContent })),
				btn: ["下载", "关闭"],
				btn1: function(_index, _layero, _instance) {
					utils.download(subtitleContent, filename);
					return false;
				}
			});
		} catch (err) {
			show.error(`预览失败: ${err instanceof Error ? err.message : String(err)}`);
			clog.error("预览字幕文件出错:", err);
		}
		else show.error("仅支持预览ASS和SRT字幕文件");
	}
	function waitForDomChange(selector, ms) {
		return new Promise((resolve) => {
			const start = Date.now();
			const el = document.querySelector(selector);
			if (!el) {
				resolve(null);
				return;
			}
			const before = el.innerHTML;
			const check = () => {
				const cur = document.querySelector(selector);
				if (!cur) {
					resolve(null);
					return;
				}
				if (cur.innerHTML !== before) {
					resolve(cur);
					return;
				}
				if (Date.now() - start > ms) {
					resolve(cur);
					return;
				}
				setTimeout(check, 200);
			};
			setTimeout(check, 200);
		});
	}
	function waitForEl(fn, ms) {
		return new Promise((resolve) => {
			const start = Date.now();
			const check = () => {
				const el = fn();
				if (el) {
					resolve(el);
					return;
				}
				if (Date.now() - start > ms) {
					resolve(null);
					return;
				}
				setTimeout(check, 150);
			};
			check();
		});
	}
	var wrapperStyle$1 = {
		margin: "10px auto",
		display: "flex",
		justifyContent: "space-between",
		alignItems: "center",
		flexWrap: "wrap",
		gap: "20px"
	};
	var rowStyle = {
		display: "flex",
		gap: "10px",
		flexWrap: "wrap"
	};
	function statusBtnStyle(width, backgroundColor) {
		return {
			width,
			backgroundColor,
			color: "white",
			textAlign: "center",
			padding: "8px 0"
		};
	}
	function DetailMenuButtons({ filterText, filterColor, favoriteText, favoriteColor, watchedText, watchedColor, showMagnetSearch }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: wrapperStyle$1,
			children: [(0, import_jsx_runtime.jsxs)("div", {
				className: "jhs-menu-status-row",
				style: rowStyle,
				children: [
					(0, import_jsx_runtime.jsx)("a", {
						id: "filterBtn",
						className: "jhs-toolbar-menu-btn",
						style: statusBtnStyle("120px", filterColor),
						children: (0, import_jsx_runtime.jsx)("span", { children: filterText })
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "favoriteBtn",
						className: "jhs-toolbar-menu-btn",
						style: statusBtnStyle("120px", favoriteColor),
						children: (0, import_jsx_runtime.jsx)("span", { children: favoriteText })
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "hasWatchBtn",
						className: "jhs-toolbar-menu-btn",
						style: statusBtnStyle("120px", watchedColor),
						children: (0, import_jsx_runtime.jsx)("span", { children: watchedText })
					})
				]
			}), (0, import_jsx_runtime.jsxs)("div", {
				className: "jhs-menu-tools-row",
				style: rowStyle,
				children: [
					(0, import_jsx_runtime.jsx)("a", {
						id: "enable-magnets-filter",
						className: "jhs-toolbar-menu-btn",
						style: {
							width: "140px",
							backgroundColor: "#c2bd4c",
							color: "white",
							textAlign: "center",
							padding: "8px 0"
						},
						children: (0, import_jsx_runtime.jsx)("span", {
							id: "magnets-span",
							children: "关闭磁力过滤"
						})
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "xunLeiSubtitleBtn",
						className: "jhs-toolbar-menu-btn",
						style: {
							width: "120px",
							background: "linear-gradient(to left, #375f7c, #2196F3)",
							color: "white",
							textAlign: "center",
							padding: "8px 0"
						},
						children: (0, import_jsx_runtime.jsx)("span", { children: "字幕 (迅雷)" })
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "search-subtitle-btn",
						className: "jhs-toolbar-menu-btn",
						style: {
							width: "160px",
							background: "linear-gradient(to bottom, #8d5656, rgb(196,159,91))",
							color: "white",
							textAlign: "center",
							padding: "8px 0"
						},
						children: (0, import_jsx_runtime.jsx)("span", { children: "字幕 (SubTitleCat)" })
					}),
					showMagnetSearch && (0, import_jsx_runtime.jsx)("a", {
						id: "magnetSearchBtn",
						className: "jhs-toolbar-menu-btn",
						style: {
							width: "120px",
							background: "linear-gradient(to right, rgb(245,140,1), rgb(84,161,29))",
							color: "white",
							textAlign: "center",
							padding: "8px 0"
						},
						children: (0, import_jsx_runtime.jsx)("span", { children: "磁力搜索" })
					})
				]
			})]
		});
	}
	function MagnetHubMountBox() {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "magnet-hub-mount",
			style: { padding: "10px" }
		});
	}
	var DetailPageButtonPlugin = class extends BasePlugin {
		_wantWatchedObserved = false;
		_lastWantState = null;
		_wantWatchedSyncing = false;
		_wantWatchedDebounce = null;
		_wantWatchedListenerInstalled = false;
		_quickActionAdded = false;
		_listPanelEnsured = false;
		_listPanelIniting = false;
		_listAjaxTriggered = false;
		_listPanelObserver = null;
		_listPanelSyncTimer = null;
		_listPanelLoadTimer = null;
		_listPanelPaginationPromise = null;
		_listPanelPaginationGeneration = 0;
		_ratingSyncDebounce = null;
		_reviewChain = null;
		getName() {
			return "DetailPageButtonPlugin";
		}
		get pageTypes() {
			return ["detail"];
		}
		async handle() {
			this.hideVideoControls();
			if (window.isDetailPage) {
				this.createMenuBtn();
				this.hookWantAndWatchedButtons();
				this.addQuickActionButtons();
				this.setupWantWatchedSyncListener();
			}
		}
		async createMenuBtn() {
			const carNum = this.getPageInfo().carNum;
			const menuHtml = jsxToString((0, import_jsx_runtime.jsx)(DetailMenuButtons, {
				filterText: BLOCK_TEXT,
				filterColor: BLOCK_COLOR,
				favoriteText: FAVORITE_TEXT,
				favoriteColor: FAVORITE_COLOR,
				watchedText: WATCHED_TEXT,
				watchedColor: WATCHED_COLOR,
				showMagnetSearch: featureFlags.magnetHubPlugin
			}));
			if (isJavdbSite) $(".tabs").after(menuHtml);
			$("#favoriteBtn").on("click", () => this.favoriteOne());
			$("#filterBtn").on("click", (event) => this.filterOne(event));
			$("#hasWatchBtn").on("click", async () => this.hasWatchOne());
			const highlightPlugin = this.getBean("HighlightMagnetPlugin");
			const enableFilter = await storageManager.getSetting("enableMagnetsFilter", "yes");
			$("#magnets-span").text(enableFilter === "yes" ? "关闭磁力过滤" : "开启磁力过滤");
			if (enableFilter === "yes") highlightPlugin.doFilterMagnet();
			$("#enable-magnets-filter").on("click", (_event) => {
				const $span = $("#magnets-span");
				if ($span.text() === "关闭磁力过滤") {
					highlightPlugin.showAll();
					$span.text("开启磁力过滤");
					storageManager.saveSettingItem("enableMagnetsFilter", "no");
				} else {
					highlightPlugin.doFilterMagnet();
					$span.text("关闭磁力过滤");
					storageManager.saveSettingItem("enableMagnetsFilter", "yes");
				}
			});
			$("#search-subtitle-btn").on("click", (event) => utils.openPage(`https://subtitlecat.com/index.php?search=${carNum}`, carNum, false, event));
			$("#xunLeiSubtitleBtn").on("click", () => this.searchXunLeiSubtitle(carNum));
			if (featureFlags.magnetHubPlugin) $("#magnetSearchBtn").on("click", () => {
				const hub = this.getBean("MagnetHubPlugin");
				if (!hub) return;
				layer.open({
					type: 1,
					title: `磁力搜索 - ${carNum}`,
					content: jsxToString((0, import_jsx_runtime.jsx)(MagnetHubMountBox, {})),
					area: utils.getResponsiveArea(["80%", "80%"]),
					success: () => {
						$("#magnet-hub-mount").append(hub.createMagnetHub(carNum ?? ""));
					}
				});
			});
			this.showStatus(carNum).then();
		}
		async showStatus(carNum) {
			const $filterSpan = $("#filterBtn span");
			const $favoriteSpan = $("#favoriteBtn span");
			const $hasWatchSpan = $("#hasWatchBtn span");
			$filterSpan.text(BLOCK_TEXT);
			$favoriteSpan.text(FAVORITE_TEXT);
			$hasWatchSpan.text(WATCHED_TEXT);
			const carRecord = await storageManager.getCar(carNum);
			if (carRecord) switch (carRecord.status) {
				case FILTER_ACTION:
					$filterSpan.text(BLOCKED_TEXT);
					break;
				case FAVORITE_ACTION:
					$favoriteSpan.text(FAVORITED_TEXT);
					break;
				case HAS_WATCH_ACTION: $hasWatchSpan.text("🔍 已标记观看");
			}
		}
		hookWantAndWatchedButtons() {
			hookWantAndWatchedButtons(this);
		}
		detectWantWatchedState(container) {
			return detectWantWatchedState(container);
		}
		async onWantAdded() {
			return onWantAdded(this);
		}
		async onWantRemoved() {
			return onWantRemoved(this);
		}
		async onWatchedAdded() {
			return onWatchedAdded(this);
		}
		async onWatchedRemoved() {
			return onWatchedRemoved(this);
		}
		async removeCarIfStatus(carNum, status) {
			return removeCarIfStatus(carNum, status);
		}
		broadcastWantWatchedSync(payload) {
			broadcastWantWatchedSync$1(payload);
		}
		setupWantWatchedSyncListener() {
			setupWantWatchedSyncListener(this);
		}
		refreshItemStatusTag(carNum) {
			refreshItemStatusTag(this, carNum);
		}
		addQuickActionButtons() {
			addQuickActionButtons(this);
		}
		_buildRatingBar(nav) {
			buildRatingBar(this, nav);
		}
		_injectRatingStyles() {
			injectRatingStyles();
		}
		_syncRatingBar() {
			syncRatingBar(this);
		}
		_setRatingBusy(busy) {
			setRatingBusy(busy);
		}
		async quickSetHasWatch(score) {
			return quickSetHasWatch(this, score);
		}
		async quickBlock() {
			return quickBlock(this);
		}
		async quickConvertToFav() {
			return quickConvertToFav(this);
		}
		async _triggerJavdbReview(score) {
			return triggerJavdbReview(this, score);
		}
		async _triggerJavdbWant() {
			return triggerJavdbWant(this);
		}
		_ensureListPanel(nav) {
			ensureListPanel(this, nav);
		}
		_bindListPanelControls(panel) {
			bindListPanelControls(this, panel);
		}
		_forwardListPanelChange(panel, displayInput) {
			forwardListPanelChange(this, panel, displayInput);
		}
		_initListPanel(forceReload = false) {
			initListPanel(this, forceReload);
		}
		_syncListPanelInputState(sourceInput) {
			syncListPanelInputState(this, sourceInput);
		}
		_updateListPanelEntryState(input) {
			updateListPanelEntryState(input);
		}
		_scheduleListPanelSync(delay = 48) {
			scheduleListPanelSync(this, delay);
		}
		_renderListPanel() {
			renderListPanel(this);
		}
		_createListPanelEntry(source) {
			return createListPanelEntry(this, source);
		}
		_applyListPanelView(panel) {
			applyListPanelView(panel);
		}
		_showListPanelLoading(panel) {
			showListPanelLoading(this, panel);
		}
		_showListPanelError(panel, message) {
			showListPanelError(this, panel, message);
		}
		_isListContainerLoaded(container) {
			return isListContainerLoaded(container);
		}
		_startListPanelLoadTimeout(panel) {
			startListPanelLoadTimeout(this, panel);
		}
		_clearListPanelLoadTimeout() {
			clearListPanelLoadTimeout(this);
		}
		_loadAllListPages(panel, container) {
			loadAllListPages(this, panel, container);
		}
		async _fetchAllListPageEntries(videoId) {
			return fetchAllListPageEntries(videoId);
		}
		_showListPanelNotice(panel, message) {
			showListPanelNotice(this, panel, message);
		}
		_clearListPanelNotice(panel) {
			clearListPanelNotice(panel);
		}
		searchXunLeiSubtitle(carNum) {
			searchXunLeiSubtitle(this, carNum);
		}
		async previewSubtitle(url, filename) {
			return previewSubtitle(url, filename);
		}
		_waitForDomChange(selector, ms) {
			return waitForDomChange(selector, ms);
		}
		_waitForEl(fn, ms) {
			return waitForEl(fn, ms);
		}
		async favoriteOne() {
			const pageInfo = this.getPageInfo();
			await storageManager.saveCar({
				carNum: pageInfo.carNum,
				url: pageInfo.url ?? void 0,
				names: pageInfo.actress ?? void 0,
				actionType: FAVORITE_ACTION,
				publishTime: pageInfo.publishTime ?? void 0
			});
			const clr = this.getBean("CarListReaderPlugin");
			if (clr) await clr.waitForPendingPush();
			this.showStatus(pageInfo.carNum).then();
			refresh();
			utils.closePage();
		}
		async hasWatchOne() {
			const pageInfo = this.getPageInfo();
			await storageManager.saveCar({
				carNum: pageInfo.carNum,
				url: pageInfo.url ?? void 0,
				names: pageInfo.actress ?? void 0,
				actionType: HAS_WATCH_ACTION,
				publishTime: pageInfo.publishTime ?? void 0
			});
			const clr = this.getBean("CarListReaderPlugin");
			if (clr) await clr.waitForPendingPush();
			this.showStatus(pageInfo.carNum).then();
			refresh();
			utils.closePage();
		}
		async filterOne(event) {
			if (event) event.preventDefault();
			const pageInfo = this.getPageInfo();
			utils.q(event, `是否屏蔽${pageInfo.carNum}?`, async () => {
				await storageManager.saveCar({
					carNum: pageInfo.carNum,
					url: pageInfo.url ?? void 0,
					names: pageInfo.actress ?? void 0,
					actionType: FILTER_ACTION,
					publishTime: pageInfo.publishTime ?? void 0
				});
				const clr = this.getBean("CarListReaderPlugin");
				if (clr) await clr.waitForPendingPush();
				this.showStatus(pageInfo.carNum).then();
				refresh();
				utils.closePage();
			});
		}
		speedVideo() {
			if ($("#preview-video").is(":visible")) {
				const videoEl = document.getElementById("preview-video");
				if (videoEl) {
					videoEl.muted = false;
					videoEl.controls = false;
					if (videoEl.currentTime + 5 < videoEl.duration) videoEl.currentTime += 5;
					else {
						show.info("预览视频结束, 已回到开头");
						videoEl.currentTime = 1;
					}
				}
				return;
			}
			const $iframe = $("iframe[id^=\"layui-layer-iframe\"]");
			if ($iframe.length > 0) {
				$iframe[0].contentWindow?.postMessage("speedVideo", "*");
				return;
			}
			const $container = $(".preview-video-container");
			if ($container.length > 0) {
				$container[0].click();
				const videoEl = document.getElementById("preview-video");
				if (videoEl) {
					videoEl.currentTime += 5;
					videoEl.muted = false;
				}
			} else $("#javTrailersBtn").click();
		}
		hideVideoControls() {
			$(document).on("mouseenter", "#preview-video", function() {
				$(this).prop("controls", true);
			});
		}
	};
	function parsePositionStyle(positionStyle) {
		if (positionStyle.includes("right")) return {
			right: 0,
			top: "5px"
		};
		return {
			left: 0,
			top: "5px"
		};
	}
	function StatusTagHtml({ text, color, dataTip, positionStyle }) {
		const posStyle = parsePositionStyle(positionStyle);
		return (0, import_jsx_runtime.jsx)("span", {
			className: "tag is-success status-tag",
			"data-tip": dataTip,
			title: "",
			style: {
				marginRight: "5px",
				borderRadius: "10px",
				position: "absolute",
				zIndex: 10,
				backgroundColor: `${color} !important`,
				...posStyle
			},
			children: text
		});
	}
	var STATUS_TAG_CONFIG = {
		IS_FILTERED: {
			text: BLOCKED_TEXT,
			color: BLOCK_COLOR,
			reasonType: "单番号屏蔽",
			isCounted: true,
			countKey: "currentPageFilterCount"
		},
		IS_FAVORITE: {
			text: FAVORITED_TEXT,
			color: FAVORITE_COLOR,
			reasonType: "",
			isCounted: true,
			countKey: "currentPageFavoriteCount"
		},
		IS_HAS_WATCH: {
			text: WATCHED_TEXT,
			color: WATCHED_COLOR,
			reasonType: "",
			isCounted: true,
			countKey: "currentPageHasWatchCount"
		},
		IS_KEYWORD_FILTER: {
			text: "❌ 关键词屏蔽",
			color: "#de3333",
			reasonType: "",
			isCounted: true,
			countKey: "currentPageKeywordFilterCount"
		},
		IS_ACTOR_FILTER: {
			text: "♂️ 男演员屏蔽",
			color: "#b22222",
			reasonType: "",
			isCounted: true,
			countKey: "currentPageActorFilterCount"
		},
		IS_ACTRESS_FILTER: {
			text: "♀️ 女演员屏蔽",
			color: "#cd5c5c",
			reasonType: "",
			isCounted: true,
			countKey: "currentPageActorFilterCount"
		},
		IS_WAIT_CHECK: {
			text: "",
			color: "",
			reasonType: "",
			isCounted: true,
			countKey: "currentPageWaitCheckCount"
		}
	};
	function getStatusTagPositionStyle(tagPosition) {
		return tagPosition === "rightTop" ? "right: 0; top:5px;" : "left: 0; top:5px;";
	}
	function buildStatusTagHtml(variant, text, color, dataTip, positionStyle) {
		return jsxToString((0, import_jsx_runtime.jsx)(StatusTagHtml, {
			variant,
			text,
			color,
			dataTip,
			positionStyle
		}));
	}
	function injectStatusTag($item, tagHtml) {
		const tagsEl = $item.find(".tags");
		if (tagsEl.length) {
			tagsEl.append(tagHtml);
			return;
		}
		const itemTagEl = $item.find(".item-tag");
		if (itemTagEl.length) {
			itemTagEl.append(tagHtml);
			return;
		}
		$item.find(".photo-info > span > div").append(tagHtml);
	}
	function PageCountTable({ readDataTime, assembleDataTime, processPageTime, totalTime, filterCount, favoriteCount, actorFilterCount, keywordFilterCount, hasWatchCount, waitCheckCount, totalCount }) {
		const tableStyle = {
			borderCollapse: "collapse",
			width: "100%"
		};
		const tdStyle = {
			padding: "3px",
			border: "1px solid #ccc"
		};
		const tdBoldStyle = {
			padding: "3px",
			border: "1px solid #ccc",
			fontWeight: "bold"
		};
		return (0, import_jsx_runtime.jsxs)("table", {
			className: "countTable",
			style: tableStyle,
			children: [
				(0, import_jsx_runtime.jsxs)("tr", { children: [(0, import_jsx_runtime.jsx)("td", {
					colSpan: 2,
					style: tdStyle,
					children: readDataTime
				}), (0, import_jsx_runtime.jsx)("td", {
					colSpan: 2,
					style: tdStyle,
					children: assembleDataTime
				})] }),
				(0, import_jsx_runtime.jsxs)("tr", { children: [(0, import_jsx_runtime.jsx)("td", {
					colSpan: 2,
					style: tdStyle,
					children: processPageTime
				}), (0, import_jsx_runtime.jsx)("td", {
					colSpan: 2,
					style: tdStyle,
					children: totalTime
				})] }),
				(0, import_jsx_runtime.jsxs)("tr", { children: [
					(0, import_jsx_runtime.jsx)("td", {
						style: tdBoldStyle,
						children: "项目"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdBoldStyle,
						children: "数量"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdBoldStyle,
						children: "项目"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdBoldStyle,
						children: "数量"
					})
				] }),
				(0, import_jsx_runtime.jsxs)("tr", { children: [
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: "屏蔽单番号"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: (0, import_jsx_runtime.jsx)("strong", { children: filterCount })
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: "收藏"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: (0, import_jsx_runtime.jsx)("strong", { children: favoriteCount })
					})
				] }),
				(0, import_jsx_runtime.jsxs)("tr", { children: [
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: "屏蔽演员"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: (0, import_jsx_runtime.jsx)("strong", { children: actorFilterCount })
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: "屏蔽关键词"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: (0, import_jsx_runtime.jsx)("strong", { children: keywordFilterCount })
					})
				] }),
				(0, import_jsx_runtime.jsxs)("tr", { children: [
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: "已观看"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: (0, import_jsx_runtime.jsx)("strong", { children: hasWatchCount })
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: "待鉴定"
					}),
					(0, import_jsx_runtime.jsx)("td", {
						style: tdStyle,
						children: (0, import_jsx_runtime.jsx)("strong", { children: waitCheckCount })
					})
				] }),
				(0, import_jsx_runtime.jsxs)("tr", { children: [(0, import_jsx_runtime.jsx)("td", {
					style: tdStyle,
					children: (0, import_jsx_runtime.jsx)("strong", { children: "总数" })
				}), (0, import_jsx_runtime.jsx)("td", {
					style: tdStyle,
					children: (0, import_jsx_runtime.jsx)("strong", { children: totalCount })
				})] })
			]
		});
	}
	async function renderItemStatusTag(item, carNum) {
		try {
			const $item = $(item);
			const carInfo = await storageManager.getCar(carNum);
			const status = carInfo ? carInfo.status : "";
			$item.find(".status-tag").remove();
			let tagConfig = null;
			if (status === "favorite") tagConfig = STATUS_TAG_CONFIG.IS_FAVORITE;
			else if (status === "hasWatch") tagConfig = STATUS_TAG_CONFIG.IS_HAS_WATCH;
			else if (status === "filter") tagConfig = STATUS_TAG_CONFIG.IS_FILTERED;
			if (!tagConfig || !tagConfig.text) return;
			const positionStyle = getStatusTagPositionStyle((await storageManager.getSetting()).tagPosition || "rightTop");
			injectStatusTag($item, buildStatusTagHtml("render", tagConfig.text, tagConfig.color, tagConfig.reasonType, positionStyle));
		} catch (err) {
			clog.error("[JHS-想看/观看] renderItemStatusTag 失败", err);
		}
	}
	async function filterMovieList(plugin, itemEls) {
		utils.time("累计耗费时间");
		utils.time("读取数据耗时");
		const [carList, titleFilterKeywords, blacklist, blacklistCarList, setting] = await Promise.all([
			storageManager.getCarList(),
			storageManager.getTitleFilterKeyword(),
			storageManager.getBlacklist(),
			storageManager.getBlacklistCarList(),
			storageManager.getSetting()
		]);
		const readDataTime = utils.time("读取数据耗时");
		const useLower = featureFlags.caseInsensitiveCarNum;
		const statusCarSets = carList.reduce((acc, car) => {
			const status = car.status ?? "";
			if (Object.prototype.hasOwnProperty.call(acc, status)) acc[status].add(useLower ? car.carNum.toLowerCase() : car.carNum);
			return acc;
		}, {
			[FILTER_ACTION]: new Set(),
			[FAVORITE_ACTION]: new Set(),
			[HAS_WATCH_ACTION]: new Set()
		});
		utils.time("组装数据耗时");
		const blacklistRoleMap = new Map(blacklist.map((item) => [item.starId, item.role]));
		const { actorCarNumToNameMap, actressCarNumToNameMap } = blacklistCarList.reduce((acc, item) => {
			const role = blacklistRoleMap.get(item.starId);
			if (!role) {
				clog.error("黑名单数据源丢失演员信息", item);
				return acc;
			}
			const targetMap = role === "actor" ? acc.actorCarNumToNameMap : acc.actressCarNumToNameMap;
			if (!targetMap.has(item.carNum)) targetMap.set(item.carNum, item.names);
			return acc;
		}, {
			actorCarNumToNameMap: new Map(),
			actressCarNumToNameMap: new Map()
		});
		const assembleDataTime = utils.time("组装数据耗时");
		const showFilterItem = setting?.showFilterItem ?? "no";
		const showFilterActorItem = setting?.showFilterActorItem ?? "no";
		const showFilterKeywordItem = setting?.showFilterKeywordItem ?? "no";
		const showFavoriteItem = setting?.showFavoriteItem ?? "yes";
		const showHasWatchItem = setting?.showHasWatchItem ?? "yes";
		const showAllItem = setting?.showAllItem ?? "no";
		const tagPosition = setting?.tagPosition || "rightTop";
		const movieShowType = featureFlags.movieShowTypeVisibility ? setting?.movieShowType || "hide" : "hide";
		plugin.currentPageFilterCount = 0;
		plugin.currentPageFavoriteCount = 0;
		plugin.currentPageHasWatchCount = 0;
		plugin.currentPageKeywordFilterCount = 0;
		plugin.currentPageActorFilterCount = 0;
		plugin.currentPageWaitCheckCount = 0;
		plugin.currentPageTotalCount = 0;
		utils.time("处理页面耗时");
		await Promise.all(itemEls.map(async (itemEl) => {
			const $item = $(itemEl);
			const { carNum, title } = plugin.findCarNumAndHref($item);
			const { filter: filterSet, favorite: favoriteSet, hasWatch: hasWatchSet } = statusCarSets;
			const lookupCarNum = useLower ? carNum.toLowerCase() : carNum;
			const lowerTitle = useLower ? (title || "").toLowerCase() : title || "";
			const isFavorite = favoriteSet.has(lookupCarNum);
			const isHasWatch = hasWatchSet.has(lookupCarNum);
			const isFiltered = filterSet.has(lookupCarNum);
			const isActorBlacklist = actorCarNumToNameMap.has(carNum);
			const isActressBlacklist = actressCarNumToNameMap.has(carNum);
			const isBlacklistActor = isActorBlacklist || isActressBlacklist;
			const matchedKeyword = titleFilterKeywords.find((keyword) => {
				if (useLower) return lowerTitle.includes(keyword.toLowerCase()) || lookupCarNum.startsWith(keyword.toLowerCase());
				return title.includes(keyword) || carNum.startsWith(keyword);
			});
			const hasKeywordMatch = !!matchedKeyword;
			if (!isSearchOrUserPage) {
				let shouldHide = showFavoriteItem === "no" && isFavorite || showHasWatchItem === "no" && isHasWatch || showFilterItem === "no" && isFiltered && !isFavorite && !isHasWatch || showFilterActorItem === "no" && isBlacklistActor || showFilterKeywordItem === "no" && hasKeywordMatch;
				if ($item.attr("data-movieShowType") !== movieShowType) {
					$item.css("border", "");
					$item.children().css("visibility", "");
					$item.removeAttr("data-hide");
					$item.show();
				}
				const isHidden = $item.attr("data-hide") === "yes";
				if (showAllItem === "yes") shouldHide = false;
				if (shouldHide !== isHidden) {
					if (shouldHide) $item.attr("data-hide", "yes");
					else $item.removeAttr("data-hide");
					if (movieShowType === "hide") if (shouldHide) $item.hide();
					else $item.show();
					else if (movieShowType === "visibility") {
						const borderStyle = shouldHide ? "1px solid rgb(192 176 176)" : "none";
						const visibilityValue = shouldHide ? "hidden" : "visible";
						$item.css("border", borderStyle);
						$item.children().css("visibility", visibilityValue);
					} else throw new Error("movieShowType值有误:" + movieShowType);
					if ($item.attr("data-movieShowType") !== movieShowType) $item.attr("data-movieShowType", movieShowType);
				}
			}
			let tagConfig = STATUS_TAG_CONFIG.IS_WAIT_CHECK;
			let reasonText = null;
			if (isFiltered) tagConfig = STATUS_TAG_CONFIG.IS_FILTERED;
			else if (isFavorite) tagConfig = STATUS_TAG_CONFIG.IS_FAVORITE;
			else if (isHasWatch) tagConfig = STATUS_TAG_CONFIG.IS_HAS_WATCH;
			else if (hasKeywordMatch) {
				tagConfig = STATUS_TAG_CONFIG.IS_KEYWORD_FILTER;
				reasonText = matchedKeyword || "未知";
			} else if (isActorBlacklist) {
				tagConfig = STATUS_TAG_CONFIG.IS_ACTOR_FILTER;
				reasonText = actorCarNumToNameMap.get(carNum) || "";
			} else if (isActressBlacklist) {
				tagConfig = STATUS_TAG_CONFIG.IS_ACTRESS_FILTER;
				reasonText = actressCarNumToNameMap.get(carNum) || "";
			}
			reasonText ||= tagConfig.reasonType;
			if (tagConfig.isCounted) plugin[tagConfig.countKey]++;
			plugin.currentPageTotalCount++;
			$item.find(".status-tag").remove();
			const positionStyle = getStatusTagPositionStyle(tagPosition);
			if (tagConfig.text) {
				const tagHtml = buildStatusTagHtml("filter", tagConfig.text, tagConfig.color, reasonText, positionStyle);
				if (isJavdbSite) $item.find(".tags").append(tagHtml);
			}
			await plugin.translate($item);
		}));
		const processPageTime = utils.time("处理页面耗时");
		const totalTime = utils.time("累计耗费时间");
		$("#waitDownBtn span").text(`打开已收藏 (${statusCarSets.favorite.size})`);
		clog.log(jsxToString((0, import_jsx_runtime.jsx)(PageCountTable, {
			readDataTime: readDataTime ?? "",
			assembleDataTime: assembleDataTime ?? "",
			processPageTime: processPageTime ?? "",
			totalTime: totalTime ?? "",
			filterCount: plugin.currentPageFilterCount,
			favoriteCount: plugin.currentPageFavoriteCount,
			actorFilterCount: plugin.currentPageActorFilterCount,
			keywordFilterCount: plugin.currentPageKeywordFilterCount,
			hasWatchCount: plugin.currentPageHasWatchCount,
			waitCheckCount: plugin.currentPageWaitCheckCount,
			totalCount: plugin.currentPageTotalCount
		})));
	}
	async function translateText(text, sourceLang = "ja", targetLang = "zh-CN") {
		if (!text) throw new Error("翻译文本不能为空");
		const url = "https://translate-pa.googleapis.com/v1/translate?" + new URLSearchParams({
			"params.client": "gtx",
			dataTypes: "TRANSLATION",
			key: "AIzaSyDLEeFI5OtFBwYBIoK_jj5m32rZK5CkCXA",
			"query.sourceLanguage": sourceLang,
			"query.targetLanguage": targetLang,
			"query.text": text
		});
		const controller = new AbortController();
		const timeoutId = setTimeout(() => controller.abort(), 1e4);
		try {
			const response = await fetch(url, { signal: controller.signal });
			if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
			return (await response.json()).translation;
		} finally {
			clearTimeout(timeoutId);
		}
	}
	function replaceTitleTextNodes($videoTitle, newText, excludeCarNum) {
		$videoTitle.contents().each((_index, node) => {
			if (node.nodeType === 3 && node.textContent.trim() !== "" && (excludeCarNum === void 0 || !node.textContent.includes(excludeCarNum))) node.textContent = " " + newText + " ";
		});
	}
	function findCarNumAndHref($item) {
		let carNum;
		let title;
		let publishTime;
		const linkEl = $item.find("a");
		const aHref = linkEl.attr("href");
		const videoTitleEl = $item.find(".video-title");
		if (videoTitleEl.length > 0) {
			const strongEl = videoTitleEl.find("strong");
			if (strongEl.length > 0) carNum = strongEl.text().trim();
			title = linkEl.attr("title") ? linkEl.attr("title").trim() : carNum ? videoTitleEl.text().replace(carNum, "").trim() : videoTitleEl.text().trim();
			publishTime = $item.find(".meta").text().trim();
		}
		if (!carNum) {
			const imgEl = $item.find("img");
			if (aHref && imgEl.length > 0) title = imgEl.attr("title")?.trim() || imgEl.attr("data-title")?.trim();
			const isDate = (val) => /^\d{4}-\d{1,2}-\d{1,2}$/.test(val);
			publishTime = $item.find("date").map((_index, el) => $(el).text().trim()).get().find(isDate);
			carNum = $item.find("date").map((_index, el) => $(el).text().trim()).get().find((val) => !isDate(val));
		}
		if (!carNum) failWithToast("提取番号信息失败");
		return {
			carNum,
			aHref: aHref || "",
			url: aHref || "",
			title: title || "",
			publishTime: publishTime || ""
		};
	}
	function replaceHdImg(plugin, imgEls) {
		if (imgEls && typeof imgEls.jquery == "string") imgEls = imgEls.toArray();
		imgEls ||= document.querySelectorAll(plugin.getSelector().coverImgSelector);
		if (isJavdbSite) imgEls.forEach((img) => {
			img.src = img.src.replace("thumbs", "covers");
			img.title = "";
		});
	}
	function showCarNumBox(carNum) {
		const matchedEl = $(".movie-list .item").toArray().find((itemEl) => $(itemEl).find(".video-title strong").text() === carNum);
		if (matchedEl) {
			const $matched = $(matchedEl);
			if ($matched.attr("data-hide") === `${carNum}-hide`) {
				$matched.show();
				$matched.removeAttr("data-hide");
			}
		}
	}
	async function bindClick(plugin) {
		const selectorConfig = plugin.getSelector();
		$(selectorConfig.boxSelector).on("click", ".item .cover", async (event) => {
			event.preventDefault();
			event.stopPropagation();
			if ($(event.target).closest("div.meta-buttons").length) return;
			const $item = $(event.target).closest(".item");
			const { carNum, aHref } = plugin.findCarNumAndHref($item);
			const dialogOpenDetail = await storageManager.getSetting("dialogOpenDetail", "yes");
			if (carNum.includes("FC2-")) {
				const movieId = plugin.parseMovieId(aHref);
				plugin.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carNum, aHref);
			} else if (dialogOpenDetail === "yes") utils.openPage(aHref, carNum, true, event);
			else window.open(aHref, "_blank", "noopener,noreferrer");
		});
		$(selectorConfig.boxSelector).on("click", ".item video", async (event) => {
			const videoEl = event.currentTarget;
			if (videoEl.paused) videoEl.play().catch((err) => clog.error("播放失败:", err));
			else videoEl.pause();
			event.preventDefault();
			event.stopPropagation();
		});
		$(selectorConfig.boxSelector).on("click", ".item .video-title", async (event) => {
			if ($(event.target).closest("[class^=\"jhs-match-\"]").length) return;
			const $item = $(event.currentTarget).closest(".item");
			const { carNum, aHref } = plugin.findCarNumAndHref($item);
			if (carNum.includes("FC2-")) {
				event.preventDefault();
				const movieId = plugin.parseMovieId(aHref);
				plugin.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carNum, aHref);
			}
		});
	}
	async function translate(plugin, $item) {
		if (await storageManager.getSetting("translateTitle", "yes") !== "yes") return;
		let sourceText = "";
		let carNum = "";
		const videoTitleEl = $item.find(".video-title");
		if (isJavdbSite) {
			sourceText = videoTitleEl.contents().filter((_index, node) => node.nodeType === 3 && node.textContent.trim() !== "").text().trim();
			carNum = $item.find(".video-title strong").text().trim();
		}
		if (plugin.cache[carNum]) {
			replaceTitleTextNodes(videoTitleEl, plugin.cache[carNum]);
			videoTitleEl.attr("title", plugin.cache[carNum]);
			return;
		}
		translateText(sourceText).then((translation) => {
			if (isJavdbSite) {
				replaceTitleTextNodes(videoTitleEl, translation, carNum);
				videoTitleEl.attr("title", translation);
			}
			plugin.writeQueue = plugin.writeQueue.then(() => {
				plugin.cache[carNum] = translation;
				localStorage.setItem("jhs_translate", JSON.stringify(plugin.cache));
			});
		}).catch((err) => {
			clog.error("翻译失败:", err);
		});
	}
	async function revertTranslation(plugin) {
		$(plugin.getSelector().itemSelector).toArray().forEach((itemEl) => {
			const $item = $(itemEl);
			const originalTitle = $item.find(".box").attr("title") || $item.find(".video-title").attr("title") || $item.find("img").attr("data-title");
			const carNum = $item.find(".video-title strong").text().trim();
			const videoTitleEl = $item.find(".video-title");
			replaceTitleTextNodes(videoTitleEl, originalTitle, carNum);
			videoTitleEl.removeAttr("title");
		});
	}
	function JumpPageControl({ controlId, value }) {
		return (0, import_jsx_runtime.jsxs)("li", {
			id: controlId,
			children: [(0, import_jsx_runtime.jsx)("input", {
				type: "number",
				id: "jumpPageInput",
				placeholder: "页码",
				min: "1",
				style: {
					width: "60px",
					marginLeft: "10px",
					padding: "10px",
					border: "1px solid #ccc",
					fontSize: "14px"
				},
				value
			}), (0, import_jsx_runtime.jsx)("button", {
				style: {
					marginLeft: "5px",
					padding: "9px 8px",
					cursor: "pointer",
					border: "1px solid #ccc",
					backgroundColor: "#f0f0f0",
					fontSize: "14px"
				},
				children: "跳转"
			})]
		});
	}
	function addJumpPageControl() {
		const controlId = "gemini-jump-page-control";
		if ($("#gemini-jump-page-control").length > 0) return;
		if ($(".pagination-link.is-current").length === 0) return;
		const currentPage = utils.getUrlParam(currentHref, "page") || 1;
		const $li = $(jsxToString((0, import_jsx_runtime.jsx)(JumpPageControl, {
			controlId,
			value: Number(currentPage) + 1
		})));
		$(".pagination-list").append($li);
		const $pageInput = $li.find("#jumpPageInput");
		const $jumpBtn = $li.find("button");
		const jumpToPage = () => {
			const pageNum = parseInt(String($pageInput.val()), 10);
			if (isNaN(pageNum) || pageNum < 1) {
				$pageInput.focus();
				return;
			}
			const url = new URL(window.location.href);
			url.searchParams.set("page", pageNum.toString());
			window.location.href = url.toString();
		};
		$jumpBtn.on("click", jumpToPage);
		$pageInput.on("keypress", (event) => {
			if (event.which === 13) {
				jumpToPage();
				event.preventDefault();
			}
		});
	}
	var ListPagePlugin = class extends BasePlugin {
		currentPageFilterCount = 0;
		currentPageFavoriteCount = 0;
		currentPageHasWatchCount = 0;
		currentPageKeywordFilterCount = 0;
		currentPageActorFilterCount = 0;
		currentPageWaitCheckCount = 0;
		currentPageTotalCount = 0;
		supervisor = new TaskSupervisor();
		cache = (() => {
			try {
				const raw = localStorage.getItem("jhs_translate");
				return raw ? JSON.parse(raw) : {};
			} catch {
				return {};
			}
		})();
		writeQueue = Promise.resolve();
		getName() {
			return "ListPagePlugin";
		}
		destroy() {
			this.supervisor.abort();
		}
		get pageTypes() {
			return ["list"];
		}
		async handle() {
			new BroadcastChannel("channel-refresh").addEventListener("message", async (event) => {
				const msgType = event.data.type;
				if (msgType === "refresh") {
					storageManager.clearCarListCache();
					await this.doFilter();
					const historyPlugin = this.getBean("HistoryPlugin");
					if (historyPlugin.tableObj) historyPlugin.tableObj.setData();
					const newVideoPlugin = this.getBean("NewVideoPlugin");
					if (newVideoPlugin) {
						newVideoPlugin.showNewVideoCount().then();
						newVideoPlugin.loadData();
					}
				} else if (msgType === "cleanCache_filter_actor_actress_car_list") storageManager.clearFilterActorActressCarListCache();
				else if (msgType === "clean_cacheSettingObj") storageManager.clearSettingCache();
			});
			this.replaceHdImg();
			this.addJumpPageControl();
			await this.doFilter();
			this.bindClick().then();
			this.rememberTagExpand();
			$(this.getSelector().itemSelector + " a").attr("target", "_blank");
			this.checkDom();
			this.getBean("DetailPageButtonPlugin").setupWantWatchedSyncListener();
		}
		rememberTagExpand() {
			if (!window.location.href.includes("actors")) return;
			const expandBtn = $(".tag-expand");
			if (expandBtn.length === 0) return;
			const storageKey = "jhs_tag_expand";
			const wasExpanded = localStorage.getItem(storageKey) === "true";
			const contentEl = $(".actor-tags .content");
			if (wasExpanded && contentEl.hasClass("collapse")) expandBtn[0].click();
			expandBtn.on("click", function() {
				const isExpanded = !contentEl.hasClass("collapse");
				localStorage.setItem(storageKey, isExpanded.toString());
			});
		}
		checkDom() {
			if (!window.isListPage) return;
			const selectorConfig = this.getSelector();
			const containerEl = document.querySelector(selectorConfig.boxSelector);
			if (!containerEl) {
				clog.error("没有找到容器节点!");
				return;
			}
			const observerOptions = {
				childList: true,
				subtree: false
			};
			const observer = this.supervisor.observe(containerEl, async () => {
				observer.disconnect();
				try {
					this.replaceHdImg();
					this.addJumpPageControl();
					await this.doFilter();
					await this.getBean("ListPageButtonPlugin").sortItems();
					$(this.getSelector().itemSelector + " a").attr("target", "_blank");
					this.getBean("AutoPagePlugin").checkLoad();
				} finally {
					observer.observe(containerEl, observerOptions);
				}
			}, observerOptions);
		}
		async doFilter() {
			if (!window.isListPage) return;
			const itemEls = $(this.getSelector().itemSelector).toArray();
			if (itemEls.length) await this.filterMovieList(itemEls);
		}
		async parseActressName(url) {
			let actressName = null;
			if (await storageManager.getSetting("enableSaveActressCarInfo", "no") === "yes") {
				clog.debug("鉴定补录演员信息-已启用, 开始解析详情页");
				clog.debug("开始解析演员详情页", url);
				const html = await gmHttp.get(url);
				const $dom = utils.htmlTo$dom(String(html));
				if (isJavdbSite) actressName = $dom.find(".female").prev().map((_index, el) => $(el).text()).get().join(" ");
				clog.debug("解析到名称:", actressName);
			}
			return actressName;
		}
		async renderItemStatusTag(item, carNum) {
			return renderItemStatusTag(item, carNum);
		}
		async filterMovieList(itemEls) {
			return filterMovieList(this, itemEls);
		}
		async translate($item) {
			return translate(this, $item);
		}
		async revertTranslation() {
			return revertTranslation(this);
		}
		findCarNumAndHref($item) {
			return findCarNumAndHref($item);
		}
		replaceHdImg(imgEls) {
			return replaceHdImg(this, imgEls);
		}
		showCarNumBox(carNum) {
			return showCarNumBox(carNum);
		}
		async bindClick() {
			return bindClick(this);
		}
		addJumpPageControl() {
			return addJumpPageControl();
		}
	};
	var DMM_VIDEO_CACHE_KEY = "jhs_dmm_video";
	var DMM_OTHER_SITE_KEY = "jhs_other_site_dmm";
	var DmmPreviewVideoResolver = class {
		carNum;
		showErrorMessages;
		constructor(carNum, showErrorMessages = true) {
			this.carNum = carNum;
			this.showErrorMessages = showErrorMessages;
		}
		_checkCache() {
			const rawCache = localStorage.getItem(DMM_VIDEO_CACHE_KEY);
			const cache = rawCache ? JSON.parse(rawCache) : {};
			if (cache[this.carNum]) {
				clog.debug("缓存中存在预览视频信息", cache[this.carNum]);
				return cache[this.carNum];
			}
			return null;
		}
		_updateCache(videoMap) {
			const rawCache = localStorage.getItem(DMM_VIDEO_CACHE_KEY);
			const cache = rawCache ? JSON.parse(rawCache) : {};
			cache[this.carNum] = videoMap;
			clog.debug("成功解析出预览视频并已缓存:", videoMap);
			localStorage.setItem(DMM_VIDEO_CACHE_KEY, JSON.stringify(cache));
		}
		async _searchContentIds() {
			const carNum = this.carNum;
			const noHyphen = carNum.replace(/-/g, "");
			const candidates = [
				{
					keyword: carNum.replace("-", "00"),
					name: "00-替换关键词"
				},
				{
					keyword: carNum,
					name: "原始番号关键词"
				},
				{
					keyword: noHyphen,
					name: "无连字符关键词"
				}
			];
			const carNumLower = carNum.toLowerCase();
			for (const candidate of candidates) {
				const { keyword, name } = candidate;
				const keywordLower = keyword.toLowerCase();
				clog.debug(`--- 尝试使用 ${name} (${keyword}) 进行 API 搜索 ---`);
				const apiUrl = `https://api.dmm.com/affiliate/v3/ItemList?${new URLSearchParams({
					api_id: "UrwskPfkqQ0DuVry2gYL",
					affiliate_id: "10278-996",
					output: "json",
					site: "FANZA",
					sort: "match",
					keyword
				}).toString()}`;
				let response;
				try {
					response = await gmHttp.get(apiUrl);
				} catch (err) {
					clog.error(`API 请求失败,跳过 ${name}:`, err);
					continue;
				}
				if (!response || !response.result || !response.result.result_count) {
					clog.debug("API 返回无结果,尝试下一个关键词。");
					continue;
				}
				const matched = [];
				for (const item of response.result.items) {
					if (matched.length >= 2) break;
					const contentId = item.content_id || "";
					const makerProduct = item.maker_product || "";
					if (contentId.includes(keywordLower.replace("-", "")) || carNumLower === makerProduct.toLowerCase() || contentId.includes(noHyphen.toLowerCase())) {
						matched.push({
							serviceCode: item.service_code || "",
							floorCode: item.floor_code || "",
							contentId,
							pageUrl: item.URL || ""
						});
						clog.debug(`[${name}] cid|makerProduct 匹配成功:`, contentId, makerProduct);
					}
				}
				if (matched.length > 0) {
					clog.debug(`--- 成功通过 ${name} 找到 Content IDs ---`);
					const $fanzaBtn = $("#fanzaBtn");
					let siteUrl = `https://www.dmm.co.jp/search/=/searchstr=${keyword}`;
					let linkType = "single";
					if (matched.length > 1) {
						$fanzaBtn.attr("href", siteUrl);
						$fanzaBtn.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
						$fanzaBtn.css("backgroundColor", "#7bc73b");
						linkType = "multiple";
					} else {
						siteUrl = matched[0].pageUrl;
						$fanzaBtn.attr("href", siteUrl);
						$fanzaBtn.css("backgroundColor", "#7bc73b");
					}
					const rawOther = localStorage.getItem(DMM_OTHER_SITE_KEY);
					const otherSiteCache = rawOther ? JSON.parse(rawOther) : {};
					otherSiteCache[this.carNum] = {
						type: linkType,
						url: siteUrl
					};
					localStorage.setItem(DMM_OTHER_SITE_KEY, JSON.stringify(otherSiteCache));
					return matched;
				}
				clog.debug(`[${name}] API 返回结果数 ${response.result.result_count},但无精确匹配的 Content ID。`);
			}
			clog.warn("所有关键词尝试均未找到匹配的Content ID, 解析Dmm视频失败");
			const $fanzaBtn = $("#fanzaBtn");
			$fanzaBtn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
			$fanzaBtn.attr("title", "未查询到, 点击前往搜索页");
			$fanzaBtn.css("backgroundColor", "#de3333");
			return null;
		}
		async _extractTrailerLinks({ contentId, serviceCode, floorCode }) {
			const playerUrl = `https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=${contentId}/mtype=AhRVShI_/service=${serviceCode}/floor=${floorCode}/mode=/`;
			const html = await gmHttp.get(playerUrl, void 0, {
				"accept-language": "ja-JP,ja;q=0.9",
				Cookie: "age_check_done=1"
			});
			if (typeof html != "string") {
				clog.error(html);
				throw new Error("解析播放页内容失败, 非文本内容");
			}
			if (html.includes("このサービスはお住まいの地域からは")) throw new Error("节点不可用,请将DMM域名分流到日本ip");
			const argsMatch = html.match(/const\s+args\s+=\s+(.*);/);
			if (!argsMatch) throw new Error("未在脚本中找到 const args = ... 变量");
			let bitrates;
			try {
				({bitrates} = JSON.parse(argsMatch[1]));
			} catch (err) {
				throw new Error(`解析播放器脚本 JSON 失败: ${err.message}`);
			}
			const videoMap = {};
			const qualityPattern = VIDEO_QUALITY_LIST.map((opt) => opt.quality).join("|");
			const qualityRegex = new RegExp(`(${qualityPattern})\\.mp4$`);
			if (!Array.isArray(bitrates)) {
				clog.error("解析画质链接失败: bitrates 字段不是一个数组或不存在");
				throw new Error("解析画质链接失败: bitrates 字段不是一个数组或不存在");
			}
			clog.debug("原始数据返回:", bitrates);
			for (const item of bitrates) {
				const src = item == null ? void 0 : item.src;
				if (!src || typeof src != "string" || !src.endsWith(".mp4")) continue;
				const qualityMatch = src.match(qualityRegex);
				let quality = "";
				if (qualityMatch && qualityMatch[1]) quality = qualityMatch[1];
				if (quality && !videoMap[quality]) videoMap[quality] = src;
			}
			if (Object.keys(videoMap).length === 0) throw new Error("未找到匹配要求的预览画质视频");
			return videoMap;
		}
		async fetchVideo() {
			const cached = this._checkCache();
			if (cached) return cached;
			let contentIds;
			try {
				const carNumLower = this.carNum.toLowerCase();
				if (carNumLower.startsWith("heyzo") || /^(n\d+|\d+(-\d+)*)$/.test(carNumLower) || /^n\d+$/.test(carNumLower)) throw new Error("无码番号类型, 取消dmm解析");
				if (this.carNum.includes("VR-")) throw new Error("VR类型, 取消dmm解析");
				contentIds = await this._searchContentIds();
			} catch (err) {
				clog.error("DMM API 搜索失败:", err);
				const $fanzaBtn = $("#fanzaBtn");
				$fanzaBtn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
				$fanzaBtn.attr("title", "未查询到, 点击前往搜索页");
				$fanzaBtn.css("backgroundColor", "#de3333");
				return null;
			}
			if (!contentIds || contentIds.length === 0) return null;
			try {
				const videoMap = await Promise.any(contentIds.map((id) => this._extractTrailerLinks(id)));
				this._updateCache(videoMap);
				return videoMap;
			} catch (err) {
				const errors = err && typeof err === "object" && "errors" in err && Array.isArray(err.errors) ? err.errors : [err];
				if (errors.some((e) => e instanceof Error && e.message.includes("节点不可用"))) {
					if (this.showErrorMessages) show.error("节点不可用,请将DMM域名分流到日本ip");
				} else {
					const first = errors[0];
					const firstMsg = first instanceof Error && first.message ? first.message : first;
					clog.error(`解析失败: ${firstMsg}`, errors);
					if (this.showErrorMessages) show.error(`解析失败: ${firstMsg}`);
				}
				const $fanzaBtn = $("#fanzaBtn");
				$fanzaBtn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
				$fanzaBtn.attr("title", "未查询到, 点击前往搜索页");
				$fanzaBtn.css("backgroundColor", "#de3333");
				return null;
			}
		}
	};
	var fetchDmmPreviewVideo = async (carNum, showErrorMessages = true) => new DmmPreviewVideoResolver(carNum, showErrorMessages).fetchVideo();
	var selectAvailableVideoQuality = (available, desired) => {
		if (!available || available.length === 0) return null;
		const availableSet = new Set(available);
		if (availableSet.has(desired)) return desired;
		const descending = VIDEO_QUALITY_LIST.map((opt) => opt.quality).reverse();
		for (const quality of descending) if (availableSet.has(quality)) return quality;
		return available[0];
	};
	function PreviewVideoActionBtn({ id, color, label }) {
		return (0, import_jsx_runtime.jsx)("button", {
			className: "jhs-toolbar-menu-btn",
			id,
			style: {
				minWidth: "120px",
				backgroundColor: color
			},
			children: label
		});
	}
	function PreviewVideoQualityBtn({ opt, src, isActive }) {
		return (0, import_jsx_runtime.jsx)("button", {
			className: `video-control-btn${isActive ? " active" : ""}`,
			id: opt.id,
			"data-quality": opt.quality,
			"data-video-src": src,
			style: {
				minWidth: "40px",
				border: "1px solid #ccc",
				backgroundColor: isActive ? "#007bff" : "#fff",
				color: isActive ? "white" : "black"
			},
			children: opt.text
		});
	}
	var VIDEO_MUTED_KEY = "jhs_videoMuted";
	async function buildVideoToolbar(plugin) {
		const $video = $("#preview-video");
		if (!$video.length) return;
		const $videoWrap = $video.parent();
		$videoWrap.css("position", "relative");
		const videoEl = $video[0];
		const mutedStored = localStorage.getItem(VIDEO_MUTED_KEY);
		if (mutedStored) videoEl.muted = mutedStored === "yes";
		videoEl.addEventListener("volumechange", () => {
			localStorage.setItem(VIDEO_MUTED_KEY, videoEl.muted ? "yes" : "no");
		});
		videoEl.play();
		const carNum = plugin.getPageInfo().carNum;
		const videoMap = await fetchDmmPreviewVideo(carNum);
		const $toolbar = $("<div></div>").attr("id", "video-bottom-toolbar").css({
			display: "flex",
			gap: "5px",
			"align-items": "center",
			"flex-wrap": "wrap"
		});
		const $qualityGroup = $("<div></div>").css({
			display: "flex",
			gap: "5px",
			"align-items": "center"
		});
		let currentQuality = null;
		if (videoMap) {
			const desiredQuality = await storageManager.getSetting("videoQuality");
			currentQuality = selectAvailableVideoQuality(Object.keys(videoMap), desiredQuality);
			const currentUrl = videoMap[currentQuality];
			if ($video.attr("src") !== currentUrl) {
				$video.attr("src", currentUrl);
				videoEl.load();
				videoEl.play();
			}
			VIDEO_QUALITY_LIST.forEach((opt) => {
				const src = videoMap[opt.quality];
				if (src) {
					const isActive = currentQuality === opt.quality;
					const $btn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoQualityBtn, {
						opt,
						src,
						isActive
					})));
					$qualityGroup.append($btn);
				}
			});
		}
		$toolbar.append($qualityGroup);
		const $actionGroup = $("<div></div>").css({
			display: "flex",
			gap: "5px",
			"align-items": "center",
			"margin-left": "auto"
		});
		const $filterBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
			id: "video-filterBtn",
			color: "#de3333",
			label: "屏蔽"
		})));
		$actionGroup.append($filterBtn);
		const $favoriteBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
			id: "video-favoriteBtn",
			color: "#25b1dc",
			label: "收藏"
		})));
		$actionGroup.append($favoriteBtn);
		const $speedBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
			id: "speed-btn",
			color: "#76b45d",
			label: "快进"
		})));
		$actionGroup.append($speedBtn);
		$toolbar.append($actionGroup);
		$videoWrap.append($toolbar);
		$toolbar.on("click", ".video-control-btn", async (event) => {
			const $btn = $(event.currentTarget);
			const src = $btn.data("video-src");
			if (!$btn.hasClass("active")) try {
				const currentTime = videoEl.currentTime;
				$video.attr("src", src);
				videoEl.load();
				videoEl.currentTime = currentTime;
				await videoEl.play();
				$toolbar.find(".video-control-btn").removeClass("active").css({
					"background-color": "#fff",
					color: "black"
				});
				$btn.addClass("active").css({
					"background-color": "#007bff",
					color: "white"
				});
			} catch (err) {
				console.error("切换画质失败:", err);
			}
		});
		$("#speed-btn").on("click", () => {
			plugin.getBean("DetailPageButtonPlugin").speedVideo();
		});
		utils.rightClick(document.body, "#speed-btn", (event) => {
			plugin.getBean("DetailPageButtonPlugin").filterOne(event);
		});
		$("#video-filterBtn").on("click", (event) => {
			plugin.getBean("DetailPageButtonPlugin").filterOne(event);
		});
		$("#video-favoriteBtn").on("click", () => {
			plugin.getBean("DetailPageButtonPlugin").favoriteOne();
		});
	}
	function PreviewVideoContainer({ coverSrc }) {
		return (0, import_jsx_runtime.jsxs)("a", {
			className: "preview-video-container",
			"data-fancybox": "gallery",
			href: "#preview-video",
			children: [(0, import_jsx_runtime.jsx)("span", { children: "預告片" }), (0, import_jsx_runtime.jsx)("img", {
				src: coverSrc,
				className: "video-cover",
				style: {
					width: "150px",
					height: "auto"
				},
				alt: ""
			})]
		});
	}
	var preview_video_plugin_default = ".video-control-btn {\n    min-width: 120px;\n    padding: 7px 12px;\n    font-size: 12px;\n    background: rgb(0, 0, 0, 0.7);\n    color: white;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\n}\n\n.video-control-btn.active {\n    background-color: #1890ff;\n    color: white;\n    font-weight: bold;\n    border: 2px solid #096dd9;\n}\n";
	var PreviewVideoPlugin = class extends BasePlugin {
		getName() {
			return "PreviewVideoPlugin";
		}
		async initCss() {
			return preview_video_plugin_default;
		}
		async handle() {
			if (!window.isDetailPage) return;
			const $container = $(".preview-video-container");
			$container.on("click", () => {
				utils.loopDetector(() => $(".fancybox-content #preview-video").length > 0, () => {
					this.handleVideo().then();
				});
			});
			if (!currentHref.includes("autoPlay=1")) this.initDmm().then();
			const href = window.location.href;
			if (href.includes("gallery-1") || href.includes("gallery-2")) utils.loopDetector(() => $(".fancybox-content #preview-video").length > 0, () => {
				if ($(".fancybox-content #preview-video").length > 0) this.handleVideo().then();
			});
			if (href.includes("autoPlay=1") && $container.length > 0) $container[0].click();
		}
		async initDmm() {
			try {
				const videoMap = await fetchDmmPreviewVideo(this.getPageInfo().carNum, false);
				if (!videoMap) return;
				const desiredQuality = await storageManager.getSetting("videoQuality");
				clog.debug("解析其它画质预览视频", "设置-期望画质", desiredQuality);
				const videoUrl = videoMap[selectAvailableVideoQuality(Object.keys(videoMap), desiredQuality)];
				clog.log("切换其它画质预览视频: ", videoUrl);
				const $video = $("#preview-video");
				const videoEl = $video.length ? $video[0] : null;
				const isHidden = !videoEl || utils.isHidden($video);
				if ($video.length) {
					if (videoEl) {
						const currentTime = videoEl.currentTime;
						$video.attr("src", videoUrl);
						if (!isHidden) {
							clog.debug("播放器已手动打开, 变更进度条");
							videoEl.currentTime = currentTime;
							videoEl.play();
						}
					}
				} else {
					clog.debug("JavDB没有视频播放元素, 开始创建...");
					const coverSrc = $(".column-video-cover img").attr("src");
					$(".preview-images").prepend(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoContainer, { coverSrc: coverSrc ?? "" })));
					$(".preview-video-container").on("click", () => {
						utils.loopDetector(() => $(".fancybox-content #preview-video").length > 0, async () => {
							await this.handleVideo();
						});
					});
				}
			} catch (err) {
				clog.error("预加载dmm失败:", err);
			}
		}
		async handleVideo() {
			await buildVideoToolbar(this);
		}
	};
	var RatingRenderer = {
		hideNativeBadge(cover) {
			cover.querySelectorAll(":scope > span").forEach((s) => {
				if (s.classList.length === 0 || s.className === "score") s.style.display = "none";
			});
		},
		showPlaceholder(item) {
			const cover = item.querySelector(".cover");
			if (!cover) return;
			if (cover.querySelector(".jhs-user-rating")) return;
			this.hideNativeBadge(cover);
			const el = document.createElement("div");
			el.className = "jhs-user-rating is-placeholder";
			el.textContent = "已看";
			el.title = "已看(悬停加载评分)";
			cover.appendChild(el);
		},
		showRating(item, rating) {
			const cover = item.querySelector(".cover");
			if (!cover) return;
			let el = cover.querySelector(".jhs-user-rating");
			if (!el) {
				this.hideNativeBadge(cover);
				el = document.createElement("div");
				el.className = "jhs-user-rating";
				cover.appendChild(el);
			}
			el.className = "jhs-user-rating";
			el.innerHTML = "";
			if (rating === 0) {
				el.classList.add("is-rated");
				el.innerHTML = jsxToString((0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("span", {
					className: "jhs-rd-icon",
					children: "★"
				}), (0, import_jsx_runtime.jsx)("span", {
					className: "jhs-rd-num",
					children: "0"
				})] }));
				el.title = "已看 · 0/5 星(未评分)";
			} else if (rating && rating >= 1 && rating <= 5) {
				el.classList.add("is-rated");
				el.innerHTML = jsxToString((0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("span", {
					className: "jhs-rd-icon",
					children: "★"
				}), (0, import_jsx_runtime.jsx)("span", {
					className: "jhs-rd-num",
					children: rating
				})] }));
				el.title = `已看 · ${rating}/5 星`;
			} else {
				el.classList.add("is-placeholder");
				el.textContent = "已看";
				el.title = "已看(未评分)";
			}
		},
		removeFrom(item) {
			const el = item?.querySelector(".jhs-user-rating");
			if (el) el.remove();
			const cover = item?.querySelector(".cover");
			if (cover) cover.querySelectorAll(":scope > span").forEach((s) => {
				if (s.style.display === "none" && (s.classList.length === 0 || s.className === "score")) s.style.display = "";
			});
		}
	};
	var RATING_CONFIG = {
		DEBUG_MODE: false,
		IDB_NAME: "JAV-JHS",
		IDB_STORE: "appData",
		CAR_LIST_KEY: "car_list",
		RATING_CACHE_KEY: "jdb:rating_cache_v2",
		IDB_RATING_KEY: "jhsRatingDisplay_data",
		ITEM_SELECTOR: ".movie-list .item, .is-user-page .column.is-one-quarter",
		HOVER_DELAY: 500,
		FETCH_CONCURRENCY: 3,
		FETCH_TIMEOUT: 8e3,
		FETCH_RETRY: 1
	};
	var parser = new DOMParser();
	function log(action, ...args) {
		if (RATING_CONFIG.DEBUG_MODE) console.log(`%c[JHS-Rating][${action}]`, "color:#fff;background:#ffc107;padding:2px 4px;border-radius:2px;", ...args);
	}
	function debounce(fn, wait) {
		let timer;
		return function(...args) {
			clearTimeout(timer);
			timer = setTimeout(() => fn.apply(this, args), wait);
		};
	}
	function createLimiter(max) {
		let active = 0;
		const queue = [];
		const runNext = () => {
			if (active >= max || queue.length === 0) return;
			active++;
			const job = queue.shift();
			Promise.resolve().then(job.fn).then(job.resolve).catch(job.reject).finally(() => {
				active--;
				runNext();
			});
		};
		return { run(fn) {
			return new Promise((resolve, reject) => {
				queue.push({
					fn,
					resolve,
					reject
				});
				runNext();
			});
		} };
	}
	function getSafeUrl(url, base = window.location.origin) {
		if (!url) return "";
		try {
			if (url.startsWith("http")) return url;
			if (url.startsWith("//")) return "https:" + url;
			return new URL(url, base).href;
		} catch {
			return url;
		}
	}
	function normalizeCode(raw) {
		if (!raw) return "";
		return raw.trim().toUpperCase().replace(/\s+/g, "-");
	}
	function getCode(item) {
		if (item.dataset.code) return item.dataset.code;
		const code = normalizeCode(item.querySelector(".video-title strong")?.textContent || "");
		if (code) item.dataset.code = code;
		return code;
	}
	function getAnchor(item) {
		return item?.querySelector("a.box, .box a") ?? null;
	}
	var RatingUtils = {
		parser,
		log,
		debounce,
		createLimiter,
		getSafeUrl,
		normalizeCode,
		getCode,
		getAnchor
	};
	function openIdb() {
		return new Promise((resolve, reject) => {
			const req = indexedDB.open(RATING_CONFIG.IDB_NAME);
			req.onsuccess = () => resolve(req.result);
			req.onerror = () => reject(req.error);
		});
	}
	async function buildWatchedMap() {
		const list = await storageManager.getCarList();
		const map = new Map();
		list.forEach((item) => {
			if (item && item.status === "hasWatch" && item.carNum) map.set(RatingUtils.normalizeCode(item.carNum), item);
		});
		RatingUtils.log("WATCHED_MAP", `${map.size} 项`);
		return map;
	}
	var RatingCache = {
		_data: {},
		async load() {
			try {
				const raw = localStorage.getItem(RATING_CONFIG.RATING_CACHE_KEY);
				if (raw) {
					const parsed = JSON.parse(raw);
					if (typeof parsed === "object" && parsed !== null) {
						this._data = parsed;
						RatingUtils.log("CACHE", `localStorage: ${Object.keys(parsed).length} 条`);
						return;
					}
				}
			} catch {}
			try {
				const db = await openIdb();
				const idbData = await new Promise((resolve) => {
					try {
						const req = db.transaction(RATING_CONFIG.IDB_STORE, "readonly").objectStore(RATING_CONFIG.IDB_STORE).get(RATING_CONFIG.IDB_RATING_KEY);
						req.onsuccess = () => resolve(req.result ?? null);
						req.onerror = () => resolve(null);
					} catch {
						resolve(null);
					}
				});
				if (idbData && typeof idbData === "object") {
					this._data = idbData;
					this.saveToLS();
					RatingUtils.log("CACHE", `IndexedDB 恢复: ${Object.keys(idbData).length} 条`);
					return;
				}
			} catch (e) {
				RatingUtils.log("CACHE_IDB_LOAD_ERROR", e);
			}
			this._data = {};
		},
		saveToLS() {
			try {
				localStorage.setItem(RATING_CONFIG.RATING_CACHE_KEY, JSON.stringify(this._data));
			} catch (e) {
				RatingUtils.log("CACHE_SAVE_ERROR", e);
			}
		},
		save() {
			this.saveToLS();
			this._syncToIdb();
		},
		async _syncToIdb() {
			try {
				(await openIdb()).transaction(RATING_CONFIG.IDB_STORE, "readwrite").objectStore(RATING_CONFIG.IDB_STORE).put(this._data, RATING_CONFIG.IDB_RATING_KEY);
			} catch (e) {
				RatingUtils.log("IDB_SYNC_ERROR", e);
			}
		},
		get(code) {
			return this._data[code] || null;
		},
		set(code, rating) {
			const existed = this._data[code];
			if (existed && existed.rating === rating) return false;
			this._data[code] = {
				rating,
				updatedAt: Date.now()
			};
			this.save();
			return true;
		},
		clear() {
			this._data = {};
			localStorage.removeItem(RATING_CONFIG.RATING_CACHE_KEY);
			openIdb().then((db) => {
				try {
					db.transaction(RATING_CONFIG.IDB_STORE, "readwrite").objectStore(RATING_CONFIG.IDB_STORE).delete(RATING_CONFIG.IDB_RATING_KEY);
				} catch {}
			}).catch(() => {});
		},
		size() {
			return Object.keys(this._data).length;
		}
	};
	var limiter = RatingUtils.createLimiter(RATING_CONFIG.FETCH_CONCURRENCY);
	async function request(url, retries = RATING_CONFIG.FETCH_RETRY) {
		for (let i = 0; i <= retries; i++) try {
			return await new Promise((resolve, reject) => {
				GM_xmlhttpRequest({
					method: "GET",
					url,
					timeout: RATING_CONFIG.FETCH_TIMEOUT,
					headers: { "X-Requested-With": "XMLHttpRequest" },
					onload: resolve,
					onerror: reject,
					ontimeout: reject,
					onabort: reject
				});
			});
		} catch (err) {
			if (i === retries) throw err;
			await new Promise((resolve) => setTimeout(resolve, 400 * (i + 1)));
		}
		throw new Error("unreachable");
	}
	function parseRating(doc) {
		if (!doc.querySelector(".review-title .tag.is-success.is-light")) return null;
		const chk = doc.querySelector("input[name=\"video_review[score]\"][checked], .rating-star input:checked");
		if (!chk) return null;
		const ratingValue = parseInt(chk.value, 10);
		return ratingValue >= 1 && ratingValue <= 5 ? ratingValue : null;
	}
	async function fetchRating(item) {
		if (item.dataset.jhsrdFetching === "true" || item.dataset.jhsrdLoaded === "true") return;
		const anchor = RatingUtils.getAnchor(item);
		if (!anchor) return;
		const code = RatingUtils.getCode(item);
		if (!code) return;
		item.dataset.jhsrdFetching = "true";
		try {
			const url = RatingUtils.getSafeUrl(anchor.href);
			const res = await limiter.run(() => request(url));
			if (res.status !== 200) {
				item.dataset.jhsrdLoaded = "true";
				return;
			}
			const rating = parseRating(RatingUtils.parser.parseFromString(res.responseText, "text/html"));
			if (rating !== null) {
				RatingCache.set(code, rating);
				RatingRenderer.showRating(item, rating);
			}
			item.dataset.jhsrdLoaded = "true";
		} catch (err) {
			RatingUtils.log("FETCH_ERROR", code, err);
		} finally {
			delete item.dataset.jhsrdFetching;
		}
	}
	var rating_display_default = ".jhs-user-rating {\n    position: absolute;\n    bottom: 6px;\n    right: 6px;\n    z-index: 5;\n    pointer-events: auto;\n    font-size: 13px;\n    font-weight: 700;\n    line-height: 1;\n    padding: 5px 10px;\n    border-radius: 12px;\n    box-shadow: 0 2px 8px rgb(0, 0, 0, 0.35), 0 0 0 1px rgb(255,255,255,0.1) inset;\n    text-shadow: 0 1px 2px rgb(0, 0, 0, 0.4);\n    color: #fff;\n    white-space: nowrap;\n    opacity: 0.95;\n    transition: transform 0.25s ease, opacity 0.2s ease, background 0.3s ease;\n    display: inline-flex;\n    align-items: center;\n    gap: 3px;\n    letter-spacing: 0.5px;\n}\n\n/* 占位(绿色) */\n.jhs-user-rating.is-placeholder {\n    background: linear-gradient(145deg, #48c78e, #2fb972);\n}\n\n/* 已评分(金色) */\n.jhs-user-rating.is-rated {\n    background: linear-gradient(145deg, #ffc107, #f57c00);\n}\n\n.jhs-rd-icon {\n    font-size: 14px;\n    filter: drop-shadow(0 1px 1px rgb(0,0,0,0.3));\n}\n\n.jhs-rd-num {\n    font-size: 14px;\n    font-weight: 900;\n}\n\n.jhs-user-rating:hover {\n    transform: scale(1.1);\n    opacity: 1;\n}\n\n/* 加载中 */\n.jhs-user-rating.is-loading {\n    animation: jhs-rd-pulse 1s infinite;\n    pointer-events: none;\n}\n\n@keyframes jhs-rd-pulse {\n    0%, 100% { opacity: 0.55; }\n    50% { opacity: 1; }\n}\n\n/* Toast */\n.jhs-rd-toast {\n    position: fixed;\n    left: 50%;\n    transform: translateX(-50%);\n    bottom: 2.5rem;\n    background: rgb(0, 0, 0, 0.88);\n    color: #fff;\n    padding: 0.5rem 0.9rem;\n    border-radius: 0.5rem;\n    z-index: 20000;\n    font-size: 0.85rem;\n    box-shadow: 0 4px 16px rgb(0, 0, 0, 0.4);\n    animation: jhs-rd-toast-in 0.22s;\n    pointer-events: none;\n}\n\n@keyframes jhs-rd-toast-in {\n    from { opacity: 0; transform: translateX(-50%) translateY(8px); }\n    to { opacity: 1; transform: translateX(-50%) translateY(0); }\n}\n";
	var RatingDisplayPlugin = class extends BasePlugin {
		watchedMap = new Map();
		_dirty = false;
		getName() {
			return "RatingDisplayPlugin";
		}
		async initCss() {
			return rating_display_default;
		}
		toast(msg) {
			document.querySelector(".jhs-rd-toast")?.remove();
			const div = document.createElement("div");
			div.className = "jhs-rd-toast";
			div.textContent = msg;
			document.body.appendChild(div);
			setTimeout(() => div.remove(), 2500);
		}
		processItem(item) {
			if (!item || item.dataset.jhsrdProcessed === "true") return;
			item.dataset.jhsrdProcessed = "true";
			const code = RatingUtils.getCode(item);
			if (!code) return;
			if (!this.watchedMap.has(code)) {
				RatingRenderer.removeFrom(item);
				return;
			}
			const cached = RatingCache.get(code);
			if (cached) {
				RatingRenderer.showRating(item, cached.rating);
				item.dataset.jhsrdLoaded = "true";
				item.dataset.jhsrdFromCache = "true";
			} else RatingRenderer.showPlaceholder(item);
		}
		refreshAll() {
			document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
				const el = item;
				RatingRenderer.removeFrom(el);
				el.dataset.jhsrdProcessed = "false";
				delete el.dataset.jhsrdLoaded;
				delete el.dataset.jhsrdFetching;
				delete el.dataset.jhsrdFromCache;
				this.processItem(el);
			});
		}
		clearPageCache() {
			const codes = new Set();
			document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
				const code = RatingUtils.getCode(item);
				if (code) codes.add(code);
			});
			let cleared = 0;
			codes.forEach((code) => {
				if (RatingCache._data[code]) {
					delete RatingCache._data[code];
					cleared++;
				}
			});
			if (cleared > 0) RatingCache.save();
			document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
				const el = item;
				RatingRenderer.removeFrom(el);
				delete el.dataset.jhsrdLoaded;
				delete el.dataset.jhsrdFromCache;
				el.dataset.jhsrdProcessed = "false";
				this.processItem(el);
			});
			this.toast(`已清除 ${cleared} 个评分缓存,当前页 ${codes.size} 张卡片`);
		}
		loadAll() {
			const targets = [];
			document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
				const el = item;
				if (el.dataset.jhsrdFetching !== "true" && el.dataset.jhsrdLoaded !== "true") targets.push(el);
			});
			if (targets.length === 0) {
				this.toast("当前页面所有卡片已加载评分");
				return;
			}
			this.toast(`开始加载 ${targets.length} 个评分...`);
			targets.forEach((item) => {
				const tag = item.querySelector(".jhs-user-rating");
				if (tag) tag.classList.add("is-loading");
				fetchRating(item).finally(() => {
					if (tag) tag.classList.remove("is-loading");
				});
			});
		}
		_invalidateCards(code, status, op, score) {
			if (status === "hasWatch" && op === "add") {
				if (!this.watchedMap.has(code)) this.watchedMap.set(code, {
					carNum: code,
					status: "hasWatch"
				});
			} else this.watchedMap.delete(code);
			if (status === "hasWatch" && op === "add" && typeof score === "number") RatingCache.set(code, score);
			else {
				delete RatingCache._data[code];
				RatingCache.save();
			}
			document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((item) => {
				const el = item;
				if (RatingUtils.getCode(el) === code) {
					RatingRenderer.removeFrom(el);
					delete el.dataset.jhsrdLoaded;
					delete el.dataset.jhsrdFromCache;
					el.dataset.jhsrdProcessed = "false";
					this.processItem(el);
				}
			});
			this._dirty = true;
			const cur = localStorage.getItem("jdb:want-watched-sync");
			if (cur) localStorage.setItem("jhsrd:last-sync-digest", cur);
		}
		async init() {
			await RatingCache.load();
			const syncVal = localStorage.getItem("jdb:want-watched-sync");
			const lastDigest = localStorage.getItem("jhsrd:last-sync-digest");
			if (syncVal && syncVal !== lastDigest) {
				RatingUtils.log("INIT_SYNC", "jhs 有新的同步事件,全量清空评分缓存");
				RatingCache.clear();
				this._dirty = true;
				localStorage.setItem("jhsrd:last-sync-digest", syncVal);
			}
			this.watchedMap = await buildWatchedMap();
			document.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR).forEach((i) => this.processItem(i));
			document.querySelectorAll(".jhs-user-rating.is-rated").forEach((el) => {
				const item = el.closest(RATING_CONFIG.ITEM_SELECTOR);
				if (item && item.dataset.jhsrdFromCache === "true") {
					delete item.dataset.jhsrdLoaded;
					delete item.dataset.jhsrdFromCache;
				}
			});
			const pending = new Set();
			const flushPending = RatingUtils.debounce(() => {
				pending.forEach((item) => this.processItem(item));
				pending.clear();
			}, 150);
			new MutationObserver((muts) => {
				for (const mutation of muts) {
					for (const addedNode of mutation.addedNodes) {
						if (addedNode.nodeType !== 1) continue;
						const el = addedNode;
						if (el.matches(RATING_CONFIG.ITEM_SELECTOR)) pending.add(el);
						const found = el.querySelectorAll(RATING_CONFIG.ITEM_SELECTOR);
						if (found && found.length) found.forEach((node) => pending.add(node));
					}
					const target = mutation.target;
					if (target instanceof Element && target.closest(".tags.has-addons")) {
						const item = target.closest(RATING_CONFIG.ITEM_SELECTOR);
						if (item) {
							item.dataset.jhsrdProcessed = "false";
							this.processItem(item);
						}
					}
				}
				flushPending();
			}).observe(document.body, {
				childList: true,
				subtree: true,
				attributes: true,
				attributeFilter: ["class"]
			});
			let hoverTimer = null;
			let hoveredItem = null;
			document.body.addEventListener("pointerover", (e) => {
				const item = e.target?.closest(RATING_CONFIG.ITEM_SELECTOR);
				if (!item || item === hoveredItem) return;
				hoveredItem = item;
				if (item.dataset.jhsrdLoaded === "true") return;
				const tag = item.querySelector(".jhs-user-rating.is-placeholder");
				if (!tag) return;
				if (hoverTimer) clearTimeout(hoverTimer);
				hoverTimer = setTimeout(() => {
					if (hoveredItem !== item) return;
					tag.classList.add("is-loading");
					fetchRating(item).finally(() => {
						tag.classList.remove("is-loading");
					});
				}, RATING_CONFIG.HOVER_DELAY);
			});
			document.body.addEventListener("pointerout", (e) => {
				const item = e.target?.closest(RATING_CONFIG.ITEM_SELECTOR);
				if (!item || item !== hoveredItem) return;
				hoveredItem = null;
				if (hoverTimer) clearTimeout(hoverTimer);
				const tag = item.querySelector(".jhs-user-rating.is-loading");
				if (tag) tag.classList.remove("is-loading");
			});
			GM_registerMenuCommand("全量加载当前页评分", () => {
				this.loadAll();
			});
			GM_registerMenuCommand("清空当前页评分缓存", () => {
				this.clearPageCache();
			});
			GM_registerMenuCommand("清空所有评分缓存", () => {
				RatingCache.clear();
				this.refreshAll();
				this.toast("所有评分缓存已清空");
			});
			GM_registerMenuCommand("刷新已看列表", async () => {
				this.watchedMap = await buildWatchedMap();
				this.refreshAll();
				this.toast(`已看: ${this.watchedMap.size} 项 · 缓存: ${RatingCache.size()} 条`);
			});
			document.addEventListener("jdb:want-watched-sync", (e) => {
				const { carNum, status, op, score } = e.detail || {};
				if (!carNum || !status || !op) return;
				const code = RatingUtils.normalizeCode(carNum);
				RatingUtils.log("SYNC_EVENT", code, status, op, score);
				this._invalidateCards(code, status, op, score);
			}, { passive: true });
			window.addEventListener("storage", (e) => {
				if (e.key === "jdb:want-watched-sync" && e.newValue) try {
					const payload = JSON.parse(e.newValue);
					if (payload && payload.carNum && payload.status && payload.op) {
						const code = RatingUtils.normalizeCode(payload.carNum);
						RatingUtils.log("STORAGE_SYNC", "跨标签页精确刷新", code, payload.status, payload.op);
						this._invalidateCards(code, payload.status, payload.op, payload.score);
					}
				} catch {
					this._dirty = true;
				}
			});
			document.addEventListener("visibilitychange", () => {
				if (document.hidden) return;
				document.querySelectorAll(".jhs-user-rating.is-rated").forEach((el) => {
					const item = el.closest(RATING_CONFIG.ITEM_SELECTOR);
					if (item) item.dataset.jhsrdLoaded = "false";
				});
				if (this._dirty) {
					this._dirty = false;
					this.refreshAll();
				}
			}, { passive: true });
			RatingUtils.log("INIT", `已看 ${this.watchedMap.size} · 缓存 ${RatingCache.size()}`);
		}
		async handle() {
			await this.init();
		}
	};
	var panelInfoStyle$1 = { marginTop: "20px" };
	var toolbarStyle$1 = { margin: "30px 0" };
	var videoPanelStyle = { marginTop: "20px" };
	var magnetsStyle = { margin: "0 0.75rem" };
	var hiddenStyle$2 = { display: "none" };
	function Fc2DetailDialog() {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "movie-detail-container",
			children: [
				(0, import_jsx_runtime.jsx)("div", {
					className: "movie-info-container",
					children: (0, import_jsx_runtime.jsx)("div", {
						className: "search-loading",
						children: "加载中..."
					})
				}),
				(0, import_jsx_runtime.jsx)("div", {
					className: "movie-panel-info fc2-movie-panel-info",
					style: panelInfoStyle$1,
					children: (0, import_jsx_runtime.jsx)("strong", { children: "第三方资源: " })
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: toolbarStyle$1,
					children: [
						(0, import_jsx_runtime.jsx)("a", {
							id: "filterBtn",
							className: "jhs-toolbar-menu-btn",
							style: { backgroundColor: BLOCK_COLOR },
							children: (0, import_jsx_runtime.jsx)("span", { children: BLOCK_TEXT })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "favoriteBtn",
							className: "jhs-toolbar-menu-btn",
							style: { backgroundColor: FAVORITE_COLOR },
							children: (0, import_jsx_runtime.jsx)("span", { children: FAVORITE_TEXT })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "hasDownBtn",
							className: "jhs-toolbar-menu-btn",
							style: { backgroundColor: HAS_DOWN_COLOR },
							children: (0, import_jsx_runtime.jsx)("span", { children: HAS_DOWN_TEXT$1 })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "hasWatchBtn",
							className: "jhs-toolbar-menu-btn",
							style: { backgroundColor: WATCHED_COLOR },
							children: (0, import_jsx_runtime.jsx)("span", { children: WATCHED_TEXT })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "search-subtitle-btn",
							className: "jhs-toolbar-menu-btn fr-btn",
							style: { background: "linear-gradient(to bottom, #8d5656, rgb(196,159,91))" },
							children: (0, import_jsx_runtime.jsx)("span", { children: "字幕 (SubTitleCat)" })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "xunLeiSubtitleBtn",
							className: "jhs-toolbar-menu-btn fr-btn",
							style: { background: "linear-gradient(to left, #375f7c, #2196F3)" },
							children: (0, import_jsx_runtime.jsx)("span", { children: "字幕 (迅雷)" })
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "magnetSearchBtn",
							className: "jhs-toolbar-menu-btn fr-btn",
							style: {
								width: "120px",
								background: "linear-gradient(to right, rgb(245,140,1), rgb(84,161,29))",
								color: "white",
								textAlign: "center",
								padding: "8px 0"
							},
							children: (0, import_jsx_runtime.jsx)("span", { children: "磁力搜索" })
						})
					]
				}),
				(0, import_jsx_runtime.jsx)("div", {
					className: "message video-panel",
					style: videoPanelStyle,
					children: (0, import_jsx_runtime.jsx)("div", {
						id: "magnets-content",
						className: "magnet-links",
						style: magnetsStyle,
						children: (0, import_jsx_runtime.jsx)("div", {
							className: "search-loading",
							children: "加载中..."
						})
					})
				}),
				(0, import_jsx_runtime.jsx)("div", { id: "reviews-content" }),
				(0, import_jsx_runtime.jsx)("div", { id: "related-content" }),
				(0, import_jsx_runtime.jsx)("span", {
					id: "data-actress",
					style: hiddenStyle$2
				})
			]
		});
	}
	function Fc2MagnetItem({ magnet, rowClass }) {
		const magnetUri = `magnet:?xt=urn:btih:${magnet.hash}`;
		return (0, import_jsx_runtime.jsxs)("div", {
			className: `item columns is-desktop ${rowClass}`,
			children: [
				(0, import_jsx_runtime.jsx)("div", {
					className: "magnet-name column is-four-fifths",
					children: (0, import_jsx_runtime.jsxs)("a", {
						href: magnetUri,
						title: "右鍵點擊並選擇「複製鏈接地址」",
						children: [
							(0, import_jsx_runtime.jsx)("span", {
								className: "name",
								children: magnet.name
							}),
							(0, import_jsx_runtime.jsx)("br", {}),
							(0, import_jsx_runtime.jsxs)("span", {
								className: "meta",
								children: [
									(magnet.size / 1024).toFixed(2),
									"GB, ",
									magnet.files_count,
									"個文件"
								]
							}),
							(0, import_jsx_runtime.jsx)("br", {}),
							(0, import_jsx_runtime.jsxs)("div", {
								className: "tags",
								children: [magnet.hd ? (0, import_jsx_runtime.jsx)("span", {
									className: "tag is-primary is-small is-light",
									children: "高清"
								}) : "", magnet.cnsub ? (0, import_jsx_runtime.jsx)("span", {
									className: "tag is-warning is-small is-light",
									children: "字幕"
								}) : ""]
							})
						]
					})
				}),
				(0, import_jsx_runtime.jsx)("div", {
					className: "buttons column",
					children: (0, import_jsx_runtime.jsx)("button", {
						className: "button is-info is-small copy-to-clipboard",
						"data-clipboard-text": magnetUri,
						type: "button",
						children: "\xA0複製\xA0"
					})
				}),
				(0, import_jsx_runtime.jsx)("div", {
					className: "date column",
					children: (0, import_jsx_runtime.jsx)("span", {
						className: "time",
						children: magnet.created_at
					})
				})
			]
		});
	}
	var galleryStyle$1 = { marginTop: "10px" };
	var fc2MarketStyle = { marginLeft: "5px" };
	var hiddenStyle$1 = { display: "none" };
	function Fc2MovieDetail({ detail, actors, imgList }) {
		const carNumWithoutPrefix = (detail.carNum || "").replace("FC2-", "");
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsx)("h3", {
				className: "movie-title",
				children: (0, import_jsx_runtime.jsx)("strong", {
					className: "current-title",
					children: detail.title || "无标题"
				})
			}),
			(0, import_jsx_runtime.jsxs)("div", {
				className: "movie-meta",
				children: [
					(0, import_jsx_runtime.jsxs)("span", { children: [(0, import_jsx_runtime.jsx)("strong", { children: "番号: " }), detail.carNum || "未知"] }),
					(0, import_jsx_runtime.jsxs)("span", { children: [(0, import_jsx_runtime.jsx)("strong", { children: "年份: " }), detail.releaseDate || "未知"] }),
					(0, import_jsx_runtime.jsxs)("span", { children: [(0, import_jsx_runtime.jsx)("strong", { children: "评分: " }), detail.score || "无"] }),
					(0, import_jsx_runtime.jsxs)("span", { children: [(0, import_jsx_runtime.jsx)("strong", { children: "时长: " }), detail.duration + " m" || "无"] })
				]
			}),
			(0, import_jsx_runtime.jsx)("div", {
				className: "movie-meta",
				children: (0, import_jsx_runtime.jsxs)("span", { children: [
					(0, import_jsx_runtime.jsx)("strong", { children: "站点: " }),
					(0, import_jsx_runtime.jsx)("a", {
						href: `https://fc2ppvdb.com/articles/${carNumWithoutPrefix}`,
						target: "_blank",
						children: "fc2ppvdb"
					}),
					(0, import_jsx_runtime.jsx)("a", {
						style: fc2MarketStyle,
						href: `https://adult.contents.fc2.com/article/${carNumWithoutPrefix}/`,
						target: "_blank",
						children: "fc2电子市场"
					})
				] })
			}),
			(0, import_jsx_runtime.jsx)("div", {
				className: "movie-actors",
				children: (0, import_jsx_runtime.jsxs)("div", {
					className: "actor-list",
					children: [(0, import_jsx_runtime.jsx)("strong", { children: "主演: " }), actors.length > 0 ? actors.map((actor) => (0, import_jsx_runtime.jsx)("span", {
						className: "actor-tag",
						children: (0, import_jsx_runtime.jsx)("a", {
							href: `/actors/${actor.id}`,
							target: "_blank",
							children: actor.name
						})
					})) : (0, import_jsx_runtime.jsx)("span", {
						className: "no-data",
						children: "暂无演员信息"
					})]
				})
			}),
			(0, import_jsx_runtime.jsxs)("div", {
				className: "movie-gallery",
				style: galleryStyle$1,
				children: [(0, import_jsx_runtime.jsx)("strong", { children: "剧照: " }), (0, import_jsx_runtime.jsx)("div", {
					className: "image-list",
					children: Array.isArray(imgList) && imgList.length > 0 ? imgList.map((img, idx) => (0, import_jsx_runtime.jsx)("a", {
						href: img,
						"data-fancybox": "movie-gallery",
						"data-caption": `剧照 ${idx + 1}`,
						children: (0, import_jsx_runtime.jsx)("img", {
							src: img,
							className: "movie-image-thumb",
							alt: ""
						})
					})) : (0, import_jsx_runtime.jsx)("div", {
						className: "no-data",
						children: "暂无剧照"
					})
				})]
			}),
			(0, import_jsx_runtime.jsx)("div", {
				id: "data-releaseDate",
				style: hiddenStyle$1,
				children: detail.releaseDate || ""
			})
		] });
	}
	function MovieError({ message }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "movie-error",
			children: ["加载失败: ", message]
		});
	}
	var innerStyle = {
		marginTop: "50px",
		color: "#000",
		cursor: "auto"
	};
	function ScreenLoadingPlaceholder({ maxHeight }) {
		return (0, import_jsx_runtime.jsx)("a", {
			className: "tile-item screen-container",
			style: {
				overflow: "hidden",
				maxHeight,
				maxWidth: maxHeight,
				textAlign: "center"
			},
			children: (0, import_jsx_runtime.jsx)("div", {
				style: innerStyle,
				children: "正在加载缩略图"
			})
		});
	}
	var fc2_plugin_default = "/* Fc2Plugin 弹层样式(提取自未删减版 jhs.user.js Fc2Plugin.initCss) */\n\n/* 弹层样式 */\n.movie-detail-layer .layui-layer-title {\n    font-size: 18px;\n    color: #333;\n    background: #f8f8f8;\n}\n\n/* 容器样式 */\n.movie-detail-container {\n    margin: 40px;\n    height: 100%;\n    background: #fff;\n}\n\n.movie-poster-container {\n    flex: 0 0 60%;\n    padding: 15px;\n}\n\n.right-box {\n    flex: 1;\n    padding: 20px;\n    overflow-y: auto;\n}\n\n/* 预告片iframe */\n.movie-trailer {\n    width: 100%;\n    height: 100%;\n    min-height: 400px;\n    background: #000;\n    border-radius: 4px;\n}\n\n/* 电影信息样式 */\n.movie-title {\n    font-size: 24px;\n    margin-bottom: 15px;\n    color: #333;\n}\n\n.movie-meta {\n    margin-bottom: 20px;\n    color: #666;\n}\n\n.movie-meta span {\n    margin-right: 15px;\n}\n\n/* 演员列表 */\n.actor-list {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 8px;\n    margin-top: 10px;\n}\n\n.actor-tag {\n    padding: 4px 12px;\n    background: #f0f0f0;\n    border-radius: 15px;\n    font-size: 12px;\n    color: #555;\n}\n\n/* 图片列表 */\n.image-list {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 10px;\n    margin-top: 10px;\n}\n\n.movie-image-thumb {\n    width: 120px;\n    height: 80px;\n    object-fit: cover;\n    border-radius: 4px;\n    cursor: pointer;\n    transition: transform 0.3s;\n}\n\n.movie-image-thumb:hover {\n    transform: scale(1.05);\n}\n\n/* 加载中和错误状态 */\n.search-loading,\n.movie-error {\n    padding: 40px;\n    text-align: center;\n    color: #999;\n}\n\n.movie-error {\n    color: #f56c6c;\n}\n\n.fancybox-container {\n    z-index: var(--jhs-z-top);\n}\n\n/* 错误提示样式 */\n.movie-not-found,\n.movie-error {\n    text-align: center;\n    padding: 30px;\n    color: #666;\n}\n\n.movie-not-found h3,\n.movie-error h3 {\n    color: #f56c6c;\n    margin: 15px 0;\n}\n\n.icon-warning,\n.icon-error {\n    font-size: 50px;\n    color: #e6a23c;\n}\n\n.icon-error {\n    color: #f56c6c;\n}\n\n.fc2-movie-panel-info .panel-block {\n    padding: 0 !important;\n}\n";
	var Fc2Plugin = class extends BasePlugin {
		getName() {
			return "Fc2Plugin";
		}
		async initCss() {
			return fc2_plugin_default;
		}
		async handle() {
			const fc2SearchHref = "/advanced_search?type=3&score_min=0&d=1";
			$(".navbar-item:contains(\"FC2\")").attr("href", fc2SearchHref);
			$(".tabs a:contains(\"FC2\")").attr("href", fc2SearchHref);
			if (currentHref.includes("advanced_search?type=3")) {
				$("h2.section-title").contents().first().replaceWith("Fc2PPV");
				$(".section .container > .box").remove();
			}
			if (currentHref.includes("collection_codes?movieId")) {
				$("section").html("");
				const params = new URLSearchParams(window.location.search);
				const movieId = params.get("movieId");
				const carNum = params.get("carNum");
				const url = params.get("url");
				if (movieId && carNum && url) this.openFc2Dialog(movieId, carNum, url);
			}
		}
		openFc2Dialog(movieId, carNum, url) {
			const carNumWithoutPrefix = carNum.replace("FC2-", "");
			if (url.includes("123av")) {
				const fc2By123Av = this.getBean("Fc2By123AvPlugin");
				if (fc2By123Av) {
					fc2By123Av.open123AvFc2Dialog(carNum, url);
					return;
				}
			}
			const dialogHtml = jsxToString((0, import_jsx_runtime.jsx)(Fc2DetailDialog, {}));
			layer.open({
				type: 1,
				title: carNum,
				content: dialogHtml,
				area: utils.getResponsiveArea(["70%", "90%"]),
				skin: "movie-detail-layer",
				scrollbar: false,
				success: (_layerEl, layerIndex) => {
					this.loadData(movieId, carNum);
					$("#favoriteBtn").on("click", async () => {
						const names = $("#data-actress").text();
						const publishTime = $("#data-releaseDate").text();
						await storageManager.saveCar({
							carNum,
							url,
							names,
							actionType: FAVORITE_ACTION,
							publishTime
						});
						window.refresh();
						layer.closeAll();
					});
					$("#filterBtn").on("click", (event) => {
						utils.q(event, `是否屏蔽${carNum}?`, async () => {
							const names = $("#data-actress").text();
							const publishTime = $("#data-releaseDate").text();
							await storageManager.saveCar({
								carNum,
								url,
								names,
								actionType: FILTER_ACTION,
								publishTime
							});
							window.refresh();
							layer.closeAll();
							if (window.location.href.includes("collection_codes?movieId")) utils.closePage();
						});
					});
					$("#hasDownBtn").on("click", async () => {
						const names = $("#data-actress").text();
						const publishTime = $("#data-releaseDate").text();
						await storageManager.saveCar({
							carNum,
							url,
							names,
							actionType: HAS_DOWN_ACTION,
							publishTime
						});
						window.refresh();
						layer.closeAll();
					});
					$("#hasWatchBtn").on("click", async () => {
						const names = $("#data-actress").text();
						const publishTime = $("#data-releaseDate").text();
						await storageManager.saveCar({
							carNum,
							url,
							names,
							actionType: HAS_WATCH_ACTION,
							publishTime
						});
						window.refresh();
						layer.closeAll();
					});
					$("#search-subtitle-btn").on("click", (event) => utils.openPage(`https://subtitlecat.com/index.php?search=${carNum}`, carNum, false, event));
					$("#xunLeiSubtitleBtn").on("click", () => this.getBean("DetailPageButtonPlugin")?.searchXunLeiSubtitle(carNum));
					$("#magnetSearchBtn").on("click", () => {
						const magnetHub = this.getBean("MagnetHubPlugin");
						if (!magnetHub) return;
						const magnetHubHtml = magnetHub.createMagnetHub(carNum);
						layer.open({
							type: 1,
							title: "磁力搜索",
							content: jsxToString((0, import_jsx_runtime.jsx)("div", { id: "magnetHubBox" })),
							area: utils.getResponsiveArea(["60%", "80%"]),
							scrollbar: false,
							success: () => {
								$("#magnetHubBox").append(magnetHubHtml);
							}
						});
					});
					this.getBean("OtherSitePlugin")?.loadOtherSite(carNumWithoutPrefix, carNum).then();
					utils.setupEscClose(layerIndex);
				},
				end() {
					if (window.location.href.includes("collection_codes?movieId")) utils.closePage();
				}
			});
		}
		loadData(movieId, carNum) {
			const carNumWithoutPrefix = carNum.replace("FC2-", "");
			this.handleMovieDetail(movieId);
			this.handleLongImg(carNumWithoutPrefix);
			this.handleMagnets(movieId);
			this.getBean("ReviewPlugin")?.showReview(String(movieId), $("#reviews-content")).then();
			this.getBean("RelatedPlugin")?.showRelated($("#related-content"), String(movieId)).then();
		}
		handleMovieDetail(movieId) {
			fetchMovieDetail(movieId).then((detail) => {
				const actors = detail.actors || [];
				const imgList = detail.imgList || [];
				let actressNames = "";
				for (let i = 0; i < actors.length; i++) {
					const actor = actors[i];
					if (actor.gender === 0) actressNames += actor.name + " ";
				}
				if (actressNames) $("#data-actress").text(actressNames);
				$(".movie-info-container").html(jsxToString((0, import_jsx_runtime.jsx)(Fc2MovieDetail, {
					detail,
					actors,
					imgList
				})));
				this.getBean("TranslatePlugin")?.translate(detail.carNum, false)?.then();
			}).catch((err) => {
				clog.error(err);
				$(".movie-info-container").html(jsxToString((0, import_jsx_runtime.jsx)(MovieError, { message: err instanceof Error ? err.message : String(err) })));
			});
		}
		handleLongImg(carNumWithoutPrefix) {
			utils.loopDetector(() => $(".movie-gallery .image-list").length > 0, async () => {
				$(".movie-gallery .image-list").prepend(jsxToString((0, import_jsx_runtime.jsx)(ScreenLoadingPlaceholder, { maxHeight: "150px" })));
				const screenShot = this.getBean("ScreenShotPlugin");
				if (!screenShot) return;
				const screenshotUrl = await screenShot.getScreenshot(carNumWithoutPrefix);
				if (screenshotUrl) await screenShot.addImg("缩略图", screenshotUrl);
			});
		}
		handleMagnets(movieId) {
			(async () => {
				const url = `${API_BASE}/v1/movies/${movieId}/magnets`;
				const headers = { jdSignature: await reBuildSignature() };
				return (await gmHttp.get(url, void 0, headers)).data.magnets;
			})().then((magnets) => {
				let magnetsHtml = "";
				if (magnets.length > 0) for (let i = 0; i < magnets.length; i++) {
					const magnet = magnets[i];
					let rowClass = "";
					if (i % 2 === 0) rowClass = "odd";
					magnetsHtml += jsxToString((0, import_jsx_runtime.jsx)(Fc2MagnetItem, {
						magnet,
						rowClass
					}));
				}
				else magnetsHtml = jsxToString((0, import_jsx_runtime.jsx)("span", {
					className: "no-data",
					children: "暂无磁力信息"
				}));
				$("#magnets-content").html(magnetsHtml);
			}).catch((err) => {
				clog.error(err);
				$("#magnets-content").html(jsxToString((0, import_jsx_runtime.jsx)(MovieError, { message: err instanceof Error ? err.message : String(err) })));
			});
		}
		async openFc2Page(movieId, carNum, url) {
			const javdbUrl = await this.getBean("OtherSitePlugin")?.getJavDbUrl();
			window.open(`${javdbUrl}/users/collection_codes?movieId=${encodeURIComponent(movieId)}&carNum=${encodeURIComponent(carNum)}&url=${encodeURIComponent(url)}`, "_blank", "noopener,noreferrer");
		}
	};
	var SELECTOR_LEFT = "body > section > div > nav > a.pagination-previous";
	var SELECTOR_RIGHT = "body > section > div > nav > a.pagination-next";
	var KeyPageTurningPlugin = class extends BasePlugin {
		lockLeft = false;
		lockRight = false;
		getName() {
			return "KeyPageTurningPlugin";
		}
		get pageTypes() {
			return [
				"list",
				"fc2",
				"unknown"
			];
		}
		async initCss() {
			return "";
		}
		async handle() {
			if (window.isDetailPage) return;
			window.addEventListener("keydown", (e) => {
				if (this.isTyping()) return;
				if (e.key === "ArrowLeft" && !this.lockLeft) {
					const a = document.querySelector(SELECTOR_LEFT) || null;
					if (a) {
						e.preventDefault();
						this.safeClick(a);
						this.lockLeft = true;
					}
				} else if (e.key === "ArrowRight" && !this.lockRight) {
					const a = document.querySelector(SELECTOR_RIGHT) || null;
					if (a) {
						e.preventDefault();
						this.safeClick(a);
						this.lockRight = true;
					}
				}
			}, { passive: false });
			window.addEventListener("keyup", (e) => {
				if (e.key === "ArrowLeft") this.lockLeft = false;
				if (e.key === "ArrowRight") this.lockRight = false;
			});
		}
		isTyping() {
			const el = document.activeElement;
			if (!el) return false;
			const tag = el.tagName;
			return el.isContentEditable || tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT";
		}
		safeClick(a) {
			if (!a) return false;
			if (typeof a.click === "function") {
				a.click();
				return true;
			}
			const evt = new MouseEvent("click", {
				bubbles: true,
				cancelable: true
			});
			return a.dispatchEvent(evt);
		}
	};
	var ModMyListOpenWayPlugin = class extends BasePlugin {
		getName() {
			return "ModMyListOpenWayPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			if (!location.pathname.includes("/users/lists")) return;
			const segments = location.pathname.split("/").filter(Boolean);
			const last = segments[segments.length - 1];
			const ul = document.querySelector("#lists > ul");
			if (!ul) return;
			const lis = ul.children;
			const isListsPage = last === "lists";
			const page = Number(new URLSearchParams(location.search).get("page")) || 1;
			if (isListsPage && page < 2) lis[0].style.display = "none";
			for (let i = isListsPage && page < 2 ? 1 : 0; i < lis.length; i++) {
				const a = lis[i].querySelector("div.column.is-10 > a");
				if (!a) continue;
				a.target = "_blank";
				if (isListsPage) a.href = `/lists/${new URL(a.href).searchParams.get("id")}`;
			}
		}
	};
	var page_sort_plugin_default = "/**\n * page-sort 插件样式 —— 排序按钮选中态。\n *\n * 原脚本 injectSortStyles() 用 document.createElement('style') 注入:\n *   style.textContent = `\n *       .button.is-small.selected-method,\n *       .button.is-small.selected-method:hover {\n *           background-color: rgb(25, 135, 84) !important;\n *           border-color: transparent !important;\n *           color: #fff !important;\n *       }\n *   `;\n *\n * 此处提取为独立 .css,由 initCss() 返回 → PluginManager utils.insertStyle 注入。\n * CSS 规则内容与原脚本一致(缩进标准化为 4 空格,CSS 解析忽略空白,渲染等价)。\n */\n.button.is-small.selected-method,\n.button.is-small.selected-method:hover {\n    background-color: rgb(25, 135, 84) !important;\n    border-color: transparent !important;\n    color: #fff !important;\n}\n";
	var LOG$2 = "[pageSort]";
	function compareItems($itemA, $itemB) {
		const getStrongText = ($item) => {
			const $strong = $item.find("a > div.video-title > strong");
			return $strong.length ? $strong.text().trim() : "";
		};
		const textA = getStrongText($itemA);
		const textB = getStrongText($itemB);
		return textA.localeCompare(textB);
	}
	function getScore($item) {
		const $span = $item.find("a > div.score > span");
		if (!$span.length) return 0;
		const match = $span.text().trim().match(/(\d+\.\d+)/);
		if (!match) return 0;
		return parseFloat(match[1]) || 0;
	}
	function newOption(text) {
		return $("<span>", {
			text,
			class: "button is-small"
		});
	}
	var SORT_CONFIGS = [
		{
			label: "按照名称升序",
			sortFn: (items) => items.sort((a, b) => compareItems($(a), $(b))),
			implemented: true
		},
		{
			label: "按照名称降序",
			sortFn: (items) => items.sort((a, b) => compareItems($(b), $(a))),
			implemented: true
		},
		{
			label: "按照评分升序",
			sortFn: (items) => items.sort((a, b) => getScore($(a)) - getScore($(b))),
			implemented: true
		},
		{
			label: "按照评分降序",
			sortFn: (items) => items.sort((a, b) => getScore($(b)) - getScore($(a))),
			implemented: true
		}
	];
	var PageSortPlugin = class extends BasePlugin {
		$container = null;
		activeSort = null;
		isApplyingSort = false;
		sortGuardRetries = 0;
		MAX_GUARD_RETRIES = 5;
		sortGuard = null;
		$buttons = null;
		getName() {
			return "PageSortPlugin";
		}
		async initCss() {
			return page_sort_plugin_default;
		}
		async handle() {
			if (!window.isListPage) return;
			this.waitForContainer();
		}
		waitForContainer() {
			if (this.createSortSelector()) return;
			console.log(`${LOG$2} 页面容器未就绪,开始 MutationObserver 等待`);
			new MutationObserver((_mutations, obs) => {
				if (this.createSortSelector()) obs.disconnect();
			}).observe(document.body, {
				childList: true,
				subtree: true
			});
		}
		createSortSelector() {
			const $toolbar = $("body > section > div > div.toolbar");
			if (!$toolbar.length) {
				console.warn(`${LOG$2} 未找到工具栏 .toolbar,跳过排序选择器注入`);
				return false;
			}
			const $container = $("body > section > div > div.movie-list.h.cols-4.vcols-8");
			if (!$container.length) {
				console.warn(`${LOG$2} 未找到视频列表容器 .movie-list,跳过排序选择器注入`);
				return false;
			}
			this.$container = $container;
			const $items = $container.children(".item");
			if ($items.length === 0) {
				console.warn(`${LOG$2} 视频列表为空,跳过排序选择器注入`);
				return false;
			}
			$items.each(function(i) {
				if (!this.hasAttribute("data-original-index")) this.setAttribute("data-original-index", String(i));
			});
			const sortGuard = new MutationObserver(() => {
				if (this.activeSort && !this.isApplyingSort) {
					if (this.sortGuardRetries >= this.MAX_GUARD_RETRIES) {
						console.warn(`${LOG$2} 排序守卫重试已达上限 (${this.MAX_GUARD_RETRIES}),放弃自动恢复`);
						return;
					}
					this.sortGuardRetries++;
					console.log(`${LOG$2} 检测到 DOM 顺序被外部修改,重新应用排序 (${this.sortGuardRetries}/${this.MAX_GUARD_RETRIES})`);
					this.applySort(this.activeSort);
				}
			});
			this.sortGuard = sortGuard;
			sortGuard.observe($container[0], { childList: true });
			const $buttonGroup = $("<div>", { css: {
				display: "inline-block",
				marginBottom: ".1rem",
				lineHeight: "2.2rem",
				marginRight: ".4rem",
				marginLeft: "auto"
			} });
			const $buttons = $("<div>", { class: "buttons has-addons" });
			this.$buttons = $buttons;
			$buttonGroup.append($buttons);
			$toolbar.append($buttonGroup);
			SORT_CONFIGS.forEach((config) => {
				$buttons.append(newOption(config.label));
			});
			$buttons.on("click", ".button.is-small", (e) => {
				e.preventDefault();
				e.stopPropagation();
				const $this = $(e.currentTarget);
				const isActive = $this.hasClass("selected-method");
				this.sortGuardRetries = 0;
				localStorage.removeItem("jhs_sortMethod");
				if (isActive) {
					$this.removeClass("selected-method");
					this.activeSort = null;
					this.applySort(null);
				} else {
					$this.siblings(".selected-method").removeClass("selected-method");
					$this.addClass("selected-method");
					const method = $this.text();
					this.activeSort = method;
					this.applySort(method);
				}
			});
			$("#sort-toggle-btn").on("click", () => {
				this.activeSort = null;
				this.sortGuardRetries = 0;
				if (this.$buttons) this.$buttons.find(".selected-method").removeClass("selected-method");
			});
			console.log(`${LOG$2} 排序选择器已注入,共 ${$items.length} 个影片`);
			return true;
		}
		applySort(sortMethod) {
			if (this.isApplyingSort) return;
			this.isApplyingSort = true;
			this.sortGuard?.disconnect();
			try {
				const currentItems = this.$container.children(".item").get();
				if (currentItems.length === 0) return;
				if (sortMethod === null) {
					currentItems.sort((a, b) => {
						return (parseInt(a.getAttribute("data-original-index") || "0") || 0) - (parseInt(b.getAttribute("data-original-index") || "0") || 0);
					});
					this.$container.append(currentItems);
					console.log(`${LOG$2} 已恢复原始顺序`);
				} else {
					const config = SORT_CONFIGS.find((c) => c.label === sortMethod);
					if (!config) {
						console.warn(`${LOG$2} 未识别的排序选项: ${sortMethod}`);
						return;
					}
					if (!config.implemented || !config.sortFn) {
						console.log(`${LOG$2} ${sortMethod} - 待实现`);
						return;
					}
					config.sortFn(currentItems);
					this.$container.append(currentItems);
					console.log(`${LOG$2} 已${sortMethod}排列 ${currentItems.length} 个影片`);
				}
				this.sortGuard?.takeRecords();
			} finally {
				if (this.$container && this.sortGuard) this.sortGuard.observe(this.$container[0], { childList: true });
				this.isApplyingSort = false;
			}
		}
	};
	var STATUS_TAG_SELECTOR = ".item .tags.has-addons .tag.is-success.status-tag";
	var JHS_HIDE_ATTR = "data-hide";
	var NO_TAG_VALUE = "no-tag";
	function collectStatusTagCounts() {
		const counts = {};
		document.querySelectorAll(STATUS_TAG_SELECTOR).forEach((el) => {
			const itemEl = el.closest(".item");
			if (itemEl && itemEl.hasAttribute("data-hide")) return;
			const text = el.textContent?.trim() || "";
			if (text) counts[text] = (counts[text] || 0) + 1;
		});
		return counts;
	}
	function countNoStatusItems() {
		let count = 0;
		document.querySelectorAll(".item").forEach((item) => {
			if (item.hasAttribute("data-hide")) return;
			if (!item.querySelector(".item .tags.has-addons .tag.is-success.status-tag")) count++;
		});
		return count;
	}
	var HIDDEN_ATTR = "data-status-tag-hidden";
	function applyFilter$2() {
		const activeChips = document.querySelectorAll(".status-tag-filter-chip.active");
		const selectedValues = new Set(Array.from(activeChips).map((c) => c.dataset.value || ""));
		if (selectedValues.size === 0) {
			document.querySelectorAll(`.item[${HIDDEN_ATTR}]`).forEach((item) => {
				const htmlItem = item;
				if (htmlItem.hasAttribute("data-hide")) return;
				htmlItem.removeAttribute(HIDDEN_ATTR);
				htmlItem.style.display = "";
			});
			return;
		}
		const showNoTag = selectedValues.has(NO_TAG_VALUE);
		const selectedTags = new Set([...selectedValues].filter((v) => v !== NO_TAG_VALUE));
		document.querySelectorAll(".item").forEach((item) => {
			const htmlItem = item;
			const hiddenByJhs = htmlItem.hasAttribute(JHS_HIDE_ATTR);
			const hiddenByOther = htmlItem.style.display === "none" && !htmlItem.hasAttribute(HIDDEN_ATTR);
			if (hiddenByJhs || hiddenByOther) return;
			const itemStatusTags = new Set();
			item.querySelectorAll(STATUS_TAG_SELECTOR).forEach((el) => {
				const text = el.textContent?.trim() || "";
				if (text) itemStatusTags.add(text);
			});
			let tagMatch = false;
			if (selectedTags.size > 0) tagMatch = [...selectedTags].some((t) => itemStatusTags.has(t));
			const noTagMatch = showNoTag && itemStatusTags.size === 0;
			if (tagMatch || noTagMatch) {
				htmlItem.removeAttribute(HIDDEN_ATTR);
				htmlItem.style.display = "";
			} else {
				htmlItem.setAttribute(HIDDEN_ATTR, "");
				htmlItem.style.display = "none";
			}
		});
	}
	var LOG$1 = "[状态标签筛选]";
	function createFilterChip$2(labelText, value, opts = {}) {
		const { isNoTag = false, count } = opts;
		const chip = document.createElement("span");
		chip.className = "status-tag-filter-chip";
		if (isNoTag) chip.classList.add("no-status");
		chip.textContent = count !== void 0 ? `${labelText} ${count}` : labelText;
		chip.dataset.value = value;
		chip.addEventListener("click", () => {
			chip.classList.toggle("active");
			applyFilter$2();
		});
		return chip;
	}
	function doBuild(mountTarget) {
		if (document.querySelector(".status-tag-filter-bar")) return;
		const filterBar = document.createElement("div");
		filterBar.className = "status-tag-filter-bar";
		const label = document.createElement("span");
		label.className = "status-tag-filter-label";
		label.textContent = "状态:";
		filterBar.appendChild(label);
		const chipsContainer = document.createElement("div");
		chipsContainer.className = "status-tag-filter-chips";
		filterBar.appendChild(chipsContainer);
		const refreshChips = () => {
			const activeValues = new Set(Array.from(chipsContainer.querySelectorAll(".status-tag-filter-chip.active")).map((c) => c.dataset.value || ""));
			chipsContainer.innerHTML = "";
			const noTagChip = createFilterChip$2("无状态标签", NO_TAG_VALUE, {
				isNoTag: true,
				count: countNoStatusItems()
			});
			if (activeValues.has("no-tag")) noTagChip.classList.add("active");
			chipsContainer.appendChild(noTagChip);
			const allCounts = collectStatusTagCounts();
			Object.keys(allCounts).sort().forEach((tagName) => {
				const chip = createFilterChip$2(tagName, tagName, { count: allCounts[tagName] });
				if (activeValues.has(tagName)) chip.classList.add("active");
				chipsContainer.appendChild(chip);
			});
		};
		refreshChips();
		if (mountTarget.matches(".jhs-vlt-filter-bar, .actor-tags.tags, .tabs.is-boxed")) mountTarget.insertAdjacentElement("afterend", filterBar);
		else mountTarget.insertAdjacentElement("beforebegin", filterBar);
		filterBar._refreshChips = refreshChips;
		console.log(`${LOG$1} 筛选栏已挂载`);
	}
	function findMountTarget() {
		const tagFilterBar = document.querySelector(".jhs-vlt-filter-bar");
		if (tagFilterBar) return tagFilterBar;
		if (/^\/actors\//.test(window.location.pathname)) {
			const actorTags = document.querySelector("body > section > div > div.actor-tags.tags");
			if (actorTags) return actorTags;
		} else {
			const tabsBoxed = document.querySelector("body > section > div > div.tabs.is-boxed");
			if (tabsBoxed) return tabsBoxed;
		}
		const section = document.querySelector("body > section > div > div");
		if (section && section.firstElementChild) {
			if (!section.firstElementChild.matches(".jhs-vlt-filter-bar, .status-tag-filter-bar")) return section.firstElementChild;
		}
		const container = document.querySelector("body > section > div");
		if (container && container.firstElementChild) {
			if (!container.firstElementChild.matches(".jhs-vlt-filter-bar, .status-tag-filter-bar")) return container.firstElementChild;
		}
		return null;
	}
	var status_tag_filter_plugin_default = "/**\n * status-tag-filter 插件样式 —— 状态标签筛选栏 + 芯片。\n *\n * 原脚本 GM_addStyle(`...`) 注入,此处提取为独立 .css,由 initCss() 返回 →\n * PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进标准化,\n * CSS 解析忽略空白,渲染等价)。\n */\n\n.status-tag-filter-chip.active {\n    background: #198754;\n    border-color: #198754;\n    color: #fff;\n}\n\n.status-tag-filter-chip.no-status {\n    border-style: dashed;\n    color: #6c757d;\n}\n\n.status-tag-filter-chip.no-status.active {\n    background: #6c757d;\n    border-color: #6c757d;\n    border-style: solid;\n    color: #fff;\n}\n";
	var StatusTagFilterPlugin = class extends BasePlugin {
		observerDebounce = 0;
		supervisor = new TaskSupervisor();
		getName() {
			return "StatusTagFilterPlugin";
		}
		get pageTypes() {
			return ["list"];
		}
		async initCss() {
			return status_tag_filter_plugin_default;
		}
		async handle() {
			if (!window.isListPage) return;
			this.init();
		}
		init() {
			console.log(`${LOG$1} 初始化, pathname:`, window.location.pathname);
			if (!document.body) {
				console.warn(`${LOG$1} document.body 不存在,延后初始化`);
				this.supervisor.setTimeout(() => this.init(), 100);
				return;
			}
			if (this.tryBuild()) {
				this.startObserving();
				return;
			}
			console.log(`${LOG$1} 未找到挂载目标,开始 MutationObserver 等待`);
			let mountDebounce = 0;
			const mountObserver = this.supervisor.observe(document.body, () => {
				clearTimeout(mountDebounce);
				mountDebounce = this.supervisor.setTimeout(() => {
					if (this.tryBuild()) {
						console.log(`${LOG$1} MutationObserver 挂载成功`);
						mountObserver.disconnect();
						this.startObserving();
						clearTimeout(mountTimeout);
					}
				}, 100);
			}, {
				childList: true,
				subtree: true
			});
			const mountTimeout = this.supervisor.setTimeout(() => {
				mountObserver.disconnect();
				if (!document.querySelector(".status-tag-filter-bar")) {
					const fallback = findMountTarget() || document.body.firstElementChild;
					if (fallback) {
						doBuild(fallback);
						this.startObserving();
						console.warn(`${LOG$1} 通过最终回退挂载`, fallback);
					} else console.warn(`${LOG$1} 超时后仍无挂载目标`);
				}
			}, 1e4);
		}
		tryBuild() {
			if (document.querySelector(".status-tag-filter-bar")) return true;
			const mountTarget = findMountTarget();
			if (!mountTarget) return false;
			doBuild(mountTarget);
			return true;
		}
		updateFilterBar() {
			const filterBar = document.querySelector(".status-tag-filter-bar");
			if (filterBar && filterBar._refreshChips) {
				filterBar._refreshChips();
				applyFilter$2();
			}
		}
		startObserving() {
			this.supervisor.observe(document.body, (mutations) => {
				let shouldRefresh = false;
				for (const mutation of mutations) {
					for (const node of mutation.addedNodes) {
						if (node.nodeType !== Node.ELEMENT_NODE) continue;
						const el = node;
						if (el.matches?.(".item") || el.querySelectorAll?.(".item").length > 0 || el.matches?.(".tag.is-success.status-tag") || el.querySelectorAll?.(".tag.is-success.status-tag").length > 0) {
							shouldRefresh = true;
							break;
						}
					}
					if (shouldRefresh) break;
				}
				if (shouldRefresh) {
					clearTimeout(this.observerDebounce);
					this.observerDebounce = this.supervisor.setTimeout(() => {
						this.updateFilterBar();
					}, 150);
				}
			}, {
				childList: true,
				subtree: true
			});
		}
		destroy() {
			this.supervisor.abort();
		}
	};
	var SCROLL_TOP_SVG_PATH = "M12 4l-8 8h6v8h4v-8h6z";
	function ScrollTopIcon() {
		return (0, import_jsx_runtime.jsx)("svg", {
			viewBox: "0 0 24 24",
			children: (0, import_jsx_runtime.jsx)("path", { d: SCROLL_TOP_SVG_PATH })
		});
	}
	function scrollTopIconHtml() {
		return jsxToString((0, import_jsx_runtime.jsx)(ScrollTopIcon, {}));
	}
	function createBackToTopButton(options) {
		const id = options?.selector ?? "jdb-wf-back-to-top";
		const threshold = options?.threshold ?? 300;
		if (document.getElementById("jhs-back-to-top") || document.getElementById(id)) return () => {};
		const btn = document.createElement("div");
		btn.id = id;
		btn.title = "回到顶部";
		btn.innerHTML = scrollTopIconHtml();
		document.body.appendChild(btn);
		let ticking = false;
		const onScroll = () => {
			if (ticking) return;
			ticking = true;
			window.requestAnimationFrame(() => {
				if (window.scrollY > threshold) btn.classList.add("show");
				else btn.classList.remove("show");
				ticking = false;
			});
		};
		const onClick = () => {
			window.scrollTo({
				top: 0,
				behavior: "smooth"
			});
		};
		window.addEventListener("scroll", onScroll, { passive: true });
		btn.addEventListener("click", onClick);
		return () => {
			window.removeEventListener("scroll", onScroll);
			btn.removeEventListener("click", onClick);
			btn.remove();
		};
	}
	var LOG_PREFIX$3 = "[listWaterfall]";
	var MAX_PAGES = 200;
	var SEL = {
		box: "#lists > ul",
		item: "#lists > ul > li",
		nextLink: "a.pagination-next",
		paginationNav: "nav.pagination",
		itemLink: "div.column.is-10 > a"
	};
	function findNextUrl(doc) {
		const a = doc.querySelector(SEL.nextLink);
		return a ? a.getAttribute("href") : null;
	}
	function toAbsolute(href) {
		return new URL(href, location.href).href;
	}
	function rewriteItemLinks(container) {
		container.querySelectorAll(SEL.itemLink).forEach((a) => {
			const anchor = a;
			anchor.target = "_blank";
			const href = anchor.getAttribute("href") || "";
			if (/^\/lists\/[^/]+$/.test(href)) return;
			const m = href.match(/[?&]id=([^&]+)/);
			if (m) anchor.href = `/lists/${m[1]}`;
		});
	}
	function gmGet(url) {
		return new Promise((resolve, reject) => {
			GM_xmlhttpRequest({
				method: "GET",
				url,
				timeout: 3e4,
				onload: (resp) => {
					if (resp.status >= 200 && resp.status < 300) resolve(resp.responseText);
					else reject(new Error(`HTTP ${resp.status}`));
				},
				onerror: () => reject(new Error("network error")),
				ontimeout: () => reject(new Error("timeout"))
			});
		});
	}
	function setState(plugin, cls, text) {
		if (!plugin.loader) return;
		plugin.loader.className = `jdb-wf-loader ${cls}`.trim();
		plugin.loader.textContent = text;
	}
	async function loadNextPage(plugin) {
		if (plugin.isLoading || !plugin.nextUrl || !plugin.hasMore) return;
		if (plugin.currentPage >= MAX_PAGES) {
			setState(plugin, "no-more", `已达最大页数 ${MAX_PAGES},停止加载`);
			plugin.hasMore = false;
			return;
		}
		plugin.isLoading = true;
		setState(plugin, "loading", "加载中...");
		try {
			const html = await gmGet(plugin.nextUrl);
			const doc = new DOMParser().parseFromString(html, "text/html");
			const remoteUl = doc.querySelector(SEL.box);
			if (!remoteUl) throw new Error("下一页未找到列表容器");
			const newLis = Array.from(remoteUl.children).filter((li) => li.tagName === "LI");
			if (newLis.length > 0 && newLis[0].id && plugin.loadedIds.has(newLis[0].id)) {
				plugin.hasMore = false;
				plugin.nextUrl = null;
				setState(plugin, "no-more", "已经到底了");
				console.log(`${LOG_PREFIX$3} 检测到重复数据,停止瀑布流`);
				return;
			}
			const topBefore = plugin.container.scrollHeight;
			const fragment = document.createDocumentFragment();
			newLis.forEach((li) => {
				if (li.id) plugin.loadedIds.add(li.id);
				fragment.appendChild(li);
			});
			plugin.container.appendChild(fragment);
			rewriteItemLinks(plugin.container);
			plugin.currentPage += 1;
			plugin.pageItems.push({
				page: plugin.currentPage,
				top: topBefore,
				url: plugin.nextUrl
			});
			const nextHref = findNextUrl(doc);
			plugin.nextUrl = nextHref ? toAbsolute(nextHref) : null;
			plugin.hasMore = !!plugin.nextUrl;
			const remoteNav = doc.querySelector(SEL.paginationNav);
			if (remoteNav) {
				const currentNav = document.querySelector(SEL.paginationNav);
				if (currentNav) currentNav.replaceWith(remoteNav);
			}
			setState(plugin, "", "");
			if (!plugin.hasMore) setState(plugin, "no-more", "已经到底了");
			console.log(`${LOG_PREFIX$3} 已加载第 ${plugin.currentPage} 页,追加 ${newLis.length} 项`);
		} catch (err) {
			clog.error(`${LOG_PREFIX$3} 加载失败:`, err);
			setState(plugin, "error", "加载失败,点击重试");
		} finally {
			plugin.isLoading = false;
		}
	}
	var PRELOAD_DISTANCE = 800;
	function checkLoad(plugin) {
		if (!plugin.loader || !plugin.hasMore) return;
		if (plugin.loader.getBoundingClientRect().top < window.innerHeight + PRELOAD_DISTANCE) loadNextPage(plugin);
	}
	function updateCurrentPageFromScroll(plugin) {
		const y = window.scrollY;
		for (let i = plugin.pageItems.length - 1; i >= 0; i--) {
			const item = plugin.pageItems[i];
			if (y >= item.top) {
				if (plugin.currentPage !== item.page) plugin.currentPage = item.page;
				break;
			}
		}
	}
	var list_waterfall_plugin_default = "/**\n * list-waterfall 插件样式 —— 瀑布流 loader 三态 + 回到顶部按钮。\n *\n * 原脚本 GM_addStyle(`...`) 注入(L80-153),此处提取为独立 .css,由 initCss()\n * 返回 → PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进\n * 标准化,CSS 解析忽略空白,渲染等价)。\n */\n.jdb-wf-loader {\n    text-align: center;\n    padding: 24px 0 40px;\n    font-size: 0.9rem;\n    color: #6c757d;\n    min-height: 44px;\n    box-sizing: border-box;\n}\n\n.jdb-wf-loader.loading {\n    color: #485fc7;\n}\n\n.jdb-wf-loader.loading::before {\n    content: \"\";\n    display: inline-block;\n    width: 14px;\n    height: 14px;\n    margin-right: 8px;\n    border: 2px solid currentcolor;\n    border-top-color: transparent;\n    border-radius: 50%;\n    vertical-align: -2px;\n    animation: jdb-wf-spin 0.8s linear infinite;\n}\n\n.jdb-wf-loader.error {\n    color: #f44336;\n    cursor: pointer;\n    text-decoration: underline;\n}\n\n.jdb-wf-loader.no-more {\n    color: #4CAF50;\n}\n\n@keyframes jdb-wf-spin {\n    to {\n        transform: rotate(360deg);\n    }\n}\n";
	var ENABLED_KEY = "jdb:list-waterfall-enabled";
	var ALLOWED_PATHS = new Set(["/users/lists", "/users/favorite_lists"]);
	function getInitialPage() {
		const m = location.search.match(/[?&]page=(\d+)/);
		return m ? parseInt(m[1], 10) : 1;
	}
	function isEnabled() {
		return GM_getValue(ENABLED_KEY, true);
	}
	var ListWaterfallPlugin = class extends BasePlugin {
		currentPage = getInitialPage();
		nextUrl = null;
		hasMore = false;
		isLoading = false;
		loader = null;
		container = null;
		loadedIds = new Set();
		pageItems = [];
		_onScroll = null;
		cleanupBackToTop = null;
		supervisor = new TaskSupervisor();
		getName() {
			return "ListWaterfallPlugin";
		}
		async initCss() {
			return list_waterfall_plugin_default;
		}
		async handle() {
			if (!ALLOWED_PATHS.has(location.pathname)) return;
			if (!isEnabled()) {
				console.log(`${LOG_PREFIX$3} 瀑布流已关闭,退出`);
				return;
			}
			GM_registerMenuCommand(`${isEnabled() ? "✓" : "✗"} 清单瀑布流自动翻页`, this.toggleEnabled.bind(this));
			this.init();
		}
		toggleEnabled() {
			const next = !isEnabled();
			GM_setValue(ENABLED_KEY, next);
			console.log(`${LOG_PREFIX$3} 瀑布流开关: ${next ? "开启" : "关闭"}`);
			if (window.confirm(`清单瀑布流自动翻页已${next ? "开启" : "关闭"},是否刷新页面应用?`)) window.location.reload();
		}
		init() {
			this.container = document.querySelector(SEL.box);
			if (!this.container) {
				console.warn(`${LOG_PREFIX$3} 未找到容器 ${SEL.box},退出`);
				return;
			}
			this.container.querySelectorAll(SEL.item).forEach((li) => {
				if (li.id) this.loadedIds.add(li.id);
			});
			this.loader = document.createElement("div");
			this.loader.className = "jdb-wf-loader";
			this.container.parentNode.insertBefore(this.loader, this.container.nextSibling);
			this.supervisor.addEventListener(this.loader, "click", () => {
				if (this.loader.classList.contains("error")) this.loadNextPage();
			});
			const nextHref = findNextUrl(document);
			this.nextUrl = nextHref ? toAbsolute(nextHref) : null;
			this.hasMore = !!this.nextUrl;
			this.pageItems.push({
				page: this.currentPage,
				top: 0,
				url: window.location.href
			});
			this.cleanupBackToTop = createBackToTopButton();
			this._onScroll = () => {
				this.checkLoad();
				this.updateCurrentPageFromScroll();
			};
			this.supervisor.addEventListener(window, "scroll", this._onScroll, { passive: true });
			this.supervisor.setTimeout(() => this.checkLoad(), 500);
			if (!this.hasMore) this.setState("no-more", "已经到底了");
			else this.setState("", "");
			console.log(`${LOG_PREFIX$3} 已启动 (页码 ${this.currentPage})`);
		}
		async loadNextPage() {
			return loadNextPage(this);
		}
		checkLoad() {
			checkLoad(this);
		}
		updateCurrentPageFromScroll() {
			updateCurrentPageFromScroll(this);
		}
		setState(cls, text) {
			setState(this, cls, text);
		}
		destroy() {
			this.cleanupBackToTop?.();
			this.supervisor.abort();
		}
	};
	var LOG_PREFIX$2 = "[listReadingStatus]";
	var STORAGE_KEY = "jdb:list-reading-status";
	var RATING_STORAGE_KEY = "jdb:list-rating";
	var LAST_URI_KEY = "jdb:list-last-uri";
	var SORT_KEY = "jdb:list-sort";
	var FILTER_READ_KEY = "jdb:list-filter-read";
	var FILTER_RATING_KEY = "jdb:list-filter-rating";
	var JHS_DB_NAME = "JAV-JHS";
	var JHS_STORE_NAME = "appData";
	var BACKUP_KEY = "listReadingStatus_data";
	function getRatingMap() {
		const raw = GM_getValue(RATING_STORAGE_KEY);
		if (!raw) return {};
		try {
			return JSON.parse(raw);
		} catch {
			return {};
		}
	}
	function saveRatingMap(map) {
		GM_setValue(RATING_STORAGE_KEY, JSON.stringify(map));
		syncToIndexedDB();
	}
	function setRating(listId, rating) {
		const map = getRatingMap();
		if (rating > 0) map[listId] = rating;
		else delete map[listId];
		saveRatingMap(map);
		console.log(`${LOG_PREFIX$2} 评分 ${listId}: ${rating || "清除"}`);
	}
	function getRating(listId) {
		return getRatingMap()[listId] || 0;
	}
	function getLastUriMap() {
		const raw = GM_getValue(LAST_URI_KEY);
		if (!raw) return {};
		try {
			return JSON.parse(raw);
		} catch {
			return {};
		}
	}
	function saveLastUri(listId) {
		const map = getLastUriMap();
		map[listId] = {
			path: location.pathname + location.search,
			timestamp: Date.now()
		};
		GM_setValue(LAST_URI_KEY, JSON.stringify(map));
		syncToIndexedDB();
	}
	function getLastUri(listId) {
		return getLastUriMap()[listId] || null;
	}
	function getReadSet() {
		const raw = GM_getValue(STORAGE_KEY);
		if (!raw) return new Set();
		try {
			const arr = JSON.parse(raw);
			return new Set(Array.isArray(arr) ? arr : []);
		} catch {
			return new Set();
		}
	}
	function saveReadSet(readSet) {
		GM_setValue(STORAGE_KEY, JSON.stringify([...readSet]));
		syncToIndexedDB();
	}
	function markAsRead(listId) {
		const readSet = getReadSet();
		readSet.add(listId);
		saveReadSet(readSet);
		console.log(`${LOG_PREFIX$2} 已标记已读完: ${listId}`);
	}
	function markAsUnread(listId) {
		const readSet = getReadSet();
		readSet.delete(listId);
		saveReadSet(readSet);
		console.log(`${LOG_PREFIX$2} 已取消标记: ${listId}`);
	}
	function isRead(listId) {
		return getReadSet().has(listId);
	}
	function openJhsDB() {
		return new Promise((resolve, reject) => {
			const request = indexedDB.open(JHS_DB_NAME);
			request.onsuccess = () => resolve(request.result);
			request.onerror = () => reject(request.error);
			request.onupgradeneeded = (event) => {
				const db = event.target.result;
				if (!db.objectStoreNames.contains(JHS_STORE_NAME)) db.createObjectStore(JHS_STORE_NAME);
			};
		});
	}
	function syncToIndexedDB() {
		try {
			const data = {
				readingStatus: [...getReadSet()],
				ratings: getRatingMap(),
				lastUris: getLastUriMap(),
				_updatedAt: new Date().toISOString()
			};
			openJhsDB().then((db) => {
				const tx = db.transaction(JHS_STORE_NAME, "readwrite");
				tx.objectStore(JHS_STORE_NAME).put(data, BACKUP_KEY);
				tx.oncomplete = () => db.close();
				tx.onerror = () => db.close();
			}).catch(() => {});
		} catch {}
	}
	async function restoreFromIndexedDB() {
		try {
			const db = await openJhsDB();
			const store = db.transaction(JHS_STORE_NAME, "readonly").objectStore(JHS_STORE_NAME);
			const data = await new Promise((resolve, reject) => {
				const req = store.get(BACKUP_KEY);
				req.onsuccess = () => resolve(req.result);
				req.onerror = reject;
			});
			db.close();
			if (!data || !data.readingStatus) return false;
			let restored = false;
			const localReadSet = getReadSet();
			const cloudRead = Array.isArray(data.readingStatus) ? data.readingStatus : [];
			const mergedRead = new Set([...localReadSet, ...cloudRead]);
			if (mergedRead.size > localReadSet.size) {
				GM_setValue(STORAGE_KEY, JSON.stringify([...mergedRead]));
				restored = true;
			}
			const localRatings = getRatingMap();
			const cloudRatings = data.ratings && typeof data.ratings === "object" ? data.ratings : {};
			let ratingChanged = false;
			for (const [id, rating] of Object.entries(cloudRatings)) if (!(id in localRatings)) {
				localRatings[id] = rating;
				ratingChanged = true;
			}
			if (ratingChanged) {
				GM_setValue(RATING_STORAGE_KEY, JSON.stringify(localRatings));
				restored = true;
			}
			const localLastUris = getLastUriMap();
			const cloudLastUris = data.lastUris && typeof data.lastUris === "object" ? data.lastUris : {};
			let lastUriChanged = false;
			for (const [id, uri] of Object.entries(cloudLastUris)) {
				const local = localLastUris[id];
				const cloudUri = uri;
				if (!local || cloudUri.timestamp && cloudUri.timestamp > (local.timestamp || 0)) {
					localLastUris[id] = cloudUri;
					lastUriChanged = true;
				}
			}
			if (lastUriChanged) {
				GM_setValue(LAST_URI_KEY, JSON.stringify(localLastUris));
				restored = true;
			}
			if (restored) console.log(`${LOG_PREFIX$2} 已从云端合并恢复数据 (更新于 ${data._updatedAt || "未知"})`);
			return restored;
		} catch {
			return false;
		}
	}
	var STAR_PATH = "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z";
	var LRS_HIDDEN_ATTR = "data-lrs-hidden";
	var LRS_ORDER_ATTR = "data-lrs-order";
	function updateSelectAppearance(select) {
		select.setAttribute("data-status", select.value);
	}
	function renderStars(starsEl, rating) {
		starsEl.querySelectorAll(".list-rating-star").forEach((svg, i) => {
			if (i < rating) svg.classList.add("filled");
			else svg.classList.remove("filled");
		});
	}
	function createStarWidget(plugin, listId) {
		const container = document.createElement("span");
		container.className = "list-rating-stars";
		container.title = "评分 1-5 星,再次点击取消评分";
		const currentRating = getRating(listId);
		const NS = "http://www.w3.org/2000/svg";
		for (let i = 1; i <= 5; i++) {
			const svg = document.createElementNS(NS, "svg");
			svg.setAttribute("viewBox", "0 0 24 24");
			svg.classList.add("list-rating-star");
			svg.dataset.rating = String(i);
			const path = document.createElementNS(NS, "path");
			path.setAttribute("d", STAR_PATH);
			svg.appendChild(path);
			if (i <= currentRating) svg.classList.add("filled");
			plugin.supervisor.addEventListener(svg, "click", (e) => {
				e.stopPropagation();
				const clicked = parseInt(svg.dataset.rating || "0");
				const newRating = clicked === getRating(listId) ? 0 : clicked;
				setRating(listId, newRating);
				renderStars(container, newRating);
			});
			plugin.supervisor.addEventListener(svg, "mouseenter", () => {
				renderStars(container, parseInt(svg.dataset.rating || "0"));
			});
			container.appendChild(svg);
		}
		plugin.supervisor.addEventListener(container, "mouseleave", () => {
			renderStars(container, getRating(listId));
		});
		return container;
	}
	function createDropdown(plugin, listId) {
		const select = document.createElement("select");
		select.className = "list-reading-dropdown";
		const optionUnread = document.createElement("option");
		optionUnread.value = "unread";
		optionUnread.textContent = "未读完";
		const optionRead = document.createElement("option");
		optionRead.value = "read";
		optionRead.textContent = "已读完";
		select.appendChild(optionUnread);
		select.appendChild(optionRead);
		select.value = isRead(listId) ? "read" : "unread";
		updateSelectAppearance(select);
		plugin.supervisor.addEventListener(select, "change", () => {
			if (select.value === "read") markAsRead(listId);
			else markAsUnread(listId);
			updateSelectAppearance(select);
		});
		return select;
	}
	function ensureWidgets(plugin, li) {
		const listId = li.id;
		if (!listId) return;
		const container = li.querySelector(":scope > div");
		if (!container) return;
		let select = container.querySelector(".list-reading-dropdown");
		if (select) {
			select.value = isRead(listId) ? "read" : "unread";
			updateSelectAppearance(select);
		} else {
			select = createDropdown(plugin, listId);
			container.prepend(select);
		}
		let stars = container.querySelector(".list-rating-stars");
		if (stars) renderStars(stars, getRating(listId));
		else {
			stars = createStarWidget(plugin, listId);
			container.prepend(stars);
		}
		let uriLink = container.querySelector(".list-last-uri-link");
		const lastUri = getLastUri(listId);
		if (lastUri) {
			if (!uriLink) {
				uriLink = document.createElement("a");
				uriLink.className = "list-last-uri-link";
				const d = new Date(lastUri.timestamp);
				const pad = (n) => String(n).padStart(2, "0");
				const dateStr = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
				const search = lastUri.path.includes("?") ? " " + lastUri.path.slice(lastUri.path.indexOf("?") + 1) : "";
				uriLink.textContent = `继续浏览 →${search} (${dateStr})`;
				container.appendChild(uriLink);
			}
			uriLink.href = lastUri.path;
		} else if (uriLink) uriLink.remove();
	}
	function ensureHeaderWidgets(plugin) {
		if (plugin.isProcessing) return;
		plugin.isProcessing = true;
		const m = location.pathname.match(/\/lists\/([^/]+)$/);
		if (!m) {
			plugin.isProcessing = false;
			return;
		}
		const listId = "list-" + m[1];
		saveLastUri(listId);
		const h2 = document.querySelector("body > section > div > div.columns.is-mobile.section-columns > div > h2");
		if (!h2) {
			plugin.isProcessing = false;
			return;
		}
		let select = h2.querySelector(".list-reading-dropdown");
		if (select) {
			select.value = isRead(listId) ? "read" : "unread";
			updateSelectAppearance(select);
		} else {
			select = createDropdown(plugin, listId);
			h2.prepend(select);
		}
		let stars = h2.querySelector(".list-rating-stars");
		if (stars) renderStars(stars, getRating(listId));
		else {
			stars = createStarWidget(plugin, listId);
			h2.prepend(stars);
		}
		Promise.resolve().then(() => {
			plugin.isProcessing = false;
		});
	}
	function processAllItems(plugin) {
		if (plugin.isProcessing) return false;
		plugin.isProcessing = true;
		const ul = document.querySelector("#lists > ul");
		if (!ul) {
			plugin.isProcessing = false;
			return false;
		}
		const items = ul.querySelectorAll(":scope > li");
		items.forEach((li) => ensureWidgets(plugin, li));
		plugin.applySortAndFilter();
		Promise.resolve().then(() => {
			plugin.isProcessing = false;
		});
		return items.length > 0;
	}
	function getListMeta(_plugin, li) {
		const listId = li.id || "";
		const titleEl = li.querySelector("a[href*='/lists/']");
		const title = titleEl ? titleEl.textContent.trim() : "";
		const metaTxt = li.querySelector(".meta")?.textContent ?? "";
		const moviesMatch = metaTxt.match(/([\d,]+)\s*部影片/);
		const clicksMatch = metaTxt.match(/點擊了\s*([\d,]+)/);
		return {
			listId,
			title,
			movies: moviesMatch ? parseInt(moviesMatch[1].replace(/,/g, "")) : 0,
			clicks: clicksMatch ? parseInt(clicksMatch[1].replace(/,/g, "")) : 0,
			rating: getRating(listId),
			visited: getLastUri(listId)?.timestamp ?? 0,
			order: parseInt(li.getAttribute("data-lrs-order") || "0") || 0
		};
	}
	function ensureLiOrder(plugin, li) {
		if (!li.hasAttribute("data-lrs-order")) li.setAttribute(LRS_ORDER_ATTR, String(plugin.orderCounter++));
	}
	function compareLi(plugin, a, b) {
		const ma = getListMeta(plugin, a);
		const mb = getListMeta(plugin, b);
		let cmp;
		switch (plugin.currentSort) {
			case "rating-desc":
				cmp = mb.rating - ma.rating;
				break;
			case "rating-asc":
				cmp = ma.rating - mb.rating;
				break;
			case "movies-desc":
				cmp = mb.movies - ma.movies;
				break;
			case "movies-asc":
				cmp = ma.movies - mb.movies;
				break;
			case "clicks-desc":
				cmp = mb.clicks - ma.clicks;
				break;
			case "clicks-asc":
				cmp = ma.clicks - mb.clicks;
				break;
			case "visited-desc":
				cmp = mb.visited - ma.visited;
				break;
			case "visited-asc":
				cmp = ma.visited - mb.visited;
				break;
			case "title-asc":
				cmp = ma.title.localeCompare(mb.title, "zh");
				break;
			default: cmp = 0;
		}
		if (cmp === 0) cmp = ma.order - mb.order;
		return cmp;
	}
	function applySort(plugin) {
		if (plugin.currentSort === "default") return;
		const ul = document.querySelector("#lists > ul");
		if (!ul) return;
		const lis = [...ul.querySelectorAll(":scope > li")];
		if (lis.length < 2) return;
		lis.forEach((li) => ensureLiOrder(plugin, li));
		lis.sort((a, b) => compareLi(plugin, a, b));
		if (lis.map((li) => li.id).join(",") === [...ul.querySelectorAll(":scope > li")].map((li) => li.id).join(",")) return;
		const frag = document.createDocumentFragment();
		lis.forEach((li) => frag.appendChild(li));
		ul.appendChild(frag);
	}
	function saveFilterReadState(plugin, v) {
		plugin.filterReadStatus = v;
		GM_setValue(FILTER_READ_KEY, v);
	}
	function saveFilterRatingState(plugin, set) {
		plugin.filterRatingChips = set;
		GM_setValue(FILTER_RATING_KEY, JSON.stringify([...set]));
	}
	function matchesFilter(plugin, li) {
		const listId = li.id;
		if (!listId) return true;
		if (plugin.filterReadStatus !== "all") {
			const read = isRead(listId);
			if (plugin.filterReadStatus === "read" && !read) return false;
			if (plugin.filterReadStatus === "unread" && read) return false;
		}
		if (plugin.filterRatingChips.size > 0) {
			const rating = getRating(listId);
			let match = false;
			if (plugin.filterRatingChips.has("rated") && rating > 0) match = true;
			if (plugin.filterRatingChips.has("unrated") && rating === 0) match = true;
			for (let i = 1; i <= 5; i++) if (plugin.filterRatingChips.has(`rating-${i}`) && rating === i) {
				match = true;
				break;
			}
			if (!match) return false;
		}
		return true;
	}
	function applyFilter$1(plugin) {
		const ul = document.querySelector("#lists > ul");
		if (!ul) return;
		const lis = ul.querySelectorAll(":scope > li");
		if (plugin.filterReadStatus === "all" && plugin.filterRatingChips.size === 0) {
			lis.forEach((li) => {
				const htmlLi = li;
				if (htmlLi.hasAttribute("data-lrs-hidden")) {
					htmlLi.removeAttribute(LRS_HIDDEN_ATTR);
					htmlLi.style.display = "";
				}
			});
			return;
		}
		lis.forEach((li) => {
			const htmlLi = li;
			if (htmlLi.style.display === "none" && !htmlLi.hasAttribute("data-lrs-hidden")) return;
			if (matchesFilter(plugin, htmlLi)) {
				htmlLi.removeAttribute(LRS_HIDDEN_ATTR);
				htmlLi.style.display = "";
			} else {
				htmlLi.setAttribute(LRS_HIDDEN_ATTR, "");
				htmlLi.style.display = "none";
			}
		});
	}
	function applySortAndFilter(plugin) {
		if (plugin.isToolbarProcessing) return;
		plugin.isToolbarProcessing = true;
		try {
			applySort(plugin);
			applyFilter$1(plugin);
		} finally {
			plugin.isToolbarProcessing = false;
		}
	}
	function countFilterStats() {
		const stats = {
			read: 0,
			unread: 0,
			rated: 0,
			unrated: 0,
			stars: [
				0,
				0,
				0,
				0,
				0
			]
		};
		const ul = document.querySelector("#lists > ul");
		if (!ul) return stats;
		ul.querySelectorAll(":scope > li").forEach((li) => {
			const id = li.id;
			if (!id) return;
			if (isRead(id)) stats.read++;
			else stats.unread++;
			const r = getRating(id);
			if (r > 0) {
				stats.rated++;
				if (r >= 1 && r <= 5) stats.stars[r - 1]++;
			} else stats.unrated++;
		});
		return stats;
	}
	function createFilterChip$1(plugin, label, value, count) {
		const chip = document.createElement("span");
		chip.className = "list-filter-chip";
		chip.dataset.value = value;
		const labelText = document.createElement("span");
		labelText.textContent = label;
		chip.appendChild(labelText);
		const countSpan = document.createElement("span");
		countSpan.className = "chip-count";
		countSpan.textContent = String(count);
		chip.appendChild(countSpan);
		plugin.supervisor.addEventListener(chip, "click", () => {
			if (value === "read" || value === "unread") {
				const wasActive = chip.classList.contains("active");
				document.querySelectorAll(".list-filter-chip[data-value='read'], .list-filter-chip[data-value='unread']").forEach((c) => c.classList.remove("active"));
				if (!wasActive) {
					chip.classList.add("active");
					saveFilterReadState(plugin, value);
				} else saveFilterReadState(plugin, "all");
			} else {
				chip.classList.toggle("active");
				const next = new Set(plugin.filterRatingChips);
				if (chip.classList.contains("active")) next.add(value);
				else next.delete(value);
				saveFilterRatingState(plugin, next);
			}
			applySortAndFilter(plugin);
		});
		return chip;
	}
	function loadToolbarState(plugin) {
		const s = GM_getValue(SORT_KEY);
		if (s) plugin.currentSort = s;
		const r = GM_getValue(FILTER_READ_KEY);
		if (r === "read" || r === "unread") plugin.filterReadStatus = r;
		const rc = GM_getValue(FILTER_RATING_KEY);
		if (rc) try {
			const arr = JSON.parse(rc);
			if (Array.isArray(arr)) plugin.filterRatingChips = new Set(arr);
		} catch {
			plugin.filterRatingChips = new Set();
		}
	}
	function saveSortState(plugin, v) {
		plugin.currentSort = v;
		GM_setValue(SORT_KEY, v);
	}
	function buildToolbar(plugin) {
		if (plugin.isDetailPage) return null;
		const lists = document.querySelector("#lists");
		if (!lists) return null;
		if (document.querySelector(".list-toolbar")) return document.querySelector(".list-toolbar");
		const toolbar = document.createElement("div");
		toolbar.className = "list-toolbar";
		const sortGroup = document.createElement("div");
		sortGroup.className = "list-toolbar-group";
		const sortLabel = document.createElement("span");
		sortLabel.className = "list-toolbar-label";
		sortLabel.textContent = "排序:";
		const sortSelect = document.createElement("select");
		sortSelect.className = "list-sort-select";
		[
			["default", "默认"],
			["rating-desc", "评分 ↓"],
			["rating-asc", "评分 ↑"],
			["movies-desc", "影片数 ↓"],
			["movies-asc", "影片数 ↑"],
			["clicks-desc", "点击数 ↓"],
			["clicks-asc", "点击数 ↑"],
			["visited-desc", "最近访问 ↓"],
			["visited-asc", "最久访问 ↓"],
			["title-asc", "标题 A-Z"]
		].forEach(([val, txt]) => {
			const opt = document.createElement("option");
			opt.value = val;
			opt.textContent = txt;
			if (val === plugin.currentSort) opt.selected = true;
			sortSelect.appendChild(opt);
		});
		plugin.supervisor.addEventListener(sortSelect, "change", () => {
			saveSortState(plugin, sortSelect.value);
			applySortAndFilter(plugin);
		});
		sortGroup.appendChild(sortLabel);
		sortGroup.appendChild(sortSelect);
		toolbar.appendChild(sortGroup);
		const div1 = document.createElement("div");
		div1.className = "list-filter-divider";
		toolbar.appendChild(div1);
		const readGroup = document.createElement("div");
		readGroup.className = "list-toolbar-group";
		const readLabel = document.createElement("span");
		readLabel.className = "list-toolbar-label";
		readLabel.textContent = "阅读:";
		readGroup.appendChild(readLabel);
		const readChipsHost = document.createElement("div");
		readGroup.appendChild(readChipsHost);
		toolbar.appendChild(readGroup);
		const div2 = document.createElement("div");
		div2.className = "list-filter-divider";
		toolbar.appendChild(div2);
		const ratingGroup = document.createElement("div");
		ratingGroup.className = "list-toolbar-group";
		const ratingLabel = document.createElement("span");
		ratingLabel.className = "list-toolbar-label";
		ratingLabel.textContent = "评分:";
		ratingGroup.appendChild(ratingLabel);
		const ratingChipsHost = document.createElement("div");
		ratingGroup.appendChild(ratingChipsHost);
		toolbar.appendChild(ratingGroup);
		const reset = document.createElement("a");
		reset.className = "list-toolbar-reset";
		reset.textContent = "重置筛选";
		plugin.supervisor.addEventListener(reset, "click", (e) => {
			e.preventDefault();
			saveSortState(plugin, "default");
			saveFilterReadState(plugin, "all");
			saveFilterRatingState(plugin, new Set());
			sortSelect.value = "default";
			toolbar.querySelectorAll(".list-filter-chip.active").forEach((c) => c.classList.remove("active"));
			applySortAndFilter(plugin);
		});
		toolbar.appendChild(reset);
		lists.insertAdjacentElement("beforebegin", toolbar);
		toolbar._readHost = readChipsHost;
		toolbar._ratingHost = ratingChipsHost;
		toolbar._sortSelect = sortSelect;
		refreshChips$1(plugin, toolbar);
		console.log(`${LOG_PREFIX$2} 排序与筛选工具栏已挂载`);
		return toolbar;
	}
	function refreshChips$1(plugin, toolbar) {
		const stats = countFilterStats();
		const readHost = toolbar._readHost;
		if (readHost) {
			readHost.innerHTML = "";
			const readChip = createFilterChip$1(plugin, "已读完", "read", stats.read);
			if (plugin.filterReadStatus === "read") readChip.classList.add("active");
			readHost.appendChild(readChip);
			const unreadChip = createFilterChip$1(plugin, "未读完", "unread", stats.unread);
			if (plugin.filterReadStatus === "unread") unreadChip.classList.add("active");
			readHost.appendChild(unreadChip);
		}
		const ratingHost = toolbar._ratingHost;
		if (ratingHost) {
			ratingHost.innerHTML = "";
			const ratedChip = createFilterChip$1(plugin, "有评分", "rated", stats.rated);
			if (plugin.filterRatingChips.has("rated")) ratedChip.classList.add("active");
			ratingHost.appendChild(ratedChip);
			const unratedChip = createFilterChip$1(plugin, "无评分", "unrated", stats.unrated);
			if (plugin.filterRatingChips.has("unrated")) unratedChip.classList.add("active");
			ratingHost.appendChild(unratedChip);
			for (let i = 1; i <= 5; i++) {
				const starChip = createFilterChip$1(plugin, `${i}星`, `rating-${i}`, stats.stars[i - 1]);
				if (plugin.filterRatingChips.has(`rating-${i}`)) starChip.classList.add("active");
				ratingHost.appendChild(starChip);
			}
		}
	}
	function tryBuildToolbar(plugin) {
		if (plugin.isDetailPage) return false;
		const toolbar = buildToolbar(plugin);
		if (!toolbar) return false;
		refreshChips$1(plugin, toolbar);
		applySortAndFilter(plugin);
		return true;
	}
	function restoreToolbarUI(plugin) {
		const toolbar = document.querySelector(".list-toolbar");
		if (!toolbar) return;
		const sortSelect = toolbar._sortSelect;
		if (sortSelect) sortSelect.value = plugin.currentSort;
		refreshChips$1(plugin, toolbar);
	}
	var list_reading_status_plugin_default = "/**\n * list-reading-status 插件样式 —— 阅读进度下拉框 + 星级评分 + 排序筛选工具栏。\n *\n * 原脚本 3 段 GM_addStyle(L263-303 下拉框 / L305-349 星级评分+访问链接 /\n * L353-445 工具栏),此处合并提取为独立 .css,由 initCss() 返回 →\n * PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进标准化,\n * CSS 解析忽略空白,渲染等价)。\n */\n\n/* ---------- 阅读进度下拉框 ---------- */\n.list-reading-dropdown {\n    appearance: none;\n    -webkit-appearance: none;\n    display: inline-flex;\n    align-items: center;\n    height: 24px;\n    padding: 0 24px 0 10px;\n    font-size: 0.72rem;\n    font-weight: 600;\n    line-height: 22px;\n    border-radius: 50rem;\n    cursor: pointer;\n    user-select: none;\n    border: 1.5px solid #ced4da;\n    color: #6c757d;\n    background-color: #fff;\n    background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%236c757d'/%3E%3C/svg%3E\");\n    background-repeat: no-repeat;\n    background-position: right 8px center;\n    background-size: 10px 6px;\n    transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;\n    margin-right: 6px;\n    vertical-align: middle;\n}\n\n.list-reading-dropdown:hover {\n    border-color: #adb5bd;\n    background-color: #f8f9fa;\n}\n\n.list-reading-dropdown[data-status=\"read\"] {\n    color: #fff;\n    background-color: #198754;\n    border-color: #198754;\n    background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23fff'/%3E%3C/svg%3E\");\n}\n\n.list-reading-dropdown[data-status=\"read\"]:hover {\n    background-color: #157347;\n    border-color: #157347;\n}\n\n/* ---------- 星级评分 ---------- */\n.list-rating-stars {\n    display: inline-flex;\n    gap: 2px;\n    cursor: pointer;\n    user-select: none;\n    margin-right: 10px;\n    vertical-align: middle;\n    align-items: center;\n}\n\n.list-rating-star {\n    width: 18px;\n    height: 18px;\n    flex-shrink: 0;\n    transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),\n                filter 0.2s ease;\n}\n\n.list-rating-star path {\n    fill: #cbd5e1;\n    stroke: #94a3b8;\n    stroke-width: 0.6;\n    transition: fill 0.2s ease, stroke 0.2s ease;\n}\n\n.list-rating-star.filled path {\n    fill: #f59e0b;\n    stroke: #d97706;\n}\n\n.list-rating-star:hover {\n    transform: scale(1.25);\n}\n\n.list-rating-star.filled:hover {\n    filter: drop-shadow(0 0 5px rgb(245, 158, 11, 0.45));\n}\n\n.list-last-uri-link {\n    font-size: 0.72rem;\n    color: #485fc7;\n    margin-left: 8px;\n    text-decoration: none;\n    transition: color 0.15s ease;\n}\n\n.list-last-uri-link:hover {\n    color: #363636;\n    text-decoration: underline;\n}\n\n/* ---------- 排序与筛选工具栏 ---------- */\n.list-toolbar {\n    display: flex;\n    flex-wrap: wrap;\n    align-items: center;\n    gap: 8px 16px;\n    padding: 10px 0;\n    margin-bottom: 6px;\n    border-bottom: 1px solid #e9ecef;\n    font-size: 0.82rem;\n}\n\n.list-toolbar-group {\n    display: flex;\n    align-items: center;\n    gap: 6px;\n    flex-wrap: wrap;\n}\n\n.list-toolbar-label {\n    font-weight: 600;\n    color: #6c757d;\n    flex-shrink: 0;\n}\n\n.list-sort-select {\n    appearance: none;\n    -webkit-appearance: none;\n    height: 26px;\n    padding: 0 22px 0 10px;\n    font-size: 0.78rem;\n    font-weight: 600;\n    border: 1.5px solid #ced4da;\n    border-radius: 50rem;\n    color: #495057;\n    background-color: #fff;\n    background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%236c757d'/%3E%3C/svg%3E\");\n    background-repeat: no-repeat;\n    background-position: right 8px center;\n    background-size: 10px 6px;\n    cursor: pointer;\n    transition: background-color 0.2s ease, border-color 0.2s ease;\n}\n\n.list-sort-select:hover {\n    border-color: #adb5bd;\n    background-color: #f8f9fa;\n}\n\n.list-filter-chip {\n    display: inline-flex;\n    align-items: center;\n    padding: 2px 10px;\n    font-size: 0.76rem;\n    font-weight: 600;\n    border: 1.5px solid #dee2e6;\n    border-radius: 50rem;\n    color: #6c757d;\n    background-color: #fff;\n    cursor: pointer;\n    user-select: none;\n    transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;\n    line-height: 1.4;\n}\n\n.list-filter-chip:hover {\n    border-color: #adb5bd;\n    background-color: #f8f9fa;\n}\n\n.list-filter-chip.active {\n    color: #fff;\n    background-color: #485fc7;\n    border-color: #485fc7;\n}\n\n.list-filter-chip .chip-count {\n    margin-left: 4px;\n    opacity: 0.85;\n    font-weight: 700;\n}\n\n.list-filter-divider {\n    width: 1px;\n    height: 18px;\n    background: #dee2e6;\n    margin: 0 4px;\n    flex-shrink: 0;\n}\n\n.list-toolbar-reset {\n    font-size: 0.74rem;\n    color: #adb5bd;\n    cursor: pointer;\n    text-decoration: none;\n    margin-left: auto;\n    transition: color 0.15s ease;\n}\n\n.list-toolbar-reset:hover {\n    color: #6c757d;\n    text-decoration: underline;\n}\n";
	var ListReadingStatusPlugin = class extends BasePlugin {
		isProcessing = false;
		currentSort = "default";
		filterReadStatus = "all";
		filterRatingChips = new Set();
		isToolbarProcessing = false;
		orderCounter = 0;
		lastLiCount = -1;
		supervisor = new TaskSupervisor();
		isDetailPage = false;
		getName() {
			return "ListReadingStatusPlugin";
		}
		async initCss() {
			return list_reading_status_plugin_default;
		}
		async handle() {
			const pathname = location.pathname;
			const isListPage = pathname.startsWith("/users/favorite_lists") || pathname.startsWith("/users/lists");
			const isDetail = /\/lists\/[^/]+$/.test(pathname);
			if (!isListPage && !isDetail) return;
			this.isDetailPage = isDetail;
			this.loadToolbarState();
			if (this.isDetailPage) this.ensureHeaderWidgets();
			else {
				this.processAllItems();
				this.tryBuildToolbar();
			}
			restoreFromIndexedDB().then((restored) => {
				if (restored) if (this.isDetailPage) this.ensureHeaderWidgets();
				else {
					this.processAllItems();
					const tb = document.querySelector(".list-toolbar");
					if (tb) this.refreshChips(tb);
				}
			});
			this.supervisor.observe(document.body, () => {
				if (this.isProcessing) return;
				if (this.isDetailPage) this.ensureHeaderWidgets();
				else {
					this.processAllItems();
					const ul = document.querySelector("#lists > ul");
					const cnt = ul ? ul.querySelectorAll(":scope > li").length : 0;
					if (cnt !== this.lastLiCount) {
						this.lastLiCount = cnt;
						const tb = document.querySelector(".list-toolbar");
						if (tb) this.refreshChips(tb);
					}
				}
			}, {
				childList: true,
				subtree: true
			});
			if (typeof GM_addValueChangeListener !== "undefined") {
				const refreshListToolbar = () => {
					if (this.isDetailPage) return;
					const tb = document.querySelector(".list-toolbar");
					if (tb) this.refreshChips(tb);
				};
				GM_addValueChangeListener(STORAGE_KEY, () => {
					if (this.isDetailPage) this.ensureHeaderWidgets();
					else {
						this.processAllItems();
						refreshListToolbar();
					}
				});
				GM_addValueChangeListener(RATING_STORAGE_KEY, () => {
					if (this.isDetailPage) this.ensureHeaderWidgets();
					else {
						this.processAllItems();
						refreshListToolbar();
					}
				});
				GM_addValueChangeListener(SORT_KEY, () => {
					const v = GM_getValue(SORT_KEY);
					if (v) this.currentSort = v;
					if (this.isDetailPage) return;
					this.restoreToolbarUI();
					this.applySortAndFilter();
				});
				GM_addValueChangeListener(FILTER_READ_KEY, () => {
					const v = GM_getValue(FILTER_READ_KEY);
					if (v === "read" || v === "unread") this.filterReadStatus = v;
					else this.filterReadStatus = "all";
					if (this.isDetailPage) return;
					this.restoreToolbarUI();
					this.applySortAndFilter();
				});
				GM_addValueChangeListener(FILTER_RATING_KEY, () => {
					const rc = GM_getValue(FILTER_RATING_KEY);
					try {
						const arr = JSON.parse(rc);
						this.filterRatingChips = new Set(Array.isArray(arr) ? arr : []);
					} catch {
						this.filterRatingChips = new Set();
					}
					if (this.isDetailPage) return;
					this.restoreToolbarUI();
					this.applySortAndFilter();
				});
			}
		}
		loadToolbarState() {
			loadToolbarState(this);
		}
		ensureHeaderWidgets() {
			ensureHeaderWidgets(this);
		}
		processAllItems() {
			return processAllItems(this);
		}
		tryBuildToolbar() {
			return tryBuildToolbar(this);
		}
		refreshChips(toolbar) {
			refreshChips$1(this, toolbar);
		}
		restoreToolbarUI() {
			restoreToolbarUI(this);
		}
		applySortAndFilter() {
			applySortAndFilter(this);
		}
		destroy() {
			this.supervisor.abort();
		}
	};
	var LOG_PREFIX$1 = "[modalListDisabler]";
	var TARGET_LIST_ID = 501;
	var CONTAINER_SELECTOR = "#modal-save-list > div.modal-card.fixed-height-600 > section > div > div:nth-child(1)";
	var ModalListDisablerPlugin = class extends BasePlugin {
		supervisor = new TaskSupervisor();
		getName() {
			return "ModalListDisablerPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			this.tryDisable();
			this.supervisor.observe(document.body, () => {
				this.tryDisable();
			}, {
				childList: true,
				subtree: true
			});
		}
		destroy() {
			this.supervisor.abort();
		}
		disableTargetItem(container) {
			let found = false;
			for (const child of Array.from(container.children)) {
				const span = child.querySelector("label > span");
				if (!span) continue;
				const match = span.innerHTML.match(/\((\d+)\)/);
				if (match && parseInt(match[1], 10) === TARGET_LIST_ID) {
					const input = child.querySelector("label > input");
					if (input && !input.disabled && !input.checked) {
						input.disabled = true;
						console.log(`${LOG_PREFIX$1} 已禁用清单 #${TARGET_LIST_ID}`);
					}
					found = true;
				}
			}
			return found;
		}
		tryDisable() {
			const container = document.querySelector(CONTAINER_SELECTOR);
			if (!container) return false;
			return this.disableTargetItem(container);
		}
	};
	var TAG_HIDDEN_ATTR = "data-video-lists-tag-hidden";
	var FILTER_MODES = {
		CONTAINS_ANY: "contains-any",
		CONTAINS_ALL: "contains-all",
		EXCLUDES_ALL: "excludes-all",
		EXCLUDES_ANY: "excludes-any"
	};
	function collectAllUniqueTags() {
		const tagNames = new Set();
		document.querySelectorAll(".jhs-vlt-tag-link:not([style*='pointer-events: none'])").forEach((el) => {
			const name = el.textContent?.trim() || "";
			if (name && name !== "—") tagNames.add(name);
		});
		return [...tagNames].sort();
	}
	function collectTagCounts() {
		const counts = {};
		document.querySelectorAll(".jhs-vlt-tag-link:not([style*='pointer-events: none'])").forEach((el) => {
			const name = el.textContent?.trim() || "";
			if (name && name !== "—") counts[name] = (counts[name] || 0) + 1;
		});
		return counts;
	}
	function countNoTagItems() {
		let count = 0;
		document.querySelectorAll(".item").forEach((item) => {
			if (item.querySelectorAll(".jhs-vlt-tag-link:not([style*='pointer-events: none'])").length === 0) count++;
		});
		return count;
	}
	function applyFilter(plugin) {
		const activeChips = document.querySelectorAll(".jhs-vlt-filter-chip.jhs-vlt-active");
		const selectedValues = new Set(Array.from(activeChips).map((c) => c.dataset.value || ""));
		if (selectedValues.size === 0) {
			document.querySelectorAll(`.item[${TAG_HIDDEN_ATTR}]`).forEach((item) => {
				item.removeAttribute(TAG_HIDDEN_ATTR);
				item.style.display = "";
			});
			return;
		}
		const showNoTag = selectedValues.has("no-tag");
		const selectedTags = new Set([...selectedValues].filter((v) => v !== "no-tag"));
		document.querySelectorAll(".item").forEach((item) => {
			const htmlItem = item;
			if (htmlItem.style.display === "none" && !htmlItem.hasAttribute("data-video-lists-tag-hidden")) return;
			const tagLinks = item.querySelectorAll(".jhs-vlt-tag-link:not([style*='pointer-events: none'])");
			const itemTagNames = new Set(Array.from(tagLinks).map((el) => el.textContent?.trim() || ""));
			let tagMatch = false;
			if (selectedTags.size > 0) switch (plugin.currentFilterMode) {
				case FILTER_MODES.CONTAINS_ANY:
					tagMatch = [...selectedTags].some((t) => itemTagNames.has(t));
					break;
				case FILTER_MODES.CONTAINS_ALL:
					tagMatch = [...selectedTags].every((t) => itemTagNames.has(t));
					break;
				case FILTER_MODES.EXCLUDES_ALL:
					tagMatch = ![...selectedTags].some((t) => itemTagNames.has(t));
					break;
				case FILTER_MODES.EXCLUDES_ANY:
					tagMatch = ![...selectedTags].every((t) => itemTagNames.has(t));
					break;
				default: tagMatch = [...selectedTags].some((t) => itemTagNames.has(t));
			}
			const noTagMatch = showNoTag && itemTagNames.size === 0;
			if (tagMatch || noTagMatch) {
				htmlItem.removeAttribute(TAG_HIDDEN_ATTR);
				htmlItem.style.display = "";
			} else {
				htmlItem.setAttribute(TAG_HIDDEN_ATTR, "");
				htmlItem.style.display = "none";
			}
		});
	}
	var FILTER_MODE_CONFIG = [
		{
			value: FILTER_MODES.CONTAINS_ANY,
			label: "包含任意一个",
			group: "include"
		},
		{
			value: FILTER_MODES.CONTAINS_ALL,
			label: "全都包含",
			group: "include"
		},
		{
			value: FILTER_MODES.EXCLUDES_ALL,
			label: "不包含以下标签",
			group: "exclude"
		},
		{
			value: FILTER_MODES.EXCLUDES_ANY,
			label: "不包含以下任意一个",
			group: "exclude"
		}
	];
	function buildFilterModeDropdown(plugin) {
		const details = document.createElement("details");
		details.className = "jhs-vlt-filter-mode-dropdown";
		const summary = document.createElement("summary");
		summary.className = "jhs-vlt-filter-mode-summary";
		const indicator = document.createElement("span");
		indicator.className = "jhs-vlt-filter-mode-indicator";
		summary.appendChild(indicator);
		const modeText = document.createElement("span");
		modeText.className = "jhs-vlt-filter-mode-text";
		summary.appendChild(modeText);
		const arrow = document.createElement("span");
		arrow.className = "jhs-vlt-filter-mode-arrow";
		arrow.textContent = "▼";
		summary.appendChild(arrow);
		details.appendChild(summary);
		const panel = document.createElement("div");
		panel.className = "jhs-vlt-filter-mode-panel";
		const updateModeUI = () => {
			const config = FILTER_MODE_CONFIG.find((m) => m.value === plugin.currentFilterMode) || FILTER_MODE_CONFIG[0];
			modeText.textContent = config.label;
			indicator.className = "jhs-vlt-filter-mode-indicator jhs-vlt-" + config.group;
			panel.querySelectorAll(".jhs-vlt-filter-mode-item").forEach((el) => {
				el.classList.toggle("jhs-vlt-selected", el.dataset.mode === plugin.currentFilterMode);
			});
		};
		let lastGroup = null;
		FILTER_MODE_CONFIG.forEach((mode) => {
			if (lastGroup && lastGroup !== mode.group) {
				const separator = document.createElement("div");
				separator.className = "jhs-vlt-filter-mode-separator";
				panel.appendChild(separator);
			}
			lastGroup = mode.group;
			const item = document.createElement("div");
			item.className = "jhs-vlt-filter-mode-item";
			if (mode.group === "exclude") item.classList.add("jhs-vlt-exclude");
			item.dataset.mode = mode.value;
			const dot = document.createElement("span");
			dot.className = "jhs-vlt-filter-mode-indicator jhs-vlt-" + mode.group;
			item.appendChild(dot);
			const text = document.createElement("span");
			text.textContent = mode.label;
			item.appendChild(text);
			item.addEventListener("click", () => {
				plugin.currentFilterMode = mode.value;
				updateModeUI();
				details.open = false;
				applyFilter(plugin);
			});
			panel.appendChild(item);
		});
		details.appendChild(panel);
		details._updateModeUI = updateModeUI;
		updateModeUI();
		return details;
	}
	function createFilterChip(plugin, labelText, value, opts = {}) {
		const { isNoTag = false, count } = opts;
		const chip = document.createElement("span");
		chip.className = "jhs-vlt-filter-chip";
		if (isNoTag) chip.classList.add("jhs-vlt-no-tag");
		chip.textContent = count !== void 0 ? `${labelText} ${count}` : labelText;
		chip.dataset.value = value;
		chip.addEventListener("click", () => {
			chip.classList.toggle("jhs-vlt-active");
			applyFilter(plugin);
		});
		return chip;
	}
	function refreshChips(plugin, chipsContainer) {
		const activeValues = new Set(Array.from(chipsContainer.querySelectorAll(".jhs-vlt-filter-chip.jhs-vlt-active")).map((c) => c.dataset.value || ""));
		chipsContainer.innerHTML = "";
		const allCounts = collectTagCounts();
		const noTagChip = createFilterChip(plugin, "无标签", "no-tag", {
			isNoTag: true,
			count: countNoTagItems()
		});
		if (activeValues.has("no-tag")) noTagChip.classList.add("jhs-vlt-active");
		chipsContainer.appendChild(noTagChip);
		collectAllUniqueTags().forEach((tagName) => {
			const chip = createFilterChip(plugin, tagName, tagName, { count: allCounts[tagName] });
			if (activeValues.has(tagName)) chip.classList.add("jhs-vlt-active");
			chipsContainer.appendChild(chip);
		});
	}
	function buildFilterBar(plugin) {
		if (document.querySelector(".jhs-vlt-filter-bar")) return;
		const mountTarget = /^\/actors\//.test(window.location.pathname) ? document.querySelector("body > section > div > div.actor-tags.tags") : document.querySelector("body > section > div > div.tabs.is-boxed");
		if (!mountTarget) return;
		const filterBar = document.createElement("div");
		filterBar.className = "jhs-vlt-filter-bar";
		const label = document.createElement("span");
		label.className = "jhs-vlt-filter-label";
		label.textContent = "筛选:";
		filterBar.appendChild(label);
		const modeDropdown = buildFilterModeDropdown(plugin);
		filterBar.appendChild(modeDropdown);
		filterBar._modeDropdown = modeDropdown;
		const chipsContainer = document.createElement("div");
		chipsContainer.className = "jhs-vlt-filter-chips";
		filterBar.appendChild(chipsContainer);
		const toggleWrapper = document.createElement("label");
		toggleWrapper.className = "jhs-vlt-auto-refresh-toggle";
		toggleWrapper.title = "监听清单操作,自动刷新标签";
		const switchSpan = document.createElement("span");
		switchSpan.className = "jhs-vlt-auto-refresh-switch";
		const checkbox = document.createElement("input");
		checkbox.type = "checkbox";
		checkbox.checked = plugin.autoRefreshEnabled;
		const slider = document.createElement("span");
		slider.className = "jhs-vlt-auto-refresh-slider";
		switchSpan.appendChild(checkbox);
		switchSpan.appendChild(slider);
		const toggleLabel = document.createElement("span");
		toggleLabel.textContent = "自动刷新";
		toggleWrapper.appendChild(switchSpan);
		toggleWrapper.appendChild(toggleLabel);
		filterBar.appendChild(toggleWrapper);
		checkbox.addEventListener("change", () => {
			plugin.autoRefreshEnabled = checkbox.checked;
			plugin.saveAutoRefreshState(plugin.autoRefreshEnabled);
			if (plugin.autoRefreshEnabled) console.log("[视频清单标签] 自动刷新已开启");
			else console.log("[视频清单标签] 自动刷新已关闭");
		});
		const boundRefreshChips = () => refreshChips(plugin, chipsContainer);
		boundRefreshChips();
		mountTarget.insertAdjacentElement("afterend", filterBar);
		filterBar._refreshChips = boundRefreshChips;
	}
	function updateFilterBar(plugin) {
		const filterBar = document.querySelector(".jhs-vlt-filter-bar");
		if (filterBar && filterBar._refreshChips) {
			filterBar._refreshChips();
			applyFilter(plugin);
		}
	}
	var BOOTSTRAP_COLORS = [
		{
			name: "primary",
			bg: "#0d6efd",
			text: "#fff"
		},
		{
			name: "secondary",
			bg: "#6c757d",
			text: "#fff"
		},
		{
			name: "success",
			bg: "#198754",
			text: "#fff"
		},
		{
			name: "danger",
			bg: "#dc3545",
			text: "#fff"
		},
		{
			name: "warning",
			bg: "#ffc107",
			text: "#212529"
		},
		{
			name: "info",
			bg: "#0dcaf0",
			text: "#212529"
		},
		{
			name: "dark",
			bg: "#212529",
			text: "#fff"
		}
	];
	function getRandomBootstrapColor() {
		const color = BOOTSTRAP_COLORS[Math.floor(Math.random() * BOOTSTRAP_COLORS.length)];
		return {
			bg: color.bg,
			text: color.text,
			isLight: color.text !== "#fff"
		};
	}
	function tagsEqual(a, b) {
		if (a === b) return true;
		if (!a || !b) return false;
		if (a.length !== b.length) return false;
		return JSON.stringify(a) === JSON.stringify(b);
	}
	function createTagBadge(tag) {
		const urlTrimmed = tag.url?.trim();
		const hasUrl = !!urlTrimmed;
		const el = document.createElement(hasUrl ? "a" : "span");
		el.className = "jhs-vlt-tag-link";
		if (hasUrl && urlTrimmed) {
			const anchor = el;
			anchor.href = urlTrimmed;
			anchor.target = "_blank";
			anchor.rel = "noopener noreferrer";
		}
		el.textContent = tag.name;
		const style = tag.style;
		if (style && style.bg && style.text) {
			el.style.backgroundColor = style.bg;
			el.style.color = style.text;
			if (style.text !== "#fff") el.classList.add("jhs-vlt-light-bg");
		} else {
			const color = getRandomBootstrapColor();
			el.style.backgroundColor = color.bg;
			el.style.color = color.text;
			if (color.isLight) el.classList.add("jhs-vlt-light-bg");
		}
		return el;
	}
	function addTagDisplay(plugin, item) {
		if (item.querySelector(".jhs-vlt-tags-display")) return;
		const strongEl = item.querySelector("a > div.video-title > strong");
		if (!strongEl) return;
		const designation = strongEl.innerHTML;
		const tagsCache = plugin.getTagsCache();
		if (!tagsCache) return;
		const meta = item.querySelector(".meta");
		if (!meta) return;
		const container = document.createElement("div");
		container.className = "jhs-vlt-tags-display";
		const tags = tagsCache[designation];
		if (tags && tags.length > 0) tags.forEach((tag) => {
			container.appendChild(createTagBadge(tag));
		});
		else {
			const placeholder = document.createElement("span");
			placeholder.className = "jhs-vlt-tag-link";
			placeholder.textContent = "—";
			placeholder.style.backgroundColor = "#e9ecef";
			placeholder.style.color = "#6c757d";
			placeholder.style.pointerEvents = "none";
			placeholder.style.userSelect = "none";
			container.appendChild(placeholder);
		}
		container.addEventListener("wheel", (e) => {
			if (e.deltaY !== 0) {
				const atStart = container.scrollLeft <= 0 && e.deltaY < 0;
				const atEnd = container.scrollLeft + container.clientWidth >= container.scrollWidth - 1 && e.deltaY > 0;
				if (!atStart && !atEnd) {
					e.preventDefault();
					container.scrollLeft += e.deltaY;
				}
			}
		}, { passive: false });
		meta.insertAdjacentElement("afterend", container);
	}
	function renderTags(plugin) {
		document.querySelectorAll(".item").forEach((item) => addTagDisplay(plugin, item));
	}
	var LAST_SYNC_KEY = "jdb:last-sync";
	var NO_CHANGE_ASSOCS = {
		existed: true,
		limit_exceeded: true,
		unchanged: true
	};
	var SYNC_DEBOUNCE_MS = 500;
	function handleSyncNotify(plugin, payload, onSync, state) {
		if (!plugin.autoRefreshEnabled) {
			console.log("[视频清单标签] 收到同步事件但自动刷新已关闭,跳过");
			return;
		}
		if (!payload || !payload.designation) {
			console.warn("[视频清单标签] 收到同步事件但无 designation:", payload);
			return;
		}
		if (NO_CHANGE_ASSOCS[payload.association ?? ""]) {
			console.log(`[视频清单标签] association=${payload.association} 不影响标签,跳过`);
			return;
		}
		const now = Date.now();
		if (now - state.lastRefreshTime < SYNC_DEBOUNCE_MS) {
			console.log(`[视频清单标签] 距上次刷新 ${now - state.lastRefreshTime}ms < ${SYNC_DEBOUNCE_MS}ms,防抖跳过`);
			return;
		}
		state.lastRefreshTime = now;
		console.log("[视频清单标签] 收到同步事件 → 精准刷新", payload);
		onSync(payload);
	}
	function setupAutoRefreshListener(plugin, onSync) {
		const state = { lastRefreshTime: 0 };
		broadcastSubscribe(LAST_SYNC_KEY, (payload) => handleSyncNotify(plugin, payload, onSync, state), {
			eventName: "jdb:sync-complete",
			onDelivery: (delivery) => {
				if (delivery.channel === "customEvent") console.log("[视频清单标签] [CustomEvent] 收到 jdb:sync-complete");
				else if (delivery.channel === "storage") console.log(`[视频清单标签] [storage] key=${LAST_SYNC_KEY} newValue=${delivery.rawValue ? "<set>" : "<empty>"}`);
				else console.log(`[视频清单标签] [GM_addValueChangeListener] remote=${delivery.remote} newValue=${delivery.rawValue ? "<set>" : "<empty>"}`);
			}
		});
		console.log(`[视频清单标签] 自动刷新监听已就绪 (autoRefreshEnabled=${plugin.autoRefreshEnabled})`);
	}
	var AUTO_REFRESH_KEY = "jdb:auto-refresh-enabled";
	var VltTags = class {
		tagsCache = null;
		currentFilterMode = "contains-any";
		autoRefreshEnabled = true;
		pendingNewItems = [];
		debounceTimer = null;
		DEBOUNCE_MS = 300;
		getTagsCache() {
			return this.tagsCache;
		}
		async fetchTags(designations) {
			this.tagsCache = await VltDb.queryMoviesLists(designations);
		}
		async fetchAndMergeTags(designations) {
			const newTags = await VltDb.queryMoviesLists(designations);
			if (!this.tagsCache) this.tagsCache = newTags;
			else Object.assign(this.tagsCache, newTags);
		}
		addTagDisplay(item) {
			addTagDisplay(this, item);
		}
		async refreshAllTags() {
			const items = document.querySelectorAll(".item");
			const lists = Array.from(items).map((item) => {
				const strong = item.querySelector("a > div.video-title > strong");
				return strong ? strong.innerHTML : null;
			}).filter((s) => !!s);
			if (lists.length === 0) return;
			console.log(`[视频清单标签] 开始刷新,共 ${lists.length} 个番号`);
			try {
				await this.fetchTags(lists);
			} catch (err) {
				clog.error(`自动刷新标签数据失败(${lists.length} 个番号):`, err);
				return;
			}
			document.querySelectorAll(".jhs-vlt-tags-display").forEach((el) => el.remove());
			renderTags(this);
			this.updateFilterBar();
			console.log("[视频清单标签] 自动刷新完成");
		}
		async refreshDesignation(designation) {
			console.log(`[视频清单标签] refreshDesignation: ${designation}`);
			const allItems = document.querySelectorAll(".item");
			const targetItem = Array.from(allItems).find((item) => {
				const strong = item.querySelector("a > div.video-title > strong");
				return strong && strong.innerHTML === designation;
			});
			if (!targetItem) {
				console.log(`[视频清单标签] ${designation} 不在当前页面 (共 ${allItems.length} 张卡片)`);
				return;
			}
			const oldTags = this.tagsCache ? this.tagsCache[designation] || [] : null;
			try {
				await this.fetchAndMergeTags([designation]);
			} catch (err) {
				clog.error(`[视频清单标签] 刷新 ${designation} 失败:`, err);
				return;
			}
			const newTags = this.tagsCache[designation] || [];
			if (tagsEqual(oldTags, newTags)) {
				console.log(`[视频清单标签] ${designation} 标签未变化,跳过 DOM 更新 (${newTags.length} 个标签)`);
				return;
			}
			const oldContainer = targetItem.querySelector(".jhs-vlt-tags-display");
			if (oldContainer) oldContainer.remove();
			this.addTagDisplay(targetItem);
			this.updateFilterBar();
			console.log(`[视频清单标签] ${designation} 标签已更新 (${oldTags ? oldTags.length : 0} → ${newTags.length})`);
		}
		loadAutoRefreshState() {
			try {
				const val = GM_getValue(AUTO_REFRESH_KEY);
				if (val === void 0) {
					this.autoRefreshEnabled = true;
					console.log("[视频清单标签] 自动刷新: 未设置过 → 默认开启");
				} else {
					this.autoRefreshEnabled = val === true || val === "true";
					console.log(`[视频清单标签] 自动刷新: 存储值 = ${this.autoRefreshEnabled} (原始=${JSON.stringify(val)})`);
				}
			} catch (e) {
				this.autoRefreshEnabled = true;
				console.warn("[视频清单标签] 自动刷新: 读取异常 → 默认开启", e);
			}
		}
		saveAutoRefreshState(enabled) {
			try {
				GM_setValue(AUTO_REFRESH_KEY, enabled);
			} catch {}
		}
		applyFilter() {
			applyFilter(this);
		}
		buildFilterBar() {
			buildFilterBar(this);
		}
		updateFilterBar() {
			updateFilterBar(this);
		}
		collectAllUniqueTags() {
			return collectAllUniqueTags();
		}
		collectTagCounts() {
			return collectTagCounts();
		}
		countNoTagItems() {
			return countNoTagItems();
		}
		async initExistingItems() {
			this.loadAutoRefreshState();
			const items = document.querySelectorAll(".item");
			if (items.length === 0) return;
			const lists = Array.from(items).map((item) => {
				const strong = item.querySelector("a > div.video-title > strong");
				return strong ? strong.innerHTML : null;
			}).filter((s) => !!s);
			if (lists.length === 0) return;
			try {
				await this.fetchTags(lists);
				console.log(`[视频清单标签] 初始化加载完成: ${lists.length} 个番号, ${Object.keys(this.tagsCache || {}).length} 个有标签`);
			} catch (err) {
				clog.error("获取标签数据失败:", err);
				this.tagsCache = {};
				return;
			}
			renderTags(this);
			this.buildFilterBar();
		}
		async handleNewItems(newItems) {
			newItems.forEach((item) => this.addTagDisplay(item));
			this.pendingNewItems.push(...newItems);
			if (this.debounceTimer) clearTimeout(this.debounceTimer);
			this.debounceTimer = setTimeout(async () => {
				const itemsToRefresh = [...this.pendingNewItems];
				this.pendingNewItems = [];
				this.debounceTimer = null;
				const uncachedCodes = [];
				const seen = new Set();
				for (const item of itemsToRefresh) {
					const strong = item.querySelector("a > div.video-title > strong");
					if (!strong) continue;
					const code = strong.innerHTML;
					if (!code || seen.has(code)) continue;
					if (!this.tagsCache || !(code in this.tagsCache)) {
						uncachedCodes.push(code);
						seen.add(code);
					}
				}
				if (uncachedCodes.length === 0) {
					this.updateFilterBar();
					return;
				}
				try {
					await this.fetchAndMergeTags(uncachedCodes);
				} catch (err) {
					clog.error("[视频清单标签] 获取新增标签数据失败:", err);
					return;
				}
				itemsToRefresh.forEach((item) => {
					const oldContainer = item.querySelector(".jhs-vlt-tags-display");
					if (oldContainer) oldContainer.remove();
					this.addTagDisplay(item);
				});
				this.updateFilterBar();
				console.log(`[视频清单标签] 已为 ${uncachedCodes.length} 个新番号获取标签`);
			}, this.DEBOUNCE_MS);
		}
		setupAutoRefreshListener(onSync) {
			setupAutoRefreshListener(this, onSync);
		}
	};
	var LOG_PREFIX = "[JavDB]";
	var LIST_MGMT_KEY = "jdb:list-mgmt";
	function setupListMgmtBroadcastListener(onDelete, onRename) {
		const handlePayload = (payload) => {
			if (!payload || !payload.type || !payload.listId) return;
			console.log(`${LOG_PREFIX} 收到清单管理广播:`, payload);
			if (payload.type === "delete") onDelete(payload.listId);
			else if (payload.type === "rename" && payload.newName) onRename(payload.listId, payload.newName);
		};
		broadcastSubscribe(LIST_MGMT_KEY, (payload) => handlePayload(payload));
	}
	var video_lists_tag_default = "/**\n * video-lists-tag 插件样式 —— 标签显示 + 筛选栏 + Toast。\n *\n * 合并自 archetype/videoListsTag.user.js 的 GM_addStyle(L24-275)\n * 和 archetype/listsOptionSync.user.js 的 injectToastStyles(L40-115)。\n * CSS 规则内容与原脚本一致(缩进标准化,渲染等价)。\n */\n\n/* ---------- 标签显示(Bootstrap Badge Pill 风格) ---------- */\n.jhs-vlt-tags-display {\n    margin: 5px 0;\n    padding: 6px;\n    white-space: nowrap;\n    overflow-x: auto;\n    overflow-y: hidden;\n    scrollbar-width: none;\n    -webkit-overflow-scrolling: touch;\n    padding-bottom: 2px;\n}\n\n.jhs-vlt-tags-display::-webkit-scrollbar {\n    display: none;\n}\n\n.jhs-vlt-tag-link {\n    display: inline-block;\n    padding: 0.35em 0.65em;\n    margin-right: 6px;\n    font-size: 0.75em;\n    font-weight: 700;\n    line-height: 1;\n    text-align: center;\n    white-space: nowrap;\n    vertical-align: baseline;\n    border-radius: 50rem;\n    text-decoration: none;\n    color: #fff;\n    transition:\n        filter 0.15s ease,\n        transform 0.15s ease;\n    box-shadow: 0 1px 2px rgb(0, 0, 0, 0.1);\n}\n\n.jhs-vlt-tag-link:hover {\n    filter: brightness(0.92);\n    transform: translateY(-1px);\n    box-shadow: 0 2px 5px rgb(0, 0, 0, 0.15);\n}\n\n.jhs-vlt-tag-link.jhs-vlt-light-bg {\n    color: #212529;\n}\n\n/* ---------- 标签筛选栏 ---------- */\n\n.jhs-vlt-filter-chip.jhs-vlt-active {\n    background: #0d6efd;\n    border-color: #0d6efd;\n    color: #fff;\n}\n\n.jhs-vlt-filter-chip.jhs-vlt-no-tag {\n    border-style: dashed;\n    color: #6c757d;\n}\n\n.jhs-vlt-filter-chip.jhs-vlt-no-tag.jhs-vlt-active {\n    background: #6c757d;\n    border-color: #6c757d;\n    border-style: solid;\n    color: #fff;\n}\n\n/* ---------- 自动刷新开关 ---------- */\n.jhs-vlt-auto-refresh-toggle {\n    display: flex;\n    align-items: center;\n    gap: 6px;\n    margin-left: auto;\n    flex-shrink: 0;\n    font-size: 0.78em;\n    color: #6c757d;\n    user-select: none;\n}\n\n.jhs-vlt-auto-refresh-switch {\n    position: relative;\n    width: 36px;\n    height: 20px;\n    flex-shrink: 0;\n}\n\n.jhs-vlt-auto-refresh-switch input {\n    opacity: 0;\n    width: 0;\n    height: 0;\n}\n\n.jhs-vlt-auto-refresh-slider {\n    position: absolute;\n    inset: 0;\n    background: #ced4da;\n    border-radius: 50rem;\n    cursor: pointer;\n    transition: background 0.2s;\n}\n\n.jhs-vlt-auto-refresh-slider::before {\n    content: '';\n    position: absolute;\n    left: 2px;\n    top: 2px;\n    width: 16px;\n    height: 16px;\n    border-radius: 50%;\n    background: #fff;\n    transition: transform 0.2s;\n}\n\n.jhs-vlt-auto-refresh-switch input:checked + .jhs-vlt-auto-refresh-slider {\n    background: #198754;\n}\n\n.jhs-vlt-auto-refresh-switch input:checked + .jhs-vlt-auto-refresh-slider::before {\n    transform: translateX(16px);\n}\n\n/* ---------- 筛选模式下拉 ---------- */\n.jhs-vlt-filter-mode-dropdown {\n    position: relative;\n    display: inline-block;\n    flex-shrink: 0;\n}\n\n.jhs-vlt-filter-mode-summary {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n    padding: 0.25em 0.7em;\n    font-size: 0.75em;\n    font-weight: 600;\n    line-height: 1.5;\n    border-radius: 50rem;\n    cursor: pointer;\n    user-select: none;\n    border: 1.5px solid #dee2e6;\n    background: #fff;\n    color: #495057;\n    transition: background-color 0.15s ease, border-color 0.15s ease;\n    list-style: none;\n}\n\n.jhs-vlt-filter-mode-summary::-webkit-details-marker {\n    display: none;\n}\n\n.jhs-vlt-filter-mode-summary:hover {\n    border-color: #adb5bd;\n    background: #f8f9fa;\n}\n\n.jhs-vlt-filter-mode-indicator {\n    display: inline-block;\n    width: 8px;\n    height: 8px;\n    border-radius: 50%;\n    flex-shrink: 0;\n}\n\n.jhs-vlt-filter-mode-indicator.jhs-vlt-include {\n    background: #0d6efd;\n    box-shadow: 0 0 0 2px rgb(13, 110, 253, 0.2);\n}\n\n.jhs-vlt-filter-mode-indicator.jhs-vlt-exclude {\n    background: #dc3545;\n    box-shadow: 0 0 0 2px rgb(220, 53, 69, 0.2);\n}\n\n.jhs-vlt-filter-mode-arrow {\n    font-size: 0.7em;\n    color: #adb5bd;\n    transition: transform 0.2s;\n}\n\n.jhs-vlt-filter-mode-dropdown[open] .jhs-vlt-filter-mode-arrow {\n    transform: rotate(180deg);\n}\n\n.jhs-vlt-filter-mode-panel {\n    position: absolute;\n    top: calc(100% + 4px);\n    left: 0;\n    min-width: 190px;\n    background: #fff;\n    border: 1px solid #dee2e6;\n    border-radius: 8px;\n    box-shadow: 0 4px 16px rgb(0, 0, 0, 0.12);\n    padding: 4px 0;\n    z-index: 1000;\n    animation: jhs-vlt-filter-mode-in 0.15s ease;\n}\n\n@keyframes jhs-vlt-filter-mode-in {\n    from {\n        opacity: 0;\n        transform: translateY(-4px);\n    }\n\n    to {\n        opacity: 1;\n        transform: translateY(0);\n    }\n}\n\n.jhs-vlt-filter-mode-item {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    padding: 6px 14px;\n    font-size: 0.78em;\n    font-weight: 500;\n    color: #495057;\n    cursor: pointer;\n    transition: background 0.1s;\n    white-space: nowrap;\n}\n\n.jhs-vlt-filter-mode-item:hover {\n    background: #f8f9fa;\n}\n\n.jhs-vlt-filter-mode-item.jhs-vlt-selected {\n    background: rgb(13, 110, 253, 0.08);\n    color: #0d6efd;\n    font-weight: 600;\n}\n\n.jhs-vlt-filter-mode-item.jhs-vlt-exclude.jhs-vlt-selected {\n    background: rgb(220, 53, 69, 0.08);\n    color: #dc3545;\n}\n\n.jhs-vlt-filter-mode-item .jhs-vlt-filter-mode-indicator {\n    flex-shrink: 0;\n}\n\n.jhs-vlt-filter-mode-separator {\n    height: 1px;\n    margin: 4px 8px;\n    background: #e9ecef;\n}\n\n/* ---------- Toast 通知 ---------- */\n#jdb-toast-container {\n    position: fixed;\n    top: 72px;\n    left: 20px;\n    z-index: var(--jhs-z-page);\n    display: flex;\n    flex-direction: column;\n    pointer-events: none;\n}\n\n.jdb-toast {\n    display: flex;\n    align-items: center;\n    gap: 10px;\n    min-width: 220px;\n    max-width: 380px;\n    max-height: 200px;\n    padding: 12px 16px;\n    border-radius: 8px;\n    font-size: 13px;\n    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n    color: #fff;\n    line-height: 1.4;\n    box-shadow: 0 4px 16px rgb(0, 0, 0, 0.28);\n    backdrop-filter: blur(6px);\n    pointer-events: auto;\n    overflow: hidden;\n    margin-bottom: 8px;\n    animation: jdb-toast-in 0.2s cubic-bezier(0.21, 1.02, 0.73, 1) forwards;\n    transition:\n        opacity 0.2s,\n        transform 0.2s,\n        max-height 0.2s,\n        margin-bottom 0.2s;\n}\n\n.jdb-toast:last-child {\n    margin-bottom: 0;\n}\n\n.jdb-toast.removing {\n    opacity: 0;\n    max-height: 0;\n    margin-bottom: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    transform: translateX(-20px);\n}\n\n.jdb-toast--stacked {\n    max-height: 10px;\n    opacity: 0.35;\n    transform: translateX(12px);\n    margin-bottom: 2px;\n    cursor: pointer;\n}\n\n.jdb-toast--success {\n    background: rgb(22, 163, 74, 0.92);\n}\n\n.jdb-toast--error {\n    background: rgb(220, 38, 38, 0.92);\n}\n\n.jdb-toast--warning {\n    background: rgb(217, 119, 6, 0.92);\n}\n\n.jdb-toast--info {\n    background: rgb(37, 99, 235, 0.92);\n}\n\n.jdb-toast__icon {\n    flex-shrink: 0;\n    width: 20px;\n    height: 20px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.jdb-toast__msg {\n    flex: 1;\n    word-break: break-word;\n}\n\n@keyframes jdb-toast-in {\n    from {\n        opacity: 0;\n        transform: translateX(-30px);\n    }\n\n    to {\n        opacity: 1;\n        transform: translateX(0);\n    }\n}\n\n/* ---------- 新增清單(詳情頁展開面板旁) ---------- */\n.jhs-list-panel:has(+ .jhs-list-create-wrap) {\n    border-radius: 10px 10px 0 0;\n}\n\n.jhs-list-create-wrap {\n    display: flex;\n    align-items: center;\n    gap: 6px;\n    min-height: 44px;\n    margin: -1px 0 10px;\n    padding: 7px 10px;\n    border: 1px solid #dfe4ea;\n    border-top-color: #edf0f3;\n    border-radius: 0 0 10px 10px;\n    background: #f6f8fa;\n    flex-wrap: wrap;\n}\n\n.jhs-list-create-btn {\n    min-height: 32px;\n    font-size: 12px;\n    font-weight: 600;\n}\n\n.jhs-list-create-form {\n    display: flex;\n    min-width: 0;\n    flex: 1;\n    align-items: center;\n    gap: 6px;\n    flex-wrap: nowrap;\n}\n\n.jhs-list-create-form .input.is-small {\n    width: auto;\n    min-width: 120px;\n    flex: 1;\n    font-size: 12px;\n}\n\n.jhs-list-create-wrap[aria-busy='true'] {\n    cursor: wait;\n}\n\n.jhs-list-create-wrap .button:focus-visible,\n.jhs-list-create-wrap .input:focus-visible {\n    outline: 2px solid #3273dc;\n    outline-offset: 2px;\n}\n\n.jhs-visually-hidden {\n    position: absolute !important;\n    width: 1px !important;\n    height: 1px !important;\n    padding: 0 !important;\n    margin: -1px !important;\n    overflow: hidden !important;\n    clip: rect(0, 0, 0, 0) !important;\n    white-space: nowrap !important;\n    border: 0 !important;\n}\n\n@media (width <= 768px) {\n    .jhs-list-create-wrap .button,\n    .jhs-list-create-wrap .input.is-small {\n        min-height: 44px;\n    }\n\n    .jhs-list-create-form {\n        width: 100%;\n        flex-wrap: wrap;\n    }\n\n    .jhs-list-create-form .input.is-small {\n        flex-basis: 100%;\n    }\n}\n";
	var VideoListsTagPlugin = class extends BasePlugin {
		vltTags = null;
		observer = null;
		getName() {
			return "VideoListsTagPlugin";
		}
		async initCss() {
			return video_lists_tag_default;
		}
		async handle() {
			if (window.isDetailPage) {
				setupCheckboxListener();
				setupCreateListButton();
				setupListMgmtBroadcastListener((listId) => removeDetailPageCheckbox(listId), (listId, newName) => updateDetailPageCheckboxLabel(listId, newName));
				return;
			}
			if (window.location.href.includes("/users/lists")) {
				setupListManagementListener();
				return;
			}
			if (!window.isListPage) return;
			this.vltTags = new VltTags();
			await this.vltTags.initExistingItems();
			this.setupItemObserver();
			setupListMgmtBroadcastListener(() => this.vltTags?.refreshAllTags().then(), () => this.vltTags?.refreshAllTags().then());
			this.vltTags.setupAutoRefreshListener((payload) => {
				if (payload?.designation) this.vltTags?.refreshDesignation(payload.designation).then();
			});
		}
		setupItemObserver() {
			this.observer = new MutationObserver((mutations) => {
				const newItems = [];
				for (const mutation of mutations) for (const node of mutation.addedNodes) {
					if (node.nodeType !== Node.ELEMENT_NODE) continue;
					const el = node;
					if (el.matches?.(".item")) newItems.push(el);
					else if (el.querySelectorAll?.(".item").length > 0) newItems.push(...Array.from(el.querySelectorAll(".item")));
				}
				if (newItems.length > 0) this.vltTags?.handleNewItems(newItems).then();
			});
			this.observer.observe(document.body, {
				childList: true,
				subtree: true
			});
		}
	};
	function getPayloadRevision(payload) {
		const revision = payload.revision ?? payload.ts;
		return Number.isInteger(revision) && revision >= 0 ? revision : -1;
	}
	function isDeltaPayload(value) {
		if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
		const payload = value;
		if (payload.action !== "upsert" && payload.action !== "delete") return false;
		if (!Array.isArray(payload.items) || payload.items.length === 0) return false;
		if (typeof payload.ts !== "number" || !Number.isInteger(payload.ts) || payload.ts < 0) return false;
		if (payload.revision !== void 0 && (typeof payload.revision !== "number" || !Number.isInteger(payload.revision) || payload.revision < 0)) return false;
		return payload.items.every((item) => {
			if (item === null || typeof item !== "object" || Array.isArray(item)) return false;
			const record = item;
			if (typeof record.carNum !== "string" || record.carNum.trim() === "") return false;
			if (payload.action === "delete") return true;
			return typeof record.status === "string" && record.status.trim() !== "" && STATUS_LIST.includes(record.status) && typeof record.url_path === "string" && record.url_path.trim() !== "";
		});
	}
	function readDeltaJournal(value) {
		return (Array.isArray(value) ? value : value ? [value] : []).filter(isDeltaPayload);
	}
	function sortDeltaJournal(journal) {
		return journal.map((payload, index) => ({
			payload,
			index
		})).sort((left, right) => {
			return getPayloadRevision(left.payload) - getPayloadRevision(right.payload) || left.index - right.index;
		}).map(({ payload }) => payload);
	}
	function countDeltaItems(journal) {
		return journal.reduce((total, payload) => total + payload.items.length, 0);
	}
	function compactDeltaJournal(journal) {
		if (countDeltaItems(journal) <= 256) return journal;
		const latestByCar = new Map();
		for (const payload of sortDeltaJournal(journal)) for (const item of payload.items) latestByCar.set(item.carNum.trim().toUpperCase(), {
			payload,
			item
		});
		const grouped = new Map();
		for (const { payload, item } of latestByCar.values()) {
			const key = `${getPayloadRevision(payload)}:${payload.action}:${payload.ts}`;
			const existing = grouped.get(key);
			if (existing) existing.items.push(item);
			else grouped.set(key, {
				...payload,
				items: [item]
			});
		}
		return sortDeltaJournal(Array.from(grouped.values()));
	}
	function createLogger(prefix) {
		return {
			info(step, ...args) {
				console.log(`%c${prefix}%c ${step}`, "color:#25b1dc;font-weight:bold;", "", ...args);
			},
			ok(step, ...args) {
				console.log(`%c${prefix} ✓%c ${step}`, "color:#1f7a3d;font-weight:bold;", "", ...args);
			},
			warn(step, ...args) {
				console.warn(`%c${prefix} ⚠%c ${step}`, "color:#d7a80c;font-weight:bold;", "", ...args);
			},
			err(step, ...args) {
				console.error(`%c${prefix} ✗%c ${step}`, "color:#de3333;font-weight:bold;", "", ...args);
			}
		};
	}
	var { info: logInfo$1, ok: logOk$1, warn: logWarn$1, err: logErr$1 } = createLogger(LOG_PREFIX_JHS);
	var GM_KEY_CAR_LIST_REV = "jhs_car_list_rev";
	var GM_KEY_SYNCED_REV = "jhs_car_status_synced_rev";
	var GM_KEY_LAST_SYNC_TIME = "jhs_car_status_last_sync";
	var DAILY_SYNC_INTERVAL = 1440 * 60 * 1e3;
	var CarListReaderPlugin = class extends BasePlugin {
		getName() {
			return "CarListReaderPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			storageManager.setCarListChangeCallback((event) => {
				this.pushDelta(event);
			});
			if (window.self !== window.top) return;
			try {
				GM_registerMenuCommand("🔁 全量同步车辆状态到 missav", () => {
					this.syncFullCarStatus();
				});
			} catch {}
			try {
				GM_registerMenuCommand("🔍 诊断:跨站同步发布侧", () => {
					(async () => {
						const delta = GM_getValue(GM_KEY_CAR_STATUS_DELTA);
						const data = GM_getValue(GM_KEY_CAR_STATUS_DATA);
						const journal = Array.isArray(delta) ? delta : delta ? [delta] : [];
						const info = {
							site: "javdb",
							version: GM_info.script.version,
							gmRevision: GM_getValue(GM_KEY_CAR_STATUS_REVISION, 0),
							carListRev: GM_getValue(GM_KEY_CAR_LIST_REV, 0),
							syncedRev: GM_getValue(GM_KEY_SYNCED_REV, -1),
							journal: {
								length: journal.length,
								entries: journal.slice(-5).map((e) => {
									const entry = e;
									return {
										action: entry?.action,
										revision: entry?.revision ?? entry?.ts,
										carNums: Array.isArray(entry?.items) ? entry.items.map((i) => i?.carNum) : void 0
									};
								})
							},
							fullSnapshot: data ? {
								revision: data.revision ?? data.ts,
								count: data.count,
								ready: data.ready
							} : null
						};
						const text = JSON.stringify(info, null, 2);
						console.log("[JHS CarSync 诊断-发布侧]", text);
						try {
							await navigator.clipboard.writeText(text);
						} catch {}
						show.ok("诊断信息已输出到控制台并复制到剪贴板");
					})();
				});
			} catch {}
			const currentRev = GM_getValue(GM_KEY_CAR_LIST_REV, 0);
			const syncedRev = GM_getValue(GM_KEY_SYNCED_REV, -1);
			const lastSyncTime = GM_getValue(GM_KEY_LAST_SYNC_TIME, 0);
			if (currentRev !== syncedRev || Date.now() - lastSyncTime > DAILY_SYNC_INTERVAL) {
				logInfo$1("全量同步已调度", `rev=${currentRev}, synced=${syncedRev}`);
				setTimeout(() => {
					this.syncFullCarStatus();
				}, 2e3);
			} else logInfo$1("跳过全量同步", `数据未变更 (rev=${currentRev}),上次同步 ${new Date(lastSyncTime).toLocaleString()}`);
		}
		pendingPush = Promise.resolve();
		pushDelta(event) {
			this.pendingPush = this.pushDeltaAsync(event).catch((err) => {
				logErr$1("增量推送失败", err instanceof Error ? err.message : String(err));
			});
		}
		async waitForPendingPush() {
			await this.pendingPush;
		}
		async pushDeltaAsync(event) {
			if (event.action === "upsert" && event.upserts) {
				const items = event.upserts.map((car) => {
					const { code } = normalizeUrl(car.url || "");
					return {
						carNum: car.carNum,
						status: car.status,
						url_path: code
					};
				});
				if (items.length === 0) return;
				if (items.length > 500) {
					logWarn$1("批量变更超过增量上限,改发压缩全量快照", `${items.length} 条`);
					await this.syncFullCarStatus();
					return;
				}
				const revision = await nextRevision();
				const needsFullSnapshot = await appendDeltaJournal({
					action: "upsert",
					items,
					ts: revision,
					revision
				});
				logInfo$1("增量推送", `upsert ${items.length} 条`);
				if (needsFullSnapshot) {
					logInfo$1("增量日志超过阈值,发布压缩全量快照");
					await this.syncFullCarStatus();
				}
			} else if (event.action === "delete" && event.deletes) {
				if (event.deletes.length === 0) return;
				if (event.deletes.length > 500) {
					logWarn$1("批量删除超过增量上限,改发压缩全量快照", `${event.deletes.length} 条`);
					await this.syncFullCarStatus();
					return;
				}
				const revision = await nextRevision();
				const needsFullSnapshot = await appendDeltaJournal({
					action: "delete",
					items: event.deletes.map((carNum) => ({ carNum })),
					ts: revision,
					revision
				});
				logInfo$1("增量推送", `delete ${event.deletes.length} 条`);
				if (needsFullSnapshot) {
					logInfo$1("增量日志超过阈值,发布压缩全量快照");
					await this.syncFullCarStatus();
				}
			}
			GM_setValue(GM_KEY_CAR_LIST_REV, GM_getValue(GM_KEY_CAR_LIST_REV, 0) + 1);
		}
		async syncFullCarStatus() {
			if (isFullSyncing) {
				fullResyncRequested = true;
				logWarn$1("全量同步任务在进行中,已安排完成后补发最新快照");
				return false;
			}
			isFullSyncing = true;
			try {
				logInfo$1("全量同步开始");
				const revision = await nextRevision();
				const carList = await storageManager.getCarList();
				logInfo$1("1-读取", `本地 car_list 记录数:${carList.length}`);
				if (carList.length === 0) {
					logWarn$1("car_list 为空,跳过同步(jhs 可能尚未写入数据)");
					return false;
				}
				const colRes = toColumnar(carList);
				const count = countColumnar(colRes.byStatus);
				logInfo$1("2-转列存", `列存 ${count} 条 / 丢弃 ${colRes.dropped} / url 异常 ${colRes.malformed}`);
				if (count === 0) {
					logWarn$1("列存后无有效记录,跳过");
					return false;
				}
				const base64 = await gzipToBase64(colRes.byStatus);
				if (!base64) {
					logErr$1("gzip 压缩失败(CompressionStream 不可用?非 https 环境?)");
					return false;
				}
				logInfo$1("3-压缩", `gzip+base64 体积:约 ${(base64.length / 1024).toFixed(1)} KB`);
				const payload = {
					data: base64,
					hwm: new Date(revision).toISOString(),
					count,
					ts: revision,
					revision,
					mode: "snapshot",
					ready: true
				};
				if (!await publishSnapshot(payload)) {
					logWarn$1("发现更新的全量快照,放弃发布本次旧快照", `revision=${revision}`);
					return false;
				}
				logOk$1("4-完成", `已写入 GM 存储,count=${count},hwm=${payload.hwm}`);
				GM_setValue(GM_KEY_SYNCED_REV, GM_getValue(GM_KEY_CAR_LIST_REV, 0));
				GM_setValue(GM_KEY_LAST_SYNC_TIME, Date.now());
				return true;
			} catch (err) {
				logErr$1("全量同步失败", err instanceof Error ? err.message : String(err), err);
				return false;
			} finally {
				isFullSyncing = false;
				if (fullResyncRequested) {
					fullResyncRequested = false;
					setTimeout(() => void this.syncFullCarStatus(), 0);
				}
			}
		}
	};
	var isFullSyncing = false;
	var fullResyncRequested = false;
	var lastIssuedRevision = 0;
	var JAVDB_SYNC_LOCK_NAME = "jhs-javdb-car-status-publisher";
	async function nextRevision() {
		return withExclusiveLock(JAVDB_SYNC_LOCK_NAME, async () => {
			const now = Date.now();
			let persisted = 0;
			try {
				const value = GM_getValue(GM_KEY_CAR_STATUS_REVISION, 0);
				if (typeof value === "number" && Number.isInteger(value) && value >= 0) persisted = value;
			} catch {}
			lastIssuedRevision = Math.max(now, persisted + 1, lastIssuedRevision + 1);
			GM_setValue(GM_KEY_CAR_STATUS_REVISION, lastIssuedRevision);
			return lastIssuedRevision;
		});
	}
	async function appendDeltaJournal(payload) {
		return withExclusiveLock(JAVDB_SYNC_LOCK_NAME, async () => {
			const journal = readDeltaJournal(GM_getValue(GM_KEY_CAR_STATUS_DELTA));
			journal.push(payload);
			const compacted = compactDeltaJournal(sortDeltaJournal(journal));
			GM_setValue(GM_KEY_CAR_STATUS_DELTA, compacted);
			return countDeltaItems(compacted) > 256;
		});
	}
	async function publishSnapshot(payload) {
		return withExclusiveLock(JAVDB_SYNC_LOCK_NAME, async () => {
			const current = GM_getValue(GM_KEY_CAR_STATUS_DATA);
			if ((current ? getPayloadRevision(current) : -1) >= getPayloadRevision(payload)) return false;
			GM_setValue(GM_KEY_CAR_STATUS_DATA, payload);
			const journal = readDeltaJournal(GM_getValue(GM_KEY_CAR_STATUS_DELTA));
			const retained = journal.filter((delta) => getPayloadRevision(delta) >= getPayloadRevision(payload));
			if (retained.length !== journal.length) GM_setValue(GM_KEY_CAR_STATUS_DELTA, sortDeltaJournal(retained));
			return true;
		});
	}
	var visit_history_tooltip_default = "/* 访问记录悬浮提示:时间分级配色(由近=安全 → 远=危险) */\n.jhs-visit-tooltip {\n    position: fixed;\n    padding: 8px 12px;\n    border-radius: 6px;\n    white-space: nowrap;\n    max-width: 600px;\n    pointer-events: none;\n    font-size: 14px;\n    line-height: 1.5;\n    font-weight: 600;\n    z-index: var(--jhs-z-top);\n    box-shadow: 0 6px 20px rgb(0, 0, 0, 0.22);\n    display: none;\n    border: 1px solid transparent;\n}\n\n/* 无访问记录:白底灰字 */\n.jhs-visit-tooltip--none {\n    background: #fff;\n    color: #64748b;\n    border-color: #e2e8f0;\n    box-shadow: 0 4px 14px rgb(15, 23, 42, 0.12);\n    font-weight: 500;\n}\n\n/* <1 分钟:最安全 · 翠绿 */\n.jhs-visit-tooltip--sec {\n    background: #ecfdf5;\n    color: #047857;\n    border-color: #6ee7b7;\n}\n\n/* <1 小时:安全 · 青绿 */\n.jhs-visit-tooltip--min {\n    background: #f0fdf4;\n    color: #15803d;\n    border-color: #86efac;\n}\n\n/* <1 天:留意 · 琥珀 */\n.jhs-visit-tooltip--hour {\n    background: #fffbeb;\n    color: #b45309;\n    border-color: #fcd34d;\n}\n\n/* <1 周:警告 · 橙 */\n.jhs-visit-tooltip--day {\n    background: #fff7ed;\n    color: #c2410c;\n    border-color: #fdba74;\n}\n\n/* ≥1 周:危险 · 红 */\n.jhs-visit-tooltip--old {\n    background: #fef2f2;\n    color: #b91c1c;\n    border-color: #fca5a5;\n}\n";
	var VISIT_HISTORY_STORAGE_KEY = "jhs_visit_history";
	var MAX_ENTRIES = 5e3;
	var TICK_MS = 500;
	var TIER_CLASS = {
		none: "jhs-visit-tooltip--none",
		sec: "jhs-visit-tooltip--sec",
		min: "jhs-visit-tooltip--min",
		hour: "jhs-visit-tooltip--hour",
		day: "jhs-visit-tooltip--day",
		old: "jhs-visit-tooltip--old"
	};
	var ALL_TIER_CLASSES = Object.values(TIER_CLASS).join(" ");
	var VisitHistoryPlugin = class extends BasePlugin {
		supervisor = new TaskSupervisor();
		tooltipEl = null;
		tooltipTimer = null;
		activePath = null;
		dismissListenerBound = false;
		pageshowBound = false;
		getName() {
			return "VisitHistoryPlugin";
		}
		async initCss() {
			return visit_history_tooltip_default;
		}
		async handle() {
			if (!isJavdbSite) return;
			this.recordVisit();
			this.bindPageshow();
			if (window.isDetailPage) this.injectMetaLinkTooltips();
		}
		bindPageshow() {
			if (this.pageshowBound) return;
			this.pageshowBound = true;
			this.supervisor.addEventListener(window, "pageshow", (event) => {
				if (!isJavdbSite) return;
				this.recordVisit();
				if (event.persisted && window.isDetailPage) this.injectMetaLinkTooltips(true);
			});
		}
		recordVisit() {
			const path = location.pathname + location.search;
			const history = this.readHistory();
			history[path] = Date.now();
			this.evictIfNeeded(history);
			try {
				localStorage.setItem(VISIT_HISTORY_STORAGE_KEY, JSON.stringify(history));
			} catch {
				localStorage.removeItem(VISIT_HISTORY_STORAGE_KEY);
			}
		}
		readHistory() {
			try {
				const raw = localStorage.getItem(VISIT_HISTORY_STORAGE_KEY);
				return raw ? JSON.parse(raw) : {};
			} catch {
				return {};
			}
		}
		evictIfNeeded(history) {
			const keys = Object.keys(history);
			if (keys.length <= MAX_ENTRIES) return;
			keys.sort((a, b) => history[a] - history[b]);
			const removeCount = keys.length - MAX_ENTRIES;
			for (let i = 0; i < removeCount; i++) delete history[keys[i]];
		}
		injectMetaLinkTooltips(forceRebind = false) {
			const container = document.querySelector("body > section > div > div.video-detail > div.video-meta-panel > div > div:nth-child(2)") || document.querySelector(".movie-panel-info");
			if (!container) return;
			container.querySelectorAll(".panel-block .value a[href]").forEach((a) => {
				const href = a.getAttribute("href") || "";
				const path = this.normalizePath(href);
				if (!path) return;
				const el = a;
				if (forceRebind && el.__jhsVisitEnter) {
					el.removeEventListener("mouseenter", el.__jhsVisitEnter);
					el.removeEventListener("mouseleave", el.__jhsVisitLeave);
				}
				if (el.__jhsVisitEnter && !forceRebind) return;
				const onEnter = () => {
					this.activePath = path;
					this.showVisitTooltip(el);
				};
				const onLeave = () => {
					this.hideVisitTooltip();
				};
				el.__jhsVisitEnter = onEnter;
				el.__jhsVisitLeave = onLeave;
				this.supervisor.addEventListener(el, "mouseenter", onEnter);
				this.supervisor.addEventListener(el, "mouseleave", onLeave);
			});
		}
		normalizePath(href) {
			if (!href || href.startsWith("javascript:")) return null;
			try {
				const url = new URL(href, location.origin);
				if (url.origin !== location.origin) return null;
				return url.pathname + url.search;
			} catch {
				return null;
			}
		}
		ensureTooltipEl() {
			if (!this.tooltipEl || !this.tooltipEl.isConnected) {
				const el = document.createElement("div");
				el.className = "jhs-visit-tooltip";
				document.body.appendChild(el);
				this.tooltipEl = el;
			}
			if (!this.dismissListenerBound) {
				this.dismissListenerBound = true;
				this.supervisor.addEventListener(window, "scroll", () => this.hideVisitTooltip(), { capture: true });
				this.supervisor.addEventListener(window, "resize", () => this.hideVisitTooltip(), { capture: true });
			}
			return this.tooltipEl;
		}
		applyTier(el, tier) {
			el.classList.remove(...ALL_TIER_CLASSES.split(" "));
			el.classList.add(TIER_CLASS[tier]);
		}
		showVisitTooltip(link) {
			const el = this.ensureTooltipEl();
			const update = () => {
				let ts;
				if (this.activePath) ts = this.readHistory()[this.activePath];
				if (!ts) {
					this.applyTier(el, "none");
					el.textContent = "无访问记录";
				} else {
					const { text, tier } = this.formatVisitTime(ts);
					this.applyTier(el, tier);
					el.textContent = text;
				}
				const rect = link.getBoundingClientRect();
				const tw = el.offsetWidth;
				let left = rect.left + rect.width / 2 - tw / 2;
				if (left < 8) left = 8;
				if (left + tw > window.innerWidth - 8) left = window.innerWidth - tw - 8;
				el.style.left = `${Math.round(left)}px`;
			};
			el.style.display = "block";
			update();
			const rect = link.getBoundingClientRect();
			const th = el.offsetHeight;
			let top = rect.top - th - 6;
			if (top < 8) top = rect.bottom + 6;
			el.style.top = `${Math.round(top)}px`;
			update();
			if (this.tooltipTimer) clearInterval(this.tooltipTimer);
			this.tooltipTimer = this.supervisor.setInterval(update, TICK_MS);
		}
		hideVisitTooltip() {
			this.activePath = null;
			if (this.tooltipTimer) {
				clearInterval(this.tooltipTimer);
				this.tooltipTimer = null;
			}
			if (this.tooltipEl) {
				this.tooltipEl.style.display = "none";
				this.tooltipEl.textContent = "";
				this.tooltipEl.classList.remove(...ALL_TIER_CLASSES.split(" "));
			}
		}
		destroy() {
			this.supervisor.abort();
		}
		formatVisitTime(ts) {
			const diff = Date.now() - ts;
			if (diff < 6e4) return {
				text: `${Math.max(1, Math.floor(diff / 1e3))}秒前打开过`,
				tier: "sec"
			};
			if (diff < 36e5) return {
				text: `${Math.floor(diff / 6e4)}分钟前打开过`,
				tier: "min"
			};
			if (diff < 864e5) return {
				text: `${Math.floor(diff / 36e5)}小时前打开过`,
				tier: "hour"
			};
			if (diff < 6048e5) return {
				text: `${Math.floor(diff / 864e5)}天前打开过`,
				tier: "day"
			};
			return {
				text: `${this.formatDate(ts)} 打开过`,
				tier: "old"
			};
		}
		formatDate(ts) {
			const d = new Date(ts);
			const p = (n) => String(n).padStart(2, "0");
			return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
		}
	};
	function normalizeCarNum(raw) {
		if (!raw) return "";
		const filename = raw.split("/").pop() || "";
		if (/^FC2-PPV-\d+$/i.test(filename)) return filename.toUpperCase();
		const sep = filename.includes("_") ? "_" : "-";
		const parts = filename.split(sep);
		return (parts.length >= 2 ? parts[0] + "-" + parts[1] : filename).toUpperCase();
	}
	function createBadge(status, url) {
		const cfg = STATUS_CONFIG[status];
		if (!cfg) return null;
		const a = document.createElement("a");
		a.className = "missav-status-tag";
		a.dataset.status = status;
		a.textContent = cfg.label;
		const safeUrl = sanitizeUrl(url || "");
		if (safeUrl && safeUrl !== "#") {
			a.href = safeUrl;
			a.target = "_blank";
			a.rel = "noopener noreferrer";
		} else a.removeAttribute("href");
		a.title = "点击跳转到 javdb 详情页";
		a.style.cssText = [
			"border-radius:10px",
			"position:absolute",
			"z-index:10",
			"right:5px",
			"top:5px",
			"left:auto",
			"-webkit-font-smoothing:antialiased",
			"text-rendering:optimizelegibility",
			"font-family:\"Helvetica Neue\",\"Luxi Sans\",\"DejaVu Sans\",Tahoma,\"Hiragino Sans GB\",\"Microsoft Yahei\",sans-serif",
			"cursor:pointer",
			"align-items:center",
			"display:inline-flex",
			"font-size:0.75rem",
			"height:2em",
			"justify-content:center",
			"line-height:1.5",
			"white-space:nowrap",
			"color:rgb(255,255,255)",
			"pointer-events:auto",
			`background-color:${cfg.color} !important`,
			"width:80px",
			"text-decoration:none"
		].join(";");
		return a;
	}
	function renderBadges(container, carMap) {
		if (!container || carMap.size === 0) return {
			total: 0,
			matched: 0
		};
		const items = container.querySelectorAll(".thumbnail.group");
		let total = 0;
		let matched = 0;
		for (const item of items) {
			const link = item.querySelector("a[alt]");
			if (!link) continue;
			const carNum = link.getAttribute("alt");
			if (!carNum) continue;
			const normalized = normalizeCarNum(carNum);
			const record = carMap.get(normalized);
			if (!record) continue;
			const existing = item.querySelector(".missav-status-tag");
			if (existing) {
				if (existing.dataset.status === record.status) continue;
				existing.remove();
			}
			total++;
			const thumbDiv = item.querySelector("div.relative");
			if (!thumbDiv) continue;
			if (window.getComputedStyle(thumbDiv).position === "static") thumbDiv.style.position = "relative";
			const badge = createBadge(record.status, record.url);
			if (badge) {
				thumbDiv.appendChild(badge);
				matched++;
			}
		}
		return {
			total,
			matched
		};
	}
	function isVideoPage() {
		return document.querySelector("#sprite-plyr") !== null;
	}
	var { info: logInfo, ok: logOk, warn: logWarn, err: logErr } = createLogger(LOG_PREFIX_MISSAV);
	var MissavStatusTagPlugin = class extends BasePlugin {
		consumeQueue = new KeyedQueue();
		lastAppliedRevision = -1;
		lastAppliedKind = null;
		getName() {
			return "MissavStatusTagPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			logInfo("脚本启动", `页面类型: ${isVideoPage() ? "视频播放页" : "列表页"}`);
			try {
				GM_registerMenuCommand("🔄 MissAV 刷新标签", () => {
					this.processAll();
				});
			} catch {}
			try {
				GM_registerMenuCommand("🔄 强制重新同步(清除水位线)", () => {
					(async () => {
						try {
							show.ok("正在清除同步水位线...");
							await clearAppliedRevisionLocal();
							this.lastAppliedRevision = -1;
							this.lastAppliedKind = "delta";
							show.ok("水位线已清除,开始重新消费...");
							await this.consumeFull(void 0);
							await this.consumeDeltaJournal(GM_getValue(GM_KEY_CAR_STATUS_DELTA));
							await this.processAll();
							show.ok("强制重新同步完成");
						} catch (err) {
							show.error("强制重新同步失败: " + (err instanceof Error ? err.message : String(err)));
						}
					})();
				});
			} catch {}
			try {
				GM_registerMenuCommand("🔍 诊断:跨站同步消费侧", () => {
					(async () => {
						const delta = GM_getValue(GM_KEY_CAR_STATUS_DELTA);
						const data = GM_getValue(GM_KEY_CAR_STATUS_DATA);
						const journal = Array.isArray(delta) ? delta : delta ? [delta] : [];
						let syncMeta = null;
						let carCount = -1;
						let mgt140 = null;
						try {
							const db = await openLocalDB();
							try {
								syncMeta = await new Promise((resolve) => {
									const req = db.transaction(MISSAV_DB_META_STORE, "readonly").objectStore(MISSAV_DB_META_STORE).get(MISSAV_SYNC_META_KEY);
									req.onsuccess = () => resolve(req.result ?? null);
									req.onerror = () => resolve(null);
								});
								carCount = await new Promise((resolve) => {
									const req = db.transaction(MISSAV_DB_STORE, "readonly").objectStore(MISSAV_DB_STORE).count();
									req.onsuccess = () => resolve(req.result);
									req.onerror = () => resolve(-1);
								});
								mgt140 = await new Promise((resolve) => {
									const req = db.transaction(MISSAV_DB_STORE, "readonly").objectStore(MISSAV_DB_STORE).get("MGT-140");
									req.onsuccess = () => resolve(req.result ?? null);
									req.onerror = () => resolve(null);
								});
							} finally {
								db.close();
							}
						} catch {}
						const info = {
							site: "missav",
							version: GM_info.script.version,
							gmRevision: GM_getValue(GM_KEY_CAR_STATUS_REVISION, 0),
							journal: {
								length: journal.length,
								lastEntries: journal.slice(-3).map((e) => {
									const entry = e;
									return {
										action: entry?.action,
										revision: entry?.revision ?? entry?.ts,
										carNums: Array.isArray(entry?.items) ? entry.items.map((i) => i?.carNum) : void 0
									};
								})
							},
							fullSnapshot: data ? {
								revision: data.revision ?? data.ts,
								count: data.count,
								ready: data.ready
							} : null,
							idb: {
								syncMeta,
								carCount,
								MGT140: mgt140
							},
							inMemory: {
								lastAppliedRevision: this.lastAppliedRevision,
								lastAppliedKind: this.lastAppliedKind
							}
						};
						const text = JSON.stringify(info, null, 2);
						console.log("[MissAV 诊断-消费侧]", text);
						try {
							await navigator.clipboard.writeText(text);
						} catch {}
						show.ok("诊断信息已输出到控制台并复制到剪贴板");
					})();
				});
			} catch {}
			try {
				GM_addValueChangeListener(GM_KEY_CAR_STATUS_DELTA, (_key, _oldValue, newValue, remote) => {
					if (remote && newValue) this.consumeDeltaJournal(newValue);
				});
				logOk("已注册增量变更监听");
			} catch {
				logWarn("GM_addValueChangeListener 不可用");
			}
			try {
				GM_addValueChangeListener(GM_KEY_CAR_STATUS_DATA, (_key, _oldValue, newValue, remote) => {
					if (remote && newValue) {
						logInfo("收到 javdb 端全量数据通知");
						this.consumeFull(newValue);
					}
				});
			} catch {}
			await this.consumeFull(void 0);
			await this.consumeDeltaJournal(GM_getValue(GM_KEY_CAR_STATUS_DELTA));
			try {
				const gmRevision = GM_getValue(GM_KEY_CAR_STATUS_REVISION, 0);
				if (typeof gmRevision === "number" && gmRevision > 0 && this.lastAppliedRevision < gmRevision) {
					logWarn("消费验证:IDB 水位线落后于 GM 修订号", `idb=${this.lastAppliedRevision} gm=${gmRevision},尝试补消费`);
					await this.consumeDeltaJournal(GM_getValue(GM_KEY_CAR_STATUS_DELTA));
				}
			} catch {}
			const pending = readPendingIntents();
			if (pending.length > 0) {
				logInfo("恢复未完成消费", `${pending.length} 条待处理意图`);
				for (const intent of pending) {
					if (intent.type === "delta") {
						const journal = GM_getValue(GM_KEY_CAR_STATUS_DELTA);
						await this.consumeDeltaJournal(journal);
					}
					clearIntent(intent.revision);
				}
			}
			cleanStaleIntents();
			this.observeAndProcess();
		}
		async processAll() {
			try {
				const allCarNums = new Set();
				const allThumbs = document.querySelectorAll(".thumbnail.group");
				for (const thumb of allThumbs) {
					const link = thumb.querySelector("a[alt]");
					if (link) {
						const cn = link.getAttribute("alt");
						if (cn) allCarNums.add(normalizeCarNum(cn));
					}
				}
				if (allCarNums.size === 0) return;
				const carMap = await queryLocalCars(Array.from(allCarNums));
				if (carMap.size === 0) return;
				this.processPage(carMap);
			} catch (err) {
				logErr("处理页面失败", err instanceof Error ? err.message : String(err));
			}
		}
		processPage(carMap) {
			if (isVideoPage()) this.processVideoPage(carMap);
			else this.processListPage(carMap);
		}
		processVideoPage(carMap) {
			const bottomGrid = document.querySelector("body > div:nth-child(3) > div.sm\\:container.mx-auto.px-4.content-without-search.pb-12 > div > div.flex-1.order-first > div.relative.overflow-hidden > div.grid.grid-cols-2.md\\:grid-cols-3.xl\\:grid-cols-4.gap-5");
			if (bottomGrid) this.queryAndRender(bottomGrid, carMap.size > 0 ? carMap : null, "视频页-底部推荐");
			const sideContainer = document.querySelector("body > div:nth-child(3) > div.sm\\:container.mx-auto.px-4.content-without-search.pb-12 > div > div.hidden.lg\\:flex.h-full.ml-6.order-last > div");
			if (sideContainer) this.queryAndRender(sideContainer, carMap.size > 0 ? carMap : null, "视频页-侧边推荐");
			if (!bottomGrid && !sideContainer) {
				logWarn("视频页选择器未命中,回退到全页扫描");
				this.queryAndRender(document.body, carMap.size > 0 ? carMap : null, "视频页-兜底全页");
			}
		}
		processListPage(carMap) {
			this.queryAndRender(document.body, carMap.size > 0 ? carMap : null, "列表页");
		}
		async queryAndRender(container, existingMap, label) {
			if (!container) return;
			let map = existingMap;
			if (!map || map.size === 0) {
				const carNums = new Set();
				const thumbs = container.querySelectorAll(".thumbnail.group");
				for (const thumb of thumbs) {
					const link = thumb.querySelector("a[alt]");
					if (link) {
						const cn = link.getAttribute("alt");
						if (cn) carNums.add(normalizeCarNum(cn));
					}
				}
				if (carNums.size === 0) return;
				map = await queryLocalCars(Array.from(carNums));
			}
			if (!map || map.size === 0) return;
			const { total, matched } = renderBadges(container, map);
			const cumulativeMatched = container.querySelectorAll(".missav-status-tag").length;
			const totalThumbs = container.querySelectorAll(".thumbnail.group").length;
			logInfo("渲染标签", `${label}: +${total} 新增, +${matched} 命中 | 累计 ${cumulativeMatched}/${totalThumbs} 个标签`);
		}
		observeAndProcess() {
			let retries = 0;
			const maxRetries = 30;
			const tryProcess = () => {
				if (document.querySelectorAll(".thumbnail.group").length > 0) {
					this.processAll();
					return;
				}
				retries++;
				if (retries < maxRetries) setTimeout(tryProcess, 500);
			};
			setTimeout(tryProcess, 1500);
			let debounceTimer = null;
			new MutationObserver((mutations) => {
				let hasNewThumbnails = false;
				for (const mutation of mutations) {
					if (mutation.type === "childList") for (const node of mutation.addedNodes) {
						if (node.nodeType !== Node.ELEMENT_NODE) continue;
						const el = node;
						if (el.matches?.(".thumbnail.group") || el.querySelector?.(".thumbnail.group")) {
							hasNewThumbnails = true;
							break;
						}
					}
					if (mutation.type === "attributes" && mutation.attributeName === "alt" && mutation.target.matches?.("a[alt]") && mutation.target.closest?.(".thumbnail.group")) hasNewThumbnails = true;
					if (hasNewThumbnails) break;
				}
				if (hasNewThumbnails) {
					if (debounceTimer) clearTimeout(debounceTimer);
					debounceTimer = setTimeout(() => this.processAll(), 300);
				}
			}).observe(document.body, {
				childList: true,
				subtree: true,
				attributes: true,
				attributeFilter: ["alt"]
			});
		}
		async consumeDeltaJournal(value) {
			const journal = sortDeltaJournal(readDeltaJournal(value));
			for (const delta of journal) await this.consumeQueue.enqueue("consume", () => this.applyDelta(delta));
		}
		async consumeFull(payload) {
			return this.consumeQueue.enqueue("consume", () => this.applyFull(payload));
		}
		async applyDelta(delta) {
			try {
				const revision = getPayloadRevision(delta);
				if (revision < 0 || !isDeltaPayload(delta)) {
					logWarn("忽略无效增量载荷");
					return;
				}
				if (!this.shouldApply(revision, "delta")) return;
				writeIntent(revision, "delta");
				let rollback;
				if (!(await withSyncRevision(revision, "delta", async () => {
					const previous = await readLocalCarsSelection(delta.items.map((item) => item.carNum));
					rollback = () => restoreLocalCarsSelection(previous);
					if (delta.action === "upsert") {
						const records = delta.items.map((item) => ({
							carNum: item.carNum.trim(),
							status: (item.status || "").trim(),
							url_path: (item.url_path || "").trim()
						}));
						await upsertLocalCars(records);
						logInfo("增量更新", `upsert ${records.length} 条`);
					} else {
						const carNums = delta.items.map((item) => item.carNum.trim());
						await deleteLocalCars(carNums);
						logInfo("增量更新", `delete ${carNums.length} 条`);
					}
				}, async () => {
					if (rollback) await rollback();
				})).applied) {
					this.markApplied(revision, "delta");
					clearIntent(revision);
					return;
				}
				this.markApplied(revision, "delta");
				await this.processAll();
				clearIntent(revision);
			} catch (err) {
				logErr("增量消费失败", err instanceof Error ? err.message : String(err));
			}
		}
		async applyFull(payload) {
			try {
				let data = payload ?? GM_getValue("jhs_car_status_data");
				if (!payload && data) {
					const rev1 = data.revision ?? data.ts;
					await new Promise((resolve) => setTimeout(resolve, 50));
					const data2 = GM_getValue(GM_KEY_CAR_STATUS_DATA);
					const rev2 = data2 ? data2.revision ?? data2.ts : -1;
					if (rev1 !== rev2) {
						logWarn("全量快照双读不一致", `rev1=${rev1} rev2=${rev2},使用第二次读取结果`);
						data = data2;
					}
				}
				if (!data || typeof data !== "object" || typeof data.data !== "string" || !data.data) {
					if (payload !== void 0) logWarn("GM 存储中无全量数据");
					return;
				}
				const revision = getPayloadRevision(data);
				if (revision < 0 || !Number.isInteger(data.count) || data.count < 0 || data.mode !== void 0 && data.mode !== "snapshot" || data.ready === false || data.count === 0 && data.ready !== true) {
					logWarn("拒绝未就绪或格式无效的全量快照");
					return;
				}
				if (!this.shouldApply(revision, "full")) return;
				writeIntent(revision, "full");
				logInfo("全量消费开始", `count=${data.count} hwm=${data.hwm} revision=${revision}`);
				const store = await gunzipFromBase64(data.data);
				if (!store) {
					logErr("解压失败(DecompressionStream 不可用?数据损坏?)");
					return;
				}
				const validation = validateColumnarSnapshot(store, data.count);
				if (!validation.ok) {
					logErr("全量快照校验失败,拒绝覆盖本地数据", validation.reason);
					return;
				}
				logInfo("解压完成", `${validation.records.length} 条记录`);
				let rollback;
				const result = await withSyncRevision(revision, "full", async () => {
					const previous = await readLocalCarsSnapshot();
					rollback = () => restoreLocalCarsSnapshot(previous);
					return replaceLocalCars(validation.records, previous);
				}, async () => {
					if (rollback) await rollback();
				});
				if (!result.applied) {
					this.markApplied(revision, "full");
					clearIntent(revision);
					return;
				}
				const { written, deleted } = result.value;
				logOk("对账本地 IDB", `写入 ${written} 条,删除 ${deleted} 条`);
				this.markApplied(revision, "full");
				await this.processAll();
				clearIntent(revision);
			} catch (err) {
				logErr("全量消费失败", err instanceof Error ? err.message : String(err));
			}
		}
		shouldApply(revision, kind) {
			if (revision < this.lastAppliedRevision) {
				logWarn("忽略过期同步载荷", `${kind} revision=${revision} < ${this.lastAppliedRevision}`);
				return false;
			}
			if (revision === this.lastAppliedRevision && kind === "full") {
				logWarn("忽略重复或落后的全量快照", `revision=${revision}, last=${this.lastAppliedKind || "none"}`);
				return false;
			}
			return true;
		}
		markApplied(revision, kind) {
			this.lastAppliedRevision = Math.max(this.lastAppliedRevision, revision);
			this.lastAppliedKind = kind;
		}
	};
	async function clearAppliedRevisionLocal() {
		const db = await openLocalDB();
		try {
			await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_META_STORE, "readwrite");
				tx.objectStore(MISSAV_DB_META_STORE).delete(MISSAV_SYNC_META_KEY);
				tx.oncomplete = () => resolve();
				tx.onerror = () => reject(tx.error || new Error("清理同步修订号失败"));
				tx.onabort = () => reject(tx.error || new Error("清理同步修订号事务中止"));
			});
		} finally {
			db.close();
		}
	}
	var JAVDB_ICON_SVG = `<svg  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"  class="icon icon-tabler icons-tabler-outline icon-tabler-letter-j-small"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 8h4v6a2 2 0 1 1 -4 0" /></svg>`;
	function JavDBIcon() {
		return (0, import_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: JAVDB_ICON_SVG } });
	}
	var LOG = "[MissAV 快速复制]";
	var MENU_BAR_SELECTOR = "body > div:nth-child(3) > div.sm\\:container.mx-auto.px-4.content-without-search.pb-12 > div > div.flex-1.order-first > div.mt-4 > div";
	function extractCode(pathname) {
		const filename = pathname.split("/").pop() || "";
		if (/^FC2-PPV-\d+$/i.test(filename)) return filename;
		const parts = filename.split("-");
		return parts.length >= 2 ? parts[0] + "-" + parts[1] : filename;
	}
	function copyToClipboard(text) {
		return navigator.clipboard.writeText(text).then(() => true).catch(() => false);
	}
	function showToast(message, duration = 2e3) {
		const toast = document.createElement("div");
		toast.textContent = message;
		Object.assign(toast.style, {
			position: "fixed",
			bottom: "20px",
			left: "50%",
			transform: "translateX(-50%)",
			background: "rgba(0,0,0,0.7)",
			color: "#fff",
			padding: "8px 16px",
			borderRadius: "4px",
			fontSize: "14px",
			zIndex: "9999",
			transition: "opacity 0.3s",
			opacity: "1"
		});
		document.body.appendChild(toast);
		setTimeout(() => {
			toast.style.opacity = "0";
			setTimeout(() => toast.remove(), 300);
		}, duration);
	}
	function openInNewTab(url) {
		console.log(`${LOG} openInNewTab 触发`);
		try {
			const a = document.createElement("a");
			a.href = url;
			a.target = "_blank";
			a.style.display = "none";
			document.body.appendChild(a);
			a.click();
			console.log(`${LOG} 执行 模拟单击 a 标签`);
			document.body.removeChild(a);
			return true;
		} catch (e) {
			console.log(`${LOG} 单击 a 标签失败:`, e);
			return false;
		}
	}
	function createButton(label, svgElement, onClick) {
		const button = document.createElement("button");
		button.type = "button";
		button.className = "inline-flex items-center whitespace-nowrap shadow-sm text-sm text-nord4 leading-4 font-medium focus:outline-none hover:text-nord6 mr-2";
		button.appendChild(svgElement);
		button.appendChild(document.createTextNode(label));
		button.addEventListener("click", (e) => {
			e.preventDefault();
			e.stopPropagation();
			onClick();
		});
		return button;
	}
	function createSVGClipboard() {
		const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
		svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
		svg.setAttribute("width", "16");
		svg.setAttribute("height", "16");
		svg.setAttribute("fill", "currentColor");
		svg.setAttribute("class", "bi bi-clipboard-check mr-1");
		svg.setAttribute("viewBox", "0 0 16 16");
		const path1 = document.createElementNS(svg.namespaceURI, "path");
		path1.setAttribute("fill-rule", "evenodd");
		path1.setAttribute("d", "M10.854 7.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 9.793l2.646-2.647a.5.5 0 0 1 .708 0");
		const path2 = document.createElementNS(svg.namespaceURI, "path");
		path2.setAttribute("d", "M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z");
		const path3 = document.createElementNS(svg.namespaceURI, "path");
		path3.setAttribute("d", "M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z");
		svg.appendChild(path1);
		svg.appendChild(path2);
		svg.appendChild(path3);
		return svg;
	}
	function createSVGJavDB() {
		const html = jsxToString((0, import_jsx_runtime.jsx)(JavDBIcon, {}));
		const template = document.createElement("template");
		template.innerHTML = html;
		return template.content.querySelector("svg");
	}
	function insertButtons(menuBar) {
		const fanhao = extractCode(window.location.pathname);
		const copyBtn = createButton("复制番号", createSVGClipboard(), () => {
			copyToClipboard(fanhao).then((success) => {
				showToast(success ? `番号 ${fanhao} 已复制` : "复制失败");
			});
		});
		menuBar.prepend(copyBtn);
		const javdbBtn = createButton("转到JavDB搜索", createSVGJavDB(), () => {
			const javdbUrl = `https://javdb.com/search?q=${encodeURIComponent(fanhao)}&f=all`;
			console.log(`${LOG} 尝试打开 JavDB 链接:`, javdbUrl);
			if (openInNewTab(javdbUrl)) showToast(`正在跳转到 JavDB 搜索: ${fanhao}`);
			else {
				showToast("跳转失败,请检查弹窗阻止设置");
				copyToClipboard(javdbUrl).then((copied) => {
					if (copied) showToast("链接已复制到剪贴板,请手动打开");
				});
			}
		});
		menuBar.appendChild(javdbBtn);
		console.log(`${LOG} ✅ Copy 和 JavDB 按钮已插入 menu_bar`);
	}
	var MissavQuickCopyPlugin = class extends BasePlugin {
		observer = null;
		getName() {
			return "MissavQuickCopyPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			const existing = document.querySelector(MENU_BAR_SELECTOR);
			if (existing) {
				insertButtons(existing);
				return;
			}
			this.observer = new MutationObserver(() => {
				const menuBar = document.querySelector(MENU_BAR_SELECTOR);
				if (menuBar) {
					this.observer?.disconnect();
					this.observer = null;
					insertButtons(menuBar);
				}
			});
			this.observer.observe(document.body, {
				childList: true,
				subtree: true
			});
		}
	};
	var errorStyle = { color: "red" };
	function TranslatedTitle({ error, children }) {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "translated-title",
			style: error ? errorStyle : void 0,
			children
		});
	}
	var translate_plugin_default = "/* 标题翻译插件样式(原 translate-plugin.tsx initCss 返回的 <style> 块,\n   改走 CSS 管线:utils.insertStyle 自动包裹 <style> 注入 head,时机/作用域与原先一致)。 */\n.translated-title {\n    margin-top: 8px;\n    padding: 12px;\n    border-radius: 5px;\n    border-left: 4px solid rgb(76, 175, 80);\n    background: linear-gradient(135deg, rgb(255, 255, 255) 0%, rgb(245, 245, 245) 100%);\n    box-shadow: 0 4px 8px rgb(0, 0, 0, 0.08);\n    font-size: 20px;\n}\n";
	var TranslatePlugin = class extends BasePlugin {
		getName() {
			return "TranslatePlugin";
		}
		get pageTypes() {
			return ["detail"];
		}
		async initCss() {
			return translate_plugin_default;
		}
		async handle() {
			if (!featureFlags.translatePlugin) return;
			if (window.isDetailPage) this.translate().then();
		}
		async translate(carNum, showCarNum = true) {
			if (await storageManager.getSetting("translateTitle", "yes") !== "yes") return;
			let $titleElement = $(".origin-title");
			if (!$titleElement.length) $titleElement = $(".current-title");
			if (!$titleElement.length) $titleElement = $("h3");
			if (!$titleElement.length) return;
			const originalText = $titleElement.text().trim();
			if (!originalText) {
				show.error("获取标题失败, 无法进行翻译");
				return;
			}
			if ($titleElement.next(".translated-title").length) return;
			$titleElement.after(jsxToString((0, import_jsx_runtime.jsx)(TranslatedTitle, { children: "翻译中..." })));
			const $loadingElement = $titleElement.next(".translated-title");
			if (!carNum) try {
				carNum = this.getPageInfo().carNum || "";
			} catch {
				carNum = "";
			}
			const cache = localStorage.getItem("jhs_translate") ? JSON.parse(localStorage.getItem("jhs_translate")) : {};
			if (carNum && cache[carNum]) {
				$loadingElement.html(showCarNum ? carNum + "&nbsp;&nbsp;&nbsp;" + cache[carNum] : cache[carNum]);
				return;
			}
			try {
				const translatedText = await translateText(originalText, "ja", "zh-CN");
				$loadingElement.html(showCarNum && carNum ? carNum + "&nbsp;&nbsp;&nbsp;" + translatedText : translatedText);
				if (carNum) {
					cache[carNum] = translatedText;
					localStorage.setItem("jhs_translate", JSON.stringify(cache));
				}
			} catch (error) {
				clog.error("翻译失败:", error);
				const message = error instanceof DOMException && error.name === "AbortError" ? "翻译超时,请稍后重试" : `翻译失败: ${error instanceof Error ? error.message : String(error)}`;
				$loadingElement.replaceWith(jsxToString((0, import_jsx_runtime.jsx)(TranslatedTitle, {
					error: true,
					children: message
				})));
			}
		}
	};
	var reloadingStyle = {
		marginTop: "50px",
		cursor: "auto",
		color: "#000"
	};
	function ScreenReloading() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: reloadingStyle,
			children: "正在重新加载..."
		});
	}
	var fallbackStyle = {
		marginTop: "50px",
		cursor: "auto",
		color: "#000"
	};
	function ScreenShotFallback({ carNum }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsx)("div", {
				style: fallbackStyle,
				children: "获取缩略图失败"
			}),
			(0, import_jsx_runtime.jsx)("br", {}),
			(0, import_jsx_runtime.jsx)("a", {
				href: "#",
				className: "retry-link",
				children: "点击重试"
			}),
			" ",
			"或",
			" ",
			(0, import_jsx_runtime.jsx)("a", {
				className: "check-link",
				href: `https://javstore.net/search?q=${carNum}`,
				target: "_blank",
				children: "前往确认"
			})
		] });
	}
	var fullWidthStyle = { width: "100%" };
	function ScreenShotImage({ src, alt }) {
		return (0, import_jsx_runtime.jsx)("img", {
			src,
			alt,
			loading: "lazy",
			style: fullWidthStyle
		});
	}
	var ScreenShotPlugin = class extends BasePlugin {
		getName() {
			return "ScreenShotPlugin";
		}
		get pageTypes() {
			return ["detail"];
		}
		async handle() {
			if (!featureFlags.screenShotPlugin) return;
			this.loadScreenShot().then();
		}
		async loadScreenShot() {
			if (!window.isDetailPage) return;
			const carNum = this.getPageInfo().carNum;
			$(".preview-images .tile-item").first().before(jsxToString((0, import_jsx_runtime.jsx)(ScreenLoadingPlaceholder, { maxHeight: "215px" })));
			try {
				const imgUrl = await this.getScreenshot(carNum);
				this.addImg("缩略图", imgUrl);
				clog.log("加载缩略图:", imgUrl);
			} catch (e) {
				this.showErrorFallback(carNum, e);
			}
		}
		async getScreenshot(carNum) {
			let cacheData = {};
			try {
				const cached = localStorage.getItem("jhs_screenShot");
				if (cached) cacheData = JSON.parse(cached);
			} catch {}
			if (cacheData[carNum]) {
				clog.debug("缓存中存在缩略图:", carNum, cacheData[carNum]);
				return cacheData[carNum];
			}
			let imgUrl = null;
			try {
				imgUrl = await this.getJavStoreScreenShot(carNum);
			} catch (e) {
				clog.error("获取缩略图资源失败:", imgUrl, e);
				throw e;
			}
			if (!imgUrl) {
				this.showErrorFallback(carNum, null);
				return null;
			}
			const httpsIndex = imgUrl.indexOf("https://");
			if (httpsIndex !== -1) imgUrl = imgUrl.substring(httpsIndex);
			cacheData[carNum] = imgUrl;
			clog.log("缩略图获取成功:", imgUrl);
			localStorage.setItem("jhs_screenShot", JSON.stringify(cacheData));
			return imgUrl;
		}
		async getJavStoreScreenShot(carNum) {
			const url = `https://javstore.net/search?q=${encodeURIComponent(carNum.toLowerCase().replace("fc2-", ""))}`;
			clog.log("正在解析缩略图:", url);
			const html = await gmHttp.get(url);
			const $dom = utils.htmlTo$dom(String(html));
			const tempCarNum = carNum.toLowerCase().replace(/fc2-(ppv-)?/g, "").replace(/-/g, "");
			let detailPageUrl = null;
			const $itemList = $dom.find("main .grid a");
			for (let i = 0; i < $itemList.length; i++) {
				const href = $($itemList[i]).attr("href") || "";
				if (href.toLowerCase().replace(/fc2-(ppv-)?/g, "").replace(/-/g, "").includes(tempCarNum)) {
					detailPageUrl = new URL(href, "https://javstore.net").href;
					break;
				}
			}
			if (!detailPageUrl) {
				clog.error("JavStore, 查询番号失败:", url);
				return null;
			}
			const detailPageHtml = await gmHttp.get(detailPageUrl);
			const $detailPageDom = utils.htmlTo$dom(String(detailPageHtml));
			const imgUrl = $detailPageDom.find("a:contains('CLICK HERE')").attr("href") || $detailPageDom.find("img[src*='_s.jpg']").attr("src");
			if (!imgUrl) {
				clog.error("JavStore, 解析预览图失败:", url);
				return null;
			}
			return String(imgUrl).replace(".th", "");
		}
		addImg(title, imgUrl) {
			if (imgUrl) {
				$(".screen-container").html(jsxToString((0, import_jsx_runtime.jsx)(ScreenShotImage, {
					src: imgUrl,
					alt: title
				})));
				$(".screen-container").on("click", (event) => {
					event.stopPropagation();
					event.preventDefault();
					window.showImageViewer(event.currentTarget);
				});
			}
		}
		showErrorFallback(carNum, error) {
			clog.error("获取缩略图失败:", error instanceof Error ? error.message.substring(0, 100) : String(error));
			$(".screen-container").html(jsxToString((0, import_jsx_runtime.jsx)(ScreenShotFallback, { carNum }))).off("click", ".retry-link").off("click", ".check-link").on("click", ".retry-link", async (e) => {
				e.stopPropagation();
				e.preventDefault();
				$(".screen-container").html(jsxToString((0, import_jsx_runtime.jsx)(ScreenReloading, {})));
				try {
					const imgUrl = await this.getScreenshot(carNum);
					this.addImg("缩略图", imgUrl);
				} catch (err) {
					this.showErrorFallback(carNum, err);
				}
			}).on("click", ".check-link", async (e) => {
				e.stopPropagation();
				e.preventDefault();
				window.open(`https://javstore.net/search?q=${encodeURIComponent(carNum)}`, "_blank", "noopener,noreferrer");
			});
		}
	};
	function MagnetHubContainer() {
		return (0, import_jsx_runtime.jsx)("div", { className: "magnet-container" });
	}
	function MagnetHubTabs() {
		return (0, import_jsx_runtime.jsx)("div", { className: "magnet-tabs" });
	}
	function MagnetHubResults() {
		return (0, import_jsx_runtime.jsx)("div", { className: "magnet-results" });
	}
	function MagnetHubLoading({ engineName, keyword }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "magnet-loading",
			children: [
				"正在从 ",
				engineName,
				" 搜索 \"",
				keyword,
				"\"..."
			]
		});
	}
	function MagnetHubError({ message }) {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "magnet-error",
			children: message
		});
	}
	function MagnetHubTab({ engineId, engineName }) {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "magnet-tab",
			"data-engine": engineId,
			children: engineName
		});
	}
	function MagnetHubTargetLink({ href }) {
		return (0, import_jsx_runtime.jsx)("a", {
			style: {
				marginRight: "20px",
				marginTop: "3px"
			},
			id: "targetBox",
			href,
			target: "_blank",
			children: "原网页"
		});
	}
	function MagnetResultCard({ magnet, title, size, date }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "magnet-result",
			children: [
				(0, import_jsx_runtime.jsx)("div", {
					className: "magnet-title",
					children: (0, import_jsx_runtime.jsx)("a", {
						href: magnet,
						children: title
					})
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					className: "magnet-info",
					children: [(0, import_jsx_runtime.jsxs)("span", { children: ["大小: ", size] }), (0, import_jsx_runtime.jsxs)("span", { children: ["日期: ", date] })]
				}),
				(0, import_jsx_runtime.jsx)("div", {
					className: "magnet-copy",
					children: (0, import_jsx_runtime.jsx)("button", {
						className: "magnet-hub-btn copy-btn",
						"data-magnet": magnet,
						children: "复制链接"
					})
				})
			]
		});
	}
	var magnet_hub_plugin_default = "/*\n * 磁链聚合 MagnetHubPlugin 样式。\n *\n * 原脚本位于 MagnetHubPlugin.initCss() 返回的 `<style>` 字符串内(经\n * PluginManager.processCss → utils.insertStyle 注入 head),此处提取为\n * 独立 .css,由 initCss() 返回 → PluginManager utils.insertStyle 注入\n * (insertStyle 检测无 <style> 标签时自动包裹)。注入目标始终为 head\n * (全局作用域),与原实现一致。CSS 规则内容与原字符串一致(缩进标准化,\n * CSS 解析忽略空白,渲染等价)。\n */\n.magnet-container { margin: 20px auto; width: 100%; font-family: Arial, sans-serif; }\n.magnet-tabs { display: flex; border-bottom: 1px solid #ddd; margin-bottom: 15px; justify-content: space-between; }\n.magnet-tab { padding: 5px 12px; cursor: pointer; border: 1px solid transparent; border-bottom: none; margin-right: 5px; background: #f5f5f5; border-radius: 5px 5px 0 0; }\n.magnet-tab.active { background: #fff; border-color: #ddd; border-bottom: 1px solid #fff; margin-bottom: -1px; font-weight: bold; }\n.magnet-tab:hover:not(.active) { background: #e9e9e9; }\n.magnet-results { min-height: 200px; }\n.magnet-result { padding: 15px; border-bottom: 1px solid #eee; position: relative; }\n.magnet-result:hover { background-color: #f9f9f9; }\n.magnet-title { font-weight: bold; margin-bottom: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 80px; }\n.magnet-info { display: flex; justify-content: space-between; color: #666; font-size: 13px; }\n.magnet-copy { position: absolute; right: 15px; top: 15px; }\n.magnet-hub-btn { padding: 4px 10px; margin-left: 4px; cursor: pointer; border: 1px solid #ddd; border-radius: 3px; background: #f5f5f5; }\n.magnet-hub-btn.copied { background: #4caf50; color: #fff; }\n.magnet-loading, .magnet-error { padding: 20px; text-align: center; color: #666; }\n.magnet-error { color: #c00; }\n";
	var MagnetHubPlugin = class extends BasePlugin {
		currentEngine = null;
		_searchSeq = 0;
		searchEngines = [
			{
				name: "U9A9",
				id: "u9a9",
				url: "https://u9a9.com/?type=2&search={keyword}",
				targetPage: "https://u9a9.com/?type=2&search={keyword}",
				parseHtml: this.parseU3C3
			},
			{
				name: "U3C3",
				id: "u3c3",
				url: "https://u3c3.com/?search2=a8lr16lo&search={keyword}",
				targetPage: "https://u3c3.com/?search2=a8lr16lo&search={keyword}",
				parseHtml: this.parseU3C3
			},
			{
				name: "Sukebei",
				id: "Sukebei",
				url: "https://sukebei.nyaa.si/?f=0&c=0_0&q={keyword}",
				targetPage: "https://sukebei.nyaa.si/?f=0&c=0_0&q={keyword}",
				parseHtml: this.parseSukebei
			}
		];
		getName() {
			return "MagnetHubPlugin";
		}
		async initCss() {
			return magnet_hub_plugin_default;
		}
		createMagnetHub(keyword) {
			if (!featureFlags.magnetHubPlugin) return $(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubError, { message: "磁力聚合未启用" })));
			keyword = keyword.replace("FC2-", "");
			const $container = $(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubContainer, {})));
			const $tabs = $(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubTabs, {})));
			const key = "jhs_magnetHub_selectedEngine";
			const savedEngineId = localStorage.getItem(key);
			let defaultEngineIndex = 0;
			const $tabBox = $(document.createElement("div")).css("display", "flex");
			this.searchEngines.forEach((engine, index) => {
				const $tab = $(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubTab, {
					engineId: engine.id,
					engineName: engine.name
				})));
				if (savedEngineId && engine.id === savedEngineId) {
					$tab.addClass("active");
					this.currentEngine = engine;
					defaultEngineIndex = index;
				} else if (index === 0 && !savedEngineId) {
					$tab.addClass("active");
					this.currentEngine = engine;
				}
				$tabBox.append($tab);
			});
			$tabs.append($tabBox);
			const engine = this.currentEngine || this.searchEngines[0];
			$tabs.append(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubTargetLink, { href: engine.targetPage.replace("{keyword}", encodeURIComponent(keyword)) })));
			$container.append($tabs);
			const $resultsContainer = $(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubResults, {})));
			$container.append($resultsContainer);
			$container.on("click", ".magnet-tab", (e) => {
				const engineId = $(e.target).data("engine");
				this.currentEngine = this.searchEngines.find((eng) => eng.id === engineId) || null;
				if (this.currentEngine) {
					$("#targetBox").attr("href", this.currentEngine.targetPage.replace("{keyword}", encodeURIComponent(keyword)));
					localStorage.setItem(key, engineId);
					$container.find(".magnet-tab").removeClass("active");
					$(e.target).addClass("active");
					this.searchEngine($resultsContainer, this.currentEngine, keyword);
				}
			});
			this.searchEngine($resultsContainer, this.currentEngine || this.searchEngines[defaultEngineIndex], keyword);
			return $container;
		}
		searchEngine($container, engine, keyword) {
			const seq = ++this._searchSeq;
			$container.html(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubLoading, {
				engineName: engine.name,
				keyword
			})));
			const cacheKey = `${engine.name}_${keyword}`;
			const cached = sessionStorage.getItem(cacheKey);
			if (cached) try {
				this.displayResults($container, JSON.parse(cached), engine.name);
				return;
			} catch {}
			const url = engine.url.replace("{keyword}", encodeURIComponent(keyword));
			if (engine.parseHtml) GM_xmlhttpRequest({
				method: "GET",
				url,
				timeout: 15e3,
				onload: (response) => {
					try {
						const results = engine.parseHtml.call(this, response.responseText, keyword);
						if (results.length > 0) sessionStorage.setItem(cacheKey, JSON.stringify(results));
						if (seq !== this._searchSeq) return;
						this.displayResults($container, results, engine.name);
					} catch (e) {
						$container.html(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubError, { message: `解析 ${engine.name} 结果失败: ${e instanceof Error ? e.message : String(e)}` })));
					}
				},
				onerror: (error) => {
					if (seq !== this._searchSeq) return;
					$container.html(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubError, { message: `从 ${engine.name} 获取数据失败: ${error.statusText || "网络错误"}` })));
				},
				ontimeout: () => {
					if (seq !== this._searchSeq) return;
					$container.html(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubError, { message: `从 ${engine.name} 获取数据超时` })));
				}
			});
		}
		displayResults($container, results, _engineName) {
			$container.empty();
			if (results.length === 0) {
				$container.append(jsxToString((0, import_jsx_runtime.jsx)(MagnetHubError, { message: "没有找到相关结果" })));
				return;
			}
			results.forEach((result) => {
				const $result = $(jsxToString((0, import_jsx_runtime.jsx)(MagnetResultCard, {
					magnet: result.magnet,
					title: result.title,
					size: result.size || "未知",
					date: result.date || "未知"
				})));
				$container.append($result);
			});
			$container.on("click", ".copy-btn", function() {
				const $btn = $(this);
				const magnet = $btn.data("magnet");
				const showCopied = () => {
					const originalText = $btn.text();
					$btn.addClass("copied").text("已复制");
					setTimeout(() => {
						$btn.removeClass("copied").text(originalText);
					}, 2e3);
				};
				if (navigator.clipboard) navigator.clipboard.writeText(magnet).then(showCopied).catch(() => {
					utils.copyToClipboard("磁链", magnet);
					showCopied();
				});
				else {
					utils.copyToClipboard("磁链", magnet);
					showCopied();
				}
			});
		}
		parseU3C3(html, keyword) {
			const $dom = utils.htmlTo$dom(html);
			const results = [];
			$dom.find(".torrent-list tbody tr").each((_i, el) => {
				const $el = $(el);
				if ($el.text().includes("置顶")) return;
				const title = $el.find("td:nth-child(2) a").attr("title") || $el.find("td:nth-child(2) a").text().trim();
				if (!title.toLowerCase().includes(keyword.toLowerCase())) return;
				const magnet = $el.find("td:nth-child(3) a[href^='magnet:']").attr("href");
				const size = $el.find("td:nth-child(4)").text().trim();
				const date = $el.find("td:nth-child(5)").text().trim();
				if (magnet) results.push({
					title,
					magnet,
					size,
					date
				});
			});
			return results;
		}
		parseSukebei(html, keyword) {
			return this.parseU3C3(html, keyword);
		}
	};
	function ImageRecognitionDialog() {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: { padding: "20px" },
			children: [(0, import_jsx_runtime.jsxs)("div", {
				id: "upload-area",
				children: [
					(0, import_jsx_runtime.jsxs)("div", {
						style: {
							color: "#555",
							marginBottom: "15px"
						},
						children: [(0, import_jsx_runtime.jsx)("p", { children: "拖拽图片到此处 或 点击按钮选择图片" }), (0, import_jsx_runtime.jsx)("p", { children: "也可以直接 Ctrl+V 粘贴图片 / 图片URL" })]
					}),
					(0, import_jsx_runtime.jsx)("button", {
						id: "select-image-btn",
						children: "选择图片"
					}),
					(0, import_jsx_runtime.jsx)("input", {
						type: "file",
						style: { display: "none" },
						id: "image-file",
						accept: "image/*"
					})
				]
			}), (0, import_jsx_runtime.jsxs)("div", {
				id: "preview-area",
				style: {
					marginBottom: "20px",
					textAlign: "center",
					display: "none"
				},
				children: [
					(0, import_jsx_runtime.jsx)("img", {
						id: "preview-image",
						alt: "",
						src: "",
						style: {
							maxWidth: "100%",
							maxHeight: "300px",
							borderRadius: "4px"
						}
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						style: {
							marginTop: "15px",
							display: "flex",
							justifyContent: "center",
							gap: "10px"
						},
						id: "action-btns",
						children: [(0, import_jsx_runtime.jsx)("button", {
							id: "handle-btn",
							children: "搜索图片"
						}), (0, import_jsx_runtime.jsx)("button", {
							id: "cancel-btn",
							children: "取消"
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						id: "search-results",
						style: { display: "none" },
						children: [(0, import_jsx_runtime.jsxs)("p", {
							style: { margin: "20px auto" },
							children: ["请选择识图网站:", (0, import_jsx_runtime.jsx)("a", {
								id: "openAll",
								style: { cursor: "pointer" },
								children: "全部打开"
							})]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "search-img-site-btns-container",
							id: "search-img-site-btns-container"
						})]
					})
				]
			})]
		});
	}
	function ImageRecognitionHint() {
		return (0, import_jsx_runtime.jsx)("p", {
			style: { color: "#c00" },
			children: "图片尚未获得公网 URL,请重试搜索"
		});
	}
	function ImageRecognitionSiteButton({ href, icon, name }) {
		return (0, import_jsx_runtime.jsxs)("a", {
			className: "search-img-site-btn",
			href,
			target: "_blank",
			children: [(0, import_jsx_runtime.jsx)("img", {
				src: icon,
				alt: ""
			}), (0, import_jsx_runtime.jsx)("span", { children: name })]
		});
	}
	var image_recognition_plugin_default = "/*\n * 以图识图 ImageRecognitionPlugin 样式。\n *\n * 原脚本位于 ImageRecognitionPlugin.initCss() 返回的 `\\3c style>` 字符串内\n * (经 PluginManager.processCss → utils.insertStyle 注入 head),此处提取\n * 为独立 .css,由 initCss() 返回 → PluginManager utils.insertStyle 注入\n * (insertStyle 检测无 \\3c style> 标签时自动包裹)。注入目标始终为 head\n * (全局作用域),与原实现一致。CSS 规则内容与原字符串一致(缩进标准化,\n * CSS 解析忽略空白,渲染等价)。\n */\n#upload-area {\n    border: 2px dashed #85af68; border-radius: 8px; padding: 40px;\n    text-align: center; margin-bottom: 20px; transition: border-color 0.3s, background-color 0.3s;\n    background-color: #f9f9f9;\n}\n#upload-area:hover { border-color: #76b947; background-color: #f0f0f0; }\n#upload-area.highlight { border-color: #2196F3; background-color: #e3f2fd; }\n\n#select-image-btn {\n    background-color: #4CAF50; color: white; border: none;\n    padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 16px;\n}\n\n#handle-btn, #cancel-btn {\n    padding: 8px 16px; border-radius: 4px; cursor: pointer;\n    font-size: 14px; border: none;\n}\n#handle-btn { background-color: #2196F3; color: white; }\n#cancel-btn { background-color: #f44336; color: white; }\n\n.search-img-site-btns-container {\n    display: flex; flex-wrap: wrap; gap: 10px; margin-top: 15px;\n}\n\n.search-img-site-btn {\n    display: flex; align-items: center; padding: 8px 12px;\n    background-color: #f5f5f5; border-radius: 4px; text-decoration: none;\n    color: #333; font-size: 14px; border: 1px solid #ddd;\n}\n.search-img-site-btn img { width: 16px; height: 16px; margin-right: 6px; }\n";
	var ImageRecognitionPlugin = class extends BasePlugin {
		siteList = [
			{
				name: "Google旧版",
				url: "https://www.google.com/searchbyimage?image_url={placeholder}&client=firefox-b-d",
				ico: "https://www.google.com/favicon.ico"
			},
			{
				name: "Google",
				url: "https://lens.google.com/uploadbyurl?url={placeholder}",
				ico: "https://www.google.com/favicon.ico"
			},
			{
				name: "Yandex",
				url: "https://yandex.ru/images/search?rpt=imageview&url={placeholder}",
				ico: "https://yandex.ru/favicon.ico"
			}
		];
		isUploading = false;
		currentImageUrl = null;
		getName() {
			return "ImageRecognitionPlugin";
		}
		async initCss() {
			return image_recognition_plugin_default;
		}
		open(onOpenFun) {
			if (!featureFlags.imageRecognitionPlugin) return;
			layer.open({
				type: 1,
				title: "以图识图",
				content: jsxToString((0, import_jsx_runtime.jsx)(ImageRecognitionDialog, {})),
				area: utils.isMobile() ? utils.getResponsiveArea() : ["40%", "80%"],
				success: async () => {
					this.initEventListeners();
					onOpenFun?.();
				},
				end: () => {
					$(document).off("paste.searchImg");
				}
			});
		}
		initEventListeners() {
			const $uploadArea = $("#upload-area");
			const $fileInput = $("#image-file");
			const $selectBtn = $("#select-image-btn");
			const $previewArea = $("#preview-area");
			const $previewImage = $("#preview-image");
			const $searchImage = $("#handle-btn");
			const $cancelBtn = $("#cancel-btn");
			const $searchResults = $("#search-results");
			const $siteBtnsContainer = $("#search-img-site-btns-container");
			$uploadArea.on("dragover", (e) => {
				e.preventDefault();
				$uploadArea.addClass("highlight");
			}).on("dragleave", () => $uploadArea.removeClass("highlight")).on("drop", (e) => {
				e.preventDefault();
				$uploadArea.removeClass("highlight");
				const files = e.originalEvent?.dataTransfer?.files;
				if (files?.[0]) this.handleImageFile(files[0]);
			});
			$selectBtn.on("click", () => $fileInput.trigger("click"));
			$fileInput.on("change", (e) => {
				const files = e.target.files;
				if (files?.[0]) this.handleImageFile(files[0]);
			});
			$(document).on("paste.searchImg", async (e) => {
				const clipData = e.originalEvent?.clipboardData;
				const items = clipData?.items;
				if (!items) return;
				for (let i = 0; i < items.length; i++) if (items[i].type.indexOf("image") !== -1) {
					const file = items[i].getAsFile();
					if (file) this.handleImageFile(file);
					return;
				}
				const text = clipData?.getData("text");
				if (text && /^https?:\/\//.test(text)) {
					this.currentImageUrl = text;
					$previewImage.attr("src", text);
					$uploadArea.hide();
					$previewArea.show();
				}
			});
			$searchImage.on("click", async () => {
				if (!this.currentImageUrl) {
					show.error("请先选择图片");
					return;
				}
				await this.searchByImage(this.currentImageUrl);
				$searchResults.show();
				this.renderSiteButtons($siteBtnsContainer);
			});
			$cancelBtn.on("click", () => {
				this.currentImageUrl = null;
				$previewArea.hide();
				$uploadArea.show();
				$searchResults.hide();
				$fileInput.val("");
			});
			$("#openAll").on("click", () => {
				this.siteList.forEach((site) => {
					if (this.currentImageUrl) window.open(site.url.replace("{placeholder}", encodeURIComponent(this.currentImageUrl)), "_blank");
				});
			});
		}
		handleImageFile(file) {
			const reader = new FileReader();
			reader.onload = (e) => {
				const dataUrl = e.target.result;
				this.currentImageUrl = dataUrl;
				$("#preview-image").attr("src", dataUrl);
				$("#upload-area").hide();
				$("#preview-area").show();
				this.searchByImage(dataUrl).then(() => {
					$("#search-results").show();
					this.renderSiteButtons($("#search-img-site-btns-container"));
				});
			};
			reader.readAsDataURL(file);
		}
		async searchByImage(imageSrc) {
			if (this.isUploading) return;
			if (/^https?:\/\//.test(imageSrc) && !imageSrc.startsWith("data:")) {
				this.currentImageUrl = imageSrc;
				return;
			}
			this.isUploading = true;
			try {
				const base64 = imageSrc.replace(/^data:image\/\w+;base64,/, "");
				const resp = await new Promise((resolve, reject) => {
					GM_xmlhttpRequest({
						method: "POST",
						url: "https://api.imgur.com/3/image",
						headers: {
							Authorization: "Client-ID d70305e7c3ac5c6",
							"Content-Type": "application/json"
						},
						data: JSON.stringify({
							image: base64,
							type: "base64"
						}),
						onload: (r) => {
							try {
								resolve(JSON.parse(r.responseText));
							} catch (err) {
								reject(err);
							}
						},
						onerror: reject
					});
				});
				if (resp?.data?.link) this.currentImageUrl = resp.data.link;
				else show.error("图片上传失败");
			} catch (e) {
				clog.error(e);
				show.error("图片上传失败: " + (e instanceof Error ? e.message : String(e)));
			} finally {
				this.isUploading = false;
			}
		}
		renderSiteButtons($container) {
			$container.empty();
			if (!this.currentImageUrl || this.currentImageUrl.startsWith("data:")) {
				$container.append(jsxToString((0, import_jsx_runtime.jsx)(ImageRecognitionHint, {})));
				return;
			}
			this.siteList.forEach((site) => {
				const href = site.url.replace("{placeholder}", encodeURIComponent(this.currentImageUrl));
				$container.append(jsxToString((0, import_jsx_runtime.jsx)(ImageRecognitionSiteButton, {
					href,
					icon: site.ico,
					name: site.name
				})));
			});
		}
	};
	var wrapperStyle = { marginBottom: "15px" };
	var searchRowStyle = {
		display: "flex",
		gap: "8px",
		flexWrap: "wrap",
		marginBottom: "10px"
	};
	var keywordInputStyle = { maxWidth: "280px" };
	var sortSelectStyle = { height: "2.5em" };
	var paginationStyle = {
		marginTop: "15px",
		textAlign: "center"
	};
	function Fc2BrowsePage({ keyword }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: wrapperStyle,
			children: [
				(0, import_jsx_runtime.jsx)("h2", {
					className: "title is-4",
					children: "123Av FC2 浏览"
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: searchRowStyle,
					children: [
						(0, import_jsx_runtime.jsx)("input", {
							id: "fc2-123av-keyword",
							className: "input",
							style: keywordInputStyle,
							placeholder: "搜索关键词",
							value: keyword || ""
						}),
						(0, import_jsx_runtime.jsx)("button", {
							id: "fc2-123av-search",
							className: "button is-info",
							children: "搜索"
						}),
						(0, import_jsx_runtime.jsxs)("select", {
							id: "fc2-123av-sort",
							className: "select",
							style: sortSelectStyle,
							children: [
								(0, import_jsx_runtime.jsx)("option", {
									value: "release_date",
									children: "发布日期"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "recent_update",
									children: "最近更新"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "trending",
									children: "热门"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "most_viewed_today",
									children: "今天最多观看"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "most_viewed_week",
									children: "本周最多观看"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "most_viewed_month",
									children: "本月最多观看"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "most_viewed",
									children: "最多观看"
								}),
								(0, import_jsx_runtime.jsx)("option", {
									value: "most_favourited",
									children: "最受欢迎"
								})
							]
						})
					]
				}),
				(0, import_jsx_runtime.jsx)("div", {
					id: "fc2-123av-list",
					className: "movie-list h cols-4 vcols-8"
				}),
				(0, import_jsx_runtime.jsx)("div", {
					id: "fc2-123av-pagination",
					style: paginationStyle
				})
			]
		});
	}
	function hookPage(plugin) {
		document.title = "123Av FC2";
		const $box = plugin.$contentBox;
		if (!$box?.length) return;
		$box.html(jsxToString((0, import_jsx_runtime.jsx)(Fc2BrowsePage, { keyword: plugin.keyword ?? void 0 })));
		$("#fc2-123av-sort").val(plugin.sortVal);
		$("#fc2-123av-search").on("click", () => {
			plugin.keyword = String($("#fc2-123av-keyword").val() || "") || null;
			plugin.currentPage = 1;
			plugin.handleQuery();
		});
		$("#fc2-123av-sort").on("change", () => {
			plugin.sortVal = String($("#fc2-123av-sort").val() || "release_date");
			plugin.currentPage = 1;
			plugin.handleQuery();
		});
	}
	function renderPagination(plugin) {
		const $pg = $("#fc2-123av-pagination");
		if (!plugin.maxPage || plugin.maxPage <= 1) {
			$pg.empty();
			return;
		}
		let html = "";
		const cur = plugin.currentPage;
		const max = plugin.maxPage;
		const pages = [];
		for (let i = 1; i <= max; i++) if (i === 1 || i === max || i >= cur - 2 && i <= cur + 2) pages.push(i);
		let last = 0;
		for (const p of pages) {
			if (last && p - last > 1) html += jsxToString((0, import_jsx_runtime.jsx)("span", {
				style: { margin: "0 4px" },
				children: "…"
			}));
			html += jsxToString((0, import_jsx_runtime.jsx)("a", {
				className: `button is-small ${p === cur ? "is-primary" : ""}`,
				"data-page": p,
				style: { margin: "2px" },
				children: p
			}));
			last = p;
		}
		$pg.html(html);
		$pg.find("a[data-page]").on("click", (e) => {
			e.preventDefault();
			plugin.currentPage = parseInt($(e.currentTarget).attr("data-page") || "1", 10);
			plugin.handleQuery();
		});
	}
	async function handleQuery(plugin) {
		const seq = ++plugin._querySeq;
		const base = await plugin.getBaseUrl();
		const fetchPage = async (page) => {
			let url;
			if (plugin.keyword) url = `${base}/search?keyword=${encodeURIComponent(plugin.keyword)}&page=${page}&sort=${plugin.sortVal}`;
			else url = `${base}/makers/fc2?page=${page}&sort=${plugin.sortVal}`;
			const html = await gmHttp.get(url);
			return utils.htmlTo$dom(String(html));
		};
		try {
			show.info("正在加载 123Av FC2...");
			const pageA = (plugin.currentPage - 1) * 2 + 1;
			const pageB = pageA + 1;
			const $dom1 = await fetchPage(pageA);
			let movies = parseCards(plugin, $dom1);
			try {
				const $dom2 = await fetchPage(pageB);
				movies = movies.concat(parseCards(plugin, $dom2));
			} catch {}
			if (seq !== plugin._querySeq) return;
			const lastPageText = $dom1.find(".pagination .page-link").last().text() || $dom1.find(".pagination a").last().text();
			plugin.maxPage = Math.max(1, Math.ceil((parseInt(lastPageText, 10) || 1) / 2));
			const html = movies.map((movie) => jsxToString((0, import_jsx_runtime.jsx)(HitShowMovieItem, { movie }))).join("");
			$("#fc2-123av-list").html(html || jsxToString((0, import_jsx_runtime.jsx)("p", { children: "无结果" })));
			renderPagination(plugin);
			$("#fc2-123av-list .item a.box").on("click", (e) => {
				e.preventDefault();
				const href = $(e.currentTarget).attr("href") || "";
				const carNum = $(e.currentTarget).find("strong").text().trim() || href.split("/").pop() || "";
				plugin.open123AvFc2Dialog(carNum, href.startsWith("http") ? href : base + href);
			});
		} catch (e) {
			clog.error(e);
			show.error("加载 123Av FC2 失败: " + (e instanceof Error ? e.message : String(e)));
		}
	}
	function parseCards(_plugin, $dom) {
		const list = [];
		$dom.find(".card, .movie-list .item, .box").each((_i, el) => {
			const $el = $(el);
			const $a = $el.find("a").first();
			const href = $a.attr("href") || "";
			const title = $a.attr("title") || $el.find(".video-title, .title, h3").text().trim() || "";
			const number = $el.find("strong").text().trim() || (title.match(/FC2[-_]?PPV[-_]?(\d+)/i) ? "FC2-" + title.match(/FC2[-_]?PPV[-_]?(\d+)/i)[1] : title.split(" ")[0]);
			const cover = $el.find("img").attr("data-src") || $el.find("img").attr("src") || "";
			const id = href.split("/").filter(Boolean).pop() || number;
			if (number || href) list.push({
				id,
				number: number.startsWith("FC2") ? number : `FC2-${number}`,
				origin_title: title,
				cover_url: cover,
				release_date: $el.find(".meta, .date").text().trim() || "",
				has_cnsub: false,
				magnets_count: 0,
				new_magnets: false,
				_href: href
			});
		});
		return list;
	}
	var containerStyle = { padding: "15px" };
	var panelInfoStyle = { marginTop: "15px" };
	var toolbarStyle = { margin: "20px 0" };
	var galleryStyle = { marginTop: "10px" };
	var btnBaseStyle = {
		color: "#fff",
		padding: "6px 12px"
	};
	var filterBtnStyle = {
		...btnBaseStyle,
		backgroundColor: "#de3333",
		marginRight: "6px"
	};
	var favoriteBtnStyle = {
		...btnBaseStyle,
		backgroundColor: "#25b1dc",
		marginRight: "6px"
	};
	var hasDownBtnStyle = {
		...btnBaseStyle,
		backgroundColor: "#7bc73b",
		marginRight: "6px"
	};
	var hasWatchBtnStyle = {
		...btnBaseStyle,
		backgroundColor: "#d7a80c",
		marginRight: "6px"
	};
	var magnetSearchBtnStyle = {
		...btnBaseStyle,
		background: "linear-gradient(to right,#f58c01,#54a11d)"
	};
	function Fc2123avDetailDialog() {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "movie-detail-container",
			style: containerStyle,
			children: [
				(0, import_jsx_runtime.jsx)("div", {
					className: "movie-info-container",
					children: (0, import_jsx_runtime.jsx)("div", {
						className: "search-loading",
						children: "加载中..."
					})
				}),
				(0, import_jsx_runtime.jsx)("div", {
					className: "movie-panel-info",
					style: panelInfoStyle,
					children: (0, import_jsx_runtime.jsx)("strong", { children: "第三方资源: " })
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					style: toolbarStyle,
					children: [
						(0, import_jsx_runtime.jsx)("a", {
							id: "filterBtn",
							className: "jhs-toolbar-menu-btn",
							style: filterBtnStyle,
							children: "🚫 屏蔽"
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "favoriteBtn",
							className: "jhs-toolbar-menu-btn",
							style: favoriteBtnStyle,
							children: "⭐ 收藏"
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "hasDownBtn",
							className: "jhs-toolbar-menu-btn",
							style: hasDownBtnStyle,
							children: "📥️ 已下载"
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "hasWatchBtn",
							className: "jhs-toolbar-menu-btn",
							style: hasWatchBtnStyle,
							children: "🔍 已观看"
						}),
						(0, import_jsx_runtime.jsx)("a", {
							id: "magnetSearchBtn",
							className: "jhs-toolbar-menu-btn",
							style: magnetSearchBtnStyle,
							children: "磁力搜索"
						})
					]
				}),
				(0, import_jsx_runtime.jsx)("div", {
					id: "magnets-content",
					className: "magnet-links"
				}),
				(0, import_jsx_runtime.jsxs)("div", {
					className: "movie-gallery",
					style: galleryStyle,
					children: [(0, import_jsx_runtime.jsx)("strong", { children: "剧照: " }), (0, import_jsx_runtime.jsx)("div", { className: "image-list" })]
				})
			]
		});
	}
	var posterWrapStyle = { marginTop: "8px" };
	var posterImgStyle = { maxWidth: "320px" };
	var actorsStyle = { marginTop: "8px" };
	var actressTagStyle = { margin: "2px" };
	var hiddenStyle = { display: "none" };
	function Fc2123avMovieInfo({ info, carNum, actresses }) {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
			(0, import_jsx_runtime.jsx)("div", {
				className: "movie-title",
				children: (0, import_jsx_runtime.jsx)("strong", { children: info.title || carNum })
			}),
			(0, import_jsx_runtime.jsxs)("div", { children: ["番号: ", info.id || carNum] }),
			(0, import_jsx_runtime.jsxs)("div", { children: ["发布日: ", info.releaseDate || ""] }),
			info.poster ? (0, import_jsx_runtime.jsx)("div", {
				style: posterWrapStyle,
				children: (0, import_jsx_runtime.jsx)("img", {
					src: info.poster,
					style: posterImgStyle
				})
			}) : "",
			(0, import_jsx_runtime.jsxs)("div", {
				className: "movie-actors",
				style: actorsStyle,
				children: [(0, import_jsx_runtime.jsx)("strong", { children: "主演: " }), actresses.length > 0 ? actresses.map((actress) => (0, import_jsx_runtime.jsx)("span", {
					className: "tag",
					style: actressTagStyle,
					children: actress
				})) : "未知"]
			}),
			(0, import_jsx_runtime.jsx)("div", {
				id: "data-releaseDate",
				style: hiddenStyle,
				children: info.releaseDate || ""
			})
		] });
	}
	var HAS_DOWN_STATUS = "hasDown";
	async function open123AvFc2Dialog(plugin, carNum, href) {
		const dialogHtml = jsxToString((0, import_jsx_runtime.jsx)(Fc2123avDetailDialog, {}));
		layer.open({
			type: 1,
			title: carNum,
			content: dialogHtml,
			area: utils.getResponsiveArea(["80%", "90%"]),
			success: async () => {
				await loadData(plugin, carNum, href);
				handleLongImg(plugin, carNum.replace(/^FC2-/, ""));
				$("#filterBtn").on("click", () => saveAction(plugin, carNum, href, FILTER_ACTION));
				$("#favoriteBtn").on("click", () => saveAction(plugin, carNum, href, FAVORITE_ACTION));
				$("#hasDownBtn").on("click", () => saveAction(plugin, carNum, href, HAS_DOWN_STATUS));
				$("#hasWatchBtn").on("click", () => saveAction(plugin, carNum, href, HAS_WATCH_ACTION));
				$("#magnetSearchBtn").on("click", () => {
					const magnetHub = plugin.getBean("MagnetHubPlugin");
					if (magnetHub) $("#magnets-content").empty().append(magnetHub.createMagnetHub(carNum));
				});
			}
		});
	}
	async function saveAction(_plugin, carNum, url, actionType) {
		await storageManager.saveCar({
			carNum,
			url,
			names: void 0,
			actionType,
			publishTime: $("#data-releaseDate").text() || ""
		});
		show.ok("操作成功");
		refresh();
	}
	async function loadData(plugin, carNum, href) {
		try {
			const info = await get123AvVideoInfo(plugin, href);
			const fc2Num = carNum.replace(/^FC2-?(PPV-?)?/i, "");
			const actressInfo = await getActressInfo(plugin, fc2Num).catch(() => null);
			const imgList = await getImgList(plugin, fc2Num).catch(() => []);
			const actresses = actressInfo?.actors?.length ? actressInfo.actors : [];
			const imagesHtml = imgList.map((src) => jsxToString((0, import_jsx_runtime.jsx)("a", {
				className: "tile-item",
				href: src,
				target: "_blank",
				children: (0, import_jsx_runtime.jsx)("img", {
					src,
					style: {
						maxWidth: "150px",
						margin: "4px"
					},
					loading: "lazy"
				})
			}))).join("");
			$(".movie-info-container").html(jsxToString((0, import_jsx_runtime.jsx)(Fc2123avMovieInfo, {
				info,
				carNum,
				actresses
			})));
			$(".movie-gallery .image-list").html(imagesHtml);
			plugin.getBean("TranslatePlugin")?.translate?.(carNum, false)?.then?.();
		} catch (e) {
			clog.error(e);
			$(".movie-info-container").html(jsxToString((0, import_jsx_runtime.jsx)(MovieError, { message: e instanceof Error ? e.message : String(e) })));
		}
	}
	function handleLongImg(plugin, carNum) {
		utils.loopDetector(() => $(".movie-gallery .image-list").length > 0, async () => {
			$(".movie-gallery .image-list").prepend(jsxToString((0, import_jsx_runtime.jsx)(ScreenLoadingPlaceholder, { maxHeight: "150px" })));
			const screenShot = plugin.getBean("ScreenShotPlugin");
			if (!screenShot) return;
			try {
				const screenshotUrl = await screenShot.getScreenshot(carNum);
				if (screenshotUrl) screenShot.addImg("缩略图", screenshotUrl);
			} catch {}
		});
	}
	async function get123AvVideoInfo(plugin, href) {
		const fullHref = href.startsWith("http") ? href : await plugin.getBaseUrl() + href;
		const html = await gmHttp.get(fullHref);
		const $dom = utils.htmlTo$dom(String(html));
		const title = $dom.find("h1").first().text().trim() || $dom.find(".title").first().text().trim() || "";
		const poster = $dom.find("video").attr("poster") || $dom.find(".detail-img img, .cover img").attr("src") || "";
		const releaseDate = $dom.find(".detail-item:contains(\"発売日\"), .detail-item:contains(\"发布\")").text().replace(/.*?[::]/, "").trim() || $dom.find("time").text().trim() || "";
		return {
			id: $dom.find(".detail-item:contains(\"品番\"), .detail-item:contains(\"番号\")").text().replace(/.*?[::]/, "").trim() || title.split(" ")[0] || "",
			releaseDate,
			title,
			poster
		};
	}
	async function getActressInfo(_plugin, fc2Num) {
		try {
			const html = await gmHttp.get(`https://fc2ppvdb.com/articles/${fc2Num}`);
			const $dom = utils.htmlTo$dom(String(html));
			const actors = [];
			$dom.find("a[href*=\"/actress\"], .actress a, .actors a").each((_i, el) => {
				const name = $(el).text().trim();
				if (name) actors.push(name);
			});
			return { actors };
		} catch {
			return null;
		}
	}
	async function getImgList(_plugin, fc2Num) {
		try {
			const html = await gmHttp.get(`https://adult.contents.fc2.com/article/${fc2Num}/`);
			const $dom = utils.htmlTo$dom(String(html));
			const imgs = [];
			$dom.find("img").each((_i, el) => {
				const src = $(el).attr("src") || $(el).attr("data-src") || "";
				if (src && /sample|preview|main/i.test(src)) imgs.push(src);
			});
			return imgs.slice(0, 20);
		} catch {
			return [];
		}
	}
	var Fc2By123AvPlugin = class extends BasePlugin {
		$contentBox = null;
		urlParams = new URLSearchParams(window.location.search);
		sortVal = "release_date";
		currentPage = 1;
		maxPage = null;
		keyword = null;
		_querySeq = 0;
		constructor() {
			super();
			this.sortVal = this.urlParams.get("sort") || "release_date";
			this.currentPage = parseInt(this.urlParams.get("page") || "", 10) || 1;
			this.keyword = this.urlParams.get("keyword") || null;
		}
		getName() {
			return "Fc2By123AvPlugin";
		}
		async getBaseUrl() {
			return "https://123av.com".replace(/\/$/, "") + "/ja";
		}
		async handle() {
			if (!featureFlags.fc2By123AvPlugin) return;
			this.injectNavEntry();
			if (window.location.href.includes("/advanced_search?type=100")) {
				this.$contentBox = $(".section .container");
				this.hookPage();
				await this.handleQuery();
			}
		}
		injectNavEntry() {
			const href = "/advanced_search?type=100&released_start=2099-09";
			if ($("#navbar-item-123av-fc2").length === 0) {
				const $fc2Nav = $("#navbar-menu-hero a.navbar-item").filter((_i, el) => {
					const text = $(el).text().trim();
					const link = $(el).attr("href") || "";
					return text === "FC2" || link.includes("advanced_search?type=3");
				}).first();
				if ($fc2Nav.length) $fc2Nav.after(jsxToString((0, import_jsx_runtime.jsx)("a", {
					className: "navbar-item",
					id: "navbar-item-123av-fc2",
					href,
					children: "123Av-Fc2"
				})));
				else $("#navbar-menu-hero .navbar-start").first().append(jsxToString((0, import_jsx_runtime.jsx)("a", {
					className: "navbar-item",
					id: "navbar-item-123av-fc2",
					href,
					children: "123Av-Fc2"
				})));
			}
			if ($(".tabs li:contains(\"FC2\")").length && !$(".tabs a[href*=\"advanced_search?type=100\"]").length) $(".tabs li:contains(\"FC2\")").after(jsxToString((0, import_jsx_runtime.jsx)("li", {
				id: "tab-123av-fc2",
				children: (0, import_jsx_runtime.jsx)("a", {
					href,
					children: (0, import_jsx_runtime.jsx)("span", { children: "123Av-Fc2" })
				})
			})));
		}
		hookPage() {
			hookPage(this);
		}
		renderPagination() {
			renderPagination(this);
		}
		async handleQuery() {
			await handleQuery(this);
		}
		parseCards($dom) {
			return parseCards(this, $dom);
		}
		async open123AvFc2Dialog(carNum, href) {
			await open123AvFc2Dialog(this, carNum, href);
		}
		async saveAction(carNum, url, actionType) {
			await saveAction(this, carNum, url, actionType);
		}
		async loadData(carNum, href) {
			await loadData(this, carNum, href);
		}
		handleLongImg(carNum) {
			handleLongImg(this, carNum);
		}
		async get123AvVideoInfo(href) {
			return get123AvVideoInfo(this, href);
		}
		async getActressInfo(fc2Num) {
			return getActressInfo(this, fc2Num);
		}
		async getImgList(fc2Num) {
			return getImgList(this, fc2Num);
		}
	};
	var loading_default = ".loading-container {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    background-color: rgb(0, 0, 0, 0.1);\n    z-index: var(--jhs-z-top);\n}\n\n.loading-animation {\n    position: relative;\n    width: 60px;\n    height: 12px;\n    background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);\n    border-radius: 6px;\n    animation: loading-animate 1.8s ease-in-out infinite;\n    box-shadow: 0 4px 12px rgb(0, 0, 0, 0.1);\n}\n\n.loading-animation::before,\n.loading-animation::after {\n    position: absolute;\n    display: block;\n    content: '';\n    animation: loading-animate 1.8s ease-in-out infinite;\n    height: 12px;\n    border-radius: 6px;\n    box-shadow: 0 4px 12px rgb(0, 0, 0, 0.1);\n}\n\n.loading-animation::before {\n    top: -20px;\n    left: 10px;\n    width: 40px;\n    background: linear-gradient(90deg, #ff758c 0%, #ff7eb3 100%);\n}\n\n.loading-animation::after {\n    bottom: -20px;\n    width: 35px;\n    background: linear-gradient(90deg, #ff9a9e 0%, #fad0c4 100%);\n}\n\n@keyframes loading-animate {\n    0% {\n        transform: translateX(40px);\n    }\n\n    50% {\n        transform: translateX(-30px);\n    }\n\n    100% {\n        transform: translateX(40px);\n    }\n}\n";
	var viewer_default = ".viewer-canvas {\n    overflow: auto !important;\n}\n\n.viewer-close {\n    background: rgb(255, 0, 0, 0.6) !important;\n}\n\n.viewer-close:hover {\n    background: rgb(255, 0, 0, 0.8) !important;\n}\n";
	var logger_default = ".console-logger-container {\n    position: fixed;\n    bottom: 0;\n    right: 0;\n    z-index: var(--jhs-z-top);\n    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n    width: fit-content;\n}\n\n.console-logger-toggle {\n    width: 40px;\n    height: 30px;\n    background: #2c3e50;\n    border-radius: 120px 10px 0 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    cursor: pointer;\n    box-shadow: -2px 0 5px rgb(0, 0, 0, 0.1);\n    transition: background-color 0.3s ease;\n    color: white;\n    font-size: 16px;\n}\n\n.console-logger-toggle:hover {\n    background: #34495e;\n}\n\n.console-logger-toggle::after {\n    content: '▼';\n    transition: transform 0.3s ease;\n}\n\n.console-logger-toggle.collapsed::after {\n    content: '▲';\n}\n\n.console-logger-window {\n    width: 400px;\n    height: 400px;\n    background: white;\n    border-radius: 10px 0 10px 10px;\n    box-shadow: 0 5px 15px rgb(0, 0, 0, 0.1);\n    display: flex;\n    flex-direction: column;\n    overflow: hidden;\n    transform: translateY(0);\n    opacity: 1;\n\n    /* 简化过渡属性 */\n    transition:\n        width 0.3s ease,\n        height 0.3s ease,\n        opacity 0.3s ease,\n        transform 0.3s ease;\n}\n\n.console-logger-window.maximized {\n    width: 600px !important;\n    height: 85vh !important;\n    border-radius: 10px 0 0 10px; /* 调整圆角以匹配右下角 */\n}\n\n.console-logger-window.collapsed {\n    height: 0 !important;\n    min-height: 0 !important;\n    opacity: 0;\n}\n\n.console-logger-header {\n    background: #2c3e50;\n    color: white;\n    padding: 12px 15px;\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    flex-shrink: 0;\n}\n\n.console-logger-title {\n    font-weight: 600;\n    font-size: 16px;\n}\n\n.console-logger-controls {\n    display: flex;\n    gap: 10px;\n}\n\n.console-logger-controls button {\n    background: transparent;\n    border: 1px solid rgb(255, 255, 255, 0.3);\n    padding: 5px 10px;\n    font-size: 12px;\n    color: white;\n    border-radius: 4px;\n    cursor: pointer;\n    transition: background 0.3s;\n}\n\n.console-logger-controls button:hover {\n    background: rgb(255, 255, 255, 0.1);\n}\n\n/* 新增的按钮样式 */\n.console-logger-maximize-toggle {\n    line-height: 1;\n    font-size: 14px !important; /* 使箭头看起来更大 */\n    padding: 5px 8px !important;\n}\n\n.console-logger-maximize-toggle::before {\n    content: '⇱'; /* Unicode symbol for maximized */\n}\n\n.console-logger-maximize-toggle.active::before {\n    content: '⇲'; /* Unicode symbol for minimized */\n}\n\n.console-logger-filters {\n    display: flex;\n    align-items: center;\n    gap: 5px;\n    padding: 10px;\n    background: #f8f9fa;\n    border-bottom: 1px solid #e9ecef;\n    flex-shrink: 0;\n    overflow-x: hidden;\n}\n\n/* 新增: 过滤器按钮组的容器,负责滚动 */\n.console-logger-filter-group {\n    display: flex;\n    gap: 5px;\n    overflow-x: auto; /* 允许过滤器按钮滚动 */\n    flex-grow: 1; /* 占据剩余空间 */\n    padding-right: 10px; /* 避免滚动条影响按钮 */\n}\n\n.console-logger-filter {\n    padding: 5px 10px;\n    font-size: 12px;\n    border-radius: 15px;\n    background: #ecf0f1;\n    color: #7f8c8d;\n    border: 1px solid #ddd;\n    cursor: pointer;\n    transition: background-color 0.3s, color 0.3s, border-color 0.3s;\n    white-space: nowrap;\n    flex-shrink: 0; /* 确保不被压缩 */\n}\n\n.console-logger-filter.active {\n    background: #3498db;\n    color: white;\n    border-color: #3498db;\n}\n\n/* 新增: 滚动到底部按钮的样式 (位于 filtersContainer 内部右侧) */\n.console-logger-scroll-to-bottom {\n    background: #3498db;\n    border: none;\n    padding: 5px 10px;\n    font-size: 12px;\n    color: white;\n    border-radius: 4px;\n    cursor: pointer;\n    transition: background 0.3s;\n    line-height: 1;\n    height: fit-content;\n    white-space: nowrap;\n    margin-left: auto; /* 将按钮推到最右侧 */\n    flex-shrink: 0; /* 确保不被压缩 */\n}\n\n.console-logger-scroll-to-bottom:hover {\n    background: #2980b9;\n}\n\n.console-logger-content {\n    flex: 1;\n    overflow-y: auto;\n    padding: 10px;\n    background: #fff;\n    overflow-wrap: break-word;\n    text-align: left;\n}\n\n.console-logger-entry {\n    padding: 8px 10px;\n    margin-bottom: 3px;\n    border-radius: 4px;\n    font-size: 12px;\n    line-height: 1.4;\n\n    /* animation: consoleFadeIn 0.3s ease; */\n    border-left: 3px solid transparent;\n}\n\n@keyframes consoleFadeIn {\n    from {\n        opacity: 0;\n        transform: translateY(5px);\n    }\n\n    to {\n        opacity: 1;\n        transform: translateY(0);\n    }\n}\n\n.console-logger-timestamp {\n    color: #7f8c8d;\n    font-size: 11px;\n    margin-right: 2px;\n}\n\n@media (width <= 768px) {\n    .console-logger-container {\n        right: 10px;\n        bottom: 10px;\n    }\n\n    .console-logger-window {\n        width: calc(100vw - 20px);\n        height: 300px;\n    }\n}\n\n.console-logger-message[data-type='json'] {\n    white-space: pre-wrap;\n}\n";
	var javdb_site_default = "/* __HIDENAV2__ */\n\n.navbar {\n    z-index: 12345679 !important;\n    padding: 0 0;\n}\n\n.navbar-link:not(.is-arrowless) {\n    padding-right: 33px;\n}\n\n.sub-header,\n    /*#search-bar-container, !*搜索框*!*/\n    #footer,\n    /*.search-recent-keywords, !*搜索框底部热搜词条*!*/\n    .app-desktop-banner,\n    div[data-controller=\"movie-tab\"] .tabs,\n    h3.main-title,\n    div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(3), /* 相关清单*/\n    div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(2), /* 短评按钮*/\n    div.video-detail > div:nth-child(4) > div > div.tabs.no-bottom > ul > li:nth-child(1), /*磁力面板 按钮*/\n    .top-meta,\n    .float-buttons {\n    display: none !important;\n}\n\ndiv.tabs.no-bottom,\n.tabs ul {\n    border-bottom: none !important;\n}\n\n/* 视频列表项 相对相对 方便标签绝对定位 */\n.movie-list .item {\n    position: relative !important;\n}\n\n.video-title {\n    white-space: normal !important;\n    height: 80px; /* 固定高度 容器就不会出现高低不一 */\n    display: -webkit-box; /* 必须设置,使接下来的属性生效 */\n    -webkit-box-orient: vertical; /* 垂直方向堆叠行 */\n    -webkit-line-clamp: 3; /* 设置文本最多显示的行数 */\n    line-clamp: 3;\n}\n\n/* 列表页顶部分类自适应 */\n.main-tabs,\n.tabs {\n    overflow-x: hidden;\n    flex-wrap: wrap;\n    justify-content: flex-start;\n}\n\n.main-tabs ul,\n.tabs ul {\n    flex-wrap: wrap;\n    flex-grow: 0;\n}\n\n/* 二级工具栏 大小封面,可播放,含磁链... */\n.toolbar {\n    display: flex;\n}\n";
	var common_toolbar_default = "/* 全局通用样式 */\n.fr-btn {\n    float: right;\n    margin-left: 4px !important;\n}\n\n.menu-box {\n    position: fixed;\n    right: 10px;\n    top: 50%;\n    transform: translateY(-50%);\n    display: flex;\n    flex-direction: column;\n    z-index: 1000;\n    gap: 6px;\n}\n\n.jhs-toolbar-menu-btn {\n    display: inline-block;\n    min-width: 80px;\n    padding: 7px 12px;\n    border-radius: 4px;\n    color: white !important;\n    text-decoration: none;\n    font-weight: bold;\n    font-size: 12px;\n    text-align: center;\n    cursor: pointer;\n    transition: transform 0.3s ease, box-shadow 0.3s ease, opacity 0.3s ease;\n    box-shadow: 0 2px 5px rgb(0, 0, 0, 0.1);\n    text-shadow: 0 1px 1px rgb(0, 0, 0, 0.2);\n    border: none;\n    line-height: 1.3;\n    margin: 0;\n}\n\n.jhs-toolbar-menu-btn:hover {\n    transform: translateY(-1px);\n    box-shadow: 0 3px 6px rgb(0, 0, 0, 0.15);\n    opacity: 0.9;\n}\n\n.jhs-toolbar-menu-btn:active {\n    transform: translateY(0);\n    box-shadow: 0 1px 2px rgb(0, 0, 0, 0.1);\n}\n\n.do-hide {\n    display: none !important;\n}\n\n.main-tab-btn {\n    border-bottom: none !important;\n    border-radius: 3px !important;\n    height: 30px;\n    margin-left: 5px !important;\n}\n\n.jhs-icon {\n    width: 16px;\n    height: 16px;\n}\n\n/* 表格内按钮溢出,防止被隐藏 */\n.tabulator .tabulator-row .action-cell-dropdown {\n    overflow: visible !important;\n}\n\n/* 去除行内鼠标小手 */\n.tabulator .tabulator-row.tabulator-selectable:hover {\n    cursor: default !important;\n}\n\n/* 排序小箭头颜色 */\n.tabulator .tabulator-col.tabulator-sortable[aria-sort='ascending'] .tabulator-arrow {\n    border-bottom-color: #337ab7 !important;\n}\n\n.tabulator .tabulator-col.tabulator-sortable[aria-sort='descending'] .tabulator-arrow {\n    border-top-color: #337ab7 !important;\n}\n\n/* 针对折叠行的容器或内容进行样式修改 */\n.tabulator-responsive-collapse {\n    border-top: none !important;\n}\n\n.tabulator-responsive-collapse table {\n    margin-left: 50px !important;\n}\n\n.tabulator-cell {\n    height: auto !important;\n}\n\n/* 列允许换行,去除省略号 */\n.tabulator .tabulator-cell {\n    white-space: normal !important;\n    text-overflow: clip !important;\n}\n\n.tabulator-tableholder {\n    overflow-x: hidden !important;\n}\n\n/*\n * Toastify 宽度修复:toastify-js 源 CSS 中 .toastify-center 有两行\n *   max-width: fit-content;\n *   max-width: -moz-fit-content;\n * lightningcss 压缩时删除了标准 fit-content 只留 -moz-fit-content(Firefox\n * 前缀),Chrome 不认 -moz- 前缀致 max-width 失效,toast 退回 .toastify 的\n * calc(50% - 20px) 变成超宽(~937px)。此处用 !important 强制 fit-content\n * 覆盖,恢复 toast 自适应内容宽度。详见 doc/32-css-layout-fix.md。\n */\n.toastify-center {\n    max-width: fit-content !important;\n}\n\n/* __SCROLLBAR__ */\n";
	var a_normal_buttons_default = ".a-normal, /* 白色 */\n    .a-primary, /* 浅蓝色 */\n    .a-success, /* 浅绿色 */\n    .a-danger, /* 浅粉色 */\n    .a-warning, /* 浅橙色 */\n    .a-info /* 灰色 */ {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    padding: 6px 14px;\n    margin-right: 10px;\n    border-radius: 6px;\n    text-decoration: none;\n    font-size: 13px;\n    font-weight: 500;\n    transition: background-color 0.2s ease;\n    cursor: pointer;\n    border: 1px solid rgb(0, 0, 0, 0.08);\n    white-space: nowrap;\n}\n\n.a-primary {\n    background: #e0f2fe;\n    color: #0369a1;\n    border-color: #bae6fd;\n}\n\n.a-primary:hover {\n    background: #bae6fd;\n}\n\n.a-success {\n    background: #dcfce7;\n    color: #166534;\n    border-color: #bbf7d0;\n}\n\n.a-success:hover {\n    background: #bbf7d0;\n}\n\n.a-danger {\n    background: #fee2e2;\n    color: #b91c1c;\n    border-color: #fecaca;\n}\n\n.a-danger:hover {\n    background: #fecaca;\n}\n\n.a-warning {\n    background: #ffedd5;\n    color: #9a3412;\n    border-color: #fed7aa;\n}\n\n.a-warning:hover {\n    background: #fed7aa;\n}\n\n.a-info {\n    background: #e2e8f0;\n    color: #334155;\n    border-color: #cbd5e1;\n}\n\n.a-info:hover {\n    background: #cbd5e1;\n}\n\n.a-normal {\n    background: transparent;\n    color: #64748b;\n    border-color: #cbd5e1;\n}\n\n.a-normal:hover {\n    background: #f8fafc;\n}\n";
	var accessibility_default = "/* 无障碍基础样式(doc/145 批次 5 基础) */\n\n/* focus-visible:键盘导航时显示焦点环,鼠标点击时不显示 */\n:focus-visible {\n    outline: 2px solid #5d87c2;\n    outline-offset: 2px;\n}\n\n/* 交互元素的焦点样式 */\nbutton:focus-visible,\na:focus-visible,\ninput:focus-visible,\nselect:focus-visible,\ntextarea:focus-visible,\n[tabindex]:focus-visible {\n    outline: 2px solid #5d87c2;\n    outline-offset: 2px;\n}\n\n/* 减少动态效果:尊重用户系统偏好 */\n@media (prefers-reduced-motion: reduce) {\n    *,\n    *::before,\n    *::after {\n        animation-duration: 0.01ms !important;\n        animation-iteration-count: 1 !important;\n        transition-duration: 0.01ms !important;\n        scroll-behavior: auto !important;\n    }\n}\n";
	var design_tokens_default = "/* JavDB Power Tools 设计令牌(doc/147 批次 5 基础) */\n\n/* 作用域:.jhs-ui 或全局 :root,供所有插件 CSS 引用 */\n\n:root {\n    /* 主色 */\n    --jhs-color-primary: #5d87c2;\n    --jhs-color-primary-hover: #4a73b0;\n    --jhs-color-primary-light: #e8eef6;\n\n    /* 语义色 */\n    --jhs-color-success: #64bb69;\n    --jhs-color-warning: #d7a80c;\n    --jhs-color-error: #de3333;\n    --jhs-color-info: #25b1dc;\n\n    /* 中性色 */\n    --jhs-color-text: #363636;\n    --jhs-color-text-secondary: #6c757d;\n    --jhs-color-text-muted: #999;\n    --jhs-color-border: #e2e8f0;\n    --jhs-color-bg: #fff;\n    --jhs-color-bg-secondary: #fbfcfd;\n    --jhs-color-bg-hover: #f5f5f5;\n\n    /* 间距 */\n    --jhs-space-xs: 4px;\n    --jhs-space-sm: 8px;\n    --jhs-space-md: 12px;\n    --jhs-space-lg: 16px;\n    --jhs-space-xl: 20px;\n    --jhs-space-2xl: 24px;\n\n    /* 圆角 */\n    --jhs-radius-sm: 4px;\n    --jhs-radius-md: 6px;\n    --jhs-radius-lg: 8px;\n    --jhs-radius-full: 9999px;\n\n    /* 字体 */\n    --jhs-font-size-xs: 11px;\n    --jhs-font-size-sm: 12px;\n    --jhs-font-size-md: 13px;\n    --jhs-font-size-lg: 14px;\n    --jhs-font-size-xl: 16px;\n\n    /* 阴影 */\n    --jhs-shadow-sm: 0 1px 3px rgb(0, 0, 0, 0.08);\n    --jhs-shadow-md: 0 2px 8px rgb(0, 0, 0, 0.12);\n    --jhs-shadow-lg: 0 4px 16px rgb(0, 0, 0, 0.16);\n\n    /* z-index 层级(layer.js z-index 无上限递增,above-layer 层需 genuinely large 常量) */\n    --jhs-z-dropdown: 100;\n    --jhs-z-sticky: 200;\n    --jhs-z-page: 9999;\n    --jhs-z-top: 999999999;\n\n    /* 过渡 */\n    --jhs-transition-fast: 150ms ease;\n    --jhs-transition-normal: 250ms ease;\n\n    /* 触控目标最小尺寸 */\n    --jhs-touch-target: 44px;\n}\n";
	var filter_chip_base_default = "/**\n * 筛选栏 + 芯片共享基础样式 —— status-tag-filter / video-lists-tag / preload-status-badge\n * 三个插件的筛选栏布局与芯片基础样式逐字节相同,此处以分组选择器统一,\n * 各插件 CSS 仅保留 active 配色与 no-tag 变体。\n *\n * 注入方式:main.tsx 顶层 injectCss(始终注入,与 design-tokens.css 同级)。\n */\n\n/* ---------- 筛选栏容器 ---------- */\n.status-tag-filter-bar,\n.jhs-vlt-filter-bar,\n.preload-filter-bar {\n    display: flex;\n    align-items: flex-start;\n    gap: 8px;\n    padding: 8px 0 12px 0;\n    border-bottom: 1px solid #e9ecef;\n}\n\n/* ---------- 筛选栏标签 ---------- */\n.status-tag-filter-label,\n.jhs-vlt-filter-label,\n.preload-filter-label {\n    flex-shrink: 0;\n    font-size: 0.8em;\n    font-weight: 600;\n    color: #6c757d;\n    line-height: 1.8;\n    margin-right: 4px;\n}\n\n/* ---------- 芯片容器 ---------- */\n.status-tag-filter-chips,\n.jhs-vlt-filter-chips,\n.preload-filter-chips {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 6px;\n}\n\n/* ---------- 芯片基础 ---------- */\n.status-tag-filter-chip,\n.jhs-vlt-filter-chip,\n.preload-filter-chip {\n    display: inline-block;\n    padding: 0.25em 0.7em;\n    font-size: 0.75em;\n    font-weight: 600;\n    line-height: 1.5;\n    border-radius: 50rem;\n    cursor: pointer;\n    user-select: none;\n    border: 1.5px solid #dee2e6;\n    background: #fff;\n    color: #495057;\n    transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;\n}\n\n/* ---------- 芯片悬停 ---------- */\n.status-tag-filter-chip:hover,\n.jhs-vlt-filter-chip:hover,\n.preload-filter-chip:hover {\n    border-color: #adb5bd;\n    background: #f8f9fa;\n}\n";
	var javdbHideNavCss = "";
	if (window.location.href.includes("hideNav=1")) javdbHideNavCss = "\n        .main-nav,#search-bar-container {\n            display: none !important;\n        }\n        \n        html {\n            padding-top:0px!important;\n        }\n    ";
	var javdbSiteCss = javdb_site_default.replace("/*__HIDENAV2__*/", javdbHideNavCss);
	function generateScrollbarCss() {
		const scrollbarSelectors = [
			".jhs-scrollbar",
			".content-panel",
			".tabulator-tableholder",
			".has-navbar-fixed-top",
			".layui-layer-content"
		];
		const appendPseudo = (selectors, pseudo) => selectors.map((selector) => `${selector}${pseudo}`).join(",");
		return `\n    ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar")}{width:6px;height:6px;}\n    ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar-track")}{background:#f1f1f1;border-radius:10px;}\n    ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar-thumb")}{background:#888;border-radius:10px;}\n    ${appendPseudo(scrollbarSelectors, "::-webkit-scrollbar-thumb:hover")}{background:#555;}\n    `.trim().replace(/\n/g, "");
	}
	var commonToolbarCss = common_toolbar_default.replace("/*__SCROLLBAR__*/", generateScrollbarCss());
	if (isJavdbSite) injectCss(javdbSiteCss);
	injectCss(a_normal_buttons_default);
	injectCss(commonToolbarCss);
	injectCss(accessibility_default);
	injectCss(design_tokens_default);
	injectCss(filter_chip_base_default);
	window.utils = new CommonUtil();
	window.gmHttp = new GmHttp();
	window.storageManager = new StorageManager();
	window.loadGfriends = loadGfriends;
	window.filetreeDb = filetreeDb;
	window.WebDavClient = WebDavClient;
	var refreshChannel = new BroadcastChannel("channel-refresh");
	window.refresh = function() {
		refreshChannel.postMessage({ type: "refresh" });
	};
	window.cleanCache_filter_actor_actress_car_list = function() {
		refreshChannel.postMessage({ type: "cleanCache_filter_actor_actress_car_list" });
	};
	window.clean_cacheSettingObj = function() {
		refreshChannel.postMessage({ type: "clean_cacheSettingObj" });
	};
	injectCss(loading_default);
	window.loading = createLoading;
	window.show = show$1;
	(function() {
		function resetOverflow(delay = 10) {
			setTimeout(() => {
				const shadeCount = document.querySelectorAll(".layui-layer-shade").length;
				document.documentElement.style.overflow = shadeCount > 0 ? "hidden" : "";
			}, delay);
		}
		injectCss(viewer_default);
		window.showImageViewer = function(src, alt = "") {
			let container;
			let isTemporary = false;
			if (typeof src == "string" || src instanceof String) {
				container = $(jsxToString((0, import_jsx_runtime.jsx)(TemporaryImageContainer, {
					src: String(src),
					alt
				}))).appendTo("body");
				isTemporary = true;
			} else container = $(src);
			const viewerRef = { current: null };
			const viewerOptions = VIEWER_CONFIG({
				container,
				isTemporary,
				resetOverflow,
				viewerRef
			});
			viewerRef.current = new Viewer(container[0], viewerOptions);
			viewerRef.current.show();
		};
	})();
	(async function() {
		injectCss(logger_default);
		try {
			if (unsafeWindow.parent.clog && typeof unsafeWindow.parent.clog.log == "function") window.clog = unsafeWindow.parent.clog;
			else window.clog = new Logger();
		} catch (err) {
			console.error("创建日志控制台出现异常", err);
			window.clog = new Logger();
		}
		(function() {
			const logger = window.clog || console;
			window.addEventListener("error", function(event) {
				const filename = event.filename;
				const message = event.message;
				if (!filename.includes("javdb")) logger.error(`[全局 Error 异常捕获] ${message} 来源: ${filename}`);
			});
			window.addEventListener("unhandledrejection", function(event) {
				const reason = event.reason;
				const reasonMessage = (reason == null ? void 0 : reason.message) ?? "";
				if (reasonMessage.includes("play()")) return;
				if (reasonMessage.includes("The element has no supported sources")) {
					show$1.error("播放失败, 请检查是否已对节点分流?");
					logger.error("播放失败, 请检查是否已对节点分流?");
					return;
				}
				if (reasonMessage.includes("<span>1005</span>") && reasonMessage.includes("fc2ppvdb")) return;
				const logMessage = `[全局 Promise 异常捕获] ${reason.message || reason}`;
				logger.error(logMessage, reason);
				event.preventDefault();
			});
		})();
		document.addEventListener("mousedown", (event) => {
			const clog = window.clog;
			if (!clog.isInitialized || !clog.container) return;
			const target = event.target;
			const loggerSelectors = [
				".console-logger-container",
				".layui-layer-shade",
				".loading-container"
			].join(",");
			if (target.closest(loggerSelectors)) clog.highZIndex();
			else clog.lowZIndex();
		});
	})();
	setupTooltip();
	window.encryptCredential = encryptCredential;
	window.decryptCredential = decryptCredential;
	setupLayerWrapper();
	var pluginManager$1 = (function() {
		const manager = new PluginManager();
		if (isJavdbSite) {
			manager.register(ListPagePlugin);
			manager.register(AutoPagePlugin);
			manager.register(FoldCategoryPlugin);
			manager.register(ListPageButtonPlugin);
			manager.register(HistoryPlugin);
			manager.register(SettingPlugin);
			manager.register(NavBarPlugin);
			manager.register(HitShowPlugin);
			manager.register(Top250Plugin);
			manager.register(DetailPagePlugin);
			manager.register(ReviewPlugin);
			manager.register(DetailPageButtonPlugin);
			manager.register(HighlightMagnetPlugin);
			manager.register(PreviewVideoPlugin);
			manager.register(ActressInfoPlugin);
			manager.register(OtherSitePlugin);
			manager.register(WantAndWatchedVideosPlugin);
			manager.register(RelatedPlugin);
			manager.register(BlacklistPlugin);
			manager.register(FavoriteActressesPlugin);
			manager.register(NewVideoPlugin);
			manager.register(RatingDisplayPlugin);
			manager.register(Fc2Plugin);
			manager.register(KeyPageTurningPlugin);
			manager.register(ModMyListOpenWayPlugin);
			manager.register(PageSortPlugin);
			manager.register(StatusTagFilterPlugin);
			manager.register(ListWaterfallPlugin);
			manager.register(ListReadingStatusPlugin);
			manager.register(ModalListDisablerPlugin);
			manager.register(VideoListsTagPlugin);
			manager.register(CarListReaderPlugin);
			manager.register(VisitHistoryPlugin);
			if (featureFlags.translatePlugin) manager.register(TranslatePlugin, "translatePlugin");
			if (featureFlags.screenShotPlugin) manager.register(ScreenShotPlugin, "screenShotPlugin");
			if (featureFlags.magnetHubPlugin) manager.register(MagnetHubPlugin, "magnetHubPlugin");
			if (featureFlags.imageRecognitionPlugin) manager.register(ImageRecognitionPlugin, "imageRecognitionPlugin");
			if (featureFlags.fc2By123AvPlugin) manager.register(Fc2By123AvPlugin, "fc2By123AvPlugin");
		}
		if (isMissavSite) {
			manager.register(MissavStatusTagPlugin);
			manager.register(MissavQuickCopyPlugin);
		}
		return manager;
	})();
	(async function() {
		const ctx = initPageContext();
		window.isDetailPage = ctx.isDetailPage;
		window.isListPage = ctx.isListPage;
		window.isFc2Page = ctx.isFc2Page;
		await pluginManager$1.processCss();
		if (isJavdbSite) await storageManager.runMigrations();
		storageRevision.init();
		storageRevision.onRemoteChange(() => {
			storageManager.clearCarListCache();
			storageManager.clearSettingCache();
			storageManager.clearFilterActorActressCarListCache();
		});
		if (isJavdbSite && /(^|;)\s*locale\s*=\s*en\s*($|;)/i.test(document.cookie)) show$1.error("请切换到中文语言下才可正常使用本脚本", { duration: -1 });
		await pluginManager$1.processPlugins();
		if (isJavdbSite) {
			const settingPlugin = pluginManager$1.getBean("SettingPlugin");
			if (settingPlugin) settingPlugin.autoBackup().catch((err) => window.clog.error("自动备份失败", err));
		}
		registerDiagnosticsMenu(pluginManager$1);
		window.addEventListener("beforeunload", () => pluginManager$1.destroyAll());
	})();
})();