JavDB Power Tools

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

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey, Greasemonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

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

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

Advertisement:

// ==UserScript==
// @name         JavDB Power Tools
// @namespace    zerobiubiu.top
// @version      1.2.0
// @author       zerobiubiu
// @description  JavDB/MissAV 双站增强工具箱:收藏管理、状态标签、屏蔽过滤、跨站同步、热播/Top250榜单、新作品检测、预告片、字幕搜索、WebDav云备份、演员信息、清单管理、快捷键等 36 个功能插件
// @license      MIT
// @icon         https://cdn.jsdelivr.net/gh/zerobiubiu/Figure-bed/b507c13a-9f4e-41b5-bbbb-129d0a21f97d.png
// @homepageURL  https://github.com/zerobiubiu/javdb-tools
// @include      https://javdb*.com/*
// @include      https://missav*.ws/*
// @include      https://missav*.live/*
// @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      *
// @grant        GM_addStyle
// @grant        GM_addValueChangeListener
// @grant        GM_getValue
// @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 = 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(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) {
					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(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) 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) 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) 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 ? 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) {
						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) {
					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(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,
		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) 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(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 ? data : new Row(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) || 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) || 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) 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}");
	var win = window;
	win.layer = import_layer.default;
	win.Tabulator = TabulatorFull$1;
	win.Toastify = import_toastify.default;
	win.localforage = import_localforage.default;
	win.Viewer = import_viewer.default;
	win.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";
	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: rgba(0, 0, 0, 0.1);\n    z-index: 99999999;\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 rgba(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 rgba(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    50% {\n        transform: translateX(-30px);\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: rgba(255, 0, 0, 0.6) !important;\n}\n.viewer-close:hover {\n    background: rgba(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: 99999999;\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 rgba(0, 0, 0, 0.1);\n    transition: all 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 rgba(0, 0, 0, 0.1);\n    display: flex;\n    flex-direction: column;\n    overflow: hidden;\n    transform: translateY(0);\n    opacity: 1;\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 rgba(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: rgba(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.console-logger-maximize-toggle::before {\n    content: '⇱'; /* Unicode symbol for maximized */\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: all 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: #ffffff;\n    word-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    /*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    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 (max-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\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.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: all 0.3s ease;\n    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n    border: none;\n    line-height: 1.3;\n    margin: 0;\n}\n\n.menu-btn:hover {\n    transform: translateY(-1px);\n    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15);\n    opacity: 0.9;\n}\n\n.menu-btn:active {\n    transform: translateY(0);\n    box-shadow: 0 1px 2px rgba(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.tool-box .jhs-icon {\n    width: 1.5rem;\n    height: 1.5rem;\n}\n\n/*表格内按钮溢出,防止被隐藏*/\n.tabulator .tabulator-row .action-cell-dropdown {\n    overflow: visible !important;\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.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: all 0.2s ease;\n    cursor: pointer;\n    border: 1px solid rgba(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 Hotkey = class Hotkey {
		static isMac = navigator.platform.indexOf("Mac") === 0;
		static registerHotKeyMap = new Map();
		static handleKeydown = (event) => {
			for (const [, entry] of Hotkey.registerHotKeyMap) {
				const hotkeyString = entry.hotkeyString;
				const callback = entry.callback;
				if (Hotkey.judgeHotkey(hotkeyString, event)) callback(event);
			}
		};
		static handleKeyup = (event) => {
			for (const [, entry] of Hotkey.registerHotKeyMap) {
				const hotkeyString = entry.hotkeyString;
				const keyupCallback = entry.keyupCallback;
				if (keyupCallback && Hotkey.judgeHotkey(hotkeyString, event)) keyupCallback(event);
			}
		};
		constructor() {
			if (new.target === Hotkey) throw new Error("HotkeyManager cannot be instantiated.");
		}
		static registerHotkey(hotkeyStr, keydownCallback, keyupCallback = null) {
			if (Array.isArray(hotkeyStr)) {
				const ids = [];
				hotkeyStr.forEach((item) => {
					if (!Hotkey.isHotkeyFormat(item)) throw new Error("快捷键格式错误");
					const id = Hotkey.recordHotkey(item, keydownCallback, keyupCallback);
					ids.push(id);
				});
				return ids;
			}
			if (!Hotkey.isHotkeyFormat(hotkeyStr)) throw new Error("快捷键格式错误");
			return Hotkey.recordHotkey(hotkeyStr, keydownCallback, keyupCallback);
		}
		static recordHotkey(hotkeyStr, keydownCallback, keyupCallback) {
			const id = Math.random().toString(36).substr(2);
			Hotkey.registerHotKeyMap.set(id, {
				hotkeyString: hotkeyStr,
				callback: keydownCallback,
				keyupCallback
			});
			return id;
		}
		static unregisterHotkey(id) {
			if (Hotkey.registerHotKeyMap.has(id)) Hotkey.registerHotKeyMap.delete(id);
		}
		static isHotkeyFormat(hotkeyStr) {
			return hotkeyStr.toLowerCase().split("+").map((item) => item.trim()).every((item) => [
				"ctrl",
				"shift",
				"alt"
			].includes(item) || item.length === 1);
		}
		static judgeHotkey(hotkeyStr, event) {
			const parts = hotkeyStr.toLowerCase().split("+").map((item) => item.trim());
			const withCtrl = parts.includes("ctrl");
			const withShift = parts.includes("shift");
			const withAlt = parts.includes("alt");
			const mainKey = parts.find((item) => item !== "ctrl" && item !== "shift" && item !== "alt");
			return (Hotkey.isMac ? event.metaKey : event.ctrlKey) === withCtrl && event.shiftKey === withShift && event.altKey === withAlt && event.key.toLowerCase() === mainKey;
		}
	};
	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";
	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) {
		const loadingHandle = loading();
		try {
			await ensureFiletreeLoaded();
		} catch (error) {
			show.error(error);
			return [];
		} finally {
			loadingHandle.close();
		}
		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 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 backup(folder, filename, content) {
			await this._sendRequest("MKCOL", 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._sendRequest("MKCOL", 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)
	};
	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 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="${String(value)}"`);
				continue;
			}
			if (key === "style") {
				if (typeof value === "string") parts.push(`style="${value}"`);
				else if (typeof value === "object" && value !== null) {
					const css = styleToCss(value);
					if (css) parts.push(`style="${css}"`);
				}
				continue;
			}
			if (value === true) {
				parts.push(key);
				continue;
			}
			parts.push(`${key}="${String(value)}"`);
		}
		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();
	}))();
	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 INDENT_BEFORE = "\n                ";
	var INDENT_BETWEEN = "\n                ";
	var INDENT_AFTER = "\n            ";
	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,
				dangerouslySetInnerHTML: { __html: 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";
	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() {
			this.createContainer();
			this.bindEvents();
			this.checkInitialMaximizeState();
			this.checkInitialCollapseState();
		}
		createContainer() {
			this.container = document.createElement("div");
			this.container.className = "console-logger-container";
			this.container.style.display = "none";
			this.toggleBtn = document.createElement("div");
			this.toggleBtn.className = "console-logger-toggle collapsed";
			this.container.appendChild(this.toggleBtn);
			this.window = document.createElement("div");
			this.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";
			this.maximizeBtn = document.createElement("button");
			this.maximizeBtn.textContent = "";
			this.maximizeBtn.classList.add("console-logger-maximize-toggle");
			controls.appendChild(this.maximizeBtn);
			const clearBtn = document.createElement("button");
			clearBtn.textContent = "清空";
			clearBtn.addEventListener("click", () => this.clear());
			controls.appendChild(clearBtn);
			header.appendChild(title);
			header.appendChild(controls);
			this.filtersContainer = document.createElement("div");
			this.filtersContainer.className = "console-logger-filters";
			this.filterButtonGroup = document.createElement("div");
			this.filterButtonGroup.className = "console-logger-filter-group";
			this.filtersContainer.appendChild(this.filterButtonGroup);
			this.scrollToBottomBtn = document.createElement("button");
			this.scrollToBottomBtn.className = "console-logger-scroll-to-bottom";
			this.scrollToBottomBtn.textContent = "到底部";
			this.filtersContainer.appendChild(this.scrollToBottomBtn);
			this.content = document.createElement("div");
			this.content.className = "console-logger-content jhs-scrollbar";
			this.window.appendChild(header);
			this.window.appendChild(this.filtersContainer);
			this.window.appendChild(this.content);
			this.container.appendChild(this.window);
			document.body.appendChild(this.container);
			Object.keys(LOG_TYPE_STYLES).forEach((typeName) => {
				const filterBtn = document.createElement("div");
				filterBtn.className = "console-logger-filter";
				if (typeName === this.currentFilter) filterBtn.classList.add("active");
				filterBtn.textContent = LOG_TYPE_STYLES[typeName].label;
				filterBtn.dataset.type = typeName;
				filterBtn.addEventListener("click", () => this.setFilter(typeName));
				this.filterButtonGroup.appendChild(filterBtn);
			});
		}
		bindEvents() {
			this.toggleBtn.addEventListener("click", () => {
				this.toggleExpandCollapsed();
			});
			this.maximizeBtn.addEventListener("click", () => this.toggleMaximize());
			this.scrollToBottomBtn.addEventListener("click", () => {
				this.content.scrollTop = this.content.scrollHeight;
				this.userScrolledUp = false;
			});
			this.content.addEventListener("scroll", () => {
				const atBottom = this.content.scrollHeight - this.content.clientHeight <= this.content.scrollTop + 5;
				this.userScrolledUp = !atBottom;
			});
			this.content.addEventListener("wheel", (evt) => {
				const atTop = this.content.scrollTop === 0;
				const atBottom = this.content.scrollHeight - this.content.clientHeight <= this.content.scrollTop + 1;
				if (atTop && evt.deltaY < 0 || atBottom && evt.deltaY > 0) {
					evt.preventDefault();
					evt.stopPropagation();
				}
			}, { passive: false });
		}
		toggleExpandCollapsed() {
			const isCollapsed = this.window.classList.toggle("collapsed");
			this.toggleBtn.classList.toggle("collapsed");
			if (isCollapsed) localStorage.setItem(EXPAND_KEY, "no");
			else {
				localStorage.setItem(EXPAND_KEY, "yes");
				this.reRenderAllLogs();
			}
		}
		checkInitialCollapseState() {
			const stored = localStorage.getItem(EXPAND_KEY);
			if (stored && stored !== "no") {
				this.window.classList.toggle("collapsed");
				this.toggleBtn.classList.toggle("collapsed");
				setTimeout(() => {
					this.content.scrollTop = this.content.scrollHeight;
				}, 0);
			} else {
				this.window.classList.add("collapsed");
				this.toggleBtn.classList.add("collapsed");
			}
		}
		checkInitialMaximizeState() {
			if (localStorage.getItem(MAXIMIZE_KEY) === "maximized") {
				this.window.classList.add("maximized");
				this.maximizeBtn.classList.add("active");
			}
		}
		toggleMaximize() {
			const isMaximized = this.window.classList.toggle("maximized");
			this.maximizeBtn.classList.toggle("active", isMaximized);
			if (isMaximized) localStorage.setItem(MAXIMIZE_KEY, "maximized");
			else localStorage.setItem(MAXIMIZE_KEY, "minimized");
			if (!this.window.classList.contains("collapsed")) this.content.scrollTop = this.content.scrollHeight;
		}
		addLog(message, typeArg = "base", ...extraArgs) {
			if (!this.maxLogCountInitialized) {
				this.maxLogCountInitialized = true;
				storageManager.getSetting("clogMsgCount", 2e3).then((v) => {
					this.maxLogCount = v;
				});
			}
			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("<br/>" + JSON.stringify(part, null, 2));
					messageType = "json";
				} catch {
					parts.push(String(part));
					messageType = "msg";
				}
				else parts.push(String(part));
			});
			let formattedMessage = parts.join("  ");
			formattedMessage = formattedMessage.replace(/(?:(?:https?|ftp):\/\/|www\.|(?:\/\/))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]/gi, (match) => {
				const isHttpOrFtp = match.startsWith("http") || match.startsWith("ftp");
				const isProtocolRelative = match.startsWith("//");
				const isWww = match.startsWith("www.");
				let href = match;
				if (isProtocolRelative) href = `http:${match}`;
				else if (!isHttpOrFtp && isWww) href = `http://${match}`;
				return `<a href="${href}" target="_blank">${match}</a>`;
			});
			const entry = {
				message: formattedMessage,
				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) this.renderLog(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);
		}
		renderLog(entry) {
			if (this.container.style.display === "none") return;
			if (this.window.classList.contains("collapsed")) return;
			if (!(FILTER_TYPE_MAP[this.currentFilter] || []).includes(entry.type)) return;
			const el = this._createLogElement(entry);
			this.content.appendChild(el);
			if (!this.window.classList.contains("collapsed") && !this.userScrolledUp) this.content.scrollTop = this.content.scrollHeight;
		}
		reRenderAllLogs() {
			if (this.container.style.display !== "none") {
				if (!this.window.classList.contains("collapsed")) setTimeout(() => {
					this.content.innerHTML = "";
					if (this.logs.length === 0) return;
					const filterTypes = FILTER_TYPE_MAP[this.currentFilter] || [];
					const fragment = document.createDocumentFragment();
					this.logs.forEach((entry) => {
						if (filterTypes.includes(entry.type)) {
							const el = this._createLogElement(entry);
							fragment.appendChild(el);
						}
					});
					this.content.appendChild(fragment);
					this.content.scrollTop = this.content.scrollHeight;
				}, 0);
			}
		}
		_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;
		}
		setFilter(filterType) {
			if (this.currentFilter === filterType) return;
			this.currentFilter = filterType;
			localStorage.setItem(FILTER_KEY, filterType);
			this.filterButtonGroup.querySelectorAll(".console-logger-filter").forEach((btn) => {
				if (btn.dataset.type === filterType) btn.classList.add("active");
				else btn.classList.remove("active");
			});
			this.reRenderAllLogs();
		}
		clear() {
			this.logs = [];
			this.content.innerHTML = "";
		}
		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 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 = "hasDown";
	var UNCENSORED_TAG = "(無碼)";
	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 = localforage.createInstance({
			driver: localforage.INDEXEDDB,
			name: "JAV-JHS",
			version: 1,
			storeName: "appData"
		});
		cache_filter_actor_actress_car_list = null;
		cacheSettingObj = null;
		carListChangeCallback;
		setCarListChangeCallback(cb) {
			this.carListChangeCallback = cb;
		}
		clearFilterActorActressCarListCache() {
			this.cache_filter_actor_actress_car_list = null;
		}
		clearSettingCache() {
			this.cacheSettingObj = null;
		}
		constructor() {
			if (StorageManager.instance) throw new Error("StorageManager已被实例化过了!");
			StorageManager.instance = this;
		}
		async getCarList() {
			return await this.forage.getItem(this.car_list_key) || [];
		}
		async getCar(carNum) {
			return (await this.getCarList()).find((car) => car.carNum === carNum);
		}
		_saveSingleCar(input, list) {
			let { carNum, url, names, actionType, publishTime, starId, score } = input;
			if (!carNum) {
				show.error("番号为空!");
				throw new Error("番号为空!");
			}
			if (!url) {
				show.error("url为空!");
				throw new Error("url为空!");
			}
			if (!url.includes("http")) url = window.location.origin + url;
			if (names) names = names.trim();
			let car = 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") {
						const msg = `${carNum} 已在屏蔽列表中`;
						show.error(msg);
						throw new Error(msg);
					}
					car.status = FILTER_ACTION;
					break;
				case FAVORITE_ACTION:
					if (car.status === "favorite") {
						const msg = `${carNum} 已在收藏列表中`;
						show.error(msg);
						throw new Error(msg);
					}
					car.status = FAVORITE_ACTION;
					break;
				case HAS_DOWN_STATUS:
					car.status = HAS_DOWN_STATUS;
					break;
				case HAS_WATCH_ACTION:
					car.status = HAS_WATCH_ACTION;
					break;
				default: {
					const msg = "actionType错误, 请联系作者更正: " + actionType;
					show.error(msg);
					throw new Error(msg);
				}
			}
		}
		async saveCar(input) {
			const list = await this.forage.getItem(this.car_list_key) || [];
			this._saveSingleCar(input, list);
			await this.forage.setItem(this.car_list_key, list);
			await this.removeNewVideoList([input.carNum]);
			const car = list.find((c) => c.carNum === input.carNum);
			if (car) this.carListChangeCallback?.({
				action: "upsert",
				upserts: [car]
			});
		}
		async updateCarInfo(input) {
			let { carNum, url, names, actionType, remark } = input;
			if (!carNum) {
				show.error("番号为空!");
				throw new Error("番号为空!");
			}
			if (!url) {
				show.error("url为空!");
				throw new Error("url为空!");
			}
			if (names) names = names.trim();
			const list = await this.forage.getItem(this.car_list_key) || [];
			const car = list.find((item) => item.carNum === carNum);
			if (!car) {
				const msg = "数据不存在: " + carNum;
				show.error(msg);
				throw new Error(msg);
			}
			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: {
					const msg = "actionType错误, 请联系作者更正: " + actionType;
					show.error(msg);
					throw new Error(msg);
				}
			}
			await this.forage.setItem(this.car_list_key, list);
			this.carListChangeCallback?.({
				action: "upsert",
				upserts: [car]
			});
		}
		async saveCarList(inputs) {
			if (!inputs || !Array.isArray(inputs) || inputs.length === 0) {
				show.error("记录列表为空!");
				throw new Error("记录列表为空!");
			}
			const list = await this.forage.getItem(this.car_list_key) || [];
			for (const item of inputs) try {
				this._saveSingleCar(item, list);
			} catch (err) {
				throw err;
			}
			await this.forage.setItem(this.car_list_key, list);
			const numSet = new Set(inputs.map((i) => i.carNum));
			const upserts = list.filter((c) => numSet.has(c.carNum));
			if (upserts.length > 0) this.carListChangeCallback?.({
				action: "upsert",
				upserts
			});
		}
		async removeNewVideoList(carNums) {
			const actressList = await this.getFavoriteActressList();
			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 this.forage.setItem(this.favorite_actresses_key, updated);
		}
		async removeCar(carNum) {
			const list = await this.getCarList();
			const beforeLen = list.length;
			const filtered = list.filter((item) => item.carNum !== carNum);
			if (filtered.length === beforeLen) {
				show.error(`${carNum} 不存在`);
				return false;
			} else {
				await this.forage.setItem(this.car_list_key, filtered);
				this.carListChangeCallback?.({
					action: "delete",
					deletes: [carNum]
				});
				return true;
			}
		}
		async batchRemoveCars(carNums) {
			const list = await this.getCarList();
			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 this.forage.setItem(this.car_list_key, filtered);
			this.carListChangeCallback?.({
				action: "delete",
				deletes: carNums
			});
			return removed;
		}
		async getBlacklist() {
			return await this.forage.getItem(this.blacklist_key) || [];
		}
		async addBlacklistItem(item) {
			let { 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 this.getBlacklist();
			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 this.forage.setItem(this.blacklist_key, list);
		}
		async updateBlacklistItem(item) {
			if (!item || !item.starId) throw new Error("参数不全");
			const list = await this.getBlacklist();
			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 this.forage.setItem(this.blacklist_key, list);
		}
		async deleteBlacklistItem(starId) {
			const list = await this.getBlacklist();
			const filtered = list.filter((entry) => entry.starId !== starId);
			if (list.length !== filtered.length) await this.forage.setItem(this.blacklist_key, filtered);
		}
		async getBlacklistCarList() {
			const cached = this.cache_filter_actor_actress_car_list;
			if (cached && cached.length > 0) return cached;
			const fresh = await this.forage.getItem(this.blacklist_car_list_key) || [];
			this.cache_filter_actor_actress_car_list = fresh;
			return fresh;
		}
		async batchSaveBlacklistCarList(inputs) {
			const list = await this.getBlacklistCarList();
			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)) {
				this._saveSingleCar(item, cloned);
				clog.log(`屏蔽演员番号: <span style="color: #f40">${item.names} ${item.carNum}</span>`);
				changed = true;
				newCarNums.push(item.carNum);
			}
			if (changed) {
				await this.forage.setItem(this.blacklist_car_list_key, cloned);
				await this.removeNewVideoList(newCarNums);
				window.cleanCache_filter_actor_actress_car_list();
			}
		}
		async removeBlacklistCarList(starId) {
			const list = await this.getBlacklistCarList();
			const filtered = list.filter((item) => item.starId !== starId);
			if (filtered.length !== list.length) {
				await this.forage.setItem(this.blacklist_car_list_key, filtered);
				window.cleanCache_filter_actor_actress_car_list();
			}
		}
		async getFavoriteActressList() {
			return await this.forage.getItem(this.favorite_actresses_key) || [];
		}
		async addFavoriteActressList(inputs) {
			const list = await this.getFavoriteActressList();
			let count = 0;
			for (const item of inputs) {
				let { starId, name, allName, avatar, lastCheckTime, lastPublishTime, 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(`<span style="color: #f40">补全女优头像: ${name}</span>`);
							count++;
						}
					}
					if (!existing.actressType && actressType) {
						existing.actressType = actressType;
						clog.log(`<span style="color: #f40">补全女优类别: ${name} ${actressType}</span>`);
						count++;
					}
					if (existing.name.includes(UNCENSORED_TAG)) {
						existing.name = name;
						existing.allName = allName;
						clog.log(`<span style="color: #f40">更正女优名字: ${name} ${allName}</span>`);
						count++;
					}
					continue;
				}
				const now = utils.getNowStr();
				list.push({
					starId,
					name,
					allName,
					avatar,
					lastCheckTime,
					lastPublishTime,
					createDate: now,
					updateDate: now,
					actressType
				});
				clog.log(`<span style="color: #f40">同步JavDB已收藏的演员: ${name}</span>`);
				count++;
			}
			if (count > 0) await this.forage.setItem(this.favorite_actresses_key, list);
			else clog.log("信息已记录, 无需要进行同步收藏的演员");
			return count;
		}
		async removeFavoriteActress(starId) {
			const list = await this.getFavoriteActressList();
			const beforeLen = list.length;
			const filtered = list.filter((entry) => entry.starId !== starId);
			if (filtered.length === beforeLen) {
				clog.error(`移除演员失败, ${starId} 不存在`);
				return false;
			} else {
				await this.forage.setItem(this.favorite_actresses_key, filtered);
				return true;
			}
		}
		async updateFavoriteActress(item) {
			const list = await this.getFavoriteActressList();
			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 this.forage.setItem(this.favorite_actresses_key, list);
		}
		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 #saveKeyword(keyword, key, label) {
			let list;
			if (Array.isArray(keyword)) list = [...keyword];
			else {
				list = await this.forage.getItem(key) || [];
				if (list.includes(keyword)) {
					const msg = `${keyword} ${label}已存在`;
					show.error(msg);
					throw new Error(msg);
				}
				list.push(keyword);
			}
			await this.forage.setItem(key, list);
			return list;
		}
		async saveTitleFilterKeyword(keyword) {
			await this.#saveKeyword(keyword, this.filter_keyword_title_key, "标题关键词");
			if (Array.isArray(keyword)) return null;
			const actressList = await this.getFavoriteActressList();
			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 this.forage.setItem(this.favorite_actresses_key, updated);
		}
		async saveReviewFilterKeyword(keyword) {
			return this.#saveKeyword(keyword, this.filter_keyword_review_key, "评论关键词");
		}
		async getTitleFilterKeyword() {
			return await this.forage.getItem(this.filter_keyword_title_key) || [];
		}
		async getReviewFilterKeywordList() {
			return await this.forage.getItem(this.filter_keyword_review_key) || [];
		}
		async getSetting(key = null, defaultValue) {
			if (!this.cacheSettingObj) this.cacheSettingObj = await this.forage.getItem(this.setting_key) || {};
			const setting = 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);
				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) {
			await this.forage.clear();
			const tasks = [];
			for (const key in data) {
				const value = data[key];
				const task = this.forage.setItem(key, value);
				tasks.push(task);
			}
			await Promise.all(tasks);
		}
		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 merge_table_name() {
			let oldKey = "filter_actor_actress_info_list";
			let items = await this.forage.getItem(oldKey) || [];
			if (items && items.length > 0) {
				console.log("更正", oldKey);
				await this.forage.setItem(this.blacklist_key, items);
			}
			await this.forage.removeItem(oldKey);
			oldKey = "favorite_actresses_info_list";
			items = await this.forage.getItem(oldKey) || [];
			if (items && items.length > 0) {
				console.log("更正", oldKey);
				await this.forage.setItem(this.favorite_actresses_key, items);
			}
			await this.forage.removeItem(oldKey);
			oldKey = "car_list_filter_actor_actress";
			items = await this.forage.getItem(oldKey) || [];
			if (items && items.length > 0) {
				console.log("更正", oldKey);
				await this.forage.setItem(this.blacklist_car_list_key, items);
			}
			await this.forage.removeItem(oldKey);
			oldKey = "title_filter_keyword";
			items = await this.forage.getItem(oldKey) || [];
			if (items && items.length > 0) {
				console.log("更正", oldKey);
				await this.forage.setItem(this.filter_keyword_title_key, items);
			}
			await this.forage.removeItem(oldKey);
			oldKey = "review_filter_keyword";
			items = await this.forage.getItem(oldKey) || [];
			if (items && items.length > 0) {
				console.log("更正", oldKey);
				await this.forage.setItem(this.filter_keyword_review_key, items);
			}
			await this.forage.removeItem(oldKey);
			oldKey = "highlightedTags";
			items = await this.forage.getItem(oldKey) || [];
			if (items && items.length > 0) {
				console.log("更正", oldKey);
				await this.forage.setItem(this.highlighted_tags_key, items);
			}
			await this.forage.removeItem(oldKey);
		}
		async clean_no_url_blacklist() {
			const [blacklistCars, blacklist] = await Promise.all([this.getBlacklistCarList(), this.getBlacklist()]);
			if (blacklistCars.length && !blacklistCars[0].actress) 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 this.forage.setItem(this.blacklist_car_list_key, filteredCars);
				this.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 this.forage.setItem(this.blacklist_key, cleanedBlacklist);
			}
		}
		async async_merge_other() {
			const setting = await this.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 this.saveSetting(setting);
				clog.debug("配置数据已更正");
			}
		}
		async merge_blacklist() {
			const list = await this.getBlacklist();
			if (!list || list.length === 0) 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 this.forage.setItem(this.blacklist_key, merged);
			}
			const carList = await this.getBlacklistCarList();
			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 this.forage.setItem(this.blacklist_car_list_key, mergedCars);
			}
		}
		async merge_favoriteActress() {
			const list = await this.getFavoriteActressList();
			if (!list || list.length === 0) return;
			let changed = false;
			const merged = list.map((item) => {
				let itemChanged = false;
				if (item.dbId) {
					item.starId = item.dbId;
					delete item.dbId;
					itemChanged = true;
				}
				if (itemChanged) changed = true;
				return item;
			});
			if (changed) {
				clog.debug("更正 favoriteActressesInfoList 数据结构");
				await this.forage.setItem(this.favorite_actresses_key, merged);
			}
		}
		async merge_tow_car_list_table() {
			const blacklistCars = await this.getBlacklistCarList();
			const carList = await this.getCarList();
			let changed = false;
			const mergedBlacklistCars = blacklistCars.map((item) => {
				let itemChanged = false;
				if (item.actress !== void 0) {
					item.names = item.actress;
					delete item.actress;
					itemChanged = true;
				}
				if (itemChanged) changed = true;
				return item;
			});
			if (changed) {
				clog.debug("更正 blacklistCarList 数据结构 actress->names");
				await this.forage.setItem(this.blacklist_car_list_key, mergedBlacklistCars);
			}
			changed = false;
			const mergedCars = carList.map((item) => {
				let itemChanged = false;
				if (item.actress !== void 0) {
					item.names = item.actress;
					delete item.actress;
					itemChanged = true;
				}
				if (itemChanged) changed = true;
				return item;
			});
			if (changed) {
				clog.debug("更正 carList 数据结构 actress->names");
				await this.forage.setItem(this.car_list_key, mergedCars);
			}
		}
	};
	var CommonUtil = class CommonUtil {
		static instance;
		intervalContainer = {};
		mimeTypes = {
			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"
		};
		timers = new Map();
		insertStyle = (css) => {
			if (css) {
				if (css.indexOf("<style>") === -1) css = "<style>" + css + "</style>";
				$("head").append(css);
			}
		};
		layerIndexStack = [];
		_boundHandler = null;
		constructor() {
			CommonUtil.instance ||= this;
			return CommonUtil.instance;
		}
		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);
		}
		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: 0 });
				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: this.getResponsiveArea(["85%", "90%"]),
				isOutAnim: false,
				anim: -1,
				success: (_layerEl, layerIdx) => {
					this.setupEscClose(layerIdx);
				}
			});
		}
		_handleGlobalEscKey(event) {
			if (event.key !== "Escape" && event.keyCode !== 27) return;
			if (this.layerIndexStack.length === 0) return;
			const layerIdx = this.layerIndexStack[this.layerIndexStack.length - 1];
			const layerEl = $(`#layui-layer${layerIdx}`);
			let hasViewer = false;
			if (layerEl.find(".viewer-container").length > 0) hasViewer = true;
			else {
				const iframeEl = layerEl.find(`#layui-layer-iframe${layerIdx}`)[0];
				if (iframeEl && iframeEl.contentDocument) try {
					if ($(iframeEl.contentDocument).find(".viewer-container").length > 0) hasViewer = true;
				} catch {
					clog.warn("无法检查跨域 iframe 内的 .viewer-container");
				}
			}
			if (!hasViewer) {
				this.layerIndexStack.pop();
				layer.close(layerIdx);
			}
		}
		setupEscClose(layerIdx) {
			if (!this._boundHandler) {
				this._boundHandler = this._handleGlobalEscKey.bind(this);
				$(document).off("keydown.globalLayerEsc");
				$(document).on("keydown.globalLayerEsc", this._boundHandler);
			}
			if (this.layerIndexStack.indexOf(layerIdx) === -1) this.layerIndexStack.push(layerIdx);
			const iframeEl = $(`#layui-layer-iframe${layerIdx}`);
			const eventNamespace = `keydown.layerEsc${layerIdx}`;
			try {
				const doc = iframeEl[0]?.contentDocument;
				if (doc) {
					if (iframeEl.attr("data-esc-bound") === "yes") return;
					$(doc).off(eventNamespace);
					$(doc).on(eventNamespace, this._boundHandler);
					iframeEl.attr("data-esc-bound", "yes");
				}
			} catch (err) {
				clog.error("iframe监听失败 (跨域或未加载完毕):", err);
			}
		}
		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();
			});
		}
		loopDetector(checkFn, onSuccess, intervalMs = 20, timeoutMs = 1e4, callOnTimeout = true) {
			const token = String(Math.random());
			const startTime = new Date().getTime();
			const finish = (triggered) => {
				clearInterval(this.intervalContainer[token]);
				if (triggered && onSuccess) onSuccess();
				delete this.intervalContainer[token];
			};
			this.intervalContainer[token] = setInterval(() => {
				const elapsed = new Date().getTime() - startTime;
				if (checkFn()) finish(true);
				else if (elapsed >= timeoutMs) finish(callOnTimeout);
			}, intervalMs);
		}
		rightClick(container, targetSelector, handler) {
			let el;
			if (typeof container === "string") el = document.querySelector(container);
			else if (container instanceof HTMLElement) el = container;
			if (!el) {
				console.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 console.error("rightClick(), 必须提供有效的 targetSelector。");
		}
		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;
			}
			let layerIdx = layer.confirm(content, {
				offset: [top, left],
				title: "提示",
				btn: ["确定", "取消"],
				shade: 0,
				zIndex: 999999991
			}, function() {
				if (onConfirm) onConfirm();
				layer.close(layerIdx);
			}, function() {
				if (onCancel) onCancel();
			});
		}
		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)}`;
		}
		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)}`;
		}
		getHourDifference(start, end) {
			const startMs = start.getTime();
			const endMs = end.getTime();
			const hours = Math.abs(endMs - startMs) / 36e5;
			return Math.floor(hours);
		}
		isUnnecessaryCheck(timeStr, checkIntervalTime) {
			if (!checkIntervalTime) throw new Error("未传入checkIntervalTime");
			const hours = parseInt(String(checkIntervalTime), 10);
			return this.getHourDifference(new Date(timeStr), new Date()) < hours;
		}
		download(data, filename) {
			show.info("开始请求下载...");
			const ext = filename.split(".").pop().toLowerCase();
			const mimeType = this.mimeTypes[ext] || "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);
		}
		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();
				});
			});
		}
		simpleId() {
			return crypto.randomUUID().replace("-", "");
		}
		isUrl(str) {
			try {
				new URL(str);
				return true;
			} catch {
				return false;
			}
		}
		setHrefParam(key, value) {
			const url = new URL(window.location.href);
			url.searchParams.set(key, value);
			window.history.pushState({}, "", url.toString());
		}
		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;
		}
		reBuildSignature() {
			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;
		}
		getResponsiveArea(area) {
			const width = window.innerWidth;
			if (width >= 1200) return area || this.getDefaultArea();
			else if (width >= 768) return ["70%", "90%"];
			else return ["95%", "95%"];
		}
		getDefaultArea() {
			return ["85%", "90%"];
		}
		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));
		}
		copyToClipboard(label, text) {
			navigator.clipboard.writeText(text).then(() => show.info(`${label}已复制到剪切板, ${text}`)).catch((err) => console.error("复制失败: ", err));
		}
		htmlTo$dom(html) {
			const parser = new DOMParser();
			return $(parser.parseFromString(html, "text/html"));
		}
		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}`);
						console.log("document.cookie = '" + segments.join("; ") + "'");
						document.cookie = segments.join("; ");
					}
				}
			});
		}
		isHidden(el) {
			const node = el.jquery ? el[0] : el;
			return !node || node.offsetWidth <= 0 && node.offsetHeight <= 0 || window.getComputedStyle(node).display === "none";
		}
		time(label = "default", unit = "s", precision = 2) {
			if (this.timers.has(label)) {
				const entry = this.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 = "毫秒";
				}
				this.timers.delete(label);
				return `${label}: ${formatted}${unitLabel}`;
			}
			this.timers.set(label, {
				startTime: performance.now(),
				unit,
				precision
			});
		}
		sleep(ms = 1e3) {
			return new Promise((resolve) => setTimeout(resolve, ms));
		}
		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 = 0;
					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;
			});
		}
		async 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}`);
			}
		}
	};
	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 = 0;
			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.message);
				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)}`;
				const promise = 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);
			}
			try {
				await Promise.all(promises);
				clog.log(`[${filename}] 所有分块下载完成,开始合并...`);
			} catch (err) {
				clog.error(`[${filename}] 分块下载过程中发生错误:`, err.message);
				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 !== requestUrl) reject("请求被重定向了,URL是:" + response.finalUrl);
							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);
		}
	};
	function resetOverflowByShadeCount(delay = 10) {
		setTimeout(() => {
			const shadeCount = document.querySelectorAll(".layui-layer-shade").length;
			document.documentElement.style.overflow = shadeCount > 0 ? "hidden" : "";
		}, delay);
	}
	function setupLayerWrapper() {
		const originalClose = layer.close;
		layer.close = function(index) {
			const result = originalClose.call(this, index);
			resetOverflowByShadeCount();
			return result;
		};
		const originalOpen = layer.open;
		layer.open = function(options) {
			const opts = options || {};
			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\n    pointer-events: none;\n    font-size: 14px;\n    line-height: 1.5;\n    z-index: 9999999999;\n\n    background: #f0fdf4;\n    color: #166534;\n    border: none;\n    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);\n\n    display: none;\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.innerHTML = 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 PluginManager = class {
		plugins = new Map();
		register(pluginClass) {
			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}"已注册`);
			this.plugins.set(pluginName, instance);
		}
		getBean(name) {
			return this.plugins.get(name);
		}
		async processCss() {
			const failed = (await Promise.all(Array.from(this.plugins).map(async ([name, plugin]) => {
				try {
					if (typeof plugin.initCss === "function") {
						const css = await plugin.initCss();
						if (css) utils.insertStyle(css);
						return {
							name,
							status: "fulfilled"
						};
					}
					return {
						name,
						status: "skipped"
					};
				} catch (err) {
					console.error(`插件 ${name} 加载 CSS 失败`, err);
					return {
						name,
						status: "rejected",
						error: err
					};
				}
			}))).filter((result) => result.status === "rejected");
			if (failed.length) console.error("以下插件的 CSS 加载失败:", failed.map((result) => result.name));
		}
		async processPlugins() {
			const failed = (await Promise.all(Array.from(this.plugins).map(async ([name, plugin]) => {
				try {
					if (typeof plugin.handle === "function") {
						await plugin.handle();
						return {
							name,
							status: "fulfilled"
						};
					}
					return {
						name,
						status: "skipped"
					};
				} catch (err) {
					clog.error(`插件 ${name} 执行失败`, err);
					return {
						name,
						status: "rejected",
						error: err
					};
				}
			}))).filter((result) => result.status === "rejected");
			if (failed.length) console.error("以下插件执行失败:", failed.map((result) => result.name));
		}
	};
	var SETTING_SVG = "<svg t=\"1760926954860\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4947\" width=\"200\" height=\"200\"><path d=\"M511.099222 365.825763c-80.7786 0-146.26579 65.482515-146.26579 146.259556 0 80.7786 65.48719 146.259556 146.26579 146.259556 80.777041 0 146.259556-65.480957 146.259556-146.259556C657.358779 431.308278 591.876263 365.825763 511.099222 365.825763L511.099222 365.825763zM511.099222 585.215097c-40.391637 0-73.136012-32.742816-73.136012-73.129778 0-40.391637 32.742816-73.129778 73.136012-73.129778 40.386962 0 73.129778 32.738141 73.129778 73.129778C584.229 552.472281 551.486184 585.215097 511.099222 585.215097L511.099222 585.215097zM511.099222 585.215097M900.893017 568.24369l-26.451395-15.268032c3.065451-27.021784 3.138697-54.472139 0.077922-81.822754l26.373473-15.225955c69.953678-40.391637 93.920921-129.844512 53.533959-199.799749-40.390079-69.95212-129.839837-93.925596-199.799749-53.533959l-26.373473 15.225955c-22.153219-16.330888-45.963059-29.99217-70.896534-40.843585l0-30.545416c0-80.777041-65.48719-146.259556-146.26579-146.259556-80.7786 0-146.259556 65.482515-146.259556 146.259556l0 30.515806c-12.377127 5.421811-24.587501 11.55583-36.562551 18.473743-11.97505 6.917913-23.396854 14.420242-34.277879 22.432179l-26.431136-15.258682c-69.958353-40.391637-159.406553-16.424395-199.79819 53.533959C27.378272 326.082437 51.343956 415.535311 121.299193 455.922273l26.449837 15.275825c-3.063892 27.020226-3.137139 54.465905-0.077922 81.822754l-26.373473 15.224397c-69.953678 40.391637-93.920921 129.841395-53.533959 199.799749 40.391637 69.95212 129.839837 93.920921 199.79819 53.533959l26.375032-15.224397c22.153219 16.32933 45.963059 29.984378 70.896534 40.843585l0 30.537624c0 80.7786 65.48719 146.26579 146.26579 146.26579 80.777041 0 146.259556-65.48719 146.259556-146.26579l0-30.515806c12.377127-5.415577 24.587501-11.55583 36.567226-18.467509 11.97505-6.917913 23.398412-14.420242 34.277879-22.432179l26.423343 15.258682c69.959912 40.391637 159.408111 16.418162 199.799749-53.533959C994.813938 698.085085 970.848254 608.635327 900.893017 568.24369L900.893017 568.24369zM891.096666 731.474653c-20.198936 34.982294-64.923035 46.962019-99.900654 26.770875l-63.331869-36.567226 0 0 0 0-7.988562-4.611422c-18.134004 18.450366-39.024886 34.787489-62.516805 48.353705-23.49971 13.559983-48.091888 23.482568-73.129778 29.964118l0 9.222846 0 0 0 65.828489 0 7.301289c0 40.391637-32.742816 73.136012-73.136012 73.136012-40.386962 0-73.129778-32.742816-73.129778-73.136012l0-7.402588 0-65.72719 0 0 0-9.300768c-50.682014-13.090892-97.855981-39.682547-135.652816-78.232109l-7.983886 4.606747 0 0-63.331869 36.567226c-34.977618 20.191144-79.706394 8.206743-99.900654-26.770875-20.192702-34.977618-8.206743-79.701718 26.770875-99.899095l6.341291-3.657657 0 0 64.972905-37.516316c-14.487254-52.005129-13.929333-106.151555 0.073247-156.593569l-8.057133-4.650384 0 0-63.331869-36.567226c-34.982294-20.192702-46.963578-64.923035-26.770875-99.900654 20.192702-34.97606 64.923035-46.962019 99.900654-26.763083l6.324148 3.649866 0 0 64.996282 37.528784c18.132445-18.450366 39.024886-34.790606 62.516805-48.353705 23.493477-13.559983 48.085654-23.485685 73.129778-29.964118l0-9.229079L437.960093 153.739276l0-7.309082c0-40.385404 32.742816-73.129778 73.129778-73.129778 40.391637 0 73.129778 32.744375 73.129778 73.129778l0 7.404147 0 65.72719 0 9.307001c50.686689 13.086217 97.862215 39.684106 135.657491 78.232109l48.487732-27.997368 22.828023-13.176607c34.977618-20.192702 79.701718-8.212977 99.89442 26.763083 20.198936 34.982294 8.212977 79.706394-26.764641 99.900654l-30.822819 17.79738-32.50905 18.769847 0 0 0 0-7.983886 4.605189c14.488813 52.009805 13.929333 106.159347-0.077922 156.599803l64.979139 37.511641 0 0 6.414537 3.701294C899.303409 651.772936 911.289368 696.498594 891.096666 731.474653L891.096666 731.474653zM891.096666 731.474653M197.330785 324.240361c-1.932465 3.232203-3.824411 6.497135-5.649343 9.785442L197.330785 324.240361 197.330785 324.240361zM197.330785 324.240361M830.515443 690.133926l-5.655577 9.804144C826.793889 696.699632 828.685835 693.433143 830.515443 690.133926L830.515443 690.133926zM830.515443 690.133926M505.297151 146.430195l11.304921 0C512.835324 146.369416 509.067017 146.374091 505.297151 146.430195L505.297151 146.430195zM505.297151 146.430195M516.898176 877.740444l-11.31583 0C509.350653 877.796547 513.125193 877.796547 516.898176 877.740444L516.898176 877.740444zM516.898176 877.740444\" fill=\"#272636\" p-id=\"4948\"></path></svg>";
	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 CHECK_SVG = "<svg t=\"1760921633527\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"5603\" width=\"200\" height=\"200\"><path d=\"M924.928 544A413.76 413.76 0 0 1 544 924.736v3.264h-64v-3.2A413.696 413.696 0 0 1 99.072 544H96v-64h3.072A413.696 413.696 0 0 1 480 99.2V96h64v3.2a413.76 413.76 0 0 1 380.928 380.8h3.072v64h-3.072z m-64-64A350.016 350.016 0 0 0 544 163.2V288h-64V163.2A350.016 350.016 0 0 0 163.072 480H288v64H163.072A350.016 350.016 0 0 0 480 860.8V736h64v124.8a350.016 350.016 0 0 0 316.928-316.8H736v-64h124.928zM512 544a32 32 0 1 1 32-32 32 32 0 0 1-32 32z\" fill=\"#333333\" p-id=\"5604\"></path></svg>";
	var ACTRESS_SVG = "<svg t=\"1760926744637\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"1948\" width=\"200\" height=\"200\"><path d=\"M265.950168 668.467036V209.809493A209.809493 209.809493 0 0 1 475.759661 0h40.949536A209.809493 209.809493 0 0 1 726.564189 209.809493v440.435\" p-id=\"1949\"></path><path d=\"M916.558657 825.861124a193.463804 193.463804 0 0 0-137.442564-155.83573l-186.001889-45.795231-10.487631-124.293214H424.106373L412.231008 624.025416l-170.623063 44.44162a193.452429 193.452429 0 0 0-133.666108 154.698244L76.410695 1023.192384h871.189985z\" fill=\"#FFE7D9\" p-id=\"1950\"></path><path d=\"M668.472724 265.682859c68.431223-29.187919 96.140409 100.349111 5.20969 151.774902z\" fill=\"#FFCFB5\" p-id=\"1951\"></path><path d=\"M676.378259 334.421203c1.137487-99.814492-38.674561-172.158671-38.674561-172.15867l-59.740822 11.920865a493.805894 493.805894 0 0 1-80.761583 9.099896 493.669396 493.669396 0 0 1-80.761583-9.099896l-59.683948-11.88674s-39.812048 72.344179-38.776934 172.15867l-1.080613 92.05683c5.209691 56.271486 92.4777 121.381247 195.022161 119.163147 61.196805 0.034125 165.59537-51.573665 165.59537-119.197272z\" fill=\"#FFE7D9\" p-id=\"1952\"></path><path d=\"M322.198905 274.703131c-68.419848-29.187919-96.140409 100.349111-5.209691 151.774902z\" fill=\"#FFCFB5\" p-id=\"1953\"></path><path d=\"M297.390311 812.461526H742.034014a38.458438 38.458438 0 0 1 38.458438 38.458439V1020.325917H258.931873V850.90859a38.458438 38.458438 0 0 1 38.458438-38.447064z\" fill=\"#FFD527\" p-id=\"1954\"></path><path d=\"M690.539973 92.284327c-20.645391 84.287793-275.613121 235.323328-424.589805 117.525166l104.955934-95.548915 139.399042-64.529643z\" p-id=\"1955\"></path><path d=\"M285.321573 383.708519h33.624119v177.118114h-33.624119zM675.855015 383.708519h33.624118v177.118114h-33.624118z\" fill=\"#FFD527\" p-id=\"1956\"></path></svg>";
	var NEW_SVG = "<svg t=\"1760926857487\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"3954\" width=\"200\" height=\"200\"><path d=\"M508.330667 733.994667c-11.008-7.338667-13.44-17.109333-7.338667-29.333334 28.117333-37.888 41.557333-98.986667 40.341333-183.317333v-165.013333c0-14.656 7.338667-23.210667 21.994667-25.664 37.888-1.216 82.496-5.504 133.845333-12.842667 13.44-2.432 21.376 3.072 23.829334 16.512 1.216 12.224-4.266667 19.562667-16.512 21.994667a1787.093333 1787.093333 0 0 1-113.664 11.008c-6.101333 0-9.173333 3.669333-9.173334 10.986666v84.330667h135.68c12.224 1.237333 18.944 7.957333 20.16 20.181333-1.216 10.986667-7.936 17.109333-20.16 18.346667h-36.672v223.658667c-1.216 12.202667-7.936 18.944-20.16 20.16-11.008-1.216-17.109333-7.957333-18.346666-20.16V501.162667h-60.48v18.346666c1.216 92.885333-13.44 161.92-44.010667 207.146667-6.101333 12.224-15.893333 14.677333-29.333333 7.338667z m-131.989334-282.325334c-1.237333 0-2.453333 0.618667-3.669333 1.834667h45.824a522.666667 522.666667 0 0 0 16.512-31.168c7.317333-12.224 12.224-20.778667 14.656-25.664 6.122667-11.008 15.274667-14.677333 27.52-11.008 9.770667 6.122667 12.202667 14.058667 7.317333 23.829333-4.906667 9.792-13.44 24.448-25.664 44.010667h49.493334c9.770667 1.216 15.274667 6.72 16.512 16.490667-1.237333 11.008-6.741333 17.109333-16.512 18.346666h-82.496a12.437333 12.437333 0 0 1 3.669333 9.173334v38.485333h69.653333c9.792 1.216 15.296 6.72 16.512 16.490667-1.216 11.008-6.72 17.130667-16.512 18.346666h-69.653333v108.16c0 34.218667-15.274667 51.946667-45.845333 53.162667h-16.490667a195.157333 195.157333 0 0 1-20.16 1.834667c-12.224 0-19.562667-6.72-22.016-20.16 1.237333-12.224 7.338667-18.944 18.346667-20.16 2.432 0 6.101333 0.597333 10.986666 1.834666h11.008c15.893333 0 23.829333-8.554667 23.829334-25.685333v-98.986667H314.026667c-11.008-1.216-17.109333-7.338667-18.346667-18.346666 1.237333-9.770667 7.338667-15.274667 18.346667-16.490667h75.157333V497.493333c0-3.669333 1.216-6.72 3.669333-9.173333h-89.813333c-11.029333-1.216-17.130667-7.317333-18.346667-18.325333 1.216-9.770667 7.317333-15.274667 18.346667-16.490667h56.810667c-3.669333-1.216-6.72-4.266667-9.173334-9.173333-1.216-1.216-3.050667-4.266667-5.482666-9.173334a758.336 758.336 0 0 0-14.677334-23.829333c-4.885333-9.770667-3.050667-17.706667 5.504-23.829333 11.008-3.669333 19.562667-1.216 25.664 7.338666 2.453333 2.432 6.122667 7.338667 11.008 14.656 6.101333 8.554667 9.770667 14.08 10.986667 16.512 4.906667 9.770667 2.453333 18.346667-7.317333 25.664z m-60.501333-71.509333c-9.792-1.216-15.274667-7.317333-16.512-18.346667 1.237333-9.749333 6.72-15.253333 16.512-16.490666h75.157333c-3.669333-12.202667-7.338667-21.973333-10.986666-29.333334-1.237333-12.202667 3.648-19.541333 14.656-21.973333 12.224-2.453333 21.397333 1.216 27.52 10.986667 0 1.216 0.597333 3.669333 1.813333 7.338666 4.906667 15.872 9.173333 26.88 12.842667 32.981334h60.48c11.008 1.237333 17.130667 6.741333 18.346666 16.512-1.216 11.008-7.338667 17.109333-18.346666 18.346666h-181.482667z m-14.677333 311.68c-8.533333-6.122667-10.986667-14.08-7.338667-23.829333a1659.648 1659.648 0 0 0 33.002667-66.005334c4.906667-9.792 12.224-12.842667 22.016-9.173333 9.770667 4.906667 13.44 12.224 10.986666 21.994667-3.669333 6.122667-9.173333 17.728-16.490666 34.837333-8.554667 15.893333-14.677333 27.52-18.346667 34.837333-4.885333 8.554667-12.821333 11.008-23.829333 7.338667z m201.664-25.664c-9.770667 4.885333-18.346667 2.432-25.664-7.338667a1138.56 1138.56 0 0 1-27.498667-44.010666c-4.885333-8.533333-3.050667-16.490667 5.504-23.829334 9.770667-3.669333 18.346667-1.216 25.664 7.338667l14.677333 21.994667c6.101333 9.770667 10.389333 17.109333 12.821334 21.994666 4.906667 8.554667 3.050667 16.512-5.504 23.850667z\" fill=\"#333333\" p-id=\"3955\"></path><path d=\"M675.328 117.717333A425.429333 425.429333 0 0 0 512 85.333333C276.352 85.333333 85.333333 276.352 85.333333 512s191.018667 426.666667 426.666667 426.666667 426.666667-191.018667 426.666667-426.666667c0-56.746667-11.093333-112-32.384-163.328a21.333333 21.333333 0 0 0-39.402667 16.341333A382.762667 382.762667 0 0 1 896 512c0 212.074667-171.925333 384-384 384S128 724.074667 128 512 299.925333 128 512 128c51.114667 0 100.8 9.984 146.986667 29.12a21.333333 21.333333 0 0 0 16.341333-39.402667z\" fill=\"#333333\" p-id=\"3956\"></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 BLACKLIST_SVG = "<svg t=\"1761386375897\" class=\"jhs-icon icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"1936\" width=\"200\" height=\"200\"><path d=\"M513.199827 65.667605c-246.537999 0-446.399933 199.861934-446.399933 446.399933 0 246.553349 199.861934 446.399933 446.399933 446.399933 246.553349 0 446.399933-199.846584 446.399933-446.399933C959.599759 265.529539 759.753175 65.667605 513.199827 65.667605zM513.199827 894.697075c-211.320916 0-382.629537-171.322947-382.629537-382.628514 0-94.183056 34.029024-180.417069 90.461291-247.080352l165.389818 165.389818c4.320399 39.651069 26.816762 73.840752 58.981323 94.068446-72.189136 27.369348-123.517151 97.156784-123.517151 178.936345l337.541643 0 100.846826 100.846826C693.608709 860.664981 607.375719 894.697075 513.199827 894.697075zM805.362956 759.14175 697.264982 651.0448c-16.556071-58.332547-60.10082-105.306394-116.275213-126.601396 35.888372-22.570042 59.752896-62.511729 59.752896-108.032482 0-70.436212-57.108672-127.542838-127.542838-127.542838-48.218188 0-90.184999 26.765597-111.865787 66.245773L266.120498 219.900316c66.663282-56.432267 152.897296-90.461291 247.079328-90.461291 211.304544 0 382.628514 171.308621 382.628514 382.629537C895.82834 606.244454 861.796246 692.476421 805.362956 759.14175z\" fill=\"#272636\" p-id=\"1937\"></path></svg>";
	var BasePlugin = class {
		pluginManager = null;
		settingSvg = SETTING_SVG;
		editSvg = EDIT_SVG;
		deleteSvg = DELETE_SVG;
		checkSvg = CHECK_SVG;
		actressSvg = ACTRESS_SVG;
		newSvg = NEW_SVG;
		refreshSvg = REFRESH_SVG;
		blacklistSvg = BLACKLIST_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");
				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 为空";
				console.error("Error in getBoxCarInfo:", msg, "Box Element:", boxEl.get(0));
				show.error(msg);
				throw new Error(msg);
			}
			return {
				carNum,
				url: url || "",
				title: title || "",
				publishTime: publishTime || ""
			};
		}
		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.message, "元素索引:", 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 consecutive = 0;
			for (let i = 0; i < other.length; i++) {
				const car = other[i] ? other[i].carNum : null;
				if (car && existing.has(car)) {
					consecutive++;
					if (consecutive >= 2) {
						clog.warn("警告: 检测到连续番号信息重复, 该类别可能已被限制页码。");
						return true;
					}
				} else consecutive = 0;
			}
			return false;
		}
	};
	var DetailPagePlugin = class extends BasePlugin {
		getName() {
			return "DetailPagePlugin";
		}
		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 FilterTitleKeywordPlugin = class extends BasePlugin {
		getName() {
			return "FilterTitleKeywordPlugin";
		}
		async handle() {
			if (!window.isDetailPage && !window.isFc2Page) return;
			if (await storageManager.getSetting("enableTitleSelectFilter", "yes") !== "yes") return;
			let selector;
			if (isJavdbSite) selector = ".title strong, .current-title";
			utils.rightClick(document.body, selector, (event) => {
				const selectedText = window.getSelection()?.toString() ?? "";
				if (selectedText) {
					event.preventDefault();
					const position = {
						clientX: event.clientX,
						clientY: event.clientY + 80
					};
					utils.q(position, `是否屏蔽标题关键词 ${selectedText}?`, async () => {
						await storageManager.saveTitleFilterKeyword(selectedText);
						window.refresh();
						utils.closePage();
					});
				}
			});
		}
	};
	var HighlightMagnetPlugin = class extends BasePlugin {
		getName() {
			return "HighlightMagnetPlugin";
		}
		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: "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, hotkey }) {
		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: "menu-btn  main-tab-btn",
				id: "foldCategoryBtn",
				style: { backgroundColor: "#d23e60 !important" },
				children: [
					(0, import_jsx_runtime.jsx)("span", {}),
					hotkey ? ` (${hotkey})` : "",
					(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.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 rgba(0, 0, 0, 0.2);\n    display: none;\n    z-index: 999;\n}\n/* 当父元素被高亮时,按钮变为其他颜色 */\n.highlighted .highlight-btn {\n    background-color: #ff5722;\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";
		}
		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(() => $("#waitCheckBtn").length, () => {
						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() {
			const hotkey = await storageManager.getSetting("foldCategoryHotKey");
			let tagsEl = $("#tags");
			let selectedTagsText = $("#tags dl div.tag.is-info").map(function() {
				return $(this).text().replaceAll("\n", "").replaceAll(" ", "");
			}).get().join(" ");
			if (!selectedTagsText) return;
			$(".tabs").append(jsxToString((0, import_jsx_runtime.jsx)(FoldCategoryToolbar, {
				selectedTagsText,
				hotkey: hotkey || ""
			})));
			let 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";
			let [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"]();
			});
		}
	};
	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";
	function ActressInfoDetailSegment({ actressName, info, wikiApiUrl }) {
		if (info) return (0, import_jsx_runtime.jsxs)("div", {
			className: "panel-block actress-info",
			children: [(0, import_jsx_runtime.jsxs)("strong", { children: [actressName, ":"] }), (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.jsx)("div", {
			className: "panel-block actress-info",
			children: (0, import_jsx_runtime.jsx)("a", {
				href: wikiApiUrl + actressName,
				target: "_blank",
				children: (0, import_jsx_runtime.jsxs)("strong", { children: [actressName, ":"] })
			})
		});
	}
	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 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);
			const cache = rawCache ? JSON.parse(rawCache) : {};
			let info = null;
			let html = "";
			for (const actressName of actressNames) {
				info = cache[actressName];
				if (!info) try {
					info = await this.searchInfo(actressName);
					if (info) cache[actressName] = info;
				} catch {
					console.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;
			let 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);
			const cache = rawCache ? JSON.parse(rawCache) : {};
			let info = null;
			for (const actressName of names) {
				info = cache[actressName];
				if (info) break;
				try {
					info = await this.searchInfo(actressName);
				} catch {
					console.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 = 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_TTL_SECONDS = 20;
	var SIGNATURE_NAMESPACE = "lpw6vgqzsp";
	var SIGNATURE_SALT = "71cf27bb3c0bcdf207b64abecddc970098c7421ee7203b9cdae54478478a199e7d5a6e1a57691123c1a931c057842fb73ba3b3c83bcd69c17ccf174081e3d8aa";
	function reBuildSignature() {
		const now = Math.floor(Date.now() / 1e3);
		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;
	}
	async function fetchMovieReviews(movieId, page = 1, limit = 20) {
		const url = `${API_BASE}/v1/movies/${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/${movieId}`;
		const headers = { jdSignature: await reBuildSignature() };
		const resp = await gmHttp.get(url, null, headers);
		if (!resp.data) {
			show.error("获取视频详情失败: " + resp.message);
			throw new Error(resp.message);
		}
		const movie = resp.data.movie;
		const imgList = [];
		movie.preview_images.forEach((img) => {
			imgList.push(img.large_url.replace("https://tp-iu.cmastd.com/rhe951l4q", "https://c0.jdbstatic.com"));
		});
		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=${movieId}&page=${page}&limit=${limit}`;
		const headers = { jdSignature: await reBuildSignature() };
		const resp = await gmHttp.get(url, null, 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, null, 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, null, headers);
	}
	function HitShowMovieItem({ movie }) {
		return (0, import_jsx_runtime.jsx)("div", {
			className: "item",
			id: 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: movie.cover_url.replace("https://tp-iu.cmastd.com/rhe951l4q", "https://c0.jdbstatic.com"),
							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("");
			const loadingOverlay = loading();
			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);
			} finally {
				if (success || attempt === 3) loadingOverlay.close();
			}
		}
		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.message}\n`, 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("");
			const loadingOverlay = loading();
			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("无数据");
						loadingOverlay.close();
						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, {})));
				}
			} finally {
				if (success || attempt === 3) loadingOverlay.close();
			}
		}
		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: 0 });
			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;
						}
						const loadingOverlay = loading();
						(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, null, headers);
						})(username, password).then(async (response) => {
							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.message);
						}).finally(() => {
							loadingOverlay.close();
						});
					});
				}
			});
		}
	};
	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-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    /* 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, {})));
			$("#search-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);
			}).on("keypress", (event) => {
				if (event.key === "Enter") setTimeout(() => {
					$("#search-btn").click();
				}, 0);
			});
			$("#search-btn").on("click", (_event) => {
				const keyword = $("#search-keyword").val();
				const searchType = $("#search-type option:selected").val();
				if (keyword !== "") if (window.location.href.includes("/search")) window.location.href = "/search?q=" + keyword + "&f=" + searchType;
				else window.open("/search?q=" + keyword + "&f=" + searchType);
			});
		}
		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", "以图识图");
		}
		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() < 1600 && $(window).width() > 1023) {
				searchBox.hide();
				searchBarContainer.show();
			}
			if ($(window).width() > 1600) {
				searchBox.show();
				searchBarContainer.hide();
			}
		}
	};
	var AsyncTaskQueue = class {
		queue;
		constructor() {
			this.queue = Promise.resolve();
		}
		addTask(task) {
			this.queue = this.queue.then(() => task()).catch((err) => {
				clog.error("执行异步队列任务失败:", err);
			});
		}
		async waitAllFinished() {
			return this.queue;
		}
	};
	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", "")
			})]
		});
	}
	function SiteResultTag() {
		return (0, import_jsx_runtime.jsx)("span", {
			className: "site-tag",
			style: { top: "-15px" },
			children: "多结果"
		});
	}
	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.site-btn:hover {\n    color: white;\n    transform: translateY(-2px);\n    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\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 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")
		}];
		settingCache = null;
		lastFetchTime = 0;
		CACHE_DURATION = 1e4;
		getName() {
			return "OtherSitePlugin";
		}
		async initCss() {
			return other_site_plugin_default;
		}
		async handle() {
			if (window.isDetailPage) this.loadOtherSite().then();
		}
		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) {
			const buttonEl = $(`#${siteConfig.id}`);
			if (siteConfig.initUrl) {
				buttonEl.attr("href", siteConfig.initUrl(carNum));
				buttonEl.css("backgroundColor", this.warnBackgroundColor);
			}
			if (siteConfig.noHandle && siteConfig.noHandle === true) {
				const dmmStorageKey = "jhs_other_site_dmm";
				const dmmCachedResult = (localStorage.getItem(dmmStorageKey) ? JSON.parse(localStorage.getItem(dmmStorageKey)) : {})[carNum];
				if (dmmCachedResult) {
					if (dmmCachedResult.type === "single") {
						buttonEl.attr("href", dmmCachedResult.url);
						buttonEl.css("backgroundColor", this.okBackgroundColor);
					} else if (dmmCachedResult.type === "multiple") {
						buttonEl.attr("href", dmmCachedResult.url);
						buttonEl.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
						buttonEl.css("backgroundColor", this.okBackgroundColor);
					}
				}
			} else try {
				if (buttonEl.attr("href")) return;
				if (utils.isHidden(buttonEl)) return;
				const storageKey = "jhs_other_site";
				const cache = localStorage.getItem(storageKey) ? JSON.parse(localStorage.getItem(storageKey)) : {};
				const cacheKey = carNum + "_" + siteConfig.id.replace("Btn", "");
				const cachedResult = cache[cacheKey];
				if (cachedResult) {
					if (cachedResult.type === "single") {
						buttonEl.attr("href", cachedResult.url);
						buttonEl.css("backgroundColor", this.okBackgroundColor);
					} else if (cachedResult.type === "multiple") {
						buttonEl.attr("href", cachedResult.url);
						buttonEl.append(jsxToString((0, import_jsx_runtime.jsx)(SiteResultTag, {})));
						buttonEl.css("backgroundColor", this.okBackgroundColor);
					}
					return;
				}
				const baseUrl = await siteConfig.getBaseUrl();
				const searchUrl = siteConfig.searchPath(baseUrl, carNum);
				buttonEl.attr("href", searchUrl);
				const htmlContent = await gmHttp.get(searchUrl, null, siteConfig.headers, true);
				const $dom = utils.htmlTo$dom(htmlContent);
				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", this.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", this.okBackgroundColor);
					resultData = {
						type: "multiple",
						url: searchUrl
					};
				} else {
					buttonEl.attr("href", searchUrl);
					buttonEl.attr("title", "未查询到, 点击前往搜索页");
					buttonEl.css("backgroundColor", this.errorBackgroundColor);
				}
				if (resultData) new AsyncTaskQueue().addTask(() => {
					const cache = localStorage.getItem(storageKey) ? JSON.parse(localStorage.getItem(storageKey)) : {};
					cache[cacheKey] = resultData;
					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", this.warnBackgroundColor);
					clog.warn(`检测第三方资源失败, ${siteName} 需Cloudflare安全检查`);
				} else if (errorMsg.includes("重定向")) {
					buttonEl.attr("title", "域名失效");
					buttonEl.css("backgroundColor", this.domainErrorBackgroundColor);
					clog.warn(`检测第三方资源失败, ${siteName} 域名被重定向`);
				} else if (errorMsg.includes("404 Page Not Found")) {
					buttonEl.attr("title", "未查询到, 点击前往搜索页");
					buttonEl.css("backgroundColor", this.errorBackgroundColor);
				} else {
					console.error(error);
					buttonEl.attr("title", "请求失败。");
					buttonEl.css("backgroundColor", this.errorBackgroundColor);
					clog.warn(`检测第三方资源失败, ${siteName}`);
				}
			}
		}
		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() {
			const stored = localStorage.getItem("jhs_enabled_sites");
			if (stored) return JSON.parse(stored);
			else return this.siteConfigs.map((siteConfig) => siteConfig.id);
		}
		saveEnabledSites(siteIds) {
			localStorage.setItem("jhs_enabled_sites", JSON.stringify(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");
			settingsArea?.addEventListener("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);
				}
			});
		}
	};
	function ReviewContainers() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", { id: "reviewsContainer" }), (0, import_jsx_runtime.jsx)("div", { id: "reviewsFooter" })] });
	}
	function ReviewEmpty() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: "无评论"
		});
	}
	function ReviewEnd() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				textAlign: "center",
				padding: "10px",
				color: "#666",
				marginTop: "10px"
			},
			children: "已加载全部评论"
		});
	}
	function ReviewError() {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: ["获取评论失败", (0, import_jsx_runtime.jsx)("a", {
				id: "retryFetchReviews",
				href: "javascript:;",
				style: {
					marginLeft: "10px",
					color: "#1890ff",
					textDecoration: "none"
				},
				children: "重试"
			})]
		});
	}
	function ReviewHeader({ 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": "想要发表评论? 滑上去, 点击上面的按钮-看过",
					children: "❓ 评论区"
				}),
				(0, import_jsx_runtime.jsxs)("a", {
					id: "reviewsFold",
					style: {
						marginLeft: "8px",
						color: "#1890ff",
						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 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" },
					dangerouslySetInnerHTML: { __html: ` ${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
			}),
			" ",
			(0, import_jsx_runtime.jsx)("button", {
				className: "button is-info down-115",
				"data-magnet": match,
				style: { fontSize: "11px" },
				children: "115离线下载"
			}),
			" "
		] });
		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
			}),
			" ",
			(0, import_jsx_runtime.jsx)("button", {
				className: "button is-info down-115",
				"data-magnet": match,
				style: { fontSize: "11px" },
				children: "115离线下载"
			}),
			" "
		] });
		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 ReviewLoadMore() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("button", {
			id: "loadMoreReviews",
			style: {
				width: "100%",
				backgroundColor: "#e1f5fe",
				border: "none",
				padding: "10px",
				marginTop: "10px",
				cursor: "pointer",
				color: "#0277bd",
				fontWeight: "bold",
				borderRadius: "4px"
			},
			children: "加载更多评论"
		}), (0, import_jsx_runtime.jsx)("div", {
			id: "reviewsEnd",
			style: {
				display: "none",
				textAlign: "center",
				padding: "10px",
				color: "#666",
				marginTop: "10px"
			},
			children: "已加载全部评论"
		})] });
	}
	function ReviewLoading() {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "reviewsLoading",
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: "获取评论中..."
		});
	}
	var ReviewPlugin = class extends BasePlugin {
		floorIndex = 1;
		isInit = false;
		constructor() {
			super();
		}
		getName() {
			return "ReviewPlugin";
		}
		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)(ReviewHeader, {
				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)(ReviewContainers, {})));
			if (isExpanded === "yes") await this.fetchAndDisplayReviews(movieId);
		}
		async fetchAndDisplayReviews(movieId) {
			const container = $("#reviewsContainer");
			const footer = $("#reviewsFooter");
			container.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewLoading, {})));
			const limit = await storageManager.getSetting("reviewCount", 20);
			let reviews = null;
			try {
				reviews = await fetchMovieReviews(movieId, 1, limit);
			} catch (err) {
				if (err.toString().includes("簽名已過期")) show.error("生成签名失败, 请检查系统时间及时区是否正确!");
				clog.error("获取评论失败:", err);
				console.error("获取评论失败:", err);
			} finally {
				$("#reviewsLoading").remove();
			}
			if (!reviews) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewError, {})));
				$("#retryFetchReviews").on("click", async () => {
					$("#retryFetchReviews").parent().remove();
					await this.fetchAndDisplayReviews(movieId);
				});
				return;
			}
			if (reviews.length === 0) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(ReviewEmpty, {})));
				return;
			}
			const filterKeywords = await storageManager.getReviewFilterKeywordList();
			this.displayReviews(reviews, container, filterKeywords);
			if (reviews.length === limit) {
				footer.html(jsxToString((0, import_jsx_runtime.jsx)(ReviewLoadMore, {})));
				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) {
						console.error("加载更多评论失败:", err);
					} finally {
						loadMoreBtn.text("加载失败, 请点击重试").prop("disabled", false);
					}
					if (moreReviews) {
						this.displayReviews(moreReviews, container, filterKeywords);
						if (moreReviews.length < limit) {
							loadMoreBtn.remove();
							$("#reviewsEnd").show();
						} else loadMoreBtn.text("加载更多评论").prop("disabled", false);
					}
				});
			} else footer.html(jsxToString((0, import_jsx_runtime.jsx)(ReviewEnd, {})));
		}
		displayReviews(reviews, container, filterKeywords) {
			if (reviews.length) {
				reviews.forEach((review) => {
					if (filterKeywords.some((keyword) => review.content.includes(keyword))) return;
					const stars = Array(review.score).fill("<i class=\"icon-star\"></i>").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);
				});
				this.rightClickFilter();
			}
		}
		async rightClickFilter() {
			if (await storageManager.getSetting("enableTitleSelectFilter", "yes") === "yes") utils.rightClick(document.body, ".review-content", async (event) => {
				const selectedText = window.getSelection().toString();
				if (selectedText) {
					event.preventDefault();
					await utils.q(event, `是否将 '${selectedText}' 加入评论区关键词?`, async () => {
						await storageManager.saveReviewFilterKeyword(selectedText);
						show.ok("操作成功, 刷新页面后生效");
					});
				}
			});
		}
	};
	var BLACKLIST_DEFAULT_LABEL = "加入黑名单";
	var BLACKLIST_DEFAULT_COLOR = "#d22020";
	var BLACKLIST_TIP = "将演员加入黑名单, 后续有作品更新也会纳入屏蔽中";
	var FILTER_ALL_TIP = "一键屏蔽已选分类的视频列表至鉴定记录中";
	var SORT_DEFAULT_LABEL = "当前排序方式: 默认";
	function menuBtnStyle(backgroundColor) {
		return { backgroundColor: `${backgroundColor} !important` };
	}
	function MenuButtonBoxHtml({ blacklistLabel = BLACKLIST_DEFAULT_LABEL, blacklistColor = BLACKLIST_DEFAULT_COLOR, actorsPage = false, 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: "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: "menu-btn main-tab-btn",
					style: menuBtnStyle("#2caac0"),
					children: (0, import_jsx_runtime.jsx)("span", { children: "打开已收藏" })
				}),
				actorsPage && (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("a", {
					id: "addBlacklistBtn",
					className: "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.jsx)("a", {
					id: "filterAllVideo",
					className: "menu-btn main-tab-btn",
					style: {
						backgroundColor: "#e8ab39 !important",
						marginRight: "30px!important"
					},
					"data-tip": FILTER_ALL_TIP,
					children: (0, import_jsx_runtime.jsx)("span", { children: "一键屏蔽所有作品" })
				})] }),
				tagsPage && (0, import_jsx_runtime.jsx)("a", {
					id: "addBlacklistBtn",
					className: "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: "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: "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: "menu-btn main-tab-btn",
					style: menuBtnStyle("#8783ab"),
					children: ` ${sortLabel} `
				})
			]
		})] });
	}
	var HAS_DOWN_TEXT = "📥️ 已下载";
	var ListPageButtonPlugin = class extends BasePlugin {
		loadObj = null;
		getName() {
			return "ListPageButtonPlugin";
		}
		async handle() {
			if (!window.isListPage) return;
			await this.createMenuBtn();
			this.bindEvent();
			if (await storageManager.getSetting("autoPage") === "yes") $("#sort-toggle-btn").hide();
			else this.sortItems().then();
		}
		async createMenuBtn() {
			if (isJavdbSite) {
				const isActorsPage = currentHref.includes("/actors/");
				let containerEl = $(".main-tabs, .tabs");
				let blacklistLabel = "加入黑名单";
				let blacklistColor = "#d22020";
				let tagBlacklistEntry = null;
				if (isActorsPage) {
					containerEl = $(".toolbar, .section-addition").filter(":last");
					const blacklist = await storageManager.getBlacklist();
					const actressInfo = this.getActressPageInfo();
					if (blacklist.find((entry) => entry.starId === actressInfo.starId)) {
						blacklistLabel = "已加入黑名单";
						blacklistColor = "#885d5d";
					}
				} else 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,
					actorsPage: isActorsPage,
					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);
			});
			$("#filterAllVideo").on("click", async (event) => {
				const position = {
					clientX: event.clientX,
					clientY: event.clientY + 80
				};
				const nameEl = $(".actor-section-name");
				if (nameEl.length === 0) {
					show.error("获取演员名称失败");
					return;
				}
				const actressName = nameEl.text().trim().split(",")[0];
				utils.q(position, "一键屏蔽视频列表?", async () => {
					this.loadObj = loading();
					try {
						await blacklistPlugin.filterAllVideo(actressName);
						window.refresh();
					} catch (err) {
						console.error(err);
					} finally {
						this.loadObj?.close();
					}
				});
			});
		}
		async sortItems() {
			if (currentHref.includes("handle") || currentHref.includes("advanced_search")) return;
			const autoPage = await storageManager.getSetting("autoPage");
			if (isSearchOrUserPage || autoPage === "yes") 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.sort((itemA, itemB) => $(itemA).data("original-index") - $(itemB).data("original-index")).appendTo(listEl);
			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);
				}
				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) => b.createDate - 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);
				clog.debug("打开已收藏", carNum, url);
			}
		}
	};
	var auto_page_plugin_default = ".jhs-scroll {\n    text-align: center;\n    padding-top: 20px;\n    font-size: 14px;\n}\n.jhs-scroll.waterfall-loading {\n    color: #000;\n}\n.jhs-scroll.waterfall-error {\n    color: #f44336;\n    cursor: pointer;\n}\n.jhs-scroll.waterfall-no-more {\n    color: #4caf50;\n}\n";
	var AutoPagePlugin = class extends BasePlugin {
		preloadDistance = 500;
		currentPage = this.getInitialPageNumber();
		pageItems = [];
		container = null;
		loader = null;
		nextUrl = void 0;
		hasMore = false;
		isLoading = false;
		getName() {
			return "AutoPagePlugin";
		}
		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) {
				console.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
			});
			loader.addEventListener("click", () => {
				if (loader.classList.contains("waterfall-error")) this.loadNextPage().then();
			});
			window.addEventListener("scroll", () => {
				this.checkLoad();
				this.checkScrollPosition();
			});
			const nextLinkEl = document.querySelector(selectorConfig.nextPageSelector);
			this.nextUrl = nextLinkEl == null ? void 0 : nextLinkEl.href;
			this.hasMore = !!this.nextUrl;
			setTimeout(() => {
				this.checkLoad();
			}, 1e3);
			if (!this.hasMore) this.setState("waterfall-no-more", "已经到底了");
		}
		async loadNextPage() {
			if (await storageManager.getSetting("autoPage", "yes") === "no") {
				this.setState("waterfall-loading", "");
				return;
			}
			if (this.isLoading || !this.nextUrl) return;
			this.isLoading = true;
			this.setState("waterfall-loading", "加载中...");
			const selectorConfig = this.getSelector();
			try {
				const pageNum = utils.getUrlParam(this.nextUrl, "page");
				let maxPage = 60;
				if (currentHref.includes("c11")) maxPage = 30;
				if (isJavdbSite && pageNum > maxPage || currentHref.includes("month")) {
					const beyond60Plugin = this.getBean("Beyond60Plugin");
					if (beyond60Plugin) {
						const { html, nextUrl: beyondNextUrl, hasMore: beyondHasMore } = await beyond60Plugin.handleBeyond60(this.nextUrl);
						if (html) {
							const scrollHeight = this.container.scrollHeight;
							this.pageItems.push({
								page: this.currentPage + 1,
								top: scrollHeight,
								url: this.nextUrl
							});
							$(".movie-list").append(html);
						}
						this.hasMore = beyondHasMore;
						this.nextUrl = beyondNextUrl;
						const paginationHtml = beyond60Plugin.createPagination(pageNum, beyondHasMore);
						$(".pagination").html(paginationHtml);
						this.setState("waterfall-loading", "");
						if (!this.hasMore) this.setState("waterfall-no-more", "已经到底了");
						return;
					}
				}
				const responseHtml = await gmHttp.get(this.nextUrl);
				clog.log("请求下一页内容:", this.nextUrl);
				const $dom = utils.htmlTo$dom(responseHtml);
				const items = $dom.find(this.getSelector().requestDomItemSelector);
				const existingList = this.getBoxCarInfoList();
				const newList = this.getBoxCarInfoList(items);
				if (this.checkDuplicateCarNumbers(existingList, newList)) {
					this.nextUrl = null;
					this.hasMore = false;
					this.setState("waterfall-error", "翻页内容出现重复数据, 页码受JavDB限制, 已停止瀑布流");
					return;
				}
				const scrollHeight = this.container.scrollHeight;
				this.pageItems.push({
					page: this.currentPage + 1,
					top: scrollHeight,
					url: this.nextUrl
				});
				const listPagePlugin = this.getBean("ListPagePlugin");
				const coverImgs = $dom.find(this.getSelector().coverImgSelector);
				listPagePlugin.replaceHdImg(coverImgs);
				$(this.getSelector().boxSelector).append(items);
				const nextLinkEl = $dom.find(selectorConfig.nextPageSelector);
				this.nextUrl = nextLinkEl == null ? void 0 : nextLinkEl.attr("href");
				this.hasMore = !!this.nextUrl;
				const paginationEl = $dom.find(".pagination");
				$(".pagination").replaceWith(paginationEl);
				this.setState("waterfall-loading", "");
				if (!this.hasMore) this.setState("waterfall-no-more", "已经到底了");
			} catch (err) {
				clog.error("加载失败:", err);
				this.setState("waterfall-error", "加载失败,点击重试");
			} finally {
				this.isLoading = false;
			}
		}
		checkScrollPosition() {
			const scrollY = window.scrollY;
			for (let i = this.pageItems.length - 1; i >= 0; i--) {
				const item = this.pageItems[i];
				if (scrollY >= item.top) {
					if (this.currentPage !== item.page) {
						this.currentPage = item.page;
						this.updatePageUrl(item.url);
					}
					break;
				}
			}
		}
		checkLoad() {
			if (!this.loader) return;
			if (this.loader.getBoundingClientRect().top < window.innerHeight + this.preloadDistance) this.loadNextPage().then();
		}
		async shouldDisablePaging() {
			if (!window.isListPage) return true;
			await storageManager.getSetting("autoPage", "yes");
			return [
				"search?q",
				"handlePlayback=1",
				"handleTop=1",
				"/want_watch_videos",
				"/watched_videos",
				"/advanced_search?type=100"
			].some((pattern) => currentHref.includes(pattern));
		}
		updatePageUrl_old(url) {
			window.history.pushState({}, "", url);
		}
		updatePageUrl(url) {
			window.history.replaceState({}, "", url);
		}
		setState(stateClass, text) {
			this.loader.className = `jhs-scroll ${stateClass}`;
			this.loader.textContent = text;
		}
	};
	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)" }
			})]
		});
	}
	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", {}), " 注意: 当前页面非第一页, 屏蔽数据将从此页面开始"] })
		] });
	}
	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,
					")"
				]
			})
		] });
	}
	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 BlacklistUrlTypeCell({ hasTag }) {
		return (0, import_jsx_runtime.jsx)("span", {
			style: { color: hasTag ? "#cc4444" : void 0 },
			children: hasTag ? "按所选分类屏蔽" : "未筛选分类"
		});
	}
	function BlacklistStatusCell({ tipText, statusText }) {
		return (0, import_jsx_runtime.jsx)("span", {
			"data-tip": tipText,
			style: { color: tipText ? "#cc4444" : void 0 },
			children: statusText
		});
	}
	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 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] });
	}
	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" }
			})
		] });
	}
	var BlacklistPlugin = class extends BasePlugin {
		loadObj;
		tableObj;
		nextPageLink;
		lastPageLink;
		checkBlacklist_ruleTime = 8760;
		currentCarCount = 0;
		getName() {
			return "BlacklistPlugin";
		}
		async addBlacklist(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 = this.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) {
						this.loadObj = loading();
						try {
							await storageManager.addBlacklistItem({
								starId,
								name,
								allName,
								role,
								movieType,
								url: blacklistUrl
							});
							await this.filterActorVideo(name, starId);
							const okShow = show.ok(`屏蔽结束,是否跳转到最后一页: ${this.lastPageLink}`, {
								duration: -1,
								close: true,
								onClick: () => {
									okShow.closeShow();
									window.location.href = this.lastPageLink;
								}
							});
						} catch (error) {
							clog.error(error);
							const errorShow = show.error("发生错误, 是否填转到解析失败的那一页? (点击并跳转)", {
								duration: -1,
								close: true,
								onClick: () => {
									errorShow.closeShow();
									window.location.href = this.nextPageLink;
								}
							});
						} finally {
							this.loadObj.close();
						}
					} else show.error("当前有定时任务在后台执行中, 无法发起此操作");
				}).catch((lockError) => {
					console.error("锁任务出现错误:", lockError);
					clog.error("锁任务出现错误:", lockError);
				});
			});
		}
		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() {
			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, this.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
				};
			});
			this.currentCarCount = finalData.reduce((sum, row) => sum + (row.count || 0), 0);
			return finalData;
		}
		async loadTableData() {
			this.checkBlacklist_ruleTime = await storageManager.getSetting("checkBlacklist_ruleTime") || 8760;
			const data = await this.getTableData();
			this.tableObj = new Tabulator("#table-container", {
				layout: "fitColumns",
				placeholder: "暂无数据",
				virtualDom: true,
				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: this.currentCarCount
				})),
				responsiveLayout: "collapse",
				responsiveLayoutCollapse: true,
				columnDefaults: {
					headerHozAlign: "center",
					hozAlign: "center"
				},
				index: "starId",
				columns: [
					{
						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 = `停更${this.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("操作成功");
										this.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, {}));
						}
					}
				],
				initialSort: [{
					column: "createTime",
					dir: "desc"
				}],
				locale: "zh-cn",
				langs: { "zh-cn": { pagination: {
					first: "首页",
					first_title: "首页",
					last: "尾页",
					last_title: "尾页",
					prev: "上一页",
					prev_title: "上一页",
					next: "下一页",
					next_title: "下一页",
					all: "所有",
					page_size: "每页行数"
				} } }
			});
		}
		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) {
			let items;
			let nextPageHref;
			if ($dom) {
				items = $dom.find(this.getSelector().requestDomItemSelector);
				nextPageHref = $dom.find(this.getSelector().nextPageSelector).attr("href");
			} else {
				items = $(this.getSelector().itemSelector);
				nextPageHref = $(this.getSelector().nextPageSelector).attr("href");
			}
			if (nextPageHref && items.length === 0) {
				show.error("解析列表失败");
				throw new Error("解析列表失败");
			}
			for (const itemEl of items) {
				const $item = $(itemEl);
				const { carNum, url, publishTime } = this.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) {
					console.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();
				const $parsed = $(domParser.parseFromString(pageHtml, "text/html"));
				await this.filterAllVideo(names, $parsed);
			} else {
				show.ok("执行结束!");
				refresh();
			}
		}
		async filterActorVideo(name, starId, $dom) {
			const { nextPageLink } = await this.parseAndSaveFilterInfo($dom, name, starId);
			this.nextPageLink = nextPageLink;
			if (nextPageLink) {
				let nextDom;
				this.lastPageLink = nextPageLink;
				show.info("请不要关闭窗口, 正在解析下一页:" + nextPageLink);
				const pageNum = utils.getUrlParam(nextPageLink, "page") || 0;
				const beyond60Plugin = this.getBean("Beyond60Plugin");
				if (isJavdbSite && beyond60Plugin && 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(pageHtml);
				}
				await this.filterActorVideo(name, starId, nextDom);
			} else {
				show.ok("执行结束!");
				refresh();
			}
		}
		async parseAndSaveFilterInfo($dom, names, starId) {
			let items;
			let nextPageHref;
			if ($dom) {
				let siteType = JAVDB;
				items = $dom.find(this.getSelector(siteType).requestDomItemSelector);
				nextPageHref = $dom.find(this.getSelector(siteType).nextPageSelector).attr("href");
			} else {
				items = $(this.getSelector().itemSelector);
				nextPageHref = $(this.getSelector().nextPageSelector).attr("href");
			}
			if (nextPageHref && items.length === 0) return {
				nextPageLink: null,
				lastPublishTime: null
			};
			let carList = [];
			let lastPublishTime = null;
			for (const itemEl of items) {
				const $item = $(itemEl);
				const { carNum, url, publishTime } = this.getBean("ListPagePlugin").findCarNumAndHref($item);
				lastPublishTime ||= publishTime;
				if (url && carNum) carList.push({
					carNum,
					url,
					names,
					actionType: FILTER_ACTION,
					starId,
					publishTime
				});
			}
			try {
				await storageManager.batchSaveBlacklistCarList(carList);
			} catch (error) {
				clog.error("保存失败:", error);
				console.error("保存失败:", error);
			}
			return {
				nextPageLink: nextPageHref,
				lastPublishTime
			};
		}
	};
	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;
		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} <br/> <span style='color: #f40'>执行此功能前请记得备份数据</span>`, async () => {
				const loadingOverlay = loading();
				try {
					await this.parseMovieList();
				} catch (error) {
					console.error(error);
				} finally {
					loadingOverlay.close();
				}
			});
		}
		async parseMovieList(rootEl) {
			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: null,
						actionType: this.type,
						publishTime: metaText
					});
				} catch (error) {
					console.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) {
						console.error(request);
						show.error("加载下一页失败:" + request.message);
					}
				});
			} else {
				show.ok("导入结束!");
				refresh();
			}
		}
	};
	function RelatedContainers() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("div", { id: "relatedContainer" }), (0, import_jsx_runtime.jsx)("div", { id: "relatedFooter" })] });
	}
	function RelatedEmpty() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: "无清单"
		});
	}
	function RelatedEnd() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: {
				textAlign: "center",
				padding: "10px",
				color: "#666",
				marginTop: "10px"
			},
			children: "已加载全部清单"
		});
	}
	function RelatedError() {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: ["获取清单失败", (0, import_jsx_runtime.jsx)("a", {
				id: "retryFetchRelateds",
				href: "javascript:;",
				style: {
					marginLeft: "10px",
					color: "#1897ff",
					textDecoration: "none"
				},
				children: "重试"
			})]
		});
	}
	function RelatedHeader({ 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" },
					children: "相关清单"
				}),
				(0, import_jsx_runtime.jsxs)("a", {
					id: "relatedFold",
					style: {
						marginLeft: "8px",
						color: "#1897ff",
						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 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
					]
				})
			]
		});
	}
	function RelatedLoadMore() {
		return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)("button", {
			id: "loadMoreRelateds",
			style: {
				width: "100%",
				backgroundColor: "#e1f5fe",
				border: "none",
				padding: "10px",
				marginTop: "10px",
				cursor: "pointer",
				color: "#0277bd",
				fontWeight: "bold",
				borderRadius: "4px"
			},
			children: "加载更多清单"
		}), (0, import_jsx_runtime.jsx)("div", {
			id: "relatedEnd",
			style: {
				display: "none",
				textAlign: "center",
				padding: "10px",
				color: "#666",
				marginTop: "10px"
			},
			children: "已加载全部清单"
		})] });
	}
	function RelatedLoading() {
		return (0, import_jsx_runtime.jsx)("div", {
			id: "relatedLoading",
			style: {
				marginTop: "15px",
				backgroundColor: "#ffffff",
				padding: "10px",
				marginLeft: "-10px"
			},
			children: "获取清单中..."
		});
	}
	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)(RelatedHeader, {
				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)(RelatedContainers, {})));
			if (isExpanded === "yes") await this.fetchAndDisplayRelateds(movieId);
		}
		async fetchAndDisplayRelateds(movieId) {
			const container = $("#relatedContainer");
			const footer = $("#relatedFooter");
			container.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedLoading, {})));
			const limit = 20;
			let list = null;
			try {
				list = await fetchRelatedCollections(movieId, 1, limit);
			} catch (err) {
				if (err.toString().includes("簽名已過期")) show.error("生成签名失败, 请检查系统时间及时区是否正确!");
				clog.error("获取清单失败:", err);
				console.error("获取清单失败:", err);
			} finally {
				$("#relatedLoading").remove();
			}
			if (!list) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedError, {})));
				$("#retryFetchRelateds").on("click", async () => {
					$("#retryFetchRelateds").parent().remove();
					await this.fetchAndDisplayRelateds(movieId);
				});
				return;
			}
			if (list.length === 0) {
				container.append(jsxToString((0, import_jsx_runtime.jsx)(RelatedEmpty, {})));
				return;
			}
			this.displayRelateds(list, container);
			if (list.length === limit) {
				footer.html(jsxToString((0, import_jsx_runtime.jsx)(RelatedLoadMore, {})));
				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) {
						console.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)(RelatedEnd, {})));
		}
		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 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");
				}
			}
		}
	};
	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.actress-card {\n    background: #fff;\n    border: 1px solid #e0e0e0;\n    border-radius: 8px;\n    box-shadow: 0 4px 8px rgba(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.actress-card:hover {\n    box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);\n}\n.actress-card-name {\n    font-size: 1.2em;\n    font-weight: bold;\n    color: #007bff;\n    margin-top: 10px;\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.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 rgba(0, 0, 0, 0.1);\n}\n\n.card-tag {\n    position: absolute;\n    top: 15px; /* 调整标签距离顶部的距离 */\n    right: -50px; /* 调整标签距离右侧的距离,负值让它移到外面一点 */\n\n    width: 150px; /* 标签的宽度,影响斜角长度 */\n    padding: 5px 0; /* 上下内边距 */\n    text-align: center;\n\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 rgba(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@media (max-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 rgba(0, 0, 0, 0.08),\n        -8px -8px 16px rgba(255, 255, 255, 1);\n    transition: all 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 rgba(0, 0, 0, 0.1),\n        inset -5px -5px 10px rgba(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.btn-check-actress:hover svg path {\n    fill: #388e3c;\n}\n\n.btn-edit-actress svg path {\n    fill: #ffc107;\n}\n.btn-edit-actress:hover svg path {\n    fill: #ffb300;\n}\n\n.btn-delete-actress svg path {\n    fill: #f44336;\n}\n.btn-delete-actress:hover svg path {\n    fill: #d32f2f;\n}\n";
	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#gfriends-prompt {\n    color: #555;\n    font-weight: 500;\n    border-bottom: 1px solid #eee;\n    padding-bottom: 10px;\n}\n#gfriends-image-list {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 15px;\n    justify-content: center;\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 rgba(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.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.gfriends-image-item-wrapper:hover {\n    transform: translateY(-4px) scale(1.02);\n    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);\n}\n.gfriends-selectable-img.is-selected {\n    border-color: #ff6347;\n    box-shadow: 0 0 0 3px #ff6347;\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: rgba(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";
	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" })
			]
		});
	}
	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: "切换源会清除本地缓存的数据,并在下次搜索时重新加载。"
				})
			]
		});
	}
	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))
				})
			})]
		});
	}
	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));
		let 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,
					" 页)"
				]
			})
		] });
	}
	function NewVideoDialogTitle() {
		return (0, import_jsx_runtime.jsx)("span", {
			style: { padding: "0 10px" },
			"data-tip": "数据来源: 女优页面首页,含磁链分类",
			children: "新作品检测 ❓"
		});
	}
	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() {
			const $container = $("#actress-card-container");
			if (!$container.length) return;
			let favoriteActresses = await storageManager.getFavoriteActressList();
			const typeFilter = $("#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 / this.pageSize);
			const startIndex = (this.currentPage - 1) * this.pageSize;
			const endIndex = startIndex + this.pageSize;
			const pageActresses = sortedActresses.slice(startIndex, endIndex);
			const javDbUrl = await this.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);
				let typeLabel = "未知";
				let typeColor = "#9E9E9E";
				if (actress.actressType === "uncensored") {
					typeLabel = "无码";
					typeColor = "#4CAF50";
				} else if (actress.actressType === "censored") {
					typeLabel = "有码";
					typeColor = "#FF9800";
				}
				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: this.editSvg,
					deleteSvg: this.deleteSvg,
					btnStyle,
					typeLabel,
					typeColor,
					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);
				utils.q(event, `是否取消收藏 ${actress.name}?`, async () => {
					const uncollectUrl = `${await this.getBean("OtherSitePlugin").getJavDbUrl()}/actors/${starId}/uncollect`;
					const csrfToken = document.querySelector("meta[name=csrf-token]")?.getAttribute("content") ?? "";
					const response = await gmHttp.post(uncollectUrl, null, { "x-csrf-token": csrfToken });
					if (response.includes("removeClass")) {
						await storageManager.removeFavoriteActress(starId);
						this.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) this.editActress(actress);
				else show.error(`未找到 starId 为 ${starId} 的女优记录。`);
			});
			this.renderPagination(totalCount, totalPages);
			show.ok("加载完成");
		}
		async editActress(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 this.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 = $("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 = $("#edit-actress-avatar").val().trim();
					const name = $("#edit-actress-name").val().trim();
					const allNameText = $("#edit-actress-allname").val().trim();
					const newVideoText = $("#edit-actress-newvideolist").val().trim();
					const remark = $("#edit-remark").val().trim();
					const actressType = $("#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 {
						this.renderActressCards().then();
						show.ok(`女优 ${name} 信息已更新`);
						layer.close(layerIndex);
					}
				}
			});
		}
		renderPagination(totalCount, totalPages) {
			const page = this.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 !== this.currentPage) {
					this.currentPage = targetPage;
					this.renderActressCards();
				}
			});
		}
		async 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.message || error}`);
				return;
			} finally {
				loader.close();
			}
			if (avatarUrls.length === 0) {
				show.error(`未找到与 '${searchNames.join("、")}' 相关的头像。请检查名称。`);
				return;
			}
			const dialogContent = "<style>" + avatar_select_dialog_default + "</style>" + 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 = $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 = $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 = {
		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 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: "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: "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: "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: "menu-btn history-hasWatchBtn",
							style: {
								backgroundColor: watchedColor,
								marginBottom: "5px"
							},
							children: watchedText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "menu-btn history-favoriteBtn",
							style: {
								backgroundColor: favoriteColor,
								marginBottom: "5px"
							},
							children: favoriteText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "menu-btn history-filterBtn",
							style: {
								backgroundColor: blockColor,
								marginBottom: "5px"
							},
							children: blockText
						})
					]
				})]
			}), (0, import_jsx_runtime.jsx)("a", {
				className: "menu-btn history-detailBtn",
				style: {
					backgroundColor: "#3397de",
					color: "white",
					marginBottom: "5px"
				},
				children: (0, import_jsx_runtime.jsx)("span", { children: "📄 详情页" })
			})]
		});
	}
	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: "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: "menu-btn multiple-history-hasWatchBtn",
							style: {
								backgroundColor: watchedColor,
								marginBottom: "5px"
							},
							children: watchedText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "menu-btn multiple-history-favoriteBtn",
							style: {
								backgroundColor: favoriteColor,
								marginBottom: "5px"
							},
							children: favoriteText
						}),
						(0, import_jsx_runtime.jsx)("a", {
							className: "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;
		}
	}
	function HistorySourceCell({ text, color }) {
		return (0, import_jsx_runtime.jsx)("span", {
			style: { color },
			children: text
		});
	}
	function HistoryStatusCell({ text, color }) {
		return (0, import_jsx_runtime.jsx)("span", {
			style: { color },
			children: text
		});
	}
	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 rgba(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,
						url: href,
						names: null,
						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) => {
				event.preventDefault();
				event.stopPropagation();
				const btn = $(event.currentTarget);
				const selectedRows = this.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 (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("操作成功");
						}
						this.tableObj.deselectRow();
						this.reloadTable().then();
					} catch (err) {
						console.error(err);
					} finally {
						loader.close();
					}
				});
			});
		}
		async getDataList(page, size, sort) {
			const carList = await storageManager.getCarList();
			this.allCount = carList.length;
			this.filterCount = 0;
			this.favoriteCount = 0;
			this.hasWatchCount = 0;
			carList.forEach((car) => {
				switch (car.status) {
					case FILTER_ACTION:
						this.filterCount++;
						break;
					case FAVORITE_ACTION:
						this.favoriteCount++;
						break;
					case HAS_WATCH_ACTION: this.hasWatchCount++;
				}
			});
			$("#dataType option[value=\"all\"]").text(`所有 (${this.allCount})`);
			$("#dataType option[value=\"filter\"]").text(`${BLOCKED_TEXT} (${this.filterCount})`);
			$("#dataType option[value=\"favorite\"]").text(`${FAVORITED_TEXT} (${this.favoriteCount})`);
			$("#dataType option[value=\"hasWatch\"]").text(`${WATCHED_TEXT} (${this.hasWatchCount})`);
			const selectedType = $("#dataType").val();
			let filtered = selectedType === "all" ? carList : carList.filter((car) => car.status === selectedType);
			const searchText = $("#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
			};
		}
		async loadTableData() {
			this.tableObj = new Tabulator("#table-container", {
				layout: "fitColumns",
				placeholder: "暂无数据",
				virtualDom: true,
				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 this.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} 条记录`,
				responsiveLayout: "collapse",
				responsiveLayoutCollapse: true,
				columnDefaults: {
					headerHozAlign: "center",
					hozAlign: "center"
				},
				selectableRowsPersistence: false,
				index: "carNum",
				columns: [
					{
						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 `<a class="table-link-param">${carNum.substring(0, dashIndex + 1)}</a>${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) => `<a class="table-link-param">${part}</a>`).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) => {
							let url = cell.getData().url;
							if (url) if (url.includes("javdb")) return jsxToString((0, import_jsx_runtime.jsx)(HistorySourceCell, {
								text: "Javdb",
								color: "#d34f9e"
							}));
							else return jsxToString((0, import_jsx_runtime.jsx)(HistorySourceCell, {
								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)(HistoryStatusCell, {
								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", () => {
									this.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
							}));
						}
					}
				],
				initialSort: [{
					column: "updateDate",
					dir: "desc"
				}],
				locale: "zh-cn",
				langs: { "zh-cn": { pagination: {
					first: "首页",
					first_title: "首页",
					last: "尾页",
					last_title: "尾页",
					prev: "上一页",
					prev_title: "上一页",
					next: "下一页",
					next_title: "下一页",
					all: "所有",
					page_size: "每页行数"
				} } }
			});
			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=" + carInfo.carNum, "_blank");
					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 = $("#edit-names").val().trim();
					const status = $("#edit-status").val();
					const url = $("#edit-url").val().trim();
					const remark = $("#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 image_preview_default = ".image-hover-preview {\n    position: fixed;\n    display: none;\n    z-index: 9999999999; /*__Z_INDEX__*/\n    border-radius: 4px;\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n    overflow: hidden;\n    pointer-events: none;\n    opacity: 0;\n    transition: opacity 0.2s ease; /*__TRANSITION__*/\n    background-color: #fff;\n}\n\n.image-hover-preview.active {\n    opacity: 1;\n}\n\n.image-hover-preview img {\n    max-width: 1000px; /*__MAX_WIDTH__*/\n    max-height: 1000px; /*__MAX_HEIGHT__*/\n    display: block;\n    object-fit: contain;\n}\n\n.image-hover-preview::after {\n    content: '';\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    background: rgba(0, 0, 0, 0.03);\n    pointer-events: none;\n}\n\n.image-hover-preview.loading::before {\n    content: '加载中...';\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    color: #666;\n    font-size: 14px;\n}\n";
	var errorStyle = {
		padding: "10px",
		color: "#f00"
	};
	function ImagePreviewError() {
		return (0, import_jsx_runtime.jsx)("div", {
			style: errorStyle,
			children: "图片加载失败"
		});
	}
	function ImagePreviewImg({ src }) {
		return (0, import_jsx_runtime.jsx)("img", {
			src,
			alt: "预览图"
		});
	}
	var ImagePreview = class {
		config;
		preview = null;
		currentTarget = null;
		timer = null;
		imgElement = null;
		boundElements = new WeakSet();
		constructor(options = {}) {
			this.config = {
				selector: ".hover-preview",
				dataAttribute: "data-full",
				maxWidth: 1e3,
				maxHeight: 1e3,
				offsetX: 20,
				offsetY: 20,
				zIndex: 9999999999,
				transition: .2,
				autoAdjustPosition: true,
				...options
			};
			this.init();
		}
		init() {
			this.injectStyles();
			this.createPreviewElement();
			this.bindEvents();
		}
		injectStyles() {
			injectCss(image_preview_default.replace("9999999999; /*__Z_INDEX__*/", `${this.config.zIndex}; /*__Z_INDEX__*/`).replace("0.2s ease; /*__TRANSITION__*/", `${this.config.transition}s ease; /*__TRANSITION__*/`).replace("1000px; /*__MAX_WIDTH__*/", `${this.config.maxWidth}px; /*__MAX_WIDTH__*/`).replace("1000px; /*__MAX_HEIGHT__*/", `${this.config.maxHeight}px; /*__MAX_HEIGHT__*/`));
		}
		createPreviewElement() {
			this.preview = document.createElement("div");
			this.preview.className = "image-hover-preview";
			document.body.appendChild(this.preview);
		}
		bindEvents() {
			document.querySelectorAll(this.config.selector).forEach((element) => {
				if (!this.boundElements.has(element)) {
					element.addEventListener("mouseenter", (event) => this.handleMouseEnter(event));
					element.addEventListener("mouseleave", (event) => this.handleMouseLeave(event));
					element.addEventListener("mousemove", (event) => this.handleMouseMove(event));
					this.boundElements.add(element);
				}
			});
		}
		handleMouseEnter(event) {
			clearTimeout(this.timer);
			const target = event.currentTarget;
			this.currentTarget = target;
			const imgSrc = target.getAttribute(this.config.dataAttribute) || target.src;
			if (!imgSrc) return;
			const preview = this.preview;
			preview.innerHTML = "";
			preview.classList.add("loading");
			preview.style.display = "block";
			preview.classList.remove("active");
			const img = new Image();
			img.onload = () => {
				preview.classList.remove("loading");
				preview.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(ImagePreviewImg, { src: imgSrc }));
				this.imgElement = preview.querySelector("img");
				const { width, height } = this.calculateImageSize(img);
				preview.style.width = `${width}px`;
				preview.style.height = `${height}px`;
				preview.offsetHeight;
				preview.classList.add("active");
				this.handleMouseMove(event);
			};
			img.onerror = () => {
				preview.classList.remove("loading");
				preview.innerHTML = jsxToString((0, import_jsx_runtime.jsx)(ImagePreviewError, {}));
			};
			img.src = imgSrc;
		}
		calculateImageSize(img) {
			let width = img.naturalWidth;
			let height = img.naturalHeight;
			if (width > this.config.maxWidth || height > this.config.maxHeight) {
				const scale = Math.min(this.config.maxWidth / width, this.config.maxHeight / height);
				width *= scale;
				height *= scale;
			}
			return {
				width,
				height
			};
		}
		handleMouseMove(event) {
			const preview = this.preview;
			if (!this.currentTarget || !preview.classList.contains("active")) return;
			let { offsetX, offsetY } = this.config;
			let left = event.clientX + offsetX;
			let top = event.clientY + offsetY;
			if (this.config.autoAdjustPosition) {
				const previewWidth = preview.offsetWidth;
				const previewHeight = preview.offsetHeight;
				if (left + previewWidth > window.innerWidth) left = event.clientX - previewWidth - offsetX;
				if (top + previewHeight > window.innerHeight) top = event.clientY - previewHeight - offsetY;
				left = Math.max(0, left);
				top = Math.max(0, top);
			}
			preview.style.left = `${left}px`;
			preview.style.top = `${top}px`;
		}
		handleMouseLeave(_event) {
			const preview = this.preview;
			preview.classList.remove("active");
			preview.style.display = "none";
			this.currentTarget = null;
			this.imgElement = null;
		}
		destroy() {
			document.querySelectorAll(this.config.selector).forEach((element) => {
				if (this.boundElements.has(element)) {
					element.removeEventListener("mouseenter", this.handleMouseEnter);
					element.removeEventListener("mouseleave", this.handleMouseLeave);
					element.removeEventListener("mousemove", this.handleMouseMove);
					this.boundElements.delete(element);
				}
			});
			const preview = this.preview;
			if (preview && preview.parentNode) preview.parentNode.removeChild(preview);
		}
	};
	var setting_plugin_default = "__CSS_TEXT__ .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    word-wrap: break-word;\n    line-height: 1.5;\n    color: #333;\n    border: 1px solid #ddd;\n}\n\n.cache-item {\n    transition: all 0.2s ease;\n}\n.cache-item:hover {\n    box-shadow: 0 2px 8px rgba(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.setting-item {\n    display: flex;\n    align-items: baseline;\n    justify-content: space-between;\n    margin-bottom: 3px;\n    padding: 3px;\n    /*border: 1px solid #ddd;\n                    border-radius: 5px;*/\n}\n.simple-setting .setting-item {\n    align-items: center;\n}\n.setting-label {\n    font-size: 14px;\n    min-width: 160px;\n    font-weight: bold;\n    margin-right: 10px;\n}\n.form-content {\n    max-width: 160px;\n    min-width: 160px;\n}\n.form-content * {\n    width: 100%;\n    padding: 5px;\n    margin-right: 10px;\n    text-align: center;\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.keyword-remove {\n    margin-left: 6px;\n    cursor: pointer;\n    font-size: 12px;\n    line-height: 1;\n}\n.keyword-input {\n    padding: 6px 12px;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    font-size: 14px;\n    float: right;\n}\n.add-tag-btn {\n    padding: 6px 12px;\n    background-color: #e2e8f0;\n    color: #334155;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\n    font-size: 14px;\n    margin-left: 8px;\n    float: right;\n}\n.add-tag-btn:hover {\n    background-color: #cbd5e1;\n}\n.tag-box {\n    margin-top: 15px;\n}\n\n#saveBtn,\n#moreBtn,\n#helpBtn,\n#clean-all {\n    padding: 8px 20px;\n    background-color: #4caf50;\n    color: white;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\n    font-size: 16px;\n    margin-top: 10px;\n}\n#saveBtn:hover {\n    background-color: #45a049;\n}\n#moreBtn {\n    background-color: #5cb85c;\n    color: white;\n}\n#moreBtn:hover {\n    background-color: #4cae4c;\n}\n#helpBtn {\n    background-color: #e67e22;\n    color: white;\n}\n#helpBtn:hover {\n    background-color: #d35400;\n}\n.simple-setting,\n.mini-simple-setting {\n    display: none;\n    background: rgba(255, 255, 255, 1);\n    position: absolute;\n    top: __SIMPLE_SETTING_TOP__;\n    right: __SIMPLE_SETTING_RIGHT__;\n    z-index: 1000;\n    border: 1px solid #ddd;\n    border-radius: 4px;\n    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n    padding: 0;\n    margin-top: 5px; /* 稍微拉开一点距离 */\n    color: #333;\n}\n\n.mini-switch {\n    appearance: none;\n    -webkit-appearance: none;\n    width: 40px;\n    height: 20px;\n    background: #e0e0e0;\n    border-radius: 20px;\n    position: relative;\n    cursor: pointer;\n    outline: none;\n    /*transition: all 0.2s ease;*/\n}\n\n.mini-switch:checked {\n    background: #4caf50;\n}\n\n.mini-switch::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 rgba(0, 0, 0, 0.2);\n    /*transition: all 0.2s ease;*/\n}\n\n.mini-switch:checked::before {\n    left: calc(100% - 18px);\n}\n\n.side-menu-item {\n    padding: 10px 14px;\n    cursor: pointer;\n    color: #333;\n    border-left: 3px solid transparent;\n    transition: all 0.2s;\n    display: flex;\n    align-items: center;\n    gap: 5px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    font-size: 14px;\n}\n\n.side-menu-item .icon {\n    height: 24px;\n    width: 24px;\n}\n\n.side-menu-item:hover {\n    background-color: #e9e9e9;\n}\n\n.side-menu-item.active {\n    background-color: #e0e0e0;\n    border-left: 3px solid #5d87c2;\n    font-weight: bold;\n}\n\n.content-panel {\n    display: none;\n    margin-top: 20px;\n    padding: 0 10px 10px 0;\n    height: 100%;\n    overflow-x: hidden;\n    overflow-y: auto;\n}\n\n.content-panel.active {\n    display: block;\n}\n\ninput[type='checkbox']:disabled {\n    opacity: 0.6;\n    cursor: default !important;\n}\n";
	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.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 rgba(0, 0, 0, 0.1);\n}\n";
	var back_to_top_button_default = "#jhs-back-to-top {\n    position: fixed;\n    bottom: 40px;\n    right: 40px;\n    width: 44px;\n    height: 44px;\n    background-color: rgba(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: 9999;\n    opacity: 0;\n    visibility: hidden;\n    transform: translateY(20px) scale(0.9);\n    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n    border: 1px solid rgba(255, 255, 255, 0.05);\n    user-select: none;\n}\n#jhs-back-to-top:hover {\n    background-color: #ff8400;\n    color: #fff;\n    transform: translateY(0) scale(1);\n    box-shadow: 0 8px 20px rgba(255, 132, 0, 0.3);\n    border-color: #ff8400;\n}\n#jhs-back-to-top.show {\n    opacity: 1;\n    visibility: visible;\n    transform: translateY(0) scale(1);\n}\n#jhs-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_vertical_default = ".cover {\n    min-height: 350px !important;\n    overflow: hidden !important;\n    padding-top: 142% !important;\n}\n\n.cover img {\n    object-fit: cover !important;\n    object-position: 100% 50% !important; /*__OBJECT_POSITION__*/\n}\n\n/* bus的 */\n.masonry .movie-box img {\n    min-height: 500px !important;\n    object-fit: cover !important;\n    object-position: top right;\n}\n";
	var setting_image_mode_horizontal_default = ".cover {\n    min-height: auto !important;\n    padding-top: 67% !important;\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 HR_STYLE$1 = {
		border: 0,
		height: "1px",
		margin: "20px 0",
		backgroundImage: "linear-gradient(to right, rgba(0,0,0,0), rgba(159,137,137,0.75), rgba(0,0,0,0))"
	};
	function SettingDialog({ panelName, cacheItemsHtml, qualityOptionsHtml, isJavdbSite, blockText, favoriteText, watchedText }) {
		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: "15px 0",
					background: "#f5f5f5",
					borderRight: "1px solid #ddd",
					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 === "hotkey-panel" ? "active" : ""}`,
						"data-panel": "hotkey-panel",
						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.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.jsxs)("div", {
							id: "backup-panel",
							className: "content-panel",
							style: { display: panelName === "backup-panel" ? "block" : "none" },
							children: [
								(0, import_jsx_runtime.jsxs)("div", {
									style: { marginBottom: "20px" },
									children: [
										(0, import_jsx_runtime.jsx)("a", {
											id: "importBtn",
											className: "menu-btn",
											style: { backgroundColor: "#d25a88" },
											children: (0, import_jsx_runtime.jsx)("span", { children: "导入数据" })
										}),
										" ",
										(0, import_jsx_runtime.jsx)("a", {
											id: "exportBtn",
											className: "menu-btn",
											style: { backgroundColor: "#85d0a3" },
											children: (0, import_jsx_runtime.jsx)("span", { children: "导出数据" })
										})
									]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "WebDav备份"
									}), (0, import_jsx_runtime.jsxs)("div", { children: [
										(0, import_jsx_runtime.jsx)("a", {
											id: "webdavBackupListBtn",
											className: "menu-btn",
											style: { backgroundColor: "#5d87c2" },
											children: (0, import_jsx_runtime.jsx)("span", { children: "查看备份" })
										}),
										" ",
										(0, import_jsx_runtime.jsx)("a", {
											id: "webdavBackupBtn",
											className: "menu-btn",
											style: { backgroundColor: "#64bb69" },
											children: (0, import_jsx_runtime.jsx)("span", { children: "备份数据" })
										})
									] })]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "服务地址:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", { id: "webDavUrl" })
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "用户名:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", { id: "webDavUsername" })
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "密码:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", { id: "webDavPassword" })
									})]
								})
							]
						}),
						(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)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "打开待鉴定|已收藏 窗口数:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "number",
											id: "waitCheckCount",
											min: "1",
											max: "20",
											style: { width: "100%" }
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "已鉴定标签展示位置:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsxs)("select", {
											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.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsxs)("span", {
										className: "setting-label",
										style: {
											display: "flex",
											alignItems: "center",
											gap: "5px"
										},
										children: [
											"鉴定补录演员信息",
											" ",
											(0, import_jsx_runtime.jsx)("span", {
												"data-tip": "在列表页进行鉴定是获取不到演员名称的, 开启后, 额外解析详情页补录演员名称, 因发请求解析费时, 会被以往慢1秒左右",
												children: "❓"
											})
										]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "checkbox",
											id: "enableSaveActressCarInfo",
											className: "mini-switch"
										})
									})]
								}),
								(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "预览视频默认画质:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("select", {
											id: "videoQuality",
											dangerouslySetInnerHTML: { __html: qualityOptionsHtml }
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "评论区条数:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsxs)("select", {
											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.jsxs)("div", {
									className: `setting-item ${isJavdbSite ? "" : "do-hide"}`,
									children: [(0, import_jsx_runtime.jsxs)("span", {
										className: "setting-label",
										children: [
											"高亮已收藏演员",
											" ",
											(0, import_jsx_runtime.jsx)("span", {
												"data-tip": "详情页, 对已收藏的演员进行边框高亮提醒",
												children: "❓"
											})
										]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "checkbox",
											id: "enableFavoriteActresses",
											className: "mini-switch"
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: `setting-item ${isJavdbSite ? "" : "do-hide"}`,
									children: [(0, import_jsx_runtime.jsx)("span", {
										id: "highlightedTagLabel",
										className: "setting-label",
										children: "分类标签|高亮演员-边框样式:"
									}), (0, import_jsx_runtime.jsxs)("div", {
										className: "form-content",
										style: {
											display: "flex",
											alignItems: "center"
										},
										children: [(0, import_jsx_runtime.jsx)("input", {
											type: "number",
											id: "highlightedTagNumber",
											min: "0",
											max: "20"
										}), (0, import_jsx_runtime.jsx)("input", {
											type: "color",
											id: "highlightedTagColor"
										})]
									})]
								}),
								(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "请求超时时间(毫秒):"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "number",
											id: "httpTimeout",
											min: "1000",
											max: "10000",
											style: { width: "100%" }
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "请求失败重试次数:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "number",
											id: "httpRetryCount",
											min: "0",
											max: "10",
											style: { width: "100%" }
										})
									})]
								}),
								(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "启用控制台日志:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsxs)("select", {
											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.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "日志最大行数:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "number",
											id: "clogMsgCount",
											min: "100",
											max: "3000",
											style: { width: "100%" }
										})
									})]
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							id: "domain-panel",
							className: "content-panel",
							style: { display: panelName === "domain-panel" ? "block" : "none" },
							children: [(0, import_jsx_runtime.jsxs)("div", {
								className: "setting-item",
								children: [(0, import_jsx_runtime.jsx)("span", {
									className: "setting-label",
									children: "域名 - MissAv:"
								}), (0, import_jsx_runtime.jsx)("div", {
									className: "form-content",
									children: (0, import_jsx_runtime.jsx)("input", { id: "missAvUrl" })
								})]
							}), (0, import_jsx_runtime.jsxs)("div", {
								className: "setting-item",
								children: [(0, import_jsx_runtime.jsx)("span", {
									className: "setting-label",
									children: "域名 - SupJav:"
								}), (0, import_jsx_runtime.jsx)("div", {
									className: "form-content",
									children: (0, import_jsx_runtime.jsx)("input", { id: "supJavUrl" })
								})]
							})]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							id: "hotkey-panel",
							className: "content-panel",
							style: { display: panelName === "hotkey-panel" ? "block" : "none" },
							children: [
								(0, import_jsx_runtime.jsx)("p", {
									style: {
										color: "#666",
										fontSize: "0.9em"
									},
									children: "修改后, 刷新页面生效"
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsxs)("span", {
										className: "setting-label",
										children: [blockText, ":"]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											id: "filterHotKey",
											placeholder: "录入快捷键",
											"data-default-hotkey": "a"
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsxs)("span", {
										className: "setting-label",
										children: [favoriteText, ":"]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											id: "favoriteHotKey",
											placeholder: "录入快捷键",
											"data-default-hotkey": "s"
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsxs)("span", {
										className: "setting-label",
										children: [watchedText, ":"]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											id: "hasWatchHotKey",
											placeholder: "录入快捷键"
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "⏩ 快进:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											id: "speedVideoHotKey",
											placeholder: "录入快捷键",
											"data-default-hotkey": "z"
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "▲ 折叠:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											id: "foldCategoryHotKey",
											placeholder: "录入快捷键"
										})
									})]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsx)("span", {
										className: "setting-label",
										children: "💻 控制台:"
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											id: "clogHotKey",
											placeholder: "录入快捷键"
										})
									})]
								}),
								(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsxs)("span", {
										className: "setting-label",
										children: [
											(0, import_jsx_runtime.jsx)("span", {
												"data-tip": "列表页,鼠标放置图片上时可使用快捷键",
												children: "❓"
											}),
											" ",
											"对视频列表页启用快捷键:"
										]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "form-content",
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "checkbox",
											id: "enableImageHotKey",
											className: "mini-switch"
										})
									})]
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							id: "filter-panel",
							className: "content-panel",
							style: { display: panelName === "filter-panel" ? "block" : "none" },
							children: [
								(0, import_jsx_runtime.jsxs)("div", {
									className: "setting-item",
									children: [(0, import_jsx_runtime.jsxs)("span", {
										className: "setting-label",
										children: [
											"启用划词屏蔽",
											" ",
											(0, import_jsx_runtime.jsx)("span", {
												"data-tip": "视频详情页中, 标题或评论区选中文字, 按右键可快捷加入屏蔽词",
												children: "❓"
											})
										]
									}), (0, import_jsx_runtime.jsx)("div", {
										style: { display: "flex" },
										children: (0, import_jsx_runtime.jsx)("input", {
											type: "checkbox",
											id: "enableTitleSelectFilter",
											className: "mini-switch"
										})
									})]
								}),
								(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
								(0, import_jsx_runtime.jsxs)("div", {
									id: "reviewKeywordContainer",
									children: [(0, import_jsx_runtime.jsxs)("div", {
										className: "setting-item",
										children: [(0, import_jsx_runtime.jsx)("span", {
											className: "setting-label",
											children: "评论区屏蔽词:"
										}), (0, import_jsx_runtime.jsxs)("div", {
											style: { display: "flex" },
											children: [(0, import_jsx_runtime.jsx)("input", {
												type: "text",
												className: "keyword-input",
												placeholder: "添加屏蔽词"
											}), (0, import_jsx_runtime.jsx)("button", {
												className: "add-tag-btn",
												children: "添加"
											})]
										})]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "tag-box",
										children: " "
									})]
								}),
								(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE$1 }),
								(0, import_jsx_runtime.jsxs)("div", {
									id: "filterKeywordContainer",
									children: [(0, import_jsx_runtime.jsxs)("div", {
										className: "setting-item",
										children: [(0, import_jsx_runtime.jsx)("span", {
											className: "setting-label",
											children: "视频标题屏蔽词:"
										}), (0, import_jsx_runtime.jsxs)("div", {
											style: { display: "flex" },
											children: [(0, import_jsx_runtime.jsx)("input", {
												type: "text",
												className: "keyword-input",
												placeholder: "添加屏蔽词"
											}), (0, import_jsx_runtime.jsx)("button", {
												className: "add-tag-btn",
												children: "添加"
											})]
										})]
									}), (0, import_jsx_runtime.jsx)("div", {
										className: "tag-box",
										children: " "
									})]
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							id: "cache-panel",
							className: "content-panel",
							style: { display: panelName === "cache-panel" ? "block" : "none" },
							children: [
								(0, import_jsx_runtime.jsxs)("div", {
									style: {
										display: "flex",
										justifyContent: "space-between",
										alignItems: "center",
										marginBottom: "4px"
									},
									children: [(0, import_jsx_runtime.jsx)("h1", {
										style: {
											fontSize: "18px",
											fontWeight: "bold",
											margin: "0"
										},
										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",
										marginTop: "20px"
									},
									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"
									} })
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							id: "vlt-panel",
							className: "content-panel",
							style: {
								display: panelName === "vlt-panel" ? "block" : "none",
								padding: "15px"
							},
							children: [
								(0, import_jsx_runtime.jsx)("h3", {
									style: {
										margin: "0 0 12px 0",
										fontSize: "16px",
										color: "#333"
									},
									children: "收藏清单关系"
								}),
								(0, import_jsx_runtime.jsxs)("p", {
									style: {
										margin: "0 0 16px 0",
										color: "#6c757d",
										fontSize: "13px",
										lineHeight: "1.6"
									},
									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 文件(备份/迁移)。"
									]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									style: {
										display: "flex",
										gap: "12px",
										marginBottom: "20px"
									},
									children: [
										(0, import_jsx_runtime.jsx)("a", {
											id: "vlt-import-btn",
											className: "menu-btn",
											style: {
												backgroundColor: "#0d6efd",
												cursor: "pointer"
											},
											children: (0, import_jsx_runtime.jsx)("span", { children: "导入数据" })
										}),
										" ",
										(0, import_jsx_runtime.jsx)("a", {
											id: "vlt-export-btn",
											className: "menu-btn",
											style: {
												backgroundColor: "#198754",
												cursor: "pointer"
											},
											children: (0, import_jsx_runtime.jsx)("span", { children: "导出数据" })
										})
									]
								}),
								(0, import_jsx_runtime.jsx)("div", {
									id: "vlt-status",
									style: {
										fontSize: "13px",
										color: "#6c757d",
										marginTop: "8px"
									}
								}),
								(0, import_jsx_runtime.jsx)("input", {
									type: "file",
									id: "vlt-file-input",
									accept: ".json,application/json",
									style: { display: "none" }
								})
							]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							id: "missav-panel",
							className: "content-panel",
							style: {
								display: panelName === "missav-panel" ? "block" : "none",
								padding: "15px"
							},
							children: [
								(0, import_jsx_runtime.jsx)("h3", {
									style: {
										margin: "0 0 12px 0",
										fontSize: "16px",
										color: "#333"
									},
									children: "MissAV 状态标签同步"
								}),
								(0, import_jsx_runtime.jsxs)("p", {
									style: {
										margin: "0 0 16px 0",
										color: "#6c757d",
										fontSize: "13px",
										lineHeight: "1.6"
									},
									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 备份)。"
									]
								}),
								(0, import_jsx_runtime.jsxs)("div", {
									style: {
										display: "flex",
										gap: "12px",
										marginBottom: "20px"
									},
									children: [
										(0, import_jsx_runtime.jsx)("a", {
											id: "missav-sync-btn",
											className: "menu-btn",
											style: {
												backgroundColor: "#25b1dc",
												cursor: "pointer"
											},
											children: (0, import_jsx_runtime.jsx)("span", { children: "立即同步" })
										}),
										" ",
										(0, import_jsx_runtime.jsx)("a", {
											id: "missav-import-btn",
											className: "menu-btn",
											style: {
												backgroundColor: "#0d6efd",
												cursor: "pointer"
											},
											children: (0, import_jsx_runtime.jsx)("span", { children: "导入数据" })
										}),
										" ",
										(0, import_jsx_runtime.jsx)("a", {
											id: "missav-export-btn",
											className: "menu-btn",
											style: {
												backgroundColor: "#198754",
												cursor: "pointer"
											},
											children: (0, import_jsx_runtime.jsx)("span", { children: "导出数据" })
										})
									]
								}),
								(0, import_jsx_runtime.jsx)("div", {
									id: "missav-status",
									style: {
										fontSize: "13px",
										color: "#6c757d",
										marginTop: "8px"
									}
								}),
								(0, import_jsx_runtime.jsx)("input", {
									type: "file",
									id: "missav-file-input",
									accept: ".json,application/json",
									style: { display: "none" }
								})
							]
						})
					]
				}), (0, import_jsx_runtime.jsxs)("div", {
					style: {
						flexShrink: 0,
						padding: "15px 20px",
						textAlign: "right",
						borderTop: "1px solid #eee",
						background: "white"
					},
					children: [(0, import_jsx_runtime.jsx)("button", {
						id: "saveBtn",
						children: "保存设置"
					}), (0, import_jsx_runtime.jsx)("button", {
						id: "clean-all",
						style: { display: "none" },
						children: "♾️ 清理全部缓存"
					})]
				})]
			})]
		});
	}
	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.jsxs)("div", {
						className: "help-content",
						children: [
							(0, import_jsx_runtime.jsx)("p", { children: "方法一:设置中-添加视频标题关键词,如: VENX-" }),
							(0, import_jsx_runtime.jsx)("p", { children: "方法二:进入详情页,选中标题文字,右键可加入" }),
							(0, import_jsx_runtime.jsx)("img", {
								src: "https://i.imgur.com/lVnhK5A.png",
								alt: "进入详情页,选中标题,进行右键"
							})
						]
					})]
				}),
				(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: "屏蔽演员前,先筛选分类,再点屏蔽"
						})]
					})]
				}),
				(0, import_jsx_runtime.jsxs)("details", {
					className: "help-section",
					children: [
						(0, import_jsx_runtime.jsx)("summary", { children: "4. 如何多浏览器同时登录115网盘?" }),
						(0, import_jsx_runtime.jsxs)("div", {
							className: "help-content",
							children: [(0, import_jsx_runtime.jsx)("p", { children: "① 访问115登录页, 选择JHS-扫码面板, 并扫码登录" }), (0, import_jsx_runtime.jsx)("img", {
								src: "https://imgur.com/XbaisWD.png",
								alt: ""
							})]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							className: "help-content",
							children: [(0, import_jsx_runtime.jsx)("p", { children: "② 进入网盘后, 右下角悬浮按钮, 复制Cookie" }), (0, import_jsx_runtime.jsx)("img", {
								src: "https://imgur.com/GvzJ2Gy.png",
								alt: ""
							})]
						}),
						(0, import_jsx_runtime.jsxs)("div", {
							className: "help-content",
							children: [(0, import_jsx_runtime.jsx)("p", { children: "③ 打开另一个浏览器(需装JHS脚本), 进入登录页面, 选择JHS-扫码面板, 输入Cookie并回车" }), (0, import_jsx_runtime.jsx)("img", {
								src: "https://imgur.com/FX08qdO.png",
								alt: ""
							})]
						})
					]
				})
			]
		});
	}
	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 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: "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: "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: "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 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 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" })]
			});
		}
	}
	var HR_STYLE = {
		border: 0,
		height: "1px",
		margin: "10px 0",
		backgroundImage: "linear-gradient(to right, rgba(0,0,0,0), rgba(159,137,137,0.75), rgba(0,0,0,0))"
	};
	var LABEL_SPAN_STYLE = {
		display: "inline-block",
		width: "80px",
		fontSize: "13px",
		fontWeight: "bold",
		textAlign: "left"
	};
	function SimpleSettingPanel({ isJavdbSite }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			className: "jhs-scrollbar",
			style: {
				marginTop: "20px",
				maxHeight: "90vh",
				overflowY: "auto"
			},
			children: [(0, import_jsx_runtime.jsxs)("div", {
				style: { margin: "0 10px" },
				children: [
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsx)("span", {
							className: "setting-label",
							children: "显示已鉴定内容:"
						}), (0, import_jsx_runtime.jsxs)("div", {
							className: "form-content",
							style: {
								display: "flex",
								flexWrap: "wrap",
								alignItems: "center",
								justifyContent: "flex-end"
							},
							children: [
								(0, import_jsx_runtime.jsx)("span", {
									style: LABEL_SPAN_STYLE,
									children: "屏蔽单番号: "
								}),
								(0, import_jsx_runtime.jsx)("input", {
									type: "checkbox",
									id: "showFilterItem",
									className: "mini-switch"
								}),
								(0, import_jsx_runtime.jsx)("br", {}),
								(0, import_jsx_runtime.jsx)("span", {
									style: LABEL_SPAN_STYLE,
									children: "屏蔽演员: "
								}),
								(0, import_jsx_runtime.jsx)("input", {
									type: "checkbox",
									id: "showFilterActorItem",
									className: "mini-switch"
								}),
								(0, import_jsx_runtime.jsx)("br", {}),
								(0, import_jsx_runtime.jsx)("span", {
									style: LABEL_SPAN_STYLE,
									children: "屏蔽关键词: "
								}),
								(0, import_jsx_runtime.jsx)("input", {
									type: "checkbox",
									id: "showFilterKeywordItem",
									className: "mini-switch"
								}),
								(0, import_jsx_runtime.jsx)("br", {}),
								(0, import_jsx_runtime.jsx)("span", {
									style: LABEL_SPAN_STYLE,
									children: "收藏: "
								}),
								(0, import_jsx_runtime.jsx)("input", {
									type: "checkbox",
									id: "showFavoriteItem",
									className: "mini-switch"
								}),
								(0, import_jsx_runtime.jsx)("br", {}),
								(0, import_jsx_runtime.jsx)("span", {
									style: LABEL_SPAN_STYLE,
									children: "已观看: "
								}),
								(0, import_jsx_runtime.jsx)("input", {
									type: "checkbox",
									id: "showHasWatchItem",
									className: "mini-switch"
								}),
								(0, import_jsx_runtime.jsx)("br", {})
							]
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [
								(0, import_jsx_runtime.jsx)("span", {
									"data-tip": "快速显示所有已鉴定内容,减少对以上开关的频繁操作",
									children: "❓"
								}),
								" ",
								"显示所有:"
							]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: {
								display: "flex",
								flexWrap: "wrap",
								alignItems: "center",
								justifyContent: "flex-end"
							},
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "showAllItem",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [(0, import_jsx_runtime.jsx)("span", {
								"data-tip": "点击封面的打开方式,弹窗|新窗口",
								children: "❓"
							}), " 弹窗方式打开页面:"]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "dialogOpenDetail",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsx)("span", {
							className: "setting-label",
							children: "鉴定后立即关闭页面:"
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "needClosePage",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [(0, import_jsx_runtime.jsx)("span", {
								"data-tip": "使用瀑布流模式, 排序方式将调整为默认",
								children: "❓"
							}), " 瀑布流模式:"]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "autoPage",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsx)("span", {
							className: "setting-label",
							children: "启用标题翻译:"
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "translateTitle",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsx)("span", {
							className: "setting-label",
							children: "启用悬浮大图:"
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "hoverBigImg",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsx)("span", {
							className: "setting-label",
							children: "启用115视频匹配: "
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "enable115Match",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
					isJavdbSite && (0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [
								(0, import_jsx_runtime.jsx)("span", {
									"data-tip": "详情页是否展示女优年龄、三围等信息",
									children: "❓"
								}),
								" ",
								"加载女优信息:"
							]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "enableLoadActressInfo",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [
								(0, import_jsx_runtime.jsx)("span", {
									"data-tip": "详情页第三方资源检测,如missAv,SupJav",
									children: "❓"
								}),
								" ",
								"加载第三方视频资源:"
							]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "enableLoadOtherSite",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [(0, import_jsx_runtime.jsx)("span", {
								"data-tip": "详情页图片区首列位置加载长缩略图",
								children: "❓"
							}), " 加载长缩略图:"]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "enableLoadScreenShot",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [
								(0, import_jsx_runtime.jsx)("span", {
									"data-tip": "详情页解析更多更高画质的预览视频",
									children: "❓"
								}),
								" ",
								"更高画质预览视频:"
							]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "enableLoadPreviewVideo",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsx)("hr", { style: HR_STYLE }),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: [(0, import_jsx_runtime.jsx)("span", {
								"data-tip": "列数6以上,建议开启竖图",
								children: "❓"
							}), " 竖图模式:"]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							style: { textAlign: "right" },
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "checkbox",
								id: "enableVerticalModel",
								className: "mini-switch"
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: ["页面列数: ", (0, import_jsx_runtime.jsx)("span", { id: "showContainerColumns" })]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "range",
								id: "containerColumns",
								min: "2",
								max: "10",
								step: "1",
								style: { padding: "5px 0" }
							})
						})]
					}),
					(0, import_jsx_runtime.jsxs)("div", {
						className: "setting-item",
						children: [(0, import_jsx_runtime.jsxs)("span", {
							className: "setting-label",
							children: ["页面宽度: ", (0, import_jsx_runtime.jsx)("span", { id: "showContainerWidth" })]
						}), (0, import_jsx_runtime.jsx)("div", {
							className: "form-content",
							children: (0, import_jsx_runtime.jsx)("input", {
								type: "range",
								id: "containerWidth",
								min: "0",
								max: "30",
								step: "1",
								style: { padding: "5px 0" }
							})
						})]
					})
				]
			}), (0, import_jsx_runtime.jsxs)("div", {
				style: {
					padding: "0 20px 15px",
					textAlign: "right",
					borderTop: "1px solid #eee"
				},
				children: [(0, import_jsx_runtime.jsx)("button", {
					id: "helpBtn",
					style: { float: "left" },
					children: "常见问题"
				}), (0, import_jsx_runtime.jsx)("button", {
					id: "moreBtn",
					children: "更多设置"
				})]
			})]
		});
	}
	function VideoQualityOption({ quality, text }) {
		return (0, import_jsx_runtime.jsx)("option", {
			value: quality,
			children: text
		});
	}
	var DB_NAME = "JAV-JHS";
	var STORE_NAME = "appData";
	var MAX_COUNT = 501;
	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 randomBootstrapStyle() {
		return BOOTSTRAP_COLORS[Math.floor(Math.random() * BOOTSTRAP_COLORS.length)];
	}
	var KEYS = {
		MOVIES: "vlt_movies",
		INVENTORY: "vlt_inventory",
		MOVIE_INVENTORY: "vlt_movie_inventory",
		META: "vlt_meta"
	};
	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 dbGet(db, key) {
		return new Promise((resolve, reject) => {
			const req = db.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(key);
			req.onsuccess = () => resolve(req.result);
			req.onerror = () => reject(req.error);
		});
	}
	function dbPut(db, key, value) {
		return new Promise((resolve, reject) => {
			const tx = db.transaction(STORE_NAME, "readwrite");
			tx.objectStore(STORE_NAME).put(value, key);
			tx.oncomplete = () => resolve();
			tx.onerror = () => reject(tx.error);
		});
	}
	var VltDb = class {
		static async sync(designation, listId, movie, list, action) {
			const db = await openDb();
			try {
				const movies = await dbGet(db, KEYS.MOVIES) || {};
				const inventory = await dbGet(db, KEYS.INVENTORY) || {};
				const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
				const movieExisted = !!movies[designation];
				const score = movie.score != null ? Number(movie.score) : null;
				if (movieExisted) movies[designation] = {
					...movies[designation],
					href: movie.href,
					title: movie.title ?? null,
					coverSrc: movie.cover_src ?? null,
					score,
					releaseDate: movie.release_date ?? null,
					series: movie.series ?? null,
					code: movie.code ?? null
				};
				else movies[designation] = {
					designation,
					href: movie.href,
					title: movie.title ?? null,
					coverSrc: movie.cover_src ?? null,
					score,
					releaseDate: movie.release_date ?? null,
					createdAt: new Date().toISOString(),
					series: movie.series ?? null,
					code: movie.code ?? null
				};
				const movieStatus = movieExisted ? "existed" : "created";
				const listExisted = !!inventory[listId];
				if (!listExisted) inventory[listId] = {
					listId,
					name: list.name,
					url: list.url ?? null,
					count: 0,
					style: randomBootstrapStyle()
				};
				const listStatus = listExisted ? "existed" : "created";
				const assocKey = `${designation}::${listId}`;
				let associationStatus;
				if (action === "add") if (mi[assocKey]) associationStatus = "existed";
				else {
					const currentCount = inventory[listId]?.count ?? 0;
					if (currentCount >= MAX_COUNT) associationStatus = "limit_exceeded";
					else {
						mi[assocKey] = true;
						inventory[listId].count = currentCount + 1;
						associationStatus = "created";
					}
				}
				else if (mi[assocKey]) {
					delete mi[assocKey];
					if (inventory[listId]) inventory[listId].count = Math.max(0, inventory[listId].count - 1);
					associationStatus = "deleted";
				} else associationStatus = "unchanged";
				await dbPut(db, KEYS.MOVIES, movies);
				await dbPut(db, KEYS.INVENTORY, inventory);
				await dbPut(db, KEYS.MOVIE_INVENTORY, mi);
				return {
					movie: movieStatus,
					list: listStatus,
					association: associationStatus
				};
			} finally {
				db.close();
			}
		}
		static async queryMoviesLists(designations) {
			const db = await openDb();
			try {
				const inventory = await dbGet(db, KEYS.INVENTORY) || {};
				const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
				const result = {};
				for (const des of designations) result[des] = [];
				for (const key of Object.keys(mi)) {
					const sepIdx = key.indexOf("::");
					if (sepIdx < 0) continue;
					const des = key.substring(0, sepIdx);
					const lid = key.substring(sepIdx + 2);
					if (result[des] !== void 0) {
						const inv = inventory[lid];
						if (inv) result[des].push({
							name: inv.name,
							url: inv.url,
							style: inv.style
						});
					}
				}
				return result;
			} finally {
				db.close();
			}
		}
		static async check(designation, listId) {
			const db = await openDb();
			try {
				const movies = await dbGet(db, KEYS.MOVIES) || {};
				const inventory = await dbGet(db, KEYS.INVENTORY) || {};
				const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
				return {
					movie: !!movies[designation],
					inventory: !!inventory[listId],
					movieInventory: !!mi[`${designation}::${listId}`]
				};
			} finally {
				db.close();
			}
		}
		static async importData(data) {
			const db = await openDb();
			try {
				await dbPut(db, KEYS.MOVIES, data.movies);
				await dbPut(db, KEYS.INVENTORY, data.inventory);
				await dbPut(db, KEYS.MOVIE_INVENTORY, data.movieInventory);
				await dbPut(db, KEYS.META, {
					version: data._version,
					exportedAt: data._exportedAt,
					importedAt: new Date().toISOString(),
					source: data._source
				});
				return {
					movies: Object.keys(data.movies).length,
					inventory: Object.keys(data.inventory).length,
					movieInventory: Object.keys(data.movieInventory).length
				};
			} finally {
				db.close();
			}
		}
		static async isImported() {
			const db = await openDb();
			try {
				return !!(await dbGet(db, KEYS.META))?.importedAt;
			} finally {
				db.close();
			}
		}
		static async getAllInventory() {
			const db = await openDb();
			try {
				return await dbGet(db, KEYS.INVENTORY) || {};
			} finally {
				db.close();
			}
		}
		static async exportData() {
			const db = await openDb();
			try {
				const movies = await dbGet(db, KEYS.MOVIES) || {};
				const inventory = await dbGet(db, KEYS.INVENTORY) || {};
				const mi = await dbGet(db, KEYS.MOVIE_INVENTORY) || {};
				const meta = await dbGet(db, KEYS.META);
				return {
					_version: meta?.version ?? 1,
					_exportedAt: meta?.exportedAt ?? new Date().toISOString(),
					_source: "IndexedDB (local export)",
					movies,
					inventory,
					movieInventory: mi
				};
			} finally {
				db.close();
			}
		}
	};
	var queue = {
		MAX_VISIBLE: 2,
		SIMULTANEOUS_WINDOW: 500,
		EXTRA_DURATION: 1e3,
		visible: [],
		overflow: [],
		lastAddTime: 0
	};
	var 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 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.overflow.length === 0 || queue.visible.length >= queue.MAX_VISIBLE) return;
		const stacked = queue.visible.find((v) => v.el.classList.contains("jdb-toast--stacked"));
		if (stacked) stacked.el.classList.remove("jdb-toast--stacked");
		const next = queue.overflow.shift();
		getToastContainer().appendChild(next.el);
		next.el.offsetHeight;
		const now = Date.now();
		const isSimultaneous = now - queue.lastAddTime < queue.SIMULTANEOUS_WINDOW;
		let adjustedDuration = next.duration;
		if (isSimultaneous) adjustedDuration += queue.EXTRA_DURATION;
		queue.lastAddTime = now;
		queue.visible.push({
			el: next.el,
			timerId: setTimeout(() => dismissToast(next.el), adjustedDuration),
			createdAt: now
		});
	}
	function dismissToast(el) {
		const idx = queue.visible.findIndex((v) => v.el === el);
		if (idx < 0) return;
		const onTransitionEnd = () => {
			el.removeEventListener("transitionend", onTransitionEnd);
			el.remove();
			const i = queue.visible.findIndex((v) => v.el === el);
			if (i >= 0) queue.visible.splice(i, 1);
			promoteOverflow();
		};
		el.classList.add("removing");
		el.addEventListener("transitionend", onTransitionEnd);
		setTimeout(() => {
			if (el.parentNode) {
				el.remove();
				const i = queue.visible.findIndex((v) => v.el === el);
				if (i >= 0) queue.visible.splice(i, 1);
				promoteOverflow();
			}
		}, 300);
		if (idx >= 0) clearTimeout(queue.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 = `<span class="jdb-toast__icon">${ICONS[type]}</span><span class="jdb-toast__msg"></span>`;
		toast.querySelector(".jdb-toast__msg").textContent = msg;
		toast.addEventListener("click", () => dismissToast(toast));
		if (queue.visible.length < queue.MAX_VISIBLE) {
			const now = Date.now();
			const isSimultaneous = now - queue.lastAddTime < queue.SIMULTANEOUS_WINDOW;
			let adjustedDuration = duration;
			if (isSimultaneous) adjustedDuration += queue.EXTRA_DURATION;
			queue.lastAddTime = now;
			container.appendChild(toast);
			queue.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.overflow.find((o) => o.el === toast)) {
					const i = queue.overflow.findIndex((o) => o.el === toast);
					queue.overflow.splice(i, 1);
					promoteOverflow();
				}
			});
			queue.overflow.push({
				el: toast,
				msg,
				type,
				duration
			});
		}
	}
	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 MISSAV_DB_NAME = "MissAV-CarStatus";
	var MISSAV_DB_STORE = "cars";
	var LOG_PREFIX_JHS = "[JHS CarSync]";
	var LOG_PREFIX_MISSAV = "[MissAV]";
	function normalizeUrl(rawUrl) {
		let path = rawUrl;
		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;
		}
	}
	function openLocalDB() {
		return new Promise((resolve, reject) => {
			const request = indexedDB.open(MISSAV_DB_NAME, 1);
			request.onupgradeneeded = (event) => {
				const db = event.target.result;
				if (!db.objectStoreNames.contains("cars")) db.createObjectStore(MISSAV_DB_STORE, { keyPath: "carNum" });
			};
			request.onsuccess = () => resolve(request.result);
			request.onerror = () => reject(request.error);
			request.onblocked = () => reject(new Error("数据库被阻塞,请关闭其他标签页后刷新"));
		});
	}
	async function upsertLocalCars(records) {
		const BATCH_SIZE = 3e3;
		let totalWritten = 0;
		const db = await openLocalDB();
		try {
			for (let i = 0; i < records.length; i += BATCH_SIZE) {
				const batch = records.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) {
						if (!rec.carNum || !rec.status || rec.url_path === void 0) continue;
						const req = store.put({
							carNum: rec.carNum.toUpperCase(),
							status: rec.status,
							url: buildJavdbUrlLocal(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 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();
		}
	}
	async function importLocalDB(records) {
		const db = await openLocalDB();
		try {
			await new Promise((resolve, reject) => {
				const tx = db.transaction(MISSAV_DB_STORE, "readwrite");
				tx.objectStore(MISSAV_DB_STORE).clear();
				tx.oncomplete = () => resolve();
				tx.onerror = () => reject(tx.error);
			});
		} finally {
			db.close();
		}
		let written = 0;
		const BATCH_SIZE = 3e3;
		const db2 = await openLocalDB();
		try {
			for (let i = 0; i < records.length; i += BATCH_SIZE) {
				const batch = records.slice(i, i + BATCH_SIZE);
				written += await new Promise((resolveBatch, rejectBatch) => {
					const tx = db2.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.toUpperCase(),
							status: rec.status,
							url: rec.url,
							updateDate: ""
						});
						req.onsuccess = () => count++;
					}
					tx.oncomplete = () => resolveBatch(count);
					tx.onerror = () => rejectBatch(tx.error);
				});
			}
		} finally {
			db2.close();
		}
		return written;
	}
	function buildJavdbUrlLocal(urlPath) {
		if (!urlPath) return "https://javdb.com";
		if (urlPath.startsWith("/")) return "https://javdb.com" + urlPath;
		return "https://javdb.com/v/" + urlPath;
	}
	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`;
	}
	var SettingPlugin = class extends BasePlugin {
		folderName = "JHS-数据备份";
		cacheItems = [
			{
				key: "jhs_dmm_video",
				text: "🎥 预览视频缓存",
				title: "DMM 预告片画质→URL 映射(联动清理 jhs_other_site_dmm)"
			},
			{
				key: "jhs_other_site",
				text: "🌍 第三方站点缓存",
				title: "missav/supjav 等站点搜索结果"
			},
			{
				key: "jhs_translate",
				text: "🆎 标题翻译",
				title: "番号→中文标题翻译(Google Translate)"
			},
			{
				key: "jhs_actress_info",
				text: "👩 演员信息",
				title: "演员身高/体重/三围/罩杯/生日(日文维基百科)"
			},
			{
				key: "jhs_score_info",
				text: "⭐ Top250|热播 评分数据",
				title: "影片评分 HTML 快照(javdb 详情页)"
			}
		];
		getName() {
			return "SettingPlugin";
		}
		async initCss() {
			const settings = await storageManager.getSetting();
			const containerWidth = (settings == null ? void 0 : settings.containerWidth) ?? "100";
			const containerColumns = utils.isMobile() && window.innerWidth < 1e3 ? 1 : (settings == null ? void 0 : settings.containerColumns) ?? 5;
			this.applyImageMode().then();
			let 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).replace("__SIMPLE_SETTING_TOP__", "35px").replace("__SIMPLE_SETTING_RIGHT__", "-300%");
		}
		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", () => {
				$(".simple-setting").html(this.simpleSetting()).show();
				this.initSimpleSettingForm().then();
				clog.lowZIndex();
			}).on("mouseleave", ".setting-box", () => {
				$(".simple-setting").html("").hide();
			});
			$(".main-nav, .container-fluid").on("mouseenter", ".mini-setting-box", () => {
				$(".mini-simple-setting").html(this.simpleSetting()).show();
				this.initSimpleSettingForm().then();
				clog.lowZIndex();
			}).on("mouseleave", ".mini-setting-box", () => {
				$(".mini-simple-setting").html("").hide();
			});
			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() > 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,
				blockText: BLOCK_TEXT,
				favoriteText: FAVORITE_TEXT,
				watchedText: WATCHED_TEXT
			}));
			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 loadForm() {
			const settings = await storageManager.getSetting();
			$("#videoQuality").val(settings.videoQuality);
			$("#reviewCount").val(settings.reviewCount || 20);
			$("#tagPosition").val(settings.tagPosition || "rightTop");
			$("#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);
			$("#webDavUrl").val(settings.webDavUrl || "");
			$("#webDavUsername").val(settings.webDavUsername || "");
			$("#webDavPassword").val(settings.webDavPassword || "");
			$("#enableTitleSelectFilter").prop("checked", !settings.enableTitleSelectFilter || settings.enableTitleSelectFilter === "yes");
			$("#enableFavoriteActresses").prop("checked", !settings.enableFavoriteActresses || settings.enableFavoriteActresses === "yes");
			$("#enableSaveActressCarInfo").prop("checked", !!settings.enableSaveActressCarInfo && settings.enableSaveActressCarInfo === "yes");
			const otherSitePlugin = this.getBean("OtherSitePlugin");
			const missAvUrl = await otherSitePlugin.getMissAvUrl();
			const supJavUrl = await otherSitePlugin.getSupJavUrl();
			$("#missAvUrl").val(missAvUrl);
			$("#supJavUrl").val(supJavUrl);
			const reviewFilterKeywordList = await storageManager.getReviewFilterKeywordList();
			const titleFilterKeyword = await storageManager.getTitleFilterKeyword();
			if (reviewFilterKeywordList) reviewFilterKeywordList.forEach((keyword) => {
				this.addLabelTag("#reviewKeywordContainer", keyword);
			});
			if (titleFilterKeyword) titleFilterKeyword.forEach((keyword) => {
				this.addLabelTag("#filterKeywordContainer", keyword);
			});
			["#reviewKeywordContainer", "#filterKeywordContainer"].forEach((containerSelector) => {
				$(`${containerSelector} .add-tag-btn`).on("click", () => this.addKeyword(containerSelector));
				$(`${containerSelector} .keyword-input`).on("keypress", (event) => {
					if (event.key === "Enter") this.addKeyword(containerSelector);
				});
			});
			$("#hotkey-panel [id]").map((_index, element) => element.id).get().forEach((inputId) => {
				const $input = $(`#${inputId}`);
				const hotkeyValue = settings[inputId] !== void 0 ? settings[inputId] : $input.attr("data-default-hotkey") || "";
				$input.val(hotkeyValue).on("input", (event) => {
					const value = $(event.target).val();
					if (/[\u4e00-\u9fa5]/.test(value) || /^Shift[a-zA-Z0-9]+$/.test(value)) {
						$(event.target).val("");
						show.error("非法输入:不能输入中文或输入法转换错误");
					}
				}).on("keydown", (event) => this.handleHotkeyInput(event, $input));
			});
			$("#enableImageHotKey").prop("checked", !!settings.enableImageHotKey && settings.enableImageHotKey === "yes");
		}
		handleHotkeyInput(event, $input) {
			event.preventDefault();
			const hotkeyString = this.parseHotkey(event);
			if (hotkeyString !== "") if (this.isDuplicateHotkey(hotkeyString, $input.attr("id"))) show.error("该快捷键已被其他功能使用!");
			else $input.val(hotkeyString);
			else $input.val("");
		}
		parseHotkey(event) {
			if (event.key === "Backspace" || event.key === "Process") return "";
			const parts = [];
			if (event.ctrlKey) parts.push("Ctrl");
			if (event.shiftKey) parts.push("Shift");
			if (event.altKey) parts.push("Alt");
			if (event.metaKey) parts.push("Cmd");
			const keyName = {
				" ": "Space",
				Control: "Ctrl",
				Meta: "Cmd",
				ArrowUp: "Up",
				ArrowDown: "Down",
				ArrowLeft: "Left",
				ArrowRight: "Right"
			}[event.key] || (event.key.length > 1 ? event.key.replace("Arrow", "") : event.key);
			if (![
				"Control",
				"Shift",
				"Alt",
				"Meta"
			].includes(event.key)) parts.push(keyName);
			if (parts.length > 0) return parts.join("+");
			else return "";
		}
		isDuplicateHotkey(hotkeyString, inputId) {
			let isDuplicate = false;
			$("#hotkey-panel [id]").each((_index, element) => {
				if (element.id !== inputId && hotkeyString && hotkeyString === $(element).val()) {
					isDuplicate = true;
					return false;
				}
			});
			return isDuplicate;
		}
		async initSimpleSettingForm() {
			const settings = await storageManager.getSetting();
			$("#containerColumns").val(settings.containerColumns || 5);
			$("#showContainerColumns").text(settings.containerColumns || 5);
			$("#containerWidth").val((settings.containerWidth || 100) - 70);
			$("#showContainerWidth").text((settings.containerWidth || 100) + "%");
			$("#dialogOpenDetail").prop("checked", !settings.dialogOpenDetail || settings.dialogOpenDetail === "yes");
			$("#needClosePage").prop("checked", !settings.needClosePage || settings.needClosePage === "yes");
			$("#autoPage").prop("checked", !settings.autoPage || settings.autoPage === "yes");
			$("#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").on("input", async () => {
				const columns = $("#containerColumns").val();
				$("#showContainerColumns").text(columns);
				if (isJavdbSite) document.querySelector(".movie-list").style.gridTemplateColumns = `repeat(${columns}, minmax(0, 1fr))`;
				await storageManager.saveSettingItem("containerColumns", columns);
				this.applyImageMode();
			});
			$("#containerWidth").on("input", async (event) => {
				const rangeValue = parseInt($(event.target).val());
				const widthPercent = rangeValue + 70 + "%";
				$("#showContainerWidth").text(widthPercent);
				if (isJavdbSite) document.querySelector("section .container").style.minWidth = widthPercent;
				storageManager.saveSettingItem("containerWidth", rangeValue + 70);
			});
			$("#dialogOpenDetail").on("change", () => {
				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").on("change", async () => {
				const value = $("#showFilterItem").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("showFilterItem", value);
				refresh();
			});
			$("#showFilterActorItem").on("change", async () => {
				const value = $("#showFilterActorItem").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("showFilterActorItem", value);
				refresh();
			});
			$("#showFilterKeywordItem").on("change", async () => {
				const value = $("#showFilterKeywordItem").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("showFilterKeywordItem", value);
				refresh();
			});
			$("#showFavoriteItem").on("change", async () => {
				const value = $("#showFavoriteItem").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("showFavoriteItem", value);
				refresh();
			});
			$("#showHasWatchItem").on("change", 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", "请先关闭显示所有才可点击");
				else $filterCheckboxes.removeAttr("data-tip");
			};
			$("#showAllItem").prop("checked", !!settings.showAllItem && settings.showAllItem === "yes");
			$("#showAllItem").on("change", async () => {
				const value = $("#showAllItem").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("showAllItem", value);
				updateDisabledState();
				refresh();
			});
			updateDisabledState();
			$("#needClosePage").on("change", async () => {
				await storageManager.saveSettingItem("needClosePage", $("#needClosePage").is(":checked") ? "yes" : "no");
				refresh();
			});
			$("#autoPage").on("change", async () => {
				const value = $("#autoPage").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("autoPage", value);
				if (value === "yes") $("#sort-toggle-btn").hide();
				else $("#sort-toggle-btn").show();
			});
			$("#translateTitle").on("change", async () => {
				const value = $("#translateTitle").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("translateTitle", value);
				if (value === "yes") await this.getBean("ListPagePlugin").doFilter();
				else {
					await this.getBean("ListPagePlugin").revertTranslation();
					$(".translated-title").remove();
				}
			});
			$("#hoverBigImg").prop("checked", !!settings.hoverBigImg && settings.hoverBigImg === "yes");
			$("#hoverBigImg").on("change", async () => {
				const value = $("#hoverBigImg").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("hoverBigImg", value);
				if (value === "yes") window.imageHoverPreviewObj = new ImagePreview({ selector: this.getSelector().coverImgSelector });
				else if (window.imageHoverPreviewObj) window.imageHoverPreviewObj.destroy();
			});
			$("#enableLoadActressInfo").on("change", async () => {
				const value = $("#enableLoadActressInfo").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("enableLoadActressInfo", value);
				if (value === "yes") this.getBean("ActressInfoPlugin").loadActressInfo();
				else $(".actress-info").remove();
			});
			$("#enableLoadOtherSite").on("change", async () => {
				const value = $("#enableLoadOtherSite").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("enableLoadOtherSite", value);
				if (value === "yes") this.getBean("OtherSitePlugin").loadOtherSite().then();
				else $("#otherSiteBox").remove();
			});
			$("#enableLoadScreenShot").prop("checked", !settings.enableLoadScreenShot || settings.enableLoadScreenShot === "yes");
			$("#enableLoadScreenShot").on("change", async () => {
				const value = $("#enableLoadScreenShot").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("enableLoadScreenShot", value);
				if (value !== "yes") $(".screen-container").remove();
			});
			$("#enableLoadPreviewVideo").prop("checked", !settings.enableLoadPreviewVideo || settings.enableLoadPreviewVideo === "yes");
			$("#enableLoadPreviewVideo").on("change", async () => {
				const value = $("#enableLoadPreviewVideo").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("enableLoadPreviewVideo", value);
			});
			$("#enable115Match").prop("checked", !!settings.enable115Match && settings.enable115Match === "yes");
			$("#enable115Match").on("change", async () => {
				const value = $("#enable115Match").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("enable115Match", value);
			});
			$("#enableVerticalModel").prop("checked", !!settings.enableVerticalModel && settings.enableVerticalModel === "yes");
			$("#enableVerticalModel").on("change", async () => {
				const value = $("#enableVerticalModel").is(":checked") ? "yes" : "no";
				await storageManager.saveSettingItem("enableVerticalModel", value);
				this.applyImageMode();
			});
			$("#moreBtn").on("click", () => {
				$(".simple-setting").html("").hide();
				this.openSettingDialog("base-panel");
			});
			$("#helpBtn").on("click", () => {
				layer.open({
					type: 1,
					title: "",
					shadeClose: true,
					scrollbar: false,
					content: "<style>" + help_dialog_default + "</style>" + jsxToString((0, import_jsx_runtime.jsx)(HelpDialog, {})),
					area: utils.getResponsiveArea(["50%", "90%"])
				});
			});
		}
		async applyImageMode() {
			$("#verticalImgStyle").remove();
			if (await storageManager.getSetting("enableVerticalModel", "no") === "yes") {
				let objectPosition = "100% 50% !important";
				if (window.location.href.includes("/advanced_search?type=100")) objectPosition = "50% 50% !important";
				const verticalCss = setting_image_mode_vertical_default.replace("100% 50% !important; /*__OBJECT_POSITION__*/", `${objectPosition}; /*__OBJECT_POSITION__*/`);
				$("<style>").attr("id", "verticalImgStyle").text(verticalCss).appendTo("head");
			} else $("<style>").attr("id", "verticalImgStyle").text(setting_image_mode_horizontal_default).appendTo("head");
		}
		bindClick() {
			$(".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();
					this.refreshAllCacheStats();
				} else if (panelName === "vlt-panel") {
					$("#saveBtn").hide();
					$("#clean-all").hide();
				} else if (panelName === "missav-panel") {
					$("#saveBtn").hide();
					$("#clean-all").hide();
				} else {
					$("#saveBtn").show();
					$("#clean-all").hide();
				}
			});
			$("#importBtn").on("click", () => this.importData());
			$("#exportBtn").on("click", () => this.exportData());
			$("#webdavBackupBtn").on("click", () => this.backupDataByWebDav());
			$("#webdavBackupListBtn").on("click", () => this.backupListBtnByWebDav());
			$("#saveBtn").on("click", () => this.saveForm());
			this.refreshAllCacheStats();
			$(".clean-btn").on("click", (event) => {
				const cacheKey = $(event.currentTarget).data("key");
				const cacheItem = this.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();
				this.refreshCacheStats(cacheKey);
				this.refreshAllCacheStats();
			});
			$("#clean-all").on("click", () => {
				this.cacheItems.forEach((item) => localStorage.removeItem(item.key));
				localStorage.removeItem("jhs_other_site_dmm");
				show.ok("全部缓存已清理");
				$("#cache-data-display").hide();
				this.refreshAllCacheStats();
			});
			$(".view-btn").on("click", (event) => {
				const cacheKey = $(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("无数据");
			});
			$(".export-btn").on("click", (event) => {
				const cacheKey = $(event.currentTarget).data("key");
				const cachedData = localStorage.getItem(cacheKey);
				if (!cachedData) {
					show.error("缓存为空,无可导出数据");
					return;
				}
				const cacheItem = this.cacheItems.find((item) => item.key === cacheKey);
				const blob = new Blob([cachedData], { type: "application/json" });
				const url = URL.createObjectURL(blob);
				const a = document.createElement("a");
				a.href = url;
				a.download = `${cacheKey}-${new Date().toISOString().split("T")[0]}.json`;
				document.body.appendChild(a);
				a.click();
				document.body.removeChild(a);
				URL.revokeObjectURL(url);
				show.ok(`${cacheItem.text} 已导出`);
			});
			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", () => {
				$("#vlt-file-input").trigger("click");
			});
			$("#vlt-file-input").on("change", async (e) => {
				const file = e.target.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) {
					$status.text(`✗ 导入失败:${err.message}`).css("color", "#dc3545");
					showToast$1(`✗ 导入失败:${err.message}`, "error");
				}
				e.target.value = "";
			});
			$("#vlt-export-btn").on("click", async () => {
				const $status = $("#vlt-status");
				$status.text("⏳ 导出中...").css("color", "#0d6efd");
				try {
					const data = await VltDb.exportData();
					const json = JSON.stringify(data, null, 2);
					const blob = new Blob([json], { type: "application/json" });
					const url = URL.createObjectURL(blob);
					const a = document.createElement("a");
					a.href = url;
					a.download = `vlt-export-${new Date().toISOString().split("T")[0]}.json`;
					document.body.appendChild(a);
					a.click();
					document.body.removeChild(a);
					URL.revokeObjectURL(url);
					$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) {
					$status.text(`✗ 导出失败:${err.message}`).css("color", "#dc3545");
					showToast$1(`✗ 导出失败:${err.message}`, "error");
				}
			});
			$("#missav-sync-btn").on("click", async () => {
				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) {
					$status.text(`✗ 同步失败:${err.message}`).css("color", "#dc3545");
					showToast$1(`✗ 同步失败:${err.message}`, "error");
				}
			});
			$("#missav-import-btn").on("click", () => {
				$("#missav-file-input").trigger("click");
			});
			$("#missav-file-input").on("change", async (e) => {
				const file = e.target.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) {
					$status.text(`✗ 导入失败:${err.message}`).css("color", "#dc3545");
					showToast$1(`✗ 导入失败:${err.message}`, "error");
				}
				e.target.value = "";
			});
			$("#missav-export-btn").on("click", async () => {
				const $status = $("#missav-status");
				$status.text("⏳ 导出中...").css("color", "#0d6efd");
				try {
					const records = await exportLocalDB();
					const json = JSON.stringify(records, null, 2);
					const blob = new Blob([json], { type: "application/json" });
					const url = URL.createObjectURL(blob);
					const a = document.createElement("a");
					a.href = url;
					a.download = `missav-status-${new Date().toISOString().split("T")[0]}.json`;
					document.body.appendChild(a);
					a.click();
					document.body.removeChild(a);
					URL.revokeObjectURL(url);
					$status.html(`✓ 导出完成:${records.length} 条记录`).css("color", "#198754");
					showToast$1("✓ 导出完成", "success");
				} catch (err) {
					$status.text(`✗ 导出失败:${err.message}`).css("color", "#dc3545");
					showToast$1(`✗ 导出失败:${err.message}`, "error");
				}
			});
		}
		refreshCacheStats(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} 条` : "空");
		}
		refreshAllCacheStats() {
			let totalSize = 0;
			for (const item of this.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)}`);
		}
		async saveForm() {
			const settings = await storageManager.getSetting();
			settings.videoQuality = $("#videoQuality").val();
			settings.reviewCount = $("#reviewCount").val();
			settings.tagPosition = $("#tagPosition").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();
			settings.webDavUrl = $("#webDavUrl").val();
			settings.webDavUsername = $("#webDavUsername").val();
			settings.webDavPassword = $("#webDavPassword").val();
			settings.missAvUrl = $("#missAvUrl").val().replace(/\/$/, "");
			settings.supJavUrl = $("#supJavUrl").val().replace(/\/$/, "");
			settings.enableTitleSelectFilter = $("#enableTitleSelectFilter").is(":checked") ? "yes" : "no";
			settings.enableFavoriteActresses = $("#enableFavoriteActresses").is(":checked") ? "yes" : "no";
			settings.enableSaveActressCarInfo = $("#enableSaveActressCarInfo").is(":checked") ? "yes" : "no";
			$("#hotkey-panel [id]").map((_index, element) => element.id).get().forEach((inputId) => {
				settings[inputId] = $(`#${inputId}`).val();
			});
			settings.enableImageHotKey = $("#enableImageHotKey").is(":checked") ? "yes" : "no";
			await storageManager.saveSetting(settings);
			const reviewKeywordList = [];
			$("#reviewKeywordContainer .keyword-label").toArray().forEach((label) => {
				const keyword = $(label).text().replace("×", "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
				reviewKeywordList.push(keyword);
			});
			await storageManager.saveReviewFilterKeyword(reviewKeywordList);
			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 = this.getBean("NewVideoPlugin");
			if (newVideoPlugin) newVideoPlugin.resetBtnTip();
			this.getBean("BlacklistPlugin").resetBtnTip();
			this.getBean("BlacklistPlugin").reloadTable();
		}
		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_jsx_runtime.jsx)(KeywordLabel, {
					keyword,
					bgColor,
					textColor,
					variant: "link",
					href: `/video_codes/${keyword.replace("-", "")}`
				})));
			} else $label = $(jsxToString((0, import_jsx_runtime.jsx)(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);
		}
		addKeyword(containerSelector) {
			const $input = $(`${containerSelector} .keyword-input`);
			const keyword = $input.val().trim();
			if (keyword) {
				this.addLabelTag(containerSelector, keyword);
				$input.val("");
			}
		}
		importData() {
			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 = (loadEvent) => {
						try {
							const resultText = loadEvent.target.result.toString();
							const parsedData = JSON.parse(resultText);
							layer.confirm("确定是否要覆盖导入?", {
								icon: 3,
								title: "确认覆盖",
								btn: ["确定", "取消"]
							}, async (layerIndex) => {
								await storageManager.importData(parsedData);
								show.ok("数据导入成功");
								layer.close(layerIndex);
								location.reload();
							});
						} catch (err) {
							console.error(err);
							show.error("导入失败:文件内容不是有效的JSON格式 " + 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.message);
			}
		}
		async backupDataByWebDav() {
			const settings = await storageManager.getSetting();
			const webDavUrl = settings.webDavUrl;
			if (!webDavUrl) {
				show.error("请填写webDav服务地址并保存后, 再试此功能");
				return;
			}
			const webDavUsername = settings.webDavUsername;
			if (!webDavUsername) {
				show.error("请填写webDav用户名并保存后, 再试此功能");
				return;
			}
			const webDavPassword = settings.webDavPassword;
			if (!webDavPassword) {
				show.error("请填写webDav密码并保存后, 再试此功能");
				return;
			}
			const fileName = utils.getNowStr("_", "_") + ".json";
			let exportText = JSON.stringify(await storageManager.exportData());
			exportText = window.encryptCredential(exportText);
			const loadingHandle = loading();
			try {
				await new window.WebDavClient(webDavUrl, webDavUsername, webDavPassword).backup(this.folderName, fileName, exportText);
				show.ok("备份完成");
			} catch (err) {
				console.error(err);
				show.error(err.toString());
			} finally {
				loadingHandle.close();
			}
		}
		async backupListBtnByWebDav() {
			const settings = await storageManager.getSetting();
			const webDavUrl = settings.webDavUrl;
			if (!webDavUrl) {
				show.error("请填写webDav服务地址并保存后, 再试此功能");
				return;
			}
			const webDavUsername = settings.webDavUsername;
			if (!webDavUsername) {
				show.error("请填写webDav用户名并保存后, 再试此功能");
				return;
			}
			const webDavPassword = settings.webDavPassword;
			if (!webDavPassword) {
				show.error("请填写webDav密码并保存后, 再试此功能");
				return;
			}
			const loadingHandle = loading();
			try {
				const webdavClient = new window.WebDavClient(webDavUrl, webDavUsername, webDavPassword);
				const backupList = await webdavClient.getBackupList(this.folderName);
				this.openFileListDialog(backupList, webdavClient, "WebDav");
			} catch (err) {
				console.error(err);
				show.error(`发生错误: ${err ? err.message : err}`);
			} finally {
				loadingHandle.close();
			}
		}
		openFileListDialog(backupList, webdavClient, titlePrefix) {
			layer.open({
				type: 1,
				title: titlePrefix + "备份文件",
				content: jsxToString((0, import_jsx_runtime.jsx)(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, _params, _onRendered) => {
									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, _params, _onRendered) => {
									const data = cell.getData();
									return `${utils.getNowStr("-", ":", data.createTime)}`;
								}
							},
							{
								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", (_event) => {
											layer.confirm(`是否删除 ${rowData.name} ?`, {
												icon: 3,
												title: "提示",
												btn: ["确定", "取消"]
											}, async (layerIndex) => {
												layer.close(layerIndex);
												let loadingHandle = loading();
												try {
													await webdavClient.deleteFile(rowData.fileId);
													let newList = await webdavClient.getBackupList(this.folderName);
													table.replaceData(newList);
													layer.alert("删除成功");
												} catch (err) {
													console.error(err);
													show.error(`发生错误: ${err ? err.message : err}`);
												} finally {
													loadingHandle.close();
												}
											});
										});
										if ($primaryBtn) $primaryBtn.addEventListener("click", async (_event) => {
											let loadingHandle = loading();
											try {
												const decrypted = window.decryptCredential(await webdavClient.getFileContent(rowData.fileId));
												utils.download(decrypted, rowData.name);
											} catch (err) {
												clog.error(err);
												show.error("下载失败: " + err);
											} finally {
												loadingHandle.close();
											}
										});
										if ($successBtn) $successBtn.addEventListener("click", (_event) => {
											layer.confirm(`是否将该云备份数据 ${rowData.name} 导入?`, {
												icon: 3,
												title: "提示",
												btn: ["确定", "取消"]
											}, async (layerIndex) => {
												layer.close(layerIndex);
												let loadingHandle = loading();
												try {
													let fileContent = await webdavClient.getFileContent(rowData.fileId);
													show.info("解密文件内容...");
													fileContent = window.decryptCredential(fileContent);
													show.info("解密完成, 开始导入...");
													const parsedData = JSON.parse(fileContent);
													await storageManager.importData(parsedData);
													show.ok("导入成功!");
													window.location.reload();
												} catch (err) {
													console.error(err);
													show.error(err);
												} finally {
													loadingHandle.close();
												}
											});
										});
									});
									return "\n                                    <a class=\"a-danger\">删除</a>\n                                    <a class=\"a-primary\">下载</a>\n                                    <a class=\"a-success\">导入</a>\n                                ";
								}
							}
						],
						locale: "zh-cn",
						langs: { "zh-cn": { pagination: {
							first: "首页",
							first_title: "首页",
							last: "尾页",
							last_title: "尾页",
							prev: "上一页",
							prev_title: "上一页",
							next: "下一页",
							next_title: "下一页",
							all: "所有",
							page_size: "每页行数"
						} } }
					});
				}
			});
		}
		async exportData() {
			try {
				const exportText = JSON.stringify(await storageManager.exportData());
				const fileName = `${utils.getNowStr("_", "_")}.json`;
				utils.download(exportText, fileName);
				show.ok("数据导出成功");
			} catch (err) {
				console.error(err);
				show.error("导出数据时出错: " + err.message);
			}
		}
	};
	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"
				}
			})
		});
	}
	var wrapperStyle = {
		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 }) {
		return (0, import_jsx_runtime.jsxs)("div", {
			style: wrapperStyle,
			children: [(0, import_jsx_runtime.jsxs)("div", {
				style: rowStyle,
				children: [
					(0, import_jsx_runtime.jsx)("a", {
						id: "filterBtn",
						className: "menu-btn",
						style: statusBtnStyle("120px", filterColor),
						children: (0, import_jsx_runtime.jsx)("span", { children: filterText })
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "favoriteBtn",
						className: "menu-btn",
						style: statusBtnStyle("120px", favoriteColor),
						children: (0, import_jsx_runtime.jsx)("span", { children: favoriteText })
					}),
					(0, import_jsx_runtime.jsx)("a", {
						id: "hasWatchBtn",
						className: "menu-btn",
						style: statusBtnStyle("120px", watchedColor),
						children: (0, import_jsx_runtime.jsx)("span", { children: watchedText })
					})
				]
			}), (0, import_jsx_runtime.jsxs)("div", {
				style: rowStyle,
				children: [
					(0, import_jsx_runtime.jsx)("a", {
						id: "enable-magnets-filter",
						className: "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: "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: "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)" })
					})
				]
			})]
		});
	}
	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: "已读"
			})]
		})] });
	}
	function ListPanel() {
		return (0, import_jsx_runtime.jsx)("div", { className: "jhs-list-panel" });
	}
	var rating_bar_default = "/* 隐藏 review-buttons 内第二个 panel-block(下載/訂正磁力按钮) */\n.review-buttons > .panel-block ~ .panel-block {\n    display: none !important;\n}\n/* 隐藏 review-buttons 后紧跟的 panel-block(N人想看/看過统计) */\n.review-buttons + .panel-block {\n    display: none !important;\n}\n/* 隐藏原生评价状态标签和按钮(星星组件已替代) */\n.review-buttons .review-title {\n    display: none !important;\n}\n.review-buttons .buttons.are-small.review-buttons {\n    display: none !important;\n}\n/* 永久隐藏清单 modal(DOM 保留供 Stimulus ajax 操作) */\n#modal-save-list {\n    display: none !important;\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.jhs-stars {\n    display: inline-flex;\n    gap: 6px;\n    align-items: center;\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.jhs-star:hover {\n    transform: scale(1.15);\n}\n.jhs-star.is-preview {\n    color: #f5b301;\n}\n.jhs-star.is-active {\n    color: #f5b301;\n}\n.jhs-star.is-active:hover {\n    color: #ffce3a;\n}\n.jhs-star.is-popping {\n    animation: jhs-star-pop 0.3s ease;\n}\n@keyframes jhs-star-pop {\n    0% {\n        transform: scale(1);\n    }\n    40% {\n        transform: scale(1.4);\n    }\n    100% {\n        transform: scale(1);\n    }\n}\n.jhs-stars.is-disabled .jhs-star {\n    cursor: default;\n    opacity: 0.4;\n    pointer-events: none;\n}\n.jhs-rating-actions {\n    display: flex;\n    gap: 8px;\n    align-items: center;\n}\n.jhs-read-btn,\n.jhs-fav-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: all 0.15s;\n    white-space: nowrap;\n}\n.jhs-read-btn:hover,\n.jhs-fav-btn:hover {\n    border-color: #b5b5b5;\n    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);\n}\n.jhs-read-btn.is-active {\n    background: #48c774;\n    border-color: #48c774;\n    color: #fff;\n}\n.jhs-fav-btn.is-active {\n    background: #3273dc;\n    border-color: #3273dc;\n    color: #fff;\n}\n.jhs-read-btn.is-popping,\n.jhs-fav-btn.is-popping {\n    animation: jhs-star-pop 0.3s ease;\n}\n.jhs-rating-bar.is-busy {\n    pointer-events: none;\n    opacity: 0.6;\n}\n/* 清单平铺面板(位于 #otherSiteBox 下方) */\n.jhs-list-panel {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 8px 16px;\n    margin: 8px 0;\n    padding: 8px 12px;\n    background: #fafafa;\n    border-radius: 6px;\n    min-height: 36px;\n}\n.jhs-list-panel:empty {\n    display: none;\n}\n.jhs-list-panel .control {\n    margin: 0;\n}\n.jhs-list-panel .checkbox {\n    display: inline-flex;\n    align-items: center;\n    gap: 4px;\n    font-size: 13px;\n    cursor: pointer;\n}\n.jhs-list-panel .checkbox input {\n    margin: 0;\n}\n";
	var DetailPageButtonPlugin = class extends BasePlugin {
		answerCount = 1;
		filterHotKey = null;
		favoriteHotKey = null;
		hasWatchHotKey = null;
		speedVideoHotKey = null;
		_wantWatchedObserved = false;
		_lastWantState = null;
		_wantWatchedSyncing = false;
		_wantWatchedDebounce = null;
		_wantWatchedListenerInstalled = false;
		_quickActionAdded = false;
		_listPanelEnsured = false;
		_listPanelIniting = false;
		_listAjaxTriggered = false;
		_ratingSyncDebounce = null;
		_reviewChain = null;
		getName() {
			return "DetailPageButtonPlugin";
		}
		constructor() {
			super();
			this.answerCount = 1;
		}
		async handle() {
			const settings = await storageManager.getSetting();
			this.filterHotKey = settings.filterHotKey;
			this.favoriteHotKey = settings.favoriteHotKey;
			this.hasWatchHotKey = settings.hasWatchHotKey;
			this.speedVideoHotKey = settings.speedVideoHotKey;
			this.bindHotkey().then();
			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
			}));
			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));
			this.showStatus(carNum).then();
		}
		async showStatus(carNum) {
			const $filterSpan = $("#filterBtn span");
			const $favoriteSpan = $("#favoriteBtn span");
			const $hasWatchSpan = $("#hasWatchBtn span");
			const formatHotkey = (key) => key ? `(${key})` : "";
			$filterSpan.text(`${BLOCK_TEXT} ${formatHotkey(this.filterHotKey)}`);
			$favoriteSpan.text(`${FAVORITE_TEXT} ${formatHotkey(this.favoriteHotKey)}`);
			$hasWatchSpan.text(`${WATCHED_TEXT} ${formatHotkey(this.hasWatchHotKey)}`);
			const carRecord = await storageManager.getCar(carNum);
			if (carRecord) switch (carRecord.status) {
				case FILTER_ACTION:
					$filterSpan.text(`${BLOCKED_TEXT} ${formatHotkey(this.filterHotKey)}`);
					break;
				case FAVORITE_ACTION:
					$favoriteSpan.text(`${FAVORITED_TEXT} ${formatHotkey(this.favoriteHotKey)}`);
					break;
				case HAS_WATCH_ACTION: $hasWatchSpan.text(`🔍 已标记观看 ${formatHotkey(this.hasWatchHotKey)}`);
			}
		}
		hookWantAndWatchedButtons() {
			if (!isJavdbSite) return;
			if (this._wantWatchedObserved) return;
			const self = this;
			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);
					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();
		}
		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 onWantAdded() {
			const pageInfo = this.getPageInfo();
			try {
				const carRecord = await storageManager.getCar(pageInfo.carNum);
				if (carRecord && carRecord.status === "favorite") {} else {
					await storageManager.saveCar({
						carNum: pageInfo.carNum,
						url: pageInfo.url,
						names: pageInfo.actress,
						actionType: FAVORITE_ACTION,
						publishTime: pageInfo.publishTime
					});
					this.broadcastWantWatchedSync({
						carNum: pageInfo.carNum,
						status: FAVORITE_ACTION,
						op: "add"
					});
					show.ok(`${pageInfo.carNum} 已收藏`);
				}
			} catch (err) {
				console.error("[JHS-想看自动同步] 写入失败", err);
			}
			this.showStatus(pageInfo.carNum).then();
		}
		async onWantRemoved() {
			const pageInfo = this.getPageInfo();
			try {
				if (await this.removeCarIfStatus(pageInfo.carNum, "favorite")) {
					this.broadcastWantWatchedSync({
						carNum: pageInfo.carNum,
						status: FAVORITE_ACTION,
						op: "remove"
					});
					show.ok(`${pageInfo.carNum} 已取消收藏`);
				}
			} catch (err) {
				console.error("[JHS-想看自动同步] 移除失败", err);
			}
			this.showStatus(pageInfo.carNum).then();
		}
		async onWatchedAdded() {
			const pageInfo = this.getPageInfo();
			try {
				const carRecord = await storageManager.getCar(pageInfo.carNum);
				if (carRecord && carRecord.status === "hasWatch") {} else {
					await storageManager.saveCar({
						carNum: pageInfo.carNum,
						url: pageInfo.url,
						names: pageInfo.actress,
						actionType: HAS_WATCH_ACTION,
						publishTime: pageInfo.publishTime
					});
					this.broadcastWantWatchedSync({
						carNum: pageInfo.carNum,
						status: HAS_WATCH_ACTION,
						op: "add"
					});
					show.ok(`${pageInfo.carNum} 已标记看过`);
				}
			} catch (err) {
				console.error("[JHS-观看自动同步] 写入失败", err);
			}
			this.showStatus(pageInfo.carNum).then();
		}
		async onWatchedRemoved() {
			const pageInfo = this.getPageInfo();
			try {
				if (await this.removeCarIfStatus(pageInfo.carNum, "hasWatch")) {
					this.broadcastWantWatchedSync({
						carNum: pageInfo.carNum,
						status: HAS_WATCH_ACTION,
						op: "remove"
					});
					show.ok(`${pageInfo.carNum} 已取消看过`);
				}
			} catch (err) {
				console.error("[JHS-观看自动同步] 移除失败", err);
			}
			this.showStatus(pageInfo.carNum).then();
		}
		async removeCarIfStatus(carNum, status) {
			const carRecord = await storageManager.getCar(carNum);
			if (!carRecord) return false;
			if (carRecord.status !== status) return false;
			return await storageManager.removeCar(carNum);
		}
		broadcastWantWatchedSync(payload) {
			try {
				const json = JSON.stringify({
					...payload,
					time: Date.now()
				});
				try {
					GM_setValue("jdb:want-watched-sync", json);
				} catch {}
				try {
					localStorage.setItem("jdb:want-watched-sync", json);
				} catch {}
				try {
					document.dispatchEvent(new CustomEvent("jdb:want-watched-sync", { detail: payload }));
				} catch {}
			} catch (err) {
				console.error("[JHS-想看/观看同步] 广播失败", err);
			}
		}
		setupWantWatchedSyncListener() {
			if (!isJavdbSite) return;
			if (this._wantWatchedListenerInstalled) return;
			this._wantWatchedListenerInstalled = true;
			const self = this;
			const handleSync = (rawData) => {
				const payload = rawData && rawData.detail || (() => {
					try {
						return JSON.parse(rawData);
					} catch {
						return null;
					}
				})();
				if (!payload || !payload.carNum) return;
				try {
					const currentCarNum = self.getPageInfo().carNum;
					if (currentCarNum && payload.carNum === currentCarNum) self.showStatus(currentCarNum).then(() => {});
				} catch {}
				self.refreshItemStatusTag(payload.carNum);
			};
			document.addEventListener("jdb:want-watched-sync", (event) => handleSync(event.detail));
			window.addEventListener("storage", (event) => {
				if (event.key !== "jdb:want-watched-sync" || !event.newValue) return;
				handleSync(event.newValue);
			});
			try {
				GM_addValueChangeListener("jdb:want-watched-sync", (_name, _oldValue, newValue) => {
					if (!newValue) return;
					handleSync(newValue);
				});
			} catch {}
		}
		refreshItemStatusTag(carNum) {
			try {
				const itemSelector = this.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 = this.getBean("ListPagePlugin");
					if (!listPagePlugin) continue;
					listPagePlugin.renderItemStatusTag(item, carNum);
				}
			} catch (err) {
				console.error("[JHS-想看/观看] 刷新列表项 status-tag 失败", err);
			}
		}
		addQuickActionButtons() {
			if (!window.isDetailPage) return;
			if (this._quickActionAdded) return;
			this._quickActionAdded = true;
			const self = this;
			this._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);
						self._ratingSyncDebounce = setTimeout(() => {
							self._buildRatingBar(nav);
							self._syncRatingBar();
						}, 200);
					}).observe(rb, {
						childList: true,
						subtree: true
					});
				}
			};
			ensure();
		}
		_buildRatingBar(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 = this;
			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");
			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();
				}
			});
			column.insertBefore(bar, column.firstChild);
		}
		_ensureListPanel(nav) {
			if (this._listPanelEnsured) return;
			const otherSite = nav.querySelector("#otherSiteBox");
			if (!otherSite) {
				setTimeout(() => this._ensureListPanel(nav), 400);
				return;
			}
			this._listPanelEnsured = true;
			const self = this;
			if (!nav.querySelector(".jhs-list-panel")) otherSite.insertAdjacentHTML("afterend", jsxToString((0, import_jsx_runtime.jsx)(ListPanel, {})));
			self._initListPanel();
			const listPanel = nav.querySelector(".jhs-list-panel");
			if (listPanel && !listPanel.__jhsListClickBound) {
				listPanel.__jhsListClickBound = true;
				listPanel.addEventListener("change", (e) => {
					if (e.target.type !== "checkbox") return;
					const listContainer = document.querySelector("#modal-save-list")?.querySelector("[data-list-target=\"listContainer\"]");
					if (!listContainer) return;
					const idx = Array.from(listPanel.querySelectorAll("input[type=\"checkbox\"]")).indexOf(e.target);
					const target = listContainer.querySelectorAll("input[type=\"checkbox\"]")[idx];
					if (target) {
						target.checked = e.target.checked;
						target.dispatchEvent(new Event("change", { bubbles: true }));
					}
				});
			}
		}
		_initListPanel() {
			if (this._listPanelIniting) return;
			this._listPanelIniting = true;
			const self = this;
			const ensure = () => {
				const btn = document.querySelector("#save-list-button");
				const modal = document.querySelector("#modal-save-list");
				if (!btn || !modal) {
					setTimeout(ensure, 400);
					return;
				}
				const listContainer = modal.querySelector("[data-list-target=\"listContainer\"]");
				if (!listContainer) return;
				if (!self._listAjaxTriggered) {
					self._listAjaxTriggered = true;
					btn.click();
				}
				if (!listContainer.__jhsListObserved) {
					listContainer.__jhsListObserved = true;
					const sync = () => {
						const panel = document.querySelector(".jhs-list-panel");
						if (!panel) return;
						panel.innerHTML = "";
						Array.from(listContainer.children).forEach((child) => {
							if (child.textContent.includes("預設清單")) return;
							const clone = child.cloneNode(true);
							panel.appendChild(clone);
						});
					};
					new MutationObserver(sync).observe(listContainer, {
						childList: true,
						subtree: true,
						attributes: true,
						attributeFilter: ["checked", "disabled"]
					});
					setTimeout(sync, 500);
				}
			};
			ensure();
		}
		_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);
		}
		_syncRatingBar() {
			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) this._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");
			if (want) {
				stars.forEach((s) => s.classList.remove("is-active"));
				starsEl.classList.remove("is-disabled");
				readBtn.classList.remove("is-active");
				favBtn.classList.add("is-active");
			} else if (watched) {
				stars.forEach((s, i) => s.classList.toggle("is-active", i < score));
				starsEl.classList.remove("is-disabled");
				readBtn.classList.toggle("is-active", score === 0);
				favBtn.classList.remove("is-active");
			} else {
				stars.forEach((s) => s.classList.remove("is-active"));
				starsEl.classList.remove("is-disabled");
				readBtn.classList.remove("is-active");
				favBtn.classList.remove("is-active");
			}
		}
		_setRatingBusy(busy) {
			const bar = document.querySelector(".jhs-rating-bar");
			if (bar) bar.classList.toggle("is-busy", busy);
		}
		async quickSetHasWatch(score) {
			const pageInfo = this.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,
					names: pageInfo.actress,
					actionType: HAS_WATCH_ACTION,
					publishTime: pageInfo.publishTime,
					score
				});
				this.broadcastWantWatchedSync({
					carNum: pageInfo.carNum,
					status: HAS_WATCH_ACTION,
					op: "add"
				});
				show.ok(pageInfo.carNum + " 已标记看过 " + (score > 0 ? "★" + score : ""));
			} catch (err) {
				console.error("[JHS-快键] 设为已观看失败", err);
				show.error("操作失败: " + err.message);
				return;
			}
			this._reviewChain = (this._reviewChain || Promise.resolve()).then(async () => {
				this._wantWatchedSyncing = true;
				try {
					await this._triggerJavdbReview(score);
					this._syncRatingBar();
				} finally {
					this._wantWatchedSyncing = false;
				}
			}).catch(() => {});
		}
		_getCsrfToken() {
			const meta = document.querySelector("meta[name=\"csrf-token\"]");
			return meta ? meta.content : null;
		}
		_getVideoId() {
			return location.pathname.match(/\/v\/([^/]+)/)?.[1] || null;
		}
		_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;
		}
		_execRailsJs(jsText) {
			try {
				const script = document.createElement("script");
				script.textContent = jsText;
				document.head?.appendChild(script);
				script.remove();
			} catch (err) {
				console.error("[JHS-快键] 执行 Rails JS 失败", err);
			}
		}
		async _javdbReviewApi(action, score = 0) {
			const token = this._getCsrfToken();
			if (!token) throw new Error("无法获取 CSRF token");
			const videoId = this._getVideoId();
			if (!videoId) throw new Error("无法获取 videoId");
			const reviewId = this._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}`);
				this._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}`);
					this._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}`);
				this._execRailsJs(await res.text());
			}
			const rb = document.querySelector(".review-buttons");
			if (rb && this._wantWatchedObserved) this._lastWantState = this.detectWantWatchedState(rb);
		}
		async _triggerJavdbReview(score) {
			await this._javdbReviewApi("watched", score);
		}
		_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);
			});
		}
		_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();
			});
		}
		async quickConvertToFav() {
			const pageInfo = this.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,
					names: pageInfo.actress,
					actionType: FAVORITE_ACTION,
					publishTime: pageInfo.publishTime
				});
				this.broadcastWantWatchedSync({
					carNum: pageInfo.carNum,
					status: FAVORITE_ACTION,
					op: "add"
				});
				show.ok(pageInfo.carNum + " 已转为收藏");
			} catch (err) {
				console.error("[JHS-快键] 转为已收藏失败", err);
				show.error("操作失败: " + err.message);
				return;
			}
			this._reviewChain = (this._reviewChain || Promise.resolve()).then(async () => {
				this._wantWatchedSyncing = true;
				try {
					await this._triggerJavdbWant();
					this._syncRatingBar();
				} finally {
					this._wantWatchedSyncing = false;
				}
			}).catch(() => {});
		}
		async _triggerJavdbWant() {
			await this._javdbReviewApi("wanted");
		}
		async favoriteOne() {
			const pageInfo = this.getPageInfo();
			await storageManager.saveCar({
				carNum: pageInfo.carNum,
				url: pageInfo.url,
				names: pageInfo.actress,
				actionType: FAVORITE_ACTION,
				publishTime: pageInfo.publishTime
			});
			this.showStatus(pageInfo.carNum).then();
			refresh();
			utils.closePage();
		}
		async hasWatchOne() {
			const pageInfo = this.getPageInfo();
			await storageManager.saveCar({
				carNum: pageInfo.carNum,
				url: pageInfo.url,
				names: pageInfo.actress,
				actionType: HAS_WATCH_ACTION,
				publishTime: pageInfo.publishTime
			});
			this.showStatus(pageInfo.carNum).then();
			refresh();
			utils.closePage();
		}
		searchXunLeiSubtitle(carNum) {
			const loadingHandle = loading();
			gmHttp.get(`https://api-shoulei-ssl.xunlei.com/oracle/subtitle?gcid=&cid=&name=${carNum}`).then((response) => {
				const subtitleList = response.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", {
							layout: "fitColumns",
							placeholder: "暂无数据",
							virtualDom: true,
							data: subtitleList,
							responsiveLayout: "collapse",
							responsiveLayoutCollapse: true,
							columnDefaults: {
								headerHozAlign: "center",
								hozAlign: "center"
							},
							columns: [
								{
									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;
												this.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, {}));
									}
								}
							],
							locale: "zh-cn",
							langs: { "zh-cn": { pagination: {
								first: "首页",
								first_title: "首页",
								last: "尾页",
								last_title: "尾页",
								prev: "上一页",
								prev_title: "上一页",
								next: "下一页",
								next_title: "下一页",
								all: "所有",
								page_size: "每页行数"
							} } }
						});
						utils.setupEscClose(index);
					}
				});
				else show.error("迅雷中找不到相关字幕!");
			}).catch((err) => {
				console.error(err);
				show.error(err);
			}).finally(() => {
				loadingHandle.close();
			});
		}
		async filterOne(event, force) {
			if (event) event.preventDefault();
			const pageInfo = this.getPageInfo();
			if (force) {
				await storageManager.saveCar({
					carNum: pageInfo.carNum,
					url: pageInfo.url,
					names: pageInfo.actress,
					actionType: FILTER_ACTION,
					publishTime: pageInfo.publishTime
				});
				this.showStatus(pageInfo.carNum).then();
				refresh();
				utils.closePage();
				layer.closeAll();
				this.answerCount = 1;
			} else utils.q(event, `是否屏蔽${pageInfo.carNum}?`, async () => {
				await storageManager.saveCar({
					carNum: pageInfo.carNum,
					url: pageInfo.url,
					names: pageInfo.actress,
					actionType: FILTER_ACTION,
					publishTime: pageInfo.publishTime
				});
				this.showStatus(pageInfo.carNum).then();
				refresh();
				utils.closePage();
			}, () => {
				this.answerCount = 1;
			});
		}
		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);
			});
		}
		async bindHotkey() {
			const hotkeyMap = {};
			if (this.filterHotKey) hotkeyMap[this.filterHotKey] = () => {
				if (this.answerCount >= 2) this.filterOne(null, true);
				else this.filterOne(null);
				this.answerCount++;
			};
			if (this.favoriteHotKey) hotkeyMap[this.favoriteHotKey] = () => this.favoriteOne();
			if (this.hasWatchHotKey) hotkeyMap[this.hasWatchHotKey] = () => this.hasWatchOne();
			if (this.speedVideoHotKey) hotkeyMap[this.speedVideoHotKey] = () => this.speedVideo();
			const register = (hotkeyStr, callback) => {
				Hotkey.registerHotkey(hotkeyStr, (_keyEvent) => {
					const activeEl = document.activeElement;
					if (activeEl.tagName !== "INPUT" && activeEl.tagName !== "TEXTAREA" && !activeEl.isContentEditable) if (window.isDetailPage) callback();
					else ((key) => {
						const $iframe = $(".layui-layer-content iframe");
						if ($iframe.length !== 0) $iframe[0].contentWindow.postMessage(key, "*");
					})(hotkeyStr);
				});
			};
			if (window.isDetailPage) window.addEventListener("message", (messageEvent) => {
				if (hotkeyMap[messageEvent.data]) hotkeyMap[messageEvent.data]();
			});
			Object.entries(hotkeyMap).forEach(([key, cb]) => {
				register(key, cb);
			});
		}
		async previewSubtitle(url, filename) {
			if (!url) {
				console.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.message}`);
				console.error("预览字幕文件出错:", err);
			}
			else show.error("仅支持预览ASS和SRT字幕文件");
		}
	};
	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
		});
	}
	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 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.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: keywordFilterCount })
					}),
					(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.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: waitCheckCount })
					}),
					(0, import_jsx_runtime.jsx)("td", { style: tdStyle }),
					(0, import_jsx_runtime.jsx)("td", { style: tdStyle })
				] }),
				(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 })
				})] })
			]
		});
	}
	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"
		}
	};
	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 response = await fetch(url);
		if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
		return (await response.json()).translation;
	}
	var ListPagePlugin = class extends BasePlugin {
		currentPageFilterCount = 0;
		currentPageFavoriteCount = 0;
		currentPageHasWatchCount = 0;
		currentPageKeywordFilterCount = 0;
		currentPageActorFilterCount = 0;
		currentPageWaitCheckCount = 0;
		currentPageTotalCount = 0;
		cache = localStorage.getItem("jhs_translate") ? JSON.parse(localStorage.getItem("jhs_translate")) : {};
		writeQueue = Promise.resolve();
		$currentImage = null;
		filterHotKey;
		favoriteHotKey;
		hasWatchHotKey;
		enableImageHotKey;
		clogHotKey;
		foldCategoryHotKey;
		getName() {
			return "ListPagePlugin";
		}
		async handle() {
			new BroadcastChannel("channel-refresh").addEventListener("message", async (event) => {
				const msgType = event.data.type;
				if (msgType === "refresh") {
					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.bindListPageHotKey().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");
				console.log("触发");
				localStorage.setItem(storageKey, isExpanded.toString());
			});
		}
		checkDom() {
			if (!window.isListPage) return;
			const selectorConfig = this.getSelector();
			const containerEl = document.querySelector(selectorConfig.boxSelector);
			if (!containerEl) {
				console.error("没有找到容器节点!");
				return;
			}
			const observerOptions = {
				childList: true,
				subtree: false
			};
			const observer = new MutationObserver(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);
				}
			});
			observer.observe(containerEl, observerOptions);
		}
		async doFilter() {
			if (!window.isListPage) return;
			const itemEls = $(this.getSelector().itemSelector).toArray();
			if (itemEls.length) await this.filterMovieList(itemEls);
		}
		async 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 = ((await storageManager.getSetting()).tagPosition || "rightTop") === "rightTop" ? "right: 0; top:5px;" : "left: 0; top:5px;";
				const tagHtml = jsxToString((0, import_jsx_runtime.jsx)(StatusTagHtml, {
					variant: "render",
					text: tagConfig.text,
					color: tagConfig.color,
					dataTip: tagConfig.reasonType,
					positionStyle
				}));
				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);
			} catch (err) {
				console.error("[JHS-想看/观看] renderItemStatusTag 失败", err);
			}
		}
		async filterMovieList(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 statusCarSets = carList.reduce((acc, car) => {
				const status = car.status;
				if (acc.hasOwnProperty(status)) acc[status].add(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";
			this.currentPageFilterCount = 0;
			this.currentPageFavoriteCount = 0;
			this.currentPageHasWatchCount = 0;
			this.currentPageKeywordFilterCount = 0;
			this.currentPageActorFilterCount = 0;
			this.currentPageWaitCheckCount = 0;
			this.currentPageTotalCount = 0;
			utils.time("处理页面耗时");
			await Promise.all(itemEls.map(async (itemEl) => {
				const $item = $(itemEl);
				const { carNum, title } = this.findCarNumAndHref($item);
				const { filter: filterSet, favorite: favoriteSet, hasWatch: hasWatchSet } = statusCarSets;
				const isFavorite = favoriteSet.has(carNum);
				const isHasWatch = hasWatchSet.has(carNum);
				const isFiltered = filterSet.has(carNum);
				const isActorBlacklist = actorCarNumToNameMap.has(carNum);
				const isActressBlacklist = actressCarNumToNameMap.has(carNum);
				const isBlacklistActor = isActorBlacklist || isActressBlacklist;
				const matchedKeyword = titleFilterKeywords.find((keyword) => 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;
					const isHidden = $item.attr("data-hide") === "yes";
					if (showAllItem === "yes") shouldHide = false;
					if (shouldHide && !isHidden) $item.hide().attr("data-hide", "yes");
					else if (!shouldHide && isHidden) $item.show().removeAttr("data-hide");
				}
				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) this[tagConfig.countKey]++;
				this.currentPageTotalCount++;
				$item.find(".status-tag").remove();
				const positionStyle = tagPosition === "rightTop" ? "right: 0; top:5px;" : "left: 0; top:5px;";
				if (tagConfig.text) {
					const tagHtml = jsxToString((0, import_jsx_runtime.jsx)(StatusTagHtml, {
						variant: "filter",
						text: tagConfig.text,
						color: tagConfig.color,
						dataTip: reasonText,
						positionStyle
					}));
					if (isJavdbSite) $item.find(".tags").append(tagHtml);
				}
				await this.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,
				assembleDataTime,
				processPageTime,
				totalTime,
				filterCount: this.currentPageFilterCount,
				favoriteCount: this.currentPageFavoriteCount,
				actorFilterCount: this.currentPageActorFilterCount,
				keywordFilterCount: this.currentPageKeywordFilterCount,
				hasWatchCount: this.currentPageHasWatchCount,
				waitCheckCount: this.currentPageWaitCheckCount,
				totalCount: this.currentPageTotalCount
			})));
		}
		async bindClick() {
			const selectorConfig = this.getSelector();
			$(selectorConfig.boxSelector).on("click", ".item img", async (event) => {
				event.preventDefault();
				event.stopPropagation();
				if ($(event.target).closest("div.meta-buttons").length) return;
				const $item = $(event.target).closest(".item");
				const { carNum, aHref } = this.findCarNumAndHref($item);
				const dialogOpenDetail = await storageManager.getSetting("dialogOpenDetail", "yes");
				if (carNum.includes("FC2-")) {
					const movieId = this.parseMovieId(aHref);
					this.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carNum, aHref);
				} else if (dialogOpenDetail === "yes") {
					utils.openPage(aHref, carNum, true, event);
					this.$currentImage = null;
				} else window.open(aHref);
			});
			$(selectorConfig.boxSelector).on("click", ".item video", async (event) => {
				const videoEl = event.currentTarget;
				if (videoEl.paused) videoEl.play().catch((err) => console.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 } = this.findCarNumAndHref($item);
				if (carNum.includes("FC2-")) {
					event.preventDefault();
					const movieId = this.parseMovieId(aHref);
					this.getBean("Fc2Plugin")?.openFc2Dialog(movieId, carNum, aHref);
				}
			});
			$(selectorConfig.boxSelector).on("contextmenu", ".item img, .item video", async (event) => {
				event.preventDefault();
				const $item = $(event.target).closest(".item");
				const { carNum, url, publishTime } = this.findCarNumAndHref($item);
				const nameEl = $(".actor-section-name");
				let actressName = "";
				if (nameEl.length) actressName = nameEl.text().trim().split(",")[0].replace("(無碼)", "");
				utils.q(event, `是否屏蔽番号 ${carNum}?`, async () => {
					setTimeout(async () => {
						actressName ||= await this.parseActressName(url);
						await storageManager.saveCar({
							carNum,
							url,
							names: actressName,
							actionType: FILTER_ACTION,
							publishTime
						});
						refresh();
						show.ok("操作成功");
					});
				});
			});
		}
		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(html);
				if (isJavdbSite) actressName = $dom.find(".female").prev().map((_index, el) => $(el).text()).get().join(" ");
				clog.debug("解析到名称:", actressName);
			}
			return actressName;
		}
		async bindListPageHotKey() {
			this.$currentImage = null;
			$(document).on("mouseenter", this.getSelector().coverImgSelector, (event) => {
				this.$currentImage = $(event.currentTarget);
			}).on("mouseleave", this.getSelector().coverImgSelector, () => {
				this.$currentImage = null;
			});
			const setting = await storageManager.getSetting();
			this.filterHotKey = setting.filterHotKey;
			this.favoriteHotKey = setting.favoriteHotKey;
			this.hasWatchHotKey = setting.hasWatchHotKey;
			this.enableImageHotKey = setting.enableImageHotKey || "no";
			this.clogHotKey = setting.clogHotKey;
			this.foldCategoryHotKey = setting.foldCategoryHotKey;
			if (this.enableImageHotKey === "no") return;
			const saveCarByHotkey = async (carInfo, actionType) => {
				setTimeout(async () => {
					const names = await this.parseActressName(carInfo.url);
					await storageManager.saveCar({
						carNum: carInfo.carNum,
						url: carInfo.url,
						names,
						actionType,
						publishTime: carInfo.publishTime
					});
					refresh();
					show.ok("操作成功");
				});
			};
			const hotkeyHandlers = {};
			if (this.filterHotKey) hotkeyHandlers[this.filterHotKey] = (carInfo) => {
				saveCarByHotkey(carInfo, FILTER_ACTION);
			};
			if (this.favoriteHotKey) hotkeyHandlers[this.favoriteHotKey] = (carInfo) => {
				saveCarByHotkey(carInfo, FAVORITE_ACTION);
			};
			if (this.hasWatchHotKey) hotkeyHandlers[this.hasWatchHotKey] = (carInfo) => {
				saveCarByHotkey(carInfo, HAS_WATCH_ACTION);
			};
			if (this.clogHotKey) Hotkey.registerHotkey(this.clogHotKey, () => {
				clog.toggleExpandCollapsed();
			});
			if (this.foldCategoryHotKey) Hotkey.registerHotkey(this.foldCategoryHotKey, () => {
				const foldBtn = $("#foldCategoryBtn");
				if (foldBtn.length) foldBtn[0].click();
			});
			const registerImageHotkey = (hotkey, handler) => {
				Hotkey.registerHotkey(hotkey, () => {
					const activeEl = document.activeElement;
					if (activeEl.tagName !== "INPUT" && activeEl.tagName !== "TEXTAREA" && !activeEl.isContentEditable && this.$currentImage) {
						const $item = this.$currentImage.closest(".item");
						handler(this.findCarNumAndHref($item));
					}
				});
			};
			Object.entries(hotkeyHandlers).forEach(([hotkey, handler]) => {
				registerImageHotkey(hotkey, handler);
			});
		}
		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) {
				const errorMsg = "提取番号信息失败";
				show.error(errorMsg);
				throw new Error(errorMsg);
			}
			return {
				carNum,
				aHref: aHref || "",
				url: aHref || "",
				title: title || "",
				publishTime: publishTime || ""
			};
		}
		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");
				}
			}
		}
		replaceHdImg(imgEls) {
			if (imgEls && typeof imgEls.jquery == "string") imgEls = imgEls.toArray();
			imgEls ||= document.querySelectorAll(this.getSelector().coverImgSelector);
			if (isJavdbSite) imgEls.forEach((img) => {
				img.src = img.src.replace("thumbs", "covers");
				img.title = "";
			});
			storageManager.getSetting("hoverBigImg", "no").then((setting) => {
				if (setting === "yes") {
					const win = window;
					if (win.imageHoverPreviewObj) win.imageHoverPreviewObj.bindEvents();
					else win.imageHoverPreviewObj = new ImagePreview({ selector: this.getSelector().coverImgSelector });
				}
			});
		}
		async translate($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 (this.cache[carNum]) {
				videoTitleEl.contents().each((_index, node) => {
					if (node.nodeType === 3 && node.textContent.trim() !== "") node.textContent = " " + this.cache[carNum] + " ";
				});
				videoTitleEl.attr("title", this.cache[carNum]);
				return;
			}
			translateText(sourceText).then((translation) => {
				if (isJavdbSite) {
					videoTitleEl.contents().each((_index, node) => {
						if (node.nodeType === 3 && node.textContent.trim() !== "" && !node.textContent.includes(carNum)) node.textContent = " " + translation + " ";
					});
					videoTitleEl.attr("title", translation);
				}
				this.writeQueue = this.writeQueue.then(() => {
					this.cache[carNum] = translation;
					localStorage.setItem("jhs_translate", JSON.stringify(this.cache));
				});
			}).catch((err) => {
				console.error("翻译失败:", err);
			});
		}
		async revertTranslation() {
			$(this.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");
				videoTitleEl.contents().each((_index, node) => {
					if (node.nodeType === 3 && node.textContent.trim() !== "" && !node.textContent.includes(carNum)) node.textContent = " " + originalTitle + " ";
				});
				videoTitleEl.removeAttr("title");
			});
		}
		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: currentPage + 1
			})));
			$(".pagination-list").append($li);
			const $pageInput = $li.find("#jumpPageInput");
			const $jumpBtn = $li.find("button");
			const jumpToPage = () => {
				const pageNum = parseInt($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();
				}
			});
		}
	};
	function PreviewVideoActionBtn({ id, color, label, hotKey }) {
		return (0, import_jsx_runtime.jsxs)("button", {
			className: "menu-btn",
			id,
			style: {
				minWidth: "120px",
				backgroundColor: color
			},
			children: [
				label,
				" ",
				hotKey ? `(${hotKey})` : ""
			]
		});
	}
	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
		});
	}
	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: rgba(0, 0, 0, 0.7);\n    color: white;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\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 DMM_VIDEO_CACHE_KEY = "jhs_dmm_video";
	var DMM_OTHER_SITE_KEY = "jhs_other_site_dmm";
	var VIDEO_MUTED_KEY = "jhs_videoMuted";
	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];
	};
	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, null, {
				"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.errors || [err];
				if (errors.some((e) => e.message.includes("节点不可用"))) {
					if (this.showErrorMessages) show.error("节点不可用,请将DMM域名分流到日本ip");
				} else {
					const firstMsg = errors[0].message || errors[0];
					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 PreviewVideoPlugin = class extends BasePlugin {
		filterHotKey = null;
		favoriteHotKey = null;
		speedVideoHotKey = null;
		getName() {
			return "PreviewVideoPlugin";
		}
		async initCss() {
			return preview_video_plugin_default;
		}
		async handle() {
			if (!window.isDetailPage) return;
			const settings = await storageManager.getSetting();
			this.filterHotKey = settings.filterHotKey;
			this.favoriteHotKey = settings.favoriteHotKey;
			this.speedVideoHotKey = settings.speedVideoHotKey;
			const $container = $(".preview-video-container");
			$container.on("click", () => {
				utils.loopDetector(() => $(".fancybox-content #preview-video").length > 0, () => {
					this.handleVideo().then();
				});
			});
			if (await storageManager.getSetting("enableLoadPreviewVideo", "yes") === "yes" && !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 })));
					$(".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() {
			if (await storageManager.getSetting("enableLoadPreviewVideo", "yes") === "no") return;
			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 = this.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: "屏蔽",
				hotKey: this.filterHotKey
			})));
			$actionGroup.append($filterBtn);
			const $favoriteBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
				id: "video-favoriteBtn",
				color: "#25b1dc",
				label: "收藏",
				hotKey: this.favoriteHotKey
			})));
			$actionGroup.append($favoriteBtn);
			const $speedBtn = $(jsxToString((0, import_jsx_runtime.jsx)(PreviewVideoActionBtn, {
				id: "speed-btn",
				color: "#76b45d",
				label: "快进",
				hotKey: this.speedVideoHotKey
			})));
			$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", () => {
				this.getBean("DetailPageButtonPlugin").speedVideo();
			});
			utils.rightClick(document.body, "#speed-btn", (event) => {
				this.getBean("DetailPageButtonPlugin").filterOne(event);
			});
			$("#video-filterBtn").on("click", (event) => {
				this.getBean("DetailPageButtonPlugin").filterOne(event);
			});
			$("#video-favoriteBtn").on("click", (event) => {
				this.getBean("DetailPageButtonPlugin").favoriteOne(event);
			});
		}
	};
	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 && 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$1(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: getCode$1,
		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 {\r\n    position: absolute;\r\n    bottom: 6px;\r\n    right: 6px;\r\n    z-index: 5;\r\n    pointer-events: auto;\r\n    font-size: 13px;\r\n    font-weight: 700;\r\n    line-height: 1;\r\n    padding: 5px 10px;\r\n    border-radius: 12px;\r\n    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(255,255,255,0.1) inset;\r\n    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);\r\n    color: #fff;\r\n    white-space: nowrap;\r\n    opacity: 0.95;\r\n    transition: transform 0.25s ease, opacity 0.2s ease, background 0.3s ease;\r\n    display: inline-flex;\r\n    align-items: center;\r\n    gap: 3px;\r\n    letter-spacing: 0.5px;\r\n}\r\n\r\n/* 占位(绿色) */\r\n.jhs-user-rating.is-placeholder {\r\n    background: linear-gradient(145deg, #48c78e, #2fb972);\r\n}\r\n\r\n/* 已评分(金色) */\r\n.jhs-user-rating.is-rated {\r\n    background: linear-gradient(145deg, #ffc107, #f57c00);\r\n}\r\n\r\n.jhs-rd-icon {\r\n    font-size: 14px;\r\n    filter: drop-shadow(0 1px 1px rgba(0,0,0,0.3));\r\n}\r\n\r\n.jhs-rd-num {\r\n    font-size: 14px;\r\n    font-weight: 900;\r\n}\r\n\r\n.jhs-user-rating:hover {\r\n    transform: scale(1.1);\r\n    opacity: 1;\r\n}\r\n\r\n/* 加载中 */\r\n.jhs-user-rating.is-loading {\r\n    animation: jhs-rd-pulse 1s infinite;\r\n    pointer-events: none;\r\n}\r\n\r\n@keyframes jhs-rd-pulse {\r\n    0%, 100% { opacity: 0.55; }\r\n    50% { opacity: 1; }\r\n}\r\n\r\n/* Toast */\r\n.jhs-rd-toast {\r\n    position: fixed;\r\n    left: 50%;\r\n    transform: translateX(-50%);\r\n    bottom: 2.5rem;\r\n    background: rgba(0, 0, 0, 0.88);\r\n    color: #fff;\r\n    padding: 0.5rem 0.9rem;\r\n    border-radius: 0.5rem;\r\n    z-index: 20000;\r\n    font-size: 0.85rem;\r\n    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);\r\n    animation: jhs-rd-toast-in 0.22s;\r\n    pointer-events: none;\r\n}\r\n\r\n@keyframes jhs-rd-toast-in {\r\n    from { opacity: 0; transform: translateX(-50%) translateY(8px); }\r\n    to { opacity: 1; transform: translateX(-50%) translateY(0); }\r\n}\r\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) {
			if (status === "hasWatch" && op === "add") {
				if (!this.watchedMap.has(code)) this.watchedMap.set(code, {
					carNum: code,
					status: "hasWatch"
				});
			} else this.watchedMap.delete(code);
			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 } = e.detail || {};
				if (!carNum || !status || !op) return;
				const code = RatingUtils.normalizeCode(carNum);
				RatingUtils.log("SYNC_EVENT", code, status, op);
				this._invalidateCards(code, status, op);
			}, { 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);
					}
				} 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 fc2_plugin_default = "/* Fc2Plugin 弹层样式(提取自未删减版 jhs.user.js Fc2Plugin.initCss) */\r\n\r\n/* 弹层样式 */\r\n.movie-detail-layer .layui-layer-title {\r\n    font-size: 18px;\r\n    color: #333;\r\n    background: #f8f8f8;\r\n}\r\n\r\n/* 容器样式 */\r\n.movie-detail-container {\r\n    margin: 40px;\r\n    height: 100%;\r\n    background: #fff;\r\n}\r\n\r\n.movie-poster-container {\r\n    flex: 0 0 60%;\r\n    padding: 15px;\r\n}\r\n\r\n.right-box {\r\n    flex: 1;\r\n    padding: 20px;\r\n    overflow-y: auto;\r\n}\r\n\r\n/* 预告片iframe */\r\n.movie-trailer {\r\n    width: 100%;\r\n    height: 100%;\r\n    min-height: 400px;\r\n    background: #000;\r\n    border-radius: 4px;\r\n}\r\n\r\n/* 电影信息样式 */\r\n.movie-title {\r\n    font-size: 24px;\r\n    margin-bottom: 15px;\r\n    color: #333;\r\n}\r\n\r\n.movie-meta {\r\n    margin-bottom: 20px;\r\n    color: #666;\r\n}\r\n\r\n.movie-meta span {\r\n    margin-right: 15px;\r\n}\r\n\r\n/* 演员列表 */\r\n.actor-list {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: 8px;\r\n    margin-top: 10px;\r\n}\r\n\r\n.actor-tag {\r\n    padding: 4px 12px;\r\n    background: #f0f0f0;\r\n    border-radius: 15px;\r\n    font-size: 12px;\r\n    color: #555;\r\n}\r\n\r\n/* 图片列表 */\r\n.image-list {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: 10px;\r\n    margin-top: 10px;\r\n}\r\n\r\n.movie-image-thumb {\r\n    width: 120px;\r\n    height: 80px;\r\n    object-fit: cover;\r\n    border-radius: 4px;\r\n    cursor: pointer;\r\n    transition: transform 0.3s;\r\n}\r\n\r\n.movie-image-thumb:hover {\r\n    transform: scale(1.05);\r\n}\r\n\r\n/* 加载中和错误状态 */\r\n.search-loading,\r\n.movie-error {\r\n    padding: 40px;\r\n    text-align: center;\r\n    color: #999;\r\n}\r\n\r\n.movie-error {\r\n    color: #f56c6c;\r\n}\r\n\r\n.fancybox-container {\r\n    z-index: 99999999;\r\n}\r\n\r\n/* 错误提示样式 */\r\n.movie-not-found,\r\n.movie-error {\r\n    text-align: center;\r\n    padding: 30px;\r\n    color: #666;\r\n}\r\n\r\n.movie-not-found h3,\r\n.movie-error h3 {\r\n    color: #f56c6c;\r\n    margin: 15px 0;\r\n}\r\n\r\n.icon-warning,\r\n.icon-error {\r\n    font-size: 50px;\r\n    color: #e6a23c;\r\n}\r\n\r\n.icon-error {\r\n    color: #f56c6c;\r\n}\r\n\r\n.fc2-movie-panel-info .panel-block {\r\n    padding: 0 !important;\r\n}\r\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 = `
            <div class="movie-detail-container">
                <!--<div class="movie-poster-container">
                    <iframe class="movie-trailer" frameborder="0" allowfullscreen scrolling="no"></iframe>
                </div>-->
               <!-- <div class="right-box">-->
                    <div class="movie-info-container">
                        <div class="search-loading">加载中...</div>
                    </div>

                    <div class="movie-panel-info fc2-movie-panel-info" style="margin-top:20px"><strong>第三方资源: </strong></div>

                    <div style="margin: 30px 0">
                        <a id="filterBtn" class="menu-btn" style="background-color:${BLOCK_COLOR}"><span>${BLOCK_TEXT}</span></a>
                        <a id="favoriteBtn" class="menu-btn" style="background-color:${FAVORITE_COLOR}"><span>${FAVORITE_TEXT}</span></a>
                        <a id="hasDownBtn" class="menu-btn" style="background-color:${HAS_DOWN_COLOR}"><span>${HAS_DOWN_TEXT$1}</span></a>
                        <a id="hasWatchBtn" class="menu-btn" style="background-color:${WATCHED_COLOR};"><span>${WATCHED_TEXT}</span></a>

                        <a id="search-subtitle-btn" class="menu-btn fr-btn" style="background:linear-gradient(to bottom, #8d5656, rgb(196,159,91))">
                            <span>字幕 (SubTitleCat)</span>
                        </a>
                        <a id="xunLeiSubtitleBtn" class="menu-btn fr-btn" style="background:linear-gradient(to left, #375f7c, #2196F3)">
                            <span>字幕 (迅雷)</span>
                        </a>
                        <a id="magnetSearchBtn" class="menu-btn fr-btn" style="width: 120px; background: linear-gradient(to right, rgb(245,140,1), rgb(84,161,29)); color: white; text-align: center; padding: 8px 0;">
                            <span>磁力搜索</span>
                        </a>
                    </div>
                    <div class="message video-panel" style="margin-top:20px">
                        <div id="magnets-content" class="magnet-links" style="margin: 0 0.75rem">
                            <div class="search-loading">加载中...</div>
                        </div>
                    </div>
                    <div id="reviews-content">
                    </div>
                    <div id="related-content">
                    </div>
                    <span id="data-actress" style="display: none"></span>
                <!--</div>-->
            </div>
        `;
			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: "<div id=\"magnetHubBox\"></div>",
							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(movieId, $("#reviews-content")).then();
			this.getBean("RelatedPlugin")?.showRelated($("#related-content"), movieId).then();
		}
		handleMovieDetail(movieId) {
			fetchMovieDetail(movieId).then((detail) => {
				const actors = detail.actors || [];
				const imgList = detail.imgList || [];
				let actorsHtml = "";
				if (actors.length > 0) {
					let actressNames = "";
					for (let i = 0; i < actors.length; i++) {
						const actor = actors[i];
						actorsHtml += `<span class="actor-tag"><a href="/actors/${actor.id}" target="_blank">${actor.name}</a></span>`;
						if (actor.gender === 0) actressNames += actor.name + " ";
					}
					$("#data-actress").text(actressNames);
				} else actorsHtml = "<span class=\"no-data\">暂无演员信息</span>";
				let imagesHtml = "";
				imagesHtml = Array.isArray(imgList) && imgList.length > 0 ? imgList.map((img, idx) => `
                <a href="${img}" data-fancybox="movie-gallery" data-caption="剧照 ${idx + 1}">
                    <img src="${img}" class="movie-image-thumb"  alt=""/>
                </a>
            `).join("") : "<div class=\"no-data\">暂无剧照</div>";
				$(".movie-info-container").html(`
                <h3 class="movie-title"><strong class="current-title">${detail.title || "无标题"}</strong></h3>
                <div class="movie-meta">
                    <span><strong>番号: </strong>${detail.carNum || "未知"}</span>
                    <span><strong>年份: </strong>${detail.releaseDate || "未知"}</span>
                    <span><strong>评分: </strong>${detail.score || "无"}</span>
                    <span><strong>时长: </strong>${detail.duration + " m" || "无"}</span>
                </div>
                <div class="movie-meta">
                    <span>
                        <strong>站点: </strong>
                        <a href="https://fc2ppvdb.com/articles/${(detail.carNum || "").replace("FC2-", "")}" target="_blank">fc2ppvdb</a>
                        <a style="margin-left: 5px;" href="https://adult.contents.fc2.com/article/${(detail.carNum || "").replace("FC2-", "")}/" target="_blank">fc2电子市场</a>
                    </span>
                </div>
                <div class="movie-actors">
                    <div class="actor-list"><strong>主演: </strong>${actorsHtml}</div>
                </div>
                <div class="movie-gallery" style="margin-top:10px">
                    <strong>剧照: </strong>
                    <div class="image-list">${imagesHtml}</div>
                </div>
                <div id="data-releaseDate" style="display: none">${detail.releaseDate || ""}</div>
            `);
				this.getBean("TranslatePlugin")?.translate(detail.carNum, false)?.then();
			}).catch((err) => {
				console.error(err);
				$(".movie-info-container").html(`
                <div class="movie-error">加载失败: ${err.message}</div>
            `);
			});
		}
		handleLongImg(carNumWithoutPrefix) {
			utils.loopDetector(() => $(".movie-gallery .image-list").length > 0, async () => {
				$(".movie-gallery .image-list").prepend(" <a class=\"tile-item screen-container\" style=\"overflow:hidden;max-height: 150px;max-width:150px; text-align:center;\"><div style=\"margin-top: 50px;color: #000;cursor: auto\">正在加载缩略图</div></a> ");
				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, null, 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 += `
                        <div class="item columns is-desktop ${rowClass}">
                            <div class="magnet-name column is-four-fifths">
                                <a href="magnet:?xt=urn:btih:${magnet.hash}" title="右鍵點擊並選擇「複製鏈接地址」">
                                    <span class="name">${magnet.name}</span>
                                    <br>
                                    <span class="meta">
                                        ${(magnet.size / 1024).toFixed(2)}GB, ${magnet.files_count}個文件
                                     </span>
                                    <br>
                                    <div class="tags">
                                        ${magnet.hd ? "<span class=\"tag is-primary is-small is-light\">高清</span>" : ""}
                                        ${magnet.cnsub ? "<span class=\"tag is-warning is-small is-light\">字幕</span>" : ""}
                                    </div>
                                </a>
                            </div>
                            <div class="buttons column">
                                <button class="button is-info is-small copy-to-clipboard" data-clipboard-text="magnet:?xt=urn:btih:${magnet.hash}" type="button">&nbsp;複製&nbsp;</button>
                            </div>
                            <div class="date column"><span class="time">${magnet.created_at}</span></div>
                        </div>
                    `;
				}
				else magnetsHtml = "<span class=\"no-data\">暂无磁力信息</span>";
				$("#magnets-content").html(magnetsHtml);
				$(".buttons button[data-clipboard-text*='magnet:']").each((_idx, btn) => {
					$(btn).parent().append($("<button>").text("115离线下载").addClass("button is-info is-small").click(async (event) => {
						event.stopPropagation();
						event.preventDefault();
						const loadingHandle = loading();
						try {
							await this.getBean("WangPan115TaskPlugin")?.handleAddTask($(btn).attr("data-clipboard-text"));
						} catch (err) {
							show.error("发生错误:" + err);
							console.error(err);
						} finally {
							loadingHandle.close();
						}
					}));
				});
			}).catch((err) => {
				console.error(err);
				$("#magnets-content").html(`
                <div class="movie-error">加载失败: ${err.message}</div>
            `);
			});
		}
		async openFc2Page(movieId, carNum, url) {
			const javdbUrl = await this.getBean("OtherSitePlugin")?.getJavDbUrl();
			window.open(`${javdbUrl}/users/collection_codes?movieId=${movieId}&carNum=${carNum}&url=${url}`);
		}
	};
	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";
		}
		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 = "/**\r\n * page-sort 插件样式 —— 排序按钮选中态。\r\n *\r\n * 原脚本 injectSortStyles() 用 document.createElement('style') 注入:\r\n *   style.textContent = `\r\n *       .button.is-small.selected-method,\r\n *       .button.is-small.selected-method:hover {\r\n *           background-color: rgb(25, 135, 84) !important;\r\n *           border-color: transparent !important;\r\n *           color: #fff !important;\r\n *       }\r\n *   `;\r\n *\r\n * 此处提取为独立 .css,由 initCss() 返回 → PluginManager utils.insertStyle 注入。\r\n * CSS 规则内容与原脚本一致(缩进标准化为 4 空格,CSS 解析忽略空白,渲染等价)。\r\n */\r\n.button.is-small.selected-method,\r\n.button.is-small.selected-method:hover {\r\n    background-color: rgb(25, 135, 84) !important;\r\n    border-color: transparent !important;\r\n    color: #fff !important;\r\n}\r\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$1($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$1($(a)) - getScore$1($(b))),
			implemented: true
		},
		{
			label: "按照评分降序",
			sortFn: (items) => items.sort((a, b) => getScore$1($(b)) - getScore$1($(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;
			if (await storageManager.getSetting("autoPage") === "yes") return;
			this.waitForContainer();
		}
		waitForContainer() {
			console.log(`${LOG$2} 等待页面容器加载...`);
			new MutationObserver((_mutations, obs) => {
				if ($("body > section > div").length) {
					obs.disconnect();
					console.log(`${LOG$2} 页面容器已就绪,开始注入排序选择器`);
					this.createSortSelector();
				}
			}).observe(document.body, {
				childList: true,
				subtree: true
			});
		}
		createSortSelector() {
			const $toolbar = $("body > section > div > div.toolbar");
			if (!$toolbar.length) {
				console.warn(`${LOG$2} 未找到工具栏 .toolbar,跳过排序选择器注入`);
				return;
			}
			const $container = $("body > section > div > div.movie-list.h.cols-4.vcols-8");
			if (!$container.length) {
				console.warn(`${LOG$2} 未找到视频列表容器 .movie-list,跳过排序选择器注入`);
				return;
			}
			this.$container = $container;
			const $items = $container.children(".item");
			if ($items.length === 0) {
				console.warn(`${LOG$2} 视频列表为空,跳过排序选择器注入`);
				return;
			}
			$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} 个影片`);
		}
		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_filter_plugin_default = "/**\r\n * status-tag-filter 插件样式 —— 状态标签筛选栏 + 芯片。\r\n *\r\n * 原脚本 GM_addStyle(`...`) 注入,此处提取为独立 .css,由 initCss() 返回 →\r\n * PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进标准化,\r\n * CSS 解析忽略空白,渲染等价)。\r\n */\r\n.status-tag-filter-bar {\r\n    display: flex;\r\n    align-items: flex-start;\r\n    gap: 8px;\r\n    padding: 8px 0 12px 0;\r\n    border-bottom: 1px solid #e9ecef;\r\n}\r\n.status-tag-filter-label {\r\n    flex-shrink: 0;\r\n    font-size: 0.8em;\r\n    font-weight: 600;\r\n    color: #6c757d;\r\n    line-height: 1.8;\r\n    margin-right: 4px;\r\n}\r\n.status-tag-filter-chips {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: 6px;\r\n}\r\n.status-tag-filter-chip {\r\n    display: inline-block;\r\n    padding: 0.25em 0.7em;\r\n    font-size: 0.75em;\r\n    font-weight: 600;\r\n    line-height: 1.5;\r\n    border-radius: 50rem;\r\n    cursor: pointer;\r\n    user-select: none;\r\n    border: 1.5px solid #dee2e6;\r\n    background: #fff;\r\n    color: #495057;\r\n    transition: all 0.15s ease;\r\n}\r\n.status-tag-filter-chip:hover {\r\n    border-color: #adb5bd;\r\n    background: #f8f9fa;\r\n}\r\n.status-tag-filter-chip.active {\r\n    background: #198754;\r\n    border-color: #198754;\r\n    color: #fff;\r\n}\r\n.status-tag-filter-chip.no-status {\r\n    border-style: dashed;\r\n    color: #6c757d;\r\n}\r\n.status-tag-filter-chip.no-status.active {\r\n    background: #6c757d;\r\n    border-color: #6c757d;\r\n    border-style: solid;\r\n    color: #fff;\r\n}\r\n";
	var LOG$1 = "[状态标签筛选]";
	var HIDDEN_ATTR = "data-status-tag-hidden";
	var JHS_HIDE_ATTR = "data-hide";
	var STATUS_TAG_SELECTOR = ".item .tags.has-addons .tag.is-success.status-tag";
	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(JHS_HIDE_ATTR)) 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(JHS_HIDE_ATTR)) return;
			if (!item.querySelector(STATUS_TAG_SELECTOR)) count++;
		});
		return count;
	}
	var StatusTagFilterPlugin = class extends BasePlugin {
		observerDebounce = null;
		observer = null;
		getName() {
			return "StatusTagFilterPlugin";
		}
		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 不存在,延后初始化`);
				setTimeout(() => this.init(), 100);
				return;
			}
			if (this.tryBuild()) {
				this.startObserving();
				return;
			}
			console.log(`${LOG$1} 未找到挂载目标,开始 MutationObserver 等待`);
			let mountDebounce = null;
			const mountObserver = new MutationObserver(() => {
				if (mountDebounce) clearTimeout(mountDebounce);
				mountDebounce = setTimeout(() => {
					if (this.tryBuild()) {
						console.log(`${LOG$1} MutationObserver 挂载成功`);
						mountObserver.disconnect();
						this.startObserving();
						if (mountTimeout) clearTimeout(mountTimeout);
					}
				}, 100);
			});
			mountObserver.observe(document.body, {
				childList: true,
				subtree: true
			});
			const mountTimeout = setTimeout(() => {
				mountObserver.disconnect();
				if (!document.querySelector(".status-tag-filter-bar")) {
					const fallback = this.findMountTarget() || document.body.firstElementChild;
					if (fallback) {
						this.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 = this.findMountTarget();
			if (!mountTarget) return false;
			this.doBuild(mountTarget);
			return true;
		}
		findMountTarget() {
			const tagFilterBar = document.querySelector(".tag-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(".tag-filter-bar, .status-tag-filter-bar")) return section.firstElementChild;
			}
			const container = document.querySelector("body > section > div");
			if (container && container.firstElementChild) {
				if (!container.firstElementChild.matches(".tag-filter-bar, .status-tag-filter-bar")) return container.firstElementChild;
			}
			return null;
		}
		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 noCount = countNoStatusItems();
				const noTagChip = this.createFilterChip("无状态标签", NO_TAG_VALUE, {
					isNoTag: true,
					count: noCount
				});
				if (activeValues.has(NO_TAG_VALUE)) noTagChip.classList.add("active");
				chipsContainer.appendChild(noTagChip);
				const allCounts = collectStatusTagCounts();
				Object.keys(allCounts).sort().forEach((tagName) => {
					const chip = this.createFilterChip(tagName, tagName, { count: allCounts[tagName] });
					if (activeValues.has(tagName)) chip.classList.add("active");
					chipsContainer.appendChild(chip);
				});
			};
			refreshChips();
			if (mountTarget.matches(".tag-filter-bar, .actor-tags.tags, .tabs.is-boxed")) mountTarget.insertAdjacentElement("afterend", filterBar);
			else mountTarget.insertAdjacentElement("beforebegin", filterBar);
			filterBar._refreshChips = refreshChips;
			console.log(`${LOG$1} 筛选栏已挂载`);
		}
		createFilterChip(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");
				this.applyFilter();
			});
			return chip;
		}
		applyFilter() {
			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(JHS_HIDE_ATTR)) 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";
				}
			});
		}
		updateFilterBar() {
			const filterBar = document.querySelector(".status-tag-filter-bar");
			if (filterBar && filterBar._refreshChips) {
				filterBar._refreshChips();
				this.applyFilter();
			}
		}
		startObserving() {
			this.observer = new MutationObserver((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) {
					if (this.observerDebounce) clearTimeout(this.observerDebounce);
					this.observerDebounce = setTimeout(() => {
						this.updateFilterBar();
					}, 150);
				}
			});
			this.observer.observe(document.body, {
				childList: true,
				subtree: true
			});
		}
	};
	var list_waterfall_plugin_default = "/**\r\n * list-waterfall 插件样式 —— 瀑布流 loader 三态 + 回到顶部按钮。\r\n *\r\n * 原脚本 GM_addStyle(`...`) 注入(L80-153),此处提取为独立 .css,由 initCss()\r\n * 返回 → PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进\r\n * 标准化,CSS 解析忽略空白,渲染等价)。\r\n */\r\n.jdb-wf-loader {\r\n    text-align: center;\r\n    padding: 24px 0 40px;\r\n    font-size: 0.9rem;\r\n    color: #6c757d;\r\n    min-height: 44px;\r\n    box-sizing: border-box;\r\n}\r\n.jdb-wf-loader.loading {\r\n    color: #485fc7;\r\n}\r\n.jdb-wf-loader.loading::before {\r\n    content: \"\";\r\n    display: inline-block;\r\n    width: 14px;\r\n    height: 14px;\r\n    margin-right: 8px;\r\n    border: 2px solid currentColor;\r\n    border-top-color: transparent;\r\n    border-radius: 50%;\r\n    vertical-align: -2px;\r\n    animation: jdb-wf-spin 0.8s linear infinite;\r\n}\r\n.jdb-wf-loader.error {\r\n    color: #f44336;\r\n    cursor: pointer;\r\n    text-decoration: underline;\r\n}\r\n.jdb-wf-loader.no-more {\r\n    color: #4CAF50;\r\n}\r\n@keyframes jdb-wf-spin {\r\n    to {\r\n        transform: rotate(360deg);\r\n    }\r\n}\r\n\r\n/* 回到顶部按钮 */\r\n#jdb-wf-back-to-top {\r\n    position: fixed;\r\n    bottom: 40px;\r\n    right: 40px;\r\n    width: 44px;\r\n    height: 44px;\r\n    background-color: rgba(30, 30, 30, 0.9);\r\n    backdrop-filter: blur(4px);\r\n    color: #e0e0e0;\r\n    border-radius: 50%;\r\n    display: flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    cursor: pointer;\r\n    z-index: 9999;\r\n    opacity: 0;\r\n    visibility: hidden;\r\n    transform: translateY(20px) scale(0.9);\r\n    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\r\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\r\n    border: 1px solid rgba(255, 255, 255, 0.05);\r\n    user-select: none;\r\n}\r\n#jdb-wf-back-to-top:hover {\r\n    background-color: #ff8400;\r\n    color: #fff;\r\n    transform: translateY(0) scale(1);\r\n    box-shadow: 0 8px 20px rgba(255, 132, 0, 0.3);\r\n    border-color: #ff8400;\r\n}\r\n#jdb-wf-back-to-top.show {\r\n    opacity: 1;\r\n    visibility: visible;\r\n    transform: translateY(0) scale(1);\r\n}\r\n#jdb-wf-back-to-top svg {\r\n    width: 22px;\r\n    height: 22px;\r\n    fill: currentColor;\r\n    stroke: currentColor;\r\n    stroke-width: 0;\r\n}\r\n";
	var LOG_PREFIX$3 = "[listWaterfall]";
	var ENABLED_KEY = "jdb:list-waterfall-enabled";
	var PRELOAD_DISTANCE = 800;
	var MAX_PAGES = 200;
	var ALLOWED_PATHS = new Set(["/users/lists", "/users/favorite_lists"]);
	var SEL = {
		box: "#lists > ul",
		item: "#lists > ul > li",
		nextLink: "a.pagination-next",
		paginationNav: "nav.pagination",
		itemLink: "div.column.is-10 > a"
	};
	function getInitialPage() {
		const m = location.search.match(/[?&]page=(\d+)/);
		return m ? parseInt(m[1], 10) : 1;
	}
	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 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;
		backToTopBtn = null;
		_ticking = false;
		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.loader.addEventListener("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.createBackToTopBtn();
			this._onScroll = () => {
				this.checkLoad();
				this.updateCurrentPageFromScroll();
				this.updateBackToTopBtn();
			};
			window.addEventListener("scroll", this._onScroll, { passive: true });
			setTimeout(() => this.checkLoad(), 500);
			if (!this.hasMore) this.setState("no-more", "已经到底了");
			else this.setState("", "");
			console.log(`${LOG_PREFIX$3} 已启动 (页码 ${this.currentPage})`);
		}
		async loadNextPage() {
			if (this.isLoading || !this.nextUrl || !this.hasMore) return;
			if (this.currentPage >= MAX_PAGES) {
				this.setState("no-more", `已达最大页数 ${MAX_PAGES},停止加载`);
				this.hasMore = false;
				return;
			}
			this.isLoading = true;
			this.setState("loading", "加载中...");
			try {
				const html = await gmGet(this.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 && this.loadedIds.has(newLis[0].id)) {
					this.hasMore = false;
					this.nextUrl = null;
					this.setState("no-more", "已经到底了");
					console.log(`${LOG_PREFIX$3} 检测到重复数据,停止瀑布流`);
					return;
				}
				const topBefore = this.container.scrollHeight;
				const fragment = document.createDocumentFragment();
				newLis.forEach((li) => {
					if (li.id) this.loadedIds.add(li.id);
					fragment.appendChild(li);
				});
				this.container.appendChild(fragment);
				rewriteItemLinks(this.container);
				this.currentPage += 1;
				this.pageItems.push({
					page: this.currentPage,
					top: topBefore,
					url: this.nextUrl
				});
				const nextHref = findNextUrl(doc);
				this.nextUrl = nextHref ? toAbsolute(nextHref) : null;
				this.hasMore = !!this.nextUrl;
				const remoteNav = doc.querySelector(SEL.paginationNav);
				if (remoteNav) {
					const currentNav = document.querySelector(SEL.paginationNav);
					if (currentNav) currentNav.replaceWith(remoteNav);
				}
				this.setState("", "");
				if (!this.hasMore) this.setState("no-more", "已经到底了");
				console.log(`${LOG_PREFIX$3} 已加载第 ${this.currentPage} 页,追加 ${newLis.length} 项`);
			} catch (err) {
				console.error(`${LOG_PREFIX$3} 加载失败:`, err);
				this.setState("error", "加载失败,点击重试");
			} finally {
				this.isLoading = false;
			}
		}
		checkLoad() {
			if (!this.loader || !this.hasMore) return;
			if (this.loader.getBoundingClientRect().top < window.innerHeight + PRELOAD_DISTANCE) this.loadNextPage();
		}
		updateCurrentPageFromScroll() {
			const y = window.scrollY;
			for (let i = this.pageItems.length - 1; i >= 0; i--) {
				const item = this.pageItems[i];
				if (y >= item.top) {
					if (this.currentPage !== item.page) {
						this.currentPage = item.page;
						window.history.replaceState({}, "", item.url);
					}
					break;
				}
			}
		}
		setState(cls, text) {
			if (!this.loader) return;
			this.loader.className = `jdb-wf-loader ${cls}`.trim();
			this.loader.textContent = text;
		}
		createBackToTopBtn() {
			const btn = document.createElement("div");
			btn.id = "jdb-wf-back-to-top";
			btn.title = "回到顶部";
			btn.innerHTML = "<svg viewBox=\"0 0 24 24\"><path d=\"M12 4l-8 8h6v8h4v-8h6z\"></path></svg>";
			document.body.appendChild(btn);
			btn.addEventListener("click", () => {
				window.scrollTo({
					top: 0,
					behavior: "smooth"
				});
			});
			this.backToTopBtn = btn;
		}
		updateBackToTopBtn() {
			if (!this.backToTopBtn || this._ticking) return;
			this._ticking = true;
			window.requestAnimationFrame(() => {
				if (window.scrollY > 300) this.backToTopBtn.classList.add("show");
				else this.backToTopBtn.classList.remove("show");
				this._ticking = false;
			});
		}
	};
	var list_reading_status_plugin_default = "/**\r\n * list-reading-status 插件样式 —— 阅读进度下拉框 + 星级评分 + 排序筛选工具栏。\r\n *\r\n * 原脚本 3 段 GM_addStyle(L263-303 下拉框 / L305-349 星级评分+访问链接 /\r\n * L353-445 工具栏),此处合并提取为独立 .css,由 initCss() 返回 →\r\n * PluginManager utils.insertStyle 注入。CSS 规则内容与原脚本一致(缩进标准化,\r\n * CSS 解析忽略空白,渲染等价)。\r\n */\r\n\r\n/* ---------- 阅读进度下拉框 ---------- */\r\n.list-reading-dropdown {\r\n    appearance: none;\r\n    -webkit-appearance: none;\r\n    display: inline-flex;\r\n    align-items: center;\r\n    height: 24px;\r\n    padding: 0 24px 0 10px;\r\n    font-size: 0.72rem;\r\n    font-weight: 600;\r\n    line-height: 22px;\r\n    border-radius: 50rem;\r\n    cursor: pointer;\r\n    user-select: none;\r\n    border: 1.5px solid #ced4da;\r\n    color: #6c757d;\r\n    background-color: #fff;\r\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\");\r\n    background-repeat: no-repeat;\r\n    background-position: right 8px center;\r\n    background-size: 10px 6px;\r\n    transition: all 0.2s ease;\r\n    margin-right: 6px;\r\n    vertical-align: middle;\r\n}\r\n.list-reading-dropdown:hover {\r\n    border-color: #adb5bd;\r\n    background-color: #f8f9fa;\r\n}\r\n.list-reading-dropdown[data-status=\"read\"] {\r\n    color: #fff;\r\n    background-color: #198754;\r\n    border-color: #198754;\r\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\");\r\n}\r\n.list-reading-dropdown[data-status=\"read\"]:hover {\r\n    background-color: #157347;\r\n    border-color: #157347;\r\n}\r\n\r\n/* ---------- 星级评分 ---------- */\r\n.list-rating-stars {\r\n    display: inline-flex;\r\n    gap: 2px;\r\n    cursor: pointer;\r\n    user-select: none;\r\n    margin-right: 10px;\r\n    vertical-align: middle;\r\n    align-items: center;\r\n}\r\n.list-rating-star {\r\n    width: 18px;\r\n    height: 18px;\r\n    flex-shrink: 0;\r\n    transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),\r\n                filter 0.2s ease;\r\n}\r\n.list-rating-star path {\r\n    fill: #cbd5e1;\r\n    stroke: #94a3b8;\r\n    stroke-width: 0.6;\r\n    transition: fill 0.2s ease, stroke 0.2s ease;\r\n}\r\n.list-rating-star.filled path {\r\n    fill: #f59e0b;\r\n    stroke: #d97706;\r\n}\r\n.list-rating-star:hover {\r\n    transform: scale(1.25);\r\n}\r\n.list-rating-star.filled:hover {\r\n    filter: drop-shadow(0 0 5px rgba(245, 158, 11, 0.45));\r\n}\r\n.list-last-uri-link {\r\n    font-size: 0.72rem;\r\n    color: #485fc7;\r\n    margin-left: 8px;\r\n    text-decoration: none;\r\n    transition: color 0.15s ease;\r\n}\r\n.list-last-uri-link:hover {\r\n    color: #363636;\r\n    text-decoration: underline;\r\n}\r\n\r\n/* ---------- 排序与筛选工具栏 ---------- */\r\n.list-toolbar {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    align-items: center;\r\n    gap: 8px 16px;\r\n    padding: 10px 0;\r\n    margin-bottom: 6px;\r\n    border-bottom: 1px solid #e9ecef;\r\n    font-size: 0.82rem;\r\n}\r\n.list-toolbar-group {\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 6px;\r\n    flex-wrap: wrap;\r\n}\r\n.list-toolbar-label {\r\n    font-weight: 600;\r\n    color: #6c757d;\r\n    flex-shrink: 0;\r\n}\r\n.list-sort-select {\r\n    appearance: none;\r\n    -webkit-appearance: none;\r\n    height: 26px;\r\n    padding: 0 22px 0 10px;\r\n    font-size: 0.78rem;\r\n    font-weight: 600;\r\n    border: 1.5px solid #ced4da;\r\n    border-radius: 50rem;\r\n    color: #495057;\r\n    background-color: #fff;\r\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\");\r\n    background-repeat: no-repeat;\r\n    background-position: right 8px center;\r\n    background-size: 10px 6px;\r\n    cursor: pointer;\r\n    transition: all 0.2s ease;\r\n}\r\n.list-sort-select:hover {\r\n    border-color: #adb5bd;\r\n    background-color: #f8f9fa;\r\n}\r\n.list-filter-chip {\r\n    display: inline-flex;\r\n    align-items: center;\r\n    padding: 2px 10px;\r\n    font-size: 0.76rem;\r\n    font-weight: 600;\r\n    border: 1.5px solid #dee2e6;\r\n    border-radius: 50rem;\r\n    color: #6c757d;\r\n    background-color: #fff;\r\n    cursor: pointer;\r\n    user-select: none;\r\n    transition: all 0.15s ease;\r\n    line-height: 1.4;\r\n}\r\n.list-filter-chip:hover {\r\n    border-color: #adb5bd;\r\n    background-color: #f8f9fa;\r\n}\r\n.list-filter-chip.active {\r\n    color: #fff;\r\n    background-color: #485fc7;\r\n    border-color: #485fc7;\r\n}\r\n.list-filter-chip .chip-count {\r\n    margin-left: 4px;\r\n    opacity: 0.85;\r\n    font-weight: 700;\r\n}\r\n.list-filter-divider {\r\n    width: 1px;\r\n    height: 18px;\r\n    background: #dee2e6;\r\n    margin: 0 4px;\r\n    flex-shrink: 0;\r\n}\r\n.list-toolbar-reset {\r\n    font-size: 0.74rem;\r\n    color: #adb5bd;\r\n    cursor: pointer;\r\n    text-decoration: none;\r\n    margin-left: auto;\r\n    transition: color 0.15s ease;\r\n}\r\n.list-toolbar-reset:hover {\r\n    color: #6c757d;\r\n    text-decoration: underline;\r\n}\r\n";
	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";
	var LRS_HIDDEN_ATTR = "data-lrs-hidden";
	var LRS_ORDER_ATTR = "data-lrs-order";
	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";
	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 ListReadingStatusPlugin = class extends BasePlugin {
		isProcessing = false;
		currentSort = "default";
		filterReadStatus = "all";
		filterRatingChips = new Set();
		isToolbarProcessing = false;
		orderCounter = 0;
		lastLiCount = -1;
		observer = null;
		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.observer = new MutationObserver(() => {
				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);
					}
				}
			});
			this.observer.observe(document.body, {
				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();
				});
			}
		}
		updateSelectAppearance(select) {
			select.setAttribute("data-status", select.value);
		}
		renderStars(starsEl, rating) {
			starsEl.querySelectorAll(".list-rating-star").forEach((svg, i) => {
				if (i < rating) svg.classList.add("filled");
				else svg.classList.remove("filled");
			});
		}
		createStarWidget(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");
				svg.addEventListener("click", (e) => {
					e.stopPropagation();
					const clicked = parseInt(svg.dataset.rating || "0");
					const newRating = clicked === getRating(listId) ? 0 : clicked;
					setRating(listId, newRating);
					this.renderStars(container, newRating);
				});
				svg.addEventListener("mouseenter", () => {
					this.renderStars(container, parseInt(svg.dataset.rating || "0"));
				});
				container.appendChild(svg);
			}
			container.addEventListener("mouseleave", () => {
				this.renderStars(container, getRating(listId));
			});
			return container;
		}
		createDropdown(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";
			this.updateSelectAppearance(select);
			select.addEventListener("change", () => {
				if (select.value === "read") markAsRead(listId);
				else markAsUnread(listId);
				this.updateSelectAppearance(select);
			});
			return select;
		}
		ensureWidgets(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";
				this.updateSelectAppearance(select);
			} else {
				select = this.createDropdown(listId);
				container.prepend(select);
			}
			let stars = container.querySelector(".list-rating-stars");
			if (stars) this.renderStars(stars, getRating(listId));
			else {
				stars = this.createStarWidget(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();
		}
		ensureHeaderWidgets() {
			if (this.isProcessing) return;
			this.isProcessing = true;
			const m = location.pathname.match(/\/lists\/([^/]+)$/);
			if (!m) {
				this.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) {
				this.isProcessing = false;
				return;
			}
			let select = h2.querySelector(".list-reading-dropdown");
			if (select) {
				select.value = isRead(listId) ? "read" : "unread";
				this.updateSelectAppearance(select);
			} else {
				select = this.createDropdown(listId);
				h2.prepend(select);
			}
			let stars = h2.querySelector(".list-rating-stars");
			if (stars) this.renderStars(stars, getRating(listId));
			else {
				stars = this.createStarWidget(listId);
				h2.prepend(stars);
			}
			Promise.resolve().then(() => {
				this.isProcessing = false;
			});
		}
		processAllItems() {
			if (this.isProcessing) return false;
			this.isProcessing = true;
			const ul = document.querySelector("#lists > ul");
			if (!ul) {
				this.isProcessing = false;
				return false;
			}
			const items = ul.querySelectorAll(":scope > li");
			items.forEach((li) => this.ensureWidgets(li));
			this.applySortAndFilter();
			Promise.resolve().then(() => {
				this.isProcessing = false;
			});
			return items.length > 0;
		}
		loadToolbarState() {
			const s = GM_getValue(SORT_KEY);
			if (s) this.currentSort = s;
			const r = GM_getValue(FILTER_READ_KEY);
			if (r === "read" || r === "unread") this.filterReadStatus = r;
			const rc = GM_getValue(FILTER_RATING_KEY);
			if (rc) try {
				const arr = JSON.parse(rc);
				if (Array.isArray(arr)) this.filterRatingChips = new Set(arr);
			} catch {
				this.filterRatingChips = new Set();
			}
		}
		saveSortState(v) {
			this.currentSort = v;
			GM_setValue(SORT_KEY, v);
		}
		saveFilterReadState(v) {
			this.filterReadStatus = v;
			GM_setValue(FILTER_READ_KEY, v);
		}
		saveFilterRatingState(set) {
			this.filterRatingChips = set;
			GM_setValue(FILTER_RATING_KEY, JSON.stringify([...set]));
		}
		getListMeta(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(LRS_ORDER_ATTR) || "0") || 0
			};
		}
		ensureLiOrder(li) {
			if (!li.hasAttribute(LRS_ORDER_ATTR)) li.setAttribute(LRS_ORDER_ATTR, String(this.orderCounter++));
		}
		compareLi(a, b) {
			const ma = this.getListMeta(a);
			const mb = this.getListMeta(b);
			let cmp = 0;
			switch (this.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;
		}
		applySort() {
			if (this.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) => this.ensureLiOrder(li));
			lis.sort((a, b) => this.compareLi(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);
		}
		matchesFilter(li) {
			const listId = li.id;
			if (!listId) return true;
			if (this.filterReadStatus !== "all") {
				const read = isRead(listId);
				if (this.filterReadStatus === "read" && !read) return false;
				if (this.filterReadStatus === "unread" && read) return false;
			}
			if (this.filterRatingChips.size > 0) {
				const rating = getRating(listId);
				let match = false;
				if (this.filterRatingChips.has("rated") && rating > 0) match = true;
				if (this.filterRatingChips.has("unrated") && rating === 0) match = true;
				for (let i = 1; i <= 5; i++) if (this.filterRatingChips.has(`rating-${i}`) && rating === i) {
					match = true;
					break;
				}
				if (!match) return false;
			}
			return true;
		}
		applyFilter() {
			const ul = document.querySelector("#lists > ul");
			if (!ul) return;
			const lis = ul.querySelectorAll(":scope > li");
			if (this.filterReadStatus === "all" && this.filterRatingChips.size === 0) {
				lis.forEach((li) => {
					const htmlLi = li;
					if (htmlLi.hasAttribute(LRS_HIDDEN_ATTR)) {
						htmlLi.removeAttribute(LRS_HIDDEN_ATTR);
						htmlLi.style.display = "";
					}
				});
				return;
			}
			lis.forEach((li) => {
				const htmlLi = li;
				if (htmlLi.style.display === "none" && !htmlLi.hasAttribute(LRS_HIDDEN_ATTR)) return;
				if (this.matchesFilter(htmlLi)) {
					htmlLi.removeAttribute(LRS_HIDDEN_ATTR);
					htmlLi.style.display = "";
				} else {
					htmlLi.setAttribute(LRS_HIDDEN_ATTR, "");
					htmlLi.style.display = "none";
				}
			});
		}
		applySortAndFilter() {
			if (this.isToolbarProcessing) return;
			this.isToolbarProcessing = true;
			try {
				this.applySort();
				this.applyFilter();
			} finally {
				this.isToolbarProcessing = false;
			}
		}
		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;
		}
		createFilterChip(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);
			chip.addEventListener("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");
						this.saveFilterReadState(value);
					} else this.saveFilterReadState("all");
				} else {
					chip.classList.toggle("active");
					const next = new Set(this.filterRatingChips);
					if (chip.classList.contains("active")) next.add(value);
					else next.delete(value);
					this.saveFilterRatingState(next);
				}
				this.applySortAndFilter();
			});
			return chip;
		}
		buildToolbar() {
			if (this.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 === this.currentSort) opt.selected = true;
				sortSelect.appendChild(opt);
			});
			sortSelect.addEventListener("change", () => {
				this.saveSortState(sortSelect.value);
				this.applySortAndFilter();
			});
			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 = "重置筛选";
			reset.addEventListener("click", (e) => {
				e.preventDefault();
				this.saveSortState("default");
				this.saveFilterReadState("all");
				this.saveFilterRatingState(new Set());
				sortSelect.value = "default";
				toolbar.querySelectorAll(".list-filter-chip.active").forEach((c) => c.classList.remove("active"));
				this.applySortAndFilter();
			});
			toolbar.appendChild(reset);
			lists.insertAdjacentElement("beforebegin", toolbar);
			toolbar._readHost = readChipsHost;
			toolbar._ratingHost = ratingChipsHost;
			toolbar._sortSelect = sortSelect;
			this.refreshChips(toolbar);
			console.log(`${LOG_PREFIX$2} 排序与筛选工具栏已挂载`);
			return toolbar;
		}
		refreshChips(toolbar) {
			const stats = this.countFilterStats();
			const readHost = toolbar._readHost;
			if (readHost) {
				readHost.innerHTML = "";
				const readChip = this.createFilterChip("已读完", "read", stats.read);
				if (this.filterReadStatus === "read") readChip.classList.add("active");
				readHost.appendChild(readChip);
				const unreadChip = this.createFilterChip("未读完", "unread", stats.unread);
				if (this.filterReadStatus === "unread") unreadChip.classList.add("active");
				readHost.appendChild(unreadChip);
			}
			const ratingHost = toolbar._ratingHost;
			if (ratingHost) {
				ratingHost.innerHTML = "";
				const ratedChip = this.createFilterChip("有评分", "rated", stats.rated);
				if (this.filterRatingChips.has("rated")) ratedChip.classList.add("active");
				ratingHost.appendChild(ratedChip);
				const unratedChip = this.createFilterChip("无评分", "unrated", stats.unrated);
				if (this.filterRatingChips.has("unrated")) unratedChip.classList.add("active");
				ratingHost.appendChild(unratedChip);
				for (let i = 1; i <= 5; i++) {
					const starChip = this.createFilterChip(`${i}星`, `rating-${i}`, stats.stars[i - 1]);
					if (this.filterRatingChips.has(`rating-${i}`)) starChip.classList.add("active");
					ratingHost.appendChild(starChip);
				}
			}
		}
		tryBuildToolbar() {
			if (this.isDetailPage) return false;
			const toolbar = this.buildToolbar();
			if (!toolbar) return false;
			this.refreshChips(toolbar);
			this.applySortAndFilter();
			return true;
		}
		restoreToolbarUI() {
			const toolbar = document.querySelector(".list-toolbar");
			if (!toolbar) return;
			const sortSelect = toolbar._sortSelect;
			if (sortSelect) sortSelect.value = this.currentSort;
			this.refreshChips(toolbar);
		}
	};
	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 {
		observer = null;
		getName() {
			return "ModalListDisablerPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			this.tryDisable();
			this.observer = new MutationObserver(() => {
				this.tryDisable();
			});
			this.observer.observe(document.body, {
				childList: true,
				subtree: true
			});
		}
		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 SPAN_SELECTOR = "div.columns.is-mobile.section-columns span.actor-section-name";
	var MAX_RETRIES = 50;
	var RETRY_INTERVAL = 200;
	var ListParserPlugin = class extends BasePlugin {
		getName() {
			return "ListParserPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			if (!location.pathname.startsWith("/lists/")) return;
			if (location.pathname.startsWith("/users/")) return;
			this.waitForAndInsert();
		}
		waitForAndInsert(retries = MAX_RETRIES, interval = RETRY_INTERVAL) {
			let attempts = 0;
			const id = setInterval(() => {
				if (this.insertWakeButton() || ++attempts >= retries) clearInterval(id);
			}, interval);
		}
		insertWakeButton() {
			const span = document.querySelector(SPAN_SELECTOR);
			if (!span) return false;
			if (document.getElementById("lists-protocol-wake-btn")) return true;
			const btn = document.createElement("button");
			btn.id = "lists-protocol-wake-btn";
			btn.type = "button";
			btn.textContent = "唤醒解析器";
			btn.style.marginLeft = "8px";
			btn.style.verticalAlign = "middle";
			btn.style.display = "inline-block";
			btn.style.fontWeight = "400";
			btn.style.lineHeight = "1.5";
			btn.style.textAlign = "center";
			btn.style.whiteSpace = "nowrap";
			btn.style.userSelect = "none";
			btn.style.border = "1px solid #0d6efd";
			btn.style.padding = "0.25rem 0.5rem";
			btn.style.fontSize = "0.875rem";
			btn.style.borderRadius = "0.25rem";
			btn.style.backgroundColor = "#0d6efd";
			btn.style.color = "#fff";
			btn.style.cursor = "pointer";
			btn.style.transition = "color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out";
			btn.addEventListener("mouseenter", () => {
				btn.style.backgroundColor = "#0b5ed7";
				btn.style.borderColor = "#0a58ca";
			});
			btn.addEventListener("mouseleave", () => {
				btn.style.backgroundColor = "#0d6efd";
				btn.style.borderColor = "#0d6efd";
			});
			btn.addEventListener("click", (e) => {
				e.preventDefault();
				const fullUrl = location.origin + location.pathname;
				const protocolUrl = "lists://?url=" + encodeURIComponent(fullUrl);
				location.href = protocolUrl;
			});
			span.insertAdjacentElement("afterend", btn);
			return true;
		}
	};
	var video_lists_tag_default = "/**\r\n * video-lists-tag 插件样式 —— 标签显示 + 筛选栏 + Toast。\r\n *\r\n * 合并自 archetype/videoListsTag.user.js 的 GM_addStyle(L24-275)\r\n * 和 archetype/listsOptionSync.user.js 的 injectToastStyles(L40-115)。\r\n * CSS 规则内容与原脚本一致(缩进标准化,渲染等价)。\r\n */\r\n\r\n/* ---------- 标签显示(Bootstrap Badge Pill 风格) ---------- */\r\n.custom-tags-display {\r\n    margin: 5px 0;\r\n    padding: 6px;\r\n    white-space: nowrap;\r\n    overflow-x: auto;\r\n    overflow-y: hidden;\r\n    scrollbar-width: none;\r\n    -webkit-overflow-scrolling: touch;\r\n    padding-bottom: 2px;\r\n}\r\n.custom-tags-display::-webkit-scrollbar {\r\n    display: none;\r\n}\r\n.custom-tag-link {\r\n    display: inline-block;\r\n    padding: 0.35em 0.65em;\r\n    margin-right: 6px;\r\n    font-size: 0.75em;\r\n    font-weight: 700;\r\n    line-height: 1;\r\n    text-align: center;\r\n    white-space: nowrap;\r\n    vertical-align: baseline;\r\n    border-radius: 50rem;\r\n    text-decoration: none;\r\n    color: #fff;\r\n    transition: filter 0.15s ease, transform 0.15s ease;\r\n    box-shadow: 0 1px 2px rgba(0,0,0,0.1);\r\n}\r\n.custom-tag-link:hover {\r\n    filter: brightness(0.92);\r\n    transform: translateY(-1px);\r\n    box-shadow: 0 2px 5px rgba(0,0,0,0.15);\r\n}\r\n.custom-tag-link.light-bg {\r\n    color: #212529;\r\n}\r\n\r\n/* ---------- 标签筛选栏 ---------- */\r\n.tag-filter-bar {\r\n    display: flex;\r\n    align-items: flex-start;\r\n    gap: 8px;\r\n    padding: 8px 0 12px 0;\r\n    border-bottom: 1px solid #e9ecef;\r\n}\r\n.tag-filter-label {\r\n    flex-shrink: 0;\r\n    font-size: 0.8em;\r\n    font-weight: 600;\r\n    color: #6c757d;\r\n    line-height: 1.8;\r\n    margin-right: 4px;\r\n}\r\n.tag-filter-chips {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: 6px;\r\n}\r\n.tag-filter-chip {\r\n    display: inline-block;\r\n    padding: 0.25em 0.7em;\r\n    font-size: 0.75em;\r\n    font-weight: 600;\r\n    line-height: 1.5;\r\n    border-radius: 50rem;\r\n    cursor: pointer;\r\n    user-select: none;\r\n    border: 1.5px solid #dee2e6;\r\n    background: #fff;\r\n    color: #495057;\r\n    transition: all 0.15s ease;\r\n}\r\n.tag-filter-chip:hover {\r\n    border-color: #adb5bd;\r\n    background: #f8f9fa;\r\n}\r\n.tag-filter-chip.active {\r\n    background: #0d6efd;\r\n    border-color: #0d6efd;\r\n    color: #fff;\r\n}\r\n.tag-filter-chip.no-tag {\r\n    border-style: dashed;\r\n    color: #6c757d;\r\n}\r\n.tag-filter-chip.no-tag.active {\r\n    background: #6c757d;\r\n    border-color: #6c757d;\r\n    border-style: solid;\r\n    color: #fff;\r\n}\r\n\r\n/* ---------- 自动刷新开关 ---------- */\r\n.auto-refresh-toggle {\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 6px;\r\n    margin-left: auto;\r\n    flex-shrink: 0;\r\n    font-size: 0.78em;\r\n    color: #6c757d;\r\n    user-select: none;\r\n}\r\n.auto-refresh-switch {\r\n    position: relative;\r\n    width: 36px;\r\n    height: 20px;\r\n    flex-shrink: 0;\r\n}\r\n.auto-refresh-switch input {\r\n    opacity: 0;\r\n    width: 0;\r\n    height: 0;\r\n}\r\n.auto-refresh-slider {\r\n    position: absolute;\r\n    inset: 0;\r\n    background: #ced4da;\r\n    border-radius: 50rem;\r\n    cursor: pointer;\r\n    transition: background 0.2s;\r\n}\r\n.auto-refresh-slider::before {\r\n    content: \"\";\r\n    position: absolute;\r\n    left: 2px;\r\n    top: 2px;\r\n    width: 16px;\r\n    height: 16px;\r\n    border-radius: 50%;\r\n    background: #fff;\r\n    transition: transform 0.2s;\r\n}\r\n.auto-refresh-switch input:checked + .auto-refresh-slider {\r\n    background: #198754;\r\n}\r\n.auto-refresh-switch input:checked + .auto-refresh-slider::before {\r\n    transform: translateX(16px);\r\n}\r\n\r\n/* ---------- 筛选模式下拉 ---------- */\r\n.filter-mode-dropdown {\r\n    position: relative;\r\n    display: inline-block;\r\n    flex-shrink: 0;\r\n}\r\n.filter-mode-summary {\r\n    display: inline-flex;\r\n    align-items: center;\r\n    gap: 6px;\r\n    padding: 0.25em 0.7em;\r\n    font-size: 0.75em;\r\n    font-weight: 600;\r\n    line-height: 1.5;\r\n    border-radius: 50rem;\r\n    cursor: pointer;\r\n    user-select: none;\r\n    border: 1.5px solid #dee2e6;\r\n    background: #fff;\r\n    color: #495057;\r\n    transition: all 0.15s ease;\r\n    list-style: none;\r\n}\r\n.filter-mode-summary::-webkit-details-marker {\r\n    display: none;\r\n}\r\n.filter-mode-summary:hover {\r\n    border-color: #adb5bd;\r\n    background: #f8f9fa;\r\n}\r\n.filter-mode-indicator {\r\n    display: inline-block;\r\n    width: 8px;\r\n    height: 8px;\r\n    border-radius: 50%;\r\n    flex-shrink: 0;\r\n}\r\n.filter-mode-indicator.include {\r\n    background: #0d6efd;\r\n    box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.2);\r\n}\r\n.filter-mode-indicator.exclude {\r\n    background: #dc3545;\r\n    box-shadow: 0 0 0 2px rgba(220, 53, 69, 0.2);\r\n}\r\n.filter-mode-arrow {\r\n    font-size: 0.7em;\r\n    color: #adb5bd;\r\n    transition: transform 0.2s;\r\n}\r\n.filter-mode-dropdown[open] .filter-mode-arrow {\r\n    transform: rotate(180deg);\r\n}\r\n.filter-mode-panel {\r\n    position: absolute;\r\n    top: calc(100% + 4px);\r\n    left: 0;\r\n    min-width: 190px;\r\n    background: #fff;\r\n    border: 1px solid #dee2e6;\r\n    border-radius: 8px;\r\n    box-shadow: 0 4px 16px rgba(0,0,0,0.12);\r\n    padding: 4px 0;\r\n    z-index: 1000;\r\n    animation: filterModeIn 0.15s ease;\r\n}\r\n@keyframes filterModeIn {\r\n    from { opacity: 0; transform: translateY(-4px); }\r\n    to { opacity: 1; transform: translateY(0); }\r\n}\r\n.filter-mode-item {\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 8px;\r\n    padding: 6px 14px;\r\n    font-size: 0.78em;\r\n    font-weight: 500;\r\n    color: #495057;\r\n    cursor: pointer;\r\n    transition: background 0.1s;\r\n    white-space: nowrap;\r\n}\r\n.filter-mode-item:hover {\r\n    background: #f8f9fa;\r\n}\r\n.filter-mode-item.selected {\r\n    background: rgba(13, 110, 253, 0.08);\r\n    color: #0d6efd;\r\n    font-weight: 600;\r\n}\r\n.filter-mode-item.exclude.selected {\r\n    background: rgba(220, 53, 69, 0.08);\r\n    color: #dc3545;\r\n}\r\n.filter-mode-item .filter-mode-indicator {\r\n    flex-shrink: 0;\r\n}\r\n.filter-mode-separator {\r\n    height: 1px;\r\n    margin: 4px 8px;\r\n    background: #e9ecef;\r\n}\r\n\r\n/* ---------- Toast 通知 ---------- */\r\n#jdb-toast-container {\r\n    position: fixed;\r\n    top: 20px;\r\n    left: 20px;\r\n    z-index: 99999;\r\n    display: flex;\r\n    flex-direction: column;\r\n    pointer-events: none;\r\n}\r\n.jdb-toast {\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 10px;\r\n    min-width: 220px;\r\n    max-width: 380px;\r\n    max-height: 200px;\r\n    padding: 12px 16px;\r\n    border-radius: 8px;\r\n    font-size: 13px;\r\n    font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\r\n    color: #fff;\r\n    line-height: 1.4;\r\n    box-shadow: 0 4px 16px rgba(0,0,0,.28);\r\n    backdrop-filter: blur(6px);\r\n    pointer-events: auto;\r\n    overflow: hidden;\r\n    margin-bottom: 8px;\r\n    animation: jdb-toast-in .2s cubic-bezier(.21,1.02,.73,1) forwards;\r\n    transition: opacity .2s, transform .2s, max-height .2s, margin-bottom .2s;\r\n}\r\n.jdb-toast:last-child {\r\n    margin-bottom: 0;\r\n}\r\n.jdb-toast.removing {\r\n    opacity: 0;\r\n    max-height: 0;\r\n    margin-bottom: 0;\r\n    padding-top: 0;\r\n    padding-bottom: 0;\r\n    transform: translateX(-20px);\r\n}\r\n.jdb-toast--stacked {\r\n    max-height: 10px;\r\n    opacity: 0.35;\r\n    transform: translateX(12px);\r\n    margin-bottom: 2px;\r\n    cursor: pointer;\r\n}\r\n.jdb-toast--success { background: rgba(22,163,74,.92); }\r\n.jdb-toast--error   { background: rgba(220,38,38,.92); }\r\n.jdb-toast--warning { background: rgba(217,119,6,.92); }\r\n.jdb-toast--info    { background: rgba(37,99,235,.92); }\r\n.jdb-toast__icon {\r\n    flex-shrink: 0;\r\n    width: 20px;\r\n    height: 20px;\r\n    display: flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n}\r\n.jdb-toast__msg {\r\n    flex: 1;\r\n    word-break: break-word;\r\n}\r\n@keyframes jdb-toast-in {\r\n    from { opacity: 0; transform: translateX(-30px); }\r\n    to { opacity: 1; transform: translateX(0); }\r\n}\r\n";
	var bootstrapColors = [
		{
			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 = bootstrapColors[Math.floor(Math.random() * bootstrapColors.length)];
		return {
			bg: color.bg,
			text: color.text,
			isLight: color.text !== "#fff"
		};
	}
	var TAG_HIDDEN_ATTR = "data-video-lists-tag-hidden";
	var AUTO_REFRESH_KEY = "jdb:auto-refresh-enabled";
	var LAST_SYNC_KEY$1 = "jdb:last-sync";
	var FILTER_MODES = {
		CONTAINS_ANY: "contains-any",
		CONTAINS_ALL: "contains-all",
		EXCLUDES_ALL: "excludes-all",
		EXCLUDES_ANY: "excludes-any"
	};
	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 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);
	}
	var VltTags = class {
		tagsCache = null;
		currentFilterMode = FILTER_MODES.CONTAINS_ANY;
		autoRefreshEnabled = true;
		pendingNewItems = [];
		debounceTimer = null;
		DEBOUNCE_MS = 300;
		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) {
			if (item.querySelector(".custom-tags-display")) return;
			const strongEl = item.querySelector("a > div.video-title > strong");
			if (!strongEl) return;
			const designation = strongEl.innerHTML;
			if (!this.tagsCache) return;
			const meta = item.querySelector(".meta");
			if (!meta) return;
			const container = document.createElement("div");
			container.className = "custom-tags-display";
			const tags = this.tagsCache[designation];
			if (tags && tags.length > 0) tags.forEach((tag) => {
				const urlTrimmed = tag.url?.trim();
				const hasUrl = !!urlTrimmed;
				const el = document.createElement(hasUrl ? "a" : "span");
				el.className = "custom-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("light-bg");
				} else {
					const color = getRandomBootstrapColor();
					el.style.backgroundColor = color.bg;
					el.style.color = color.text;
					if (color.isLight) el.classList.add("light-bg");
				}
				container.appendChild(el);
			});
			else {
				const placeholder = document.createElement("span");
				placeholder.className = "custom-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);
		}
		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) {
				console.error(`自动刷新标签数据失败(${lists.length} 个番号):`, err);
				return;
			}
			document.querySelectorAll(".custom-tags-display").forEach((el) => el.remove());
			document.querySelectorAll(".item").forEach((item) => this.addTagDisplay(item));
			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) {
				console.error(`[视频清单标签] 刷新 ${designation} 失败:`, err);
				return;
			}
			const newTags = this.tagsCache[designation] || [];
			if (tagsEqual(oldTags, newTags)) {
				console.log(`[视频清单标签] ${designation} 标签未变化,跳过 DOM 更新 (${newTags.length} 个标签)`);
				return;
			}
			const oldContainer = targetItem.querySelector(".custom-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() {
			const activeChips = document.querySelectorAll(".tag-filter-chip.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(TAG_HIDDEN_ATTR)) return;
				const tagLinks = item.querySelectorAll(".custom-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 (this.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";
				}
			});
		}
		buildFilterModeDropdown() {
			const details = document.createElement("details");
			details.className = "filter-mode-dropdown";
			const summary = document.createElement("summary");
			summary.className = "filter-mode-summary";
			const indicator = document.createElement("span");
			indicator.className = "filter-mode-indicator";
			summary.appendChild(indicator);
			const modeText = document.createElement("span");
			modeText.className = "filter-mode-text";
			summary.appendChild(modeText);
			const arrow = document.createElement("span");
			arrow.className = "filter-mode-arrow";
			arrow.textContent = "▼";
			summary.appendChild(arrow);
			details.appendChild(summary);
			const panel = document.createElement("div");
			panel.className = "filter-mode-panel";
			const updateModeUI = () => {
				const config = FILTER_MODE_CONFIG.find((m) => m.value === this.currentFilterMode) || FILTER_MODE_CONFIG[0];
				modeText.textContent = config.label;
				indicator.className = "filter-mode-indicator " + config.group;
				panel.querySelectorAll(".filter-mode-item").forEach((el) => {
					el.classList.toggle("selected", el.dataset.mode === this.currentFilterMode);
				});
			};
			let lastGroup = null;
			FILTER_MODE_CONFIG.forEach((mode) => {
				if (lastGroup && lastGroup !== mode.group) {
					const separator = document.createElement("div");
					separator.className = "filter-mode-separator";
					panel.appendChild(separator);
				}
				lastGroup = mode.group;
				const item = document.createElement("div");
				item.className = "filter-mode-item";
				if (mode.group === "exclude") item.classList.add("exclude");
				item.dataset.mode = mode.value;
				const dot = document.createElement("span");
				dot.className = "filter-mode-indicator " + mode.group;
				item.appendChild(dot);
				const text = document.createElement("span");
				text.textContent = mode.label;
				item.appendChild(text);
				item.addEventListener("click", () => {
					this.currentFilterMode = mode.value;
					updateModeUI();
					details.open = false;
					this.applyFilter();
				});
				panel.appendChild(item);
			});
			details.appendChild(panel);
			details._updateModeUI = updateModeUI;
			updateModeUI();
			return details;
		}
		buildFilterBar() {
			if (document.querySelector(".tag-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 = "tag-filter-bar";
			const label = document.createElement("span");
			label.className = "tag-filter-label";
			label.textContent = "筛选:";
			filterBar.appendChild(label);
			const modeDropdown = this.buildFilterModeDropdown();
			filterBar.appendChild(modeDropdown);
			filterBar._modeDropdown = modeDropdown;
			const chipsContainer = document.createElement("div");
			chipsContainer.className = "tag-filter-chips";
			filterBar.appendChild(chipsContainer);
			const toggleWrapper = document.createElement("label");
			toggleWrapper.className = "auto-refresh-toggle";
			toggleWrapper.title = "监听清单操作,自动刷新标签";
			const switchSpan = document.createElement("span");
			switchSpan.className = "auto-refresh-switch";
			const checkbox = document.createElement("input");
			checkbox.type = "checkbox";
			checkbox.checked = this.autoRefreshEnabled;
			const slider = document.createElement("span");
			slider.className = "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", () => {
				this.autoRefreshEnabled = checkbox.checked;
				this.saveAutoRefreshState(this.autoRefreshEnabled);
				if (this.autoRefreshEnabled) console.log("[视频清单标签] 自动刷新已开启");
				else console.log("[视频清单标签] 自动刷新已关闭");
			});
			const createFilterChip = (labelText, value, opts = {}) => {
				const { isNoTag = false, count } = opts;
				const chip = document.createElement("span");
				chip.className = "tag-filter-chip";
				if (isNoTag) chip.classList.add("no-tag");
				chip.textContent = count !== void 0 ? `${labelText} ${count}` : labelText;
				chip.dataset.value = value;
				chip.addEventListener("click", () => {
					chip.classList.toggle("active");
					this.applyFilter();
				});
				return chip;
			};
			const refreshChips = () => {
				const activeValues = new Set(Array.from(chipsContainer.querySelectorAll(".tag-filter-chip.active")).map((c) => c.dataset.value || ""));
				chipsContainer.innerHTML = "";
				const allCounts = this.collectTagCounts();
				const noCount = this.countNoTagItems();
				const noTagChip = createFilterChip("无标签", "no-tag", {
					isNoTag: true,
					count: noCount
				});
				if (activeValues.has("no-tag")) noTagChip.classList.add("active");
				chipsContainer.appendChild(noTagChip);
				this.collectAllUniqueTags().forEach((tagName) => {
					const chip = createFilterChip(tagName, tagName, { count: allCounts[tagName] });
					if (activeValues.has(tagName)) chip.classList.add("active");
					chipsContainer.appendChild(chip);
				});
			};
			refreshChips();
			mountTarget.insertAdjacentElement("afterend", filterBar);
			filterBar._refreshChips = refreshChips;
		}
		updateFilterBar() {
			const filterBar = document.querySelector(".tag-filter-bar");
			if (filterBar && filterBar._refreshChips) {
				filterBar._refreshChips();
				this.applyFilter();
			}
		}
		collectAllUniqueTags() {
			const tagNames = new Set();
			document.querySelectorAll(".custom-tag-link:not([style*='pointer-events: none'])").forEach((el) => {
				const name = el.textContent?.trim() || "";
				if (name && name !== "—") tagNames.add(name);
			});
			return [...tagNames].sort();
		}
		collectTagCounts() {
			const counts = {};
			document.querySelectorAll(".custom-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;
		}
		countNoTagItems() {
			let count = 0;
			document.querySelectorAll(".item").forEach((item) => {
				if (item.querySelectorAll(".custom-tag-link:not([style*='pointer-events: none'])").length === 0) count++;
			});
			return count;
		}
		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) {
				console.error("获取标签数据失败:", err);
				this.tagsCache = {};
				return;
			}
			items.forEach((item) => this.addTagDisplay(item));
			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) {
					console.error("[视频清单标签] 获取新增标签数据失败:", err);
					return;
				}
				itemsToRefresh.forEach((item) => {
					const oldContainer = item.querySelector(".custom-tags-display");
					if (oldContainer) oldContainer.remove();
					this.addTagDisplay(item);
				});
				this.updateFilterBar();
				console.log(`[视频清单标签] 已为 ${uncachedCodes.length} 个新番号获取标签`);
			}, this.DEBOUNCE_MS);
		}
		setupAutoRefreshListener(onSync) {
			let lastRefreshTime = 0;
			const DEBOUNCE_MS = 500;
			const NO_CHANGE_ASSOCS = new Set([
				"existed",
				"limit_exceeded",
				"unchanged"
			]);
			const handleSyncNotify = (payload) => {
				if (!this.autoRefreshEnabled) {
					console.log("[视频清单标签] 收到同步事件但自动刷新已关闭,跳过");
					return;
				}
				if (!payload || !payload.designation) {
					console.warn("[视频清单标签] 收到同步事件但无 designation:", payload);
					return;
				}
				if (NO_CHANGE_ASSOCS.has(payload.association)) {
					console.log(`[视频清单标签] association=${payload.association} 不影响标签,跳过`);
					return;
				}
				const now = Date.now();
				if (now - lastRefreshTime < DEBOUNCE_MS) {
					console.log(`[视频清单标签] 距上次刷新 ${now - lastRefreshTime}ms < ${DEBOUNCE_MS}ms,防抖跳过`);
					return;
				}
				lastRefreshTime = now;
				console.log("[视频清单标签] 收到同步事件 → 精准刷新", payload);
				onSync(payload);
			};
			document.addEventListener("jdb:sync-complete", (e) => {
				console.log("[视频清单标签] [CustomEvent] 收到 jdb:sync-complete");
				handleSyncNotify(e.detail);
			});
			window.addEventListener("storage", (e) => {
				if (e.key !== LAST_SYNC_KEY$1) return;
				console.log(`[视频清单标签] [storage] key=${e.key} newValue=${e.newValue ? "<set>" : "<empty>"}`);
				if (!e.newValue) return;
				let payload;
				try {
					payload = JSON.parse(e.newValue);
				} catch {
					return;
				}
				handleSyncNotify(payload);
			});
			GM_addValueChangeListener(LAST_SYNC_KEY$1, (_name, _oldValue, newValue, remote) => {
				console.log(`[视频清单标签] [GM_addValueChangeListener] remote=${remote} newValue=${newValue ? "<set>" : "<empty>"}`);
				if (!newValue) return;
				let payload;
				try {
					payload = JSON.parse(newValue);
				} catch {
					return;
				}
				handleSyncNotify(payload);
			});
			console.log(`[视频清单标签] 自动刷新监听已就绪 (autoRefreshEnabled=${this.autoRefreshEnabled})`);
		}
	};
	var LOG_PREFIX = "[JavDB]";
	var LAST_SYNC_KEY = "jdb:last-sync";
	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"
		})
	};
	function getSeries(d) {
		if (!d) return d;
		const i = d.indexOf("-");
		return i > 0 ? d.slice(0, i) : d;
	}
	function getCode(d) {
		if (!d) return null;
		const i = d.indexOf("-");
		return i > 0 ? d.slice(i + 1) : null;
	}
	function getScore() {
		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();
		return _cachedScore;
	}
	function getMovieInfo(videoId) {
		const detail = document.querySelector(".video-detail");
		if (!detail) {
			console.warn(`${LOG_PREFIX} 未找到 .video-detail,跳过`);
			return null;
		}
		const desEl = detail.querySelector(".panel-block.first-block a[data-clipboard-text]");
		if (!desEl) {
			console.warn(`${LOG_PREFIX} 未找到番号元素,跳过`);
			return null;
		}
		const designation = desEl.dataset.clipboardText || "";
		if (!designation) {
			console.warn(`${LOG_PREFIX} 番号为空,跳过`);
			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(designation),
				code: getCode(designation) || ""
			}
		};
	}
	function getListName(listId) {
		const input = document.querySelector(`input[data-list-id="${listId}"]`);
		if (!input) return "";
		const label = input.closest("label");
		if (!label) return "";
		return label.textContent.replace(/\(.*?\)/g, "").replace(/\s+/g, " ").trim();
	}
	function getListInfo(listId) {
		return {
			list_id: listId,
			info: {
				url: "https://javdb.com/lists/" + listId + "?locale=zh",
				name: getListName(listId)
			}
		};
	}
	async function syncMoviesLists(movieInfo, listInfo, action) {
		console.log(`${LOG_PREFIX} 同步(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);
		console.log(`${LOG_PREFIX} 同步结果: movie=${result.movie} list=${result.list} association=${result.association}`);
		return result;
	}
	var debounceTimers = new Map();
	async function handleCheckboxChange(movieInfo, listInfo, checked) {
		const des = movieInfo.designation;
		const lname = listInfo.info.name;
		const action = checked ? "add" : "remove";
		console.log(`${LOG_PREFIX} ═══ ${checked ? "勾选" : "取消"} [${des}] → ${lname} ═══`);
		let result;
		try {
			result = await syncMoviesLists(movieInfo, listInfo, action);
		} catch (err) {
			console.error(`${LOG_PREFIX} 同步失败`, err);
			showToast$1(`✗ [${des}] 同步失败:${err.message || "请检查 IndexedDB"}`, "error");
			return;
		}
		const created = [];
		if (result.movie === "created") created.push("影片");
		if (result.list === "created") created.push("清单");
		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");
		console.log(`${LOG_PREFIX} ═══ 完成 ═══`);
		const syncPayload = {
			designation: des,
			action,
			association: result.association,
			time: Date.now()
		};
		const payloadStr = JSON.stringify(syncPayload);
		GM_setValue(LAST_SYNC_KEY, payloadStr);
		localStorage.setItem(LAST_SYNC_KEY, payloadStr);
		document.dispatchEvent(new CustomEvent("jdb:sync-complete", { detail: syncPayload }));
	}
	function setupCheckboxListener() {
		document.addEventListener("change", (e) => {
			const target = e.target;
			if (target.tagName !== "INPUT" || target.type !== "checkbox" || target.dataset.action !== "change->list#listCheckboxChanged") return;
			const input = target;
			const movieInfo = getMovieInfo(input.value);
			if (!movieInfo) {
				console.warn(`${LOG_PREFIX} 无法获取影片信息,跳过`);
				return;
			}
			const listInfo = getListInfo(input.dataset.listId || "");
			if (!listInfo.info.name) {
				console.warn(`${LOG_PREFIX} 无法获取清单名称,跳过`);
				return;
			}
			const checked = input.checked;
			const key = `${movieInfo.designation}::${listInfo.list_id}`;
			clearTimeout(debounceTimers.get(key));
			debounceTimers.set(key, setTimeout(() => {
				handleCheckboxChange(movieInfo, listInfo, checked).then();
			}, 300));
		});
	}
	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();
				return;
			}
			if (!window.isListPage) return;
			this.vltTags = new VltTags();
			await this.vltTags.initExistingItems();
			this.setupItemObserver();
			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 logInfo$1(step, ...args) {
		console.log(`%c${LOG_PREFIX_JHS} %c${step}`, "color:#25b1dc;font-weight:bold;", "color:inherit;font-weight:bold;", ...args);
	}
	function logOk$1(step, ...args) {
		console.log(`%c${LOG_PREFIX_JHS} ✓ %c${step}`, "color:#1f7a3d;font-weight:bold;", "color:inherit;font-weight:bold;", ...args);
	}
	function logWarn$1(step, ...args) {
		console.warn(`%c${LOG_PREFIX_JHS} ⚠ ${step}`, "color:#d7a80c;font-weight:bold;", ...args);
	}
	function logErr$1(step, ...args) {
		console.error(`%c${LOG_PREFIX_JHS} ✗ ${step}`, "color:#de3333;font-weight:bold;", ...args);
	}
	var isFullSyncing = false;
	var CarListReaderPlugin = class extends BasePlugin {
		getName() {
			return "CarListReaderPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			if (window.self !== window.top) return;
			try {
				GM_registerMenuCommand("🔁 全量同步车辆状态到 missav", () => {
					this.syncFullCarStatus();
				});
			} catch {}
			storageManager.setCarListChangeCallback((event) => {
				this.pushDelta(event);
			});
			setTimeout(() => this.syncFullCarStatus(), 2e3);
		}
		pushDelta(event) {
			try {
				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
						};
					});
					const payload = {
						action: "upsert",
						items,
						ts: Date.now()
					};
					GM_setValue(GM_KEY_CAR_STATUS_DELTA, payload);
					logInfo$1("增量推送", `upsert ${items.length} 条`);
				} else if (event.action === "delete" && event.deletes) {
					const payload = {
						action: "delete",
						items: event.deletes.map((carNum) => ({ carNum })),
						ts: Date.now()
					};
					GM_setValue(GM_KEY_CAR_STATUS_DELTA, payload);
					logInfo$1("增量推送", `delete ${event.deletes.length} 条`);
				}
			} catch (err) {
				logErr$1("增量推送失败", err.message || String(err));
			}
		}
		async syncFullCarStatus() {
			if (isFullSyncing) {
				logWarn$1("全量同步任务在进行中,跳过");
				return;
			}
			isFullSyncing = true;
			try {
				logInfo$1("全量同步开始");
				const carList = await storageManager.getCarList();
				logInfo$1("1-读取", `本地 car_list 记录数:${carList.length}`);
				if (carList.length === 0) {
					logWarn$1("car_list 为空,跳过同步(jhs 可能尚未写入数据)");
					return;
				}
				const colRes = toColumnar(carList);
				const count = countColumnar(colRes.byStatus);
				logInfo$1("2-转列存", `列存 ${count} 条 / 丢弃 ${colRes.dropped} / url 异常 ${colRes.malformed}`);
				if (count === 0) {
					logWarn$1("列存后无有效记录,跳过");
					return;
				}
				const base64 = await gzipToBase64(colRes.byStatus);
				if (!base64) {
					logErr$1("gzip 压缩失败(CompressionStream 不可用?非 https 环境?)");
					return;
				}
				logInfo$1("3-压缩", `gzip+base64 体积:约 ${(base64.length / 1024).toFixed(1)} KB`);
				const payload = {
					data: base64,
					hwm: new Date().toISOString(),
					count,
					ts: Date.now()
				};
				GM_setValue(GM_KEY_CAR_STATUS_DATA, payload);
				logOk$1("4-完成", `已写入 GM 存储,count=${count},hwm=${payload.hwm}`);
			} catch (err) {
				logErr$1("全量同步失败", err.message || String(err), err);
			} finally {
				isFullSyncing = false;
			}
		}
	};
	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.textContent = cfg.label;
		a.href = url || "javascript:;";
		a.target = "_blank";
		a.rel = "noopener noreferrer";
		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) {
			if (item.querySelector(".missav-status-tag")) continue;
			total++;
			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 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;
	}
	function logInfo(msg, ...args) {
		console.log(`%c${LOG_PREFIX_MISSAV} %c${msg}`, "color:#25b1dc;font-weight:bold;", "", ...args);
	}
	function logOk(msg, ...args) {
		console.log(`%c${LOG_PREFIX_MISSAV} ✓%c ${msg}`, "color:#1f7a3d;font-weight:bold;", "", ...args);
	}
	function logWarn(msg, ...args) {
		console.warn(`%c${LOG_PREFIX_MISSAV} ⚠%c ${msg}`, "color:#d7a80c;font-weight:bold;", "", ...args);
	}
	function logErr(msg, ...args) {
		console.error(`%c${LOG_PREFIX_MISSAV} ✗%c ${msg}`, "color:#de3333;font-weight:bold;", "", ...args);
	}
	var isFullConsuming = false;
	var MissavStatusTagPlugin = class extends BasePlugin {
		getName() {
			return "MissavStatusTagPlugin";
		}
		async initCss() {
			return "";
		}
		async handle() {
			logInfo("脚本启动", `页面类型: ${isVideoPage() ? "视频播放页" : "列表页"}`);
			try {
				GM_registerMenuCommand("🔄 MissAV 刷新标签", () => {
					this.processAll();
				});
			} catch {}
			try {
				GM_addValueChangeListener(GM_KEY_CAR_STATUS_DELTA, (_key, _oldValue, newValue, remote) => {
					if (remote && newValue) this.consumeDelta(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);
			this.observeAndProcess();
		}
		async consumeDelta(delta) {
			try {
				if (delta.action === "upsert" && delta.items) {
					const records = delta.items.map((item) => ({
						carNum: item.carNum,
						status: item.status || "",
						url_path: item.url_path || ""
					}));
					await upsertLocalCars(records);
					logInfo("增量更新", `upsert ${records.length} 条`);
				} else if (delta.action === "delete" && delta.items) {
					const carNums = delta.items.map((item) => item.carNum);
					await deleteLocalCars(carNums);
					logInfo("增量更新", `delete ${carNums.length} 条`);
				}
				await this.processAll();
			} catch (err) {
				logErr("增量消费失败", err.message || String(err));
			}
		}
		async consumeFull(payload) {
			if (isFullConsuming) {
				logWarn("全量消费任务在进行中");
				return;
			}
			isFullConsuming = true;
			try {
				const data = payload ?? GM_getValue("jhs_car_status_data");
				if (!data || !data.data) {
					if (payload !== void 0) logWarn("GM 存储中无全量数据");
					return;
				}
				logInfo("全量消费开始", `count=${data.count} hwm=${data.hwm}`);
				const store = await gunzipFromBase64(data.data);
				if (!store) {
					logErr("解压失败(DecompressionStream 不可用?数据损坏?)");
					return;
				}
				const records = columnarToFlat(store);
				if (records.length === 0) {
					logWarn("解压后无有效记录");
					return;
				}
				logInfo("解压完成", `${records.length} 条记录`);
				logOk("写入本地 IDB", `${await upsertLocalCars(records)} 条`);
				await this.processAll();
			} catch (err) {
				logErr("全量消费失败", err.message || String(err));
			} finally {
				isFullConsuming = false;
			}
		}
		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.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, "视频页-侧边推荐");
		}
		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"]
			});
		}
	};
	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();
			document.body.removeChild(a);
			console.log(`${LOG} 执行 模拟单击 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 svgStr = `<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>`;
		const template = document.createElement("template");
		template.innerHTML = svgStr.trim();
		return template.content.firstChild;
	}
	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 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);
	unsafeWindow.utils = window.utils = new CommonUtil();
	unsafeWindow.gmHttp = window.gmHttp = new GmHttp();
	unsafeWindow.storageManager = window.storageManager = new StorageManager();
	unsafeWindow.loadGfriends = window.loadGfriends = loadGfriends;
	unsafeWindow.filetreeDb = window.filetreeDb = filetreeDb;
	unsafeWindow.WebDavClient = 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);
	unsafeWindow.loading = window.loading = createLoading;
	unsafeWindow.show = 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 = null;
			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.clog = unsafeWindow.parent.clog;
			else window.clog = unsafeWindow.clog = new Logger();
		} catch (err) {
			console.error("创建日志控制台出现异常", err);
			window.clog = unsafeWindow.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();
	document.addEventListener("keydown", (event) => {
		Hotkey.handleKeydown(event);
	});
	document.addEventListener("keyup", (event) => {
		Hotkey.handleKeyup(event);
	});
	unsafeWindow.encryptCredential = window.encryptCredential = encryptCredential;
	unsafeWindow.decryptCredential = window.decryptCredential = decryptCredential;
	setupLayerWrapper();
	var pluginManager = (function() {
		const manager = new PluginManager();
		unsafeWindow.pluginManager = manager;
		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(FilterTitleKeywordPlugin);
			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(ListParserPlugin);
			manager.register(VideoListsTagPlugin);
			manager.register(CarListReaderPlugin);
		}
		if (isMissavSite) {
			manager.register(MissavStatusTagPlugin);
			manager.register(MissavQuickCopyPlugin);
		}
		return manager;
	})();
	(async function() {
		await pluginManager.processCss();
		window.isDetailPage = (function() {
			return window.location.href.split("?")[0].includes("/v/");
		})();
		window.isListPage = (function() {
			const href = window.location.href;
			return $(".movie-list").length > 0 || href.includes("advanced_search");
		})();
		window.isFc2Page = (function() {
			const href = window.location.href;
			return href.includes("advanced_search?type=3") || href.includes("advanced_search?type=100");
		})();
		if (isJavdbSite) {
			await storageManager.merge_table_name();
			await storageManager.clean_no_url_blacklist();
			await storageManager.async_merge_other();
			await storageManager.merge_blacklist();
			await storageManager.merge_favoriteActress();
			await storageManager.merge_tow_car_list_table();
		}
		if (isJavdbSite && /(^|;)\s*locale\s*=\s*en\s*($|;)/i.test(document.cookie)) show$1.error("请切换到中文语言下才可正常使用本脚本", { duration: -1 });
		await pluginManager.processPlugins();
	})();
})();