TORN: TornTools - City Items

List all available items in your city and allow you to collect them with a single click.

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

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

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

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

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

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Advertisement:

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

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

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

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

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

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

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

Advertisement:

// ==UserScript==
// @name             TORN: TornTools - City Items
// @namespace        torntools.city-items
// @version          beta-1.0.4
// @author           DeKleineKobini [2114440] and the TornTools team
// @description      List all available items in your city and allow you to collect them with a single click.
// @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/city.php*
// @connect          torntools.tornplayground.eu
// @grant            GM.getValue
// @grant            GM.info
// @grant            GM.setValue
// @grant            GM.xmlHttpRequest
// @grant            GM_addStyle
// @grant            unsafeWindow
// @run-at           document-start
// @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);
	};
	_css(" ._toast-container_1tz0f_1{z-index:10000;pointer-events:none;flex-direction:column-reverse;gap:12px;display:flex;position:fixed;bottom:50px;right:10px}._toast-container_1tz0f_1 ._toast_1tz0f_1{pointer-events:all;opacity:0;background:#fff;border:1px solid #e5e7eb;border-radius:8px;min-width:320px;max-width:400px;transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;transform:translate(100%);box-shadow:0 4px 12px #00000026}._toast-container_1tz0f_1 ._toast_1tz0f_1._show_1tz0f_24{opacity:1;transform:translate(0)}._toast-container_1tz0f_1 ._toast_1tz0f_1._removing_1tz0f_29{opacity:0;transform:translate(100%)}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34{align-items:flex-start;gap:12px;padding:16px;display:flex}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34 ._toast-icon_1tz0f_40{flex-shrink:0;justify-content:center;align-items:center;width:24px;height:24px;margin-top:2px;display:flex}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34 ._toast-icon_1tz0f_40 svg{font-size:24px;line-height:1}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34 ._toast-message_1tz0f_55{flex:1;min-width:0}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34 ._toast-message_1tz0f_55 ._toast-title_1tz0f_59{color:#111827;margin-bottom:4px;font-size:14px;font-weight:600;line-height:1.4}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34 ._toast-message_1tz0f_55 ._toast-text_1tz0f_67{color:#6b7280;word-wrap:break-word;font-size:13px;line-height:1.4}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-close_1tz0f_76{cursor:pointer;color:#6b7280;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;width:24px;height:24px;padding:4px;transition:all .2s;display:flex;position:absolute;top:8px;right:8px}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-close_1tz0f_76:hover{color:#374151;background:#f3f4f6}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-close_1tz0f_76 svg{font-size:16px}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-progress_1tz0f_103{background:#0000001a;border-radius:0 0 8px 8px;width:100%;height:3px;position:absolute;bottom:0;left:0;overflow:hidden}._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-progress_1tz0f_103:after{content:\"\";background:var(--progress-color,currentColor);width:100%;height:100%;transform:scaleX(var(--progress-scale,1));transform-origin:0;will-change:transform;position:absolute;top:0;left:0}._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=success] ._toast-icon_1tz0f_40 svg{color:#10b981}._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=error] ._toast-icon_1tz0f_40 svg{color:#ef4444}._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=warning] ._toast-icon_1tz0f_40 svg{color:#f59e0b}._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=info] ._toast-icon_1tz0f_40 svg{color:#3b82f6}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1{background:#1f2937;border-color:#374151;box-shadow:0 4px 12px #0000004d}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34 ._toast-message_1tz0f_55 ._toast-title_1tz0f_59{color:#f9fafb}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-content_1tz0f_34 ._toast-message_1tz0f_55 ._toast-text_1tz0f_67{color:#d1d5db}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-close_1tz0f_76{color:#9ca3af}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1 ._toast-close_1tz0f_76:hover{color:#e5e7eb;background:#374151}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=success] ._toast-icon_1tz0f_40 i{color:#34d399}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=error] ._toast-icon_1tz0f_40 i{color:#f87171}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=warning] ._toast-icon_1tz0f_40 i{color:#fbbf24}body.dark-mode ._toast-container_1tz0f_1 ._toast_1tz0f_1[data-toast-type=info] ._toast-icon_1tz0f_40 i{color:#60a5fa}\n/*$vite$:1*/ ");
	var FEATURE_MANAGER;
	var ttStorage;
	var SCRIPT_INJECTOR;
	var RUNTIME_INFORMATION;
	var RUNTIME_STORAGE;
	var OFFLOAD_SERVICE;
	var DATA_FETCHER;
	var ITEM_RESOLVER;
	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;
	}
	function setOffloadService(offloadService) {
		OFFLOAD_SERVICE = offloadService;
	}
	function setDataFetcher(dataFetcher) {
		DATA_FETCHER = dataFetcher;
	}
	function setStaticItemResolver(staticItemResolver) {
		ITEM_RESOLVER = staticItemResolver;
	}
	_css("#map .tt-city-item-overlay.city-item{box-sizing:border-box;cursor:pointer;background:0 0;border:none;z-index:999!important;pointer-events:auto!important;width:38px!important;height:38px!important;margin-top:-19px!important;margin-left:-19px!important;display:none!important}#map.highlight-items .tt-city-item-overlay.city-item,#map .tt-city-item-overlay.city-item.force-hover{display:block!important}#map .tt-city-item-overlay.city-item .tt-city-item-overlay-content{box-sizing:border-box;background:#00000073;border-radius:100%;justify-content:center;align-items:center;width:38px;height:38px;padding:6px;transition:width 50ms cubic-bezier(.65,.05,.36,1),height 50ms cubic-bezier(.65,.05,.36,1),padding 50ms cubic-bezier(.65,.05,.36,1),box-shadow 50ms cubic-bezier(.65,.05,.36,1),background 50ms;display:flex;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #ffffff40,0 0 9px 4px #000}#map .tt-city-item-overlay.city-item img{object-fit:contain;pointer-events:none;width:100%;height:100%}#map .tt-city-item-overlay.city-item:hover,#map .tt-city-item-overlay.city-item.force-hover{z-index:1000!important}#map .tt-city-item-overlay.city-item:hover .tt-city-item-overlay-content,#map .tt-city-item-overlay.city-item.force-hover .tt-city-item-overlay-content{background:#000000b8;width:62px;height:62px;padding:8px;box-shadow:0 0 0 2px #ffffff59,0 0 12px 5px #000}.tt-city-total{margin-bottom:2px;font-size:14px}.tt-city-total .tt-city-total-text{font-weight:700}.tt-city-total .tt-city-total-value{color:var(--tt-color-item-text)}.tt-city-items{letter-spacing:.2px;line-height:14px}.tt-city-items p>span:nth-of-type(odd){color:#aaa}.tt-city-items .list-item{cursor:pointer}.tt-city-controls{border-bottom:1px solid var(--default-panel-divider-outer-side-color);grid-template-columns:repeat(3,minmax(0,1fr));align-items:center;width:100%;margin-bottom:4px;padding:6px 0;display:grid}.tt-city-group-filter,.tt-city-period-filter,.tt-city-search-filter{justify-content:center;align-items:center;gap:6px;min-width:0;padding:0 10px;display:flex}.tt-city-controls>*+*{border-left:1px solid var(--default-panel-divider-inner-side-color)}.tt-city-control-label{white-space:nowrap}.tt-city-group-filter .tt-checkbox-wrapper{display:inline-flex}.tt-city-period-group{margin-top:6px}.tt-city-period-header{flex-wrap:wrap;align-items:baseline;gap:4px;margin-bottom:2px;font-weight:700;display:flex}.tt-city-period-count{color:#aaa;font-weight:400}.tt-city-period-value{color:var(--tt-color-item-text);margin-left:auto;font-weight:400}.tt-city-group-pagination{border-top:1px solid var(--default-panel-divider-inner-side-color);color:var(--default-color);flex-wrap:wrap;justify-content:center;align-items:center;gap:8px;margin-top:6px;padding-top:6px;display:flex}.tt-city-group-pagination-button{font:inherit;background:0 0;border:none;padding:0}.tt-city-controls select,.tt-city-search-filter input{max-width:100%}.tt-city-search-filter input{width:180px;min-width:90px}body.tt-mobile .tt-city-controls>*,body.tt-tablet .tt-city-controls>*{flex-direction:column;align-items:stretch;gap:4px;padding:0 6px}body.tt-mobile .tt-city-group-filter,body.tt-tablet .tt-city-group-filter{grid-template-columns:auto 1fr;align-items:center;display:grid}body.tt-mobile .tt-city-group-filter .tt-city-control-label,body.tt-tablet .tt-city-group-filter .tt-city-control-label{grid-column:1/-1}body.tt-mobile .tt-city-controls select,body.tt-tablet .tt-city-controls select,body.tt-mobile .tt-city-search-filter input,body.tt-tablet .tt-city-search-filter input{width:100%;min-width:0}");
	function isMapData(page, xhr, _json) {
		return page === "city" && new URLSearchParams(xhr.responseURL).get("step") === "mapData";
	}
	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"),
				owner: new DefaultSetting("number")
			},
			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),
					memberRevives: 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),
					groupByPeriod: new DefaultSetting("boolean", false),
					groupByPeriodUnit: new DefaultSetting("string", "day")
				},
				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),
					propertiesSell: new DefaultSetting("boolean", false)
				},
				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),
				playgroundTorntools: new DefaultSetting("boolean", false)
			},
			reporting: {}
		},
		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"),
					collectionReady: 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;
	}
	_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 checkListener(listener, entry) {
		const element = listener.parent.querySelector(listener.selector);
		if (!(listener.invert ? !element : !!element)) return false;
		if (listener.timeoutId) clearTimeout(listener.timeoutId);
		entry.listeners.delete(listener);
		listener.resolve(listener.invert ? true : element);
		cleanupEntryIfEmpty(entry);
		return true;
	}
	function cleanupEntryIfEmpty(entry) {
		if (entry.listeners.size > 0) return;
		entry.observer.disconnect();
		observerRegistry.delete(entry.parent);
	}
	function removeListenerFromRegistry(listener) {
		const entry = observerRegistry.get(listener.parent);
		if (!entry) return;
		entry.listeners.delete(listener);
		cleanupEntryIfEmpty(entry);
	}
	function requireElement(selector, attributes = {}) {
		const options = {
			invert: false,
			parent: document,
			timeout: TO_MILLIS.SECONDS * 5,
			observerOptions: {
				childList: true,
				subtree: true
			},
			...attributes
		};
		const error = new Error("Maximum cycles reached.");
		return new Promise((resolve, reject) => {
			const element = options.parent.querySelector(selector);
			if (options.invert && !element) {
				resolve(true);
				return;
			} else if (!options.invert && element) {
				resolve(element);
				return;
			}
			const timeoutId = options.timeout > 0 ? window.setTimeout(() => {
				removeListenerFromRegistry(listener);
				reject(error);
			}, options.timeout) : null;
			const listener = {
				selector,
				invert: options.invert,
				parent: options.parent,
				resolve,
				reject,
				timeoutId
			};
			getOrCreateObserverEntry(options.parent).listeners.add(listener);
		});
	}
	var observerRegistry = new Map();
	function getOrCreateObserverEntry(parent) {
		const existing = observerRegistry.get(parent);
		if (existing) return existing;
		const observer = new MutationObserver(() => {
			const entry = observerRegistry.get(parent);
			if (!entry) return;
			entry.listeners.forEach((listener) => checkListener(listener, entry));
		});
		const entry = {
			parent,
			observer,
			listeners: new Set()
		};
		observerRegistry.set(parent, entry);
		observer.observe(parent, {
			childList: true,
			subtree: true
		});
		return entry;
	}
	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);
	var PHX = 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);
	var PHBoldCheckCircle = svgImport(check_circle_bold_default);
	svgImport(copy_bold_default);
	var PHBoldInfo = svgImport(info_bold_default);
	var PHBoldWarningCircle = svgImport(warning_circle_bold_default);
	var PHBoldXCircle = 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);
	svgImport(funnel_fill_default);
	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 MONTHS = [
		"January",
		"February",
		"March",
		"April",
		"May",
		"June",
		"July",
		"August",
		"September",
		"October",
		"November",
		"December"
	];
	var SCRIPT_TYPE = (() => {
		if (typeof window === "undefined" || window.location.href.endsWith("/_generated_background_page.html")) return "BACKGROUND";
		else if (typeof browser === "object" && browser.action) return "POPUP";
		else if (typeof location !== "undefined" && location.protocol?.includes("extension")) return "INTERNAL_CONTENT";
		else return "CONTENT";
	})();
	var TO_MILLIS = {
		SECONDS: 1e3,
		MINUTES: 1e3 * 60,
		HOURS: 1e3 * 60 * 60,
		DAYS: 1e3 * 60 * 60 * 24
	};
	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 getCookie(cname) {
		const name = `${cname}=`;
		for (let cookie of decodeURIComponent(document.cookie).split(";")) {
			cookie = cookie.trimStart();
			if (cookie.includes(name)) return cookie.substring(name.length);
		}
		return "";
	}
	function toNumericVersion(version) {
		return parseInt(version.split(".").map((part) => part.padStart(3, "0")).join("").padEnd(9, "9"));
	}
	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;
			}
		},
		{
			id: "16d7de5c-e9ad-4060-966e-49b4252301c5",
			version: "9.0.7",
			execute(_database, _flags, _oldStorage) {
				OFFLOAD_SERVICE.reinitializeTimers().catch(() => {});
			}
		},
		{
			id: "a1b8db49-f255-43fc-b3b8-dc82b8c072b1",
			version: "9.0.9",
			execute(database, _flags, oldStorage) {
				const owner = oldStorage.userdata?.profile?.id;
				if (!owner) return;
				database.api.torn.owner = owner;
			}
		}
	];
	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 storageListeners = {
		settings: [],
		filters: [],
		version: [],
		userdata: [],
		torndata: [],
		attackHistory: [],
		stakeouts: [],
		factionStakeouts: [],
		notes: [],
		factiondata: [],
		localdata: [],
		cache: [],
		api: [],
		npcs: [],
		stockdata: [],
		notificationHistory: [],
		notifications: [],
		quick: [],
		migrations: []
	};
	var databaseLoaded = false;
	var databaseLoadPromise = null;
	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
		};
		if (databaseLoadPromise) return await databaseLoadPromise;
		databaseLoadPromise = (async () => {
			const database = await ttStorage.get();
			populateDatabaseVariables(database);
			console.log("TT - Database loaded.", database);
			return database;
		})();
		try {
			const result = await databaseLoadPromise;
			databaseLoaded = true;
			databaseLoadPromise = null;
			return result;
		} catch (error) {
			databaseLoadPromise = null;
			throw error;
		}
	}
	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;
	}
	var initializedDatabaseListeners = false;
	function initializeDatabaseListener() {
		if (initializedDatabaseListeners) return;
		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));
			}
		});
		initializedDatabaseListeners = true;
	}
	function setLocaldata(data) {
		localdata = data;
	}
	function setFilters(data) {
		filters = data;
	}
	_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-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
		};
	}
	var alerts_module_default = {
		"toast-container": "_toast-container_1tz0f_1",
		toastContainer: "_toast-container_1tz0f_1",
		toast: "_toast_1tz0f_1",
		show: "_show_1tz0f_24",
		removing: "_removing_1tz0f_29",
		"toast-content": "_toast-content_1tz0f_34",
		toastContent: "_toast-content_1tz0f_34",
		"toast-icon": "_toast-icon_1tz0f_40",
		toastIcon: "_toast-icon_1tz0f_40",
		"toast-message": "_toast-message_1tz0f_55",
		toastMessage: "_toast-message_1tz0f_55",
		"toast-title": "_toast-title_1tz0f_59",
		toastTitle: "_toast-title_1tz0f_59",
		"toast-text": "_toast-text_1tz0f_67",
		toastText: "_toast-text_1tz0f_67",
		"toast-close": "_toast-close_1tz0f_76",
		toastClose: "_toast-close_1tz0f_76",
		"toast-progress": "_toast-progress_1tz0f_103",
		toastProgress: "_toast-progress_1tz0f_103"
	};
	function displayAlert(options) {
		const container = createToastContainer();
		const duration = options.duration ?? 5e3;
		const toast = elementBuilder({
			type: "div",
			class: [alerts_module_default.toast, alerts_module_default.show],
			children: [
				elementBuilder({
					type: "div",
					class: alerts_module_default.toastContent,
					children: [elementBuilder({
						type: "div",
						class: alerts_module_default.toastIcon,
						children: [getIconForType(options.type)]
					}), elementBuilder({
						type: "div",
						class: alerts_module_default.toastMessage,
						children: [elementBuilder({
							type: "div",
							class: alerts_module_default.toastTitle,
							text: options.title
						}), ...options.text ? [elementBuilder({
							type: "div",
							class: alerts_module_default.toastText,
							text: options.text
						})] : []]
					})]
				}),
				elementBuilder({
					type: "button",
					class: alerts_module_default.toastClose,
					attributes: { "aria-label": "Close toast" },
					children: [PHX()],
					events: { click: () => removeToast(toast) }
				}),
				elementBuilder({
					type: "div",
					class: alerts_module_default.toastProgress
				})
			],
			dataset: { toastType: options.type }
		});
		container.appendChild(toast);
		setupProgressBar(toast, duration);
	}
	function setupProgressBar(toast, duration) {
		const progressElement = toast.querySelector(`.${alerts_module_default.toastProgress}`);
		if (!progressElement || duration <= 0) return;
		const iconElement = toast.querySelector(`.${alerts_module_default.toastIcon} i`);
		if (iconElement) {
			const computedColor = getComputedStyle(iconElement).color;
			progressElement.style.setProperty("--progress-color", computedColor);
		}
		const startTime = Date.now();
		let isPaused = false;
		let animationId;
		let timeoutId;
		let totalPausedDuration = 0;
		let pausedTime = 0;
		const animateProgress = () => {
			if (isPaused) return;
			const elapsed = Date.now() - startTime - totalPausedDuration;
			const progress = Math.max(0, 1 - elapsed / duration);
			progressElement.style.setProperty("--progress-scale", progress.toString());
			if (progress > 0) animationId = requestAnimationFrame(animateProgress);
		};
		toast.addEventListener("mouseenter", () => {
			if (isPaused) return;
			isPaused = true;
			pausedTime = Date.now();
			cancelAnimationFrame(animationId);
			if (timeoutId) clearTimeout(timeoutId);
		});
		toast.addEventListener("mouseleave", () => {
			if (!isPaused) return;
			isPaused = false;
			const pauseDuration = Date.now() - pausedTime;
			totalPausedDuration += pauseDuration;
			const remainingTime = Math.max(0, duration - (Date.now() - startTime - totalPausedDuration));
			animateProgress();
			timeoutId = setTimeout(() => removeToast(toast), remainingTime);
		});
		animateProgress();
		timeoutId = setTimeout(() => removeToast(toast), duration);
	}
	function getIconForType(type) {
		switch (type) {
			case "success": return PHBoldCheckCircle();
			case "error": return PHBoldXCircle();
			case "warning": return PHBoldWarningCircle();
			default: return PHBoldInfo();
		}
	}
	function createToastContainer() {
		let container = document.querySelector(`.${alerts_module_default.toastContainer}`);
		if (!container) {
			container = elementBuilder({
				type: "div",
				class: alerts_module_default.toastContainer
			});
			document.body.appendChild(container);
		}
		return container;
	}
	function removeToast(toast) {
		toast.classList.add(alerts_module_default.removing);
		setTimeout(() => toast.remove(), 300);
	}
	var BADGE_TYPES = {
		default: {
			text: "",
			color: null
		},
		error: {
			text: "error",
			color: "#FF0000"
		},
		count: {
			text: async (options) => {
				if (options.events && options.messages) return `${options.events}/${options.messages}`;
				else if (options.events) return options.events.toString();
				else if (options.messages) return options.messages.toString();
				else return await getBadgeText() === "error" ? "error" : null;
			},
			color: async (options) => {
				if (options.events && options.messages) return "#1ed2ac";
				else if (options.events) return "#009eda";
				else if (options.messages) return "#84af03";
				else return await getBadgeText() === "error" ? "error" : null;
			}
		}
	};
	async function setBadge(type, partialOptions = {}) {
		if (SCRIPT_TYPE !== "BACKGROUND") return false;
		const options = {
			events: 0,
			messages: 0,
			...partialOptions
		};
		const badge = { ...BADGE_TYPES[type] };
		if (typeof badge.text === "function") badge.text = await badge.text(options);
		if (typeof badge.color === "function") badge.color = await badge.color(options);
		if (!badge.text) badge.text = "";
		browser.action.setBadgeText({ text: badge.text || "" });
		if (badge.color) browser.action.setBadgeBackgroundColor({ color: badge.color });
		return true;
	}
	function getBadgeText() {
		if (SCRIPT_TYPE !== "BACKGROUND") return Promise.resolve(null);
		return browser.action.getBadgeText({});
	}
	var REGEXES = {
		convertToNumber: /-?[\d,]+(\.\d+)?/,
		formatNumber: /\B(?=(\d{3})+(?!\d))/g
	};
	function camelCase(text, lowerCamelCase = true) {
		return (text.trim().charAt(0)[lowerCamelCase ? "toLowerCase" : "toUpperCase"]() + text.slice(1)).trim().replaceAll(" ", "");
	}
	function toMultipleDigits(number, digits = 2) {
		if (number === void 0) return void 0;
		return number.toString().length < digits ? toMultipleDigits(`0${number}`, digits) : number.toString();
	}
	function formatDate(date, partialOptions = {}) {
		if (typeof date === "number") return formatDate({ milliseconds: date }, partialOptions);
		else if (typeof date === "string") return formatDate({ milliseconds: new Date(date).getTime() }, partialOptions);
		else if (date instanceof Date) return formatDate({ milliseconds: date.getTime() }, partialOptions);
		const options = {
			showYear: false,
			...partialOptions
		};
		let millis;
		if ("milliseconds" in date) millis = date.milliseconds;
		else if ("seconds" in date) millis = date.seconds * 1e3;
		const _date = new Date(millis);
		let day, month, year;
		if (settings.formatting.tct) {
			day = _date.getUTCDate();
			month = _date.getUTCMonth() + 1;
			year = _date.getUTCFullYear();
		} else {
			day = _date.getDate();
			month = _date.getMonth() + 1;
			year = _date.getFullYear();
		}
		const parts = [];
		let separator;
		switch (settings.formatting.date) {
			case "us":
				separator = "/";
				parts.push(month, day);
				if (options.showYear) parts.push(year);
				break;
			case "iso":
				separator = "-";
				if (options.showYear) parts.push(year);
				parts.push(month, day);
				break;
			case "eu":
				separator = ".";
				parts.push(day, month);
				if (options.showYear) parts.push(year);
				break;
		}
		return parts.map((p) => toMultipleDigits(p)).join(separator);
	}
	function formatNumber(number, partialOptions = {}) {
		const options = {
			shorten: false,
			formatter: void 0,
			decimals: 0,
			currency: false,
			forceOperation: false,
			roman: false,
			...partialOptions
		};
		if (typeof number !== "number") if (Number.isNaN(parseInt(number))) return number;
		else number = parseFloat(number);
		if (number === Number.POSITIVE_INFINITY) return "∞";
		if (options.decimals !== void 0) number = parseFloat(number.toFixed(options.decimals));
		if (options.formatter) return options.formatter.format(number);
		if (options.roman) {
			if (number === 0) return "";
			else if (number < 0) throw "Roman numbers can only be positive!";
			const ROMAN = [
				[1e3, "M"],
				[900, "CM"],
				[500, "D"],
				[400, "CD"],
				[100, "C"],
				[90, "XC"],
				[50, "L"],
				[40, "XL"],
				[10, "X"],
				[9, "IX"],
				[5, "V"],
				[4, "IV"],
				[1, "I"]
			];
			return toRoman(number);
			function toRoman(number) {
				if (number === 0) return "";
				for (const [value, character] of ROMAN) {
					if (number < value) continue;
					return character + toRoman(number - value);
				}
				return "N/A";
			}
		}
		const abstract = Math.abs(number);
		const operation = number < 0 ? "-" : options.forceOperation ? "+" : "";
		let text;
		if (options.shorten) {
			const version = options.shorten === true ? 1 : options.shorten;
			const decimals = options.decimals !== -1 ? options.decimals : 3;
			const words = (() => {
				switch (version) {
					case 1: return {
						thousand: "k",
						million: "mil",
						billion: "bill"
					};
					case 2:
					case 3: return {
						thousand: "k",
						million: "m",
						billion: "b"
					};
				}
			})();
			if (version === 1 || version === 2) {
				if (abstract >= 1e9) if (abstract % 1e9 === 0) text = (abstract / 1e9).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + words.billion;
				else text = (abstract / 1e9).toFixed(3) + words.billion;
				else if (abstract >= 1e6) if (abstract % 1e6 === 0) text = abstract / 1e6 + words.million;
				else text = (abstract / 1e6).toFixed(3) + words.million;
				else if (abstract >= 1e3) {
					if (abstract % 1e3 === 0) text = abstract / 1e3 + words.thousand;
				}
			} else if (abstract >= 1e9) if (abstract % 1e9 === 0) text = abstract / 1e9 + words.billion;
			else text = parseFloat((abstract / 1e9).toFixed(decimals)) + words.billion;
			else if (abstract >= 1e6) if (abstract % 1e6 === 0) text = abstract / 1e6 + words.million;
			else text = parseFloat((abstract / 1e6).toFixed(decimals)) + words.million;
			else if (abstract >= 1e3) {
				if (abstract % 1e3 === 0) text = abstract / 1e3 + words.thousand;
				else if (abstract % 100 === 0) text = abstract / 1e3 + words.thousand;
			}
		}
		if (!text) text = abstract.toString().replace(REGEXES.formatNumber, ",");
		return `${operation}${options.currency ? "$" : ""}${text}`;
	}
	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();
	}
	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);
	function getRFC() {
		const rfc = getCookie("rfc_v");
		if (!rfc) for (const cookie of document.cookie.split("; ")) {
			const parts = cookie.split("=");
			if (parts[0] === "rfc_v") return parts[1];
		}
		return rfc;
	}
	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 };
	}
	function millisToNewDay() {
		const now = Date.now();
		const newDate = new Date();
		newDate.setUTCHours(0, 0, 0);
		newDate.setUTCDate(newDate.getUTCDate() + 1);
		return newDate.getTime() - now;
	}
	var CUSTOM_API_ERROR = {
		NO_NETWORK: "tt-no_network",
		NO_PERMISSION: "tt-no_permission",
		CANCELLED: "tt-cancelled"
	};
	var FETCH_PLATFORMS = {
		tornv2: "https://api.torn.com/v2/",
		torn_direct: "https://www.torn.com/",
		yata: "https://yata.yt/",
		tornstats: "https://www.tornstats.com/",
		torntools: "https://torntools.gregork.com/",
		nukefamily: "https://nuke.family/",
		uhc: "https://tornuhc.eu/",
		stig: "https://api.no1irishstig.co.uk/",
		prometheus: "https://prombot.co.uk:8443/",
		lzpt: "https://api.lzpt.io/",
		wtf: "https://what-the-f.de/",
		tornw3b: "https://weav3r.dev/",
		ffscouter: "https://ffscouter.com/",
		laekna: "https://laekna-revive-bot.onrender.com/",
		tornintel: "https://torn-intel.com/",
		playground_torntools: "https://torntools.tornplayground.eu/"
	};
	var TORN_API_PLATFORMS = ["tornv2"];
	var TEXT_RESPONSE_PLATFORMS = ["torn_direct", "laekna"];
	async function fetchData(location, partialOptions = {}) {
		const options = mergeOptions(partialOptions);
		if (options.relay && SCRIPT_TYPE !== "BACKGROUND" && !RUNTIME_INFORMATION.isUserscript()) return relayToBackground(location, options);
		const request = buildFetchRequest(location, options);
		let result;
		try {
			result = parseFetchResponse(await DATA_FETCHER.fetch(request.url, {
				method: request.method,
				...request.method === "POST" ? { body: request.body } : {},
				headers: request.headers,
				timeout: decideTimeoutTimer(location)
			}), location);
		} catch (error) {
			return await handleError(location, options, error);
		}
		if (!result.success) return await handleError(location, options, result);
		else if (isApiErrorResponse(result.data)) return await handleError(location, options, result.data);
		await handleTornApiState(location, options);
		return result.data;
	}
	function mergeOptions(partial) {
		return {
			section: void 0,
			id: void 0,
			selections: [],
			legacySelections: [],
			key: void 0,
			action: void 0,
			method: "GET",
			body: void 0,
			silent: false,
			includeKey: false,
			relay: false,
			params: {},
			...partial
		};
	}
	async function relayToBackground(location, options) {
		return OFFLOAD_SERVICE.fetchRelay(location, {
			...options,
			relay: false
		});
	}
	function decideTimeoutTimer(location) {
		switch (location) {
			case "yata": return 30 * TO_MILLIS.SECONDS;
			default: return 10 * TO_MILLIS.SECONDS;
		}
	}
	function buildFetchRequest(location, options) {
		const url = buildUrl(location, options);
		const headers = buildHeaders(location, options);
		if (options.method === "POST") return {
			url,
			method: options.method,
			body: buildBody(options),
			headers
		};
		else return {
			url,
			method: options.method,
			headers
		};
	}
	function buildUrl(location, options) {
		let path, pathSections, key;
		const params = new URLSearchParams();
		switch (location) {
			case "tornv2":
				path = `${options.section}/${options.id || ""}`;
				params.append("selections", [...options.selections, ...options.legacySelections].join(","));
				params.append("legacy", options.legacySelections.join(","));
				if (settings.apiUsage.comment) params.append("comment", settings.apiUsage.comment);
				break;
			case "torn_direct":
				path = options.action;
				params.set("rfcv", getRFC());
				break;
			case "tornstats":
				pathSections = [
					"api",
					"v2",
					options.key || api.tornstats.key || api.torn.key
				];
				if (options.section) pathSections.push(options.section);
				if (options.id) pathSections.push(options.id);
				path = pathSections.join("/");
				break;
			case "yata":
				pathSections = [
					"api",
					"v1",
					options.section
				];
				if (options.id) pathSections.push(options.id, "");
				if (options.includeKey) key = api.yata.key;
				path = pathSections.join("/");
				break;
			case "prometheus":
				path = ["api", options.section].join("/");
				break;
			case "tornw3b":
				path = ["api", options.section].join("/");
				break;
			case "ffscouter":
				path = [
					"api",
					"v1",
					options.section
				].join("/");
				key = api.ffScouter.key;
				break;
			case "tornintel":
				path = ["api", options.section].join("/");
				break;
			case "playground_torntools":
				path = ["api", options.section].join("/");
				break;
			default:
				path = options.section;
				break;
		}
		if (options.includeKey) params.append("key", options.key || key || api.torn.key);
		if (options.params) for (const [key, value] of Object.entries(options.params)) params.append(key, value.toString());
		return `${FETCH_PLATFORMS[location]}${path}${params.toString() ? `?${params}` : ""}`;
	}
	function buildHeaders(location, options) {
		const headers = {};
		if (location === "tornv2") headers["Authorization"] = `ApiKey ${options.key || api.torn.key}`;
		if (options.method === "POST") {
			if (!(options.body instanceof URLSearchParams)) headers["content-type"] = "application/json";
			if (location === "torn_direct") headers["x-requested-with"] = "XMLHttpRequest";
		}
		return headers;
	}
	function buildBody(options) {
		if (options.method !== "POST") return null;
		return options.body instanceof URLSearchParams ? options.body : JSON.stringify(options.body);
	}
	function parseFetchResponse(response, location) {
		try {
			return {
				data: JSON.parse(response.text),
				success: true
			};
		} catch {
			if (TEXT_RESPONSE_PLATFORMS.includes(location)) return {
				data: response.text,
				success: true
			};
			if (response.ok) return { success: true };
			return {
				success: false,
				error: new HTTPException(response.status)
			};
		}
	}
	async function handleError(location, options, result) {
		if (result instanceof DOMException) return handleTimeoutError(location, options);
		if (result.constructor.name === "TypeError") return handleNetworkError(location, options, result.message);
		return handleApiError(location, options, result);
	}
	async function handleTimeoutError(location, options) {
		const error = "Request cancelled because it took too long.";
		await handleTornApiState(location, options, error);
		throw {
			error,
			isLocal: false,
			code: CUSTOM_API_ERROR.CANCELLED
		};
	}
	async function handleTornApiState(location, options, error, online = false) {
		if (!TORN_API_PLATFORMS.includes(location) || options.silent || SCRIPT_TYPE !== "BACKGROUND") return;
		if (error) {
			await ttStorage.change({ api: { torn: {
				online,
				error
			} } });
			await setBadge("error");
		} else {
			await getBadgeText().then((value) => {
				if (value === "error") return setBadge("default");
			}).catch(() => console.error("TT - Couldn't get the badge text."));
			await ttStorage.change({ api: { torn: {
				online: true,
				error: ""
			} } });
		}
	}
	async function handleNetworkError(location, options, message) {
		let error = message;
		let isLocal = false;
		let code;
		if (error === "Failed to fetch") {
			isLocal = true;
			if (!RUNTIME_INFORMATION.isUserscript() && SCRIPT_TYPE === "BACKGROUND" && !await hasOrigins(FETCH_PLATFORMS[location])) {
				error = "Permission issues";
				code = CUSTOM_API_ERROR.NO_PERMISSION;
			} else {
				error = "Network issues";
				code = CUSTOM_API_ERROR.NO_NETWORK;
			}
		}
		await handleTornApiState(location, options, error);
		throw {
			error,
			isLocal,
			code
		};
	}
	async function hasOrigins(...origins) {
		return browser.permissions.contains({ origins });
	}
	async function handleApiError(location, options, result) {
		if (TORN_API_PLATFORMS.includes(location)) {
			let error, online;
			if (result.error instanceof HTTPException) {
				error = result.error.toString();
				online = false;
			} else {
				error = result.error.error;
				online = result.error.code !== 9 && !(result instanceof HTTPException);
			}
			await handleTornApiState(location, options, error, online);
			throw result.error instanceof HTTPException ? result.error.asObject() : result.error;
		}
		throw { error: result.error };
	}
	function isApiErrorResponse(data) {
		return !!data && typeof data === "object" && "error" in data;
	}
	var HTTPException = class HTTPException {
		code;
		constructor(code) {
			this.code = code;
		}
		get message() {
			return this.code in HTTPException.codes ? HTTPException.codes[this.code] : `Unknown code (${this.code})`;
		}
		asObject() {
			return {
				code: this.code,
				message: this.message,
				http: true
			};
		}
		toString() {
			return `HTTP ${this.code}: ${this.message}`;
		}
		static get codes() {
			return {
				200: "OK",
				201: "Created",
				202: "Accepted",
				203: "Non-Authoritative Information",
				204: "No Content",
				205: "Reset Content",
				206: "Partial Content",
				300: "Multiple Choices",
				301: "Moved Permanently",
				302: "Found",
				303: "See Other",
				304: "Not Modified",
				305: "Use Proxy",
				306: "Unused",
				307: "Temporary Redirect",
				400: "Bad Request",
				401: "Unauthorized",
				402: "Payment Required",
				403: "Forbidden",
				404: "Not Found",
				405: "Method Not Allowed",
				406: "Not Acceptable",
				407: "Proxy Authentication Required",
				408: "Request Timeout",
				409: "Conflict",
				410: "Gone",
				411: "Length Required",
				412: "Precondition Required",
				413: "Request Entry Too Large",
				414: "Request-URI Too Long",
				415: "Unsupported Media Type",
				416: "Requested Range Not Satisfiable",
				417: "Expectation Failed",
				418: "I'm a teapot",
				429: "Too Many Requests",
				500: "Internal Server Error",
				501: "Not Implemented",
				502: "Bad Gateway",
				503: "Service Unavailable",
				504: "Gateway Timeout",
				505: "HTTP Version Not Supported"
			};
		}
	};
	_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 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();
	}
	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";
		EVENT_CHANNELS["PROPERTIES__ROUTE"] = "PROPERTIES__ROUTE";
		EVENT_CHANNELS["PROPERTIES__ROUTE_PAGE"] = "PROPERTIES__ROUTE_PAGE";
		return EVENT_CHANNELS;
	}({});
	(() => {
		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);
	}
	var ExecutionTiming = function(ExecutionTiming) {
		ExecutionTiming["IMMEDIATELY"] = "IMMEDIATELY";
		ExecutionTiming["DOM_INTERACTIVE"] = "DOM_INTERACTIVE";
		ExecutionTiming["CONTENT_LOADED"] = "CONTENT_LOADED";
		return ExecutionTiming;
	}({});
	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;
		}
	};
	var CITY_ITEMS_MAP_EVENTS = {
		SET_ITEMS: "tt-city-items:set-items",
		REQUEST_MODEL_ITEMS: "tt-city-items:request-model-items",
		MODEL_ITEMS: "tt-city-items:model-items",
		CLEAR: "tt-city-items:clear"
	};
	var BASE_HIGHLIGHT_SIZE = 38;
	var SYNC_ATTEMPT_INTERVAL = 250;
	var SYNC_ATTEMPT_LIMIT = 80;
	function injectCityItemsMapListeners(pageWindow = window) {
		if (pageWindow.__ttCityItemsMap?.injected) return;
		const state = {
			injected: true,
			entries: [],
			overlays: new Map()
		};
		pageWindow.__ttCityItemsMap = state;
		pageWindow.addEventListener(CITY_ITEMS_MAP_EVENTS.SET_ITEMS, handleSetItemsEvent);
		pageWindow.addEventListener(CITY_ITEMS_MAP_EVENTS.REQUEST_MODEL_ITEMS, () => {
			const items = getModelItems();
			dispatchPageEvent(CITY_ITEMS_MAP_EVENTS.MODEL_ITEMS, { items });
		});
		pageWindow.addEventListener(CITY_ITEMS_MAP_EVENTS.CLEAR, clearOverlays);
		function handleSetItemsEvent(event) {
			const detail = parseEventDetail$1(event);
			if (!detail) return;
			state.entries = Array.isArray(detail.entries) ? detail.entries.filter(isCityItemsMapEntry) : [];
			scheduleSync();
		}
		function scheduleSync() {
			let attempts = 0;
			syncOverlays();
			if (state.syncTimer) return;
			state.syncTimer = pageWindow.setInterval(() => {
				attempts++;
				if (syncOverlays() || attempts >= SYNC_ATTEMPT_LIMIT || !state.entries.length) {
					if (state.syncTimer) pageWindow.clearInterval(state.syncTimer);
					state.syncTimer = void 0;
				}
			}, SYNC_ATTEMPT_INTERVAL);
		}
		function syncOverlays() {
			const map = getMap();
			const leaflet = pageWindow.L;
			if (!map || !isLeafletOverlayRuntime(leaflet)) return false;
			const activeEntryIds = new Set(state.entries.map((entry) => entry.entryId));
			for (const [entryId, record] of state.overlays) if (!activeEntryIds.has(entryId)) {
				removeOverlay(record);
				state.overlays.delete(entryId);
			}
			for (const entry of state.entries) {
				let record = state.overlays.get(entry.entryId);
				const latLng = getLatLngForEntry(entry);
				if (!latLng) continue;
				if (!record) {
					record = {
						entry,
						marker: null,
						latLng
					};
					state.overlays.set(entry.entryId, record);
				} else {
					record.entry = entry;
					record.latLng = latLng;
				}
				ensureOverlay(record, map, leaflet);
			}
			return state.entries.every((entry) => !!state.overlays.get(entry.entryId)?.marker);
		}
		function ensureOverlay(record, map, leaflet) {
			const latLng = record.latLng;
			if (!latLng) return;
			try {
				if (record.marker?._map && record.marker._map !== map) removeOverlay(record);
				if (record.marker) {
					record.marker.setLatLng?.(latLng);
					updateOverlayElement(record);
					return;
				}
				const icon = leaflet.divIcon({
					className: "tt-city-item-overlay city-item",
					html: `<span class="tt-city-item-overlay-content"><img src="${getItemImageUrl(record.entry.itemId)}" alt=""></span>`,
					iconSize: [BASE_HIGHLIGHT_SIZE, BASE_HIGHLIGHT_SIZE],
					iconAnchor: [BASE_HIGHLIGHT_SIZE / 2, BASE_HIGHLIGHT_SIZE / 2]
				});
				const marker = leaflet.marker(latLng, {
					icon,
					interactive: true,
					keyboard: false,
					zIndexOffset: 1e3
				});
				if (typeof marker.addTo !== "function") return;
				marker.addTo(map);
				record.marker = marker;
				updateOverlayElement(record);
			} catch {
				record.marker = null;
			}
		}
		function updateOverlayElement(record) {
			const element = record.marker?.getElement?.();
			if (!element) return;
			element.classList.add("tt-city-item-overlay", "city-item");
			element.dataset.id = record.entry.itemId.toString();
			element.dataset.itemId = record.entry.itemId.toString();
			element.dataset.entryId = record.entry.entryId;
			element.dataset.td = record.entry.td;
			element.removeAttribute("title");
		}
		function clearOverlays() {
			state.entries = [];
			if (state.syncTimer) {
				pageWindow.clearInterval(state.syncTimer);
				state.syncTimer = void 0;
			}
			for (const record of state.overlays.values()) removeOverlay(record);
			state.overlays.clear();
		}
		function removeOverlay(record) {
			if (!record.marker) return;
			try {
				if (record.marker.remove) record.marker.remove();
				else record.marker.removeFrom?.(getMap());
			} catch {
				try {
					record.marker._map?.removeLayer?.(record.marker);
				} catch {}
			}
			record.marker = null;
		}
		function getMap() {
			const mapElement = pageWindow.document.querySelector("#map");
			const map = getTornRuntime()?.map?.lmap ?? mapElement?._leaflet_map;
			return isLeafletMap(map) ? map : null;
		}
		function getLatLngForEntry(entry) {
			if (!Number.isFinite(entry.x) || !Number.isFinite(entry.y)) return null;
			const tornMap = getTornRuntime()?.map;
			const leaflet = pageWindow.L;
			try {
				if (tornMap?.getLPoint && leaflet?.CRS?.EPSG3857?.pointToLatLng) {
					const point = [entry.x / 2, entry.y / 2];
					const leafletPoint = tornMap.getLPoint(point);
					return normalizeLatLng(leaflet.CRS.EPSG3857.pointToLatLng(leafletPoint, tornMap.minZoom));
				}
			} catch {}
			return null;
		}
		function getModelItems() {
			const model = getTornRuntime()?.model;
			if (!model) return [];
			try {
				const fullModel = model.get();
				if (Array.isArray(fullModel?.territoryUserItems)) return fullModel.territoryUserItems;
			} catch {}
			try {
				const userItems = model.get("territoryUserItems");
				if (Array.isArray(userItems)) return userItems;
			} catch {}
			return [];
		}
		function getTornRuntime() {
			const torn = pageWindow.torn;
			return isTornRuntime(torn) ? torn : null;
		}
		function dispatchPageEvent(name, detail) {
			pageWindow.dispatchEvent(new CustomEvent(name, { detail: serializeEventDetail$1(detail) }));
		}
	}
	function parseEventDetail$1(event) {
		if (!isCustomEvent$1(event)) return null;
		if (typeof event.detail === "string") try {
			return JSON.parse(event.detail);
		} catch {
			return null;
		}
		return event.detail;
	}
	function serializeEventDetail$1(detail) {
		if (detail === void 0) return void 0;
		try {
			return JSON.stringify(detail);
		} catch {
			return;
		}
	}
	function isCustomEvent$1(event) {
		return "detail" in event;
	}
	function isCityItemsMapEntry(value) {
		return isRecord$1(value) && typeof value.entryId === "string" && typeof value.itemId === "number" && Number.isFinite(value.itemId) && typeof value.name === "string" && typeof value.td === "string" && typeof value.x === "number" && Number.isFinite(value.x) && typeof value.y === "number" && Number.isFinite(value.y);
	}
	function isRecord$1(value) {
		return typeof value === "object" && value !== null;
	}
	function isTornRuntime(value) {
		return isRecord$1(value) && (!("map" in value) || value.map == null || isTornMapRuntime(value.map)) && (!("model" in value) || value.model == null || isTornModelRuntime(value.model));
	}
	function isTornMapRuntime(value) {
		return isRecord$1(value) && (!("lmap" in value) || value.lmap == null || isLeafletMap(value.lmap)) && (!("minZoom" in value) || value.minZoom == null || typeof value.minZoom === "number") && (!("getLPoint" in value) || value.getLPoint == null || typeof value.getLPoint === "function");
	}
	function isTornModelRuntime(value) {
		return isRecord$1(value) && typeof value.get === "function";
	}
	function isLeafletMap(value) {
		return isRecord$1(value) && typeof value.addLayer === "function";
	}
	function isLeafletOverlayRuntime(value) {
		return isRecord$1(value) && typeof value.divIcon === "function" && typeof value.marker === "function";
	}
	function normalizeLatLng(latLng) {
		if (!latLng) return null;
		if (Array.isArray(latLng)) {
			const [lat, lng] = latLng;
			return Number.isFinite(lat) && Number.isFinite(lng) ? latLng : null;
		}
		return Number.isFinite(latLng.lat) && Number.isFinite(latLng.lng) ? latLng : null;
	}
	function getItemImageUrl(itemId) {
		return `https://www.torn.com/images/items/${itemId}/small.png`;
	}
	var ENCODING_NUMERIC_SYSTEM = 36;
	var GROUP_PAGE_SIZE = 10;
	var contentElement = null;
	var currentItems = [];
	var periodFilter = "all";
	var searchQuery = "";
	var visibleGroupCount = GROUP_PAGE_SIZE;
	var collectingEntries = new Set();
	function initialise() {
		SCRIPT_INJECTOR.injectCityItemsMap();
		addXHRListener(({ detail: { page, xhr, json } }) => {
			if (!FEATURE_MANAGER.isEnabled(CityItemsFeature)) return;
			if (isMapData(page, xhr, json)) {
				showCityItemsContainer(resolveUserItems(decodeTerritoryUserItems(json.territoryUserItems))).catch(console.error);
				return;
			}
			const pickupTd = getPickupTd(page, xhr.requestBody);
			if (pickupTd && isSuccessfulPickupResponse(json, xhr.responseText)) handleCollectedTd(pickupTd);
		});
		document.addEventListener("click", handleMapOverlayClick, true);
		window.addEventListener(CITY_ITEMS_MAP_EVENTS.MODEL_ITEMS, handleModelItems);
	}
	function triggerFallback() {
		if (findContainer("City Items")) return;
		const userItems = getPageModelItems();
		if (userItems) {
			showCityItemsContainer(resolveUserItems(userItems)).catch(console.error);
			return;
		}
		window.setTimeout(() => dispatchMapEvent(CITY_ITEMS_MAP_EVENTS.REQUEST_MODEL_ITEMS), 100);
	}
	function handleModelItems(event) {
		const detail = parseEventDetail(event);
		if (!FEATURE_MANAGER.isEnabled(CityItemsFeature) || findContainer("City Items") || !detail) return;
		const userItems = detail.items;
		if (!Array.isArray(userItems)) return;
		const internalItems = userItems.filter(isInternalCityItem);
		if (!internalItems) return;
		showCityItemsContainer(resolveUserItems(internalItems)).catch(console.error);
	}
	function getPageModelItems() {
		const model = SCRIPT_INJECTOR.getWindow().torn?.model;
		if (!model || typeof model.get !== "function") return null;
		try {
			const fullModel = model.get();
			if (Array.isArray(fullModel?.territoryUserItems)) return fullModel.territoryUserItems;
		} catch {}
		try {
			const userItems = model.get("territoryUserItems");
			if (Array.isArray(userItems)) return userItems;
		} catch {}
		return null;
	}
	function isInternalCityItem(value) {
		return isRecord(value) && Array.isArray(value.coordinates) && value.coordinates.length >= 2 && Number.isFinite(value.coordinates[0]) && Number.isFinite(value.coordinates[1]) && Number.isFinite(value.item_id) && Number.isFinite(value.row_id) && Number.isFinite(value.timestamp) && typeof value.title === "string";
	}
	function parseEventDetail(event) {
		if (!isCustomEvent(event)) return null;
		if (typeof event.detail === "string") try {
			return JSON.parse(event.detail);
		} catch {
			return null;
		}
		return event.detail;
	}
	function isCustomEvent(event) {
		return "detail" in event;
	}
	function isRecord(value) {
		return typeof value === "object" && value !== null;
	}
	function hasGetMethod(value) {
		return isRecord(value) && typeof value.get === "function";
	}
	function decodeTerritoryUserItems(encodedItems) {
		const binary = atob(encodedItems);
		let decoded = binary;
		try {
			const bytes = new Uint8Array(binary.length);
			for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
			decoded = new TextDecoder("utf-8").decode(bytes);
		} catch {}
		return JSON.parse(decoded);
	}
	function resolveUserItems(decodedItems) {
		const items = [];
		decodedItems.forEach((item) => {
			const id = getCityItemId(item);
			if (!Number.isFinite(id)) return;
			const timestamp = getItemTimestamp(item);
			if (!Number.isFinite(timestamp)) return;
			const entry = getCityItemEntry(item, id, timestamp);
			const name = item.title || ITEM_RESOLVER.loadItem(id)?.name || `Item ${id}`;
			if (settings.pages.city.combineDuplicates) {
				const duplicate = items.find((item) => item.item === id);
				if (duplicate) {
					duplicate.count++;
					duplicate.entries.push(entry);
					duplicate.timestamp = Math.max(duplicate.timestamp, timestamp);
				} else items.push({
					item: id,
					count: 1,
					name,
					entries: [entry],
					timestamp,
					band: ""
				});
			} else items.push({
				item: id,
				count: 1,
				name,
				entries: [entry],
				timestamp,
				band: ""
			});
		});
		for (const item of items) item.band = getBandForTimestamp(item.timestamp);
		return items;
	}
	function getItemTimestamp(item) {
		if ("coordinates" in item) return item.timestamp;
		return parseInt(item.ts, ENCODING_NUMERIC_SYSTEM);
	}
	var MILLISECONDS_PER_DAY = 864e5;
	var TIME_BANDS = [
		{
			key: "today",
			maxAgeDays: 0,
			label: "Today"
		},
		{
			key: "week",
			maxAgeDays: 7,
			label: "This week"
		},
		{
			key: "month",
			maxAgeDays: 30,
			label: "This month"
		},
		{
			key: "year",
			maxAgeDays: 365,
			label: "This year"
		},
		{
			key: "older",
			maxAgeDays: Number.POSITIVE_INFINITY,
			label: "More than a year ago"
		}
	];
	var GROUP_PERIODS = [
		{
			key: "day",
			label: "Days"
		},
		{
			key: "week",
			label: "Weeks"
		},
		{
			key: "month",
			label: "Months"
		},
		{
			key: "year",
			label: "Years"
		}
	];
	function getUtcDayStart(milliseconds) {
		const date = new Date(milliseconds);
		return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
	}
	function getUtcWeekStart(milliseconds) {
		const dayStart = getUtcDayStart(milliseconds);
		return dayStart - (new Date(dayStart).getUTCDay() + 6) % 7 * MILLISECONDS_PER_DAY;
	}
	function getBandForTimestamp(timestampSeconds) {
		const ageDays = Math.floor((getUtcDayStart(Date.now()) - getUtcDayStart(timestampSeconds * 1e3)) / MILLISECONDS_PER_DAY);
		return TIME_BANDS.find((band) => ageDays <= band.maxAgeDays)?.key ?? "older";
	}
	function getBandOrder() {
		return TIME_BANDS.map((band) => band.key);
	}
	function formatBandLabel(bandKey) {
		return TIME_BANDS.find((band) => band.key === bandKey)?.label ?? bandKey;
	}
	function getGroupPeriod() {
		const groupPeriod = settings.pages.city.groupByPeriodUnit;
		return GROUP_PERIODS.some((period) => period.key === groupPeriod) ? groupPeriod : "day";
	}
	function getGroupKey(timestampSeconds, groupPeriod = getGroupPeriod()) {
		return getGroupStart(timestampSeconds, groupPeriod).toString();
	}
	function getGroupStart(timestampSeconds, groupPeriod) {
		const milliseconds = timestampSeconds * 1e3;
		const date = new Date(milliseconds);
		if (groupPeriod === "day") return getUtcDayStart(milliseconds);
		if (groupPeriod === "week") return getUtcWeekStart(milliseconds);
		if (groupPeriod === "month") return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1);
		return Date.UTC(date.getUTCFullYear(), 0, 1);
	}
	function formatGroupLabel(groupKey, groupPeriod = getGroupPeriod()) {
		const milliseconds = Number(groupKey);
		if (!Number.isFinite(milliseconds)) return groupKey;
		const date = new Date(milliseconds);
		if (groupPeriod === "month") return `${MONTHS[date.getUTCMonth()]} ${date.getUTCFullYear()}`;
		if (groupPeriod === "year") return String(date.getUTCFullYear());
		const formattedDate = formatDate({ milliseconds }, { showYear: true });
		return groupPeriod === "week" ? `Week of ${formattedDate}` : formattedDate;
	}
	function getCityItemId(item) {
		if ("coordinates" in item) return item.item_id;
		return parseInt(item.d, ENCODING_NUMERIC_SYSTEM);
	}
	function getCityItemEntry(item, itemId, timestamp) {
		let rowId, td, x, y;
		if ("coordinates" in item) {
			rowId = item.row_id.toString(ENCODING_NUMERIC_SYSTEM);
			td = btoa([
				item.coordinates[0],
				item.coordinates[1],
				item.row_id,
				item.timestamp
			].map((value) => value.toString(ENCODING_NUMERIC_SYSTEM)).join("O"));
			x = item.coordinates[0];
			y = item.coordinates[1];
		} else {
			rowId = item.id;
			td = btoa([
				item.c.x,
				item.c.y,
				item.id,
				item.ts
			].join("O"));
			x = parseInt(item.c.x, ENCODING_NUMERIC_SYSTEM);
			y = parseInt(item.c.y, ENCODING_NUMERIC_SYSTEM);
		}
		return {
			entryId: rowId,
			itemId,
			name: item.title,
			td,
			x,
			y,
			timestamp
		};
	}
	async function showCityItemsContainer(items) {
		await requireElement("#map .leaflet-zoom-animated");
		if (!contentElement || !document.contains(contentElement)) {
			const { content, options } = createContainer("City Items", {
				class: "mt10",
				alwaysContent: true,
				nextElement: document.querySelector("#tab-menu")
			});
			contentElement = content;
			showHighlightControl(options);
		}
		setCityItems(items);
	}
	function showHighlightControl(options) {
		const checkbox = createCheckbox({ description: "Highlight items" });
		checkbox.setChecked(filters.city.highlightItems);
		setMapHighlight(filters.city.highlightItems);
		checkbox.onChange(() => {
			const highlightItems = checkbox.isChecked();
			setMapHighlight(highlightItems);
			ttStorage.change({ filters: { city: { highlightItems } } });
		});
		options.appendChild(checkbox.element);
	}
	function setMapHighlight(state) {
		document.querySelector("#map")?.classList.toggle("highlight-items", state);
	}
	function setCityItems(items) {
		currentItems = items;
		if (contentElement) populateContainer(contentElement, currentItems);
		syncVisibleMapEntries();
	}
	function populateContainer(content, items) {
		showControls(content, items);
		if (ITEM_RESOLVER.hasFullItems()) showValue(content, items);
		else content.querySelector(".tt-city-total")?.remove();
		showItemList(content, items);
	}
	function getFilteredItems(items) {
		const periodItems = periodFilter === "all" ? items : items.flatMap((item) => {
			const entries = item.entries.filter((entry) => matchesPeriodFilter(getBandForTimestamp(entry.timestamp)));
			if (!entries.length) return [];
			const timestamp = Math.max(...entries.map((entry) => entry.timestamp));
			return [{
				...item,
				count: entries.length,
				entries,
				timestamp,
				band: getBandForTimestamp(timestamp)
			}];
		});
		const query = searchQuery.trim().toLowerCase();
		return query ? periodItems.filter((item) => item.name.toLowerCase().includes(query)) : periodItems;
	}
	function matchesPeriodFilter(itemBand) {
		if (periodFilter === "older") return itemBand === "older";
		const selectedIndex = TIME_BANDS.findIndex((band) => band.key === periodFilter);
		const itemIndex = TIME_BANDS.findIndex((band) => band.key === itemBand);
		return selectedIndex >= 0 && itemIndex >= 0 && itemIndex <= selectedIndex;
	}
	function calculateItemValue(items) {
		return {
			value: items.map(({ item, count }) => {
				const fullItem = ITEM_RESOLVER.getFullItem(item);
				return fullItem ? {
					...fullItem,
					count
				} : null;
			}).filter((item) => !!item).map(({ value: { market_price: value }, count }) => value * count).filter((value) => !!value).reduce((a, b) => a + b, 0),
			count: items.reduce((total, item) => total + item.count, 0)
		};
	}
	function showValue(content, items) {
		content.querySelector(".tt-city-total")?.remove();
		if (!ITEM_RESOLVER.hasFullItems()) return;
		const { value, count } = calculateItemValue(getFilteredItems(items));
		content.appendChild(elementBuilder({
			type: "div",
			class: "tt-city-total",
			children: [elementBuilder({
				type: "span",
				class: "tt-city-total-text",
				text: `Item Value (${count}): `
			}), elementBuilder({
				type: "span",
				class: "tt-city-total-value",
				text: formatNumber(value, { currency: true })
			})]
		}));
	}
	function refreshList() {
		if (!contentElement) return;
		showValue(contentElement, currentItems);
		showItemList(contentElement, currentItems);
		syncVisibleMapEntries();
	}
	function resetVisibleGroups() {
		visibleGroupCount = GROUP_PAGE_SIZE;
	}
	function showControls(content, items) {
		content.querySelector(".tt-city-controls")?.remove();
		const groupByCheckbox = createCheckbox();
		const groupBySelect = createSelect(GROUP_PERIODS.map((period) => ({
			value: period.key,
			description: period.label
		})));
		groupByCheckbox.setChecked(!!settings.pages.city.groupByPeriod);
		groupBySelect.setSelected(getGroupPeriod());
		groupBySelect.element.disabled = !groupByCheckbox.isChecked();
		groupByCheckbox.onChange(() => {
			const checked = groupByCheckbox.isChecked();
			settings.pages.city.groupByPeriod = checked;
			groupBySelect.element.disabled = !checked;
			resetVisibleGroups();
			ttStorage.change({ settings: { pages: { city: { groupByPeriod: checked } } } });
			refreshList();
		});
		groupBySelect.onChange(() => {
			const groupByPeriodUnit = groupBySelect.getSelected();
			settings.pages.city.groupByPeriodUnit = groupByPeriodUnit;
			resetVisibleGroups();
			ttStorage.change({ settings: { pages: { city: { groupByPeriodUnit } } } });
			refreshList();
		});
		const periodSelect = createSelect([{
			value: "all",
			description: "All"
		}, ...getBandOrder().filter((band) => items.some((item) => item.entries.some((entry) => getBandForTimestamp(entry.timestamp) === band))).map((band) => ({
			value: band,
			description: formatBandLabel(band)
		}))]);
		if (!periodSelect.setSelected(periodFilter)) {
			periodSelect.setSelected("all");
			periodFilter = "all";
		}
		periodSelect.onChange(() => {
			periodFilter = periodSelect.getSelected();
			resetVisibleGroups();
			refreshList();
		});
		const searchInput = elementBuilder({
			type: "input",
			value: searchQuery,
			attributes: { type: "text" },
			events: { input: (event) => {
				if (!(event.currentTarget instanceof HTMLInputElement)) return;
				searchQuery = event.currentTarget.value;
				resetVisibleGroups();
				refreshList();
			} }
		});
		content.appendChild(elementBuilder({
			type: "div",
			class: "tt-city-controls hide-collapse",
			children: [
				elementBuilder({
					type: "div",
					class: "tt-city-group-filter",
					children: [
						elementBuilder({
							type: "span",
							class: "tt-city-control-label",
							text: "Group:"
						}),
						groupByCheckbox.element,
						groupBySelect.element
					]
				}),
				elementBuilder({
					type: "label",
					class: "tt-city-period-filter",
					children: [elementBuilder({
						type: "span",
						class: "tt-city-control-label",
						text: "Filter:"
					}), periodSelect.element]
				}),
				elementBuilder({
					type: "label",
					class: "tt-city-search-filter",
					children: [elementBuilder({
						type: "span",
						class: "tt-city-control-label",
						text: "Search:"
					}), searchInput]
				})
			]
		}));
	}
	function getGroupedItems(items) {
		const groupPeriod = getGroupPeriod();
		const groups = new Map();
		for (const item of items) for (const entry of item.entries) {
			const key = getGroupKey(entry.timestamp, groupPeriod);
			const groupItems = groups.get(key) ?? [];
			groups.set(key, groupItems);
			const duplicate = settings.pages.city.combineDuplicates ? groupItems.find((groupedItem) => groupedItem.item === item.item) : void 0;
			if (duplicate) {
				duplicate.count++;
				duplicate.entries.push(entry);
				duplicate.timestamp = Math.max(duplicate.timestamp, entry.timestamp);
				duplicate.band = getBandForTimestamp(duplicate.timestamp);
			} else groupItems.push({
				...item,
				count: 1,
				entries: [entry],
				timestamp: entry.timestamp,
				band: getBandForTimestamp(entry.timestamp)
			});
		}
		return [...groups.entries()].sort(([a], [b]) => Number(b) - Number(a)).map(([key, groupItems]) => ({
			label: formatGroupLabel(key, groupPeriod),
			items: groupItems
		}));
	}
	function showItemList(content, items) {
		content.querySelector(".tt-city-items")?.remove();
		const listElement = elementBuilder({
			type: "div",
			class: "tt-city-items hide-collapse"
		});
		const filtered = getFilteredItems(items);
		if (settings.pages.city.groupByPeriod) {
			const groups = getGroupedItems(filtered);
			const visibleGroups = groups.slice(0, visibleGroupCount);
			if (!groups.length) listElement.appendChild(elementBuilder({
				type: "p",
				text: "There are no items in the city."
			}));
			else {
				for (const group of visibleGroups) {
					const { value, count } = calculateItemValue(group.items);
					listElement.appendChild(elementBuilder({
						type: "div",
						class: "tt-city-period-group",
						children: [elementBuilder({
							type: "div",
							class: "tt-city-period-header",
							children: [
								elementBuilder({
									type: "span",
									class: "tt-city-period-name",
									text: group.label
								}),
								elementBuilder({
									type: "span",
									class: "tt-city-period-count",
									text: `(${count})`
								}),
								elementBuilder({
									type: "span",
									class: "tt-city-period-value",
									text: ITEM_RESOLVER.hasFullItems() ? formatNumber(value, { currency: true }) : ""
								})
							]
						})]
					}));
					appendItemsParagraph(listElement, group.items, false);
				}
				appendGroupPaginationControls(listElement, groups.length, visibleGroups.length);
			}
		} else appendItemsParagraph(listElement, filtered, true);
		content.appendChild(listElement);
	}
	function appendGroupPaginationControls(parent, totalGroups, visibleGroups) {
		if (totalGroups <= GROUP_PAGE_SIZE) return;
		const hasMore = visibleGroups < totalGroups;
		const controls = elementBuilder({
			type: "div",
			class: "tt-city-group-pagination",
			children: [elementBuilder({
				type: "span",
				text: `Showing ${visibleGroups} of ${totalGroups} groups`
			})]
		});
		if (hasMore) {
			controls.appendChild(elementBuilder({
				type: "button",
				class: "tt-button-link tt-city-group-pagination-button",
				text: "Show more",
				attributes: { type: "button" },
				events: { click: () => {
					visibleGroupCount = Math.min(visibleGroupCount + GROUP_PAGE_SIZE, totalGroups);
					refreshList();
				} }
			}));
			controls.appendChild(elementBuilder({
				type: "button",
				class: "tt-button-link tt-city-group-pagination-button",
				text: "Show all",
				attributes: { type: "button" },
				events: { click: () => {
					visibleGroupCount = totalGroups;
					refreshList();
				} }
			}));
		}
		if (visibleGroups > GROUP_PAGE_SIZE) controls.appendChild(elementBuilder({
			type: "button",
			class: "tt-button-link tt-city-group-pagination-button",
			text: "Show fewer",
			attributes: { type: "button" },
			events: { click: () => {
				resetVisibleGroups();
				refreshList();
			} }
		}));
		parent.appendChild(controls);
	}
	function appendItemsParagraph(parent, items, withPreamble) {
		const totalCount = items.reduce((total, item) => total + item.count, 0);
		if (!totalCount) {
			if (withPreamble) parent.appendChild(elementBuilder({
				type: "p",
				text: "There are no items in the city."
			}));
			return;
		}
		const children = [];
		if (withPreamble) children.push("There", totalCount === 1 ? " is " : " are ", elementBuilder({
			type: "strong",
			text: String(totalCount)
		}), totalCount === 1 ? " item " : " items ", "in the city: ");
		const paragraph = elementBuilder({
			type: "p",
			children
		});
		if (items.length === 1) paragraph.appendChild(createItemSpan(items[0]));
		else {
			const list = [...items];
			const last = list.splice(-1)[0];
			for (const item of list) {
				paragraph.appendChild(createItemSpan(item));
				paragraph.appendChild(document.createTextNode(", "));
			}
			if (paragraph.lastChild) paragraph.lastChild.remove();
			paragraph.appendChild(document.createTextNode(" and "));
			paragraph.appendChild(createItemSpan(last));
		}
		paragraph.appendChild(document.createTextNode("."));
		parent.appendChild(paragraph);
	}
	function createItemSpan({ item, name, count, entries }) {
		return elementBuilder({
			type: "span",
			text: count > 1 ? `${count}x ${name}` : name,
			class: "list-item",
			dataset: { id: item },
			events: {
				mouseenter() {
					highlightItem(item, true);
				},
				mouseleave() {
					highlightItem(item, false);
				},
				click(event) {
					if (!event.isTrusted) return;
					collectEntry(entries[0], item, name).catch(console.error);
				}
			}
		});
	}
	async function collectEntry(entry, item, name) {
		if (collectingEntries.has(entry.entryId)) return;
		collectingEntries.add(entry.entryId);
		try {
			await collectItem(entry.td);
			handleCollectedEntry(entry, item, name);
		} finally {
			collectingEntries.delete(entry.entryId);
		}
	}
	function handleMapOverlayClick(event) {
		if (!event.isTrusted) return;
		if (!(event.target instanceof Element)) return;
		const overlay = event.target.closest(".tt-city-item-overlay.city-item");
		if (!overlay) return;
		const entry = findEntry(overlay.dataset.td, overlay.dataset.entryId, parseNumericDatasetValue(overlay.dataset.itemId));
		if (!entry) return;
		event.preventDefault();
		event.stopPropagation();
		if (typeof event.stopImmediatePropagation === "function") event.stopImmediatePropagation();
		const item = findCityItemForEntry(entry);
		collectEntry(entry, entry.itemId, item?.name ?? entry.name).catch(console.error);
	}
	function handleCollectedTd(td) {
		const entry = findEntry(td);
		if (!entry) return;
		const item = entry.itemId;
		handleCollectedEntry(entry, item, findCityItemForEntry(entry)?.name ?? entry.name);
	}
	function handleCollectedEntry(entry, item, name) {
		if (!findEntry(entry.td, entry.entryId)) return;
		setCityItems(removeEntryFromItems(entry));
		clearForcedHighlights();
		let text;
		if (ITEM_RESOLVER.hasFullItems()) text = `Collected ${name} with a value of ${formatNumber(ITEM_RESOLVER.getFullItem(item)?.value.market_price ?? 0, { currency: true })}.`;
		else text = `Collected ${name}.`;
		displayAlert({
			title: "Collected Item",
			text,
			type: "success"
		});
	}
	function removeEntryFromItems(entry) {
		const nextItems = [];
		for (const item of currentItems) {
			const entryIndex = item.entries.findIndex((existing) => existing.td === entry.td || existing.entryId === entry.entryId);
			if (entryIndex === -1) {
				nextItems.push(item);
				continue;
			}
			if (item.entries.length > 1) {
				const entries = item.entries.filter((_, index) => index !== entryIndex);
				const timestamp = Math.max(...entries.map((entry) => entry.timestamp));
				nextItems.push({
					...item,
					count: item.count - 1,
					entries,
					timestamp,
					band: getBandForTimestamp(timestamp)
				});
			}
		}
		return nextItems;
	}
	function findEntry(td, entryId, itemId) {
		for (const item of currentItems) {
			const entry = item.entries.find((entry) => td && entry.td === td || entryId && entry.entryId === entryId || itemId && entry.itemId === itemId);
			if (entry) return entry;
		}
		return null;
	}
	function findCityItemForEntry(entry) {
		return currentItems.find((item) => item.entries.some((existing) => existing.td === entry.td || existing.entryId === entry.entryId)) ?? null;
	}
	async function collectItem(td) {
		const body = new URLSearchParams();
		body.set("step", "uif");
		body.set("td", td);
		const result = await fetchData("torn_direct", {
			action: "city.php",
			method: "POST",
			body
		});
		if (!isSuccessfulPickupResponse(result, typeof result === "string" ? result : void 0)) throw new Error("City item pickup failed.");
	}
	function syncVisibleMapEntries() {
		syncMapEntries(getFilteredItems(currentItems));
	}
	function syncMapEntries(items) {
		dispatchMapEvent(CITY_ITEMS_MAP_EVENTS.SET_ITEMS, { entries: items.flatMap(({ entries }) => entries.map(({ entryId, itemId, name, td, x, y }) => ({
			entryId,
			itemId,
			name,
			td,
			x,
			y
		}))) });
	}
	function dispatchMapEvent(name, detail) {
		SCRIPT_INJECTOR.getWindow().dispatchEvent(new CustomEvent(name, { detail: serializeEventDetail(detail) }));
	}
	function serializeEventDetail(detail) {
		if (detail === void 0) return void 0;
		try {
			return JSON.stringify(detail);
		} catch {
			return;
		}
	}
	function highlightItem(itemId, state, className = "force-hover") {
		for (const item of findAllElements(`.city-item[data-id="${itemId}"]`)) item.classList.toggle(className, state);
	}
	function clearForcedHighlights() {
		for (const item of findAllElements(".city-item.force-hover")) item.classList.remove("force-hover");
	}
	function parseNumericDatasetValue(value) {
		if (value === void 0) return void 0;
		const parsed = parseInt(value);
		return Number.isFinite(parsed) ? parsed : void 0;
	}
	function getPickupTd(page, body) {
		if (page !== "city") return null;
		if (getBodyParam(body, "step") !== "uif") return null;
		return getBodyParam(body, "td");
	}
	function getBodyParam(body, param) {
		if (!body) return null;
		if (typeof body === "string") return new URLSearchParams(body).get(param);
		if (body instanceof URLSearchParams) return body.get(param);
		if (hasGetMethod(body)) {
			const value = body.get(param);
			return value == null ? null : value.toString();
		}
		if (isRecord(body) && param in body) {
			const value = body[param];
			return value == null ? null : value.toString();
		}
		return null;
	}
	function isSuccessfulPickupResponse(json, text) {
		if (isRecord(json)) {
			if ("success" in json) return json.success === true || json.success === "true" || json.success === 1;
			if ("error" in json && json.error) return false;
		}
		if (typeof text === "string") {
			if (!text.trim()) return true;
			try {
				return isSuccessfulPickupResponse(JSON.parse(text));
			} catch {
				return false;
			}
		}
		return false;
	}
	function removeHighlight() {
		removeContainer("City Items");
		contentElement = null;
		currentItems = [];
		periodFilter = "all";
		searchQuery = "";
		resetVisibleGroups();
		collectingEntries.clear();
		clearForcedHighlights();
		setMapHighlight(false);
		dispatchMapEvent(CITY_ITEMS_MAP_EVENTS.CLEAR);
		document.removeEventListener("click", handleMapOverlayClick, true);
	}
	var CityItemsFeature = class extends Feature {
		constructor() {
			super("City Items", "city", ExecutionTiming.IMMEDIATELY);
		}
		precondition() {
			return getPageStatus().access;
		}
		isEnabled() {
			return settings.pages.city.items;
		}
		initialise() {
			initialise();
		}
		execute() {
			setTimeout(triggerFallback, 500);
		}
		cleanup() {
			removeHighlight();
		}
		requiresScreenInformation() {
			return false;
		}
		storageKeys() {
			return ["settings.pages.city.items"];
		}
	};
	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 {
		async update(key, fn) {
			const database = await this.get(key);
			fn(database);
			await this.set({ [key]: database });
		}
		async change(object) {
			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 });
			}
		}
		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)}");
	var ScriptItemResolver = {
		items: [],
		itemsMap: {},
		loadItem(id) {
			return this.getFullItem(id) ?? this.getStaticItem(id);
		},
		findItem(matcher) {
			return this.getAllFullItems().find(matcher) ?? null;
		},
		getStaticItem(id) {
			return this.getFullItem(id);
		},
		hasFullItems: () => true,
		getFullItem(id) {
			if (!Object.keys(this.itemsMap).length) throw new Error("no items loaded");
			return id in this.itemsMap ? this.itemsMap[id] : null;
		},
		async loadItems() {
			if (ttCache.hasValue("static-data", "items-map")) {
				const map = ttCache.get("static-data", "items-map");
				this.items = Object.values(map);
				this.itemsMap = map;
				return;
			}
			const itemsMap = (await fetchData("playground_torntools", { section: "static-items" })).items.reduce((acc, item) => {
				acc[item.id] = item;
				return acc;
			}, {});
			this.items = Object.values(itemsMap);
			this.itemsMap = itemsMap;
			ttCache.set({ "static-data": { "items-map": itemsMap } }, millisToNewDay());
		},
		getAllFullItems() {
			return this.items;
		},
		getAllStaticItems() {
			return this.getAllFullItems();
		}
	};
	async function registerUserscriptContext(storagePrefix) {
		setTTStorage(new TTScriptStorage(storagePrefix));
		setFeatureManager(new ScriptFeatureManager());
		setScriptInjector(UserscriptScriptInjector);
		setRuntimeInformation(UserscriptRuntimeInformation);
		setRuntimeStorage(UserscriptRuntimeStorage);
		setOffloadService(ScriptOffloadService);
		setDataFetcher(ScriptDataFetcher);
		setStaticItemResolver(ScriptItemResolver);
		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();
		}
	};
	function injectUserscriptCityItemsMapListeners() {
		injectCityItemsMapListeners(unsafeWindow);
	}
	var fetchListenerInjector = new RequestListenerInjector(injectFetchListeners);
	var xhrListenerInjector = new RequestListenerInjector(injectXhrListeners);
	var cityItemsMapListenerInjector = new RequestListenerInjector(injectUserscriptCityItemsMapListeners);
	var UserscriptScriptInjector = {
		getWindow() {
			return unsafeWindow;
		},
		injectFetch() {
			fetchListenerInjector.inject();
		},
		injectXHR() {
			xhrListenerInjector.inject();
		},
		injectCityItemsMap() {
			cityItemsMapListenerInjector.inject();
		}
	};
	var UserscriptRuntimeInformation = {
		getVersion() {
			return GM.info.version;
		},
		isUserscript() {
			return true;
		}
	};
	var UserscriptRuntimeStorage = {
		callback: () => {},
		addChangeListener(callback) {
			this.callback = callback;
		}
	};
	var ScriptOffloadService = {
		fetchRelay(_location, _options) {
			return Promise.reject(new Error("OffloadService is not available in script context. Use DataFetcher instead."));
		},
		initialize() {
			return Promise.resolve({ success: true });
		},
		reinitializeTimers() {
			return Promise.resolve();
		}
	};
	var ScriptDataFetcher = { fetch(url, options) {
		if (url.startsWith(FETCH_PLATFORMS.torn_direct)) return fetchOnPage(url, options);
		return new Promise((resolve, reject) => {
			try {
				const u = new URL(url);
				u.searchParams.append("pda-cache-busting", getUUID());
				url = u.toString();
			} catch {}
			GM.xmlHttpRequest({
				method: options?.method || "GET",
				url,
				headers: options?.headers,
				data: options?.method === "POST" ? typeof options.body === "string" ? options.body : JSON.stringify(options.body) : void 0,
				timeout: options?.timeout,
				onload: (response) => {
					if (!response) {
						reject(new Error("Request has no actual response. Likely something went wrong in the fetch implementation."));
						return;
					}
					resolve({
						text: response.responseText,
						status: response.status,
						ok: response.status >= 200 && response.status < 300
					});
				},
				onerror: (error) => {
					reject(error);
				},
				ontimeout: () => {
					reject(new DOMException("Request cancelled because it took too long.", "AbortError"));
				}
			});
		});
	} };
	async function fetchOnPage(url, options) {
		const controller = new AbortController();
		const timeoutId = options?.timeout ? setTimeout(() => controller.abort(), options.timeout) : void 0;
		try {
			const response = await fetch(url, {
				method: options?.method || "GET",
				...options?.method === "POST" ? { body: options.body } : {},
				headers: options?.headers,
				signal: controller.signal
			});
			return {
				text: await response.text(),
				status: response.status,
				ok: response.ok
			};
		} finally {
			if (timeoutId) clearTimeout(timeoutId);
		}
	}
	(async () => {
		await registerUserscriptContext("tt_ci");
		await ScriptItemResolver.loadItems();
		const feature = new CityItemsFeature();
		FEATURE_MANAGER.registerFeature(feature);
	})();
})();