JavDB Power Tools

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

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu betiği yüklemek için bir betik yöneticisi eklentisi yüklemeniz gerekecektir.

(Zaten bir betik yöneticim var, hadi yükleyelim!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

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