TORN: TornTools - City Items

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

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Advertisement:

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

Advertisement:

// ==UserScript==
// @name             TORN: TornTools - City Items
// @namespace        torntools.city-items
// @version          alpha-0.0.3
// @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);
	};
	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(".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 span:nth-of-type(odd){color:#aaa}.tt-city-items .list-item{cursor:pointer}");
	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")
			},
			tornstats: { key: new DefaultSetting("string") },
			yata: { key: new DefaultSetting("string") },
			ffScouter: { key: new DefaultSetting("string") }
		},
		settings: {
			updateNotice: new DefaultSetting("boolean", true),
			featureDisplay: new DefaultSetting("boolean", true),
			featureDisplayPosition: new DefaultSetting("string", "bottom-left"),
			featureDisplayOnlyFailed: new DefaultSetting("boolean", false),
			featureDisplayHideDisabled: new DefaultSetting("boolean", false),
			featureDisplayHideEmpty: new DefaultSetting("boolean", true),
			developer: new DefaultSetting("boolean", false),
			formatting: {
				tct: new DefaultSetting("boolean", false),
				date: new DefaultSetting("string", "eu"),
				time: new DefaultSetting("string", "eu")
			},
			sorting: { abroad: {
				column: new DefaultSetting("string", ""),
				order: new DefaultSetting("string", "none")
			} },
			notifications: {
				sound: new DefaultSetting("string", "default"),
				soundCustom: new DefaultSetting("string", ""),
				tts: new DefaultSetting("boolean", false),
				ttsVoice: new DefaultSetting("string", "default"),
				ttsRate: new DefaultSetting("number", 1),
				link: new DefaultSetting("boolean", true),
				volume: new DefaultSetting("number", 100),
				requireInteraction: new DefaultSetting("boolean", false),
				types: {
					global: new DefaultSetting("boolean", () => typeof Notification !== "undefined" && Notification.permission === "granted"),
					events: new DefaultSetting("boolean", true),
					messages: new DefaultSetting("boolean", true),
					status: new DefaultSetting("boolean", true),
					traveling: new DefaultSetting("boolean", true),
					cooldowns: new DefaultSetting("boolean", true),
					education: new DefaultSetting("boolean", true),
					newDay: new DefaultSetting("boolean", true),
					energy: new DefaultSetting("array", ["100%"]),
					nerve: new DefaultSetting("array", ["100%"]),
					happy: new DefaultSetting("array", ["100%"]),
					life: new DefaultSetting("array", ["100%"]),
					offline: new DefaultSetting("array", []),
					chainTimerEnabled: new DefaultSetting("boolean", true),
					chainBonusEnabled: new DefaultSetting("boolean", true),
					leavingHospitalEnabled: new DefaultSetting("boolean", true),
					landingEnabled: new DefaultSetting("boolean", true),
					cooldownDrugEnabled: new DefaultSetting("boolean", true),
					cooldownBoosterEnabled: new DefaultSetting("boolean", true),
					cooldownMedicalEnabled: new DefaultSetting("boolean", true),
					chainTimer: new DefaultSetting("array", []),
					chainBonus: new DefaultSetting("array", []),
					leavingHospital: new DefaultSetting("array", []),
					landing: new DefaultSetting("array", []),
					cooldownDrug: new DefaultSetting("array", []),
					cooldownBooster: new DefaultSetting("array", []),
					cooldownMedical: new DefaultSetting("array", []),
					stocks: new DefaultSetting("object", {}),
					missionsLimitEnabled: new DefaultSetting("boolean", false),
					missionsLimit: new DefaultSetting("string", ""),
					missionsExpireEnabled: new DefaultSetting("boolean", false),
					missionsExpire: new DefaultSetting("array", []),
					npcsGlobal: new DefaultSetting("boolean", true),
					npcs: new DefaultSetting("array", []),
					npcPlannedEnabled: new DefaultSetting("boolean", true),
					npcPlanned: new DefaultSetting("array", []),
					refillEnergyEnabled: new DefaultSetting("boolean", true),
					refillEnergy: new DefaultSetting("string", ""),
					refillNerveEnabled: new DefaultSetting("boolean", true),
					refillNerve: new DefaultSetting("string", "")
				}
			},
			apiUsage: {
				comment: new DefaultSetting("string", "TornTools"),
				delayEssential: new DefaultSetting("number", 30),
				delayBasic: new DefaultSetting("number", 120),
				delayPassive: new DefaultSetting("number", 3600),
				delayStakeouts: new DefaultSetting("number", 30),
				user: {
					bars: new DefaultSetting("boolean", true),
					cooldowns: new DefaultSetting("boolean", true),
					travel: new DefaultSetting("boolean", true),
					newevents: new DefaultSetting("boolean", true),
					newmessages: new DefaultSetting("boolean", true),
					refills: new DefaultSetting("boolean", true),
					stocks: new DefaultSetting("boolean", true),
					education: new DefaultSetting("boolean", true),
					networth: new DefaultSetting("boolean", true),
					inventory: new DefaultSetting("boolean", true),
					jobpoints: new DefaultSetting("boolean", true),
					merits: new DefaultSetting("boolean", true),
					perks: new DefaultSetting("boolean", true),
					icons: new DefaultSetting("boolean", true),
					ammo: new DefaultSetting("boolean", true),
					battlestats: new DefaultSetting("boolean", true),
					crimes: new DefaultSetting("boolean", true),
					workstats: new DefaultSetting("boolean", true),
					skills: new DefaultSetting("boolean", true),
					weaponexp: new DefaultSetting("boolean", true),
					properties: new DefaultSetting("boolean", true),
					calendar: new DefaultSetting("boolean", true),
					organizedcrime: new DefaultSetting("boolean", true),
					missions: new DefaultSetting("boolean", true),
					personalstats: new DefaultSetting("boolean", true),
					attacks: new DefaultSetting("boolean", true),
					money: new DefaultSetting("boolean", true),
					honors: new DefaultSetting("boolean", true),
					medals: new DefaultSetting("boolean", true),
					virus: new DefaultSetting("boolean", true)
				}
			},
			themes: {
				pages: new DefaultSetting("string", "default"),
				containers: new DefaultSetting("string", "default")
			},
			hideIcons: new DefaultSetting("array", []),
			hideCasinoGames: new DefaultSetting("array", []),
			hideStocks: new DefaultSetting("array", []),
			alliedFactions: new DefaultSetting("array", []),
			customLinks: new DefaultSetting("array", []),
			employeeInactivityWarning: new DefaultSetting("array", []),
			factionInactivityWarning: new DefaultSetting("array", []),
			userAlias: new DefaultSetting("array", []),
			csvDelimiter: new DefaultSetting("string", ";"),
			pages: {
				global: {
					alignLeft: new DefaultSetting("boolean", false),
					hideLevelUpgrade: new DefaultSetting("boolean", false),
					hideQuitButtons: new DefaultSetting("boolean", false),
					hideTutorials: new DefaultSetting("boolean", false),
					keepAttackHistory: new DefaultSetting("boolean", true),
					miniProfileLastAction: new DefaultSetting("boolean", true),
					reviveProvider: new DefaultSetting("string", ""),
					pageTitles: new DefaultSetting("boolean", true),
					stackingMode: new DefaultSetting("boolean", false),
					noOutsideLinkAlert: new DefaultSetting("boolean", false),
					urlFill: new DefaultSetting("boolean", true)
				},
				profile: {
					avgpersonalstats: new DefaultSetting("boolean", false),
					statusIndicator: new DefaultSetting("boolean", true),
					idBesideProfileName: new DefaultSetting("boolean", true),
					notes: new DefaultSetting("boolean", true),
					showAllyWarning: new DefaultSetting("boolean", true),
					ageToWords: new DefaultSetting("boolean", true),
					disableAllyAttacks: new DefaultSetting("boolean", true),
					box: new DefaultSetting("boolean", true),
					boxStats: new DefaultSetting("boolean", true),
					boxSpy: new DefaultSetting("boolean", true),
					boxStakeout: new DefaultSetting("boolean", true),
					boxAttackHistory: new DefaultSetting("boolean", true),
					boxFetch: new DefaultSetting("boolean", true)
				},
				chat: {
					fontSize: new DefaultSetting("number", 12),
					searchChat: new DefaultSetting("boolean", true),
					completeUsernames: new DefaultSetting("boolean", true),
					highlights: new DefaultSetting("array", [{
						name: "$player",
						color: "#7ca900"
					}]),
					titleHighlights: new DefaultSetting("array", []),
					tradeTimer: new DefaultSetting("boolean", true),
					resizable: new DefaultSetting("boolean", true),
					hideChatButton: new DefaultSetting("boolean", true),
					hideChat: new DefaultSetting("boolean", false)
				},
				sidebar: {
					notes: new DefaultSetting("boolean", true),
					highlightEnergy: new DefaultSetting("boolean", true),
					highlightNerve: new DefaultSetting("boolean", false),
					ocTimer: new DefaultSetting("boolean", true),
					oc2Timer: new DefaultSetting("boolean", true),
					oc2TimerPosition: new DefaultSetting("boolean", false),
					oc2TimerLevel: new DefaultSetting("boolean", true),
					factionOCTimer: new DefaultSetting("boolean", false),
					collapseAreas: new DefaultSetting("boolean", true),
					settingsLink: new DefaultSetting("boolean", true),
					hideGymHighlight: new DefaultSetting("boolean", false),
					hideNewspaperHighlight: new DefaultSetting("boolean", false),
					upkeepPropHighlight: new DefaultSetting("number", 0),
					barLinks: new DefaultSetting("boolean", true),
					pointsValue: new DefaultSetting("boolean", true),
					npcLootTimes: new DefaultSetting("boolean", true),
					npcLootTimesService: new DefaultSetting("string", "tornstats"),
					cooldownEndTimes: new DefaultSetting("boolean", true),
					companyAddictionLevel: new DefaultSetting("boolean", true),
					showJobPointsToolTip: new DefaultSetting("boolean", true),
					rwTimer: new DefaultSetting("boolean", true),
					virusTimer: new DefaultSetting("boolean", false)
				},
				popup: {
					dashboard: new DefaultSetting("boolean", true),
					marketSearch: new DefaultSetting("boolean", true),
					bazaarUsingExternal: new DefaultSetting("boolean", true),
					calculator: new DefaultSetting("boolean", true),
					stocksOverview: new DefaultSetting("boolean", true),
					notifications: new DefaultSetting("boolean", true),
					defaultTab: new DefaultSetting("string", "dashboard"),
					showStakeouts: new DefaultSetting("boolean", true),
					showIcons: new DefaultSetting("boolean", true),
					fullBarTime: new DefaultSetting("boolean", false)
				},
				icon: {
					global: new DefaultSetting("boolean", true),
					energy: new DefaultSetting("boolean", true),
					nerve: new DefaultSetting("boolean", true),
					happy: new DefaultSetting("boolean", true),
					life: new DefaultSetting("boolean", true),
					chain: new DefaultSetting("boolean", true),
					travel: new DefaultSetting("boolean", true)
				},
				education: {
					greyOut: new DefaultSetting("boolean", true),
					finishTime: new DefaultSetting("boolean", true)
				},
				jail: { filter: new DefaultSetting("boolean", true) },
				bank: {
					investmentInfo: new DefaultSetting("boolean", true),
					investmentDueTime: new DefaultSetting("boolean", true)
				},
				home: {
					networthDetails: new DefaultSetting("boolean", true),
					effectiveStats: new DefaultSetting("boolean", true)
				},
				items: {
					quickItems: new DefaultSetting("boolean", true),
					values: new DefaultSetting("boolean", true),
					drugDetails: new DefaultSetting("boolean", true),
					marketLinks: new DefaultSetting("boolean", false),
					highlightBloodBags: new DefaultSetting("string", "none"),
					missingFlowers: new DefaultSetting("boolean", false),
					missingPlushies: new DefaultSetting("boolean", false),
					bookEffects: new DefaultSetting("boolean", true),
					canGains: new DefaultSetting("boolean", true),
					nerveGains: new DefaultSetting("boolean", true),
					candyHappyGains: new DefaultSetting("boolean", true),
					energyWarning: new DefaultSetting("boolean", true),
					medicalLife: new DefaultSetting("boolean", true),
					openedSupplyPackValue: new DefaultSetting("boolean", true),
					hideRecycleMessage: new DefaultSetting("boolean", false),
					hideTooManyItemsWarning: new DefaultSetting("boolean", false)
				},
				crimes: { quickCrimes: new DefaultSetting("boolean", true) },
				companies: {
					idBesideCompanyName: new DefaultSetting("boolean", false),
					specials: new DefaultSetting("boolean", true),
					autoStockFill: new DefaultSetting("boolean", true),
					employeeEffectiveness: new DefaultSetting("number", 18)
				},
				travel: {
					computer: new DefaultSetting("boolean", true),
					table: new DefaultSetting("boolean", true),
					cleanFlight: new DefaultSetting("boolean", false),
					tabTitleTimer: new DefaultSetting("boolean", false),
					travelProfits: new DefaultSetting("boolean", true),
					fillMax: new DefaultSetting("boolean", true),
					peopleFilter: new DefaultSetting("boolean", true),
					landingTime: new DefaultSetting("boolean", true),
					flyingTime: new DefaultSetting("boolean", true),
					itemFilter: new DefaultSetting("boolean", true),
					energyWarning: new DefaultSetting("boolean", true),
					cooldownWarnings: new DefaultSetting("boolean", true),
					autoTravelTableCountry: new DefaultSetting("boolean", false),
					autoFillMax: new DefaultSetting("boolean", true),
					efficientRehab: new DefaultSetting("boolean", true),
					efficientRehabSelect: new DefaultSetting("boolean", false)
				},
				stocks: {
					filter: new DefaultSetting("boolean", true),
					acronyms: new DefaultSetting("boolean", true),
					valueAndProfit: new DefaultSetting("boolean", true),
					moneyInput: new DefaultSetting("boolean", true)
				},
				competitions: {
					easterEggs: new DefaultSetting("boolean", false),
					easterEggsAlert: new DefaultSetting("boolean", true)
				},
				events: { worth: new DefaultSetting("boolean", true) },
				hospital: { filter: new DefaultSetting("boolean", true) },
				auction: { filter: new DefaultSetting("boolean", true) },
				api: {
					autoFillKey: new DefaultSetting("boolean", true),
					autoDemo: new DefaultSetting("boolean", false),
					autoPretty: new DefaultSetting("boolean", true),
					clickableSelections: new DefaultSetting("boolean", true)
				},
				forums: {
					menu: new DefaultSetting("boolean", true),
					hidePosts: new DefaultSetting("object", {}),
					hideThreads: new DefaultSetting("object", {}),
					highlightPosts: new DefaultSetting("object", {}),
					highlightThreads: new DefaultSetting("object", {}),
					ignoredThreads: new DefaultSetting("object", {}),
					debugInfoBtn: new DefaultSetting("boolean", true),
					onlyNewFeedButton: new DefaultSetting("boolean", true)
				},
				bazaar: {
					itemsCost: new DefaultSetting("boolean", true),
					worth: new DefaultSetting("boolean", true),
					fillMax: new DefaultSetting("boolean", true),
					maxBuyIgnoreCash: new DefaultSetting("boolean", false),
					highlightSubVendorItems: new DefaultSetting("boolean", false)
				},
				trade: {
					itemValues: new DefaultSetting("boolean", true),
					openChat: new DefaultSetting("boolean", true)
				},
				displayCase: { worth: new DefaultSetting("boolean", true) },
				shops: {
					fillMax: new DefaultSetting("boolean", true),
					maxBuyIgnoreCash: new DefaultSetting("boolean", false),
					profit: new DefaultSetting("boolean", true),
					filters: new DefaultSetting("boolean", true),
					values: new DefaultSetting("boolean", true)
				},
				casino: {
					netTotal: new DefaultSetting("boolean", true),
					blackjack: new DefaultSetting("boolean", true),
					highlow: new DefaultSetting("boolean", false),
					highlowMovement: new DefaultSetting("boolean", true)
				},
				racing: {
					winPercentage: new DefaultSetting("boolean", true),
					upgrades: new DefaultSetting("boolean", true),
					filter: new DefaultSetting("boolean", true)
				},
				faction: {
					idBesideFactionName: new DefaultSetting("boolean", false),
					csvRaidReport: new DefaultSetting("boolean", true),
					csvRankedWarReport: new DefaultSetting("boolean", true),
					csvWarReport: new DefaultSetting("boolean", true),
					csvChainReport: new DefaultSetting("boolean", true),
					csvChallengeContributions: new DefaultSetting("boolean", true),
					openOc: new DefaultSetting("boolean", true),
					highlightOwn: new DefaultSetting("boolean", true),
					availablePlayers: new DefaultSetting("boolean", true),
					recommendedNnb: new DefaultSetting("boolean", true),
					ocNnb: new DefaultSetting("boolean", true),
					ocTimes: new DefaultSetting("boolean", true),
					ocLastAction: new DefaultSetting("boolean", true),
					banker: new DefaultSetting("boolean", true),
					showFullInfobox: new DefaultSetting("boolean", true),
					foldableInfobox: new DefaultSetting("boolean", true),
					numberMembers: new DefaultSetting("boolean", true),
					warFinishTimes: new DefaultSetting("boolean", false),
					memberFilter: new DefaultSetting("boolean", true),
					armoryFilter: new DefaultSetting("boolean", true),
					armoryWorth: new DefaultSetting("boolean", true),
					upgradeRequiredRespect: new DefaultSetting("boolean", true),
					memberInfo: new DefaultSetting("boolean", false),
					rankedWarFilter: new DefaultSetting("boolean", true),
					quickItems: new DefaultSetting("boolean", true),
					stakeout: new DefaultSetting("boolean", true),
					showFactionSpy: new DefaultSetting("boolean", true),
					oc2Filter: new DefaultSetting("boolean", true),
					warnCrime: new DefaultSetting("boolean", false),
					rankedWarValue: new DefaultSetting("boolean", true),
					totalChallengeContributions: new DefaultSetting("boolean", true)
				},
				property: {
					value: new DefaultSetting("boolean", true),
					happy: new DefaultSetting("boolean", true)
				},
				gym: {
					specialist: new DefaultSetting("boolean", true),
					disableStats: new DefaultSetting("boolean", true),
					graph: new DefaultSetting("boolean", true),
					steadfast: new DefaultSetting("boolean", true),
					progress: new DefaultSetting("boolean", true)
				},
				missions: {
					hints: new DefaultSetting("boolean", true),
					rewards: new DefaultSetting("boolean", true)
				},
				attack: {
					bonusInformation: new DefaultSetting("boolean", true),
					timeoutWarning: new DefaultSetting("boolean", true),
					fairAttack: new DefaultSetting("boolean", true),
					weaponExperience: new DefaultSetting("boolean", true),
					hideAttackButtons: new DefaultSetting("array", [])
				},
				city: {
					items: new DefaultSetting("boolean", true),
					combineDuplicates: new DefaultSetting("boolean", true)
				},
				joblist: { specials: new DefaultSetting("boolean", true) },
				bounties: { filter: new DefaultSetting("boolean", true) },
				userlist: { filter: new DefaultSetting("boolean", true) },
				itemmarket: {
					highlightCheapItems: new DefaultSetting("number|empty", ""),
					highlightCheapItemsSound: new DefaultSetting("boolean", false),
					leftBar: new DefaultSetting("boolean", false),
					fillMax: new DefaultSetting("boolean", true)
				},
				competition: { filter: new DefaultSetting("boolean", true) },
				museum: { autoFill: new DefaultSetting("boolean", true) },
				enemies: { filter: new DefaultSetting("boolean", true) },
				friends: { filter: new DefaultSetting("boolean", true) },
				targets: { filter: new DefaultSetting("boolean", true) },
				crimes2: {
					burglaryFilter: new DefaultSetting("boolean", true),
					value: new DefaultSetting("boolean", true)
				}
			},
			scripts: {
				noConfirm: {
					itemEquip: new DefaultSetting("boolean", true),
					tradeAccept: new DefaultSetting("boolean", false),
					pointsMarketRemove: new DefaultSetting("boolean", false),
					pointsMarketBuy: new DefaultSetting("boolean", false),
					abroadItemBuy: new DefaultSetting("boolean", true)
				},
				achievements: {
					show: new DefaultSetting("boolean", true),
					completed: new DefaultSetting("boolean", false)
				},
				lastAction: {
					factionMember: new DefaultSetting("boolean", false),
					companyOwn: new DefaultSetting("boolean", false),
					companyOther: new DefaultSetting("boolean", false)
				},
				statsEstimate: {
					global: new DefaultSetting("boolean", true),
					delay: new DefaultSetting("number", 1500),
					cachedOnly: new DefaultSetting("boolean", true),
					displayNoResult: new DefaultSetting("boolean", false),
					maxLevel: new DefaultSetting("number", 100),
					profiles: new DefaultSetting("boolean", true),
					enemies: new DefaultSetting("boolean", true),
					hof: new DefaultSetting("boolean", true),
					attacks: new DefaultSetting("boolean", true),
					userlist: new DefaultSetting("boolean", true),
					bounties: new DefaultSetting("boolean", true),
					factions: new DefaultSetting("boolean", true),
					wars: new DefaultSetting("boolean", true),
					abroad: new DefaultSetting("boolean", true),
					competition: new DefaultSetting("boolean", true),
					rankedWars: new DefaultSetting("boolean", true),
					targets: new DefaultSetting("boolean", true)
				},
				ffScouter: {
					miniProfile: new DefaultSetting("boolean", true),
					profile: new DefaultSetting("boolean", true),
					attack: new DefaultSetting("boolean", true),
					factionList: new DefaultSetting("boolean", true),
					gauge: new DefaultSetting("boolean", true)
				}
			},
			external: {
				tornstats: new DefaultSetting("boolean", false),
				yata: new DefaultSetting("boolean", false),
				prometheus: new DefaultSetting("boolean", false),
				lzpt: new DefaultSetting("boolean", false),
				tornw3b: new DefaultSetting("boolean", false),
				ffScouter: new DefaultSetting("boolean", false),
				tornintel: new DefaultSetting("boolean", false)
			}
		},
		filters: {
			hospital: {
				enabled: new DefaultSetting("boolean", true),
				timeStart: new DefaultSetting("number", 0),
				timeEnd: new DefaultSetting("number", 100),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100),
				faction: new DefaultSetting("string", ""),
				activity: new DefaultSetting("array", []),
				revivesOn: new DefaultSetting("boolean", false)
			},
			jail: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				faction: new DefaultSetting("string", "All"),
				timeStart: new DefaultSetting("number", 0),
				timeEnd: new DefaultSetting("number", 100),
				levelStart: new DefaultSetting("number", 1),
				levelEnd: new DefaultSetting("number", 100),
				scoreStart: new DefaultSetting("number", 0),
				scoreEnd: new DefaultSetting("number", 5e3),
				bailCost: new DefaultSetting("number", -1)
			},
			racing: {
				enabled: new DefaultSetting("boolean", true),
				hideRaces: new DefaultSetting("array", []),
				timeStart: new DefaultSetting("number", 0),
				timeEnd: new DefaultSetting("number", 48),
				driversMin: new DefaultSetting("number", 2),
				driversMax: new DefaultSetting("number", 100),
				lapsMin: new DefaultSetting("number", 1),
				lapsMax: new DefaultSetting("number", 100),
				track: new DefaultSetting("array", []),
				name: new DefaultSetting("string", "")
			},
			containers: new DefaultSetting("object", {}),
			travel: {
				open: new DefaultSetting("boolean", false),
				type: new DefaultSetting("string", "basic"),
				categories: new DefaultSetting("array", []),
				countries: new DefaultSetting("array", []),
				hideOutOfStock: new DefaultSetting("boolean", false),
				applySalesTax: new DefaultSetting("boolean", false),
				sellAnonymously: new DefaultSetting("boolean", false)
			},
			abroadPeople: {
				enabled: new DefaultSetting("boolean", true),
				activity: new DefaultSetting("array", []),
				status: new DefaultSetting("array", []),
				levelStart: new DefaultSetting("number", 0),
				levelEnd: new DefaultSetting("number", 100),
				faction: new DefaultSetting("string", ""),
				special: {
					newPlayer: new DefaultSetting("string", "both"),
					inCompany: new DefaultSetting("string", "both"),
					inFaction: new DefaultSetting("string", "both"),
					isDonator: new DefaultSetting("string", "both"),
					hasBounties: new DefaultSetting("string", "both"),
					bazaarOpen: new DefaultSetting("string", "both")
				},
				estimates: new DefaultSetting("array", []),
				ffScoreMax: new DefaultSetting("number", null),
				ffScoreMin: new DefaultSetting("number", null)
			},
			abroadItems: {
				enabled: new DefaultSetting("boolean", true),
				profitOnly: new DefaultSetting("boolean", false),
				outOfStock: new DefaultSetting("boolean", false),
				categories: new DefaultSetting("array", []),
				taxes: new DefaultSetting("array", [])
			},
			trade: { hideValues: new DefaultSetting("boolean", false) },
			gym: {
				specialist1: new DefaultSetting("string", "none"),
				specialist2: new DefaultSetting("string", "none"),
				strength: new DefaultSetting("boolean", false),
				speed: new DefaultSetting("boolean", false),
				defense: new DefaultSetting("boolean", false),
				dexterity: new DefaultSetting("boolean", false)
			},
			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);
	svgImport(x_default);
	svgImport(x_circle_default);
	svgImport(arrow_bend_up_left_bold_default);
	svgImport(arrow_clockwise_bold_default);
	svgImport(arrow_down_bold_default);
	svgImport(arrow_up_bold_default);
	svgImport(check_bold_default);
	svgImport(check_circle_bold_default);
	svgImport(copy_bold_default);
	svgImport(info_bold_default);
	svgImport(warning_circle_bold_default);
	svgImport(x_circle_bold_default);
	svgImport(spinner_gap_bold_default);
	svgImport(arrows_out_cardinal_fill_default);
	svgImport(airplane_fill_default);
	svgImport(bell_fill_default);
	svgImport(bell_slash_fill_default);
	var PHFillCaretDown = svgImport(caret_down_fill_default);
	svgImport(caret_right_fill_default);
	svgImport(caret_up_fill_default);
	svgImport(info_fill_default);
	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 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 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(() => {});
			}
		}
	];
	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;
	}
	function initializeDatabaseListener() {
		RUNTIME_STORAGE.addChangeListener((changes, area) => {
			if (area === "local") for (const key in changes) {
				switch (key) {
					case "settings":
						settings = changes.settings.newValue;
						break;
					case "filters":
						filters = changes.filters.newValue;
						break;
					case "version":
						version = changes.version.newValue;
						break;
					case "userdata":
						userdata = changes.userdata.newValue;
						break;
					case "api":
						api = changes.api.newValue;
						break;
					case "torndata":
						torndata = changes.torndata.newValue;
						break;
					case "stakeouts":
						stakeouts = changes.stakeouts.newValue;
						break;
					case "attackHistory":
						attackHistory = changes.attackHistory.newValue;
						break;
					case "notes":
						notes = changes.notes.newValue;
						break;
					case "factiondata":
						factiondata = changes.factiondata.newValue;
						break;
					case "quick":
						quick = changes.quick.newValue;
						break;
					case "localdata":
						localdata = changes.localdata.newValue;
						break;
					case "cache":
						ttCache.cache = changes.cache.newValue;
						break;
					case "npcs":
						npcs = changes.npcs.newValue;
						break;
					case "stockdata":
						stockdata = changes.stockdata.newValue;
						break;
					case "notificationHistory":
						notificationHistory = changes.notificationHistory.newValue;
						break;
					case "notifications":
						notifications = changes.notifications.newValue;
						break;
					case "factionStakeouts":
						factionStakeouts = changes.factionStakeouts.newValue;
						break;
				}
				if (storageListeners[key]) storageListeners[key].forEach((listener) => listener(changes[key].oldValue, changes[key].newValue));
			}
		});
	}
	function setLocaldata(data) {
		localdata = data;
	}
	function setFilters(data) {
		filters = data;
	}
	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 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";
		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 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;
		}
	};
	function initialise() {
		addXHRListener(({ detail: { page, xhr, json } }) => {
			if (!FEATURE_MANAGER.isEnabled(CityItemsFeature)) return;
			if (isMapData(page, xhr, json)) showCityItemsContainer(resolveUserItems(JSON.parse(atob(json.territoryUserItems)))).catch(console.error);
		});
	}
	function triggerFallback() {
		if (findContainer("City Items")) return;
		const model = SCRIPT_INJECTOR.getWindow().torn?.model.get();
		if (!model) return;
		const userItems = model.territoryUserItems;
		if (!userItems) return;
		showCityItemsContainer(resolveUserItems(userItems)).catch(console.error);
	}
	function resolveUserItems(decodedItems) {
		const items = [];
		decodedItems.forEach((item) => {
			const id = ITEM_RESOLVER.findItem((x) => x.name === item.title)?.id ?? -1;
			const td = btoa([
				item.c.x,
				item.c.y,
				item.id,
				item.ts
			].join("O"));
			if (settings.pages.city.combineDuplicates) {
				const duplicate = items.find((item) => item.item === id);
				if (duplicate) {
					duplicate.count++;
					duplicate.entries.push({
						id: item.id,
						td
					});
				} else items.push({
					item: id,
					count: 1,
					name: item.title,
					entries: [{
						id: item.id,
						td
					}]
				});
			} else items.push({
				item: id,
				count: 1,
				name: item.title,
				entries: [{
					id: item.id,
					td
				}]
			});
		});
		return items;
	}
	async function showCityItemsContainer(items) {
		await requireElement("#map .leaflet-zoom-animated");
		const { content } = createContainer("City Items", {
			class: "mt10",
			alwaysContent: true,
			nextElement: document.querySelector("#tab-menu")
		});
		populateContainer(content, items);
	}
	function populateContainer(content, items) {
		if (ITEM_RESOLVER.hasFullItems()) showValue(content, items);
		showItemList(content, items);
	}
	function showValue(content, items) {
		content.querySelector(".tt-city-total")?.remove();
		const totalValue = items.map(({ item, count }) => ({
			...ITEM_RESOLVER.getFullItem(item),
			count
		})).filter((item) => !!item).map(({ value: { market_price: value }, count }) => value * count).filter((value) => !!value).reduce((a, b) => a + b, 0);
		const itemCount = items.map(({ count }) => count).reduce((a, b) => a + b, 0);
		content.appendChild(elementBuilder({
			type: "div",
			class: "tt-city-total",
			children: [elementBuilder({
				type: "span",
				class: "tt-city-total-text",
				text: `Item Value (${itemCount}): `
			}), elementBuilder({
				type: "span",
				class: "tt-city-total-value",
				text: formatNumber(totalValue, { currency: true })
			})]
		}));
	}
	function showItemList(content, items) {
		const listElement = elementBuilder({
			type: "div",
			class: "tt-city-items hide-collapse"
		});
		switch ("text") {
			case "text":
				generateText();
				break;
		}
		content.appendChild(listElement);
		function generateText() {
			let element;
			if (items.length > 0) {
				const totalCount = items.map(({ count }) => count).reduce((a, b) => a + b, 0);
				element = elementBuilder({
					type: "p",
					children: [
						"There",
						totalCount === 1 ? " is " : " are ",
						elementBuilder({
							type: "strong",
							text: totalCount
						}),
						totalCount === 1 ? " item " : " items ",
						"in the city: "
					]
				});
				const _items = [...items];
				if (items.length === 1) element.appendChild(createItemElement(_items[0]));
				else {
					const last = _items.splice(-1)[0];
					for (const item of _items) {
						element.appendChild(createItemElement(item));
						element.appendChild(document.createTextNode(", "));
					}
					element.lastChild.remove();
					element.appendChild(document.createTextNode(" and "));
					element.appendChild(createItemElement(last));
				}
				element.appendChild(document.createTextNode("."));
			} else element = elementBuilder({
				type: "p",
				text: "There are no items in the city."
			});
			listElement.appendChild(element);
			function createItemElement({ item, name, count, entries }) {
				let text;
				if (count > 1) text = `${count}x ${name}`;
				else text = name;
				return elementBuilder({
					type: "span",
					text,
					class: "list-item",
					events: { click() {
						const entry = entries[0];
						collectItem(entry.td).then(() => {
							const newItems = [...items.filter((a) => a.item !== item)];
							if (entries.length > 1) newItems.push({
								item,
								name,
								count: count - 1,
								entries: entries.slice(1)
							});
							populateContainer(content, newItems);
						});
					} }
				});
			}
		}
	}
	async function collectItem(td) {
		const body = new URLSearchParams();
		body.set("step", "uif");
		body.set("td", td);
		await fetchData("torn_direct", {
			action: "city.php",
			method: "POST",
			body
		});
	}
	function removeHighlight() {
		removeContainer("City Items");
	}
	var CityItemsFeature = class extends Feature {
		constructor() {
			super("City Items", "city");
		}
		precondition() {
			return getPageStatus().access;
		}
		isEnabled() {
			return settings.pages.city.items;
		}
		initialise() {
			initialise();
		}
		execute() {
			setTimeout(triggerFallback, 500);
		}
		cleanup() {
			removeHighlight();
		}
		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 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();
		}
	};
	var fetchListenerInjector = new RequestListenerInjector(injectFetchListeners);
	var xhrListenerInjector = new RequestListenerInjector(injectXhrListeners);
	var UserscriptScriptInjector = {
		getWindow() {
			return unsafeWindow;
		},
		injectFetch() {
			fetchListenerInjector.inject();
		},
		injectXHR() {
			xhrListenerInjector.inject();
		}
	};
	var UserscriptRuntimeInformation = {
		getVersion() {
			return GM.info.version;
		},
		isUserscript() {
			return true;
		}
	};
	var UserscriptRuntimeStorage = {
		callback: () => {},
		addChangeListener(callback) {
			this.callback = callback;
		}
	};
	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) {
		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 () => {
		await registerUserscriptContext("tt_ci");
		await ScriptItemResolver.loadItems();
		const feature = new CityItemsFeature();
		FEATURE_MANAGER.registerFeature(feature);
	})();
})();