TORN: TornTools - Userlist Filter

Filter the (advanced) search userlist.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name             TORN: TornTools - Userlist Filter
// @namespace        torntools.userlist-filter
// @version          1.0.0
// @author           DeKleineKobini [2114440] and the TornTools team
// @description      Filter the (advanced) search userlist.
// @license          GPL-3.0-or-later
// @icon             https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @supportURL       https://github.com/Mephiles/torntools_extension/issues
// @match            https://*.torn.com/page.php?sid=UserList*
// @grant            GM.getValue
// @grant            GM.info
// @grant            GM.setValue
// @grant            GM_addStyle
// @grant            unsafeWindow
// @run-at           document-end
// @contributionURL  https://buymeacoffee.com/dekleinekobini
// ==/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);
	};
	var FEATURE_MANAGER;
	var ttStorage;
	var SCRIPT_INJECTOR;
	var RUNTIME_INFORMATION;
	var RUNTIME_STORAGE;
	function setFeatureManager(featureManager) {
		FEATURE_MANAGER = featureManager;
	}
	function setTTStorage(storage) {
		ttStorage = storage;
	}
	function setScriptInjector(scriptInjector) {
		SCRIPT_INJECTOR = scriptInjector;
	}
	function setRuntimeInformation(runtimeInformation) {
		RUNTIME_INFORMATION = runtimeInformation;
	}
	function setRuntimeStorage(runtimeStorage) {
		RUNTIME_STORAGE = runtimeStorage;
	}
	_css(".tt-loading-placeholder{content:var(--default-preloader-url,url(https://www.torn.com/images/v2/main/ajax-loader.gif));margin:0 auto;padding:10px;display:none}.tt-loading-placeholder.active{display:block}");
	function requireCondition(condition, partialOptions = {}) {
		const options = {
			delay: 50,
			maxCycles: 100,
			...partialOptions
		};
		const error = new Error("Maximum cycles reached.");
		return new Promise((resolve, reject) => {
			if (checkCondition()) return;
			let counter = 0;
			const checker = setInterval(() => {
				if (checkCounter(counter++) || checkCondition()) return clearInterval(checker);
			}, options.delay);
			function checkCondition() {
				const response = condition();
				if (!response) return false;
				if (typeof response === "boolean") if (response) resolve(true);
				else reject();
				else if (typeof response === "object") if (Object.hasOwn(response, "success")) if (response.success === true) resolve(response.value);
				else reject(response.value);
				else resolve(response);
				return true;
			}
			function checkCounter(count) {
				if (options.maxCycles <= 0) return false;
				if (count > options.maxCycles) {
					reject(error);
					return true;
				}
				return false;
			}
		});
	}
	function requireElement(selector, attributes = {}) {
		const options = {
			invert: false,
			parent: document,
			...attributes
		};
		if (attributes.invert) return requireCondition(() => !options.parent.querySelector(selector), attributes);
		else return requireCondition(() => options.parent.querySelector(selector), attributes);
	}
	(() => {
		if (typeof window === "undefined" || window.location.href.endsWith("/_generated_background_page.html")) return "BACKGROUND";
		else if (typeof browser === "object" && browser.action) return "POPUP";
		else return "CONTENT";
	})();
	function sleep(millis) {
		return new Promise((resolve) => setTimeout(resolve, millis));
	}
	function isIntNumber(number) {
		if (number === null) return false;
		if (number.match(/[a-zA-Z]/)) return false;
		const _number = parseFloat(number.toString());
		return !Number.isNaN(_number) && Number.isFinite(_number) && _number % 1 === 0;
	}
	function getUUID() {
		return `_${Math.random().toString(36).substr(2, 9)}`;
	}
	function toNumericVersion(version) {
		return parseInt(version.split(".").map((part) => part.padStart(3, "0")).join("").padEnd(9, "9"));
	}
	function isTabFocused() {
		return document.hasFocus();
	}
	function svgImport(svgImport) {
		if (typeof svgImport !== "string") return (attributes = {}) => createFallbackElement(attributes);
		if (svgImport.startsWith("data:image/svg+xml")) {
			const encodedData = svgImport.substring(19);
			let svgContent;
			try {
				svgContent = decodeURIComponent(encodedData);
			} catch (error) {
				console.error("Failed to decode SVG data URL", error);
				return (attributes = {}) => createFallbackElement(attributes);
			}
			return (attributes = {}) => createSvgElement(svgContent, attributes);
		}
		return (attributes = {}) => createSvgElement(svgImport, attributes);
	}
	function createFallbackElement(attributes) {
		const svgNS = "http://www.w3.org/2000/svg";
		const svg = document.createElementNS(svgNS, "svg");
		svg.setAttribute("width", "24");
		svg.setAttribute("height", "24");
		svg.setAttribute("viewBox", "0 0 24 24");
		Object.entries(attributes).filter(([, value]) => value !== false && value !== null && value !== void 0).map(([key, value]) => svg.setAttribute(key, String(value)));
		const rect = document.createElementNS(svgNS, "rect");
		rect.setAttribute("x", "0");
		rect.setAttribute("y", "0");
		rect.setAttribute("width", "24");
		rect.setAttribute("height", "24");
		rect.setAttribute("fill", "red");
		svg.appendChild(rect);
		return svg;
	}
	function createSvgElement(svgContent, attributes = {}) {
		const fullAttributes = {
			width: "size" in attributes ? attributes.size : "1em",
			height: "size" in attributes ? attributes.size : "1em",
			...attributes
		};
		const svg = elementBuilder({
			type: "template",
			html: svgContent.trim()
		}).content.firstChild;
		if (!isSVGElement(svg)) return createFallbackElement(fullAttributes);
		Object.entries(fullAttributes).filter(([, value]) => value !== false && value !== null && value !== void 0).forEach(([key, value]) => svg.setAttribute(key, String(value)));
		return svg;
	}
	var arrow_bend_up_left_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M236,200a12,12,0,0,1-24,0,84.09,84.09,0,0,0-84-84H61l27.52,27.51a12,12,0,0,1-17,17l-48-48a12,12,0,0,1,0-17l48-48a12,12,0,0,1,17,17L61,92h67A108.12,108.12,0,0,1,236,200Z'/%3e%3c/svg%3e";
	var arrow_clockwise_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M244,56v48a12,12,0,0,1-12,12H184a12,12,0,1,1,0-24H201.1l-19-17.38c-.13-.12-.26-.24-.38-.37A76,76,0,1,0,127,204h1a75.53,75.53,0,0,0,52.15-20.72,12,12,0,0,1,16.49,17.45A99.45,99.45,0,0,1,128,228h-1.37A100,100,0,1,1,198.51,57.06L220,76.72V56a12,12,0,0,1,24,0Z'/%3e%3c/svg%3e";
	var arrow_down_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M208.49,152.49l-72,72a12,12,0,0,1-17,0l-72-72a12,12,0,0,1,17-17L116,187V40a12,12,0,0,1,24,0V187l51.51-51.52a12,12,0,0,1,17,17Z'/%3e%3c/svg%3e";
	var arrow_up_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M208.49,120.49a12,12,0,0,1-17,0L140,69V216a12,12,0,0,1-24,0V69L64.49,120.49a12,12,0,0,1-17-17l72-72a12,12,0,0,1,17,0l72,72A12,12,0,0,1,208.49,120.49Z'/%3e%3c/svg%3e";
	var check_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z'/%3e%3c/svg%3e";
	var check_circle_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M176.49,95.51a12,12,0,0,1,0,17l-56,56a12,12,0,0,1-17,0l-24-24a12,12,0,1,1,17-17L112,143l47.51-47.52A12,12,0,0,1,176.49,95.51ZM236,128A108,108,0,1,1,128,20,108.12,108.12,0,0,1,236,128Zm-24,0a84,84,0,1,0-84,84A84.09,84.09,0,0,0,212,128Z'/%3e%3c/svg%3e";
	var copy_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z'/%3e%3c/svg%3e";
	var info_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M108,84a16,16,0,1,1,16,16A16,16,0,0,1,108,84Zm128,44A108,108,0,1,1,128,20,108.12,108.12,0,0,1,236,128Zm-24,0a84,84,0,1,0-84,84A84.09,84.09,0,0,0,212,128Zm-72,36.68V132a20,20,0,0,0-20-20,12,12,0,0,0-4,23.32V168a20,20,0,0,0,20,20,12,12,0,0,0,4-23.32Z'/%3e%3c/svg%3e";
	var spinner_gap_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M140,32V64a12,12,0,0,1-24,0V32a12,12,0,0,1,24,0Zm84,84H192a12,12,0,0,0,0,24h32a12,12,0,0,0,0-24Zm-42.26,48.77a12,12,0,1,0-17,17l22.63,22.63a12,12,0,0,0,17-17ZM128,180a12,12,0,0,0-12,12v32a12,12,0,0,0,24,0V192A12,12,0,0,0,128,180ZM74.26,164.77,51.63,187.4a12,12,0,0,0,17,17l22.63-22.63a12,12,0,1,0-17-17ZM76,128a12,12,0,0,0-12-12H32a12,12,0,0,0,0,24H64A12,12,0,0,0,76,128ZM68.6,51.63a12,12,0,1,0-17,17L74.26,91.23a12,12,0,0,0,17-17Z'/%3e%3c/svg%3e";
	var warning_circle_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M128,20A108,108,0,1,0,236,128,108.12,108.12,0,0,0,128,20Zm0,192a84,84,0,1,1,84-84A84.09,84.09,0,0,1,128,212Zm-12-80V80a12,12,0,0,1,24,0v52a12,12,0,0,1-24,0Zm28,40a16,16,0,1,1-16-16A16,16,0,0,1,144,172Z'/%3e%3c/svg%3e";
	var x_circle_bold_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M168.49,104.49,145,128l23.52,23.51a12,12,0,0,1-17,17L128,145l-23.51,23.52a12,12,0,0,1-17-17L111,128,87.51,104.49a12,12,0,0,1,17-17L128,111l23.51-23.52a12,12,0,0,1,17,17ZM236,128A108,108,0,1,1,128,20,108.12,108.12,0,0,1,236,128Zm-24,0a84,84,0,1,0-84,84A84.09,84.09,0,0,0,212,128Z'/%3e%3c/svg%3e";
	var airplane_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M240,136v32a8,8,0,0,1-8,8,7.61,7.61,0,0,1-1.57-.16L156,161v23.73l17.66,17.65A8,8,0,0,1,176,208v24a8,8,0,0,1-11,7.43l-37-14.81L91,239.43A8,8,0,0,1,80,232V208a8,8,0,0,1,2.34-5.66L100,184.69V161L25.57,175.84A7.61,7.61,0,0,1,24,176a8,8,0,0,1-8-8V136a8,8,0,0,1,4.42-7.16L100,89.06V44a28,28,0,0,1,56,0V89.06l79.58,39.78A8,8,0,0,1,240,136Z'/%3e%3c/svg%3e";
	var arrows_out_cardinal_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M96,136H64v24a8,8,0,0,1-13.66,5.66l-32-32a8,8,0,0,1,0-11.32l32-32A8,8,0,0,1,64,96v24H96a8,8,0,0,1,0,16Zm0-72h24V96a8,8,0,0,0,16,0V64h24a8,8,0,0,0,5.66-13.66l-32-32a8,8,0,0,0-11.32,0l-32,32A8,8,0,0,0,96,64Zm141.66,58.34-32-32A8,8,0,0,0,192,96v24H160a8,8,0,0,0,0,16h32v24a8,8,0,0,0,13.66,5.66l32-32A8,8,0,0,0,237.66,122.34ZM160,192H136V160a8,8,0,0,0-16,0v32H96a8,8,0,0,0-5.66,13.66l32,32a8,8,0,0,0,11.32,0l32-32A8,8,0,0,0,160,192Z'/%3e%3c/svg%3e";
	var bell_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M221.8,175.94C216.25,166.38,208,139.33,208,104a80,80,0,1,0-160,0c0,35.34-8.26,62.38-13.81,71.94A16,16,0,0,0,48,200H88.81a40,40,0,0,0,78.38,0H208a16,16,0,0,0,13.8-24.06ZM128,216a24,24,0,0,1-22.62-16h45.24A24,24,0,0,1,128,216Z'/%3e%3c/svg%3e";
	var bell_slash_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M221.84,192v0a1.85,1.85,0,0,1-3,.28L83.27,43.19a4,4,0,0,1,.8-6A79.55,79.55,0,0,1,129.17,24C173,24.66,207.8,61.1,208,104.92c.14,34.88,8.31,61.54,13.82,71A15.89,15.89,0,0,1,221.84,192Zm-7.92,18.62a8,8,0,0,1-11.85,10.76L182.62,200H167.16a40,40,0,0,1-78.41,0H47.91a15.78,15.78,0,0,1-13.59-7.59,16.42,16.42,0,0,1-.09-16.68c5.55-9.73,13.7-36.64,13.7-71.73A79.42,79.42,0,0,1,58.79,63.85L42,45.38A8,8,0,1,1,53.84,34.62ZM150.59,200H105.32a24,24,0,0,0,45.27,0Z'/%3e%3c/svg%3e";
	var caret_down_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,48,88H208a8,8,0,0,1,5.66,13.66Z'/%3e%3c/svg%3e";
	var caret_right_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M181.66,133.66l-80,80A8,8,0,0,1,88,208V48a8,8,0,0,1,13.66-5.66l80,80A8,8,0,0,1,181.66,133.66Z'/%3e%3c/svg%3e";
	var caret_up_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M215.39,163.06A8,8,0,0,1,208,168H48a8,8,0,0,1-5.66-13.66l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,215.39,163.06Z'/%3e%3c/svg%3e";
	var funnel_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M227.81,66.76l-.08.09L160,139.17v55.49A16,16,0,0,1,152.87,208l-32,21.34A16,16,0,0,1,96,216V139.17L28.27,66.85l-.08-.09A16,16,0,0,1,40,40H216a16,16,0,0,1,11.84,26.76Z'/%3e%3c/svg%3e";
	var funnel_x_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M227.73,66.85,160,139.17v55.49A16,16,0,0,1,152.87,208l-32,21.34A16,16,0,0,1,96,216V139.17L28.27,66.85l-.08-.09A16,16,0,0,1,40,40H216a16,16,0,0,1,11.84,26.76ZM227.31,192l18.35-18.34a8,8,0,0,0-11.32-11.32L216,180.69l-18.34-18.35a8,8,0,0,0-11.32,11.32L204.69,192l-18.35,18.34a8,8,0,0,0,11.32,11.32L216,203.31l18.34,18.35a8,8,0,0,0,11.32-11.32Z'/%3e%3c/svg%3e";
	var gear_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M216,130.16q.06-2.16,0-4.32l14.92-18.64a8,8,0,0,0,1.48-7.06,107.6,107.6,0,0,0-10.88-26.25,8,8,0,0,0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186,40.54a8,8,0,0,0-3.94-6,107.29,107.29,0,0,0-26.25-10.86,8,8,0,0,0-7.06,1.48L130.16,40Q128,40,125.84,40L107.2,25.11a8,8,0,0,0-7.06-1.48A107.6,107.6,0,0,0,73.89,34.51a8,8,0,0,0-3.93,6L67.32,64.27q-1.56,1.49-3,3L40.54,70a8,8,0,0,0-6,3.94,107.71,107.71,0,0,0-10.87,26.25,8,8,0,0,0,1.49,7.06L40,125.84Q40,128,40,130.16L25.11,148.8a8,8,0,0,0-1.48,7.06,107.6,107.6,0,0,0,10.88,26.25,8,8,0,0,0,6,3.93l23.72,2.64q1.49,1.56,3,3L70,215.46a8,8,0,0,0,3.94,6,107.71,107.71,0,0,0,26.25,10.87,8,8,0,0,0,7.06-1.49L125.84,216q2.16.06,4.32,0l18.64,14.92a8,8,0,0,0,7.06,1.48,107.21,107.21,0,0,0,26.25-10.88,8,8,0,0,0,3.93-6l2.64-23.72q1.56-1.48,3-3L215.46,186a8,8,0,0,0,6-3.94,107.71,107.71,0,0,0,10.87-26.25,8,8,0,0,0-1.49-7.06ZM128,168a40,40,0,1,1,40-40A40,40,0,0,1,128,168Z'/%3e%3c/svg%3e";
	var info_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm-4,48a12,12,0,1,1-12,12A12,12,0,0,1,124,72Zm12,112a16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40a8,8,0,0,1,0,16Z'/%3e%3c/svg%3e";
	var plus_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM184,136H136v48a8,8,0,0,1-16,0V136H72a8,8,0,0,1,0-16h48V72a8,8,0,0,1,16,0v48h48a8,8,0,0,1,0,16Z'/%3e%3c/svg%3e";
	var stethoscope_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M240,160a32,32,0,1,0-39.93,31,8,8,0,0,0-.07,1,32,32,0,0,1-32,32H144a32,32,0,0,1-32-32V151.48c31.47-4,56-31.47,56-64.31V40a8,8,0,0,0-8-8H136a8,8,0,0,0,0,16h16V87.17c0,26.58-21.25,48.49-47.36,48.83A48,48,0,0,1,56,88V48H72a8,8,0,0,0,0-16H48a8,8,0,0,0-8,8V88a64,64,0,0,0,56,63.49V192a48.05,48.05,0,0,0,48,48h24a48.05,48.05,0,0,0,48-48,8,8,0,0,0-.07-1A32,32,0,0,0,240,160Zm-32,8a8,8,0,1,1,8-8A8,8,0,0,1,208,168Z'/%3e%3c/svg%3e";
	var table_fill_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M224,48H32a8,8,0,0,0-8,8V192a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A8,8,0,0,0,224,48ZM40,112H80v32H40Zm56,0H216v32H96ZM40,160H80v32H40Zm176,32H96V160H216v32Z'/%3e%3c/svg%3e";
	var caret_down_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z'/%3e%3c/svg%3e";
	var eye_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M247.31,124.76c-.35-.79-8.82-19.58-27.65-38.41C194.57,61.26,162.88,48,128,48S61.43,61.26,36.34,86.35C17.51,105.18,9,124,8.69,124.76a8,8,0,0,0,0,6.5c.35.79,8.82,19.57,27.65,38.4C61.43,194.74,93.12,208,128,208s66.57-13.26,91.66-38.34c18.83-18.83,27.3-37.61,27.65-38.4A8,8,0,0,0,247.31,124.76ZM128,192c-30.78,0-57.67-11.19-79.93-33.25A133.47,133.47,0,0,1,25,128,133.33,133.33,0,0,1,48.07,97.25C70.33,75.19,97.22,64,128,64s57.67,11.19,79.93,33.25A133.46,133.46,0,0,1,231.05,128C223.84,141.46,192.43,192,128,192Zm0-112a48,48,0,1,0,48,48A48.05,48.05,0,0,0,128,80Zm0,80a32,32,0,1,1,32-32A32,32,0,0,1,128,160Z'/%3e%3c/svg%3e";
	var eye_slash_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M53.92,34.62A8,8,0,1,0,42.08,45.38L61.32,66.55C25,88.84,9.38,123.2,8.69,124.76a8,8,0,0,0,0,6.5c.35.79,8.82,19.57,27.65,38.4C61.43,194.74,93.12,208,128,208a127.11,127.11,0,0,0,52.07-10.83l22,24.21a8,8,0,1,0,11.84-10.76Zm47.33,75.84,41.67,45.85a32,32,0,0,1-41.67-45.85ZM128,192c-30.78,0-57.67-11.19-79.93-33.25A133.16,133.16,0,0,1,25,128c4.69-8.79,19.66-33.39,47.35-49.38l18,19.75a48,48,0,0,0,63.66,70l14.73,16.2A112,112,0,0,1,128,192Zm6-95.43a8,8,0,0,1,3-15.72,48.16,48.16,0,0,1,38.77,42.64,8,8,0,0,1-7.22,8.71,6.39,6.39,0,0,1-.75,0,8,8,0,0,1-8-7.26A32.09,32.09,0,0,0,134,96.57Zm113.28,34.69c-.42.94-10.55,23.37-33.36,43.8a8,8,0,1,1-10.67-11.92A132.77,132.77,0,0,0,231.05,128a133.15,133.15,0,0,0-23.12-30.77C185.67,75.19,158.78,64,128,64a118.37,118.37,0,0,0-19.36,1.57A8,8,0,1,1,106,49.79,134,134,0,0,1,128,48c34.88,0,66.57,13.26,91.66,38.35,18.83,18.83,27.3,37.62,27.65,38.41A8,8,0,0,1,247.31,131.26Z'/%3e%3c/svg%3e";
	var plus_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z'/%3e%3c/svg%3e";
	var question_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M140,180a12,12,0,1,1-12-12A12,12,0,0,1,140,180ZM128,72c-22.06,0-40,16.15-40,36v4a8,8,0,0,0,16,0v-4c0-11,10.77-20,24-20s24,9,24,20-10.77,20-24,20a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-.72c18.24-3.35,32-17.9,32-35.28C168,88.15,150.06,72,128,72Zm104,56A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z'/%3e%3c/svg%3e";
	var trash_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z'/%3e%3c/svg%3e";
	var x_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z'/%3e%3c/svg%3e";
	var x_circle_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20256%20256'%20fill='currentColor'%3e%3cpath%20d='M165.66,101.66,139.31,128l26.35,26.34a8,8,0,0,1-11.32,11.32L128,139.31l-26.34,26.35a8,8,0,0,1-11.32-11.32L116.69,128,90.34,101.66a8,8,0,0,1,11.32-11.32L128,116.69l26.34-26.35a8,8,0,0,1,11.32,11.32ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z'/%3e%3c/svg%3e";
	svgImport(caret_down_default);
	svgImport(eye_default);
	svgImport(eye_slash_default);
	svgImport(plus_default);
	svgImport(trash_default);
	svgImport(question_default);
	svgImport(x_default);
	svgImport(x_circle_default);
	svgImport(arrow_bend_up_left_bold_default);
	svgImport(arrow_clockwise_bold_default);
	svgImport(arrow_down_bold_default);
	svgImport(arrow_up_bold_default);
	svgImport(check_bold_default);
	svgImport(check_circle_bold_default);
	svgImport(copy_bold_default);
	svgImport(info_bold_default);
	svgImport(warning_circle_bold_default);
	svgImport(x_circle_bold_default);
	svgImport(spinner_gap_bold_default);
	svgImport(arrows_out_cardinal_fill_default);
	svgImport(airplane_fill_default);
	svgImport(bell_fill_default);
	svgImport(bell_slash_fill_default);
	var PHFillCaretDown = svgImport(caret_down_fill_default);
	svgImport(caret_right_fill_default);
	svgImport(caret_up_fill_default);
	svgImport(info_fill_default);
	var PHFillFunnel = svgImport(funnel_fill_default);
	var PHFillFunnelX = svgImport(funnel_x_fill_default);
	svgImport(gear_fill_default);
	svgImport(plus_fill_default);
	svgImport(stethoscope_fill_default);
	svgImport(table_fill_default);
	function elementBuilder(options) {
		if (typeof options === "string") return document.createElement(options);
		else if (typeof options === "object") {
			options = {
				type: "div",
				id: void 0,
				class: void 0,
				text: void 0,
				html: void 0,
				value: void 0,
				href: void 0,
				children: [],
				attributes: {},
				events: {},
				style: {},
				dataset: {},
				...options
			};
			const newElement = document.createElement(options.type);
			if (options.id) newElement.id = options.id;
			if (options.class) newElement.className = Array.isArray(options.class) ? options.class.filter((name) => !!name).join(" ") : options.class.trim();
			if (options.text !== void 0) newElement.textContent = options.text.toString();
			if (options.html) newElement.innerHTML = options.html;
			if (options.value && "value" in newElement) if (typeof options.value === "function") newElement.value = options.value();
			else newElement.value = options.value;
			if (options.href && "href" in newElement) newElement.href = options.href;
			for (const child of options.children.filter((child) => !!child) || []) if (typeof child === "string") newElement.appendChild(document.createTextNode(child));
			else newElement.appendChild(child);
			if (options.attributes) {
				let attributes = options.attributes;
				if (typeof attributes === "function") attributes = attributes();
				for (const attribute in attributes) newElement.setAttribute(attribute, attributes[attribute].toString());
			}
			for (const event in options.events) newElement.addEventListener(event, options.events[event]);
			for (const key in options.style) newElement.style[key] = options.style[key];
			for (const key in options.dataset) if (typeof options.dataset[key] === "object") newElement.dataset[key] = JSON.stringify(options.dataset[key]);
			else newElement.dataset[key] = options.dataset[key].toString();
			return newElement;
		} else throw new Error("Invalid options provided to newElement.");
	}
	function findAllElements(selector, parent = document) {
		return Array.from(parent.querySelectorAll(selector));
	}
	function findParent(element, options = {}) {
		options = {
			tag: void 0,
			class: void 0,
			partialClass: void 0,
			id: void 0,
			hasAttribute: void 0,
			maxAttempts: -1,
			currentAttempt: 1,
			...options
		};
		if (!element?.parentElement) return void 0;
		if (options.maxAttempts !== -1 && options.currentAttempt > options.maxAttempts) return void 0;
		if (options.tag && element.parentElement.tagName === options.tag) return element.parentElement;
		if (options.id && element.parentElement.id === options.id) return element.parentElement;
		if (options.class && (Array.isArray(options.class) && options.class.some((c) => element.parentElement.classList.contains(c)) || !Array.isArray(options.class) && element.parentElement.classList.contains(options.class))) return element.parentElement;
		if (options.partialClass && Array.from(element.parentElement.classList).some((c) => c.startsWith(options.partialClass))) return element.parentElement;
		if (options.hasAttribute && element.parentElement.getAttribute(options.hasAttribute) !== null) return element.parentElement;
		return findParent(element.parentElement, {
			...options,
			currentAttempt: options.currentAttempt + 1
		});
	}
	function isSVGElement(node) {
		return node && "nodeType" in node && node.nodeType === Node.ELEMENT_NODE && "ownerSVGElement" in node;
	}
	var EVENT_CHANNELS = function(EVENT_CHANNELS) {
		EVENT_CHANNELS["FETCH"] = "tt-fetch";
		EVENT_CHANNELS["XHR"] = "tt-xhr";
		EVENT_CHANNELS["CHAT_MESSAGE"] = "chat-message";
		EVENT_CHANNELS["CHAT_NEW"] = "chat-box-new";
		EVENT_CHANNELS["CHAT_OPENED"] = "chat-box-opened";
		EVENT_CHANNELS["CHAT_PEOPLE_MENU_OPENED"] = "chat-people-menu-opened";
		EVENT_CHANNELS["CHAT_SETTINGS_MENU_OPENED"] = "chat-settings-menu-opened";
		EVENT_CHANNELS["CHAT_REFRESHED"] = "chat-refreshed";
		EVENT_CHANNELS["CHAT_RECONNECTED"] = "chat-reconnected";
		EVENT_CHANNELS["CHAT_CLOSED"] = "chat-closed";
		EVENT_CHANNELS["COMPANY_EMPLOYEES_PAGE"] = "company-employees-page";
		EVENT_CHANNELS["COMPANY_STOCK_PAGE"] = "company-stock-page";
		EVENT_CHANNELS["FACTION_ARMORY_TAB"] = "faction-armory-tab";
		EVENT_CHANNELS["FACTION_CRIMES"] = "faction-crimes";
		EVENT_CHANNELS["FACTION_CRIMES2"] = "faction-crimes2";
		EVENT_CHANNELS["FACTION_CRIMES2_TAB"] = "faction-crimes2-tab";
		EVENT_CHANNELS["FACTION_CRIMES2_REFRESH"] = "faction-crimes2-refresh";
		EVENT_CHANNELS["FACTION_GIVE_TO_USER"] = "faction-give-to-user";
		EVENT_CHANNELS["FACTION_UPGRADE_INFO"] = "faction-upgrade-info";
		EVENT_CHANNELS["FACTION_INFO"] = "faction-info";
		EVENT_CHANNELS["FACTION_MAIN"] = "faction-main";
		EVENT_CHANNELS["FACTION_NATIVE_FILTER"] = "faction-filter_native";
		EVENT_CHANNELS["FACTION_NATIVE_SORT"] = "faction-sort_native";
		EVENT_CHANNELS["FACTION_NATIVE_ICON_UPDATE"] = "faction-icon_update_native";
		EVENT_CHANNELS["FF_SCOUTER_GAUGE"] = "ff-scouter-gauge";
		EVENT_CHANNELS["ITEM_AMOUNT"] = "item-amount";
		EVENT_CHANNELS["ITEM_EQUIPPED"] = "item-equipped";
		EVENT_CHANNELS["ITEM_ITEMS_LOADED"] = "item-items-loaded";
		EVENT_CHANNELS["ITEM_SWITCH_TAB"] = "item-switch-tab";
		EVENT_CHANNELS["HOSPITAL_SWITCH_PAGE"] = "hospital-switch-page";
		EVENT_CHANNELS["JAIL_SWITCH_PAGE"] = "jail-switch-page";
		EVENT_CHANNELS["USERLIST_SWITCH_PAGE"] = "userlist-switch-page";
		EVENT_CHANNELS["TRAVEL_SELECT_TYPE"] = "travel-select-type";
		EVENT_CHANNELS["TRAVEL_SELECT_COUNTRY"] = "travel-select-country";
		EVENT_CHANNELS["TRAVEL_DESTINATION_UPDATE"] = "travel-destination-update";
		EVENT_CHANNELS["TRAVEL_ABROAD__SHOP_LOAD"] = "TRAVEL_ABROAD__SHOP_LOAD";
		EVENT_CHANNELS["TRAVEL_ABROAD__SHOP_REFRESH"] = "TRAVEL_ABROAD__SHOP_REFRESH";
		EVENT_CHANNELS["FEATURE_ENABLED"] = "feature-enabled";
		EVENT_CHANNELS["FEATURE_DISABLED"] = "feature-disabled";
		EVENT_CHANNELS["STATE_CHANGED"] = "state-changed";
		EVENT_CHANNELS["SHOP__LOAD"] = "SHOP__LOAD";
		EVENT_CHANNELS["GYM_LOAD"] = "gym-load";
		EVENT_CHANNELS["GYM_TRAIN"] = "gym-train";
		EVENT_CHANNELS["CRIMES_LOADED"] = "crimes-loaded";
		EVENT_CHANNELS["CRIMES_CRIME"] = "crimes-crime";
		EVENT_CHANNELS["CRIMES2_HOME_LOADED"] = "crimes2-home-loaded";
		EVENT_CHANNELS["CRIMES2_BURGLARY_LOADED"] = "crimes2-burglary-loaded";
		EVENT_CHANNELS["CRIMES2_CRIME_LOADED"] = "crimes2-crime-loaded";
		EVENT_CHANNELS["MISSION_LOAD"] = "mission-load";
		EVENT_CHANNELS["MISSION_REWARDS"] = "mission-rewards";
		EVENT_CHANNELS["TRADE"] = "trade";
		EVENT_CHANNELS["PROFILE_FETCHED"] = "profile-fetched";
		EVENT_CHANNELS["FILTER_APPLIED"] = "filter-applied";
		EVENT_CHANNELS["STATS_ESTIMATED"] = "stats-estimated";
		EVENT_CHANNELS["SWITCH_PAGE"] = "switch-page";
		EVENT_CHANNELS["AUCTION_SWITCH_TYPE"] = "auction-switch-type";
		EVENT_CHANNELS["ITEMMARKET_CATEGORY_ITEMS"] = "itemmarket-category-items";
		EVENT_CHANNELS["ITEMMARKET_CATEGORY_ITEMS_UPDATE"] = "itemmarket-category-items-update";
		EVENT_CHANNELS["ITEMMARKET_ITEMS"] = "itemmarket-items";
		EVENT_CHANNELS["ITEMMARKET_ITEMS_UPDATE"] = "itemmarket-items-update";
		EVENT_CHANNELS["ITEMMARKET_ITEM_DETAILS"] = "itemmarket-item-details";
		EVENT_CHANNELS["WINDOW__FOCUS"] = "WINDOW__FOCUS";
		return EVENT_CHANNELS;
	}({});
	var ANTI_SCRAPE_EVENTS = [
		"TRAVEL_ABROAD__SHOP_LOAD",
		"chat-message",
		"chat-box-opened",
		"chat-closed",
		"chat-refreshed",
		"chat-reconnected",
		"itemmarket-category-items",
		"itemmarket-category-items-update",
		"itemmarket-items",
		"itemmarket-items-update"
	];
	var CUSTOM_LISTENERS = (() => {
		const listeners = {};
		for (const channel of Object.values(EVENT_CHANNELS)) listeners[channel] = [];
		return listeners;
	})();
	function addXHRListener(callback) {
		SCRIPT_INJECTOR.injectXHR();
		window.addEventListener("tt-xhr", callback);
	}
	function triggerCustomListener(channel, payload) {
		if (ANTI_SCRAPE_EVENTS.includes(channel) && !isTabFocused()) return;
		for (const listener of CUSTOM_LISTENERS[channel]) listener(payload);
	}
	function setupUserlistPage() {
		addXHRListener(async ({ detail: { page, xhr } }) => {
			if (page !== "page") return;
			if (new URLSearchParams(xhr.requestBody).get("sid") !== "UserListAjax") return;
			await requireElement(".user-info-list-wrap");
			await requireElement(".user-info-list-wrap .ajax-placeholder", { invert: true });
			triggerCustomListener(EVENT_CHANNELS.USERLIST_SWITCH_PAGE);
		});
	}
	var TornToolsCache = class {
		_cache;
		constructor() {
			this._cache = {};
		}
		set cache(value) {
			this._cache = value || {};
		}
		get cache() {
			return this._cache;
		}
		get(section, key) {
			return this.getCacheValue(section, key)?.value;
		}
		async remove(section, key) {
			if (!key) {
				key = section;
				section = null;
			}
			if (section && !this.hasValue(section, key) || !section && !this.hasValue(key.toString())) return;
			if (section) delete this.cache[section][key];
			else delete this.cache[key];
			await ttStorage.set({ cache: this.cache });
		}
		hasValue(section, key) {
			return this.getCacheValue(section, key) !== null;
		}
		getCacheValue(section, key) {
			if (!key) {
				key = section;
				section = null;
			}
			let value = null;
			if (section) {
				if (section in this.cache && key in this.cache[section]) value = this.cache[section][key];
			} else if (key in this.cache) value = this.cache[key];
			if (value === null || !("value" in value)) return null;
			if ("indefinite" in value) return value;
			else return value.timeout > Date.now() ? value : null;
		}
		async set(object, ttl, section) {
			return this._set(object, ttl, section);
		}
		setIndefinite(object, section) {
			return this._set(object, null, section);
		}
		async _set(object, ttl, section) {
			const timeout = ttl === null ? null : Date.now() + ttl;
			if (section) {
				if (!(section in this.cache)) this.cache[section] = {};
				for (const [key, value] of Object.entries(object)) this.cache[section][key] = this.createCacheValue(value, timeout);
			} else for (const [key, value] of Object.entries(object)) this.cache[key] = this.createCacheValue(value, timeout);
			await ttStorage.set({ cache: this.cache });
		}
		createCacheValue(value, timeout) {
			if (timeout === null) return {
				value,
				indefinite: true
			};
			else return {
				value,
				timeout
			};
		}
		async clear(section) {
			if (section) {
				delete this.cache[section];
				await ttStorage.set({ cache: this.cache });
			} else ttStorage.set({ cache: {} }).then(() => this.cache = {});
		}
		async refresh() {
			let hasChanged = false;
			const now = Date.now();
			refreshObject(this.cache);
			for (const section in this.cache) if (!Object.keys(this.cache[section]).length) delete this.cache[section];
			if (hasChanged) await ttStorage.set({ cache: this.cache });
			function refreshObject(object) {
				for (const key in object) {
					const value = object[key];
					if ("value" in value) {
						const cacheValue = value;
						if ("indefinite" in cacheValue || cacheValue.timeout > now) continue;
						hasChanged = true;
						delete object[key];
					} else refreshObject(value);
				}
			}
		}
	};
	var ttCache = new TornToolsCache();
	var DefaultSetting = class {
		type;
		defaultValue;
		constructor(type, defaultValue) {
			this.type = type;
			this.defaultValue = defaultValue;
		}
	};
	var DEFAULT_STORAGE = {
		version: {
			current: new DefaultSetting("string", () => RUNTIME_INFORMATION.getVersion()),
			initial: new DefaultSetting("string", () => RUNTIME_INFORMATION.getVersion()),
			oldVersion: new DefaultSetting("string"),
			showNotice: new DefaultSetting("boolean", true)
		},
		api: {
			torn: {
				key: new DefaultSetting("string"),
				online: new DefaultSetting("boolean", true),
				error: new DefaultSetting("string")
			},
			tornstats: { key: new DefaultSetting("string") },
			yata: { key: new DefaultSetting("string") },
			ffScouter: { key: new DefaultSetting("string") }
		},
		settings: {
			updateNotice: new DefaultSetting("boolean", true),
			featureDisplay: new DefaultSetting("boolean", true),
			featureDisplayPosition: new DefaultSetting("string", "bottom-left"),
			featureDisplayOnlyFailed: new DefaultSetting("boolean", false),
			featureDisplayHideDisabled: new DefaultSetting("boolean", false),
			featureDisplayHideEmpty: new DefaultSetting("boolean", true),
			developer: new DefaultSetting("boolean", false),
			formatting: {
				tct: new DefaultSetting("boolean", false),
				date: new DefaultSetting("string", "eu"),
				time: new DefaultSetting("string", "eu")
			},
			sorting: { abroad: {
				column: new DefaultSetting("string", ""),
				order: new DefaultSetting("string", "none")
			} },
			notifications: {
				sound: new DefaultSetting("string", "default"),
				soundCustom: new DefaultSetting("string", ""),
				tts: new DefaultSetting("boolean", false),
				ttsVoice: new DefaultSetting("string", "default"),
				ttsRate: new DefaultSetting("number", 1),
				link: new DefaultSetting("boolean", true),
				volume: new DefaultSetting("number", 100),
				requireInteraction: new DefaultSetting("boolean", false),
				types: {
					global: new DefaultSetting("boolean", () => typeof Notification !== "undefined" && Notification.permission === "granted"),
					events: new DefaultSetting("boolean", true),
					messages: new DefaultSetting("boolean", true),
					status: new DefaultSetting("boolean", true),
					traveling: new DefaultSetting("boolean", true),
					cooldowns: new DefaultSetting("boolean", true),
					education: new DefaultSetting("boolean", true),
					newDay: new DefaultSetting("boolean", true),
					energy: new DefaultSetting("array", ["100%"]),
					nerve: new DefaultSetting("array", ["100%"]),
					happy: new DefaultSetting("array", ["100%"]),
					life: new DefaultSetting("array", ["100%"]),
					offline: new DefaultSetting("array", []),
					chainTimerEnabled: new DefaultSetting("boolean", true),
					chainBonusEnabled: new DefaultSetting("boolean", true),
					leavingHospitalEnabled: new DefaultSetting("boolean", true),
					landingEnabled: new DefaultSetting("boolean", true),
					cooldownDrugEnabled: new DefaultSetting("boolean", true),
					cooldownBoosterEnabled: new DefaultSetting("boolean", true),
					cooldownMedicalEnabled: new DefaultSetting("boolean", true),
					chainTimer: new DefaultSetting("array", []),
					chainBonus: new DefaultSetting("array", []),
					leavingHospital: new DefaultSetting("array", []),
					landing: new DefaultSetting("array", []),
					cooldownDrug: new DefaultSetting("array", []),
					cooldownBooster: new DefaultSetting("array", []),
					cooldownMedical: new DefaultSetting("array", []),
					stocks: new DefaultSetting("object", {}),
					missionsLimitEnabled: new DefaultSetting("boolean", false),
					missionsLimit: new DefaultSetting("string", ""),
					missionsExpireEnabled: new DefaultSetting("boolean", false),
					missionsExpire: new DefaultSetting("array", []),
					npcsGlobal: new DefaultSetting("boolean", true),
					npcs: new DefaultSetting("array", []),
					npcPlannedEnabled: new DefaultSetting("boolean", true),
					npcPlanned: new DefaultSetting("array", []),
					refillEnergyEnabled: new DefaultSetting("boolean", true),
					refillEnergy: new DefaultSetting("string", ""),
					refillNerveEnabled: new DefaultSetting("boolean", true),
					refillNerve: new DefaultSetting("string", "")
				}
			},
			apiUsage: {
				comment: new DefaultSetting("string", "TornTools"),
				delayEssential: new DefaultSetting("number", 30),
				delayBasic: new DefaultSetting("number", 120),
				delayPassive: new DefaultSetting("number", 3600),
				delayStakeouts: new DefaultSetting("number", 30),
				user: {
					bars: new DefaultSetting("boolean", true),
					cooldowns: new DefaultSetting("boolean", true),
					travel: new DefaultSetting("boolean", true),
					newevents: new DefaultSetting("boolean", true),
					newmessages: new DefaultSetting("boolean", true),
					refills: new DefaultSetting("boolean", true),
					stocks: new DefaultSetting("boolean", true),
					education: new DefaultSetting("boolean", true),
					networth: new DefaultSetting("boolean", true),
					inventory: new DefaultSetting("boolean", true),
					jobpoints: new DefaultSetting("boolean", true),
					merits: new DefaultSetting("boolean", true),
					perks: new DefaultSetting("boolean", true),
					icons: new DefaultSetting("boolean", true),
					ammo: new DefaultSetting("boolean", true),
					battlestats: new DefaultSetting("boolean", true),
					crimes: new DefaultSetting("boolean", true),
					workstats: new DefaultSetting("boolean", true),
					skills: new DefaultSetting("boolean", true),
					weaponexp: new DefaultSetting("boolean", true),
					properties: new DefaultSetting("boolean", true),
					calendar: new DefaultSetting("boolean", true),
					organizedcrime: new DefaultSetting("boolean", true),
					missions: new DefaultSetting("boolean", true),
					personalstats: new DefaultSetting("boolean", true),
					attacks: new DefaultSetting("boolean", true),
					money: new DefaultSetting("boolean", true),
					honors: new DefaultSetting("boolean", true),
					medals: new DefaultSetting("boolean", true),
					virus: new DefaultSetting("boolean", true)
				}
			},
			themes: {
				pages: new DefaultSetting("string", "default"),
				containers: new DefaultSetting("string", "default")
			},
			hideIcons: new DefaultSetting("array", []),
			hideCasinoGames: new DefaultSetting("array", []),
			hideStocks: new DefaultSetting("array", []),
			alliedFactions: new DefaultSetting("array", []),
			customLinks: new DefaultSetting("array", []),
			employeeInactivityWarning: new DefaultSetting("array", []),
			factionInactivityWarning: new DefaultSetting("array", []),
			userAlias: new DefaultSetting("array", []),
			csvDelimiter: new DefaultSetting("string", ";"),
			pages: {
				global: {
					alignLeft: new DefaultSetting("boolean", false),
					hideLevelUpgrade: new DefaultSetting("boolean", false),
					hideQuitButtons: new DefaultSetting("boolean", false),
					hideTutorials: new DefaultSetting("boolean", false),
					keepAttackHistory: new DefaultSetting("boolean", true),
					miniProfileLastAction: new DefaultSetting("boolean", true),
					reviveProvider: new DefaultSetting("string", ""),
					pageTitles: new DefaultSetting("boolean", true),
					stackingMode: new DefaultSetting("boolean", false),
					noOutsideLinkAlert: new DefaultSetting("boolean", false),
					urlFill: new DefaultSetting("boolean", true)
				},
				profile: {
					avgpersonalstats: new DefaultSetting("boolean", false),
					statusIndicator: new DefaultSetting("boolean", true),
					idBesideProfileName: new DefaultSetting("boolean", true),
					notes: new DefaultSetting("boolean", true),
					showAllyWarning: new DefaultSetting("boolean", true),
					ageToWords: new DefaultSetting("boolean", true),
					disableAllyAttacks: new DefaultSetting("boolean", true),
					box: new DefaultSetting("boolean", true),
					boxStats: new DefaultSetting("boolean", true),
					boxSpy: new DefaultSetting("boolean", true),
					boxStakeout: new DefaultSetting("boolean", true),
					boxAttackHistory: new DefaultSetting("boolean", true),
					boxFetch: new DefaultSetting("boolean", true)
				},
				chat: {
					fontSize: new DefaultSetting("number", 12),
					searchChat: new DefaultSetting("boolean", true),
					completeUsernames: new DefaultSetting("boolean", true),
					highlights: new DefaultSetting("array", [{
						name: "$player",
						color: "#7ca900"
					}]),
					titleHighlights: new DefaultSetting("array", []),
					tradeTimer: new DefaultSetting("boolean", true),
					resizable: new DefaultSetting("boolean", true),
					hideChatButton: new DefaultSetting("boolean", true),
					hideChat: new DefaultSetting("boolean", false)
				},
				sidebar: {
					notes: new DefaultSetting("boolean", true),
					highlightEnergy: new DefaultSetting("boolean", true),
					highlightNerve: new DefaultSetting("boolean", false),
					ocTimer: new DefaultSetting("boolean", true),
					oc2Timer: new DefaultSetting("boolean", true),
					oc2TimerPosition: new DefaultSetting("boolean", false),
					oc2TimerLevel: new DefaultSetting("boolean", true),
					factionOCTimer: new DefaultSetting("boolean", false),
					collapseAreas: new DefaultSetting("boolean", true),
					settingsLink: new DefaultSetting("boolean", true),
					hideGymHighlight: new DefaultSetting("boolean", false),
					hideNewspaperHighlight: new DefaultSetting("boolean", false),
					upkeepPropHighlight: new DefaultSetting("number", 0),
					barLinks: new DefaultSetting("boolean", true),
					pointsValue: new DefaultSetting("boolean", true),
					npcLootTimes: new DefaultSetting("boolean", true),
					npcLootTimesService: new DefaultSetting("string", "tornstats"),
					cooldownEndTimes: new DefaultSetting("boolean", true),
					companyAddictionLevel: new DefaultSetting("boolean", true),
					showJobPointsToolTip: new DefaultSetting("boolean", true),
					rwTimer: new DefaultSetting("boolean", true),
					virusTimer: new DefaultSetting("boolean", false)
				},
				popup: {
					dashboard: new DefaultSetting("boolean", true),
					marketSearch: new DefaultSetting("boolean", true),
					bazaarUsingExternal: new DefaultSetting("boolean", true),
					calculator: new DefaultSetting("boolean", true),
					stocksOverview: new DefaultSetting("boolean", true),
					notifications: new DefaultSetting("boolean", true),
					defaultTab: new DefaultSetting("string", "dashboard"),
					showStakeouts: new DefaultSetting("boolean", true),
					showIcons: new DefaultSetting("boolean", true),
					fullBarTime: new DefaultSetting("boolean", false)
				},
				icon: {
					global: new DefaultSetting("boolean", true),
					energy: new DefaultSetting("boolean", true),
					nerve: new DefaultSetting("boolean", true),
					happy: new DefaultSetting("boolean", true),
					life: new DefaultSetting("boolean", true),
					chain: new DefaultSetting("boolean", true),
					travel: new DefaultSetting("boolean", true)
				},
				education: {
					greyOut: new DefaultSetting("boolean", true),
					finishTime: new DefaultSetting("boolean", true)
				},
				jail: { filter: new DefaultSetting("boolean", true) },
				bank: {
					investmentInfo: new DefaultSetting("boolean", true),
					investmentDueTime: new DefaultSetting("boolean", true)
				},
				home: {
					networthDetails: new DefaultSetting("boolean", true),
					effectiveStats: new DefaultSetting("boolean", true)
				},
				items: {
					quickItems: new DefaultSetting("boolean", true),
					values: new DefaultSetting("boolean", true),
					drugDetails: new DefaultSetting("boolean", true),
					marketLinks: new DefaultSetting("boolean", false),
					highlightBloodBags: new DefaultSetting("string", "none"),
					missingFlowers: new DefaultSetting("boolean", false),
					missingPlushies: new DefaultSetting("boolean", false),
					bookEffects: new DefaultSetting("boolean", true),
					canGains: new DefaultSetting("boolean", true),
					nerveGains: new DefaultSetting("boolean", true),
					candyHappyGains: new DefaultSetting("boolean", true),
					energyWarning: new DefaultSetting("boolean", true),
					medicalLife: new DefaultSetting("boolean", true),
					openedSupplyPackValue: new DefaultSetting("boolean", true),
					hideRecycleMessage: new DefaultSetting("boolean", false),
					hideTooManyItemsWarning: new DefaultSetting("boolean", false)
				},
				crimes: { quickCrimes: new DefaultSetting("boolean", true) },
				companies: {
					idBesideCompanyName: new DefaultSetting("boolean", false),
					specials: new DefaultSetting("boolean", true),
					autoStockFill: new DefaultSetting("boolean", true),
					employeeEffectiveness: new DefaultSetting("number", 18)
				},
				travel: {
					computer: new DefaultSetting("boolean", true),
					table: new DefaultSetting("boolean", true),
					cleanFlight: new DefaultSetting("boolean", false),
					tabTitleTimer: new DefaultSetting("boolean", false),
					travelProfits: new DefaultSetting("boolean", true),
					fillMax: new DefaultSetting("boolean", true),
					peopleFilter: new DefaultSetting("boolean", true),
					landingTime: new DefaultSetting("boolean", true),
					flyingTime: new DefaultSetting("boolean", true),
					itemFilter: new DefaultSetting("boolean", true),
					energyWarning: new DefaultSetting("boolean", true),
					cooldownWarnings: new DefaultSetting("boolean", true),
					autoTravelTableCountry: new DefaultSetting("boolean", false),
					autoFillMax: new DefaultSetting("boolean", true),
					efficientRehab: new DefaultSetting("boolean", true),
					efficientRehabSelect: new DefaultSetting("boolean", false)
				},
				stocks: {
					filter: new DefaultSetting("boolean", true),
					acronyms: new DefaultSetting("boolean", true),
					valueAndProfit: new DefaultSetting("boolean", true),
					moneyInput: new DefaultSetting("boolean", true)
				},
				competitions: {
					easterEggs: new DefaultSetting("boolean", false),
					easterEggsAlert: new DefaultSetting("boolean", true)
				},
				events: { worth: new DefaultSetting("boolean", true) },
				hospital: { filter: new DefaultSetting("boolean", true) },
				auction: { filter: new DefaultSetting("boolean", true) },
				api: {
					autoFillKey: new DefaultSetting("boolean", true),
					autoDemo: new DefaultSetting("boolean", false),
					autoPretty: new DefaultSetting("boolean", true),
					clickableSelections: new DefaultSetting("boolean", true)
				},
				forums: {
					menu: new DefaultSetting("boolean", true),
					hidePosts: new DefaultSetting("object", {}),
					hideThreads: new DefaultSetting("object", {}),
					highlightPosts: new DefaultSetting("object", {}),
					highlightThreads: new DefaultSetting("object", {}),
					ignoredThreads: new DefaultSetting("object", {}),
					debugInfoBtn: new DefaultSetting("boolean", true),
					onlyNewFeedButton: new DefaultSetting("boolean", true)
				},
				bazaar: {
					itemsCost: new DefaultSetting("boolean", true),
					worth: new DefaultSetting("boolean", true),
					fillMax: new DefaultSetting("boolean", true),
					maxBuyIgnoreCash: new DefaultSetting("boolean", false),
					highlightSubVendorItems: new DefaultSetting("boolean", false)
				},
				trade: {
					itemValues: new DefaultSetting("boolean", true),
					openChat: new DefaultSetting("boolean", true)
				},
				displayCase: { worth: new DefaultSetting("boolean", true) },
				shops: {
					fillMax: new DefaultSetting("boolean", true),
					maxBuyIgnoreCash: new DefaultSetting("boolean", false),
					profit: new DefaultSetting("boolean", true),
					filters: new DefaultSetting("boolean", true),
					values: new DefaultSetting("boolean", true)
				},
				casino: {
					netTotal: new DefaultSetting("boolean", true),
					blackjack: new DefaultSetting("boolean", true),
					highlow: new DefaultSetting("boolean", false),
					highlowMovement: new DefaultSetting("boolean", true)
				},
				racing: {
					winPercentage: new DefaultSetting("boolean", true),
					upgrades: new DefaultSetting("boolean", true),
					filter: new DefaultSetting("boolean", true)
				},
				faction: {
					idBesideFactionName: new DefaultSetting("boolean", false),
					csvRaidReport: new DefaultSetting("boolean", true),
					csvRankedWarReport: new DefaultSetting("boolean", true),
					csvWarReport: new DefaultSetting("boolean", true),
					csvChainReport: new DefaultSetting("boolean", true),
					csvChallengeContributions: new DefaultSetting("boolean", true),
					openOc: new DefaultSetting("boolean", true),
					highlightOwn: new DefaultSetting("boolean", true),
					availablePlayers: new DefaultSetting("boolean", true),
					recommendedNnb: new DefaultSetting("boolean", true),
					ocNnb: new DefaultSetting("boolean", true),
					ocTimes: new DefaultSetting("boolean", true),
					ocLastAction: new DefaultSetting("boolean", true),
					banker: new DefaultSetting("boolean", true),
					showFullInfobox: new DefaultSetting("boolean", true),
					foldableInfobox: new DefaultSetting("boolean", true),
					numberMembers: new DefaultSetting("boolean", true),
					warFinishTimes: new DefaultSetting("boolean", false),
					memberFilter: new DefaultSetting("boolean", true),
					armoryFilter: new DefaultSetting("boolean", true),
					armoryWorth: new DefaultSetting("boolean", true),
					upgradeRequiredRespect: new DefaultSetting("boolean", true),
					memberInfo: new DefaultSetting("boolean", false),
					rankedWarFilter: new DefaultSetting("boolean", true),
					quickItems: new DefaultSetting("boolean", true),
					stakeout: new DefaultSetting("boolean", true),
					showFactionSpy: new DefaultSetting("boolean", true),
					oc2Filter: new DefaultSetting("boolean", true),
					warnCrime: new DefaultSetting("boolean", false),
					rankedWarValue: new DefaultSetting("boolean", true),
					totalChallengeContributions: new DefaultSetting("boolean", true)
				},
				property: {
					value: new DefaultSetting("boolean", true),
					happy: new DefaultSetting("boolean", true)
				},
				gym: {
					specialist: new DefaultSetting("boolean", true),
					disableStats: new DefaultSetting("boolean", true),
					graph: new DefaultSetting("boolean", true),
					steadfast: new DefaultSetting("boolean", true),
					progress: new DefaultSetting("boolean", true)
				},
				missions: {
					hints: new DefaultSetting("boolean", true),
					rewards: new DefaultSetting("boolean", true)
				},
				attack: {
					bonusInformation: new DefaultSetting("boolean", true),
					timeoutWarning: new DefaultSetting("boolean", true),
					fairAttack: new DefaultSetting("boolean", true),
					weaponExperience: new DefaultSetting("boolean", true),
					hideAttackButtons: new DefaultSetting("array", [])
				},
				city: {
					items: new DefaultSetting("boolean", true),
					combineDuplicates: new DefaultSetting("boolean", true)
				},
				joblist: { specials: new DefaultSetting("boolean", true) },
				bounties: { filter: new DefaultSetting("boolean", true) },
				userlist: { filter: new DefaultSetting("boolean", true) },
				itemmarket: {
					highlightCheapItems: new DefaultSetting("number|empty", ""),
					highlightCheapItemsSound: new DefaultSetting("boolean", false),
					leftBar: new DefaultSetting("boolean", false),
					fillMax: new DefaultSetting("boolean", true)
				},
				competition: { filter: new DefaultSetting("boolean", true) },
				museum: { autoFill: new DefaultSetting("boolean", true) },
				enemies: { filter: new DefaultSetting("boolean", true) },
				friends: { filter: new DefaultSetting("boolean", true) },
				targets: { filter: new DefaultSetting("boolean", true) },
				crimes2: {
					burglaryFilter: new DefaultSetting("boolean", true),
					value: new DefaultSetting("boolean", true)
				}
			},
			scripts: {
				noConfirm: {
					itemEquip: new DefaultSetting("boolean", true),
					tradeAccept: new DefaultSetting("boolean", false),
					pointsMarketRemove: new DefaultSetting("boolean", false),
					pointsMarketBuy: new DefaultSetting("boolean", false),
					abroadItemBuy: new DefaultSetting("boolean", true)
				},
				achievements: {
					show: new DefaultSetting("boolean", true),
					completed: new DefaultSetting("boolean", false)
				},
				lastAction: {
					factionMember: new DefaultSetting("boolean", false),
					companyOwn: new DefaultSetting("boolean", false),
					companyOther: new DefaultSetting("boolean", false)
				},
				statsEstimate: {
					global: new DefaultSetting("boolean", true),
					delay: new DefaultSetting("number", 1500),
					cachedOnly: new DefaultSetting("boolean", true),
					displayNoResult: new DefaultSetting("boolean", false),
					maxLevel: new DefaultSetting("number", 100),
					profiles: new DefaultSetting("boolean", true),
					enemies: new DefaultSetting("boolean", true),
					hof: new DefaultSetting("boolean", true),
					attacks: new DefaultSetting("boolean", true),
					userlist: new DefaultSetting("boolean", true),
					bounties: new DefaultSetting("boolean", true),
					factions: new DefaultSetting("boolean", true),
					wars: new DefaultSetting("boolean", true),
					abroad: new DefaultSetting("boolean", true),
					competition: new DefaultSetting("boolean", true),
					rankedWars: new DefaultSetting("boolean", true),
					targets: new DefaultSetting("boolean", true)
				},
				ffScouter: {
					miniProfile: new DefaultSetting("boolean", true),
					profile: new DefaultSetting("boolean", true),
					attack: new DefaultSetting("boolean", true),
					factionList: new DefaultSetting("boolean", true),
					gauge: new DefaultSetting("boolean", true)
				}
			},
			external: {
				tornstats: new DefaultSetting("boolean", false),
				yata: new DefaultSetting("boolean", false),
				prometheus: new DefaultSetting("boolean", false),
				lzpt: new DefaultSetting("boolean", false),
				tornw3b: new DefaultSetting("boolean", false),
				ffScouter: new DefaultSetting("boolean", false),
				tornintel: new DefaultSetting("boolean", false)
			}
		},
		filters: {
			hospital: {
				enabled: new DefaultSetting("boolean", true),
				timeStart: new DefaultSetting("number", 0),
				timeEnd: new DefaultSetting("number", 100),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100),
				faction: new DefaultSetting("string", ""),
				activity: new DefaultSetting("array", []),
				revivesOn: new DefaultSetting("boolean", false)
			},
			jail: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				faction: new DefaultSetting("string", "All"),
				timeStart: new DefaultSetting("number", 0),
				timeEnd: new DefaultSetting("number", 100),
				levelStart: new DefaultSetting("number", 1),
				levelEnd: new DefaultSetting("number", 100),
				scoreStart: new DefaultSetting("number", 0),
				scoreEnd: new DefaultSetting("number", 5e3),
				bailCost: new DefaultSetting("number", -1)
			},
			racing: {
				enabled: new DefaultSetting("boolean", true),
				hideRaces: new DefaultSetting("array", []),
				timeStart: new DefaultSetting("number", 0),
				timeEnd: new DefaultSetting("number", 48),
				driversMin: new DefaultSetting("number", 2),
				driversMax: new DefaultSetting("number", 100),
				lapsMin: new DefaultSetting("number", 1),
				lapsMax: new DefaultSetting("number", 100),
				track: new DefaultSetting("array", []),
				name: new DefaultSetting("string", "")
			},
			containers: new DefaultSetting("object", {}),
			travel: {
				open: new DefaultSetting("boolean", false),
				type: new DefaultSetting("string", "basic"),
				categories: new DefaultSetting("array", []),
				countries: new DefaultSetting("array", []),
				hideOutOfStock: new DefaultSetting("boolean", false),
				applySalesTax: new DefaultSetting("boolean", false),
				sellAnonymously: new DefaultSetting("boolean", false)
			},
			abroadPeople: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				status: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100),
				faction: new DefaultSetting("string", ""),
				special: {
					newPlayer: new DefaultSetting("string", "both"),
					inCompany: new DefaultSetting("string", "both"),
					inFaction: new DefaultSetting("string", "both"),
					isDonator: new DefaultSetting("string", "both"),
					hasBounties: new DefaultSetting("string", "both"),
					bazaarOpen: new DefaultSetting("string", "both")
				},
				estimates: new DefaultSetting("array", []),
				ffScoreMax: new DefaultSetting("number", null),
				ffScoreMin: new DefaultSetting("number", null)
			},
			abroadItems: {
				enabled: new DefaultSetting("boolean", true),
				profitOnly: new DefaultSetting("boolean", false),
				outOfStock: new DefaultSetting("boolean", false),
				categories: new DefaultSetting("array", []),
				taxes: new DefaultSetting("array", [])
			},
			trade: { hideValues: new DefaultSetting("boolean", false) },
			gym: {
				specialist1: new DefaultSetting("string", "none"),
				specialist2: new DefaultSetting("string", "none"),
				strength: new DefaultSetting("boolean", false),
				speed: new DefaultSetting("boolean", false),
				defense: new DefaultSetting("boolean", false),
				dexterity: new DefaultSetting("boolean", false)
			},
			city: { highlightItems: new DefaultSetting("boolean", true) },
			bounties: {
				maxLevel: new DefaultSetting("number", 100),
				hideUnavailable: new DefaultSetting("boolean", false)
			},
			userlist: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100),
				special: {
					fedded: new DefaultSetting("string", "both"),
					fallen: new DefaultSetting("string", "both"),
					traveling: new DefaultSetting("string", "both"),
					newPlayer: new DefaultSetting("string", "both"),
					onWall: new DefaultSetting("string", "both"),
					inCompany: new DefaultSetting("string", "both"),
					inFaction: new DefaultSetting("string", "both"),
					isDonator: new DefaultSetting("string", "both"),
					inHospital: new DefaultSetting("string", "both"),
					inJail: new DefaultSetting("string", "both"),
					earlyDischarge: new DefaultSetting("string", "both"),
					hasBounties: new DefaultSetting("string", "both"),
					bazaarOpen: new DefaultSetting("string", "both")
				},
				hospReason: {
					attackedBy: new DefaultSetting("string", "both"),
					muggedBy: new DefaultSetting("string", "both"),
					hospitalizedBy: new DefaultSetting("string", "both"),
					other: new DefaultSetting("string", "both")
				},
				estimates: new DefaultSetting("array", []),
				ffScoreMax: new DefaultSetting("number", null),
				ffScoreMin: new DefaultSetting("number", null)
			},
			stocks: {
				enabled: new DefaultSetting("boolean", true),
				name: new DefaultSetting("string", ""),
				investment: {
					owned: new DefaultSetting("string", "both"),
					benefit: new DefaultSetting("string", "both"),
					passive: new DefaultSetting("string", "both")
				},
				price: {
					price: new DefaultSetting("string", "both"),
					profit: new DefaultSetting("string", "both")
				}
			},
			faction: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 1),
				levelEnd: new DefaultSetting("number", 100),
				lastActionStart: new DefaultSetting("number", 0),
				lastActionEnd: new DefaultSetting("number", -1),
				status: new DefaultSetting("array", []),
				position: new DefaultSetting("string", ""),
				special: {
					fedded: new DefaultSetting("string", "both"),
					fallen: new DefaultSetting("string", "both"),
					newPlayer: new DefaultSetting("string", "both"),
					inCompany: new DefaultSetting("string", "both"),
					isDonator: new DefaultSetting("string", "both"),
					isRecruit: new DefaultSetting("string", "both")
				},
				ffScoreMax: new DefaultSetting("number", null),
				ffScoreMin: new DefaultSetting("number", null)
			},
			factionArmory: {
				enabled: new DefaultSetting("boolean", true),
				hideUnavailable: new DefaultSetting("boolean", false),
				weapons: {
					name: new DefaultSetting("string", ""),
					category: new DefaultSetting("string", ""),
					rarity: new DefaultSetting("string", ""),
					weaponType: new DefaultSetting("string", ""),
					damage: new DefaultSetting("string", ""),
					accuracy: new DefaultSetting("string", ""),
					weaponBonus: new DefaultSetting("array", [])
				},
				armor: {
					name: new DefaultSetting("string", ""),
					rarity: new DefaultSetting("string", ""),
					defence: new DefaultSetting("string", ""),
					set: new DefaultSetting("string", ""),
					armorBonus: new DefaultSetting("string", "")
				},
				temporary: { name: new DefaultSetting("string", "") }
			},
			factionRankedWar: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				status: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 1),
				levelEnd: new DefaultSetting("number", 100),
				estimates: new DefaultSetting("array", []),
				ffScoreMax: new DefaultSetting("number", null),
				ffScoreMin: new DefaultSetting("number", null)
			},
			profile: {
				relative: new DefaultSetting("boolean", false),
				stats: new DefaultSetting("array", [])
			},
			competition: {
				levelStart: new DefaultSetting("number", 1),
				levelEnd: new DefaultSetting("number", 100),
				estimates: new DefaultSetting("array", [])
			},
			shops: {
				hideLoss: new DefaultSetting("boolean", false),
				hideUnder100: new DefaultSetting("boolean", false)
			},
			auction: {
				enabled: new DefaultSetting("boolean", true),
				weapons: {
					name: new DefaultSetting("string", ""),
					category: new DefaultSetting("string", ""),
					rarity: new DefaultSetting("string", ""),
					weaponType: new DefaultSetting("string", ""),
					damage: new DefaultSetting("string", ""),
					accuracy: new DefaultSetting("string", ""),
					weaponBonus: new DefaultSetting("array", []),
					quality: new DefaultSetting("string", "")
				},
				armor: {
					name: new DefaultSetting("string", ""),
					rarity: new DefaultSetting("string", ""),
					defence: new DefaultSetting("string", ""),
					set: new DefaultSetting("string", ""),
					armorBonus: new DefaultSetting("string", "")
				},
				items: {
					name: new DefaultSetting("string", ""),
					category: new DefaultSetting("string", ""),
					rarity: new DefaultSetting("string", "")
				}
			},
			enemies: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100),
				estimates: new DefaultSetting("array", [])
			},
			friends: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100)
			},
			targets: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100),
				estimates: new DefaultSetting("array", [])
			},
			burglary: {
				targetName: new DefaultSetting("string", ""),
				targetType: new DefaultSetting("array", [])
			},
			oc2: {
				enabled: new DefaultSetting("boolean", true),
				difficulty: new DefaultSetting("array", []),
				status: new DefaultSetting("array", [])
			}
		},
		userdata: new DefaultSetting("object", { date: -1 }),
		torndata: new DefaultSetting("object", { date: -2 }),
		stockdata: new DefaultSetting("object", {}),
		factiondata: new DefaultSetting("object", {}),
		localdata: {
			tradeMessage: new DefaultSetting("number", 0),
			popup: { calculatorItems: new DefaultSetting("array", []) },
			vault: {
				initialized: new DefaultSetting("boolean", false),
				lastTransaction: new DefaultSetting("string", ""),
				total: new DefaultSetting("number", 0),
				user: {
					initial: new DefaultSetting("number", 0),
					current: new DefaultSetting("number", 0)
				},
				partner: {
					initial: new DefaultSetting("number", 0),
					current: new DefaultSetting("number", 0)
				}
			},
			chatResize: new DefaultSetting("object", {}),
			feedHidden: new DefaultSetting("object", {}),
			threadsHiddenInFeed: new DefaultSetting("array", [])
		},
		stakeouts: new DefaultSetting("object", { list: [] }),
		factionStakeouts: new DefaultSetting("object", { list: [] }),
		attackHistory: {
			fetchData: new DefaultSetting("boolean", true),
			lastAttack: new DefaultSetting("number", 0),
			history: new DefaultSetting("object", {})
		},
		notes: {
			sidebar: {
				text: new DefaultSetting("string", ""),
				height: new DefaultSetting("string", "22px")
			},
			profile: new DefaultSetting("object", {})
		},
		quick: {
			items: new DefaultSetting("array", []),
			factionItems: new DefaultSetting("array", []),
			crimes: new DefaultSetting("array", []),
			jail: new DefaultSetting("array", [])
		},
		cache: new DefaultSetting("object", {}),
		npcs: new DefaultSetting("object", {}),
		notificationHistory: new DefaultSetting("array", []),
		notifications: {
			events: new DefaultSetting("object", {}),
			messages: new DefaultSetting("object", {}),
			newDay: new DefaultSetting("object", {}),
			energy: new DefaultSetting("object", {}),
			happy: new DefaultSetting("object", {}),
			nerve: new DefaultSetting("object", {}),
			life: new DefaultSetting("object", {}),
			travel: new DefaultSetting("object", {}),
			drugs: new DefaultSetting("object", {}),
			boosters: new DefaultSetting("object", {}),
			medical: new DefaultSetting("object", {}),
			hospital: new DefaultSetting("object", {}),
			chain: new DefaultSetting("object", {}),
			chainCount: new DefaultSetting("object", {}),
			stakeouts: new DefaultSetting("object", {}),
			npcs: new DefaultSetting("object", {}),
			offline: new DefaultSetting("object", {}),
			missionsLimit: new DefaultSetting("object", {}),
			missionsExpire: new DefaultSetting("object", {}),
			refillEnergy: new DefaultSetting("object", {}),
			refillNerve: new DefaultSetting("object", {})
		},
		migrations: new DefaultSetting("array", [])
	};
	function getDefaultStorage(defaultStorage) {
		const newStorage = {};
		for (const key in defaultStorage) if (typeof defaultStorage[key] === "object") {
			const setting = defaultStorage[key];
			if (setting instanceof DefaultSetting && "defaultValue" in setting) switch (typeof setting.defaultValue) {
				case "function":
					newStorage[key] = setting.defaultValue();
					break;
				case "boolean":
				case "number":
				case "string":
				case "object":
					newStorage[key] = setting.defaultValue;
					break;
				default:
					newStorage[key] = setting.defaultValue;
					break;
			}
			else newStorage[key] = getDefaultStorage(defaultStorage[key]);
		} else newStorage[key] = defaultStorage[key];
		return newStorage;
	}
	var MIGRATIONS = [
		{
			id: "9da14c73-0145-4b1d-90e3-0363a5b57499",
			version: "9.0.0",
			execute(_database, flags, _oldStorage) {
				flags.updateUserdata = true;
			}
		},
		{
			id: "43fae1f2-5568-4ae5-b12f-f3625e1e58c6",
			version: "9.0.0",
			execute(database, _flags, _oldStorage) {
				database.cache["personal-stats"] = {};
			}
		},
		{
			id: "b194a6d5-4230-4b03-8a8b-bebd7c431cc9",
			version: "9.0.0",
			execute(database, _flags, _oldStorage) {
				database.settings.pages.api.autoDemo = false;
			}
		},
		{
			id: "b0f539ba-41f8-4eed-93e2-e8523f7c49a5",
			version: "9.0.1",
			execute(database, _flags, oldStorage) {
				const oldCustomLinks = oldStorage?.settings?.customLinks ?? [];
				database.settings.customLinks = oldCustomLinks.map((link) => {
					return link.preset && link.preset !== "custom" ? {
						newTab: link.newTab,
						location: link.location,
						name: link.name,
						preset: link.preset
					} : {
						newTab: link.newTab,
						location: link.location,
						name: link.name,
						href: link.href
					};
				});
			}
		},
		{
			id: "360b1f70-c78b-44c1-b217-24bd6b398bac",
			version: "9.0.5",
			execute(database, _flags, oldStorage) {
				if (!oldStorage?.settings?.userAlias || Array.isArray(oldStorage.settings.userAlias)) return;
				const oldUserAliases = oldStorage.settings.userAlias;
				database.settings.userAlias = Object.entries(oldUserAliases).map(([id, { alias, name }]) => {
					const idMatch = id.match(/^(\d+)$/);
					return idMatch ? {
						userId: parseInt(idMatch[0]),
						userName: name,
						alias
					} : {
						userId: -1,
						userName: name,
						alias,
						incorrectId: id
					};
				});
			}
		},
		{
			id: "95c020eb-2c75-4bbe-8fe9-64f96f108f48",
			version: "9.0.5",
			execute(database, _flags, oldStorage) {
				if (!oldStorage?.settings?.pages?.popup?.defaultTab) return;
				if (oldStorage.settings.pages.popup.defaultTab === "stocks") database.settings.pages.popup.defaultTab = "stocksOverview";
				else if (oldStorage.settings.pages.popup.defaultTab === "market") database.settings.pages.popup.defaultTab = "marketSearch";
			}
		},
		{
			id: "96356911-fecd-4b79-9825-ee5ad422c8fe",
			version: "9.0.5",
			execute(database, _flags, oldStorage) {
				if (typeof oldStorage?.settings?.pages?.popup.hoverBarTime !== "boolean") return;
				database.settings.pages.popup.fullBarTime = oldStorage.settings.pages.popup.hoverBarTime;
			}
		},
		{
			id: "7396191c-35a9-4d92-905a-0e411f9a6823",
			version: "9.0.5",
			execute(_database, _flags, _oldStorage) {
				ttStorage.remove("usage");
			}
		},
		{
			id: "d3e6e03a-698d-4df4-9062-4d3c9ce9d479",
			version: "9.0.5",
			execute(database, _flags, oldStorage) {
				if (!oldStorage?.filters?.travel?.categories?.includes("other")) return;
				database.filters.travel.categories = [...oldStorage.filters.travel.categories, "defensive"];
			}
		},
		{
			id: "700848e9-ee48-42ce-b8b1-893cb471cfe4",
			version: "9.0.6",
			execute(_database, flags, _oldStorage) {
				flags.clearCache = true;
			}
		},
		{
			id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
			version: "9.0.6",
			execute(database, _flags, oldStorage) {
				const oldStakeouts = oldStorage?.stakeouts;
				if (!oldStakeouts || typeof oldStakeouts !== "object") return;
				const reservedKeys = new Set([
					"order",
					"date",
					"list"
				]);
				const oldOrder = oldStakeouts.order ?? [];
				const list = [];
				Object.entries(oldStakeouts).filter((entry) => !reservedKeys.has(entry[0])).forEach(([id, data]) => {
					const orderIndex = oldOrder.indexOf(id);
					list.push({
						...data,
						id: parseInt(id),
						order: orderIndex !== -1 ? orderIndex : Date.now()
					});
				});
				database.stakeouts.list = list;
			}
		},
		{
			id: "b2c3d4e5-f6a7-8901-bcde-f12345678901",
			version: "9.0.6",
			execute(database, _flags, oldStorage) {
				const oldFactionStakeouts = oldStorage?.factionStakeouts;
				if (!oldFactionStakeouts || typeof oldFactionStakeouts !== "object") return;
				const reservedKeys = new Set(["date", "list"]);
				const list = [];
				Object.entries(oldFactionStakeouts).filter((entry) => !reservedKeys.has(entry[0])).forEach(([id, data]) => {
					list.push({
						...data,
						id: parseInt(id),
						order: Date.now()
					});
				});
				database.factionStakeouts.list = list;
			}
		}
	];
	async function executeMigrationScripts(storage, oldStorage) {
		if (RUNTIME_INFORMATION.isUserscript()) return;
		const migrations = MIGRATIONS.filter(({ version }) => toNumericVersion(version) >= toNumericVersion(storage.version.initial)).filter(({ id }) => !storage.migrations.map(({ id }) => id).includes(id));
		const flags = {
			updateUserdata: false,
			updateFactiondata: false,
			updateTorndata: false,
			clearCache: false
		};
		migrations.reverse().filter((migration) => {
			migration.execute(storage, flags, oldStorage);
			storage.migrations.push({ id: migration.id });
		});
		if (flags.updateUserdata) storage.userdata.date = 0;
		if (flags.updateFactiondata) storage.factiondata.date = 0;
		if (flags.updateTorndata) storage.torndata.date = 0;
		if (flags.clearCache) storage.cache = {};
	}
	var settings;
	var filters;
	var version;
	var api;
	var userdata;
	var torndata;
	var stakeouts;
	var attackHistory;
	var notes;
	var factiondata;
	var quick;
	var localdata;
	var npcs;
	var notificationHistory;
	var stockdata;
	var factionStakeouts;
	var notifications;
	var migrations;
	var databaseLoaded = false;
	var databaseLoading = false;
	var storageListeners = {
		settings: [],
		filters: [],
		version: [],
		userdata: [],
		torndata: [],
		attackHistory: [],
		stakeouts: [],
		factionStakeouts: [],
		notes: [],
		factiondata: [],
		localdata: [],
		cache: [],
		api: [],
		npcs: [],
		stockdata: [],
		notificationHistory: [],
		notifications: [],
		quick: [],
		migrations: []
	};
	async function loadDatabase(force = false) {
		if (databaseLoaded && !force) return {
			settings,
			filters,
			version,
			userdata,
			stakeouts,
			factionStakeouts,
			notes,
			factiondata,
			localdata,
			cache: ttCache.cache,
			api,
			npcs,
			torndata,
			notificationHistory,
			attackHistory,
			quick,
			stockdata,
			notifications,
			migrations
		};
		else if (databaseLoaded && !settings || databaseLoading) {
			await sleep(75);
			return await loadDatabase(force);
		}
		databaseLoading = true;
		const database = await ttStorage.get();
		populateDatabaseVariables(database);
		console.log("TT - Database loaded.", database);
		databaseLoaded = true;
		databaseLoading = false;
		return database;
	}
	async function migrateDatabase(force = false) {
		try {
			const loadedStorage = await ttStorage.get();
			if (!loadedStorage || !Object.keys(loadedStorage).length) {
				console.log("TT - Fresh installation detected, setting up default storage.");
				await ttStorage.reset();
				await loadDatabase();
				return;
			}
			const storedVersion = loadedStorage?.version?.current || "5.0.0";
			const currentVersion = RUNTIME_INFORMATION.getVersion();
			console.log(`TT - Migration check: ${storedVersion} -> ${currentVersion}`);
			const migratedStorage = convertStorage(loadedStorage, DEFAULT_STORAGE);
			await executeMigrationScripts(migratedStorage, loadedStorage);
			migratedStorage.version.current = currentVersion;
			await ttStorage.set(migratedStorage);
			populateDatabaseVariables(migratedStorage);
			console.log("TT - Database migration completed successfully.");
		} catch (error) {
			console.error("TT - Database migration failed:", error);
			await loadDatabase();
		}
	}
	function convertStorage(oldStorage, defaultStorage) {
		const newStorage = {};
		for (const key in defaultStorage) {
			if (!oldStorage) oldStorage = {};
			if (!(key in oldStorage)) oldStorage[key] = {};
			const defaultValue = defaultStorage[key];
			if (typeof defaultValue === "object" && defaultValue !== null) if (defaultValue instanceof DefaultSetting) newStorage[key] = migrateDefaultSetting(oldStorage[key], defaultValue);
			else newStorage[key] = convertStorage(oldStorage[key], defaultValue);
			else newStorage[key] = oldStorage[key] ?? defaultValue;
		}
		return newStorage;
	}
	function migrateDefaultSetting(oldValue, setting) {
		if (isValidSettingValue(oldValue, setting)) return oldValue;
		if (setting.defaultValue) return typeof setting.defaultValue === "function" ? setting.defaultValue() : setting.defaultValue;
		return null;
	}
	function isValidSettingValue(value, setting) {
		if (setting.type === "array") return Array.isArray(value);
		return setting.type.split("|").some((type) => type === "empty" && value === "" || typeof value === type);
	}
	function populateDatabaseVariables(database) {
		settings = database.settings;
		filters = database.filters;
		version = database.version;
		api = database.api;
		userdata = database.userdata;
		torndata = database.torndata;
		localdata = database.localdata;
		stakeouts = database.stakeouts;
		attackHistory = database.attackHistory;
		notes = database.notes;
		factiondata = database.factiondata;
		quick = database.quick;
		npcs = database.npcs;
		stockdata = database.stockdata;
		factionStakeouts = database.factionStakeouts;
		notificationHistory = database.notificationHistory;
		notifications = database.notifications;
		migrations = database.migrations;
		ttCache.cache = database.cache;
	}
	function initializeDatabaseListener() {
		RUNTIME_STORAGE.addChangeListener((changes, area) => {
			if (area === "local") for (const key in changes) {
				switch (key) {
					case "settings":
						settings = changes.settings.newValue;
						break;
					case "filters":
						filters = changes.filters.newValue;
						break;
					case "version":
						version = changes.version.newValue;
						break;
					case "userdata":
						userdata = changes.userdata.newValue;
						break;
					case "api":
						api = changes.api.newValue;
						break;
					case "torndata":
						torndata = changes.torndata.newValue;
						break;
					case "stakeouts":
						stakeouts = changes.stakeouts.newValue;
						break;
					case "attackHistory":
						attackHistory = changes.attackHistory.newValue;
						break;
					case "notes":
						notes = changes.notes.newValue;
						break;
					case "factiondata":
						factiondata = changes.factiondata.newValue;
						break;
					case "quick":
						quick = changes.quick.newValue;
						break;
					case "localdata":
						localdata = changes.localdata.newValue;
						break;
					case "cache":
						ttCache.cache = changes.cache.newValue;
						break;
					case "npcs":
						npcs = changes.npcs.newValue;
						break;
					case "stockdata":
						stockdata = changes.stockdata.newValue;
						break;
					case "notificationHistory":
						notificationHistory = changes.notificationHistory.newValue;
						break;
					case "notifications":
						notifications = changes.notifications.newValue;
						break;
					case "factionStakeouts":
						factionStakeouts = changes.factionStakeouts.newValue;
						break;
				}
				if (storageListeners[key]) storageListeners[key].forEach((listener) => listener(changes[key].oldValue, changes[key].newValue));
			}
		});
	}
	function setLocaldata(data) {
		localdata = data;
	}
	function setFilters(data) {
		filters = data;
	}
	_css(".tt-textbox{border:1px solid var(--input-border-color);background:var(--input-background-color);width:75%;color:var(--input-color);border-radius:5px;padding:0 3px}");
	function createTextbox(partialOptions) {
		const options = {
			description: null,
			id: getUUID(),
			type: "text",
			attributes: {},
			style: {},
			...partialOptions
		};
		const textbox = elementBuilder({
			type: "input",
			class: "tt-textbox",
			id: options.id,
			attributes: {
				...options.attributes,
				type: options.type
			},
			style: options.style
		});
		let element;
		if (options.description) {
			element = elementBuilder({
				type: "div",
				class: "tt-textbox-wrapper"
			});
			if (typeof options.description === "string") {
				element.appendChild(elementBuilder({
					type: "label",
					text: options.description,
					attributes: { for: options.id }
				}));
				element.appendChild(textbox);
			} else {
				element.appendChild(elementBuilder({
					type: "label",
					text: options.description.before,
					attributes: { for: options.id }
				}));
				element.appendChild(textbox);
				element.appendChild(elementBuilder({
					type: "label",
					text: options.description.after,
					attributes: { for: options.id }
				}));
			}
		} else element = textbox;
		let onChangeCallback;
		function setValue(value) {
			textbox.value = value;
		}
		function setNumberValue(value) {
			if (value === null || Number.isNaN(parseInt(value.toString())) || !["string", "number"].includes(typeof value)) value = "";
			textbox.value = value.toString();
		}
		function getValue() {
			return textbox.value;
		}
		function onChange(callback) {
			onChangeCallback = callback;
			textbox.addEventListener("input", _onChangeListener);
		}
		function dispose() {
			if (onChangeCallback) {
				textbox.removeEventListener("input", _onChangeListener);
				onChangeCallback = void 0;
			}
		}
		function _onChangeListener() {
			onChangeCallback();
		}
		return {
			element,
			setValue,
			setNumberValue,
			getValue,
			onChange,
			dispose
		};
	}
	function hasAPIData() {
		const hasKey = !!api?.torn?.key;
		const hasError = !!api?.torn?.error && !api.torn.error.includes("Backend error") && api.torn.error !== "Network issues";
		const hasUserdata = !!(userdata && Object.keys(userdata).length);
		return hasKey && !hasError && hasUserdata;
	}
	_css(".tt-container.spacer{margin-bottom:10px}.tt-container .title{text-shadow:1px 1px 2px #000000a6;letter-spacing:1px;white-space:nowrap;height:30px;margin:initial;align-items:center;padding-left:10px;font-size:13px;display:flex}.tt-theme,.tt-container.tt-theme-background .title{color:var(--tt-theme-color);background:var(--tt-theme-background)}.tt-container.collapsible .title{cursor:pointer}.tt-container.spacer .title{margin-top:10px}.tt-container .title .text{width:-webkit-fill-available;width:-moz-available}.tt-container .title .icon{text-align:center;min-width:30px;margin:auto;font-size:16px;position:static!important}.tt-container.rounding.always-content .title,.tt-container.rounding .title:not(.collapsed){border-radius:5px 5px 0 0}.tt-container.rounding:not(.always-content) .title.collapsed{border-radius:5px}.tt-container .title.collapsed .icon{transform:rotate(-90deg)}.tt-container:not(.always-content) .title.collapsed+main,.tt-container.always-content .title.collapsed+main .hide-collapse{display:none!important}.tt-container .title .options{flex-direction:row-reverse;align-items:center;width:100%;margin-right:4px;display:flex}.tt-container .title .options>*{align-items:center;margin-right:4px;display:flex}.tt-container .title .options i{font-size:1rem}#sidebarroot .tt-container .title{border-top-right-radius:5px;border-bottom-right-radius:5px;align-items:center;height:22px}body.tt-tablet #sidebarroot .tt-container .title{height:34px}.tt-container>main{margin-top:initial!important}.tt-container:not(.compact)>main{padding:4px 4px 3px}.tt-container.rounding>main{border-radius:0 0 5px 5px}.tt-container>main.background{background-color:var(--default-bg-panel-color)}.tt-container.reset-styles{letter-spacing:0;color:var(--default-color)!important;font-family:Arial,serif!important}.tt-container input[type=checkbox]{accent-color:#6e8820}");
	function roundNearest(number, multiple) {
		return Math.round(number / multiple) * multiple;
	}
	function camelCase(text, lowerCamelCase = true) {
		return (text.trim().charAt(0)[lowerCamelCase ? "toLowerCase" : "toUpperCase"]() + text.slice(1)).trim().replaceAll(" ", "");
	}
	function capitalizeText(text, partialOptions = {}) {
		if (!{
			everyWord: false,
			...partialOptions
		}.everyWord) return text[0].toUpperCase() + text.slice(1);
		return text.trim().split(" ").map((word) => capitalizeText(word)).join(" ").trim();
	}
	function createContainer(title, partialOptions) {
		const options = {
			id: camelCase(title),
			class: void 0,
			showHeader: true,
			onlyHeader: false,
			collapsible: true,
			applyRounding: true,
			spacer: false,
			contentBackground: true,
			allowDragging: false,
			flexContainer: false,
			compact: false,
			alwaysContent: false,
			filter: false,
			resetStyles: false,
			...partialOptions
		};
		if (options.onlyHeader) options.collapsible = false;
		const { container, collapsed } = _createContainer(title, options);
		let parentElement;
		if ("parentElement" in options) parentElement = options.parentElement;
		else if ("nextElement" in options) parentElement = options.nextElement.parentElement;
		else if ("previousElement" in options) parentElement = options.previousElement.parentElement;
		else parentElement = document.querySelector(".content-wrapper");
		if ("nextElement" in options) parentElement.insertBefore(container, options.nextElement);
		else if ("previousElement" in options) parentElement.insertBefore(container, options.previousElement.nextSibling);
		else parentElement.appendChild(container);
		return {
			container,
			content: container.querySelector(":scope > main"),
			options: container.querySelector(".options"),
			collapsed
		};
		function _createContainer(title, options) {
			if (document.querySelector(`#${options.id}`)) document.querySelector(`#${options.id}`).remove();
			const containerClasses = ["tt-container"];
			if (options.collapsible) containerClasses.push("collapsible");
			if (options.applyRounding) containerClasses.push("rounding");
			if (options.spacer) containerClasses.push("spacer");
			if (options.compact) containerClasses.push("compact");
			if (options.alwaysContent) containerClasses.push("always-content");
			if (options.class) {
				let classes;
				if (typeof options.class === "string") classes = options.class.split(" ").filter((c) => !!c);
				else classes = options.class.filter((c) => !!c);
				containerClasses.push(...classes);
			}
			if (options.filter) containerClasses.push("tt-filter");
			if (options.resetStyles) containerClasses.push("reset-styles");
			const mainClasses = [];
			if (options.contentBackground) mainClasses.push("background");
			if (options.flexContainer) mainClasses.push("t-flex");
			containerClasses.push("tt-theme-background");
			const container = elementBuilder({
				type: "div",
				class: containerClasses.join(" "),
				id: options.id
			});
			const collapsed = options.onlyHeader || options.collapsible && (options.id in filters.containers ? filters.containers[options.id] : false);
			if (options.showHeader) container.appendChild(elementBuilder({
				type: "div",
				class: ["title", collapsed ? "collapsed" : null],
				children: [
					elementBuilder({
						type: "div",
						class: "text",
						text: title
					}),
					elementBuilder({
						type: "div",
						class: "options"
					}),
					options.collapsible ? PHFillCaretDown({ class: "icon" }) : null
				]
			}));
			if (!options.onlyHeader) container.appendChild(elementBuilder({
				type: "main",
				class: mainClasses
			}));
			if (options.collapsible) container.querySelector(".title").addEventListener("click", async () => {
				container.querySelector(".title").classList.toggle("collapsed");
				await ttStorage.change({ filters: { containers: { [options.id]: container.querySelector(".title").classList.contains("collapsed") } } });
			});
			if (options.allowDragging) {
				const content = container.querySelector(":scope > main");
				content.addEventListener("dragover", (event) => event.preventDefault());
				content.addEventListener("drop", (event) => {
					if (content.querySelector(".temp.item, .temp.quick-item")) content.querySelector(".temp.item, .temp.quick-item").classList.remove("temp");
					event.preventDefault();
					event.dataTransfer?.clearData();
				});
			}
			return {
				container,
				collapsed
			};
		}
	}
	function findContainer(title, partialOptions = {}) {
		const options = {
			id: camelCase(title),
			selector: void 0,
			...partialOptions
		};
		if (!options.id) return null;
		const container = document.querySelector(`#${options.id}`);
		if (!container) return null;
		if (options.selector) return container.querySelector(options.selector);
		else return container;
	}
	function removeContainer(title, partialOptions = {}) {
		const container = findContainer(title, partialOptions);
		if (!container) return;
		container.remove();
	}
	_css(".filter-container+*{margin-top:0!important}.filter-header{flex-direction:row-reverse;margin-bottom:10px;display:flex}.filter-header .statistic span{font-weight:700}.filter-content{flex-wrap:wrap;display:flex}.tt-mobile .filter-content .filter-wrap{flex:1 0 100%}.filter-wrap,.filter-subwrap{flex:1 0 auto;margin-bottom:10px}.filter-wrap .filter-heading{text-align:center;margin-bottom:5px;font-weight:700}.filter-slider{width:70%;margin:auto auto 10px}.filter-slider+.filter-slider-info{text-align:center;width:100%}.filter-wrap select{width:fit-content;margin:auto;display:block}.filter-hidden,.filter-hidden+.tt-user-info{display:none!important}.filter-multi-wrap{width:fit-content;margin:auto}.tt-mobile .filter-multi-wrap{width:80%;display:flex}.tt-mobile .filter-multi-wrap>*{flex:1 0 auto}.tt-checkbox-wrap input{cursor:pointer;height:13px;margin:1px 5px 0;position:relative;top:-2px}.tt-checkbox-wrap *,.tt-input-wrap *{vertical-align:top;display:inline-block}.filter-header .statistic{margin:5px 10px 0 0}.tt-filter{font-family:Arial}.tt-filter .statistics{text-align:right;width:100%;padding-top:5px;transform:translate(-10px)}.tt-filter .content{flex-wrap:wrap;justify-content:space-evenly;width:100%;padding:10px 0;display:flex}body.tt-mobile .tt-filter .content,body.tt-tablet .tt-filter .content{flex-flow:column;justify-content:center;align-items:center}body.tt-mobile .tt-filter .content .tt-checkbox-wrapper,body.tt-tablet .tt-filter .content .tt-checkbox-wrapper{margin:1px 0}.tt-filter .content .tt-yn-checkboxes>div{align-items:center;display:flex}.tt-filter .content .tt-yn-checkboxes label{margin-left:4px}.tt-filter .content>div{text-align:center;padding:0 10px}body.tt-mobile .tt-filter .content>div,body.tt-tablet .tt-filter .content>div{margin-bottom:12px}.tt-filter .content strong{margin-bottom:2px;display:block}.tt-filter .content .tt-slider{padding:0 10px}.tt-filter .content .slider-counter{margin-top:5px}.weaponBonus__section-class{grid-template:\"title title\"\"b1 v1\"\"b2 v2\"/1fr .5fr;gap:4px;display:grid}.weaponBonus__section-class strong{grid-area:title}.tt-filter-enabled-funnel{cursor:pointer;font-size:16px;margin-right:-4px!important}");
	_css(".tt-checkbox-wrapper,.tt-checkbox-wrapper label{align-items:center;display:inline-flex}.tt-checkbox-wrapper>*{cursor:pointer}.tt-checkbox-wrapper.reverse-label label{flex-flow:row-reverse}.tt-checkbox-wrapper:not(.reverse-label) input{margin-right:2px}.tt-checkbox-wrapper.reverse-label input{margin-left:2px}");
	function createCheckbox(partialOptions = {}) {
		const options = {
			description: "",
			isHTML: false,
			reverseLabel: false,
			id: getUUID(),
			class: "",
			...partialOptions
		};
		const checkbox = elementBuilder({
			type: "input",
			id: options.id,
			attributes: { type: "checkbox" }
		});
		let label;
		if (typeof options.description === "object") label = elementBuilder({
			type: "label",
			children: [options.description]
		});
		else label = elementBuilder({
			type: "label",
			[options.isHTML ? "html" : "text"]: options.description
		});
		label.insertAdjacentElement("afterbegin", checkbox);
		const checkboxWrapper = elementBuilder({
			type: "div",
			class: `tt-checkbox-wrapper ${options.reverseLabel ? "reverse-label" : ""} ${options.class}`,
			children: [label],
			events: { click(event) {
				event.stopPropagation();
			} }
		});
		let onChangeCallback;
		function setChecked(isChecked) {
			checkbox.checked = isChecked;
		}
		function isChecked() {
			return checkbox.checked;
		}
		function onChange(callback) {
			onChangeCallback = callback;
			checkbox.addEventListener("change", _onChangeListener);
		}
		function dispose() {
			if (onChangeCallback) {
				checkbox.removeEventListener("change", _onChangeListener);
				onChangeCallback = void 0;
			}
		}
		function _onChangeListener() {
			onChangeCallback();
		}
		return {
			element: checkboxWrapper,
			setChecked,
			isChecked,
			onChange,
			dispose
		};
	}
	_css(".tt-checkbox-list-wrapper{display:flex}.tt-checkbox-list-wrapper.tt-checkbox-list-column{flex-direction:column}.tt-checkbox-list-wrapper.tt-checkbox-list-row{flex-direction:row}.tt-checkbox-list-wrapper.tt-checkbox-list-row>.tt-checkbox-wrapper:not(:first-child){margin-left:10px}");
	function createCheckboxList(partialOptions) {
		const options = {
			items: [],
			orientation: "column",
			reverseLabel: false,
			useId: false,
			...partialOptions
		};
		let selectedIds = {};
		const checkboxes = {};
		let selectionChangeCallback;
		for (const item of options.items) {
			const checkbox = options.useId ? createCheckbox({
				description: item.description,
				reverseLabel: options.reverseLabel,
				id: item.id.toString()
			}) : createCheckbox({
				description: item.description,
				reverseLabel: options.reverseLabel
			});
			checkbox.onChange(() => {
				if (checkbox.isChecked()) selectedIds[item.id] = true;
				else delete selectedIds[item.id];
				if (selectionChangeCallback) selectionChangeCallback();
			});
			checkboxes[item.id] = checkbox;
		}
		const checkboxWrapper = elementBuilder({
			type: "div",
			class: ["tt-checkbox-list-wrapper", options.orientation === "row" ? "tt-checkbox-list-row" : "tt-checkbox-list-column"].join(" "),
			children: Object.values(checkboxes).map((checkbox) => checkbox.element)
		});
		function setSelections(selectedItemIds) {
			selectedIds = selectedItemIds.reduce((object, id) => {
				object[id] = true;
				return object;
			}, {});
			for (const id in checkboxes) checkboxes[id].setChecked(selectedIds[id] || false);
		}
		function getSelections() {
			return Object.keys(selectedIds);
		}
		function onSelectionChange(callback) {
			selectionChangeCallback = callback;
		}
		function dispose() {
			Object.values(checkboxes).forEach((checkbox) => checkbox.dispose());
			selectionChangeCallback = void 0;
		}
		return {
			element: checkboxWrapper,
			setSelections,
			getSelections,
			onSelectionChange,
			dispose
		};
	}
	_css(".tt-multi-select{border-radius:4px;flex-direction:column;max-height:100px;padding:5px;display:flex;overflow:hidden auto}body:not(.dark-mode) .tt-multi-select{background-color:#ddd}body.dark-mode .tt-multi-select{background-color:#444}.tt-multi-select label{cursor:pointer;align-items:center;margin-bottom:4px;display:flex}.tt-multi-select label[disabled]{cursor:not-allowed}.tt-multi-select input{cursor:pointer}.tt-multi-select span{margin-left:6px}");
	function createSelect(options) {
		let selectedOptionValue = options[0].value;
		let shownOptions = options;
		let onChangeCallback;
		const select = elementBuilder({
			type: "select",
			children: _createOptionsElements(shownOptions)
		});
		function updateOptionsList(options, s = select) {
			if (options.every((option) => option.value !== selectedOptionValue)) options.unshift(shownOptions.find((option) => option.value === selectedOptionValue));
			const newOptions = _createOptionsElements(options);
			while (s.firstChild) s.removeChild(s.firstChild);
			const documentFragment = document.createDocumentFragment();
			newOptions.forEach((newOption) => documentFragment.appendChild(newOption));
			s.appendChild(documentFragment);
			shownOptions = options;
			setSelected(selectedOptionValue);
		}
		function setSelected(optionValue) {
			const index = shownOptions.findIndex((option) => option.value === optionValue);
			if (index === -1) return false;
			if (shownOptions[index].disabled) return false;
			selectedOptionValue = optionValue;
			select.selectedIndex = index;
			return true;
		}
		function getSelected() {
			return select.value;
		}
		function onChange(callback) {
			onChangeCallback = callback;
			select.addEventListener("change", _onChangeListener);
		}
		function dispose() {
			if (onChangeCallback) {
				select.removeEventListener("change", _onChangeListener);
				onChangeCallback = void 0;
			}
		}
		function _createOptionsElements(optionsLst) {
			return optionsLst.map((option) => elementBuilder({
				type: "option",
				attributes: {
					value: option.value,
					...option.value === selectedOptionValue ? { selected: "true" } : {},
					...option.disabled ? { disabled: "true" } : {}
				},
				text: option.description
			}));
		}
		function _onChangeListener() {
			selectedOptionValue = select.value;
			if (onChangeCallback) onChangeCallback();
		}
		return {
			element: select,
			updateOptionsList,
			setSelected,
			getSelected,
			onChange,
			dispose
		};
	}
	function createMultiSelect(options) {
		let selectedValues = Array.isArray(options.defaults) ? options.defaults : [];
		let shownOptions = options.select;
		let onChangeCallback;
		const container = elementBuilder({
			type: "div",
			class: "tt-multi-select"
		});
		function renderOptions() {
			container.innerHTML = "";
			shownOptions.forEach((opt) => {
				const wrapper = elementBuilder({ type: "label" });
				if (opt.disabled) wrapper.setAttribute("disabled", "true");
				const checkbox = elementBuilder({
					type: "input",
					value: opt.value,
					attributes: { type: "checkbox" },
					events: { change: () => {
						if (checkbox.checked) {
							if (!selectedValues.includes(opt.value)) selectedValues.push(opt.value);
						} else selectedValues = selectedValues.filter((v) => v !== opt.value);
						if (onChangeCallback) onChangeCallback();
					} }
				});
				checkbox.checked = selectedValues.includes(opt.value);
				checkbox.disabled = !!opt.disabled;
				const text = elementBuilder({
					type: "span",
					text: opt.description
				});
				wrapper.appendChild(checkbox);
				wrapper.appendChild(text);
				container.appendChild(wrapper);
			});
		}
		function setSelected(values) {
			selectedValues = Array.isArray(values) ? values : [values];
			renderOptions();
		}
		function getSelected() {
			return [...selectedValues];
		}
		function onChange(callback) {
			onChangeCallback = callback;
		}
		function updateOptionsList(newList) {
			shownOptions = newList;
			renderOptions();
		}
		renderOptions();
		return {
			element: container,
			getSelected,
			setSelected,
			onChange,
			updateOptionsList
		};
	}
	_css(".tt-dual-range{user-select:none;background:#ddd;border-radius:50px;width:150px;height:12px;margin:auto;position:relative}.tt-dual-range .highlight{height:12px;width:calc(calc(var(--right) - var(--left)) + 21px);left:var(--left);z-index:1;background-color:#627e0d;border-radius:50px;position:absolute}.tt-dual-range .handle{z-index:2;cursor:grab;float:none;border-radius:50%;width:21px;height:21px;position:absolute;top:50%;transform:translateY(-50%);box-shadow:0 3px 6px #0000001a}.tt-dual-range .handle.focus{border:3px solid #888;width:15px;height:15px}body:not(.dark-mode) .tt-dual-range .handle{background-color:#fff}body.dark-mode .tt-dual-range .handle{background-color:#e8e8e8}.tt-dual-range .handle.left{left:var(--left)}.tt-dual-range .handle.right{left:var(--right)}.tt-dual-range .dump{width:0;overflow:hidden}.tt-dual-range .dump *{opacity:0}.tt-slider-wrapper{flex-direction:column;align-items:center;display:flex}.tt-slider-label{margin-top:10px}");
	var DualRangeSlider = class {
		options;
		uuid;
		startPos;
		slider;
		activeHandle;
		handles;
		moveTouchListener = this.moveTouch.bind(this);
		moveListener = this.move.bind(this);
		constructor(options = {}) {
			this.options = {
				min: 0,
				max: 100,
				step: 1,
				valueLow: options.min || 0,
				valueHigh: options.max || 100,
				...options
			};
			this.uuid = getUUID();
			this.startPos = 0;
			this.handles = [];
			this._createElement();
		}
		_createElement() {
			this.slider = elementBuilder({
				type: "div",
				class: "tt-dual-range",
				html: `	
				<label for="handle-left_${this.uuid}" class="handle left"></label>
				<span class="highlight"></span>
				<label for="handle-right_${this.uuid}" class="handle right"></label>
				<div class="dump">
					<input id="handle-left_${this.uuid}"/>
					<input id="handle-right_${this.uuid}"/>
				</div>
			`
			});
			this.handles = findAllElements(".handle", this.slider);
			this.handles.forEach((handle) => {
				const input = this.slider.querySelector(`#${handle.getAttribute("for")}`);
				handle.addEventListener("mousedown", this.startMove.bind(this));
				handle.addEventListener("touchstart", this.startMoveTouch.bind(this));
				handle.addEventListener("click", () => input.focus());
				input.addEventListener("focus", () => handle.classList.add("focus"));
				input.addEventListener("blur", () => handle.classList.remove("focus"));
				input.addEventListener("keydown", this.moveKeyboard.bind(this));
			});
			this.updateValue(this.handles[0], this.options.valueLow);
			this.updateValue(this.handles[1], this.options.valueHigh);
			window.addEventListener("mouseup", this.stopMove.bind(this));
			window.addEventListener("touchend", this.stopMove.bind(this));
			window.addEventListener("touchcancel", this.stopMove.bind(this));
			window.addEventListener("touchleave", this.stopMove.bind(this));
		}
		startMoveTouch(event) {
			const handleRect = event.target.getBoundingClientRect();
			this.startPos = event.touches[0].clientX - handleRect.x;
			this.activeHandle = event.target;
			window.addEventListener("touchmove", this.moveTouchListener);
		}
		startMove(event) {
			this.startPos = event.offsetX;
			this.activeHandle = event.target;
			window.addEventListener("mousemove", this.moveListener);
		}
		moveKeyboard(event) {
			if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
			const handle = this.slider.querySelector(`.handle[for="${event.target.id}"]`);
			if (!handle) return;
			let value = parseInt(handle.dataset.value);
			if (event.key === "ArrowLeft") value -= this.options.step;
			else if (event.key === "ArrowRight") value += this.options.step;
			this.updateValue(handle, value);
		}
		moveTouch(event) {
			this.move({ clientX: event.touches[0].clientX });
		}
		move(event) {
			const parentRect = this.slider.getBoundingClientRect();
			const handleRect = this.activeHandle.getBoundingClientRect();
			const position = Math.max(Math.min(event.clientX - parentRect.x - this.startPos, parentRect.width - handleRect.width / 2), 0 - handleRect.width / 2);
			this.updateValue(this.activeHandle, this.calculateValue((position + handleRect.width / 2) / parentRect.width));
		}
		calculateValue(percentage) {
			return Math.round(percentage * (this.options.max - this.options.min) + this.options.min);
		}
		updateValue(handle, value) {
			value = roundNearest(Math.max(Math.min(value, this.options.max), this.options.min), this.options.step);
			handle.dataset.value = value.toString();
			this.updateValues();
		}
		stopMove() {
			window.removeEventListener("mousemove", this.moveListener);
			window.removeEventListener("touchmove", this.moveTouchListener);
		}
		updateValues() {
			const valueLeft = parseInt(this.handles[0].dataset.value);
			const valueRight = parseInt(this.handles[1].dataset.value);
			const low = Math.min(valueLeft, valueRight);
			const high = Math.max(valueLeft, valueRight);
			this.updateHighlight("left", low);
			this.updateHighlight("right", high);
			this.slider.dataset.low = low.toString();
			this.slider.dataset.high = high.toString();
		}
		updateHighlight(side, value) {
			const rangeWidth = this.slider.getBoundingClientRect().width || 150;
			const handleWidth = this.handles[0].getBoundingClientRect().width || 21;
			const percentage = (value - this.options.min) / (this.options.max - this.options.min);
			this.slider.style.setProperty(`--${side}`, `${percentage * rangeWidth - handleWidth / 2}px`);
		}
	};
	var LINKS = {
		auction: "https://www.torn.com/amarket.php",
		bank: "https://www.torn.com/bank.php",
		bazaar: "https://www.torn.com/bazaar.php",
		bounties: "https://www.torn.com/bounties.php#!p=main",
		chain: "https://www.torn.com/factions.php?step=your#/war/chain",
		church: "https://www.torn.com/church.php",
		committee: "https://www.torn.com/committee.php",
		companies: "https://www.torn.com/companies.php",
		companyEmployees: "https://www.torn.com/companies.php#/option=employees",
		crimes: "https://www.torn.com/crimes.php",
		donator: "https://www.torn.com/donator.php",
		education: "https://www.torn.com/page.php?sid=education",
		events: "https://www.torn.com/events.php#/step=all",
		faction: "https://www.torn.com/factions.php",
		faction__ranked_war: "https://www.torn.com/factions.php?step=your&type=1#/war/rank",
		faction_oc: "https://www.torn.com/factions.php?step=your#/tab=crimes",
		gym: "https://www.torn.com/gym.php",
		home: "https://www.torn.com/index.php",
		homepage: "https://www.torn.com/index.php",
		hospital: "https://www.torn.com/hospitalview.php",
		itemmarket: "https://www.torn.com/page.php?sid=ItemMarket",
		items: "https://www.torn.com/item.php",
		items_booster: "https://www.torn.com/item.php#boosters-items",
		items_candy: "https://www.torn.com/item.php#candy-items",
		items_drug: "https://www.torn.com/item.php#drugs-items",
		items_medical: "https://www.torn.com/item.php#medical-items",
		jailview: "https://www.torn.com/jailview.php",
		jobs: "https://www.torn.com/companies.php",
		loan: "https://www.torn.com/loan.php",
		messages: "https://www.torn.com/messages.php",
		missions: "https://www.torn.com/loader.php?sid=missions",
		organizedCrimes: "https://www.torn.com/factions.php?step=your#/tab=crimes",
		pc: "https://www.torn.com/pc.php",
		points: "https://www.torn.com/page.php?sid=points",
		pointsmarket: "https://www.torn.com/pmarket.php",
		properties: "https://www.torn.com/properties.php",
		property_upkeep: "https://www.torn.com/properties.php#/p=options&tab=upkeep",
		property_vault: "https://www.torn.com/properties.php#/p=options&tab=vault",
		raceway: "https://www.torn.com/page.php?sid=racing",
		staff: "https://www.torn.com/staff.php",
		stocks: "https://www.torn.com/page.php?sid=stocks",
		trade: "https://www.torn.com/trade.php",
		travelagency: "https://www.torn.com/page.php?sid=travel"
	};
	LINKS.donator, LINKS.donator, LINKS.staff, LINKS.committee, LINKS.church, LINKS.jobs, LINKS.jobs, LINKS.jobs, LINKS.jobs, LINKS.jobs, LINKS.jobs, LINKS.companies, LINKS.companies, LINKS.companies, LINKS.faction, LINKS.faction, LINKS.faction, LINKS.faction, LINKS.faction, LINKS.education, LINKS.education, LINKS.bank, LINKS.bank, LINKS.travelagency, LINKS.property_vault, LINKS.loan, LINKS.auction, LINKS.bazaar, LINKS.itemmarket, LINKS.pointsmarket, LINKS.stocks, LINKS.stocks, LINKS.trade, LINKS.homepage, LINKS.raceway, LINKS.raceway, LINKS.faction_oc, LINKS.faction_oc, LINKS.faction_oc, LINKS.faction_oc, LINKS.bounties, LINKS.bank, LINKS.auction, LINKS.auction, LINKS.hospital, LINKS.hospital, LINKS.hospital, LINKS.jailview, LINKS.hospital, LINKS.items_booster, LINKS.items_booster, LINKS.items_booster, LINKS.items_booster, LINKS.items_booster, LINKS.items_medical, LINKS.items_medical, LINKS.items_medical, LINKS.items_medical, LINKS.items_medical, LINKS.items_drug, LINKS.items_drug, LINKS.items_drug, LINKS.items_drug, LINKS.items_drug, LINKS.travelagency, LINKS.travelagency, LINKS.travelagency, LINKS.travelagency, LINKS.travelagency, LINKS.items_medical, LINKS.items_medical, LINKS.items_medical, LINKS.items_medical, LINKS.items_medical, LINKS.property_upkeep, LINKS.property_upkeep, LINKS.property_upkeep;
	[
		{
			id: 1,
			reason: "Admin"
		},
		{
			id: 4,
			reason: "NPC"
		},
		{
			id: 7,
			reason: "NPC"
		},
		{
			id: 9,
			reason: "NPC"
		},
		{
			id: 10,
			reason: "NPC"
		},
		{
			id: 15,
			reason: "NPC"
		},
		{
			id: 17,
			reason: "NPC"
		},
		{
			id: 19,
			reason: "NPC"
		},
		{
			id: 20,
			reason: "NPC"
		},
		{
			id: 21,
			reason: "NPC"
		}
	].map(({ id }) => id);
	var SPECIAL_FILTER_ICONS = {
		traveling: ["icon71"],
		isFedded: ["icon70"],
		fedded: ["icon70"],
		newPlayer: ["icon72"],
		onWall: ["icon75", "icon76"],
		inCompany: [
			"icon21",
			"icon22",
			"icon23",
			"icon24",
			"icon25",
			"icon26",
			"icon27",
			"icon73",
			"icon83"
		],
		inFaction: [
			"icon9",
			"icon74",
			"icon81"
		],
		isDonator: ["icon3", "icon4"],
		inHospital: ["icon15"],
		inJail: ["icon16"],
		fallen: ["icon77"],
		earlyDischarge: ["icon82"],
		isRecruit: ["icon81"],
		hasBounties: ["icon13"],
		bazaarOpen: ["icon35"]
	};
	function is2FACheckPage() {
		return !!document.querySelector(".content-wrapper.logged-out .two-factor-auth-container");
	}
	function getPageStatus() {
		const infoMessage = document.querySelector(".content-wrapper .info-msg-cont");
		if (infoMessage?.classList.contains("red")) {
			if (infoMessage.textContent.includes("items in your inventory")) return { access: true };
			else if (findParent(infoMessage, { class: "no-parcel-wrap" })?.style?.display === "none") return { access: true };
			return {
				access: false,
				message: infoMessage.textContent
			};
		}
		if (document.querySelector(".captcha")) return {
			access: false,
			message: "Captcha required"
		};
		else if (document.querySelector(".dirty-bomb")) return {
			access: false,
			message: "Dirty bomb screen"
		};
		else if (is2FACheckPage()) return {
			access: false,
			message: "2 Factor Authentication"
		};
		return { access: true };
	}
	var RANK_TRIGGERS = {
		level: [
			2,
			6,
			11,
			26,
			31,
			50,
			71,
			100
		],
		crimes: [
			100,
			5e3,
			1e4,
			2e4,
			3e4,
			5e4
		],
		networth: [
			5e6,
			5e7,
			5e8,
			5e9,
			5e10
		],
		stats: [
			"under 2k",
			"2k - 25k",
			"20k - 250k",
			"200k - 2.5m",
			"2m - 25m",
			"20m - 250m",
			"over 200m"
		]
	};
	var HOSPITALIZATION_REASONS = {
		attackedBy: "Attacked by",
		muggedBy: "Mugged by",
		hospitalizedBy: "Hospitalized by",
		other: [
			"Attacked by",
			"Mugged by",
			"Hospitalized by"
		]
	};
	[...hasAPIData() && userdata.faction ? [{
		value: userdata.faction.tag,
		description: userdata.faction.tag
	}] : []];
	function createFilterSection(options) {
		if ("type" in options) {
			if (options.type === "Activity") return createFilterSection({
				title: "Activity",
				checkboxes: [
					{
						id: "online",
						description: "Online"
					},
					{
						id: "idle",
						description: "Idle"
					},
					{
						id: "offline",
						description: "Offline"
					}
				],
				defaults: options.defaults,
				callback: options.callback
			});
			else if (options.type === "HideRaces") return createFilterSection({
				title: "Hide Races",
				checkboxes: [
					{
						id: "full",
						description: "Full"
					},
					{
						id: "protected",
						description: "Protected"
					},
					{
						id: "incompatible",
						description: "Incompatible"
					},
					{
						id: "paid",
						description: "With Fee"
					}
				],
				defaults: options.defaults,
				callback: options.callback
			});
			else if (options.type === "LevelAll") return createFilterSection({
				title: "Level Filter",
				noTitle: true,
				slider: {
					min: 0,
					max: 100,
					step: 1,
					valueLow: options.typeData.valueLow,
					valueHigh: options.typeData.valueHigh
				},
				callback: options.callback
			});
			else if (options.type === "LevelPlayer") return createFilterSection({
				title: "Level Filter",
				noTitle: true,
				slider: {
					min: 1,
					max: 100,
					step: 1,
					valueLow: options.typeData.valueLow,
					valueHigh: options.typeData.valueHigh
				},
				callback: options.callback
			});
			return null;
		}
		const ccTitle = `${camelCase(options.title)}__section-class`;
		const section = elementBuilder({
			type: "div",
			class: ccTitle,
			style: options.style
		});
		if (!options.noTitle) section.appendChild(elementBuilder({
			type: "strong",
			text: options.title
		}));
		if (isTextOptions(options)) {
			const textbox = createTextbox({ type: typeof options.text === "string" ? options.text : "text" });
			textbox.setValue(options.default);
			textbox.onChange(options.callback);
			section.appendChild(textbox.element);
			return {
				element: section,
				getValue: () => textbox.getValue()
			};
		}
		if (isCheckboxOptions(options)) {
			const checkbox = createCheckbox({ description: options.checkbox });
			checkbox.onChange(options.callback);
			checkbox.setChecked(options.default);
			section.appendChild(checkbox.element);
			return {
				element: section,
				isChecked: (content) => content.querySelector(`.${ccTitle} input`)?.checked ?? false
			};
		}
		if (isCheckboxesOptions(options)) {
			const checkboxes = createCheckboxList({
				items: options.checkboxes,
				orientation: options.orientation ?? "column",
				useId: true
			});
			checkboxes.onSelectionChange(options.callback);
			checkboxes.setSelections(Array.isArray(options.defaults) ? options.defaults : []);
			section.appendChild(checkboxes.element);
			return {
				element: section,
				getSelections: (content) => findAllElements(`.${ccTitle} input:checked`, content).map((x) => x.getAttribute("id")?.toLowerCase().trim() ?? "")
			};
		}
		if (isYNCheckboxesOptions(options)) {
			options.ynCheckboxes.forEach((key) => {
				const ccKey = camelCase(key);
				const checkboxesDiv = elementBuilder({
					type: "div",
					class: ccKey
				});
				const yCheckbox = createCheckbox({
					description: "Y:",
					reverseLabel: true
				});
				const nCheckbox = createCheckbox({
					description: "N:",
					reverseLabel: true
				});
				const value = options.defaults[ccKey];
				if (value === "yes" || value === "both") yCheckbox.setChecked(true);
				if (value === "no" || value === "both") nCheckbox.setChecked(true);
				yCheckbox.onChange(options.callback);
				nCheckbox.onChange(options.callback);
				checkboxesDiv.appendChild(yCheckbox.element);
				checkboxesDiv.appendChild(nCheckbox.element);
				checkboxesDiv.appendChild(elementBuilder({
					type: "label",
					text: key
				}));
				section.appendChild(checkboxesDiv);
			});
			section.classList.add("tt-yn-checkboxes");
			return {
				element: section,
				getSelections
			};
			function getSelections(content) {
				const selections = {};
				for (const specialDiv of findAllElements(`.${ccTitle} > div`, content)) {
					const checkboxes = findAllElements("input", specialDiv);
					const yChecked = checkboxes[0].checked;
					const nChecked = checkboxes[1].checked;
					const key = specialDiv.className.split("__")[0];
					if (yChecked && nChecked) selections[key] = "both";
					else if (yChecked) selections[key] = "yes";
					else if (nChecked) selections[key] = "no";
					else selections[key] = "none";
				}
				return selections;
			}
		}
		if (isMultiSelectOptions(options)) {
			const multiSelect = createMultiSelect({
				select: options.select.filter((opt) => opt.value !== ""),
				defaults: Array.isArray(options.defaults) ? options.defaults : []
			});
			multiSelect.onChange(options.callback);
			section.appendChild(multiSelect.element);
			return {
				element: section,
				getSelected: () => multiSelect.getSelected(),
				updateOptions: (newOptions) => multiSelect.updateOptionsList(newOptions)
			};
		}
		if (isSelectOptions(options)) {
			const select = createSelect(options.select);
			select.setSelected(options.default ?? "");
			select.onChange(options.callback);
			section.appendChild(select.element);
			return {
				element: section,
				getSelected: (content) => content.querySelector(`.${ccTitle} select`)?.value ?? "",
				updateOptions: (newOptions, content) => select.updateOptionsList(newOptions, content.querySelector(`.${ccTitle} select`))
			};
		}
		if (isSliderOptions(options)) {
			const rangeSlider = new DualRangeSlider(options.slider);
			section.appendChild(rangeSlider.slider);
			section.appendChild(elementBuilder({
				type: "div",
				class: "slider-counter",
				text: ""
			}));
			section.classList.add("tt-slider");
			new MutationObserver(options.callback).observe(rangeSlider.slider, { attributes: true });
			return {
				element: section,
				getStartEnd,
				updateCounter
			};
			function getStartEnd(content) {
				const rangeElement = content.querySelector(`.${ccTitle} .tt-dual-range`);
				if (!rangeElement) return {
					start: options.slider.valueLow,
					end: options.slider.valueHigh
				};
				return {
					start: rangeElement.dataset.low,
					end: rangeElement.dataset.high
				};
			}
			function updateCounter(string, content) {
				const counter = content.querySelector(`.${ccTitle} .slider-counter`);
				if (!counter) return;
				counter.textContent = string;
			}
		}
		return { element: section };
	}
	function isTextOptions(options) {
		return "text" in options;
	}
	function isCheckboxOptions(options) {
		return "checkbox" in options;
	}
	function isCheckboxesOptions(options) {
		return "checkboxes" in options;
	}
	function isYNCheckboxesOptions(options) {
		return "ynCheckboxes" in options;
	}
	function isMultiSelectOptions(options) {
		return "select" in options && "multiSelect" in options;
	}
	function isSelectOptions(options) {
		return "select" in options && !("type" in options);
	}
	function isSliderOptions(options) {
		return "slider" in options;
	}
	function createStatistics(name = "entries", addBrackets = false, lowercase = false) {
		const statistics = elementBuilder({
			type: "div",
			class: "statistics",
			children: [
				`${addBrackets ? "(" : ""}${lowercase ? "s" : "S"}howing `,
				elementBuilder({
					type: "strong",
					class: "stat-count",
					text: "X"
				}),
				" of ",
				elementBuilder({
					type: "strong",
					class: "stat-total",
					text: "Y"
				}),
				` ${name}${addBrackets ? ")" : "."}`
			]
		});
		function updateStatistics(count, total, content) {
			content.querySelector(".statistics .stat-count").textContent = count.toString();
			content.querySelector(".statistics .stat-total").textContent = total.toString();
		}
		return {
			element: statistics,
			updateStatistics
		};
	}
	function getSpecialIcons(li) {
		return findAllElements(":scope li[id*='icon']", li).map((x) => x.id.split("_")[0]);
	}
	function createFilterEnabledFunnel(partialOptions = {}) {
		const options = {
			id: getUUID(),
			class: "",
			...partialOptions
		};
		const iconWrapper = elementBuilder({
			type: "div",
			class: ["tt-filter-enabled-funnel", options.class],
			attributes: {
				id: options.id,
				title: "Disable this filter."
			}
		});
		let onChangeCallback;
		let enabled = false;
		function updateIcon() {
			iconWrapper.innerHTML = "";
			iconWrapper.appendChild(enabled ? PHFillFunnel() : PHFillFunnelX());
			iconWrapper.setAttribute("title", enabled ? "Disable this filter." : "Enable this filter.");
		}
		function setEnabled(isEnabled) {
			enabled = isEnabled;
			updateIcon();
		}
		function isEnabled() {
			return enabled;
		}
		function onChange(callback) {
			onChangeCallback = callback;
			iconWrapper.addEventListener("click", _onClickListener);
		}
		function dispose() {
			if (onChangeCallback) {
				iconWrapper.removeEventListener("click", _onClickListener);
				onChangeCallback = void 0;
			}
		}
		function _onClickListener(event) {
			event.stopPropagation();
			enabled = !enabled;
			updateIcon();
			onChangeCallback(enabled);
		}
		updateIcon();
		return {
			element: iconWrapper,
			setEnabled,
			isEnabled,
			onChange,
			dispose
		};
	}
	var Feature = class {
		name;
		scope;
		executionTiming;
		constructor(name, scope, executionTiming = "CONTENT_LOADED") {
			this.name = name;
			this.scope = scope;
			this.executionTiming = executionTiming;
		}
		precondition() {
			return true;
		}
		initialise() {}
		execute(liveReload) {}
		cleanup() {}
		storageKeys() {
			return [];
		}
		requirements() {
			return true;
		}
		shouldTriggerEvents() {
			return false;
		}
		shouldLiveReload() {
			return false;
		}
		requiresScreenInformation() {
			return true;
		}
	};
	_css(".tt-stats-estimate-profile{float:right;color:var(--tt-color-light-green);padding-right:10px}.tt-stats-estimate{text-align:center;border-bottom:1px solid var(--default-panel-divider-outer-side-color);justify-content:center;align-items:center;min-height:11px;padding:5px;display:flex}body.tt-elimination .tt-stats-estimate{background-color:var(--elimination-team-list-background-color)}.tt-stats-estimate .tt-loading-placeholder{padding:0}.tt-stats-estimate-attacks-wrapper>*{margin-left:10px!important}.tt-mobile .tt-stats-estimate-attacks-wrapper>:first-child,.tt-mobile .tt-stats-estimate-attacks-wrapper>:nth-child(2){margin-left:0!important}.tt-mobile .tt-stats-estimate-attacks-wrapper>:nth-child(3){margin-left:5px!important}.tt-mobile .tt-stats-estimate-attacks-wrapper>:nth-child(4){margin-left:12px!important}.bounties-list .tt-stats-estimate{background:var(--newspaper-divider-horizontal-older-line-url) left top repeat-x}body.dark-mode .bounties-list .tt-stats-estimate{color:#aaa}.faction-war .tt-stats-estimate{border-bottom:unset}.tt-transparent-estimates .tt-stats-estimate{background-color:var(--default-bg-panel-color)}body[data-page=enemies] .tt-stats-estimate{background:var(--default-bg-panel-color)}");
	var ESTIMATE_INSTANCES = {};
	function hasStatsEstimatesLoaded(name) {
		return name in ESTIMATE_INSTANCES && !ESTIMATE_INSTANCES[name].running;
	}
	function initialiseFilters() {
		CUSTOM_LISTENERS[EVENT_CHANNELS.USERLIST_SWITCH_PAGE].push(async () => {
			if (!FEATURE_MANAGER.isEnabled(UserlistFilterFeature)) return;
			await filtering();
		});
		CUSTOM_LISTENERS[EVENT_CHANNELS.STATS_ESTIMATED].push(({ row }) => {
			if (!FEATURE_MANAGER.isEnabled(UserlistFilterFeature)) return;
			const content = findContainer("Userlist Filter", { selector: "main" });
			const statsEstimates = localFilters["Stats Estimate"]?.getSelections(content);
			if (!statsEstimates?.length) return;
			filterRow(row, { statsEstimates }, true);
		});
		CUSTOM_LISTENERS[EVENT_CHANNELS.FF_SCOUTER_GAUGE].push(async () => {
			if (!FEATURE_MANAGER.isEnabled(UserlistFilterFeature)) return;
			if (!localFilters["FF Score Max"]?.getValue() && !localFilters["FF Score Min"]?.getValue()) return;
			await filtering();
		});
	}
	var localFilters = {};
	async function addFilters() {
		await requireElement(".userlist-wrapper .user-info-list-wrap");
		const { content, options } = createContainer("Userlist Filter", {
			class: "mt10",
			nextElement: document.querySelector(".users-list-title"),
			compact: true,
			filter: true
		});
		const statistics = createStatistics("players");
		content.appendChild(statistics.element);
		localFilters["Statistics"] = { updateStatistics: statistics.updateStatistics };
		const filterContent = elementBuilder({
			type: "div",
			class: "content"
		});
		const activityFilter = createFilterSection({
			type: "Activity",
			defaults: filters.userlist.activity,
			callback: () => filtering()
		});
		filterContent.appendChild(activityFilter.element);
		localFilters["Activity"] = { getSelections: activityFilter.getSelections };
		const specialFilter = createFilterSection({
			title: "Special",
			ynCheckboxes: [
				"Fedded",
				"Fallen",
				"Traveling",
				"New Player",
				"On Wall",
				"In Company",
				"In Faction",
				"Is Donator",
				"In Hospital",
				"In Jail",
				"Early Discharge",
				"Has Bounties",
				"Bazaar Open"
			],
			defaults: filters.userlist.special,
			callback: () => filtering()
		});
		filterContent.appendChild(specialFilter.element);
		localFilters["Special"] = { getSelections: specialFilter.getSelections };
		const hospReasonFilter = createFilterSection({
			title: "Hosp Reason",
			ynCheckboxes: [
				"Attacked By",
				"Mugged By",
				"Hospitalized By",
				"Other"
			],
			defaults: filters.userlist.hospReason,
			callback: () => filtering()
		});
		filterContent.appendChild(hospReasonFilter.element);
		localFilters["Hosp Reason"] = { getSelections: hospReasonFilter.getSelections };
		const levelFilter = createFilterSection({
			type: "LevelAll",
			typeData: {
				valueLow: filters.userlist.levelStart,
				valueHigh: filters.userlist.levelEnd
			},
			callback: () => filtering()
		});
		filterContent.appendChild(levelFilter.element);
		localFilters["Level Filter"] = {
			getStartEnd: levelFilter.getStartEnd,
			updateCounter: levelFilter.updateCounter
		};
		if (settings.scripts.statsEstimate.global && settings.scripts.statsEstimate.userlist && hasAPIData()) {
			const estimatesFilter = createFilterSection({
				title: "Stats Estimates",
				checkboxes: [
					{
						id: "none",
						description: "none"
					},
					...RANK_TRIGGERS.stats.map((trigger) => ({
						id: trigger,
						description: trigger
					})),
					{
						id: "n/a",
						description: "N/A"
					}
				],
				defaults: filters.userlist.estimates,
				callback: () => filtering()
			});
			filterContent.appendChild(estimatesFilter.element);
			localFilters["Stats Estimate"] = { getSelections: estimatesFilter.getSelections };
		}
		if (settings.scripts.ffScouter.gauge && settings.external.ffScouter && hasAPIData()) {
			const ffScoreFilterMin = createFilterSection({
				title: "FF Score Min",
				text: "number",
				default: filters.userlist.ffScoreMin?.toString(),
				callback: () => filtering()
			});
			ffScoreFilterMin.element.querySelector("input").step = .1;
			filterContent.appendChild(ffScoreFilterMin.element);
			localFilters["FF Score Min"] = { getValue: ffScoreFilterMin.getValue };
			const ffScoreFilterMax = createTextbox({ type: "number" });
			ffScoreFilterMax.setValue(filters.userlist.ffScoreMax?.toString());
			ffScoreFilterMax.onChange(filtering);
			ffScoreFilterMax.element.step = "0.1";
			ffScoreFilterMin.element.appendChild(elementBuilder({
				type: "strong",
				text: "FF Score Max"
			}));
			ffScoreFilterMin.element.append(ffScoreFilterMax.element);
			localFilters["FF Score Max"] = { getValue: ffScoreFilterMax.getValue };
		}
		content.appendChild(filterContent);
		const enabledFunnel = createFilterEnabledFunnel();
		enabledFunnel.onChange(() => filtering());
		enabledFunnel.setEnabled(filters.userlist.enabled);
		options.appendChild(enabledFunnel.element);
		localFilters.enabled = { isEnabled: enabledFunnel.isEnabled };
		await filtering();
	}
	async function filtering() {
		await requireElement(".user-info-list-wrap");
		await requireCondition(() => {
			return !document.querySelector(".user-info-list-wrap .ajax-placeholder, .user-info-list-wrap .ajax-preloader") || document.evaluate("//*[contains(@class, 'userlist-wrapper')][.//*[contains(text(), 'No users found')]]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
		}, {});
		const content = findContainer("Userlist Filter", { selector: "main" });
		const activity = localFilters["Activity"].getSelections(content);
		const special = localFilters["Special"].getSelections(content);
		const hospReason = localFilters["Hosp Reason"].getSelections(content);
		const levels = localFilters["Level Filter"].getStartEnd(content);
		const levelStart = parseInt(levels.start);
		const levelEnd = parseInt(levels.end);
		const statsEstimates = hasStatsEstimatesLoaded("Userlist") && settings.scripts.statsEstimate.global && settings.scripts.statsEstimate.userlist && hasAPIData() ? localFilters["Stats Estimate"]?.getSelections(content) : void 0;
		localFilters["Level Filter"].updateCounter(`Level ${levelStart} - ${levelEnd}`, content);
		const ffScoreMin = parseFloat(localFilters["FF Score Min"]?.getValue()) || null;
		const ffScoreMax = parseFloat(localFilters["FF Score Max"]?.getValue()) || null;
		await ttStorage.change({ filters: { userlist: {
			enabled: localFilters.enabled.isEnabled(),
			activity,
			levelStart,
			levelEnd,
			special,
			hospReason,
			estimates: statsEstimates ?? filters.userlist.estimates,
			ffScoreMax,
			ffScoreMin
		} } });
		if (!localFilters.enabled.isEnabled()) {
			findAllElements(".user-info-list-wrap > li.tt-hidden").forEach((row) => {
				row.classList.remove("tt-hidden");
				delete row.dataset.hideReason;
			});
			localFilters["Statistics"].updateStatistics(findAllElements(".user-info-list-wrap > li:not(.tt-hidden)").length, findAllElements(".user-info-list-wrap > li").length, content);
			return;
		}
		for (const li of findAllElements(".user-info-list-wrap > li")) filterRow(li, {
			activity,
			special,
			hospReason,
			level: {
				start: levelStart,
				end: levelEnd
			},
			statsEstimates,
			ffScoreMin,
			ffScoreMax
		}, false);
		triggerCustomListener(EVENT_CHANNELS.FILTER_APPLIED, { filter: "Userlist Filter" });
		localFilters["Statistics"].updateStatistics(findAllElements(".user-info-list-wrap > li:not(.tt-hidden)").length, findAllElements(".user-info-list-wrap > li").length, content);
	}
	function filterRow(row, filters, individual) {
		if (row.querySelector(".ajax-preloader")) return;
		if (filters.activity) {
			if (filters.activity.length && !filters.activity.some((x) => x.trim() === row.querySelector("#iconTray li").getAttribute("title").match(/(?<=<b>).*(?=<\/b>)/g)[0].toLowerCase().trim())) {
				hide("activity");
				return;
			}
		}
		if (filters.special) {
			const match = Object.entries(filters.special).filter(([, value]) => value !== "both" && value !== "none").find(([key, value]) => {
				const icons = getSpecialIcons(row);
				const filterIcons = SPECIAL_FILTER_ICONS[key];
				return value === "yes" && !icons.some((foundIcon) => filterIcons.includes(foundIcon)) || value === "no" && icons.some((foundIcon) => filterIcons.includes(foundIcon));
			});
			if (match) {
				hide(`special-${match[0]}`);
				return;
			}
		}
		if (filters.hospReason) {
			const match = Object.entries(filters.hospReason).filter(([, value]) => value !== "both" && value !== "none").find(([key, value]) => {
				const isHospitalized = row.querySelector("li[title*='Hospital']");
				if (isHospitalized) {
					const hospitalizationReason = isHospitalized.getAttribute("title").split("<br>")[1];
					if (key === "other") return value === "yes" && HOSPITALIZATION_REASONS[key].some((reason) => hospitalizationReason.match(reason)) || value === "no" && !HOSPITALIZATION_REASONS[key].some((reason) => hospitalizationReason.match(reason));
					else return value === "yes" && !hospitalizationReason.includes(HOSPITALIZATION_REASONS[key]) || value === "no" && hospitalizationReason.includes(HOSPITALIZATION_REASONS[key]);
				}
				return false;
			});
			if (match) {
				hide(`hospReason-${match[0]}`);
				return;
			}
		}
		if (filters.level) {
			const level = parseInt(row.querySelector(".level .value").textContent);
			if (filters.level.start && level < filters.level.start || filters.level.end !== 100 && level > filters.level.end) {
				hide("level");
				return;
			}
		}
		if (filters.statsEstimates) {
			if (filters.statsEstimates.length) {
				const estimate = row.dataset.estimate?.toLowerCase() ?? "none";
				if ((estimate !== "none" || !row.classList.contains("tt-estimated")) && !filters.statsEstimates.includes(estimate)) {
					hide("stats-estimate");
					return;
				}
			}
		}
		if (filters.ffScoreMax || filters.ffScoreMin) try {
			const gauge = row.querySelector(".tt-ff-scouter-indicator.indicator-lines");
			if (gauge) {
				const ffFloat = parseFloat(gauge.getAttribute("data-ff-scout"));
				if (!Number.isNaN(ffFloat)) {
					if (filters.ffScoreMax && !Number.isNaN(filters.ffScoreMax) && ffFloat > filters.ffScoreMax) {
						hide("ff-score");
						return;
					}
					if (filters.ffScoreMin && !Number.isNaN(filters.ffScoreMin) && ffFloat < filters.ffScoreMin) {
						hide("ff-score");
						return;
					}
				}
			}
		} catch (error) {
			console.error("TT - Failed to filter row by FF Score.", error);
		}
		show();
		function show() {
			row.classList.remove("tt-hidden");
			delete row.dataset.hideReason;
			if (row.nextElementSibling?.classList.contains("tt-stats-estimate")) row.nextElementSibling.classList.remove("tt-hidden");
			if (individual) {
				const content = findContainer("Userlist Filter", { selector: "main" });
				localFilters["Statistics"].updateStatistics(findAllElements(".user-info-list-wrap > li:not(.tt-hidden)").length, findAllElements(".user-info-list-wrap > li").length, content);
			}
		}
		function hide(reason) {
			row.classList.add("tt-hidden");
			row.dataset.hideReason = reason;
			if (row.nextElementSibling?.classList.contains("tt-stats-estimate")) row.nextElementSibling.classList.add("tt-hidden");
			if (individual) {
				const content = findContainer("Userlist Filter", { selector: "main" });
				localFilters["Statistics"].updateStatistics(findAllElements(".user-info-list-wrap > li:not(.tt-hidden)").length, findAllElements(".user-info-list-wrap > li").length, content);
			}
		}
	}
	function removeFilters() {
		removeContainer("Userlist Filter");
		findAllElements(".user-info-list-wrap > li.tt-hidden").forEach((x) => x.classList.remove("tt-hidden"));
	}
	var UserlistFilterFeature = class extends Feature {
		constructor() {
			super("Userlist Filter", "userlist");
		}
		precondition() {
			return getPageStatus().access;
		}
		isEnabled() {
			return settings.pages.userlist.filter;
		}
		initialise() {
			initialiseFilters();
		}
		async execute() {
			await addFilters();
		}
		cleanup() {
			removeFilters();
		}
		storageKeys() {
			return ["settings.pages.userlist.filter"];
		}
	};
	var RequestListenerInjector = class {
		injectListeners;
		id;
		constructor(injectListeners) {
			this.injectListeners = injectListeners;
			this.id = capitalizeText(injectListeners.name);
		}
		inject() {
			if (this.isInjected()) return;
			this.injectListeners();
			this.setInjected();
		}
		isInjected() {
			return document.documentElement.dataset[`tt${this.id}`] === "true";
		}
		setInjected() {
			document.documentElement.dataset[`tt${this.id}`] = "true";
		}
	};
	function injectFetchListeners() {
		const oldFetch = SCRIPT_INJECTOR.getWindow().fetch;
		SCRIPT_INJECTOR.getWindow().fetch = (input, init) => new Promise((resolve, reject) => {
			oldFetch(input, init).then(async (response) => {
				const page = response.url.substring(response.url.indexOf("torn.com/") + 9, response.url.indexOf(".php"));
				let json = {};
				try {
					json = await response.clone().json();
				} catch {}
				let body = null;
				if (init) {
					body = init.body;
					if (body !== null && typeof body === "object" && body?.constructor?.name === "FormData") {
						const newBody = {};
						for (const [key, value] of [...body]) if (isIntNumber(value)) newBody[key] = parseFloat(value);
						else newBody[key] = value;
						body = newBody;
					}
				}
				const url = response.url || input;
				const detail = {
					page,
					json,
					text: await response.clone().text(),
					fetch: {
						url,
						body,
						status: response.status
					}
				};
				window.dispatchEvent(new CustomEvent("tt-fetch", { detail }));
				resolve(response);
			}).catch((error) => {
				reject(error);
			});
		});
	}
	function injectXhrListeners() {
		const oldXHROpen = window.XMLHttpRequest.prototype.open;
		const oldXHRSend = window.XMLHttpRequest.prototype.send;
		window.XMLHttpRequest.prototype.open = function(method, url) {
			let params = this["params"] ?? {};
			if ("xhrOpenAdjustments" in window && typeof window.xhrOpenAdjustments === "object") for (const key in window.xhrOpenAdjustments) {
				if (typeof window.xhrOpenAdjustments[key] !== "function") continue;
				const adjustments = window.xhrOpenAdjustments[key]({ ...this }, method, url);
				method = adjustments.method;
				url = adjustments.url;
				params = {
					...params,
					...adjustments.params || {}
				};
			}
			this["method"] = method;
			this["url"] = url;
			this["params"] = params;
			this.addEventListener("readystatechange", function() {
				if (this.readyState > 3 && this.status === 200) {
					const page = this.responseURL.substring(this.responseURL.indexOf("torn.com/") + 9, this.responseURL.indexOf(".php"));
					let json, uri;
					if (isJsonString(this.response)) json = JSON.parse(this.response);
					else uri = getUrlParams(this.responseURL);
					let text;
					if (this.responseType === "" || this.responseType === "text") text = this.responseText;
					window.dispatchEvent(new CustomEvent("tt-xhr", { detail: {
						page,
						json,
						uri,
						xhr: {
							requestBody: this["requestBody"],
							response: this.response,
							responseType: this.responseType,
							responseText: text,
							responseURL: this.responseURL
						}
					} }));
				}
			});
			arguments[0] = method;
			arguments[1] = url;
			return oldXHROpen.apply(this, arguments);
		};
		window.XMLHttpRequest.prototype.send = function(body) {
			this["params"] = this["params"] ?? {};
			if ("xhrSendAdjustments" in window && typeof window.xhrSendAdjustments === "object") for (const key in window.xhrSendAdjustments) {
				if (typeof window.xhrSendAdjustments[key] !== "function") continue;
				body = window.xhrSendAdjustments[key]({ ...this }, body);
			}
			this["requestBody"] = body;
			arguments[0] = body;
			return oldXHRSend.apply(this, arguments);
		};
	}
	function getUrlParams(url, prop) {
		if (!url) url = location.href;
		const definitions = decodeURIComponent(url.slice(url.indexOf("?") + 1)).split("&");
		const params = {};
		definitions.forEach((val) => {
			const parts = val.split("=", 2);
			params[parts[0]] = parts[1];
		});
		return prop && prop in params ? params[prop] : params;
	}
	function isJsonString(str) {
		if (!str || str === "") return false;
		try {
			JSON.parse(str);
		} catch {
			return false;
		}
		return true;
	}
	var TornToolsStorage = class {
		change(object) {
			return new Promise(async (resolve) => {
				const keys = Object.keys(object);
				for (const key of keys) {
					const data = this.recursive(await this.get(key), object[key]);
					await this.set({ [key]: data });
				}
				resolve();
			});
		}
		recursive(parent, toChange) {
			for (const key in toChange) if (parent && typeof parent === "object" && !Array.isArray(parent[key]) && key in parent && typeof toChange[key] === "object" && !Array.isArray(toChange[key]) && toChange[key] !== null) parent[key] = this.recursive(parent[key], toChange[key]);
			else if (parent && typeof parent === "object") {
				const value = toChange[key];
				parent[key] = Array.isArray(value) ? Array.from(value) : value;
			} else parent = { [key]: toChange[key] };
			return parent;
		}
	};
	var TTScriptStorage = class extends TornToolsStorage {
		prefix;
		constructor(prefix) {
			super();
			this.prefix = prefix;
		}
		storageKey(key) {
			return key === "cache" ? key : `${this.prefix}_${key}`;
		}
		async get(key) {
			if (Array.isArray(key)) return await Promise.all(key.map((k) => this.storageKey(k)).map((k) => GM.getValue(k)));
			else if (key) return await GM.getValue(this.storageKey(key));
			else {
				const storageKeys = Object.keys(DEFAULT_STORAGE);
				const storageValues = await this.get(storageKeys);
				return storageKeys.reduce((total, k, i) => {
					total[k] = storageValues[i];
					return total;
				}, {});
			}
		}
		async set(object) {
			await Promise.all(Object.entries(object).map(([key, value]) => {
				UserscriptRuntimeStorage.callback({ [key]: {
					newValue: value,
					oldValue: null
				} }, "local");
				return GM.setValue(this.storageKey(key), value);
			}));
		}
		remove(_key) {
			throw new Error("Method not implemented.");
		}
		clear() {
			throw new Error("Method not implemented.");
		}
		reset(_key) {
			throw new Error("Method not implemented.");
		}
		getSize() {
			throw new Error("Method not implemented.");
		}
	};
	_css(".tt-hidden{display:none!important}.tt-black-overlay{z-index:100;background-color:#00000059;width:100%;height:100%;position:fixed;top:0;left:0}.no-margin{margin:0}.tt-delimiter{border-top:#ccc;border-left:none;border-right:none;border-top:1px solid var(--sidebar-horizontal-divider-bg-color);border-bottom:#fff;border-bottom:1px solid var(--sidebar-horizontal-divider-shadow-color);height:0;margin-bottom:5px;overflow:hidden}.tt-overlay{z-index:1000000;background-color:#00000059;width:100%;height:100%;position:fixed;top:0;left:0}.tt-overlay-item,.tt-overlay-item-notbroken{z-index:999999999;position:relative}.tt-overlay-item .tt-overlay-ignore{z-index:0;pointer-events:none}.tt-overlay-item .tt-overlay-ignore:before{content:\"\";z-index:1000000;background-color:#00000059;width:100%;height:100%;position:absolute;top:0;left:0}.relative{position:relative}.flex-break{border:0;height:0;margin:0;flex-basis:100%!important}.mt10{margin-top:10px}.mb10{margin-bottom:10px}.t-flex{display:flex}[class*=torn-icon-]{vertical-align:middle;background:url(https://www.torn.com/images/v2/city/location_icons_34x34px.svg) no-repeat;width:34px;height:34px;display:inline-block}.torn-icon-item-market{background-position:-68px -34px}.tt-sidebar-area{margin-top:2px;overflow:hidden}.tt-sidebar-area>div{cursor:pointer;vertical-align:top;background-color:var(--default-bg-panel-color);border-top-right-radius:5px;border-bottom-right-radius:5px;position:relative;overflow:hidden}.tt-sidebar-area a{color:var(--default-content-font-color);justify-content:flex-start;align-items:center;height:100%;text-decoration:none;display:flex;overflow:hidden}.tt-sidebar-area a span{float:none;vertical-align:middle;margin-left:10px;display:inline-block}.tt-button-link{cursor:pointer;color:var(--default-blue-color)}.tt-btn{background-color:var(--tt-color-light-green);color:#000;border-radius:6px;width:fit-content}.tt-btn:not([disabled]){cursor:pointer}.tt-btn[disabled]{cursor:not-allowed;opacity:.4}.tt-msg-box{background:var(--info-msg-grey-gradient);box-shadow:var(--info-msg-box-shadow);color:var(--info-msg-font-color);border-radius:5px;margin-top:10px;font-size:0;line-height:16px}.tt-msg-box .tt-msg-div{background:var(--info-msg-horizontal-gradient);border-radius:5px;justify-content:flex-start;display:flex}.tt-msg-box .tt-msg{vertical-align:middle;background-color:var(--default-bg-panel-active-color);background:var(--info-msg-delimiter-gradient);border-radius:0 5px 5px 0;flex-grow:1;width:1px;height:auto}.tt-msg-box .tt-content{vertical-align:middle;color:var(--info-msg-font-color);background-color:var(--default-bg-panel-active-color);background:var(--info-msg-bg-gradient);border-radius:0 5px 5px 0;padding:10px;font-size:13px;position:relative}.tt-message-box{color:var(--info-msg-font-color);box-shadow:var(--info-msg-box-shadow);border-radius:5px;margin-top:10px;font-size:13px;display:flex}.tt-message-box .tt-message-icon-wrap{background:var(--info-msg-grey-gradient);border-radius:5px 0 0 5px;width:34px}.tt-message-box .tt-message-icon{background:var(--info-msg-horizontal-gradient);border-radius:5px 0 0 5px;justify-content:center;width:34px;height:100%;display:flex}.tt-message-box .tt-svg{width:34px;height:34px}.tt-message-box .tt-message-wrap{background-color:var(--default-bg-panel-active-color);background:var(--info-msg-bg-gradient);border-radius:0 5px 5px 0;flex-grow:1;align-items:center;padding:10px;display:flex}.tt-message-box .tt-message{flex-grow:1}.tt-svg{width:128px;height:128px}.tt-svg .tt-svg-upper{stroke:#000;fill:#000}.tt-svg .tt-svg-lower{stroke:#568725;fill:#568725}#sidebarroot .pill{cursor:pointer;background-color:var(--default-bg-panel-color);min-height:22px;color:var(--default-font-color);border-top-right-radius:5px;border-bottom-right-radius:5px;align-items:center;margin-top:2px;text-decoration:none;display:flex;overflow:hidden}#sidebarroot .pill:not([icon]){box-sizing:border-box;padding-top:5px;padding-bottom:5px}#sidebarroot .pill:not([icon]),#sidebarroot .pill[icon] span{height:100%;color:var(--default-font-color);justify-content:flex-start;align-items:center;padding-left:8px;text-decoration:none;display:flex;overflow:hidden}body.tt-tablet #sidebarroot .pill{min-height:34px}body[data-layout=hospital] #sidebarroot .pill{margin-top:0;margin-bottom:1px}#sidebarroot .pill:hover{background-color:var(--default-bg-panel-active-color)!important}.tt-sidebar-information{flex-direction:column;display:flex}.tt-sidebar-information .title{color:inherit;margin:inherit;font-weight:700;text-decoration:none}.tt-sidebar-information .countdown.short{color:var(--tt-color-red)}.tt-sidebar-information .countdown.medium{color:var(--tt-color-orange)}.tt-top-icons{gap:10px;display:flex}");
	_css(":root{--tt-color-green:#00a500;--tt-color-light-green:#acea00;--tt-color-red:#d83500;--tt-color-green--20:#00a50033;--tt-color-green--30:#00a5004d;--tt-color-green--40:#00a50066;--tt-background-torn-gray:repeating-linear-gradient(90deg, #627e0d, #627e0d 2px, #6e8820 0, #6e8820 4px);--tt-background-green:repeating-linear-gradient(90deg, #627e0d, #627e0d 2px, #6e8820 0, #6e8820 4px);--tt-background-alternative:repeating-linear-gradient(90deg, #242424, #242424 2px, #2e2e2e 0, #2e2e2e 4px)}body:not(.dark-mode){--tt-color-blue:blue;--tt-color-orange:orange;--tt-color-item-text:#678c00;--tt-color-item-quantity:black;--tt-background-popup:#f1f1f1;--tt-shadow-popup:unset}body.dark-mode{--tt-color-blue:#058cff;--tt-color-orange:gold;--tt-color-item-text:#9c0;--tt-color-item-quantity:#ddd;--tt-background-popup:#444;--tt-shadow-popup:0 0 10px black}.tt-color-green{color:var(--tt-color-green)}.tt-color-red{color:var(--tt-color-red)}");
	async function registerUserscriptContext(storagePrefix) {
		setTTStorage(new TTScriptStorage(storagePrefix));
		setFeatureManager(new ScriptFeatureManager());
		setScriptInjector(UserscriptScriptInjector);
		setRuntimeInformation(UserscriptRuntimeInformation);
		setRuntimeStorage(UserscriptRuntimeStorage);
		await migrateDatabase(true);
		initializeDatabaseListener();
		const [localdata, filters, cache] = await ttStorage.get([
			"localdata",
			"filters",
			"cache"
		]);
		setLocaldata(localdata ? localdata : getDefaultStorage(DEFAULT_STORAGE.localdata));
		setFilters(filters ? filters : getDefaultStorage(DEFAULT_STORAGE.filters));
		ttCache.cache = cache ? cache : getDefaultStorage(DEFAULT_STORAGE.cache);
		initializeScriptTheme();
	}
	function initializeScriptTheme() {
		document.documentElement.style.setProperty("--tt-theme-color", "#fff");
		document.documentElement.style.setProperty("--tt-theme-background", "var(--tt-background-green)");
	}
	var ScriptFeatureManager = class {
		createPopup() {}
		isEnabled() {
			return true;
		}
		registerFeature(feature) {
			feature.initialise();
			feature.execute();
		}
	};
	var fetchListenerInjector = new RequestListenerInjector(injectFetchListeners);
	var xhrListenerInjector = new RequestListenerInjector(injectXhrListeners);
	var UserscriptScriptInjector = {
		getWindow() {
			return unsafeWindow;
		},
		injectFetch() {
			fetchListenerInjector.inject();
		},
		injectXHR() {
			xhrListenerInjector.inject();
		}
	};
	var UserscriptRuntimeInformation = {
		getVersion() {
			return GM.info.version;
		},
		isUserscript() {
			return true;
		}
	};
	var UserscriptRuntimeStorage = {
		callback: () => {},
		addChangeListener(callback) {
			this.callback = callback;
		}
	};
	(async () => {
		await registerUserscriptContext("tt_ulf");
		setupUserlistPage();
		const feature = new UserlistFilterFeature();
		FEATURE_MANAGER.registerFeature(feature);
	})();
})();